示例#1
0
    public static void ImportDS1CollisionHKX(HKX hkx, string assetName)
    {
        // Setup a game object asset
        GameObject root = new GameObject(Path.GetFileNameWithoutExtension(assetName));

        if (!AssetDatabase.IsValidFolder(assetName))
        {
            AssetDatabase.CreateFolder(Path.GetDirectoryName(assetName + ".blah"), Path.GetFileNameWithoutExtension(assetName + ".blah"));
        }

        int index = 0;

        foreach (var col in hkx.DataSection.Objects)
        {
            if (col is HKX.HKPStorageExtendedMeshShapeMeshSubpartStorage)
            {
                var verts   = new List <Vector3>();
                var normals = new List <Vector3>();
                var indices = new List <int>();

                var coldata = (HKX.HKPStorageExtendedMeshShapeMeshSubpartStorage)col;

                for (int i = 0; i < coldata.Indices16.Size / 4; i++)
                {
                    var vert0 = coldata.Vertices.GetArrayData().Elements[coldata.Indices16.GetArrayData().Elements[i * 4].data];
                    var vert1 = coldata.Vertices.GetArrayData().Elements[coldata.Indices16.GetArrayData().Elements[i * 4 + 1].data];
                    var vert2 = coldata.Vertices.GetArrayData().Elements[coldata.Indices16.GetArrayData().Elements[i * 4 + 2].data];
                    verts.Add(new Vector3(vert0.Vector.X, vert0.Vector.Y, vert0.Vector.Z));
                    verts.Add(new Vector3(vert1.Vector.X, vert1.Vector.Y, vert1.Vector.Z));
                    verts.Add(new Vector3(vert2.Vector.X, vert2.Vector.Y, vert2.Vector.Z));
                    indices.Add(i * 3);
                    indices.Add(i * 3 + 1);
                    indices.Add(i * 3 + 2);
                }

                var mesh = new Mesh();
                mesh.indexFormat  = UnityEngine.Rendering.IndexFormat.UInt32;
                mesh.subMeshCount = 1;
                mesh.SetVertices(verts);
                mesh.SetTriangles(indices.ToArray(), 0, true);
                mesh.RecalculateNormals();
                mesh.RecalculateBounds();

                AssetDatabase.CreateAsset(mesh, assetName + "/" + Path.GetFileNameWithoutExtension(assetName) + "_" + index + ".mesh");

                // Setup a game object asset
                GameObject obj = new GameObject(Path.GetFileNameWithoutExtension(assetName) + $@"_{index}");
                obj.AddComponent <MeshFilter>();
                obj.AddComponent <MeshRenderer>();
                obj.GetComponent <MeshFilter>().mesh       = mesh;
                obj.GetComponent <MeshRenderer>().material = AssetDatabase.LoadAssetAtPath <Material>("Assets/dstools/Materials/CollisionMeshMaterial.mat");
                obj.transform.parent = root.transform;

                index++;
            }
        }

        PrefabUtility.SaveAsPrefabAsset(root, assetName + ".prefab");
        Object.DestroyImmediate(root);
    }
示例#2
0
            public override void Read(HKX hkx, HKXSection section, BinaryReaderEx br, HKXVariation variation)
            {
                SectionOffset = (uint)br.Position;

                AssertPointer(hkx, br);
                AssertPointer(hkx, br);
                AssertPointer(hkx, br);
                AssertPointer(hkx, br);
                TransformTrackToBoneIndices  = new HKArray <HKShort>(hkx, section, this, br, variation);
                FloatTrackToFloatSlotIndices = new HKArray <HKShort>(hkx, section, this, br, variation);


                if (variation != HKXVariation.HKXDS1)
                {
                    //PartitionIndices = new HKArray<HKShort>(hkx, section, this, br, variation);
                    PartitionIndices = new HKArray <HKShort>(hkx, section, this, br, variation);
                    BlendHint        = br.ReadEnum32 <AnimationBlendHint>();
                }
                else
                {
                    BlendHint            = br.ReadEnum32 <AnimationBlendHint>();
                    OriginalSkeletonName = br.ReadShiftJIS();
                    br.Pad(16);
                }

                br.Pad(16);

                DataSize = (uint)br.Position - SectionOffset;
                ResolveDestinations(hkx, section);
            }
        bool IResource._Load(string file, AccessLevel al, GameType type)
        {
            if (type == GameType.Bloodborne)
            {
                Hkx = HKX.Read(file, HKX.HKXVariation.HKXBloodBorne);
            }
            else if (type == GameType.DarkSoulsIII)
            {
                DCX.Type t;
                var      decomp = DCX.Decompress(file, out t);
                var      br     = new BinaryReaderEx(false, decomp);
                var      des    = new HKX2.PackFileDeserializer();
                Hkx2 = (hkRootLevelContainer)des.Deserialize(br);
            }
            else
            {
                Hkx = HKX.Read(file);
            }

            if (type == GameType.DarkSoulsIISOTFS || type == GameType.DarkSoulsIII || type == GameType.Bloodborne)
            {
                FrontFace = FrontFace.Clockwise;
            }
            else
            {
                FrontFace = FrontFace.CounterClockwise;
            }

            if (type == GameType.DarkSoulsIII)
            {
                return(LoadInternalNew(al));
            }
            return(LoadInternal(al));
        }
示例#4
0
 public override void Read(HKX hkx, HKXSection section, HKXObject source, BinaryReaderEx br, HKXVariation variation)
 {
     Position = new HKVector4();
     Position.Read(hkx, section, source, br, variation);
     Rotation = new HKVector4();
     Rotation.Read(hkx, section, source, br, variation);
     Scale = new HKVector4();
     Scale.Read(hkx, section, source, br, variation);
 }
示例#5
0
 public override void Read(HKX hkx, HKXSection section, HKXObject source, BinaryReaderEx br, HKXVariation variation)
 {
     //AssertPointer(hkx, br);
     //br.ReadUInt64s(1); // blah
     Name            = new HKCString(hkx, section, source, br, variation);
     LockTranslation = br.ReadInt32();
     if (variation != HKXVariation.HKXDS1)
     {
         br.ReadInt32(); // Padding?
     }
 }
 public void Write(HKX hkx, HKXSection section, BinaryWriterEx bw, uint sectionBaseOffset, HKX.HKXVariation variation)
 {
     foreach (var cls in ClassNames)
     {
         cls.Write(bw);
     }
     while ((bw.Position % 16) != 0)
     {
         // Write padding bytes to 16 byte align
         bw.WriteByte(0xFF);
     }
 }
示例#7
0
        private static Dictionary <string, HavokBoneMeme> LoadBonesFromHKX2010(string hkxName)
        {
            var hkx = HKX.Read(hkxName, HKX.HKXVariation.HKXDS1, isDS1RAnimHotfix: false);

            var result = new Dictionary <string, HavokBoneMeme>();

            foreach (var obj in hkx.DataSection.Objects)
            {
                if (obj is HKX.HKASkeleton skelington)
                {
                    List <string> boneNames = new List <string>();

                    foreach (var bone in skelington.Bones.GetArrayData().Elements)
                    {
                        var n = bone.Name.GetString();
                        result.Add(n, new HavokBoneMeme());
                        boneNames.Add(n);
                    }

                    var skelingtonTransf = skelington.Transforms.GetArrayData().Elements;

                    for (int i = 0; i < skelingtonTransf.Count; i++)
                    {
                        result[boneNames[i]].ReferenceTransform.Translation = skelingtonTransf[i].Position.Vector.ToVector3();

                        result[boneNames[i]].ReferenceTransform.Scale = skelingtonTransf[i].Scale.Vector.ToVector3();

                        result[boneNames[i]].ReferenceTransform.Rotation = skelingtonTransf[i].Rotation.Vector.ToQuat();
                    }

                    var skelingtonParentIndices = skelington.ParentIndices.GetArrayData().Elements;

                    for (int i = 0; i < skelingtonParentIndices.Count; i++)
                    {
                        var parentIndex = skelingtonParentIndices[i].data;
                        result[boneNames[i]].Parent = parentIndex >= 0 ? boneNames[parentIndex] : null;
                    }

                    foreach (var kvp in result)
                    {
                        if (kvp.Value.Parent != null)
                        {
                            if (!result[kvp.Value.Parent].Children.Contains(kvp.Key))
                            {
                                result[kvp.Value.Parent].Children.Add(kvp.Key);
                            }
                        }
                    }
                }
            }

            return(result);
        }
示例#8
0
        private static ModelDataType GetModelDataType(byte[] fileContents)
        {
            if (FLVER2.Is(fileContents))
            {
                return(ModelDataType.Flver);
            }

            if (HKX.Is(fileContents))
            {
                return(ModelDataType.Hkx);
            }

            return(ModelDataType.Unk);
        }
        private bool LoadInternalNew(AccessLevel al)
        {
            if (al == AccessLevel.AccessFull || al == AccessLevel.AccessGPUOptimizedOnly)
            {
                Bounds = new BoundingBox();
                var  submeshes = new List <CollisionSubmesh>();
                bool first     = true;
                if (Hkx2.m_namedVariants.Count == 0)
                {
                    // Yes this happens for some cols wtf From???
                    return(false);
                }
                var physicsscene = (hknpPhysicsSceneData)Hkx2.m_namedVariants[0].m_variant;

                foreach (var bodyInfo in physicsscene.m_systemDatas[0].m_bodyCinfos)
                {
                    var ncol = (HKX2.fsnpCustomParamCompressedMeshShape)bodyInfo.m_shape;
                    try
                    {
                        var mesh = new CollisionSubmesh();
                        ProcessMesh(ncol, bodyInfo, mesh);
                        if (first)
                        {
                            Bounds = mesh.Bounds;
                            first  = false;
                        }
                        else
                        {
                            Bounds = BoundingBox.Combine(Bounds, mesh.Bounds);
                        }
                        submeshes.Add(mesh);
                    }
                    catch (Exception e)
                    {
                        // Debug failing cases later
                    }
                }

                GPUMeshes = submeshes.ToArray();
            }

            if (al == AccessLevel.AccessGPUOptimizedOnly)
            {
                Hkx = null;
            }
            return(true);
        }
示例#10
0
            public override void Read(HKX hkx, HKXSection section, BinaryReaderEx br, HKXVariation variation)
            {
                SectionOffset = (uint)br.Position;

                AssertPointer(hkx, br);

                if (variation == HKXVariation.HKXBloodBorne)
                {
                    br.AssertInt32(0);
                }
                else
                {
                    AssertPointer(hkx, br);
                }

                AnimationType       = br.ReadEnum32 <AnimationType>();
                Duration            = br.ReadSingle();
                TransformTrackCount = br.ReadInt32();
                FloatTrackCount     = br.ReadInt32();

                if (variation == HKXVariation.HKXBloodBorne)
                {
                    br.Pad(16);
                }

                if (variation == HKXVariation.HKXDS1)
                {
                    br.ReadInt64s(2); // Annotations
                }
                else
                {
                    // Literally guessing here
                    br.ReadInt64s(3); // Annotations
                    //br.ReadUInt32(); // padding?
                }

                Transforms = new HKArray <Transform>(hkx, section, this, br, variation);
                Floats     = new HKArray <HKFloat>(hkx, section, this, br, variation);

                DataSize = (uint)br.Position - SectionOffset;
                ResolveDestinations(hkx, section);
            }
        bool IResource._Load(string file, AccessLevel al, GameType type)
        {
            if (type == GameType.Bloodborne)
            {
                Hkx = HKX.Read(file, HKX.HKXVariation.HKXBloodBorne);
            }
            else
            {
                Hkx = HKX.Read(file);
            }

            if (type == GameType.DarkSoulsIISOTFS || type == GameType.DarkSoulsIII || type == GameType.Bloodborne)
            {
                FrontFace = FrontFace.Clockwise;
            }
            else
            {
                FrontFace = FrontFace.CounterClockwise;
            }
            return(LoadInternal(al));
        }
示例#12
0
            public override void Read(HKX hkx, HKXSection section, BinaryReaderEx br, HKXVariation variation)
            {
                SectionOffset = (uint)br.Position;

                AssertPointer(hkx, br);
                AssertPointer(hkx, br);

                //br.ReadUInt64s(1); // Name
                Name            = new HKCString(hkx, section, this, br, variation);
                ParentIndices   = new HKArray <HKShort>(hkx, section, this, br, variation);
                Bones           = new HKArray <Bone>(hkx, section, this, br, variation);
                Transforms      = new HKArray <Transform>(hkx, section, this, br, variation);
                ReferenceFloats = new HKArray <HKFloat>(hkx, section, this, br, variation);
                br.ReadUInt64s(2); // unused array
                br.ReadUInt64s(2); // unused array
                br.ReadUInt64s(2); // unused array
                br.ReadUInt64s(2); // unused array
                br.ReadUInt64s(1); // padding

                DataSize = (uint)br.Position - SectionOffset;
                ResolveDestinations(hkx, section);
            }
示例#13
0
        public Model(HKX hkx)
        {
            Type = ModelType.ModelTypeCollision;

            Submeshes = new List <FlverSubmeshRenderer>();
            var subBoundsPoints = new List <Vector3>();

            foreach (var col in hkx.DataSection.Objects)
            {
                if (col is HKX.FSNPCustomParamCompressedMeshShape)
                {
                    var smm = new FlverSubmeshRenderer(this, hkx, (HKX.FSNPCustomParamCompressedMeshShape)col);
                    Submeshes.Add(smm);
                    subBoundsPoints.Add(smm.Bounds.Min);
                    subBoundsPoints.Add(smm.Bounds.Max);
                }

                if (col is HKX.HKPStorageExtendedMeshShapeMeshSubpartStorage)
                {
                    var smm = new FlverSubmeshRenderer(this, hkx, (HKX.HKPStorageExtendedMeshShapeMeshSubpartStorage)col);
                    Submeshes.Add(smm);
                    subBoundsPoints.Add(smm.Bounds.Min);
                    subBoundsPoints.Add(smm.Bounds.Max);
                }
            }

            if (Submeshes.Count == 0)
            {
                Bounds    = new BoundingBox();
                IsVisible = false;
            }
            else
            {
                Bounds = BoundingBox.CreateFromPoints(subBoundsPoints);
            }
        }
示例#14
0
            public override void Read(HKX hkx, HKXSection section, BinaryReaderEx br, HKXVariation variation)
            {
                SectionOffset = (uint)br.Position;

                AssertPointer(hkx, br);
                AssertPointer(hkx, br);

                if (variation != HKXVariation.HKXBloodBorne)
                {
                    AssertPointer(hkx, br);
                    AssertPointer(hkx, br);
                }

                Up.X = br.ReadSingle();
                Up.Y = br.ReadSingle();
                Up.Z = br.ReadSingle();
                Up.W = br.ReadSingle();

                Forward.X = br.ReadSingle();
                Forward.Y = br.ReadSingle();
                Forward.Z = br.ReadSingle();
                Forward.W = br.ReadSingle();

                Duration = br.ReadSingle();

                if (variation != HKXVariation.HKXDS1)
                {
                    br.AssertInt32(0); // probably padding
                }
                ReferenceFrameSamples = new HKArray <HKVector4>(hkx, section, this, br, variation);

                br.Pad(16); // probably

                DataSize = (uint)br.Position - SectionOffset;
                ResolveDestinations(hkx, section);
            }
        private bool LoadInternal(AccessLevel al)
        {
            if (al == AccessLevel.AccessFull || al == AccessLevel.AccessGPUOptimizedOnly)
            {
                Bounds = new BoundingBox();
                var  submeshes = new List <CollisionSubmesh>();
                bool first     = true;
                foreach (var obj in Hkx.DataSection.Objects)
                {
                    if (obj is HKX.HKPStorageExtendedMeshShapeMeshSubpartStorage col)
                    {
                        var mesh = new CollisionSubmesh();
                        ProcessMesh(col, mesh);
                        if (first)
                        {
                            Bounds = mesh.Bounds;
                            first  = false;
                        }
                        else
                        {
                            Bounds = BoundingBox.Combine(Bounds, mesh.Bounds);
                        }
                        submeshes.Add(mesh);
                    }
                    if (obj is HKX.FSNPCustomParamCompressedMeshShape ncol)
                    {
                        // Find a body data for this
                        HKX.HKNPBodyCInfo bodyInfo = null;
                        foreach (var scene in Hkx.DataSection.Objects)
                        {
                            if (scene is HKX.HKNPPhysicsSystemData)
                            {
                                var sys = (HKX.HKNPPhysicsSystemData)scene;
                                foreach (HKX.HKNPBodyCInfo info in sys.Bodies.GetArrayData().Elements)
                                {
                                    if (info.ShapeReference.DestObject == ncol)
                                    {
                                        bodyInfo = info;
                                        break;
                                    }
                                }
                                break;
                            }

                            try
                            {
                                var mesh = new CollisionSubmesh();
                                ProcessMesh(ncol, bodyInfo, mesh);
                                if (first)
                                {
                                    Bounds = mesh.Bounds;
                                    first  = false;
                                }
                                else
                                {
                                    Bounds = BoundingBox.Combine(Bounds, mesh.Bounds);
                                }
                                submeshes.Add(mesh);
                            }
                            catch (Exception e)
                            {
                                // Debug failing cases later
                            }
                        }
                    }
                    //Bounds = BoundingBox.CreateMerged(Bounds, GPUMeshes[i].Bounds);
                }
                GPUMeshes = submeshes.ToArray();
            }

            if (al == AccessLevel.AccessGPUOptimizedOnly)
            {
                Hkx = null;
            }
            return(true);
        }
示例#16
0
    public static void ImportDS3CollisionHKX(HKX hkx, string assetName)
    {
        var verts   = new List <Vector3>();
        var normals = new List <Vector3>();
        var indices = new List <int>();

        foreach (var col in hkx.DataSection.Objects)
        {
            if (col is HKX.FSNPCustomParamCompressedMeshShape)
            {
                // Find a body data for this
                HKX.HKNPBodyCInfo bodyInfo = null;
                foreach (var scene in hkx.DataSection.Objects)
                {
                    if (scene is HKX.HKNPPhysicsSystemData)
                    {
                        var sys = (HKX.HKNPPhysicsSystemData)scene;
                        foreach (HKX.HKNPBodyCInfo info in sys.Bodies.GetArrayData().Elements)
                        {
                            if (info.ShapeReference.DestObject == col)
                            {
                                bodyInfo = info;
                                break;
                            }
                        }
                        break;
                    }
                }

                var meshdata = (HKX.FSNPCustomParamCompressedMeshShape)col;
                var coldata  = meshdata.GetMeshShapeData();

                foreach (var chunk in coldata.Chunks.GetArrayData().Elements)
                {
                    for (int i = 0; i < chunk.ByteIndicesLength; i++)
                    {
                        var tri = coldata.MeshIndices.GetArrayData().Elements[i + chunk.ByteIndicesIndex];
                        //if (tri.Idx2 == tri.Idx3 && tri.Idx1 != tri.Idx2)
                        //{
                        if (tri.Idx0 < chunk.VertexIndicesLength)
                        {
                            ushort index = (ushort)((uint)tri.Idx0 + chunk.SmallVerticesBase);
                            indices.Add(verts.Count);

                            var vert = coldata.SmallVertices.GetArrayData().Elements[index].Decompress(chunk.SmallVertexScale, chunk.SmallVertexOffset);
                            verts.Add(TransformVert(vert, bodyInfo));
                        }
                        else
                        {
                            ushort index = (ushort)(coldata.VertexIndices.GetArrayData().Elements[tri.Idx0 + chunk.VertexIndicesIndex - chunk.VertexIndicesLength].data);
                            indices.Add(verts.Count);

                            var vert = coldata.LargeVertices.GetArrayData().Elements[index].Decompress(coldata.BoundingBoxMin, coldata.BoundingBoxMax);
                            verts.Add(TransformVert(vert, bodyInfo));
                        }

                        if (tri.Idx1 < chunk.VertexIndicesLength)
                        {
                            ushort index = (ushort)((uint)tri.Idx1 + chunk.SmallVerticesBase);
                            indices.Add(verts.Count);

                            var vert = coldata.SmallVertices.GetArrayData().Elements[index].Decompress(chunk.SmallVertexScale, chunk.SmallVertexOffset);
                            verts.Add(TransformVert(vert, bodyInfo));
                        }
                        else
                        {
                            ushort index = (ushort)(coldata.VertexIndices.GetArrayData().Elements[tri.Idx1 + chunk.VertexIndicesIndex - chunk.VertexIndicesLength].data);
                            indices.Add(verts.Count);

                            var vert = coldata.LargeVertices.GetArrayData().Elements[index].Decompress(coldata.BoundingBoxMin, coldata.BoundingBoxMax);
                            verts.Add(TransformVert(vert, bodyInfo));
                        }

                        if (tri.Idx2 < chunk.VertexIndicesLength)
                        {
                            ushort index = (ushort)((uint)tri.Idx2 + chunk.SmallVerticesBase);
                            indices.Add(verts.Count);

                            var vert = coldata.SmallVertices.GetArrayData().Elements[index].Decompress(chunk.SmallVertexScale, chunk.SmallVertexOffset);
                            verts.Add(TransformVert(vert, bodyInfo));
                        }
                        else
                        {
                            ushort index = (ushort)(coldata.VertexIndices.GetArrayData().Elements[tri.Idx2 + chunk.VertexIndicesIndex - chunk.VertexIndicesLength].data);
                            indices.Add(verts.Count);

                            var vert = coldata.LargeVertices.GetArrayData().Elements[index].Decompress(coldata.BoundingBoxMin, coldata.BoundingBoxMax);
                            verts.Add(TransformVert(vert, bodyInfo));
                        }

                        if (tri.Idx2 != tri.Idx3)
                        {
                            verts.Add(verts[verts.Count - 2]);
                            verts.Add(verts[verts.Count - 1]);
                            indices.Add(indices[indices.Count - 2]);
                            indices.Add(indices[indices.Count - 1]);
                            if (tri.Idx3 < chunk.VertexIndicesLength)
                            {
                                ushort index = (ushort)((uint)tri.Idx3 + chunk.SmallVerticesBase);
                                indices.Add(verts.Count);

                                var vert = coldata.SmallVertices.GetArrayData().Elements[index].Decompress(chunk.SmallVertexScale, chunk.SmallVertexOffset);
                                verts.Add(TransformVert(vert, bodyInfo));
                            }
                            else
                            {
                                ushort index = (ushort)(coldata.VertexIndices.GetArrayData().Elements[tri.Idx3 + chunk.VertexIndicesIndex - chunk.VertexIndicesLength].data);
                                indices.Add(verts.Count);

                                var vert = coldata.LargeVertices.GetArrayData().Elements[index].Decompress(coldata.BoundingBoxMin, coldata.BoundingBoxMax);
                                verts.Add(TransformVert(vert, bodyInfo));
                            }
                        }
                        //}
                    }
                }
            }
        }

        if (indices.Count == 0)
        {
            return;
        }

        var mesh = new Mesh();

        mesh.indexFormat  = UnityEngine.Rendering.IndexFormat.UInt32;
        mesh.subMeshCount = 1;
        mesh.SetVertices(verts);
        mesh.SetTriangles(indices.ToArray(), 0, true);
        mesh.RecalculateNormals();
        mesh.RecalculateBounds();

        AssetDatabase.CreateAsset(mesh, assetName + ".mesh");

        // Setup a game object asset
        GameObject obj = new GameObject(Path.GetFileNameWithoutExtension(assetName));

        obj.AddComponent <MeshFilter>();
        obj.AddComponent <MeshRenderer>();
        obj.GetComponent <MeshFilter>().mesh       = mesh;
        obj.GetComponent <MeshRenderer>().material = AssetDatabase.LoadAssetAtPath <Material>("Assets/dstools/Materials/CollisionMeshMaterial.mat");

        PrefabUtility.SaveAsPrefabAsset(obj, assetName + ".prefab");
        Object.DestroyImmediate(obj);
    }
示例#17
0
 public override void Write(HKX hkx, HKXSection section, BinaryWriterEx bw, uint sectionBaseOffset, HKXVariation variation)
 {
     throw new NotImplementedException();
 }
示例#18
0
    public static void ImportNavimeshHKX(HKX hkx, string assetName)
    {
        NavMesh                      nm       = ScriptableObject.CreateInstance <NavMesh>();
        List <NavMesh.Edge>          edges    = new List <NavMesh.Edge>();
        List <NavMesh.Face>          faces    = new List <NavMesh.Face>();
        List <Vector3>               vertices = new List <Vector3>();
        List <NavMesh.CostGraphNode> cgnodes  = new List <NavMesh.CostGraphNode>();
        List <NavMesh.CostGraphEdge> cgedges  = new List <NavMesh.CostGraphEdge>();

        foreach (var cl in hkx.DataSection.Objects)
        {
            if (cl is HKX.HKAINavMesh)
            {
                var mesh = (HKX.HKAINavMesh)cl;
                foreach (var f in mesh.Faces.GetArrayData().Elements)
                {
                    var face = new NavMesh.Face();
                    face.StartEdgeIndex = f.StartEdgeIndex;
                    face.EdgeCount      = f.NumEdges;
                    faces.Add(face);
                }
                foreach (var e in mesh.Edges.GetArrayData().Elements)
                {
                    var edge = new NavMesh.Edge();
                    edge.A = e.A;
                    edge.B = e.B;
                    edges.Add(edge);
                }
                foreach (var v in mesh.Vertices.GetArrayData().Elements)
                {
                    vertices.Add(new Vector3(v.Vector.X, v.Vector.Y, v.Vector.Z));
                }
                nm.Faces    = faces.ToArray();
                nm.Edges    = edges.ToArray();
                nm.Vertices = vertices.ToArray();
                continue;
            }
            else if (cl is HKX.HKCDStaticAABBTreeStorage)
            {
                var tree     = (HKX.HKCDStaticAABBTreeStorage)cl;
                var nodes    = tree.CompressedTree.GetArrayData().Elements;
                var unpacked = new NavMesh.AABBTreeNode[nodes.Count];
                for (uint i = 0; i < unpacked.Length; i++)
                {
                    unpacked[i]    = new NavMesh.AABBTreeNode();
                    unpacked[i].id = i;
                }
                unpacked[0].Min = new Vector3(tree.AABBMin.X, tree.AABBMin.Y, tree.AABBMin.Z);
                unpacked[0].Max = new Vector3(tree.AABBMax.X, tree.AABBMax.Y, tree.AABBMax.Z);
                // Propogate the decompression down the tree
                for (uint i = 0; i < unpacked.Length; i++)
                {
                    var cnode = nodes[(int)i];
                    if ((cnode.IDX0 & 0x80) > 0)
                    {
                        uint left  = i + 1;
                        uint right = i + ((((uint)cnode.IDX0 & 0x7F) << 8) | (uint)cnode.IDX1) * 2;
                        unpacked[(int)left].Min  = nodes[(int)left].DecompressMin(unpacked[i].Min, unpacked[i].Max);
                        unpacked[(int)left].Max  = nodes[(int)left].DecompressMax(unpacked[i].Min, unpacked[i].Max);
                        unpacked[(int)right].Min = nodes[(int)right].DecompressMin(unpacked[i].Min, unpacked[i].Max);
                        unpacked[(int)right].Max = nodes[(int)right].DecompressMax(unpacked[i].Min, unpacked[i].Max);
                        unpacked[i].Left         = (int)left;
                        unpacked[i].Right        = (int)right;
                        unpacked[i].IsTerminal   = false;
                    }
                    else
                    {
                        unpacked[i].IsTerminal = true;
                        unpacked[i].Left       = -1;
                        unpacked[i].Right      = -1;
                        unpacked[i].Index      = (((uint)cnode.IDX0 & 0x7F) << 8) | (uint)cnode.IDX1;
                    }
                }
                nm.AABBTree = unpacked;
            }
            else if (cl is HKX.HKAIDirectedGraphExplicitCost)
            {
                var graph = (HKX.HKAIDirectedGraphExplicitCost)cl;
                int i     = 0;
                foreach (var n in graph.Nodes.GetArrayData().Elements)
                {
                    var node = new NavMesh.CostGraphNode();
                    node.EdgeCount      = n.NumEdges;
                    node.StartEdgeIndex = n.StartEdgeIndex;
                    var pos = graph.Positions.GetArrayData().Elements[i].Vector;
                    node.Position = new Vector3(pos.X, pos.Y, pos.Z);
                    cgnodes.Add(node);
                    i++;
                }
                foreach (var e in graph.Edges.GetArrayData().Elements)
                {
                    var edge = new NavMesh.CostGraphEdge();
                    edge.Flags      = e.Flags;
                    edge.TargetNode = e.TargetNode;
                    var floatbytes = BitConverter.GetBytes(((uint)e.Cost) << 16);
                    edge.Cost = BitConverter.ToSingle(floatbytes, 0);
                    cgedges.Add(edge);
                }
                nm.CostGraphEdges = cgedges.ToArray();
                nm.CostGraphNodes = cgnodes.ToArray();
            }
        }
        AssetDatabase.CreateAsset(nm, assetName + ".asset");
    }
示例#19
0
            public override void Read(HKX hkx, HKXSection section, BinaryReaderEx br, HKXVariation variation)
            {
                SectionOffset = (uint)br.Position;

                AssertPointer(hkx, br);

                if (variation == HKXVariation.HKXBloodBorne)
                {
                    br.AssertInt32(0);
                }
                else
                {
                    AssertPointer(hkx, br);
                }

                AnimationType       = br.ReadEnum32 <AnimationType>();
                Duration            = br.ReadSingle();
                TransformTrackCount = br.ReadInt32();
                FloatTrackCount     = br.ReadInt32();

                if (variation == HKXVariation.HKXBloodBorne)
                {
                    br.Pad(16);
                }

                if (variation == HKXVariation.HKXDS1)
                {
                    br.ReadInt64s(2); // Annotations

                    FrameCount = br.ReadInt32();
                    BlockCount = br.ReadInt32();

                    FramesPerBlock       = br.ReadInt32();
                    MaskAndQuantization  = br.ReadUInt32();
                    BlockDuration        = br.ReadSingle();
                    InverseBlockDuration = br.ReadSingle();
                    FrameDuration        = br.ReadSingle();
                }
                else
                {
                    br.ReadInt64s(3); // Annotations

                    FrameCount           = br.ReadInt32();
                    BlockCount           = br.ReadInt32();
                    FramesPerBlock       = br.ReadInt32();
                    MaskAndQuantization  = br.ReadUInt32();
                    BlockDuration        = br.ReadSingle();
                    InverseBlockDuration = br.ReadSingle();
                    FrameDuration        = br.ReadSingle();
                    br.ReadUInt32(); // padding?
                }

                BlockOffsets          = new HKArray <HKUInt>(hkx, section, this, br, variation);
                FloatBlockOffsets     = new HKArray <HKUInt>(hkx, section, this, br, variation);
                TransformBlockOffsets = new HKArray <HKUInt>(hkx, section, this, br, variation);
                FloatOffsets          = new HKArray <HKUInt>(hkx, section, this, br, variation);
                Data   = new HKArray <HKByte>(hkx, section, this, br, variation);
                Endian = br.ReadInt32();

                DataSize = (uint)br.Position - SectionOffset;
                ResolveDestinations(hkx, section);
            }
        private byte[] ImportAnimToHKX()
        {
            var importedAnim = ImportAnim();

            byte[] finalHkxDataToImport = null;

            var compressed2010Hkx = importedAnim.WriteToSplineCompressedHKX2010Bytes(ImportConfig.RotationQuantizationType, ImportConfig.RotationTolerance);

            if (GameDataManager.GameType == SoulsAssetPipeline.SoulsGames.DS1R)
            {
                finalHkxDataToImport = HavokDowngrade.UpgradeHkx2010to2015(compressed2010Hkx);
            }
            else if (GameDataManager.GameType == SoulsAssetPipeline.SoulsGames.DS1)
            {
                finalHkxDataToImport = compressed2010Hkx;
            }
            else if (GameDataManager.GameType == SoulsAssetPipeline.SoulsGames.DS3)
            {
                HKX.HKAAnimationBinding          hk_binding = null;
                HKX.HKASplineCompressedAnimation hk_anim    = null;
                HKX.HKASkeleton hk_skeleton = null;
                HKX.HKADefaultAnimatedReferenceFrame hk_refFrame = null;

                var hkx = HKX.Read(compressed2010Hkx);

                foreach (var o in hkx.DataSection.Objects)
                {
                    if (o is HKX.HKASkeleton asSkeleton)
                    {
                        hk_skeleton = asSkeleton;
                    }
                    else if (o is HKX.HKAAnimationBinding asBinding)
                    {
                        hk_binding = asBinding;
                    }
                    else if (o is HKX.HKASplineCompressedAnimation asAnim)
                    {
                        hk_anim = asAnim;
                    }
                    else if (o is HKX.HKADefaultAnimatedReferenceFrame asRefFrame)
                    {
                        hk_refFrame = asRefFrame;
                    }
                }

                var root = new HKX2.hkRootLevelContainer();

                var animBinding = new HKX2.hkaAnimationBinding();

                var anim = new HKX2.hkaSplineCompressedAnimation();

                animBinding.m_animation                    = anim;
                animBinding.m_originalSkeletonName         = hk_binding.OriginalSkeletonName;
                animBinding.m_transformTrackToBoneIndices  = hk_binding.TransformTrackToBoneIndices.GetArrayData().Elements.Select(x => x.data).ToList();
                animBinding.m_floatTrackToFloatSlotIndices = new List <short>();
                animBinding.m_partitionIndices             = new List <short>();
                animBinding.m_blendHint                    = (HKX2.BlendHint)(int) hk_binding.BlendHint;

                anim.m_blockDuration        = hk_anim.BlockDuration;
                anim.m_blockInverseDuration = hk_anim.InverseBlockDuration;
                anim.m_data     = hk_anim.Data.GetArrayData().Elements.Select(x => x.data).ToList();
                anim.m_duration = hk_anim.Duration;
                anim.m_endian   = hk_anim.Endian;

                if (hk_refFrame != null)
                {
                    var rootMotion = new HKX2.hkaDefaultAnimatedReferenceFrame();

                    rootMotion.m_duration = hk_refFrame.Duration;
                    rootMotion.m_forward  = hk_refFrame.Forward;
                    rootMotion.m_referenceFrameSamples = new List <System.Numerics.Vector4>();
                    foreach (var rf in hk_refFrame.ReferenceFrameSamples.GetArrayData().Elements)
                    {
                        rootMotion.m_referenceFrameSamples.Add(rf.Vector);
                    }
                    rootMotion.m_up = hk_refFrame.Up;

                    anim.m_extractedMotion = rootMotion;
                }

                anim.m_frameDuration           = hk_anim.FrameDuration;
                anim.m_maskAndQuantizationSize = (int)hk_anim.MaskAndQuantization;
                anim.m_maxFramesPerBlock       = hk_anim.FramesPerBlock;
                anim.m_numberOfFloatTracks     = hk_anim.FloatTrackCount;
                anim.m_numberOfTransformTracks = hk_anim.TransformTrackCount;
                anim.m_numBlocks         = hk_anim.BlockCount;
                anim.m_numFrames         = hk_anim.FrameCount;
                anim.m_floatBlockOffsets = hk_anim.FloatBlockOffsets.GetArrayData().Elements.Select(b => b.data).ToList();
                anim.m_type             = HKX2.AnimationType.HK_SPLINE_COMPRESSED_ANIMATION;
                anim.m_blockOffsets     = hk_anim.BlockOffsets.GetArrayData().Elements.Select(b => b.data).ToList();
                anim.m_floatOffsets     = new List <uint>();
                anim.m_transformOffsets = new List <uint>();

                //TODO: IMPLEMENT ANNOTATION TRACK READ IN LEGACY HKX TO TRANSFER IT TO HKX2

                //anim.m_annotationTracks = new List<HKX2.hkaAnnotationTrack>();
                //for (int i = 0; i < hk_anim.TransformTrackCount; i++)
                //{
                //    var boneIndex = animBinding.m_transformTrackToBoneIndices[i];
                //    string boneName = boneNames[boneIndex];

                //    anim.m_annotationTracks.Add(new HKX2.hkaAnnotationTrack()
                //    {
                //        m_trackName = boneName,
                //        m_annotations = new List<HKX2.hkaAnnotationTrackAnnotation>(),
                //    });
                //}



                var animContainer = new HKX2.hkaAnimationContainer();

                animContainer.m_attachments = new List <HKX2.hkaBoneAttachment>();
                animContainer.m_skins       = new List <HKX2.hkaMeshBinding>();
                animContainer.m_skeletons   = new List <HKX2.hkaSkeleton>();

                animContainer.m_animations = new List <HKX2.hkaAnimation>();
                animContainer.m_animations.Add(anim);

                animContainer.m_bindings = new List <HKX2.hkaAnimationBinding>();
                animContainer.m_bindings.Add(animBinding);

                root.m_namedVariants = new List <HKX2.hkRootLevelContainerNamedVariant>();
                root.m_namedVariants.Add(new HKX2.hkRootLevelContainerNamedVariant()
                {
                    m_className = "hkaAnimationContainer",
                    m_name      = "Merged Animation Container",
                    m_variant   = animContainer
                });

                using (MemoryStream s2 = new MemoryStream())
                {
                    BinaryWriterEx bw = new BinaryWriterEx(false, s2);
                    var            s  = new HKX2.PackFileSerializer();
                    s.Serialize(root, bw);

                    finalHkxDataToImport = s2.ToArray();
                }
            }

            return(finalHkxDataToImport);
        }
        public FlverSubmeshRenderer(Model parent, HKX colhkx, HKX.HKPStorageExtendedMeshShapeMeshSubpartStorage meshdata)
        {
            Parent = parent;

            var vertices = new VertexPositionColorNormalTangentTexture[(meshdata.Indices16.Size / 4) * 3];

            //for (int i = 0; i < meshdata.Vertices.Size; i++)
            //{
            //    var vert = meshdata.Vertices.GetArrayData().Elements[i];
            //    vertices[i] = new VertexPositionColorNormalTangentTexture();
            //    vertices[i].Position = new Vector3(vert.Vector.X, vert.Vector.Y, vert.Vector.Z);
            //}

            MeshFacesets = new List <FlverSubmeshRendererFaceSet>();
            List <ushort> indices = new List <ushort>();
            int           j       = 0;

            for (var index = 0; index < meshdata.Indices16.Size / 4; index++)
            {
                var idx  = meshdata.Indices16.GetArrayData().Elements;
                var vtxs = meshdata.Vertices.GetArrayData().Elements;

                var vert1 = vtxs[idx[index * 4].data].Vector;
                var vert2 = vtxs[idx[index * 4 + 1].data].Vector;
                var vert3 = vtxs[idx[index * 4 + 2].data].Vector;

                vertices[index * 3].Position     = new Vector3(vert1.X, vert1.Y, vert1.Z);
                vertices[index * 3 + 1].Position = new Vector3(vert2.X, vert2.Y, vert2.Z);
                vertices[index * 3 + 2].Position = new Vector3(vert3.X, vert3.Y, vert3.Z);

                Vector3 a = new Vector3(vert2.X - vert1.X, vert2.Y - vert1.Y, vert2.Z - vert1.Z);
                Vector3 b = new Vector3(vert3.X - vert1.X, vert3.Y - vert1.Y, vert3.Z - vert1.Z);

                Vector3 normal = Vector3.Cross(a, b);
                normal.Normalize();

                vertices[index * 3].Normal     = normal;
                vertices[index * 3 + 1].Normal = normal;
                vertices[index * 3 + 2].Normal = normal;

                a.Normalize();
                vertices[index * 3].Tangent     = a;
                vertices[index * 3 + 1].Tangent = a;
                vertices[index * 3 + 2].Tangent = a;

                vertices[index * 3].Binormal     = Vector3.Cross(normal, a);
                vertices[index * 3 + 1].Binormal = Vector3.Cross(normal, a);
                vertices[index * 3 + 2].Binormal = Vector3.Cross(normal, a);

                indices.Add((ushort)(index * 3));
                indices.Add((ushort)(index * 3 + 1));
                indices.Add((ushort)(index * 3 + 2));
            }

            if (indices.Count > 0)
            {
                var newFaceSet = new FlverSubmeshRendererFaceSet()
                {
                    BackfaceCulling = false,
                    IsTriangleStrip = false,
                    IndexBuffer     = new IndexBuffer(
                        GFX.Device,
                        IndexElementSize.SixteenBits,
                        indices.Count,
                        BufferUsage.WriteOnly),
                    IndexCount = indices.Count,
                };

                newFaceSet.IndexBuffer.SetData(indices.Select(x => (ushort)x).ToArray());

                MeshFacesets.Add(newFaceSet);
            }
            else
            {
                vertices = new VertexPositionColorNormalTangentTexture[meshdata.Vertices.Size];

                for (int i = 0; i < meshdata.Vertices.Size; i++)
                {
                    var vert = meshdata.Vertices.GetArrayData().Elements[i];
                    vertices[i]          = new VertexPositionColorNormalTangentTexture();
                    vertices[i].Position = new Vector3(vert.Vector.X, vert.Vector.Y, vert.Vector.Z);
                }
            }

            Bounds = BoundingBox.CreateFromPoints(vertices.Select(x => x.Position));

            VertBuffer = new VertexBuffer(GFX.Device,
                                          typeof(VertexPositionColorNormalTangentTexture), vertices.Length, BufferUsage.WriteOnly);
            VertBuffer.SetData(vertices);

            VertBufferBinding = new VertexBufferBinding(VertBuffer, 0, 0);
        }
        // Used for collision rendering
        public FlverSubmeshRenderer(Model parent, HKX colhkx, HKX.FSNPCustomParamCompressedMeshShape meshdata)
        {
            Parent = parent;

            var coldata = meshdata.GetMeshShapeData();

            var tree = coldata.getMeshBVH();
            var box  = new DbgPrimWireBox(Transform.Default, Vector3.One, Color.Cyan);

            if (tree != null)
            {
                //DebugBVHDraw(tree, box);
            }

            var vertices = new VertexPositionColorNormalTangentTexture[coldata.SmallVertices.Size + coldata.LargeVertices.Size];

            /*for (int i = 0; i < coldata.SmallVertices.Size; i++)
             * {
             *  var vert = coldata.SmallVertices.GetArrayData().Elements[i].Decompress(coldata.BoundingBoxMin, coldata.BoundingBoxMax);
             *  vertices[i] = new VertexPositionColorNormalTangentTexture();
             *  vertices[i].Position = new Vector3(vert.X, vert.Y, vert.Z);
             * }*/

            var largebase = coldata.SmallVertices.Size;

            for (int i = 0; i < coldata.LargeVertices.Size; i++)
            {
                var vert = coldata.LargeVertices.GetArrayData().Elements[i].Decompress(coldata.BoundingBoxMin, coldata.BoundingBoxMax);
                vertices[i + largebase]          = new VertexPositionColorNormalTangentTexture();
                vertices[i + largebase].Position = new Vector3(vert.X, vert.Y, vert.Z);
            }

            MeshFacesets = new List <FlverSubmeshRendererFaceSet>();
            int ch = 0;

            foreach (var chunk in coldata.Chunks.GetArrayData().Elements)
            {
                /*if (ch != 1)
                 * {
                 *  ch++;
                 *  continue;
                 * }
                 * ch++;*/
                /*var tree2 = chunk.getChunkBVH();
                 * if (tree2 != null)
                 * {
                 *  DebugBVHDraw(tree2, box);
                 * }*/
                List <ushort> indices = new List <ushort>();
                for (int i = 0; i < chunk.ByteIndicesLength; i++)
                {
                    var tri = coldata.MeshIndices.GetArrayData().Elements[i + chunk.ByteIndicesIndex];
                    if (tri.Idx2 == tri.Idx3 && tri.Idx1 != tri.Idx2)
                    {
                        if (tri.Idx0 < chunk.VertexIndicesLength)
                        {
                            ushort index = (ushort)((uint)tri.Idx0 + chunk.SmallVerticesBase);
                            indices.Add(index);

                            var vert = coldata.SmallVertices.GetArrayData().Elements[index].Decompress(chunk.SmallVertexScale, chunk.SmallVertexOffset);
                            vertices[index]          = new VertexPositionColorNormalTangentTexture();
                            vertices[index].Position = new Vector3(vert.X, vert.Y, vert.Z);
                        }
                        else
                        {
                            indices.Add((ushort)(coldata.VertexIndices.GetArrayData().Elements[tri.Idx0 + chunk.VertexIndicesIndex - chunk.VertexIndicesLength].data + largebase));
                        }

                        if (tri.Idx1 < chunk.VertexIndicesLength)
                        {
                            ushort index = (ushort)((uint)tri.Idx1 + chunk.SmallVerticesBase);
                            indices.Add(index);

                            var vert = coldata.SmallVertices.GetArrayData().Elements[index].Decompress(chunk.SmallVertexScale, chunk.SmallVertexOffset);
                            vertices[index]          = new VertexPositionColorNormalTangentTexture();
                            vertices[index].Position = new Vector3(vert.X, vert.Y, vert.Z);
                        }
                        else
                        {
                            indices.Add((ushort)(coldata.VertexIndices.GetArrayData().Elements[tri.Idx1 + chunk.VertexIndicesIndex - chunk.VertexIndicesLength].data + largebase));
                        }

                        if (tri.Idx2 < chunk.VertexIndicesLength)
                        {
                            ushort index = (ushort)((uint)tri.Idx2 + chunk.SmallVerticesBase);
                            indices.Add(index);

                            var vert = coldata.SmallVertices.GetArrayData().Elements[index].Decompress(chunk.SmallVertexScale, chunk.SmallVertexOffset);
                            vertices[index]          = new VertexPositionColorNormalTangentTexture();
                            vertices[index].Position = new Vector3(vert.X, vert.Y, vert.Z);
                        }
                        else
                        {
                            indices.Add((ushort)(coldata.VertexIndices.GetArrayData().Elements[tri.Idx2 + chunk.VertexIndicesIndex - chunk.VertexIndicesLength].data + largebase));
                        }
                    }
                }

                if (indices.Count > 0)
                {
                    var newFaceSet = new FlverSubmeshRendererFaceSet()
                    {
                        BackfaceCulling = false,
                        IsTriangleStrip = false,
                        IndexBuffer     = new IndexBuffer(
                            GFX.Device,
                            IndexElementSize.SixteenBits,
                            indices.Count,
                            BufferUsage.WriteOnly),
                        IndexCount = indices.Count,
                    };

                    newFaceSet.IndexBuffer.SetData(indices.Select(x => (ushort)x).ToArray());

                    MeshFacesets.Add(newFaceSet);
                }
            }

            Bounds = BoundingBox.CreateFromPoints(vertices.Select(x => x.Position));

            VertBuffer = new VertexBuffer(GFX.Device,
                                          typeof(VertexPositionColorNormalTangentTexture), vertices.Length, BufferUsage.WriteOnly);
            VertBuffer.SetData(vertices);

            VertBufferBinding = new VertexBufferBinding(VertBuffer, 0, 0);
        }
示例#23
0
        private static void LoadRemoHKX(byte[] hkxBytes, string animName)
        {
            Scene.DisableModelDrawing();
            Scene.DisableModelDrawing2();

            HKX.HKAAnimationBinding          hk_binding = null;
            HKX.HKASplineCompressedAnimation hk_anim    = null;
            HKX.HKASkeleton hk_skeleton = null;

            if (remoCutsLoaded.ContainsKey(animName))
            {
                hk_binding  = remoCutsLoaded[animName].hk_binding;
                hk_anim     = remoCutsLoaded[animName].hk_anim;
                hk_skeleton = remoCutsLoaded[animName].hk_skeleton;
            }
            else
            {
                var hkx = HKX.Read(hkxBytes, HKX.HKXVariation.HKXDS1, false);

                foreach (var o in hkx.DataSection.Objects)
                {
                    if (o is HKX.HKASkeleton asSkeleton)
                    {
                        hk_skeleton = asSkeleton;
                    }
                    else if (o is HKX.HKAAnimationBinding asBinding)
                    {
                        hk_binding = asBinding;
                    }
                    else if (o is HKX.HKASplineCompressedAnimation asAnim)
                    {
                        hk_anim = asAnim;
                    }
                }

                remoCutsLoaded.Add(animName, new RemoCutCache()
                {
                    hk_binding  = hk_binding,
                    hk_anim     = hk_anim,
                    hk_skeleton = hk_skeleton,
                });
            }



            var animContainer = new NewAnimationContainer();

            AnimContainer = animContainer;

            animContainer.ClearAnimations();

            animContainer.Skeleton.LoadHKXSkeleton(hk_skeleton);

            var testIdleAnimThing = new NewHavokAnimation_SplineCompressed(animName,
                                                                           animContainer.Skeleton, null, hk_binding, hk_anim, animContainer);

            animContainer.AddNewAnimation(animName, testIdleAnimThing);

            animContainer.CurrentAnimationName = animName;

            var modelNames = animContainer.Skeleton.TopLevelHkxBoneIndices.Select(b => animContainer.Skeleton.HkxSkeleton[b].Name).ToList();

            CurrentCutHits.Clear();
            CurrentCutOtherBlocks.Clear();
            lock (Scene._lock_ModelLoad_Draw)
            {
                Scene.Models.Clear();
            }
            foreach (var name in modelNames)
            {
                Model mdl = null;

                if (!remoModelDict.ContainsKey(name))
                {
                    PauseStreamBGM();

                    if (name.StartsWith("c"))
                    {
                        string shortName = name.Substring(0, 5);
                        mdl = GameDataManager.LoadCharacter(shortName);
                        FmodManager.LoadInterrootFEV(shortName);

                        if (mdl.IS_PLAYER)
                        {
                            ViewportInteractor.InitializeCharacterModel(mdl, isRemo: true);
                        }
                    }
                    else if (name.StartsWith("o"))
                    {
                        string shortName = name.Substring(0, 5);
                        mdl = GameDataManager.LoadObject(shortName);
                        FmodManager.LoadInterrootFEV(shortName);
                    }
                    else if (name.StartsWith("m"))
                    {
                        mdl = GameDataManager.LoadMapPiece(AreaInt, BlockInt, 0, 0, int.Parse(name.Substring(1, 4)));
                    }
                    else if (name.StartsWith("A"))
                    {
                        int a = int.Parse(name.Substring(1, 2));
                        int b = int.Parse(name.Substring(4, 2));

                        if (b != BlockInt && !CurrentCutOtherBlocks.Contains(b))
                        {
                            CurrentCutOtherBlocks.Add(b);
                        }

                        mdl = GameDataManager.LoadMapPiece(a, b, 0, 0, int.Parse(name.Substring(8, 4)));
                    }
                    else if (name.StartsWith("d"))
                    {
                        // TODO
                        // Dummy entity e.g. 'd0000_0000'. Apparently just acts as a single DummyPoly?
                        mdl = GameDataManager.LoadCharacter("c1000");
                        mdl.RemoDummyTransformPrim =
                            new DebugPrimitives.DbgPrimWireArrow(name, new Transform(Microsoft.Xna.Framework.Matrix.CreateScale(0.25f)
                                                                                     * mdl.CurrentTransform.WorldMatrix), Microsoft.Xna.Framework.Color.Lime)
                        {
                            Category = DebugPrimitives.DbgPrimCategory.AlwaysDraw
                        };
                        mdl.RemoDummyTransformTextPrint = new StatusPrinter(null, Microsoft.Xna.Framework.Color.Lime);
                        mdl.RemoDummyTransformTextPrint.AppendLine(name);
                        mdl.IS_REMO_DUMMY = true;
                    }
                    else if (name.StartsWith("h"))
                    {
                        // Collision.
                        CurrentCutHits.Add(name);
                    }
                    else
                    {
                        throw new NotImplementedException($"Cannot tell what object type '{name}' is in remo HKX");
                    }

                    if (mdl != null)
                    {
                        mdl.Name = name;

                        remoModelDict.Add(name, mdl);
                    }
                }
                else
                {
                    mdl = remoModelDict[name];
                }

                if (mdl != null)
                {
                    mdl.AnimContainer = animContainer;
                    mdl.IsRemoModel   = true;
                    mdl.Name          = name;
                    mdl.SkeletonFlver.RevertToReferencePose();
                    mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true);
                    mdl.UpdateSkeleton();

                    lock (Scene._lock_ModelLoad_Draw)
                    {
                        Scene.Models.Add(mdl);
                    }
                }
            }



            var msbName = GameDataManager.GetInterrootPath($@"map\MapStudio\m{AreaInt:D2}_{BlockInt:D2}_00_00.msb");

            var msb = MSB1.Read(msbName);

            Vector3 mapOffset = msb.Events.MapOffsets.FirstOrDefault()?.Position.ToXna() ?? Vector3.Zero;



            uint dg1 = 0, dg2 = 0, dg3 = 0, dg4 = 0;

            foreach (var hitName in CurrentCutHits)
            {
                var hit = msb.Parts.Collisions.FirstOrDefault(h => h.Name == hitName);
                dg1 |= hit.DrawGroups[0];
                dg2 |= hit.DrawGroups[1];
                dg3 |= hit.DrawGroups[2];
                dg4 |= hit.DrawGroups[3];
            }

            bool IsThingVisible(uint[] drawGroups)
            {
                return(((drawGroups[0] & dg1) == dg1) &&
                       ((drawGroups[1] & dg2) == dg2) &&
                       ((drawGroups[2] & dg3) == dg3) &&
                       ((drawGroups[3] & dg4) == dg4));
            }

            foreach (var mapPiece in msb.Parts.MapPieces)
            {
                var thisEntityName = CurrentCutOtherBlocks.Count > 0 ? $"A{AreaInt:D2}B{BlockInt:D2}_{mapPiece.Name}"
                        : mapPiece.Name;



                if (IsThingVisible(mapPiece.DrawGroups))
                {
                    Model mdl = null;

                    if (remoModelDict.ContainsKey(thisEntityName))
                    {
                        mdl = remoModelDict[thisEntityName];
                        mdl.AnimContainer = animContainer;
                        mdl.IsRemoModel   = true;
                        mdl.SkeletonFlver.RevertToReferencePose();
                        mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true);
                        mdl.UpdateSkeleton();
                        lock (Scene._lock_ModelLoad_Draw)
                        {
                            Scene.Models.Add(mdl);
                        }
                        continue;
                    }

                    mdl = GameDataManager.LoadMapPiece(AreaInt, BlockInt, 0, 0, int.Parse(mapPiece.ModelName.Substring(1, 4)));
                    mdl.AnimContainer = animContainer;
                    mdl.IsRemoModel   = true;
                    mdl.Name          = thisEntityName;
                    mdl.SkeletonFlver.RevertToReferencePose();

                    mdl.StartTransform.Position = mapPiece.Position.ToXna() - mapOffset;
                    mdl.StartTransform.Rotation = Utils.EulerToQuaternion((mapPiece.Rotation * (SapMath.Pi / 180f)).ToXna());
                    mdl.StartTransform.Scale    = mapPiece.Scale.ToXna();
                    mdl.CurrentTransform        = mdl.StartTransform;

                    mdl.IS_REMO_NOTSKINNED = true;

                    mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true);
                    mdl.UpdateSkeleton();

                    lock (Scene._lock_ModelLoad_Draw)
                    {
                        Scene.Models.Add(mdl);
                    }

                    remoModelDict.Add(thisEntityName, mdl);
                }
            }

            foreach (var mapPiece in msb.Parts.Objects)
            {
                var thisEntityName = CurrentCutOtherBlocks.Count > 0 ? $"A{AreaInt:D2}B{BlockInt:D2}_{mapPiece.Name}"
                        : mapPiece.Name;

                if (IsThingVisible(mapPiece.DrawGroups))
                {
                    Model mdl = null;

                    if (remoModelDict.ContainsKey(thisEntityName))
                    {
                        mdl = remoModelDict[thisEntityName];
                        mdl.AnimContainer = animContainer;
                        mdl.IsRemoModel   = true;
                        mdl.SkeletonFlver.RevertToReferencePose();
                        mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true);
                        mdl.UpdateSkeleton();
                        lock (Scene._lock_ModelLoad_Draw)
                        {
                            Scene.Models.Add(mdl);
                        }
                        continue;
                    }

                    mdl = GameDataManager.LoadObject(mapPiece.ModelName);
                    mdl.AnimContainer = animContainer;
                    mdl.IsRemoModel   = true;
                    mdl.Name          = thisEntityName;

                    mdl.StartTransform.Position = mapPiece.Position.ToXna() - mapOffset;
                    mdl.StartTransform.Rotation = Utils.EulerToQuaternion((mapPiece.Rotation * (SapMath.Pi / 180f)).ToXna());
                    mdl.StartTransform.Scale    = mapPiece.Scale.ToXna();
                    mdl.CurrentTransform        = mdl.StartTransform;

                    mdl.IS_REMO_NOTSKINNED = true;

                    mdl.SkeletonFlver.RevertToReferencePose();
                    mdl.SkeletonFlver.MapToSkeleton(animContainer.Skeleton, isRemo: true);

                    mdl.UpdateSkeleton();

                    lock (Scene._lock_ModelLoad_Draw)
                    {
                        Scene.Models.Add(mdl);
                    }

                    remoModelDict.Add(thisEntityName, mdl);
                }
            }

            lock (Scene._lock_ModelLoad_Draw)
            {
                Scene.Models = Scene.Models.OrderBy(m => m.IS_PLAYER ? 0 : 1).ToList();
            }


            CurrentCut = animName;

            animContainer.ScrubRelative(0);

            List <Model> mdls = null;

            lock (Scene._lock_ModelLoad_Draw)
            {
                mdls = Scene.Models.ToList();
            }

            foreach (var m in mdls)
            {
                m.UpdateSkeleton();
            }

            GFX.World.Update(0);

            Scene.EnableModelDrawing();
            Scene.EnableModelDrawing2();

            ResumeStreamedBGM();

            ViewportInteractor.Graph.MainScreen.REMO_HOTFIX_REQUEST_PLAY_RESUME_NEXT_FRAME = true;

            ViewportInteractor.Graph.MainScreen.HardReset();
        }