Exemple #1
0
 // Token: 0x060000C7 RID: 199 RVA: 0x00007888 File Offset: 0x00005A88
 public static int IntersectsHitBox(Line3D aimRayWorld, Entity entity)
 {
     for (int i = 0; i < entity.StudioHitBoxSet.numhitboxes; i++)
     {
         mstudiobbox_t mstudiobbox_t = entity.StudioHitBoxes[i];
         int           bone          = mstudiobbox_t.bone;
         if (bone >= 0 && bone <= Helper.MaxStudioBones && mstudiobbox_t.radius > 0f)
         {
             float num;
             if (entity.Team == DoYouEvenAimBro.PlayerTeam)
             {
                 num = 0.9f;
             }
             else
             {
                 num = 1f;
             }
             Matrix  matrix     = entity.BonesMatrices[bone];
             Vector3 startPoint = matrix.Transform(mstudiobbox_t.bbmin);
             Vector3 endPoint   = matrix.Transform(mstudiobbox_t.bbmax);
             Line3D  other      = new Line3D(startPoint, endPoint);
             ValueTuple <Vector3, Vector3> valueTuple = aimRayWorld.ClosestPointsBetween(other, true);
             Vector3 item = valueTuple.Item1;
             if ((valueTuple.Item2 - item).Length() < mstudiobbox_t.radius * num)
             {
                 return(i);
             }
         }
     }
     return(-1);
 }
Exemple #2
0
        public static mstudiobbox_t GetHitBox(IClientEntity pEntity, string szModelName, int iIndex)
        {
            if (m_ModelHitboxes.ContainsKey(szModelName))
            {
                if (m_ModelHitboxes[szModelName].ContainsKey(iIndex))
                {
                    return(m_ModelHitboxes[szModelName][iIndex]);
                }
                else
                {
                    return(default(mstudiobbox_t));
                }
            }

            IntPtr pStudioHdr = pEntity.GetStudioHdr();

            if (pStudioHdr == IntPtr.Zero)
            {
                return(default(mstudiobbox_t));
            }

            int hitbox_set_index = MemoryAPI.ReadFromProcess <int>(Globals._csgo.ProcessHandle, pStudioHdr + 0xB0);

            int studio_hitbox_set = (int)pStudioHdr + hitbox_set_index;

            int num_hitboxes = MemoryAPI.ReadFromProcess <int>(Globals._csgo.ProcessHandle, new IntPtr(studio_hitbox_set + 0x4));

            int hitbox_index = MemoryAPI.ReadFromProcess <int>(Globals._csgo.ProcessHandle, new IntPtr(studio_hitbox_set + 0x8));

            m_ModelHitboxes.Add(szModelName, new Dictionary <int, mstudiobbox_t>());

            for (int i = 0; i < num_hitboxes; ++i)
            {
                mstudiobbox_t model_hitbox = MemoryAPI.ReadFromProcess <mstudiobbox_t>(Globals._csgo.ProcessHandle, new IntPtr((0x44 * i) + hitbox_index + studio_hitbox_set));
                float         radius       = model_hitbox.m_flRadius;
                if (radius != -1f)
                {
                    model_hitbox.bbmin.x -= radius;
                    model_hitbox.bbmin.y -= radius;
                    model_hitbox.bbmin.z -= radius;

                    model_hitbox.bbmin.x += radius;
                    model_hitbox.bbmin.y += radius;
                    model_hitbox.bbmin.z += radius;
                }
                m_ModelHitboxes[szModelName].Add(i, model_hitbox);
            }

            if (m_ModelHitboxes[szModelName].ContainsKey(iIndex))
            {
                return(m_ModelHitboxes[szModelName][iIndex]);
            }
            else
            {
                return(default(mstudiobbox_t));
            }
        }
Exemple #3
0
        // Token: 0x0600015D RID: 349 RVA: 0x00009E84 File Offset: 0x00008084
        private void UpdateSkeleton()
        {
            int num = 0;

            for (int i = 0; i < this.StudioHitBoxSet.numhitboxes; i++)
            {
                mstudiobbox_t mstudiobbox_t = this.StudioHitBoxes[i];
                mstudiobone_t mstudiobone_t = this.StudioBones[mstudiobbox_t.bone];
                if (mstudiobone_t.parent >= 0 && mstudiobone_t.parent < this.StudioHdr.numbones)
                {
                    this.Skeleton[num] = new ValueTuple <int, int>(mstudiobbox_t.bone, mstudiobone_t.parent);
                    num++;
                }
            }
            this.SkeletonCount = num;
        }
Exemple #4
0
        public Transform BuildModel(Boolean GenerateUV2 = false)
        {
            GameObject ModelObject = new GameObject(MDL_Header.Name);

            #region Bones
            Transform[] Bones = new Transform[MDL_Header.bone_count];
            Dictionary <Int32, String> bonePathDict = new Dictionary <Int32, String>();
            for (Int32 boneID = 0; boneID < MDL_Header.bone_count; boneID++)
            {
                GameObject BoneObject = new GameObject(MDL_BoneNames[boneID]);

                Bones[boneID] = BoneObject.transform;//MDL_Bones.Add(BoneObject.transform);

                Vector3 pos = MDL_StudioBones[boneID].pos * uLoader.UnitScale;
                Vector3 rot = MDL_StudioBones[boneID].rot * Mathf.Rad2Deg;

                //Invert x for convert right-handed to left-handed
                pos.x = -pos.x;

                if (MDL_StudioBones[boneID].parent >= 0)
                {
                    Bones[boneID].parent = Bones[MDL_StudioBones[boneID].parent];
                }
                else
                {
                    //Swap Z & Y and invert Y (ex: X Z -Y)
                    //only for parents, cuz parents used different order vectors
                    float temp = pos.y;
                    pos.y = pos.z;
                    pos.z = -temp;

                    Bones[boneID].parent = ModelObject.transform;
                }

                bonePathDict.Add(boneID, Bones[boneID].GetTransformPath(ModelObject.transform));

                Bones[boneID].localPosition = pos;
                //Bones[i].localRotation = MDL_StudioBones[i].quat;

                if (MDL_StudioBones[boneID].parent == -1)
                {
                    //Fix up parents
                    Bones[boneID].localRotation = Quaternion.Euler(-90, 90, -90) * MathLibrary.AngleQuaternion(rot);
                }
                else
                {
                    Bones[boneID].localRotation = MathLibrary.AngleQuaternion(rot);
                }
            }

            if (uLoader.DrawArmature)
            {
                MDLArmatureInfo DebugArmature = ModelObject.AddComponent <MDLArmatureInfo>();
                DebugArmature.boneNodes = Bones;
            }
            #endregion

            #region Hitboxes
            if (MDL_Hitboxsets != null)
            {
                for (Int32 HitboxsetID = 0; HitboxsetID < MDL_Header.hitbox_count; HitboxsetID++)
                {
                    for (Int32 HitboxID = 0; HitboxID < MDL_Hitboxsets[HitboxsetID].numhitboxes; HitboxID++)
                    {
                        mstudiobbox_t Hitbox = Hitboxes[HitboxsetID][HitboxID].BBox;
                        BoxCollider   BBox   = new GameObject(String.Format("Hitbox_{0}", Bones[Hitbox.bone].name)).AddComponent <BoxCollider>();

                        BBox.size   = MathLibrary.NegateX(Hitbox.bbmax - Hitbox.bbmin) * uLoader.UnitScale;
                        BBox.center = (MathLibrary.NegateX(Hitbox.bbmax + Hitbox.bbmin) / 2) * uLoader.UnitScale;

                        BBox.transform.parent        = Bones[Hitbox.bone];
                        BBox.transform.localPosition = Vector3.zero;
                        BBox.transform.localRotation = Quaternion.identity;

                        //bbox.transform.tag = HitTagType(MDL_BBoxes[i].group);
                    }
                }
            }
            #endregion

            #region BodyParts
            if (BuildMesh)
            {
                for (Int32 BodypartID = 0; BodypartID < MDL_Header.bodypart_count; BodypartID++)
                {
                    StudioBodyPart BodyPart = MDL_Bodyparts[BodypartID];

                    for (Int32 ModelID = 0; ModelID < BodyPart.Models.Length; ModelID++)
                    {
                        StudioModel Model = BodyPart.Models[ModelID];

                        //Skip if model is blank
                        if (Model.isBlank)
                        {
                            continue;
                        }

                        #region TODO: Remove this code after find way to strip unused vertexes for lod's (VTXStripGroup / VTXStrip)
                        mstudiovertex_t[] Vertexes = Model.VerticesPerLod[0];

                        BoneWeight[] BoneWeight = new BoneWeight[Vertexes.Length];
                        Vector3[]    Vertices   = new Vector3[Vertexes.Length];
                        Vector3[]    Normals    = new Vector3[Vertexes.Length];
                        Vector2[]    UvBuffer   = new Vector2[Vertexes.Length];

                        for (Int32 i = 0; i < Vertexes.Length; i++)
                        {
                            Vertices[i] = MathLibrary.SwapZY(Vertexes[i].m_vecPosition * uLoader.UnitScale);
                            Normals[i]  = MathLibrary.SwapZY(Vertexes[i].m_vecNormal);

                            Vector2 UV = Vertexes[i].m_vecTexCoord;
                            if (uLoader.SaveAssetsToUnity && uLoader.ExportTextureAsPNG)
                            {
                                UV.y = -UV.y;
                            }

                            UvBuffer[i]   = UV;
                            BoneWeight[i] = GetBoneWeight(Vertexes[i].m_BoneWeights);
                        }
                        #endregion

                        #region LOD Support
                        Boolean DetailModeEnabled =
                            uLoader.DetailMode == DetailMode.Lowest ||
                            uLoader.DetailMode == DetailMode.Low ||
                            uLoader.DetailMode == DetailMode.Medium ||
                            uLoader.DetailMode == DetailMode.High;

                        Boolean   LODExist       = uLoader.EnableLODParsing && !DetailModeEnabled && Model.NumLODs > 1;
                        Transform FirstLODObject = null;
                        LODGroup  LODGroup       = null;
                        LOD[]     LODs           = null;
                        Single    MaxSwitchPoint = 100;
                        Int32     StartLODIndex  = 0;

                        if (LODExist)
                        {
                            LODs = new LOD[Model.NumLODs];

                            for (Int32 LODID = 1; LODID < 3; LODID++)
                            {
                                Int32            LastID = Model.NumLODs - LODID;
                                ModelLODHeader_t LOD    = Model.LODData[LastID];

                                //ignore $shadowlod
                                if (LOD.switchPoint != -1)
                                {
                                    if (LOD.switchPoint > 0)
                                    {
                                        MaxSwitchPoint = LOD.switchPoint;
                                    }

                                    //Set switchPoint from MaxSwitchPoint (if switchPoint is zero or negative)
                                    if (LODID == 2 || LOD.switchPoint == 0)
                                    {
                                        MaxSwitchPoint += MaxSwitchPoint * uLoader.NegativeAddLODPrecent;
                                        Model.LODData[LOD.switchPoint == 0 ? LastID : LastID + 1].switchPoint = MaxSwitchPoint;
                                    }

                                    // + Threshold used to avoid errors with LODGroup
                                    MaxSwitchPoint += uLoader.ThresholdMaxSwitch;
                                    break;
                                }
                            }
                        }
                        else
                        {
                            if (!uLoader.EnableLODParsing)
                            {
                                Model.NumLODs = 1;
                            }
                        }

                        if (uLoader.EnableLODParsing && DetailModeEnabled)
                        {
                            StartLODIndex =
                                uLoader.DetailMode == DetailMode.Lowest ? (Model.NumLODs - 1) :
                                uLoader.DetailMode == DetailMode.Low ? (Int32)(Model.NumLODs / 1.5f) :
                                uLoader.DetailMode == DetailMode.Medium ? (Model.NumLODs / 2) : (Int32)(Model.NumLODs / 2.5f);
                        }
                        #endregion

                        #region Build Meshes
                        for (Int32 LODID = StartLODIndex; LODID < Model.NumLODs; LODID++)
                        {
                            #region TODO: Uncomment after find way to strip unused vertexes for lod's (VTXStripGroup / VTXStrip)

                            /*mstudiovertex_t[] Vertexes = Model.VerticesPerLod[LODID];
                             *
                             * BoneWeight[] BoneWeight = new BoneWeight[Vertexes.Length];
                             * Vector3[] Vertices = new Vector3[Vertexes.Length];
                             * Vector3[] Normals = new Vector3[Vertexes.Length];
                             * Vector2[] UvBuffer = new Vector2[Vertexes.Length];
                             *
                             * for (Int32 i = 0; i < Vertexes.Length; i++)
                             * {
                             *  Vertices[i] = MathLibrary.SwapZY(Vertexes[i].m_vecPosition * uLoader.UnitScale);
                             *  Normals[i] = MathLibrary.SwapZY(Vertexes[i].m_vecNormal);
                             *
                             *  Vector2 UV = Vertexes[i].m_vecTexCoord;
                             *  if (uLoader.SaveAssetsToUnity && uLoader.ExportTextureAsPNG)
                             *      UV.y = -UV.y;
                             *
                             *  UvBuffer[i] = UV;
                             *  BoneWeight[i] = GetBoneWeight(Vertexes[i].m_BoneWeights);
                             * }*/
                            #endregion

                            #region LOD
                            ModelLODHeader_t ModelLOD = Model.LODData[LODID];

                            if (LODExist)
                            {
                                if (ModelLOD.switchPoint == 0)
                                {
                                    ModelLOD.switchPoint = MaxSwitchPoint;
                                }
                                else
                                {
                                    ModelLOD.switchPoint = MaxSwitchPoint - ModelLOD.switchPoint;
                                }

                                ModelLOD.switchPoint -= ModelLOD.switchPoint * uLoader.SubstractLODPrecent;
                            }
                            #endregion

                            #region Mesh
                            //Create empty object for mesh
                            GameObject MeshObject = new GameObject(Model.Model.Name);
                            MeshObject.name            += "_vLOD" + LODID;
                            MeshObject.transform.parent = ModelObject.transform;

                            //Create empty mesh and fill parsed data
                            Mesh Mesh = new Mesh();
                            Mesh.name = MeshObject.name;

                            Mesh.subMeshCount = Model.Model.nummeshes;
                            Mesh.vertices     = Vertices;
                            //Make sure if mesh exist any vertexes
                            if (Mesh.vertexCount <= 0)
                            {
                                Debug.LogWarning(String.Format("Mesh: \"{0}\" has no vertexes, skip building... (MDL Version: {1})", Mesh.name, MDL_Header.version));
                                continue;
                            }

                            Mesh.normals = Normals;
                            Mesh.uv      = UvBuffer;
                            #endregion

                            #region Renderers
                            Renderer Renderer;
                            //SkinnedMeshRenderer (Models with "animated" bones & skin data)
                            if (!MDL_Header.flags.HasFlag(StudioHDRFlags.STUDIOHDR_FLAGS_STATIC_PROP))
                            {
                                //Bind poses & bone weights
                                SkinnedMeshRenderer SkinnedRenderer = MeshObject.AddComponent <SkinnedMeshRenderer>();
                                Renderer = SkinnedRenderer;
                                Matrix4x4[] BindPoses = new Matrix4x4[Bones.Length];

                                for (Int32 i = 0; i < BindPoses.Length; i++)
                                {
                                    BindPoses[i] = Bones[i].worldToLocalMatrix * MeshObject.transform.localToWorldMatrix;
                                }

                                Mesh.boneWeights = BoneWeight;
                                Mesh.bindposes   = BindPoses;

                                SkinnedRenderer.sharedMesh = Mesh;

                                SkinnedRenderer.bones = Bones;
                                SkinnedRenderer.updateWhenOffscreen = true;
                            }
                            //MeshRenderer (models with "STUDIOHDR_FLAGS_STATIC_PROP" flag or with generic "static_prop" bone)
                            else
                            {
                                MeshFilter MeshFilter = MeshObject.AddComponent <MeshFilter>();
                                Renderer = MeshObject.AddComponent <MeshRenderer>();
                                MeshFilter.sharedMesh = Mesh;
                            }

                            Renderer.shadowCastingMode = UnityEngine.Rendering.ShadowCastingMode.TwoSided;
                            #endregion

                            #region Debug Stuff
                            #if UNITY_EDITOR
                            DebugMaterial DebugMat = null;
                            if (uLoader.DebugMaterials)
                            {
                                DebugMat = MeshObject.AddComponent <DebugMaterial>();
                            }
                            #endif
                            #endregion

                            #region Triangles and Materials
                            Material[] Materials = new Material[Mesh.subMeshCount];

                            for (Int32 MeshID = 0; MeshID < Model.Model.nummeshes; MeshID++)
                            {
                                //Set triangles per lod & submeshes
                                Mesh.SetTriangles(Model.IndicesPerLod[LODID][MeshID], MeshID);

                                //Find & parse materials
                                String MaterialPath;
                                Int32  LastDirID = MDL_TDirectories.Length - 1;
                                for (Int32 DirID = 0; DirID < MDL_TDirectories.Length; DirID++)
                                {
                                    MaterialPath = MDL_TDirectories[DirID] + MDL_Textures[Model.Meshes[MeshID].material];

                                    //If material exist
                                    if (uResourceManager.ContainsFile(MaterialPath, uResourceManager.MaterialsSubFolder, uResourceManager.MaterialsExtension[0]))
                                    {
                                        VMTFile VMT = uResourceManager.LoadMaterial(MaterialPath);

                                        #region Debug Stuff
                                        #if UNITY_EDITOR
                                        if (uLoader.DebugMaterials)
                                        {
                                            DebugMat.Init(VMT);
                                        }
                                        #endif
                                        #endregion

                                        //Set material
                                        Materials[MeshID] = VMT.Material;
                                        break;
                                    }
                                    else if (DirID == LastDirID)
                                    {
                                        Materials[MeshID] = uResourceManager.LoadMaterial(String.Empty).Material;
                                    }
                                }
                            }

                            Renderer.sharedMaterials = Materials;
                            #endregion

                            #region UV2
                            #if UNITY_EDITOR
                            if (GenerateUV2)
                            {
                                UnityEditor.SerializedObject so = new UnityEditor.SerializedObject(Renderer);
                                so.FindProperty("m_ScaleInLightmap").floatValue = uLoader.ModelsLightmapSize;
                                so.ApplyModifiedProperties();

                                MeshObject.isStatic = GenerateUV2;
                                uResourceManager.UV2GenerateCache.Add(Mesh);
                            }
                            #endif
                            #endregion

                            #region Set LOD's
                            if (LODExist)
                            {
                                if (LODID == 0)
                                {
                                    LODGroup       = MeshObject.AddComponent <LODGroup>();
                                    FirstLODObject = MeshObject.transform;
                                }
                                else if (FirstLODObject != null)
                                {
                                    MeshObject.transform.parent = FirstLODObject;
                                }

                                LODs[LODID] = new LOD(ModelLOD.switchPoint / MaxSwitchPoint, new Renderer[] { Renderer });
                            }

                            if (uLoader.EnableLODParsing && DetailModeEnabled)
                            {
                                break;
                            }
                            #endregion
                        }//lod's per model

                        //Init all parsed lod's into LODGroup
                        if (LODGroup != null)
                        {
                            LODGroup.SetLODs(LODs);
                        }
                        #endregion
                    } //models in bodypart
                }     //Bodypart
            }
            #endregion

            #region Animations
            if (MDL_SeqDescriptions != null)
            {
                var AnimationComponent = ModelObject.AddComponent <Animation>();
                for (Int32 seqID = 0; seqID < MDL_SeqDescriptions.Length; seqID++)
                {
                    SeqInfo Sequence  = Sequences[seqID];
                    AniInfo Animation = Sequence.ani;

                    //Creating "AnimationCurve" for animation "paths" (aka frames where stored position (XYZ) & rotation (XYZW))
                    AnimationCurve[] posX = new AnimationCurve[MDL_Header.bone_count];    //X
                    AnimationCurve[] posY = new AnimationCurve[MDL_Header.bone_count];    //Y
                    AnimationCurve[] posZ = new AnimationCurve[MDL_Header.bone_count];    //Z

                    AnimationCurve[] rotX = new AnimationCurve[MDL_Header.bone_count];    //X
                    AnimationCurve[] rotY = new AnimationCurve[MDL_Header.bone_count];    //Y
                    AnimationCurve[] rotZ = new AnimationCurve[MDL_Header.bone_count];    //Z
                    AnimationCurve[] rotW = new AnimationCurve[MDL_Header.bone_count];    //W

                    //Fill "AnimationCurve" arrays
                    for (Int32 boneIndex = 0; boneIndex < MDL_Header.bone_count; boneIndex++)
                    {
                        posX[boneIndex] = new AnimationCurve();
                        posY[boneIndex] = new AnimationCurve();
                        posZ[boneIndex] = new AnimationCurve();

                        rotX[boneIndex] = new AnimationCurve();
                        rotY[boneIndex] = new AnimationCurve();
                        rotZ[boneIndex] = new AnimationCurve();
                        rotW[boneIndex] = new AnimationCurve();
                    }

                    Int32 numFrames = Animation.studioAnim.numframes;

                    //Used to avoid "Assertion failed" key count in Unity (if frames less than 2)
                    if (numFrames < 2)
                    {
                        numFrames += 1;
                    }

                    //Create animation clip
                    AnimationClip clip = new AnimationClip();
                    //Make it for legacy animation system (for now, but it possible to rework for Mecanim)
                    clip.legacy = true;
                    //Set animation clip name
                    clip.name = Animation.name;

                    //To avoid problems with "obfuscators" / "protectors" for models, make sure if model have name in sequence
                    if (String.IsNullOrEmpty(clip.name))
                    {
                        clip.name = "(empty)" + seqID;
                    }

                    for (Int32 frameIndex = 0; frameIndex < numFrames; frameIndex++)
                    {
                        //Get current frame from blend (meaning from "Animation") by index
                        //AnimationFrame frame = Animation.Frames[frameIndex];

                        //Set keys (position / rotation) from current frame
                        for (Int32 boneIndex = 0; boneIndex < Bones.Length; boneIndex++)
                        {
                            posX[boneIndex].AddKey(Animation.PosX[frameIndex][boneIndex]);
                            posY[boneIndex].AddKey(Animation.PosY[frameIndex][boneIndex]);
                            posZ[boneIndex].AddKey(Animation.PosZ[frameIndex][boneIndex]);

                            rotX[boneIndex].AddKey(Animation.RotX[frameIndex][boneIndex]);
                            rotY[boneIndex].AddKey(Animation.RotY[frameIndex][boneIndex]);
                            rotZ[boneIndex].AddKey(Animation.RotZ[frameIndex][boneIndex]);
                            rotW[boneIndex].AddKey(Animation.RotW[frameIndex][boneIndex]);

                            //Set default pose from the first animation
                            if (seqID == 0 && frameIndex == 0)
                            {
                                Bones[boneIndex].localPosition = new Vector3
                                                                 (
                                    Animation.PosX[0][boneIndex].value,
                                    Animation.PosY[0][boneIndex].value,
                                    Animation.PosZ[0][boneIndex].value
                                                                 );

                                Bones[boneIndex].localRotation = new Quaternion
                                                                 (
                                    Animation.RotX[0][boneIndex].value,
                                    Animation.RotY[0][boneIndex].value,
                                    Animation.RotZ[0][boneIndex].value,
                                    Animation.RotW[0][boneIndex].value
                                                                 );
                            }
                        }
                    }

                    //Apply animation paths (Position / Rotation) to clip
                    for (Int32 boneIndex = 0; boneIndex < MDL_Header.bone_count; boneIndex++)
                    {
                        clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localPosition.x", posX[boneIndex]);
                        clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localPosition.y", posY[boneIndex]);
                        clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localPosition.z", posZ[boneIndex]);

                        clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.x", rotX[boneIndex]);
                        clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.y", rotY[boneIndex]);
                        clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.z", rotZ[boneIndex]);
                        clip.SetCurve(bonePathDict[boneIndex], typeof(Transform), "localRotation.w", rotW[boneIndex]);
                    }

                    if (Animation.studioAnim.fps > 0.0f)
                    {
                        clip.frameRate = Animation.studioAnim.fps;
                    }

                    //This ensures a smooth interpolation (corrects the problem of "jitter" after 180~270 degrees rotation path)
                    //can be "comment" if have idea how to replace this
                    clip.EnsureQuaternionContinuity();
                    AnimationComponent.AddClip(clip, clip.name);
                }
            }
            #endregion

            //If model has compiled flag "$staticprop"
            //then rotate this model by 90 degrees (Y)
            //https://github.com/ValveSoftware/source-sdk-2013/blob/master/sp/src/public/studio.h#L1965
            //Big thanks for this tip:
            //ShadelessFox
            //REDxEYE
            if (MDL_Header.flags.HasFlag(StudioHDRFlags.STUDIOHDR_FLAGS_STATIC_PROP))
            {
                ModelObject.transform.eulerAngles = new Vector3(0, 90, 0);
            }

            return(ModelObject.transform);
        }