private static void WriteSound(BBData data, SoundInfo si, StringsChunkBuilder strings, string[] audioGroups) { var se = new SoundEntry { NameOffset = si.Name == null ? 0 : strings.GetOffset(si.Name), TypeOffset = si.Type == null ? 0 : strings.GetOffset(si.Type), FileOffset = si.File == null ? 0 : strings.GetOffset(si.File), Volume = si.VolumeMod, Pitch = si.PitchMod, GroupID = (si.Group == null || si.Group.Length == 0) ? 0 : Array.IndexOf(audioGroups, si.Group), AudioID = si.AudioID, Flags = SoundEntryFlags.Normal }; if (si.IsEmbedded) { se.Flags |= SoundEntryFlags.Embedded; } if (si.IsCompressed) { se.Flags |= SoundEntryFlags.Compressed; } data.Buffer.Write(se); }
public static void WriteFont(BBData data, FontInfo fi, StringsChunkBuilder strings, int[] texPagOffsets) { var fe = new FontEntry { CodeName = fi.CodeName == null ? 0 : strings.GetOffset(fi.CodeName), SystemName = strings.GetOffset(fi.SystemName), EmSize = fi.EmSize, Bold = fi.IsBold ? DwordBool.True : DwordBool.False, Italic = fi.IsItalic ? DwordBool.True : DwordBool.False, _ignore0 = fi.Characters[0].Character, Charset = fi.Charset, AntiAliasing = fi.AntiAliasing, TPagOffset = (uint)texPagOffsets[fi.TexPagId], Scale = fi.Scale }; foreach (var character in fi.Characters) { if (character.Character > fe._ignore1) { fe._ignore1 = character.Character; } } data.Buffer.Write(fe); data.Buffer.Position -= 8; WriteList(data, fi.Characters, WriteFontCharEntry); }
private static void WriteShader(BBData data, ShaderInfo si, StringsChunkBuilder strings) { var se = new ShaderEntry { Name = strings.GetOffset(si.Name), Type = si.Type.Encode(), AttributeCount = (uint)si.Attributes.Length }; unsafe { se.GLSL_ES.VertexSource = strings.GetOffset(si.Code.GLSL_ES.VertexShader); se.GLSL_ES.FragmentSource = strings.GetOffset(si.Code.GLSL_ES.FragmentShader); se.GLSL.VertexSource = strings.GetOffset(si.Code.GLSL.VertexShader); se.GLSL.FragmentSource = strings.GetOffset(si.Code.GLSL.FragmentShader); se.HLSL9.VertexSource = strings.GetOffset(si.Code.HLSL9.VertexShader); se.HLSL9.FragmentSource = strings.GetOffset(si.Code.HLSL9.FragmentShader); } var tmp = new BinBuffer(); tmp.Write(se); data.Buffer.Write(tmp, 0, tmp.Size - 4, 0); // TODO foreach (var attr in si.Attributes) { data.Buffer.Write(strings.GetOffset(attr)); } data.Buffer.Write(2); // TODO: ShaderEntry2 for (int i = 0; i < 12; i++) { data.Buffer.Write(0); } }
private static void WriteScript(BBData data, ScriptInfo si, StringsChunkBuilder strings) { data.Buffer.Write(new ScriptEntry { Name = strings.GetOffset(si.Name), CodeId = si.CodeId }); }
private static void WriteBackground(BBData data, BackgroundInfo bi, StringsChunkBuilder strings, int[] texPagOffsets) { data.Buffer.Write(new BgEntry { Name = strings.GetOffset(bi.Name), TextureOffset = bi.TexPageIndex.HasValue ? (uint)texPagOffsets[bi.TexPageIndex.Value] : 0 }); }
public static int[] WriteOptions(BBData data, OptionInfo opt, StringsChunkBuilder strings) { var ret = new SectionOptions(); var stringOffsetOffsets = new List <int>(); unsafe { for (int i = 0; i < 2; i++) { ret._pad0[i] = opt._pad0[i]; } for (int i = 0; i < 0xC; i++) { ret._pad1[i] = opt._pad1[i]; } } ret.GEN8FlagsDup = opt.InfoFlags; if (opt.Constants == null) { ret.ConstMap.Count = 0; } else { ret.ConstMap.Count = (uint)opt.Constants.Count; } var tmp = new BinBuffer(); tmp.Write(ret); data.Buffer.Write(tmp, 0, tmp.Size - 12, 8); if (opt.Constants != null) { foreach (var kvp in opt.Constants) { stringOffsetOffsets.Add(data.Buffer.Position + 8); data.Buffer.Write(strings.GetOffset(kvp.Key)); stringOffsetOffsets.Add(data.Buffer.Position + 8); data.Buffer.Write(strings.GetOffset(kvp.Value)); } } return(stringOffsetOffsets.ToArray()); }
private static void WriteRefDef(BBData data, ReferenceDef rd, StringsChunkBuilder strings) { data.Buffer.Write(new RefDefEntry { NameOffset = strings.GetOffset(rd.Name), Occurrences = rd.Occurrences, FirstAddress = rd.FirstOffset }); }
private static void WriteRefDefWithOthers(BBData data, ReferenceDef rd, StringsChunkBuilder strings) { data.Buffer.Write(new RefDefEntryWithOthers { NameOffset = strings.GetOffset(rd.Name), InstanceType = (int)rd.InstanceType, _pad1 = rd.unknown2, Occurrences = rd.Occurrences, FirstAddress = rd.FirstOffset }); }
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 WriteRoomObjInst(BBData data, RoomObjInst roi, StringsChunkBuilder strings) { data.Buffer.Write(new RoomObjInstEntry { Index = roi.Index, Unk1 = roi.Unk1, Depth = roi.Depth, Unk3 = roi.Unk3, InstCount = (uint)roi.Instances.Length, Name = strings.GetOffset(roi.Name) }); data.Buffer.Position -= 4; foreach (var id in roi.Instances) { data.Buffer.Write(id); } }
private static void WritePath(BBData data, PathInfo pi, StringsChunkBuilder strings) { var tmp = new BinBuffer(); tmp.Write(new PathEntry { Name = strings.GetOffset(pi.Name), IsSmooth = pi.IsSmooth ? DwordBool.True : DwordBool.False, IsClosed = pi.IsClosed ? DwordBool.True : DwordBool.False, Precision = pi.Precision, PointCount = (uint)pi.Points.Length }); data.Buffer.Write(tmp, 0, tmp.Size - 12, 0); foreach (var pt in pi.Points) { data.Buffer.Write(pt); } }
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); }
public static int[] WriteAudioGroups(BBData data, string[] audioGroups, StringsChunkBuilder strings) { int[] offsets = WriteList(data, audioGroups, (groupdata, group) => groupdata.Buffer.Write(strings.GetOffset(group))); var stringOffsetOffsets = new int[audioGroups.Length]; for (int i = 0; i < audioGroups.Length; i++) { stringOffsetOffsets[i] = offsets[i] + 8; } return(stringOffsetOffsets.ToArray()); }
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); }
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); }