// Reads the hashes and related strings private void ReadBuildHashes(BinaryReader reader) { var buildHashes = new Dictionary <int, SpriteBaseName>(); var numHashes = reader.ReadInt32(); Utilities.LogToDump($"\n<Hashtable {numHashes}>", Logger); for (var i = 0; i < numHashes; i++) { var hash = reader.ReadInt32(); var str = reader.ReadPString(); Utilities.LogToDump($" {hash} -> \"{str}\"", Logger); buildHashes[hash] = new SpriteBaseName(str); } BuildHashes = buildHashes; }
private void PackBuild(TexturePacker texture) { BuildData = new Build(); BuildData.Version = 10; // magic number SetSymbolsAndFrames(texture.SpriteAtlas); BuildData.Name = scml.GetElementsByTagName("entity")[0].Attributes["name"].Value; var histogram = texture.GetHistogram(); var hashTable = new Dictionary <SpriteBaseName, int>(); BuildData.Symbols = new List <Symbol>(); var symbolIndex = -1; SpriteBaseName lastName = null; foreach (var sprite in texture.SpriteAtlas) { // Only add each unique symbol once if (lastName != sprite.BaseName) { var symbol = new Symbol(); // The hash table caches a KleiHash translation of all sprites. // It may be unnecessary but the original had it, and I don't know if the performance impact is // small enough to remove it. if (!hashTable.ContainsKey(sprite.BaseName)) { hashTable[sprite.BaseName] = sprite.BaseName.KleiHashed; } symbol.Hash = hashTable[sprite.BaseName]; symbol.Path = symbol.Hash; symbol.Color = 0; // no Klei files use color other than 0 so fair assumption is it can be 0 // only check in decompile for flag checks flag = 8 for a layered anim (which we won't do) // so should be safe to leave flags = 0 // have seen some Klei files in which flags = 1 for some symbols but can't determine what that does symbol.Flags = 0; symbol.FrameCount = histogram[sprite.BaseName]; symbol.Frames = new List <Frame>(); BuildData.Symbols.Add(symbol); symbolIndex++; lastName = sprite.BaseName; } var frame = new Frame(); frame.SourceFrameNum = sprite.SpriteName.Index; // duration is always 1 because the frames for a symbol always are numbered incrementing by 1 // (or at least that's why I think it's always 1 in the examples I looked at) frame.Duration = 1; // this value as read from the file is unused by Klei code and all example files have it set to 0 for all symbols frame.BuildImageIndex = 0; frame.X1 = (float)sprite.X / texture.SpriteSheet.Width; frame.X2 = (float)(sprite.X + sprite.Width) / texture.SpriteSheet.Width; frame.Y1 = (float)sprite.Y / texture.SpriteSheet.Height; frame.Y2 = (float)(sprite.Y + sprite.Height) / texture.SpriteSheet.Height; // do not set frame.time since it was a calculated property and not actually used in kbild frame.PivotWidth = sprite.Width * 2; frame.PivotHeight = sprite.Height * 2; // Find the appropriate pivot from the scml var key = $"{sprite.BaseName}_{frame.SourceFrameNum}"; if (!projectSprites.ContainsKey(sprite.SpriteName)) { continue; } var scmlnode = projectSprites[sprite.SpriteName]; frame.PivotX = -(float.Parse(scmlnode.Attributes["pivot_x"].Value) - 0.5f) * frame.PivotWidth; frame.PivotY = (float.Parse(scmlnode.Attributes["pivot_y"].Value) - 0.5f) * frame.PivotHeight; BuildData.Symbols[symbolIndex].Frames.Add(frame); } // Finally, flip the key/values to get the build hash table BuildHashes = new Dictionary <int, SpriteBaseName>(); foreach (var entry in hashTable) { BuildHashes[entry.Value] = entry.Key; } BuildBuildTable(texture.SpriteSheet.Width, texture.SpriteSheet.Height); }