private Hashing.Hash128 GetModelHash(string model)
        {
            return(_modelHash.GetOrAdd(model, (modelPath) =>
            {
                var hb = Hashing.Builder();
                if (!Buffers.TryTake(out var buffer))
                {
                    buffer = new byte[1024];
                }
                using (var stream = OpenModelReader(modelPath))
                {
                    while (true)
                    {
                        var count = stream.Read(buffer, 0, buffer.Length);
                        if (count <= 0)
                        {
                            break;
                        }
                        for (var i = 0; i < count; i++)
                        {
                            hb.Add(buffer[i]);
                        }
                    }
                }

                Buffers.Add(buffer);

                var hash = hb.Build();
                if (DebugFlags.Debug(typeof(DerivedModelManager)))
                {
                    _log.Info($"Generated model hash for {model} = {hash}");
                }
                return hash;
            }));
        public MaterialEdit(ModeEnum mode, string key, string value)
        {
            Mode  = mode;
            Key   = key;
            Value = value;
            var builder = Hashing.Builder();

            builder.Add(Key);
            builder.Add(Value);
            builder.Add((byte)Mode);
            Hash = builder.Build();
        }
        protected override void Save(string rawPath, Hashing.Hash128 hash, Dictionary <string, string> materialNameMapping, Dictionary <string, object> tags)
        {
            using (PoolManager.Get(out HashSet <string> shapeNames))
            {
                if (tags.TryGetValue(MyImporterConstants.TAG_HAVOK_DESTRUCTION, out var destructionBufferIn) ||
                    tags.TryGetValue(MyImporterConstants.TAG_HAVOK_COLLISION_GEOMETRY, out destructionBufferIn))
                {
                    using (var hkWorld = new HkWorld(true, 50000, float.MaxValue, false, 4, 0.6f))
                    {
                        hkWorld.MarkForWrite();
                        hkWorld.DestructionWorld = new HkdWorld(hkWorld);
                        hkWorld.UnmarkForWrite();
                        using (var destructionStorage = new HkDestructionStorage(hkWorld.DestructionWorld))
                        {
                            var result = destructionStorage.LoadDestructionDataFromBuffer((byte[])destructionBufferIn)[0];
                            CollectShapeNamesRecursive(result, shapeNames);
//                            RenameShapesRecursive(result, "_" + hash);
//                            var rawOutput = Path.GetTempFileName();
//                            destructionStorage.SaveDestructionData(result, rawOutput);
//                            var rawBytes = File.ReadAllBytes(rawOutput);
//                            FixupMaterialReferences(rawBytes, materialNameMapping);
//                            tags[MyImporterConstants.TAG_HAVOK_DESTRUCTION] = rawBytes;
//                            File.Delete(rawOutput);
                        }
                    }
                }

                if (tags.TryGetValue(MyImporterConstants.TAG_HAVOK_COLLISION_GEOMETRY, out var havokCollision))
                {
                    using (PoolManager.Get(out Dictionary <string, string> dict))
                    {
                        foreach (var kv in materialNameMapping)
                        {
                            dict[kv.Key] = kv.Value;
                        }
                        foreach (var name in shapeNames)
                        {
                            var hb = Hashing.Builder();
                            hb.Add(name);
                            hb.Add(hash);
                            dict[name] = hb.Build().ToLimitedString(name.Length);
                        }

                        FixupMaterialReferences((byte[])havokCollision, dict);
                    }
                }
            }

            var fullPath = Path.Combine(_exportContentRoot, rawPath);

            using (var writer = new BinaryWriter(File.Open(fullPath, FileMode.Create)))
                ModelExporter.ExportModelData(writer, tags);
        }