예제 #1
0
        /// <summary>
        /// Gets the first ancestor with a skin.
        /// </summary>
        /// <param name="race"></param>
        /// <returns></returns>
        public static XivRace GetSkinRace(this XivRace race)
        {
            var node = GetNode(race);

            if (node == null)
            {
                return(XivRace.Hyur_Midlander_Male);
            }

            // Roe F is very weird and uses Highlander F's skin materials,
            // but Midlander F's models.  Blame SE hard-coding shit.
            if (node.Race == XivRace.Roegadyn_Female)
            {
                return(XivRace.Hyur_Highlander_Female);
            }

            if (node.HasSkin)
            {
                return(node.Race);
            }

            while (node.Parent != null)
            {
                node = node.Parent;
                if (node.HasSkin)
                {
                    return(node.Race);
                }
            }

            return(XivRace.Hyur_Midlander_Male);
        }
예제 #2
0
        /// <summary>
        /// Gets the Part for a given Character Item
        /// </summary>
        /// <remarks>
        /// For Body and Tail Character Items since they don't have Types
        /// </remarks>
        /// <param name="charaItem">The character item</param>
        /// <param name="race">The race</param>
        /// <param name="num">The character item number</param>
        /// <returns>A dictionary containging [</returns>
        public char[] GetPartForTextures(XivCharacter charaItem, XivRace race, int num)
        {
            var index = new Index(_gameDirectory);

            var folder = "";
            var file   = "";

            var parts = new[] { 'a', 'b', 'c', 'd', 'e', 'f' };

            if (charaItem.ItemCategory == XivStrings.Body)
            {
                folder = string.Format(XivStrings.BodyMtrlFolder, race.GetRaceCode(), num.ToString().PadLeft(4, '0'));
                file   = XivStrings.BodyMtrlFile;
            }
            else if (charaItem.ItemCategory == XivStrings.Tail)
            {
                folder = string.Format(XivStrings.TailMtrlFolder, race.GetRaceCode(), num.ToString().PadLeft(4, '0'));
                file   = XivStrings.TailMtrlFile;
            }

            var fileList = index.GetAllHashedFilesInFolder(HashGenerator.GetHash(folder), XivDataFile._04_Chara);

            return((from part in parts let mtrlFile = string.Format(file, race.GetRaceCode(), num.ToString().PadLeft(4, '0'), part)
                                                      where fileList.Contains(HashGenerator.GetHash(mtrlFile)) select part).ToArray());
        }
예제 #3
0
        /// <summary>
        /// Determines if this race is a parent of another given race or not.
        /// If the values are the same, it is considered TRUE by default.
        /// </summary>
        /// <param name="possibleParent"></param>
        /// <param name="possibleChild"></param>
        /// <returns></returns>
        public static bool IsParentOf(this XivRace possibleParent, XivRace possibleChild, bool allowSame = true)
        {
            CheckTree();
            if (possibleChild == possibleParent && allowSame)
            {
                return(true);
            }

            var node = GetNode(possibleChild);

            if (node == null)
            {
                return(false);
            }

            while (node.Parent != null)
            {
                node = node.Parent;
                if (node.Race == possibleParent)
                {
                    return(true);
                }
            }
            return(false);
        }
예제 #4
0
        /// <summary>
        /// Gets the MTRL data for the given item
        /// </summary>
        /// <remarks>
        /// It requires a race (The default is usually <see cref="XivRace.Hyur_Midlander_Male"/>)
        /// It also requires an mtrl part <see cref="GearInfo.GetPartList(IItemModel, XivRace)"/> (default is 'a')
        /// </remarks>
        /// <param name="itemModel">Item that contains model data</param>
        /// <param name="race">The race for the requested data</param>
        /// <param name="mtrlFile">The Mtrl file</param>
        /// <returns>XivMtrl containing all the mtrl data</returns>
        public XivMtrl GetMtrlData(IItemModel itemModel, XivRace race, string mtrlFile, int dxVersion)
        {
            var index    = new Index(_gameDirectory);
            var itemType = ItemType.GetItemType(itemModel);

            // Get mtrl path
            var mtrlFolder     = GetMtrlFolder(itemModel, race, itemType);
            var mtrlStringPath = $"{mtrlFolder}/{mtrlFile}";

            if (itemType == XivItemType.furniture)
            {
                mtrlStringPath = $"b{mtrlFile}";
                mtrlFolder     = Path.GetDirectoryName(mtrlStringPath).Replace("\\", "/");
                mtrlFile       = Path.GetFileName(mtrlStringPath);
            }

            // Get mtrl offset
            var mtrlOffset = index.GetDataOffset(HashGenerator.GetHash(mtrlFolder), HashGenerator.GetHash(mtrlFile),
                                                 _dataFile);

            if (mtrlOffset == 0)
            {
                throw new Exception($"Could not find offest for {mtrlStringPath}");
            }

            var mtrlData = GetMtrlData(mtrlOffset, mtrlStringPath, dxVersion);

            return(mtrlData);
        }
예제 #5
0
        /// <summary>
        /// Gets the first ancestor with a skin.
        /// </summary>
        /// <param name="race"></param>
        /// <returns></returns>
        public static XivRace GetSkinRace(this XivRace race)
        {
            var node = GetNode(race);

            if (node == null)
            {
                return(XivRace.Hyur_Midlander_Male);
            }

            if (node.HasSkin)
            {
                return(node.Race);
            }

            while (node.Parent != null)
            {
                node = node.Parent;
                if (node.HasSkin)
                {
                    return(node.Race);
                }
            }

            return(XivRace.Hyur_Midlander_Male);
        }
예제 #6
0
        /// <summary>
        /// Gets the Display Name of the Race from the Resource file in order to support localization
        /// </summary>
        /// <param name="value">The enum value</param>
        /// <returns>The localized display name of the race</returns>
        public static string GetDisplayName(this XivRace value)
        {
            var rm          = new ResourceManager(typeof(XivStrings));
            var displayName = rm.GetString(value.ToString());

            return(displayName);
        }
예제 #7
0
        /// <summary>
        /// Gets the description from the enum value, in this case the Race Code
        /// </summary>
        /// <param name="value">The enum value</param>
        /// <returns>The race code</returns>
        public static string GetRaceCode(this XivRace value)
        {
            var field     = value.GetType().GetField(value.ToString());
            var attribute = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false);

            return(attribute.Length > 0 ? attribute[0].Description : value.ToString());
        }
예제 #8
0
        private static Dictionary <XivRace, ExtraSkeletonEntry> DeserializeEstData(byte[] data, uint dataVersion)
        {
            if (dataVersion == 1)
            {
                // Version 1 didn't include EST data, so just get the defaults.
                return(null);                //// await Est.GetExtraSkeletonEntries(root);
            }

            // 6 Bytes per entry.
            int count = data.Length / 6;
            Dictionary <XivRace, ExtraSkeletonEntry> ret = new Dictionary <XivRace, ExtraSkeletonEntry>(count);

            for (int i = 0; i < count; i++)
            {
                int    offset   = i * 6;
                ushort raceCode = BitConverter.ToUInt16(data, offset);
                ushort setId    = BitConverter.ToUInt16(data, offset + 2);
                ushort skelId   = BitConverter.ToUInt16(data, offset + 4);

                XivRace race = GetXivRace(raceCode);

                ret.Add(race, new ExtraSkeletonEntry(race, setId, skelId));
            }

            return(ret);
        }
예제 #9
0
        private static string GetRaceCode(XivRace value)
        {
            FieldInfo field = value.GetType().GetField(value.ToString());

            DescriptionAttribute[] attribute = (DescriptionAttribute[])field.GetCustomAttributes(typeof(DescriptionAttribute), false);
            return(attribute.Length > 0 ? attribute[0].Description : value.ToString());
        }
 /// <summary>
 /// Applies the deformer to a model
 /// </summary>
 /// <param name="model">The model being deformed</param>
 /// <param name="currentRace">The current model race</param>
 /// <param name="targetRace">The target race to convert the model to</param>
 private static void ApplyDeformers(TTModel model, XivRace currentRace, XivRace targetRace)
 {
     // Current race is already parent node
     // Direct conversion
     // [ Current > (apply deform) > Target ]
     if (currentRace.IsDirectParentOf(targetRace))
     {
         ModelModifiers.ApplyRacialDeform(model, targetRace);
     }
     // Target race is parent node of Current race
     // Convert to parent (invert deform)
     // [ Current > (apply inverse deform) > Target ]
     else if (targetRace.IsDirectParentOf(currentRace))
     {
         ModelModifiers.ApplyRacialDeform(model, currentRace, true);
     }
     // Current race is not parent of Target Race and Current race has parent
     // Make a recursive call with the current races parent race
     // [ Current > (apply inverse deform) > Current.Parent > Recursive Call ]
     else if (currentRace.GetNode().Parent != null)
     {
         ModelModifiers.ApplyRacialDeform(model, currentRace, true);
         ApplyDeformers(model, currentRace.GetNode().Parent.Race, targetRace);
     }
     // Current race has no parent
     // Make a recursive call with the target races parent race
     // [ Target > (apply deform on Target.Parent) > Target.Parent > Recursive Call ]
     else
     {
         ModelModifiers.ApplyRacialDeform(model, targetRace.GetNode().Parent.Race);
         ApplyDeformers(model, targetRace.GetNode().Parent.Race, targetRace);
     }
 }
        private static IItemModel GetHairModel(XivRace race, byte hair)
        {
            int raceCode = int.Parse(race.GetRaceCode());

            foreach (IItem item in allItems)
            {
                if (item is IItemModel itemModel)
                {
                    if (item.PrimaryCategory != "Character")
                    {
                        continue;
                    }

                    if (item.SecondaryCategory != "Hair")
                    {
                        continue;
                    }

                    if (itemModel.ModelInfo.PrimaryID != raceCode)
                    {
                        continue;
                    }

                    XivCharacter faceItem = (XivCharacter)itemModel.Clone();

                    faceItem.ModelInfo             = new XivModelInfo();
                    faceItem.ModelInfo.SecondaryID = hair;
                    return(faceItem);
                }
            }

            throw new Exception($"Failed to find hair model: {race}, {hair}");
        }
        private static IItemModel GetFaceModel(XivRace race, byte head, byte eyebrows, byte eyes, byte nose, byte jaw, byte mouth)
        {
            int raceCode = int.Parse(race.GetRaceCode());

            foreach (IItem item in allItems)
            {
                if (item is IItemModel itemModel)
                {
                    if (item.PrimaryCategory != "Character")
                    {
                        continue;
                    }

                    if (item.SecondaryCategory != "Face")
                    {
                        continue;
                    }

                    if (itemModel.ModelInfo.PrimaryID != raceCode)
                    {
                        continue;
                    }

                    XivCharacter faceItem = (XivCharacter)itemModel.Clone();

                    faceItem.ModelInfo             = new XivModelInfo();
                    faceItem.ModelInfo.SecondaryID = head;
                    return(faceItem);
                }
            }

            throw new Exception($"Failed to find face model: {race}, {head}");
        }
        private SimpleModPackEntries GetEntry(Mod mod, Modding modding)
        {
            if (mod.fullPath.Equals(string.Empty))
            {
                return(null);
            }

            SimpleModPackEntries entry = new SimpleModPackEntries();

            entry.Name     = mod.name;
            entry.Category = mod.category;

            XivRace race = GetRace(mod.fullPath);

            entry.Race = race.GetDisplayName();

            entry.Type     = GetType(mod.fullPath);
            entry.Part     = GetPart(mod.fullPath);
            entry.Num      = GetNumber(mod.fullPath);
            entry.Map      = GetMap(mod.fullPath);
            entry.Active   = mod.enabled || mod.data.modOffset == mod.data.originalOffset;
            entry.ModEntry = mod;

            return(entry);
        }
예제 #14
0
        /// <summary>
        /// Gets the Part for a given Character Item
        /// </summary>
        /// <remarks>
        /// For Body and Tail Character Items since they don't have Types
        /// </remarks>
        /// <param name="charaItem">The character item</param>
        /// <param name="race">The race</param>
        /// <param name="num">The character item number</param>
        /// <param name="variant">the variant for the mtrl folder</param>
        /// <returns>An array of characters containing the parts for the texture</returns>
        public async Task <char[]> GetPartForTextures(XivCharacter charaItem, XivRace race, int num, int variant = 1)
        {
            var folder = "";
            var file   = "";

            var parts = Constants.Alphabet;

            if (charaItem.SecondaryCategory == XivStrings.Body)
            {
                folder = string.Format(XivStrings.BodyMtrlFolderVar, race.GetRaceCode(), num.ToString().PadLeft(4, '0'), variant.ToString().PadLeft(4, '0'));
                file   = XivStrings.BodyMtrlFile;
            }
            else if (charaItem.SecondaryCategory == XivStrings.Tail)
            {
                folder = string.Format(XivStrings.TailMtrlFolder, race.GetRaceCode(), num.ToString().PadLeft(4, '0'));
                file   = XivStrings.TailMtrlFile;
            }
            else if (charaItem.SecondaryCategory == XivStrings.Ear)
            {
                folder = string.Format(XivStrings.EarsMtrlFolder, race.GetRaceCode(), num.ToString().PadLeft(4, '0'));

                file = XivStrings.EarsMtrlFile;
            }

            var fileList = await _index.GetAllHashedFilesInFolder(HashGenerator.GetHash(folder), XivDataFile._04_Chara);

            return((from part in parts
                    let mtrlFile = string.Format(file, race.GetRaceCode(), num.ToString().PadLeft(4, '0'), part)
                                   where fileList.Contains(HashGenerator.GetHash(mtrlFile))
                                   select part).ToArray());
        }
예제 #15
0
        /// <summary>
        /// Gets the full list of children for this node.
        /// </summary>
        /// <param name="race"></param>
        /// <param name="includeNPCs"></param>
        /// <returns></returns>
        public static List <XivRace> GetChildren(this XivRace race, bool includeNPCs = false)
        {
            CheckTree();
            var node = GetNode(race);
            var name = node.Race.ToString();

            // Skip NPCs
            if (name.Contains("NPC") && !includeNPCs)
            {
                return(new List <XivRace>());
            }

            // Return ourselves if no children.
            if (node.Children == null || node.Children.Count == 0)
            {
                return new List <XivRace>()
                       {
                           race
                       }
            }
            ;

            // Recursion for children.
            var children = new List <XivRace>();

            foreach (var c in node.Children)
            {
                children.AddRange(GetChildren(c.Race, includeNPCs));
            }

            // Final return.
            return(children);
        }
예제 #16
0
        /// <summary>
        /// Gets the raw equipment or accessory deformation parameters file for a given race.
        /// </summary>
        /// <returns></returns>
        private async Task <List <byte> > LoadEquipmentDeformationFile(XivRace race, bool accessory = false)
        {
            var rootPath = accessory ? AccessoryDeformerParameterRootPath : EquipmentDeformerParameterRootPath;
            var fileName = rootPath + "c" + race.GetRaceCode() + "." + EquipmentDeformerParameterExtension;

            return(new List <byte>(await _dat.GetType2Data(fileName, false)));
        }
예제 #17
0
        public AdvancedModelImportView(XivMdl xivMdl, IItemModel itemModel, XivRace selectedRace)
        {
            InitializeComponent();

            var advancedImportViewModel = new AdvancedImportViewModel(xivMdl, itemModel, selectedRace, this);

            this.DataContext = advancedImportViewModel;
        }
 private bool IsRaceEnabled(XivRace race)
 {
     if (_metadata.EqdpEntries.ContainsKey(race))
     {
         return(_metadata.EqdpEntries[race].bit1);
     }
     return(false);
 }
예제 #19
0
        /// <summary>
        /// Retrieves the base race enum value for this race/clan/gender race.
        /// Used for CMP files and a few other things.
        /// </summary>
        /// <param name="race"></param>
        /// <returns></returns>
        public static XivBaseRace GetBaseRace(this XivRace race)
        {
            switch (race)
            {
            case XivRace.Hyur_Midlander_Male:
            case XivRace.Hyur_Midlander_Female:
            case XivRace.Hyur_Midlander_Male_NPC:
            case XivRace.Hyur_Midlander_Female_NPC:
            case XivRace.Hyur_Highlander_Male:
            case XivRace.Hyur_Highlander_Female:
            case XivRace.Hyur_Highlander_Male_NPC:
            case XivRace.Hyur_Highlander_Female_NPC:
                return(XivBaseRace.Hyur);

            case XivRace.Elezen_Male:
            case XivRace.Elezen_Female:
            case XivRace.Elezen_Male_NPC:
            case XivRace.Elezen_Female_NPC:
                return(XivBaseRace.Elezen);

            case XivRace.Lalafell_Male:
            case XivRace.Lalafell_Female:
            case XivRace.Lalafell_Male_NPC:
            case XivRace.Lalafell_Female_NPC:
                return(XivBaseRace.Lalafell);

            case XivRace.Miqote_Male:
            case XivRace.Miqote_Female:
            case XivRace.Miqote_Male_NPC:
            case XivRace.Miqote_Female_NPC:
                return(XivBaseRace.Miqote);

            case XivRace.Roegadyn_Male:
            case XivRace.Roegadyn_Female:
            case XivRace.Roegadyn_Male_NPC:
            case XivRace.Roegadyn_Female_NPC:
                return(XivBaseRace.Roegadyn);

            case XivRace.AuRa_Male:
            case XivRace.AuRa_Female:
            case XivRace.AuRa_Male_NPC:
            case XivRace.AuRa_Female_NPC:
                return(XivBaseRace.AuRa);

            case XivRace.Viera_Male:
            case XivRace.Viera_Female:
            case XivRace.Viera_Male_NPC:
            case XivRace.Viera_Female_NPC:
                return(XivBaseRace.Viera);

            case XivRace.Hrothgar_Male:
            case XivRace.Hrothgar_Male_NPC:
                return(XivBaseRace.Hrothgar);

            default:
                return(XivBaseRace.Hyur);
            }
        }
예제 #20
0
        /// <summary>
        /// Gets the Type of models for a given Character Item
        /// </summary>
        /// <param name="charaItem">The character item</param>
        /// <param name="race">The race</param>
        /// <param name="num">The character item number</param>
        /// <returns>A dictionary containging [</returns>
        public async Task <List <string> > GetTypeForModels(XivCharacter charaItem, XivRace race, int num)
        {
            var folder   = "";
            var file     = "";
            var typeDict = HairSlotAbbreviationDictionary;

            if (charaItem.ItemCategory == XivStrings.Body)
            {
                folder = string.Format(XivStrings.BodyMDLFolder, race.GetRaceCode(),
                                       num.ToString().PadLeft(4, '0'));
                typeDict = BodySlotAbbreviationDictionary;
                file     = XivStrings.BodyMDLFile;
            }
            else if (charaItem.ItemCategory == XivStrings.Hair)
            {
                folder = string.Format(XivStrings.HairMDLFolder, race.GetRaceCode(),
                                       num.ToString().PadLeft(4, '0'));
                typeDict = HairSlotAbbreviationDictionary;
                file     = XivStrings.HairMDLFile;
            }
            else if (charaItem.ItemCategory == XivStrings.Face)
            {
                folder = string.Format(XivStrings.FaceMDLFolder, race.GetRaceCode(),
                                       num.ToString().PadLeft(4, '0'));
                typeDict = FaceSlotAbbreviationDictionary;
                file     = XivStrings.FaceMDLFile;
            }
            else if (charaItem.ItemCategory == XivStrings.Tail)
            {
                folder = string.Format(XivStrings.TailMDLFolder, race.GetRaceCode(),
                                       num.ToString().PadLeft(4, '0'));
                typeDict = TailSlotAbbreviationDictionary;
                file     = XivStrings.TailMDLFile;
            }
            else if (charaItem.ItemCategory == XivStrings.Ears)
            {
                folder = string.Format(XivStrings.EarsMDLFolder, race.GetRaceCode(),
                                       num.ToString().PadLeft(4, '0'));
                typeDict = EarsSlotAbbreviationDictionary;
                file     = XivStrings.EarsMDLFile;
            }

            var fileList = await _index.GetAllHashedFilesInFolder(HashGenerator.GetHash(folder), XivDataFile._04_Chara);

            var typeList = new List <string>();

            foreach (var type in typeDict)
            {
                var mdlFile = string.Format(file, race.GetRaceCode(), num.ToString().PadLeft(4, '0'), type.Value);

                if (fileList.Contains(HashGenerator.GetHash(mdlFile)))
                {
                    typeList.Add(type.Key);
                }
            }

            return(typeList);
        }
        /// <summary>
        /// Gets the matrices for the bones used in the model
        /// </summary>
        /// <param name="boneList">List of bones used in the model</param>
        /// <param name="targetRace">Target Race to get the bone data for</param>
        /// <returns>A matrix array containing the pose data for each bone</returns>
        private Matrix[] GetMatrices(List <string> boneList, XivRace targetRace)
        {
            // Get the skeleton file for the target race
            var skeletonFile = Directory.GetCurrentDirectory() + $"/Skeletons/c{targetRace.GetRaceCode()}.skel";
            var skeletonData = File.ReadAllLines(skeletonFile);

            // Deserialize the skeleton json and create a dictionary of all bones
            var skelData = new Dictionary <string, SkeletonData>();

            foreach (var b in skeletonData)
            {
                if (b == "")
                {
                    continue;
                }
                var j = JsonConvert.DeserializeObject <SkeletonData>(b);

                skelData.Add(j.BoneName, j);
            }

            // Add matrices for bones in the model to a list
            // Add missing bones if they exist in the model but not in the target race
            var matrixList   = new List <Matrix>();
            var missingBones = new List <string>();

            foreach (var bone in boneList)
            {
                if (skelData.ContainsKey(bone))
                {
                    var matrix = new Matrix(skelData[bone].InversePoseMatrix);
                    matrix.Invert();

                    matrixList.Add(matrix);
                }
                else
                {
                    missingBones.Add(bone);
                }
            }

            // Show a warning when there is bones in the model that do not exist in the target race skeleton
            // The model will still be added, but with no bones animation will not work for that part
            if (missingBones.Count > 0)
            {
                var warning = new StringBuilder();
                warning.AppendLine();

                foreach (var bone in missingBones)
                {
                    warning.AppendLine(bone);
                }

                FlexibleMessageBox.Show(string.Format(UIMessages.MissingBones, targetRace, warning), UIMessages.MissingBonesTitle, MessageBoxButtons.OK, MessageBoxIcon.Warning);
            }

            return(matrixList.ToArray());
        }
        /// <summary>
        /// Creates the Bones to be used in the format Helix Toolkit uses
        /// </summary>
        /// <param name="boneList">The list of bones in the model</param>
        /// <param name="targetRace">The target race to get the bones from</param>
        /// <returns>A list of Bone structures used by Helix Toolkit</returns>
        private List <Bone> MakeHelixBones(List <string> boneList, XivRace targetRace)
        {
            // Get the skeleton file for the target race
            var skeletonFile = Directory.GetCurrentDirectory() + $"/Skeletons/c{targetRace.GetRaceCode()}.skel";
            var skeletonData = File.ReadAllLines(skeletonFile);


            // Deserialize the skeleton json and create a dictionary of all bones
            var boneDict = new Dictionary <int, SkeletonData>();

            foreach (var b in skeletonData)
            {
                if (b == "")
                {
                    continue;
                }
                var j = JsonConvert.DeserializeObject <SkeletonData>(b);

                boneDict.Add(j.BoneNumber, j);
            }

            // Add only the bones that are contained in the model including all parent bones
            var bonesInModel = new List <SkeletonData>();

            foreach (var bone in boneDict)
            {
                if (!boneList.Contains(bone.Value.BoneName))
                {
                    continue;
                }

                bonesInModel.Add(bone.Value);

                AddBones(boneDict, bonesInModel, bone.Value);
            }

            // Create a bone list with the bones for the model in helix toolkit format
            var helixBoneList = new List <Bone>();

            foreach (var bone in bonesInModel)
            {
                var bp = new Matrix(bone.InversePoseMatrix);
                bp.Invert();

                helixBoneList.Add(new Bone
                {
                    BindPose    = bp,
                    Name        = bone.BoneName,
                    ParentIndex = bone.BoneParent
                });
            }

            return(helixBoneList);
        }
예제 #23
0
        /// <summary>
        /// Determines if this race is a child of another given race or not.
        /// If the values are the same, it is considered TRUE by default.
        /// </summary>
        /// <param name="possibleChild"></param>
        /// <param name="possibleParent"></param>
        /// <returns></returns>
        public static bool IsChildOf(this XivRace possibleChild, XivRace possibleParent, bool allowSame = true)
        {
            CheckTree();
            if (possibleChild == possibleParent && allowSame)
            {
                return(true);
            }
            var isParent = IsParentOf(possibleParent, possibleChild, allowSame);

            return(isParent);
        }
        public AdvancedModelImportView(XivMdl xivMdl, IItemModel itemModel, XivRace selectedRace, bool fromWizard)
        {
            InitializeComponent();

            _fromWizard      = fromWizard;
            _viewModel       = new AdvancedImportViewModel(xivMdl, itemModel, selectedRace, this, fromWizard);
            this.DataContext = _viewModel;

            if (fromWizard)
            {
                Title = FFXIV_TexTools.Resources.UIStrings.Advanced_Model_Options;
                ImportButton.Content = FFXIV_TexTools.Resources.UIStrings.Add;
            }
        }
        /// <summary>
        /// Updates all models to the new skeleton
        /// </summary>
        /// <param name="previousRace">The original or previous race of the model</param>
        /// <param name="targetRace">The target race for the skeleton and model</param>
        public void UpdateSkin(XivRace race)
        {
            var shownModelList = new List <string>();

            foreach (var model in shownModels)
            {
                shownModelList.Add(model.Key);
            }

            foreach (var model in shownModelList)
            {
                UpdateModel(shownModels[model].TtModel, shownModels[model].ModelTextureData, shownModels[model].ItemModel, race, race);
            }
        }
예제 #26
0
        public AdvancedModelImportView(XivMdl xivMdl, IItemModel itemModel, XivRace selectedRace, bool fromWizard)
        {
            InitializeComponent();

            _fromWizard      = fromWizard;
            _viewModel       = new AdvancedImportViewModel(xivMdl, itemModel, selectedRace, this, fromWizard);
            this.DataContext = _viewModel;

            if (fromWizard)
            {
                Title = "Advanced Model Options";
                ImportButton.Content = "Add";
            }
        }
예제 #27
0
        /// <summary>
        /// Gets the internal FFXIV MTRL path for a given race's skin, using the tree as needed to find the appropriate ancestor skin.
        /// </summary>
        /// <param name="race"></param>
        /// <returns></returns>
        public static string GetSkinPath(this XivRace startingRace, int body = 1, string materialId = "a")
        {
            var race = GetSkinRace(startingRace);

            if (race != startingRace)
            {
                body = 1;
            }

            var bodyCode = body.ToString().PadLeft(4, '0');
            var path     = "/chara/human/c" + race.GetRaceCode() + "/obj/body/b" + bodyCode + "/material/v0001/mt_c" + race.GetRaceCode() + "b" + bodyCode + "_" + materialId + ".mtrl";

            return(path);
        }
예제 #28
0
        static void BatchExport()
        {
            _repo = new ExportRepository(Path.Combine(_repoPath, "repo"));

            // Gear
            var badGear = new HashSet <string>(new[]
            {
                "Doman Iron Hatchet", "Doman Iron Pickaxe",
                "Mammon Lucis", "Kurdalegon Lucis", "Rauni Lucis",
                "Kurdalegon Supra", "Rauni Supra",
                "SmallClothes Body", "SmallClothes Feet", "SmallClothes Legs"
            });

            var gearList = _gear.GetGearList()
                           .Where(g => !badGear.Contains(g.Name));

            foreach (var item in gearList)
            {
                var primaryPath = EnsurePath(item.EquipSlotCategory.ToString(), item.ModelInfo);
                BatchExportItem(primaryPath, item, null, () => _gear.GetRacesForModels(item, item.DataFile));

                if (item.SecondaryModelInfo.ModelID != 0)
                {
                    var secondaryPath = EnsurePath(item.EquipSlotCategory.ToString(), item.SecondaryModelInfo);
                    BatchExportItem(secondaryPath, item, item.SecondaryModelInfo, () => _gear.GetRacesForModels(item, item.DataFile));
                }
            }

            // Minions
            var monsters   = new XivRace[] { XivRace.Monster };
            var minionList = _companions.GetMinionList();

            foreach (var minion in minionList)
            {
                var modelKey = $"{minion.ModelInfo.ModelID}-{minion.ModelInfo.Body}-{minion.ModelInfo.Variant}";
                var path     = EnsurePath("minion", modelKey);
                BatchExportItem(path, minion, null, () => monsters);
            }

            // Mounts
            var mountList = _companions.GetMountList();

            foreach (var mount in mountList)
            {
                var modelKey = $"{mount.ModelInfo.ModelID}-{mount.ModelInfo.Body}-{mount.ModelInfo.Variant}";
                var path     = EnsurePath("mount", modelKey);
                BatchExportItem(path, mount, null, () => monsters);
            }
        }
        /// <summary>
        /// Updates all models to the new skeleton
        /// </summary>
        /// <param name="previousRace">The original or previous race of the model</param>
        /// <param name="targetRace">The target race for the skeleton and model</param>
        public void UpdateSkeleton(XivRace previousRace, XivRace targetRace)
        {
            var shownModelList = new List <string>();

            foreach (var model in shownModels)
            {
                shownModelList.Add(model.Key);
            }

            // Apply racial transforms
            // This pretty much replaces every model by deleting and recreating them with the target race deforms
            foreach (var model in shownModelList)
            {
                UpdateModel(shownModels[model].TtModel, shownModels[model].ModelTextureData, shownModels[model].ItemModel, previousRace, targetRace);
            }
        }
        /// <summary>
        /// Gets the matrices for the bones used in the model
        /// </summary>
        /// <param name="boneList">List of bones used in the model</param>
        /// <param name="targetRace">Target Race to get the bone data for</param>
        /// <returns>A matrix array containing the pose data for each bone</returns>
        private Matrix[] GetMatrices(XivRace targetRace)
        {
            // Get the skeleton, including all EX bones.
            var boneDict = GetBoneDictionary(targetRace);

            var matrixList = new List <Matrix>();

            foreach (var kv in boneDict)
            {
                var matrix = new Matrix(kv.Value.InversePoseMatrix);
                matrix.Invert();

                matrixList.Add(matrix);
            }

            return(matrixList.ToArray());
        }