public static int[] WriteSounds(BBData data, SoundInfo[] sounds, StringsChunkBuilder strings, string[] audioGroups) { int[] offsets = WriteList(data, sounds, (sounddata, sound) => WriteSound(sounddata, sound, strings, audioGroups)); var stringOffsetOffsets = new List <int>(); for (int i = 0; i < sounds.Length; i++) { if (sounds[i].Name != null) { stringOffsetOffsets.Add(offsets[i] + (int)Marshal.OffsetOf(typeof(SoundEntry), "NameOffset") + 8); } if (sounds[i].Type != null) { stringOffsetOffsets.Add(offsets[i] + (int)Marshal.OffsetOf(typeof(SoundEntry), "TypeOffset") + 8); } if (sounds[i].File != null) { stringOffsetOffsets.Add(offsets[i] + (int)Marshal.OffsetOf(typeof(SoundEntry), "FileOffset") + 8); } } return(stringOffsetOffsets.ToArray()); }
private static void WriteSprite(BBData data, SpriteInfo si, StringsChunkBuilder strings, int[] texPagOffsets) { var se = new SpriteEntry { Name = strings.GetOffset(si.Name), Size = si.Size, Bounding = si.Bounding, BBoxMode = si.BBoxMode, Origin = si.Origin, SeparateColMasks = si.SeparateColMasks ? DwordBool.True : DwordBool.False }; var tmp = new BinBuffer(); tmp.Write(se); data.Buffer.Write(tmp, 0, tmp.Size - 8, 0); if (si.Version >= 2) { var se2 = new SpriteEntry2(); unsafe { se2._pad2[0] = -1; se2._pad2[1] = 1; se2._pad2[2] = 0; } se2.funk = si.UnknownFloat; tmp = new BinBuffer(); tmp.Write(se2); data.Buffer.Write(tmp, 0, 0x14, 0x38); } if (si.TextureIndices == null) { data.Buffer.Write(0xFFFFFFFF); } else { data.Buffer.Write(si.TextureIndices.Length); foreach (var ti in si.TextureIndices) { data.Buffer.Write(texPagOffsets[ti]); } if (si.CollisionMasks == null) { data.Buffer.Write(0xFFFFFFFF); } else { data.Buffer.Write((uint)si.CollisionMasks.Length); foreach (var mask in si.CollisionMasks) { int w = mask.GetLength(0); for (int y = 0; y < mask.GetLength(1); y++) { for (int x = 0; x < w; x += 8) { byte b = 0; if (x < w && mask[x, y]) { b |= 0b00000001; } if (x + 1 < w && mask[x + 1, y]) { b |= 0b00000010; } if (x + 2 < w && mask[x + 2, y]) { b |= 0b00000100; } if (x + 3 < w && mask[x + 3, y]) { b |= 0b00001000; } if (x + 4 < w && mask[x + 4, y]) { b |= 0b00010000; } if (x + 5 < w && mask[x + 5, y]) { b |= 0b00100000; } if (x + 6 < w && mask[x + 6, y]) { b |= 0b01000000; } if (x + 7 < w && mask[x + 7, y]) { b |= 0b10000000; } data.Buffer.Write(b); } } } } } Pad(data, 4, 0); }
private static void WriteObject(BBData data, ObjectInfo oi, StringsChunkBuilder strings) { var oe = new ObjectEntry { Name = strings.GetOffset(oi.Name), SpriteIndex = oi.SpriteIndex, Visible = oi.IsVisible ? DwordBool.True : DwordBool.False, Solid = oi.IsSolid ? DwordBool.True : DwordBool.False, Depth = oi.Depth, Persistent = oi.IsPersistent ? DwordBool.True : DwordBool.False, ParentId = oi.ParentId == null ? -100 : (int)oi.ParentId, MaskId = oi.TexMaskId == null ? -1 : (int)oi.TexMaskId, HasPhysics = oi.Physics != null ? DwordBool.True : DwordBool.False, IsSensor = oi.IsSensor ? DwordBool.True : DwordBool.False, CollisionShape = oi.CollisionShape }; oe.Physics = oi.Physics ?? new ObjectPhysics { Density = 0.5f, Restitution = 0.1f, Group = 0, LinearDamping = 0.1f, AngularDamping = 0.1f, Unknown0 = 0, Friction = 0.2f, Unknown1 = 1, Kinematic = 0 }; for (int i = 0; i < oi.OtherFloats.Length; i++) { unsafe { oe.Rest.MoreFloats[i] = oi.OtherFloats[i]; } } var hasMore = oi.OtherFloats.Length > 0; if (hasMore) { BinBuffer tmp = new BinBuffer(); tmp.Write(oe); data.Buffer.Write(tmp.AsByteArray(), 0, (int)Marshal.OffsetOf(typeof(ObjectEntry), "Rest") + (int)Marshal.OffsetOf(typeof(ObjectRest), "ShapePoints_IfMoreFloats")); } else { BinBuffer tmp = new BinBuffer(); tmp.Write(oe); data.Buffer.Write(tmp.AsByteArray(), 0, (int)Marshal.OffsetOf(typeof(ObjectEntry), "Rest") + (int)Marshal.OffsetOf(typeof(ObjectRest), "ShapePoints")); } WriteList(data, oi.ShapePoints, (shapePointData, shapePoint) => WriteList(shapePointData, shapePoint, (pointPointData, pointPoint) => { pointPointData.Buffer.Write(pointPoint[0]); pointPointData.Buffer.Write(pointPoint[1]); // probably count pointPointData.OffsetOffsets = new int[] { pointPointData.Buffer.Position }; pointPointData.Buffer.Write(12); // probably offset for (int i = 3; i < pointPoint.Length; i++) { pointPointData.Buffer.Write(pointPoint[i]); } }) ); }
public static int[] WriteGeneral(BBData data, GeneralInfo ge, RoomInfo[] rooms, StringsChunkBuilder strings) { var ret = new SectionGeneral { Debug = ge.IsDebug, FilenameOffset = strings.GetOffset(ge.FileName), ConfigOffset = strings.GetOffset(ge.Configuration), NameOffset = strings.GetOffset(ge.Name), DisplayNameOffset = strings.GetOffset(ge.DisplayName), GameID = ge.GameID, WindowSize = ge.WindowSize, BytecodeVersion = (Int24)ge.BytecodeVersion, Major = ge.Version.Major, Minor = ge.Version.Minor, Release = ge.Version.Build, Build = ge.Version.Revision, Info = ge.InfoFlags, ActiveTargets = ge.ActiveTargets, AppID = ge.SteamAppID, LastObj = 0, LastTile = 0 }; var stringOffsetOffsets = new int[] { (int)Marshal.OffsetOf(typeof(SectionGeneral), "FilenameOffset") - 3, (int)Marshal.OffsetOf(typeof(SectionGeneral), "ConfigOffset") - 3, (int)Marshal.OffsetOf(typeof(SectionGeneral), "NameOffset") - 3, (int)Marshal.OffsetOf(typeof(SectionGeneral), "DisplayNameOffset") - 3 }; foreach (var room in rooms) { foreach (var obj in room.Objects) { if (obj.InstanceID > ret.LastObj) { ret.LastObj = obj.InstanceID; } } foreach (var tile in room.Tiles) { if (tile.InstanceID > ret.LastTile) { ret.LastTile = tile.InstanceID; } } } ret.LastObj++; ret.LastTile++; for (int i = 0; i < 4; i++) { unsafe { ret._unknown[i] = ge.unknown[i]; } } unsafe { Marshal.Copy(ge.LicenseMD5Hash, 0, (IntPtr)ret.MD5, 0x10); } ret.CRC32 = ge.LicenceCRC32; ret.Timestamp = (ulong)(ge.Timestamp.Subtract(new DateTime(1970, 1, 1))).TotalSeconds; if (ge.WeirdNumbers == null) { ret.NumberCount = 0; } else { ret.NumberCount = (uint)ge.WeirdNumbers.Length; } var tmp = new BinBuffer(); tmp.Write(ret); data.Buffer.Write(tmp, 0, tmp.Size - 12, 8); for (int i = 0; i < ret.NumberCount; i++) { data.Buffer.Write(ge.WeirdNumbers[i]); } // TODO for 2.0: some lengthy checksum/hash at the end? // exits after launch if GEN8 is modified at all, // doesn't launch if the extra stuff is missing //for (int i = 0; i < 16; i++) // data.Buffer.Write(0x3F3F3F3F); return(stringOffsetOffsets); }
public static int[] WriteList <T>(BBData data, T[] things, Action <BBData, T, StringsChunkBuilder, int[]> writeThing, StringsChunkBuilder strings, int[] texPagOffsets) { return(WriteList(data, things, (thingdata, thing) => writeThing(thingdata, thing, strings, texPagOffsets))); }
public static int[] WriteFunctionLocals(BBData data, FunctionLocalsInfo[] functions, StringsChunkBuilder strings) { var stringOffsetOffsets = new List <int>(); data.Buffer.Write(functions.Length); foreach (var func in functions) { data.Buffer.Write((uint)func.LocalNames.Length); stringOffsetOffsets.Add(data.Buffer.Position + 8); data.Buffer.Write(strings.GetOffset(func.FunctionName)); for (uint i = 0; i < func.LocalNames.Length; i++) { stringOffsetOffsets.Add(data.Buffer.Position + 12); data.Buffer.Write(new FunctionLocalEntry { Index = i, Name = strings.GetOffset(func.LocalNames[i]) }); } } return(stringOffsetOffsets.ToArray()); }
private static void WriteRoom(BBData data, RoomInfo ri, StringsChunkBuilder strings) { var re = new RoomEntry { Name = strings.GetOffset(ri.Name), Caption = ri.Caption == null ? 0 : strings.GetOffset(ri.Caption), Size = ri.Size, Speed = ri.Speed, Persistent = ri.IsPersistent ? DwordBool.True : DwordBool.False, Colour = ri.Colour, DrawBackgroundColour = ri.DrawBackgroundColour ? DwordBool.True : DwordBool.False, _unknown = ri._unknown, Flags = 0, World = ri.World, Bounding = ri.Bounding, Gravity = ri.Gravity, MetresPerPixel = ri.MetresPerPixel }; if (ri.EnableViews) { re.Flags |= RoomEntryFlags.EnableViews; } if (ri.ShowColour) { re.Flags |= RoomEntryFlags.ShowColour; } if (ri.ClearDisplayBuffer) { re.Flags |= RoomEntryFlags.ClearDisplayBuffer; } if (ri.UnknownFlag) { re.Flags |= RoomEntryFlags.Unknown; } var bgOffsetOffset = (int)Marshal.OffsetOf(typeof(RoomEntry), "BgOffset"); var viewOffsetOffset = (int)Marshal.OffsetOf(typeof(RoomEntry), "ViewOffset"); var objOffsetOffset = (int)Marshal.OffsetOf(typeof(RoomEntry), "ObjOffset"); var tileOffsetOffset = (int)Marshal.OffsetOf(typeof(RoomEntry), "TileOffset"); int objInstOffsetOffset = (int)Marshal.OffsetOf(typeof(RoomEntry), "MetresPerPixel") + 4; data.Buffer.Write(re); data.OffsetOffsets = new int[] { bgOffsetOffset, viewOffsetOffset, objOffsetOffset, tileOffsetOffset }; if (ri.ObjInst != null) { data.Buffer.Write(0); data.OffsetOffsets = data.OffsetOffsets.Concat(new int[] { objInstOffsetOffset }).ToArray(); } data.Buffer.Position = bgOffsetOffset; data.Buffer.Write(data.Buffer.Size); data.Buffer.Position = data.Buffer.Size; WriteList(data, ri.Backgrounds, WriteRoomBg); data.Buffer.Position = viewOffsetOffset; data.Buffer.Write(data.Buffer.Size); data.Buffer.Position = data.Buffer.Size; WriteList(data, ri.Views, WriteRoomView); data.Buffer.Position = objOffsetOffset; data.Buffer.Write(data.Buffer.Size); data.Buffer.Position = data.Buffer.Size; WriteList(data, ri.Objects, WriteRoomObj); data.Buffer.Position = tileOffsetOffset; data.Buffer.Write(data.Buffer.Size); data.Buffer.Position = data.Buffer.Size; WriteList(data, ri.Tiles, WriteRoomTile); if (ri.ObjInst != null) { data.Buffer.Position = objInstOffsetOffset; data.Buffer.Write(data.Buffer.Size); data.Buffer.Position = data.Buffer.Size; WriteList(data, ri.ObjInst, WriteRoomObjInst, strings); } // Unknown stuff for 2.0 //for (int i = 0; i < 8; i++) // data.Buffer.Write(0x3F3F3F3F); }