/// <summary> /// Retrieves the file path to the model's base skeleton file. /// </summary> /// <param name="fullMdlPath"></param> private static async Task <string> GetBaseSkelbPath(XivDependencyRootInfo root, XivRace race = XivRace.All_Races) { var skelFolder = ""; var skelFile = ""; if (root.PrimaryType != XivItemType.human && root.PrimaryType != XivItemType.equipment && root.PrimaryType != XivItemType.accessory) { var typeName = XivItemTypes.GetSystemName(root.PrimaryType); var prefix = XivItemTypes.GetSystemPrefix(root.PrimaryType); var id = root.PrimaryId.ToString().PadLeft(4, '0'); var bodyCode = "0001"; var path = $"chara/{typeName}/{prefix}{id}/skeleton/base/b{bodyCode}/skl_{prefix}{id}b{bodyCode}.sklb"; return(path); } else { // Equipment and accessories need an external race passed in. var raceCode = race.GetRaceCode(); if (root.PrimaryType == XivItemType.human && race != XivRace.All_Races) { raceCode = root.PrimaryId.ToString().PadLeft(4, '0'); } var bodyCode = "0001"; skelFolder = $"chara/human/c{raceCode}/skeleton/base/b{bodyCode}"; skelFile = $"skl_c{raceCode}b{bodyCode}.sklb"; return(skelFolder + "/" + skelFile); } }
public static char GetVfxPrefix(XivDependencyRootInfo root) { var itemType = root.PrimaryType; if (root.PrimaryType == XivItemType.demihuman) { itemType = (XivItemType)root.SecondaryType; } if (itemType == XivItemType.equipment) { return('e'); } else if (itemType == XivItemType.weapon) { return('w'); } else if (itemType == XivItemType.monster) { return('m'); } else { return('\0'); } }
private static async Task <string> GetExtraSkelbPath(XivDependencyRootInfo root, XivRace race = XivRace.All_Races) { var type = Est.GetEstType(root); // Type doesn't use extra skels. if (type == Est.EstType.Invalid) { return(null); } var id = (ushort)root.PrimaryId; if (type == Est.EstType.Face || type == Est.EstType.Hair) { id = (ushort)root.SecondaryId; } // Hair and face types have a race defined at root level. if ((type == Est.EstType.Face || type == Est.EstType.Hair) && race == XivRace.All_Races) { var ret = new Dictionary <XivRace, ExtraSkeletonEntry>(); race = XivRaces.GetXivRace(root.PrimaryId); } var entry = await Est.GetExtraSkeletonEntry(type, race, id); var skelId = entry.SkelId; if (skelId == 0) { if (race == XivRace.Hyur_Midlander_Male) { return(null); } // Okay, this model, *as defined* has no EX Skeleton. _HOWEVER_ its parent skeleton could. // So we need to re-call and check up the chain until we hit Hyur M. var parent = XivRaceTree.GetNode(race).Parent; if (parent == null) { return(null); } // It's worth noting in these cases, the Skeletal bones themselves will still be using the matrices appropriate // for their parent race in this method, but that should be sufficient for now. return(await GetExtraSkelbPath(root, parent.Race)); } var prefix = Est.GetSystemPrefix(type); var slot = Est.GetSystemSlot(type); var raceCode = XivRaces.GetRaceCode(race); var skelCode = skelId.ToString().PadLeft(4, '0'); var path = $"chara/human/c{raceCode}/skeleton/{slot}/{prefix}{skelCode}/skl_c{raceCode}{prefix}{skelCode}.sklb"; return(path); }
public static bool UsesImc(XivDependencyRootInfo root) { if (root.PrimaryType == XivItemType.human) { return(false); } else if (root.PrimaryType == XivItemType.indoor || root.PrimaryType == XivItemType.outdoor) { return(false); } else { return(true); } }
public static async Task <string> GetExtraSkeletonFile(XivDependencyRootInfo root, XivRace race = XivRace.All_Races) { if (root.SecondaryType == XivItemType.ear) { // Viera ears technically use their associated face's Extra Skeleton to resolve the bones. Kinda weird, but whatever. // The bones are nearly identical for all the faces, so just use face 1 var nRoot = new XivDependencyRootInfo() { PrimaryType = root.PrimaryType, PrimaryId = root.PrimaryId, SecondaryId = 1, SecondaryType = XivItemType.face, Slot = "fac" }; root = nRoot; } var file = await GetExtraSkelbPath(root, race); if (file == null) { return(null); } var skelName = Path.GetFileNameWithoutExtension(file).Replace("skl_", ""); var cwd = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); var parsedFile = Path.Combine(cwd, SkeletonsFolder, skelName + ".skel"); if (File.Exists(parsedFile)) { return(parsedFile); } try { // In some cases, the extra skeleton doesn't actually exist, despite the // game files saying it should. In these cases, SE actually intends to // default to the base skel. await ExtractAndParseSkel(file); } catch { return(null); } return(parsedFile); }
public static async Task <string> GetBaseSkeletonFile(XivDependencyRootInfo root, XivRace race) { var file = await GetBaseSkelbPath(root, race); var skelName = Path.GetFileNameWithoutExtension(file).Replace("skl_", ""); var cwd = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetEntryAssembly().Location); var parsedFile = Path.Combine(cwd, SkeletonsFolder, skelName + ".skel"); if (File.Exists(parsedFile)) { return(parsedFile); } await ExtractAndParseSkel(file); return(parsedFile); }
private void Mw_SelectedPrimaryItemValueChanged(object sender, int e) { if (_root == null) { return; } // Only human types have the weird multi-root "Item" representation thing. if (_root.Info.PrimaryType != XivItemType.human) { return; } // Body stuff is totally desynced. if (_root.Info.SecondaryType == XivItemType.body) { return; } if (e <= 0) { return; } if (e == (int)_root.Info.SecondaryId) { return; } // Change root to the new "number" root. var nRoot = new XivDependencyRootInfo() { PrimaryId = _root.Info.PrimaryId, PrimaryType = _root.Info.PrimaryType, SecondaryId = e, SecondaryType = _root.Info.SecondaryType, Slot = _root.Info.Slot }; _lastNumber = e; // Switch display to that new root. SetRoot(nRoot.ToFullRoot()); }
public static EstType GetEstType(XivDependencyRootInfo root) { if (root.PrimaryType == XivItemType.human) { if (root.SecondaryType == XivItemType.face) { return(EstType.Face); } else if (root.SecondaryType == XivItemType.hair) { return(EstType.Hair); } else { return(EstType.Invalid); } } else if (root.PrimaryType == XivItemType.equipment) { if (root.Slot == "met") { return(EstType.Head); } else if (root.Slot == "top") { return(EstType.Body); } else { return(EstType.Invalid); } } else { return(EstType.Invalid); } }
public static async Task <(string Folder, string File)> GetVfxPath(XivDependencyRootInfo root, int vfx) { var type = root.PrimaryType; var id = root.PrimaryId.ToString().PadLeft(4, '0'); var bodyVer = root.SecondaryId.ToString().PadLeft(4, '0'); var prefix = XivItemTypes.GetSystemPrefix(type); var vfxPrefix = GetVfxPrefix(root); string vfxFolder, vfxFile; switch (type) {// case XivItemType.equipment: vfxFolder = $"chara/{type}/{prefix}{id}/vfx/eff"; vfxFile = $"v{vfxPrefix}{vfx.ToString().PadLeft(4, '0')}.avfx"; break; case XivItemType.weapon: case XivItemType.monster: vfxFolder = $"chara/{type}/{prefix}{id}/obj/body/b{bodyVer}/vfx/eff"; vfxFile = $"v{vfxPrefix}{vfx.ToString().PadLeft(4, '0')}.avfx"; break; case XivItemType.demihuman: vfxFolder = $"chara/{type}/{prefix}{id}/obj/equipment/e{bodyVer}/vfx/eff"; vfxFile = $"v{vfxPrefix}{vfx.ToString().PadLeft(4, '0')}.avfx"; break; default: vfxFolder = ""; vfxFile = ""; break; } return(vfxFolder, vfxFile); }
public static async Task <Dictionary <XivRace, ExtraSkeletonEntry> > GetExtraSkeletonEntries(XivDependencyRootInfo root, bool forceDefault = false) { var type = GetEstType(root); if (type == EstType.Invalid) { return(new Dictionary <XivRace, ExtraSkeletonEntry>()); } var id = (ushort)root.PrimaryId; if (type == EstType.Face || type == EstType.Hair) { id = (ushort)root.SecondaryId; } var entries = await GetExtraSkeletonEntries(type, id, forceDefault); // Hair and Faces have to be further trimmed down to only the entries associated with their root. if (type == EstType.Face || type == EstType.Hair) { var ret = new Dictionary <XivRace, ExtraSkeletonEntry>(); var race = XivRaces.GetXivRace(root.PrimaryId); if (entries.ContainsKey(race)) { ret.Add(race, entries[race]); } else { ret.Add(race, new ExtraSkeletonEntry(race, id)); } entries = ret; } return(entries); }
public async Task <bool> SetRoot(XivDependencyRoot root, int defaultVariant = 0) { _root = root; if (_root == null) { return(false); } if (root.Info.PrimaryType == XivItemType.human) { if (_lastNumber > 0) { if (_lastNumber != (int)root.Info.SecondaryId) { // Change root to the new "number" root. var nRoot = new XivDependencyRootInfo() { PrimaryId = _root.Info.PrimaryId, PrimaryType = _root.Info.PrimaryType, SecondaryId = _lastNumber, SecondaryType = _root.Info.SecondaryType, Slot = _root.Info.Slot }; _root = nRoot.ToFullRoot(); } } if (_root.Info.SecondaryId > 0) { _lastNumber = (int)_root.Info.SecondaryId; } } SetLabel.Content = XivItemTypes.GetSystemPrefix(root.Info.PrimaryType) + root.Info.PrimaryId.ToString().PadLeft(4, '0'); SlotLabel.Content = Mdl.SlotAbbreviationDictionary.FirstOrDefault(x => x.Value == _root.Info.Slot).Key + "(" + _root.Info.Slot + ")"; var items = await _root.GetAllItems(); ItemNameBox.Text = "[" + items.Count + "] " + items[0].Name; var _modding = new Modding(XivCache.GameInfo.GameDirectory); var path = _root.Info.GetRootFile(); var mod = await _modding.TryGetModEntry(path); if (mod == null) { ToggleButton.IsEnabled = false; ToggleButton.Content = "Enable"; } else { ToggleButton.IsEnabled = true; if (mod.enabled) { ToggleButton.Content = "Disable"; } else { ToggleButton.Content = "Enable"; } } return(await _vm.SetRoot(_root, defaultVariant)); }