예제 #1
0
        public static Prop ReadFrom(Area area, BinaryReader br)
        {
            var areaVersion = 201;

            if (area != null)
            {
                areaVersion = area.Version;
            }

            var kr165Hack = false;

            var prop = new Prop(area);

            if (areaVersion > 200)
            {
                prop.Id = br.ReadInt32();
            }

            prop.EntityId = br.ReadUInt64();
            prop.Name     = br.ReadWString();
            prop.Position = br.ReadVector3F_XYZ();
            var shapeCount = br.ReadByte();

            prop.ShapeType = br.ReadInt32();

            prop.Shapes = new List <Shape>(shapeCount);
            if (areaVersion == 200)
            {
                for (var i = 0; i < shapeCount; ++i)
                {
                    var shape = Shape.ReadLegacyFrom(br);
                    prop.Shapes.Add(shape);
                }

                prop.Unk1 = br.ReadByte();

                // KR165 has a different structure for version 200 than KR72,
                // and unfortunately we have no real way to check for this
                // version looking at just the prop and its area. To work
                // around this, we're gonna check the next byte for 0 here.
                // Since there is no prop with the id 0, and the id is stored
                // in little endian, the next byte should be != 0 if it's
                // the KR72 structure. Meanwhile, the KR165 structure appears
                // to always have a 0 here, possibly for padding. If we find
                // this 0 byte, we're gonna read it, and we're gonna use that
                // information to also read the title, further down, which
                // would otherwise require version 201+.
                // If this part doesn't work correctly, parsing KR165 areas
                // will usually throw an exception on parsing the shapes
                // above, because the previous prop in the loop wasn't parsed
                // correctly, and the shapes have some sanity checks.
                var unk2 = br.ReadByte();
                br.BaseStream.Seek(-1, SeekOrigin.Current);
                kr165Hack = (unk2 == 0) || (prop.Unk1 == 0 && unk2 == 1);

                if (kr165Hack)
                {
                    prop.Unk2 = br.ReadByte();
                }

                prop.Id = br.ReadInt32();
            }
            else
            {
                for (var i = 0; i < shapeCount; ++i)
                {
                    var shape = Shape.ReadFrom(br);
                    prop.Shapes.Add(shape);
                }

                prop.IsCollision   = br.ReadBoolean();
                prop.FixedAltitude = br.ReadBoolean();
            }

            prop.Scale    = br.ReadSingle();
            prop.Rotation = br.ReadSingle();

            if (areaVersion > 200)
            {
                prop.BottomLeft = br.ReadVector3F_XZY();
                prop.TopRight   = br.ReadVector3F_XZY();
            }

            prop.ColorOverride = br.ReadColor();
            for (var i = 0; i < ColorCount; ++i)
            {
                prop.Colors[i] = br.ReadColor();
            }

            if (areaVersion > 200 || kr165Hack)
            {
                prop.Title = br.ReadWString();
            }

            prop.State = br.ReadWString();

            var parameterCount = br.ReadByte();

            prop.Parameters = new List <EntityParameter>(parameterCount);
            for (var i = 0; i < parameterCount; ++i)
            {
                var param = EntityParameter.ReadFrom(br);
                prop.Parameters.Add(param);
            }

            prop.LoadData();

            return(prop);
        }
예제 #2
0
        /// <summary>
        /// Reads area from stream and returns it.
        /// </summary>
        /// <param name="stream"></param>
        /// <returns></returns>
        public static Area ReadFrom(Stream stream)
        {
            using (var br = new BinaryReader(stream))
            {
                var area = new Area();

                area.Version = br.ReadInt16();

                if (area.Version == 200)
                {
                    throw new UnsupportedVersionException();
                }

                area.Unk8       = br.ReadInt16();
                area.Length     = br.ReadInt32();
                area.Id         = br.ReadUInt16();
                area.RegionId   = br.ReadUInt16();
                area.ServerName = br.ReadWString();
                area.Name       = br.ReadWString();
                area.PlaneX     = br.ReadInt32();
                area.PlaneY     = br.ReadInt32();
                area.Unk1       = br.ReadInt32();
                area.Unk2       = br.ReadInt32();
                var eventCount = br.ReadInt32();
                var propCount  = br.ReadInt32();
                area.Unk3        = br.ReadSingle();
                area.Unk4        = br.ReadSingle();
                area.Unk5        = br.ReadInt32();
                area.Unk6        = br.ReadInt32();
                area.Unk7        = br.ReadInt32();
                area.BottomLeft  = br.ReadVector3F_XZY();
                area.BottomRight = br.ReadVector3F_XZY();
                area.TopRight    = br.ReadVector3F_XZY();
                area.TopLeft     = br.ReadVector3F_XZY();

                if (area.Version == 203)
                {
                    area.Unk9 = br.ReadInt32();
                }

                area.Version2 = br.ReadInt32();
                var propCount2 = br.ReadInt32();

                area.Props = new List <Prop>(propCount2);
                for (var i = 0; i < propCount2; ++i)
                {
                    var prop = Prop.ReadFrom(area, br);
                    area.Props.Add(prop);
                }

                area.Events = new List <Event>(eventCount);
                for (var i = 0; i < eventCount; ++i)
                {
                    var evnt = Event.ReadFrom(area, br);
                    area.Events.Add(evnt);
                }

                var areaPlanesCount = (area.PlaneX * area.PlaneY);
                area.AreaPlanes = new List <AreaPlane>(areaPlanesCount);
                for (var i = 0; i < areaPlanesCount; ++i)
                {
                    var plane = AreaPlane.ReadFrom(br);
                    area.AreaPlanes.Add(plane);
                }

                // Usually 65|68 bytes follow the planes, purpose unknown
                // and why they appear hasn't been researched yet, neither
                // why the lengths differ.

                var length = (int)(br.BaseStream.Length - br.BaseStream.Position);
                area.Unk10 = br.ReadBytes(length);

                if (length != 65 && length != 68)
                {
                    throw new FormatException($"Expected 65|68 byte tail, got {length}.");
                }

                if (br.BaseStream.Position != br.BaseStream.Length)
                {
                    throw new FormatException($"Area file '{area.Name}' longer or shorter than expected.");
                }

                return(area);
            }
        }