//Uses box house SGB and replaces required sgbs with the given house ID's appropriate parts private void HouseRecSgb_Click(object sender, RoutedEventArgs e) { if (maplist == null) { maplist = new StringBuilder(); } maplist.Clear(); String[] poop = box.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None); box.Clear(); List <String> list = new List <string>(); foreach (String line in poop) { if (realm.Packs.FileExists(line.Trim())) { SaintCoinach.IO.File f = realm.Packs.GetFile(line.Trim()); SgbFile sgb = new SgbFile(f); //ExportSgbFileUHousing(houseIDBox.Text, "null", sgb, 0, Vector3.Zero, Vector3.Zero, Vector3.One); } } foreach (String path in list) { box.Text += path + Environment.NewLine; } }
private void addGimmicksToMapList(String lgbGroupName, LgbGimmickEntry gim) { SgbFile thisFile = gim.Gimmick; LgbGimmickEntry.HeaderData hdr = gim.Header; foreach (var iGroup in thisFile.Data) { SgbGroup eGroup = iGroup as SgbGroup; foreach (var iEntry in eGroup.Entries) { SgbModelEntry eEntry = iEntry as SgbModelEntry; if (eEntry != null) { TransformedModel mdl = eEntry.Model; TransformedModel newMdl; Vector3 pos = new Vector3(); Vector3 rot = new Vector3(); //Scale is not added or multiplied pos.X = mdl.Translation.X + hdr.Translation.X; pos.Y = mdl.Translation.Y + hdr.Translation.Y; pos.Z = mdl.Translation.Z + hdr.Translation.Z; rot.X = mdl.Rotation.X + hdr.Rotation.X; rot.Y = mdl.Rotation.Y + hdr.Rotation.Y; rot.Z = mdl.Rotation.Z + hdr.Rotation.Z; newMdl = new TransformedModel(mdl.Model, pos, rot, mdl.Scale); addToMapList(lgbGroupName, newMdl); } } } }
//Recursively obtains model paths from an sgb file private void getGimmickPaths(SgbFile file, ref List <String> list) { if (file == null) { return; } bool onec = false; foreach (var sgbGroup in file.Data.OfType <SgbGroup>()) { //Entry is model foreach (var mdl in sgbGroup.Entries.OfType <SgbModelEntry>()) { addToFileList(mdl.Model.Model.File.Path); } //Entry is another Sgb foreach (var gimmickEntry in sgbGroup.Entries.OfType <SgbGimmickEntry>()) { getGimmickPaths(gimmickEntry.Gimmick, ref list); } //Entry is Sgb1C foreach (var sgb1c in sgbGroup.Entries.OfType <SgbGroup1CEntry>()) { if (!onec) { getGimmickPaths(sgb1c.Gimmick, ref list); onec = true; } } } }
/// <summary> /// Attempts to read all entries of type SgbModelEntry from the paths contained in sgbPaths, /// constructs a HousingExteriorFixtureModel for each entry and returns all variants. /// </summary> /// <param name="realm"></param> /// <param name="sgbPaths"></param> /// <returns></returns> private static HousingExteriorFixtureVariant[] ReadSgbForVariantInfo(ARealmReversed realm, string[] sgbPaths) { HousingExteriorFixtureVariant[] variants = new HousingExteriorFixtureVariant[sgbPaths.Length]; for (int i = 0; i < sgbPaths.Length; i++) { //Check if sgb valid then get it SaintCoinach.IO.File baseFile; if (!realm.Packs.TryGetFile(sgbPaths[i], out baseFile)) { throw new FileNotFoundException(); } SgbFile sgb = new SgbFile(baseFile); //Get modelEntries HousingExteriorFixtureVariant thisVariant = new HousingExteriorFixtureVariant(); thisVariant.sgbPath = sgbPaths[i]; List <HousingExteriorFixtureModel> modelsList = new List <HousingExteriorFixtureModel>(); foreach (SgbGroup group in sgb.Data.OfType <SgbGroup>()) { foreach (SgbModelEntry mdl in group.Entries.OfType <SgbModelEntry>()) { modelsList.Add(ReadTransformedModelForModelInfo(mdl.Model)); } } thisVariant.models = modelsList.ToArray(); variants[i] = thisVariant; } return(variants); }
void ExportSgbFile(String lgbGroup, SgbFile sgbFile, int depth, Vector3 translation, Vector3 rotation, Vector3 scale) { if (sgbFile == null) { return; } bool onec = false; addToFileList(sgbFile.File.Path); foreach (var sgbGroup in sgbFile.Data.OfType <SgbGroup>()) { //Entry is model foreach (var mdl in sgbGroup.Entries.OfType <SgbModelEntry>()) { addToFileList(mdl.Model.Model.File.Path); TransformedModel tMdl = mdl.Model; TransformedModel newMdl; Vector3 pos = new Vector3(); Vector3 rot = new Vector3(); pos.X = tMdl.Translation.X + translation.X; pos.Y = tMdl.Translation.Y + translation.Y; pos.Z = tMdl.Translation.Z + translation.Z; rot.X = tMdl.Rotation.X + rotation.X; rot.Y = tMdl.Rotation.Y + rotation.Y; rot.Z = tMdl.Rotation.Z + rotation.Z; newMdl = new TransformedModel(tMdl.Model, pos, rot, tMdl.Scale); addToMapList(lgbGroup, newMdl); } //Entry is another Sgb foreach (var gimmickEntry in sgbGroup.Entries.OfType <SaintCoinach.Graphics.Sgb.SgbGimmickEntry>()) { addGimmickInfoToMapList(gimmickEntry, depth); ExportSgbFile(lgbGroup, gimmickEntry.Gimmick, depth + 1, gimmickEntry.Header.Translation, gimmickEntry.Header.Rotation, gimmickEntry.Header.Scale); addHeaderToMapList("GimmickEnd", depth); } //Entry is Sgb1C foreach (var sgb1c in sgbGroup.Entries.OfType <SgbGroup1CEntry>()) { if (!onec) { addHeaderToMapList("Gimmick1C", depth); ExportSgbFile(lgbGroup, sgb1c.Gimmick, depth + 1, translation, rotation, scale); addHeaderToMapList("GimmickEnd", depth); onec = true; } } } }
/// <summary> /// Parses an SgbFile for model entries or further gimmicks, and adds groups /// to the given MapGroup. /// </summary> /// <param name="file"></param> /// <param name="parent"></param> /// <param name="models"></param> private static void AddSgbModelsToMap(ref Map map, ref MapGroup mg, SgbFile file) { foreach (var sgbGroup in file.Data.OfType <SgbGroup>()) { foreach (var mdl in sgbGroup.Entries.OfType <SgbModelEntry>()) { int modelId = map.TryAddUniqueModel(mdl.Model.Model.ToMapModel()); mg.AddEntry(mdl.Model.ToMapModelEntry(modelId)); } } }
//Retrieves model entries from this gimmick entry private List <String> getGimmickPaths(LgbGimmickEntry entry) { List <String> gimmickFileList = new List <String>(); SgbFile thisFile = entry.Gimmick; foreach (var iGroup in thisFile.Data) { SgbGroup eGroup = iGroup as SgbGroup; foreach (var iEntry in eGroup.Entries) { SgbModelEntry eEntry = iEntry as SgbModelEntry; if (eEntry != null) { gimmickFileList.Add(eEntry.Model.Model.File.Path); } } } return(gimmickFileList); }
private bool TryGetModel(out SgbFile model) { model = null; if (SelectedFurniture == null) { return(false); } try { model = SelectedFurniture.GetScene(); var result = (model != null); if (!result) { System.Windows.MessageBox.Show(string.Format("Unable to find model for {0}.", SelectedFurniture.Item.Name), "Model not found", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); } return(result); } catch (Exception e) { System.Windows.MessageBox.Show(string.Format("Failed to load model for {0}:{2}{3}", SelectedFurniture.Item.Name, Environment.NewLine, e), "Read failure", System.Windows.MessageBoxButton.OK, System.Windows.MessageBoxImage.Error); return(false); } }
//Replaces all sgbs in box with their model contents private void ResolveBoxSgbs_Click(object sender, RoutedEventArgs e) { String[] sgbs = box.Text.Split(new[] { Environment.NewLine }, StringSplitOptions.None); box.Clear(); List <String> list = new List <string>(); foreach (String line in sgbs) { if (realm.Packs.FileExists(line.Trim())) { SaintCoinach.IO.File f = realm.Packs.GetFile(line.Trim()); SgbFile sgb = new SgbFile(f); getGimmickPaths(sgb, ref list); } } foreach (String path in list) { box.Text += path + Environment.NewLine; } }
private void ExportSgbFileUHousing(String desiredHouseID, String lgbGroup, SgbFile sgbFile, int depth, Vector3 translation, Vector3 rotation, Vector3 scale) { if (sgbFile == null) { return; } String housingPattern = @"bg/ffxiv/(est_e1|sea_s1|fst_f1|wil_w1)/hou/dyna/(.*?)/(0000)/asset/(e1h0|s1h0|f1h0|w1h0)_(.*?)(0000)(\w?).sgb"; String housingPattern2 = @"bgcommon/hou/dyna/(e1h0|s1h0|f1h0|w1h0)/(.*?)/(0000)/asset/(e1h0|s1h0|f1h0|w1h0)_(.*?)(0000)(\w?).sgb"; String housingPattern3 = @"bgcommon/hou/dyna/opt/(.*?)/(0000)/asset/opt_(.*?)(0000).sgb"; //bool onec = false; foreach (var sgbGroup in sgbFile.Data.OfType <SgbGroup>()) { //Entry is model foreach (var mdl in sgbGroup.Entries.OfType <SgbModelEntry>()) { addToFileList(mdl.Model.Model.File.Path); TransformedModel tMdl = mdl.Model; TransformedModel newMdl; Vector3 pos = new Vector3(); Vector3 rot = new Vector3(); pos.X = tMdl.Translation.X + translation.X; pos.Y = tMdl.Translation.Y + translation.Y; pos.Z = tMdl.Translation.Z + translation.Z; rot.X = tMdl.Rotation.X + rotation.X; rot.Y = tMdl.Rotation.Y + rotation.Y; rot.Z = tMdl.Rotation.Z + rotation.Z; newMdl = new TransformedModel(tMdl.Model, pos, rot, tMdl.Scale); addToMapList(lgbGroup, newMdl); } //Entry is another Sgb foreach (var gimmickEntry in sgbGroup.Entries.OfType <SgbGimmickEntry>()) { //Check against each pattern to turn it into the appropriate path String gimmickFileName = gimmickEntry.Gimmick.File.Path; addToFileList(gimmickFileName); if (Regex.IsMatch(gimmickFileName, housingPattern)) { String newGimmickPath = CreateUnitedHouseString(desiredHouseID, Regex.Match(gimmickFileName, housingPattern)); SgbFile newGim = null; if (realm.Packs.FileExists(newGimmickPath)) { newGim = new SgbFile(realm.Packs.GetFile(newGimmickPath)); } if (newGim != null) { ExportSgbFile(lgbGroup, newGim, depth + 1, gimmickEntry.Header.Translation, gimmickEntry.Header.Rotation, gimmickEntry.Header.Scale); } } else if (Regex.IsMatch(gimmickFileName, housingPattern2)) { String newGimmickPath = CreateUnitedHouseString(desiredHouseID, Regex.Match(gimmickFileName, housingPattern2)); SgbFile newGim = null; if (realm.Packs.FileExists(newGimmickPath)) { newGim = new SgbFile(realm.Packs.GetFile(newGimmickPath)); } if (newGim != null) { ExportSgbFile(lgbGroup, newGim, depth + 1, gimmickEntry.Header.Translation, gimmickEntry.Header.Rotation, gimmickEntry.Header.Scale); } } else if (Regex.IsMatch(gimmickFileName, housingPattern3)) { String newGimmickPath = CreateUnitedHouseString(desiredHouseID, Regex.Match(gimmickFileName, housingPattern3)); SgbFile newGim = null; if (realm.Packs.FileExists(newGimmickPath)) { newGim = new SgbFile(realm.Packs.GetFile(newGimmickPath)); } if (newGim != null) { ExportSgbFile(lgbGroup, newGim, depth + 1, gimmickEntry.Header.Translation, gimmickEntry.Header.Rotation, gimmickEntry.Header.Scale); } } else { addGimmickInfoToMapList(gimmickEntry, depth); ExportSgbFileUHousing(desiredHouseID, lgbGroup, gimmickEntry.Gimmick, depth + 1, gimmickEntry.Header.Translation, gimmickEntry.Header.Rotation, gimmickEntry.Header.Scale); addHeaderToMapList("GimmickEnd", depth); } } //Entry is Sgb1C // foreach (var sgb1c in sgbGroup.Entries.OfType<SgbGroup1CEntry>()) // { // if (!onec) // { // addHeaderToMapList("Gimmick1C", depth); // ExportSgbFile(lgbGroup, sgb1c.Gimmick, depth + 1, translation, // rotation, scale); // addHeaderToMapList("GimmickEnd", depth); // onec = true; // } // } } }
/// <summary> /// Returns a HousingExteriorBlueprintSet read from the small, medium, and large sgb paths in /// HousingExteriorBlueprintSet. /// </summary> /// <param name="realm"></param> /// <returns></returns> private static HousingExteriorBlueprintSet ReadExteriorBlueprintSet(ARealmReversed realm) { HousingExteriorBlueprintSet thisSet = new HousingExteriorBlueprintSet(); thisSet.set = new HousingExteriorBlueprint[HousingExteriorBlueprintSet.SgbPaths.Length]; for (int i = 0; i < HousingExteriorBlueprintSet.SgbPaths.Length; i++) { string thisPath = HousingExteriorBlueprintSet.SgbPaths[i]; HousingExteriorBlueprint thisBlueprint = new HousingExteriorBlueprint { size = (Size)i }; //These are hardcoded, double check they're there SaintCoinach.IO.File f; if (!realm.Packs.TryGetFile(thisPath, out f)) { throw new FileNotFoundException(); } SgbFile sgb = new SgbFile(f); foreach (SgbGroup group in sgb.Data.OfType <SgbGroup>()) { foreach (SgbGimmickEntry gim in group.Entries.OfType <SgbGimmickEntry>()) { string gimmickPath = gim.Gimmick.File.Path; /* * Group 1: s1h0 or opt * Group 2: size, dor/wid variant, f for fence, or opt's 2chars * Group 3: fixturetype or m for opt * Group 4: a/b/c/d for fence, . for all others */ Regex pattern = new Regex(@"asset\/(.*)?_(.{1,2})_(.{1,3})([0-9]{4})([a-z]|\.)"); Match m = pattern.Match(gimmickPath); if (!m.Success) { continue; } //Obtain fixture type string fType = m.Groups[3].Value; if (fType == "m") { fType = "o" + m.Groups[2].Value; } FixtureType fixtureType = (FixtureType)Enum.Parse(typeof(FixtureType), fType); //Obtains the variant string, examples: s, m, l, co, ca, ci, a, b, c, d string strVariant = m.Groups[5].Value == "." ? m.Groups[2].Value : m.Groups[5].Value; int variant = 0; //Attempt to parse group 2 into a Size to get variant if (!Enum.TryParse(strVariant, out Size fixtureSize)) { //If we can't parse variant to a size, we have to parse into a different fixture variant if (fixtureType == FixtureType.dor) { variant = (int)Enum.Parse(typeof(DoorVariants), strVariant); } else if (fixtureType == FixtureType.wid) { variant = (int)Enum.Parse(typeof(WindowVariants), strVariant); } else if (fixtureType == FixtureType.fnc) { variant = (int)Enum.Parse(typeof(FenceVariants), strVariant); } } else { //If rof/wal is not same size as blueprint, skip it if (fixtureSize != thisBlueprint.size) { continue; } } if (thisBlueprint.fixtureTransforms[fixtureType][variant] == null) { thisBlueprint.fixtureTransforms[fixtureType][variant] = new List <Transform>(); } List <Transform> listForVariant = thisBlueprint.fixtureTransforms[fixtureType][variant]; Transform t = TransformFromVectors(gim.Header.Translation, gim.Header.Rotation, gim.Header.Scale); listForVariant.Add(t); #region switch statement bad // switch (m.Groups[3].Value) // { // case nameof(FixtureType.rof): // if (m.Groups[2].Value == size.ToString()) // { // //exampe but cool // } // break; // case nameof(FixtureType.wal): // //Do stuff // break; // case nameof(FixtureType.wid): // //Do stuff // break; // case nameof(FixtureType.dor): // //Do stuff // break; // case "m": // switch ("o" + m.Groups[2].Value) // { // case nameof(FixtureType.orf): // //Do stuff // break; // case nameof(FixtureType.owl): // //Do stuff // break; // case nameof(FixtureType.osg): // //Do stuff // break; // } // break; // case nameof(FixtureType.fnc): // //Do stuff // break; // } #endregion } } /* * The transforms relevant to the current blueprint come first, * so figure out how many Transforms aren't for this size house * by checking how many transforms are collectively in the blueprints * below this size and variant, then remove that number of entries. */ if (i > 0) { int[][] numTransformsInSmallerBlueprints = new int[Enum.GetValues(typeof(FixtureType)).Length][]; //For every smaller blueprint for (int smallerBlueprintIndex = 0; smallerBlueprintIndex < i; smallerBlueprintIndex++) { //For every fixture type for (int fixtureTypeIndex = 0; fixtureTypeIndex < numTransformsInSmallerBlueprints.Length; fixtureTypeIndex++) { FixtureType fixtureType = (FixtureType)fixtureTypeIndex + 1; int numberOfVariants = HousingExteriorFixture.GetVariants(fixtureType); if (numTransformsInSmallerBlueprints[fixtureTypeIndex] == null) { numTransformsInSmallerBlueprints[fixtureTypeIndex] = new int[numberOfVariants]; } for (int variantIndex = 0; variantIndex < numberOfVariants; variantIndex++) { int?toAddn = thisSet.set[smallerBlueprintIndex].fixtureTransforms[fixtureType][variantIndex]?.Count; int toAdd = toAddn ?? 0; numTransformsInSmallerBlueprints[fixtureTypeIndex][variantIndex] += toAdd; } } } //Whoops, don't do it for fences for (int j = 0; j < numTransformsInSmallerBlueprints[(int)FixtureType.fnc - 1].Length; j++) { numTransformsInSmallerBlueprints[(int)FixtureType.fnc - 1][j] = 0; } //For every fixture type for (int fixtureTypeIndex = 0; fixtureTypeIndex < numTransformsInSmallerBlueprints.Length; fixtureTypeIndex++) { FixtureType fixtureType = (FixtureType)fixtureTypeIndex + 1; int numberOfVariants = HousingExteriorFixture.GetVariants(fixtureType); for (int variantIndex = 0; variantIndex < numberOfVariants; variantIndex++) { List <Transform> variantTransformsList = thisBlueprint.fixtureTransforms[fixtureType][variantIndex]; if (thisBlueprint.fixtureTransforms[fixtureType][variantIndex] == null) { continue; } if (variantTransformsList == null) { continue; } int numTransforms = variantTransformsList.Count; int difference = numTransforms - numTransformsInSmallerBlueprints[fixtureTypeIndex][variantIndex]; if (difference > 0) { List <Transform> newTransforms = new List <Transform>(); for (int tCount = 0; tCount < difference; tCount++) { newTransforms.Add(variantTransformsList[tCount]); } thisBlueprint.fixtureTransforms[fixtureType][variantIndex] = newTransforms; } } } } thisSet.set[i] = thisBlueprint; } return(thisSet); }