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); }
/// <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); } }