private static bool SaveSet(ICLIFlags flags, string basePath, ulong entityMain, string heroFileName, string skin, ref STUVoiceSetComponent voiceSetComponent, ref Combo.ComboInfo info, STUVoiceSetComponent baseComponent = null, Combo.ComboInfo baseCombo = null, Dictionary <ulong, ulong> replacements = null) { voiceSetComponent = GetInstance <STUVoiceSetComponent>(Combo.GetReplacement(entityMain, replacements)); if (voiceSetComponent?.m_voiceDefinition == null) { Debugger.Log(0, "DataTool.SaveLogic.Unlock.VoiceLine", "[DataTool.SaveLogic.Unlock.VoiceLine]: VoiceSet not found"); return(false); } info = new Combo.ComboInfo(); Combo.Find(info, Combo.GetReplacement(voiceSetComponent.m_voiceDefinition, replacements), replacements); if (baseComponent != null && baseCombo != null) { if (!Combo.RemoveDuplicateVoiceSetEntries(baseCombo, ref info, baseComponent.m_voiceDefinition, Combo.GetReplacement(voiceSetComponent.m_voiceDefinition, replacements))) { return(false); } } Log($"\tSaving {skin}"); var context = new SaveLogic.Combo.SaveContext(info); SaveLogic.Combo.SaveVoiceSet(flags, Path.Combine(basePath, Container, heroFileName, skin), context, Combo.GetReplacement(voiceSetComponent.m_voiceDefinition, replacements)); context.Wait(); return(true); }
public void Parse(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } Combo.ComboInfo info = new Combo.ComboInfo(); foreach (ulong key in TrackedFiles[0x4]) { Combo.Find(info, key); } Log($"Preparing to save roughly {info.m_textures.Count()} textures."); Log($"This will take a long time and take up a lot of space."); var saveContext = new SaveLogic.Combo.SaveContext(info); SaveLogic.Combo.SaveLooseTextures(flags, Path.Combine(basePath, "004Dump"), saveContext); saveContext.Wait(); }
public void GetLootboxes(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } foreach (ulong key in TrackedFiles[0xCF]) { STULootBox lootbox = GetInstance <STULootBox>(key); if (lootbox == null) { continue; } string name = LootBox.GetName(lootbox.m_lootboxType); Combo.ComboInfo info = Combo.Find(null, lootbox.m_baseEntity); // 003 Combo.Find(info, lootbox.m_chestEntity); // 003 Combo.Find(info, lootbox.m_idleEffect); // 00D Combo.Find(info, lootbox.m_FEC3ED62); // 00D Combo.Find(info, lootbox.m_FFE7768F); // 00D Combo.Find(info, lootbox.m_baseModelLook); // 01A Combo.Find(info, lootbox.m_modelLook); Combo.Find(info, 0x400000000001456); // coin chest, todo // 00000000315A.00C in 000000001456.003 (288230376151716950) if (lootbox.m_shopCards != null) { foreach (STULootBoxShopCard lootboxShopCard in lootbox.m_shopCards) { Combo.Find(info, lootboxShopCard.m_cardTexture); // 004 } } var context = new SaveLogic.Combo.SaveContext(info); SaveLogic.Combo.SaveLooseTextures(flags, Path.Combine(basePath, Container, name, "ShopCards"), context); SaveLogic.Combo.Save(flags, Path.Combine(basePath, Container, name), context); context.Wait(); SaveScratchDatabase(); } }
public void ExtractNewEntities(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } if (flags.Positionals.Length != 4) { throw new Exception("incorrect params provided"); } var file = flags.Positionals[3]; const string container = "DebugNewEntities2"; Combo.ComboInfo info = new Combo.ComboInfo(); var types = new ushort[] { 0x4, 0x7C, 0x3F, 0xB2 }; if (file.EndsWith("guids")) { var guids = GetGUIDs(file); AddNewByGUID(info, guids, types); } else if (file.EndsWith("cmfhashes")) { // does this even still work? var contentHashes = GetContentHashes(file); AddNewByContentHash(info, contentHashes, types); } else { throw new Exception("unknown file type"); } var context = new SaveLogic.Combo.SaveContext(info); SaveLogic.Combo.Save(flags, Path.Combine(basePath, container), context); SaveLogic.Combo.SaveAllSoundFiles(flags, Path.Combine(basePath, container, "Sounds"), context); SaveLogic.Combo.SaveAllVoiceSoundFiles(flags, Path.Combine(basePath, container, "VoiceSounds"), context); SaveLogic.Combo.SaveLooseTextures(flags, Path.Combine(basePath, container, "LooseTex"), context); SaveLogic.Combo.SaveAllStrings(flags, Path.Combine(basePath, container, "Strings"), info); context.Wait(); }
public void ExtractVoiceSets(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } const string container = "DebugVoiceSet"; foreach (ulong key in TrackedFiles[0x5F]) { if (teResourceGUID.Index(key) != 0x19F) { continue; } string voiceMaterDir = Path.Combine(basePath, container, GetFileName(key)); Combo.ComboInfo info = new Combo.ComboInfo(); var context = new SaveLogic.Combo.SaveContext(info); Combo.Find(info, key); SaveLogic.Combo.SaveVoiceSet(flags, voiceMaterDir, context, key); context.Wait(); // foreach (STUVoiceLineInstance voiceLineInstance in voiceSet.VoiceLineInstances) { // if (voiceLineInstance?.SoundDataContainer == null) continue; // // Combo.ComboInfo info = new Combo.ComboInfo(); // // Combo.Find(info, voiceLineInstance.SoundDataContainer.SoundbankMasterResource); // // foreach (ulong soundInfoNew in info.Sounds.Keys) { // SaveLogic.Combo.SaveSound(flags, voiceMaterDir, info, soundInfoNew); // } // } } }
public static void SaveAbilities(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } const string folderName = "Abilities"; foreach (ulong key in TrackedFiles[0x9E]) { STULoadout loadout = GetInstance <STULoadout>(key); if (loadout == null) { continue; } string name = GetValidFilename(GetString(loadout.m_name)?.TrimEnd().Replace(".", "_")) ?? $"Unknown{teResourceGUID.Index(key):X}"; Combo.ComboInfo info = new Combo.ComboInfo(); Combo.Find(info, loadout.m_texture); var context = new SaveLogic.Combo.SaveContext(info); SaveLogic.Combo.SaveLooseTextures(flags, Path.Combine(basePath, folderName, name), context); context.Wait(); using (Stream videoStream = OpenFile(loadout.m_infoMovie)) { if (videoStream != null) { videoStream.Position = 128; // wrapped in "MOVI" for some reason WriteFile(videoStream, Path.Combine(basePath, folderName, name, $"{teResourceGUID.LongKey(loadout.m_infoMovie):X12}.bk2")); } } } }
public void Parse(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } const string container = "GamemodeImages"; string path = Path.Combine(basePath, container); foreach (ulong key in TrackedFiles[0xEE]) { var stuE3594B8E = Helper.STUHelper.GetInstance <STU_E3594B8E>(key); if (stuE3594B8E == null) { continue; } string name = $"{teResourceGUID.Index(key):X3}_{GetString(stuE3594B8E.m_name)}"; Combo.ComboInfo info = new Combo.ComboInfo(); Combo.Find(info, (ulong)stuE3594B8E.m_21EB3E73); info.SetTextureName((ulong)stuE3594B8E.m_21EB3E73, name); var context = new SaveLogic.Combo.SaveContext(info); SaveLogic.Combo.SaveLooseTextures(flags, path, context); context.Wait(); } }
public void ExtractHeroConvos(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } if (flags.Positionals.Length < 4) { QueryHelp(QueryTypes); return; } string path = Path.Combine(basePath, Container); Dictionary <string, Dictionary <string, ParsedArg> > parsedTypes = ParseQuery(flags, QueryTypes, QueryNameOverrides); if (parsedTypes == null) { return; } Dictionary <ulong, VoiceSet> allVoiceSets = new Dictionary <ulong, VoiceSet>(); foreach (var voiceSetGUID in Program.TrackedFiles[0x5F]) { STUVoiceSet set = GetInstance <STUVoiceSet>(voiceSetGUID); if (set?.m_voiceLineInstances == null) { continue; } allVoiceSets[voiceSetGUID] = new VoiceSet(set); } // Dictionary<uint, string> mapNames = new Dictionary<uint, string>(); // foreach (ulong mapGuid in Program.TrackedFiles[0x9F]) { // STUMapHeader mapHeader = GetInstance<STUMapHeader>(mapGuid); // if (mapHeader == null) continue; // // mapNames[teResourceGUID.Index(mapGuid)] = GetValidFilename(GetString(mapHeader.m_1C706502) ?? GetString(mapHeader.m_displayName)); // } Combo.ComboInfo comboInfo = new Combo.ComboInfo(); var comboSaveContext = new SaveLogic.Combo.SaveContext(comboInfo); foreach (ulong heroGuid in Program.TrackedFiles[0x75]) { STUHero hero = GetInstance <STUHero>(heroGuid); if (hero == null) { continue; } STUVoiceSetComponent voiceSetComponent = GetInstance <STUVoiceSetComponent>(hero.m_gameplayEntity); if (voiceSetComponent?.m_voiceDefinition == null || !allVoiceSets.TryGetValue(voiceSetComponent.m_voiceDefinition, out var set)) { Debugger.Log(0, "DataTool.SaveLogic.Unlock.VoiceLine", "[DataTool.SaveLogic.Unlock.VoiceLine]: VoiceSet not found\r\n"); continue; } string heroNameActual = (GetString(hero.m_0EDCE350) ?? $"Unknown{teResourceGUID.Index(heroGuid)}").TrimEnd(' '); Dictionary <string, ParsedArg> config = GetQuery(parsedTypes, heroNameActual.ToLowerInvariant(), "*", teResourceGUID.Index(heroGuid).ToString("X")); if (config.Count == 0) { continue; } Log($"Processing data for {heroNameActual}"); heroNameActual = GetValidFilename(heroNameActual); foreach (VoiceLineInstance lineInstance in set.VoiceLines.Values) { // if (lineInstance.STU.m_voiceLineRuntime.m_4FF98D41 != null) { // var cond = lineInstance.STU.m_voiceLineRuntime.m_4FF98D41; // // HandleCondition(flags, comboInfo, lineInstance, path, heroNameActual, cond, mapNames); // } if (lineInstance.VoiceConversation == 0) { continue; } STUVoiceConversation conversation = GetInstance <STUVoiceConversation>(lineInstance.VoiceConversation); if (conversation == null) { continue; // wtf, blizz pls } string convoDir = Path.Combine(path, heroNameActual, GetFileName(lineInstance.VoiceConversation)); foreach (STUVoiceConversationLine line in conversation.m_voiceConversationLine) { string linePath = Path.Combine(convoDir, line.m_B4D405A1.ToString()); foreach (VoiceSet voiceSet in allVoiceSets.Values) { if (voiceSet.VoiceLines.ContainsKey(line.m_lineGUID)) { VoiceLine.SaveVoiceLine(flags, voiceSet.VoiceLines[line.m_lineGUID], linePath, comboSaveContext); } } } } } comboSaveContext.Wait(); }
public static bool SaveVoiceSet(ExtractFlags flags, string basePath, string heroName, ulong?voiceSetGuid, ref Combo.ComboInfo info, Combo.ComboInfo baseCombo = null, Dictionary <ulong, ulong> replacements = null, bool ignoreGroups = false) { if (voiceSetGuid == null) { return(false); } info = new Combo.ComboInfo(); Combo.Find(info, voiceSetGuid.Value, replacements); // if we're processing a skin, baseCombo is the combo from the hero, this remove duplicate check removes any sounds that belong to the base hero // this ensures you only get sounds unique to the skin when processing a skin if (baseCombo != null) { if (!Combo.RemoveDuplicateVoiceSetEntries(baseCombo, ref info, voiceSetGuid.Value, Combo.GetReplacement(voiceSetGuid.Value, replacements))) { return(false); } } foreach (var voiceSet in info.m_voiceSets) { if (voiceSet.Value.VoiceLineInstances == null) { continue; } foreach (var voicelineInstanceInfo in voiceSet.Value.VoiceLineInstances) { foreach (var voiceLineInstance in voicelineInstanceInfo.Value) { var stimulus = GetInstance <STUVoiceStimulus>(voiceLineInstance.VoiceStimulus); if (stimulus == null) { continue; } var groupName = GetVoiceGroup(voiceLineInstance.VoiceStimulus, stimulus.m_category, stimulus.m_87DCD58E); if (groupName == null) { groupName = $"Unknown\\{teResourceGUID.Index(voiceLineInstance.VoiceStimulus):X}.{teResourceGUID.Type(voiceLineInstance.VoiceStimulus):X3}"; } var soundFilesCombo = new Combo.ComboInfo(); var soundFilesContext = new SaveLogic.Combo.SaveContext(soundFilesCombo); foreach (var soundFile in voiceLineInstance.SoundFiles) { Combo.Find(soundFilesCombo, soundFile); } var path = flags.VoiceGroupByHero && flags.VoiceGroupByType ? Path.Combine(basePath, heroName, groupName) : Path.Combine(basePath, flags.VoiceGroupByHero ? Path.Combine(groupName, heroName) : groupName); if (ignoreGroups) { path = Path.Combine(basePath, heroName); } foreach (var soundInfo in soundFilesCombo.m_voiceSoundFiles.Values) { var filename = soundInfo.GetName(); if (!flags.VoiceGroupByHero && !ignoreGroups) { filename = $"{heroName}-{soundInfo.GetName()}"; } if (SoundIdCache.Contains(soundInfo.m_GUID)) { TACTLib.Logger.Debug("Tool", "Duplicate sound detected, ignoring."); continue; } SoundIdCache.Add(soundInfo.m_GUID); SaveLogic.Combo.SaveSoundFile(flags, path, soundFilesContext, soundInfo.m_GUID, true, filename); } soundFilesContext.Wait(); } } } return(true); }
private static bool SaveSet(ExtractFlags flags, string basePath, ulong entityMain, string heroNameActual, ref STUVoiceSetComponent voiceSetComponent, ref Combo.ComboInfo info, STUVoiceSetComponent baseComponent = null, Combo.ComboInfo baseCombo = null, Dictionary <ulong, ulong> replacements = null) { voiceSetComponent = GetInstance <STUVoiceSetComponent>(Combo.GetReplacement(entityMain, replacements)); if (voiceSetComponent?.m_voiceDefinition == null) { return(false); } info = new Combo.ComboInfo(); Combo.Find(info, Combo.GetReplacement(voiceSetComponent.m_voiceDefinition, replacements), replacements); if (baseComponent != null && baseCombo != null) { if (!Combo.RemoveDuplicateVoiceSetEntries(baseCombo, ref info, baseComponent.m_voiceDefinition, Combo.GetReplacement(voiceSetComponent.m_voiceDefinition, replacements))) { return(false); } } foreach (var voiceSet in info.m_voiceSets) { if (voiceSet.Value.VoiceLineInstances == null) { continue; } foreach (var voicelineInstanceInfo in voiceSet.Value.VoiceLineInstances) { foreach (var voiceLineInstance in voicelineInstanceInfo.Value) { var stimulus = GetInstance <STUVoiceStimulus>(voiceLineInstance.VoiceStimulus); if (stimulus == null) { continue; } var groupName = GetVoiceGroup(voiceLineInstance.VoiceStimulus, stimulus.m_category, stimulus.m_87DCD58E); if (groupName == null) { groupName = $"Unknown\\{teResourceGUID.Index(voiceLineInstance.VoiceStimulus):X}.{teResourceGUID.Type(voiceLineInstance.VoiceStimulus):X3}"; } var soundFilesCombo = new Combo.ComboInfo(); var soundFilesContext = new SaveLogic.Combo.SaveContext(soundFilesCombo); foreach (var soundFile in voiceLineInstance.SoundFiles) { Combo.Find(soundFilesCombo, soundFile); } var path = flags.VoiceGroupByHero && flags.VoiceGroupByType ? Path.Combine(basePath, Container, heroNameActual, groupName) : Path.Combine(basePath, Container, flags.VoiceGroupByHero ? Path.Combine(groupName, heroNameActual) : groupName); foreach (var soundInfo in soundFilesCombo.m_voiceSoundFiles.Values) { var filename = soundInfo.GetName(); if (!flags.VoiceGroupByHero) { filename = $"{heroNameActual}-{soundInfo.GetName()}"; } if (SoundIdCache.Contains(soundInfo.m_GUID)) { TACTLib.Logger.Debug("Tool", "Duplicate sound detected, ignoring."); continue; } SoundIdCache.Add(soundInfo.m_GUID); SaveLogic.Combo.SaveSoundFile(flags, path, soundFilesContext, soundInfo.m_GUID, true, filename); } soundFilesContext.Wait(); } } } return(true); }
public void SaveUnlocksForHeroes(ICLIFlags flags, IEnumerable <KeyValuePair <ulong, STUHero> > heroes, string basePath, bool npc = false) { if (flags.Positionals.Length < 4) { QueryHelp(QueryTypes); return; } Dictionary <string, Dictionary <string, ParsedArg> > parsedTypes = ParseQuery(flags, QueryTypes, QueryNameOverrides); if (parsedTypes == null) { return; } foreach (KeyValuePair <ulong, STUHero> heroPair in heroes) { var hero = heroPair.Value; string heroNameActual = Hero.GetCleanName(hero); if (heroNameActual == null) { continue; } Dictionary <string, ParsedArg> config = GetQuery(parsedTypes, heroNameActual.ToLowerInvariant(), "*", teResourceGUID.Index(heroPair.Key).ToString("X")); string heroFileName = GetValidFilename(heroNameActual); if (config.Count == 0) { continue; } string heroPath = Path.Combine(basePath, RootDir, heroFileName); VoiceSet voiceSet = new VoiceSet(hero); ProgressionUnlocks progressionUnlocks = new ProgressionUnlocks(hero); if (progressionUnlocks.LevelUnlocks == null && !npc) { continue; } if (progressionUnlocks.LootBoxesUnlocks != null && npc) { continue; } Log($"Processing unlocks for {heroNameActual}"); { Combo.ComboInfo guiInfo = new Combo.ComboInfo(); foreach (STU_1A496D3C tex in hero.m_8203BFE1) { Combo.Find(guiInfo, tex.m_texture); guiInfo.SetTextureName(tex.m_texture, teResourceGUID.AsString(tex.m_id)); } var guiContext = new SaveLogic.Combo.SaveContext(guiInfo); SaveLogic.Combo.SaveLooseTextures(flags, Path.Combine(heroPath, "GUI"), guiContext); guiContext.Wait(); } if (progressionUnlocks.OtherUnlocks != null) // achievements and stuff { Dictionary <string, TagExpectedValue> tags = new Dictionary <string, TagExpectedValue> { { "event", new TagExpectedValue("base") } }; SaveUnlocks(flags, progressionUnlocks.OtherUnlocks, heroPath, "Achievement", config, tags, voiceSet, hero); } if (npc) { foreach (var skin in hero.m_skinThemes) { if (!config.ContainsKey("skin") || !config["skin"].ShouldDo(GetFileName(skin.m_5E9665E3))) { continue; } SkinTheme.Save(flags, Path.Combine(heroPath, UnlockType.Skin.ToString(), string.Empty, GetFileName(skin.m_5E9665E3)), skin, hero); } continue; } if (progressionUnlocks.LevelUnlocks != null) // default unlocks { Dictionary <string, TagExpectedValue> tags = new Dictionary <string, TagExpectedValue> { { "event", new TagExpectedValue("base") } }; foreach (LevelUnlocks levelUnlocks in progressionUnlocks.LevelUnlocks) { SaveUnlocks(flags, levelUnlocks.Unlocks, heroPath, "Default", config, tags, voiceSet, hero); } } if (progressionUnlocks.LootBoxesUnlocks != null) { foreach (LootBoxUnlocks lootBoxUnlocks in progressionUnlocks.LootBoxesUnlocks) { if (lootBoxUnlocks.Unlocks == null) { continue; } string lootboxName = LootBox.GetName(lootBoxUnlocks.LootBoxType); var tags = new Dictionary <string, TagExpectedValue> { { "event", new TagExpectedValue(LootBox.GetBasicName(lootBoxUnlocks.LootBoxType)) } }; SaveUnlocks(flags, lootBoxUnlocks.Unlocks, heroPath, lootboxName, config, tags, voiceSet, hero); } } SaveScratchDatabase(); } }