public void Parse(ICLIFlags toolFlags) { string basePath; if (toolFlags is ExtractFlags flags) { basePath = flags.OutputPath; } else { throw new Exception("no output path"); } // Do normal heroes first then NPCs, this is because NPCs have a lot of duplicate sounds and normal heroes (should) have none // so any duplicate sounds would only come up while processing NPCs which can be ignored as they (probably) belong to heroes var heroes = Program.TrackedFiles[0x75].Select(x => new Hero(x)).OrderBy(x => !x.IsHero).ThenBy(x => x.GUID.GUID).ToArray(); foreach (var hero in heroes) { var heroStu = GetInstance <STUHero>(hero.GUID); string heroNameActual = GetValidFilename((GetString(heroStu.m_0EDCE350) ?? $"Unknown{teResourceGUID.Index(hero.GUID)}").TrimEnd(' ')); Logger.Log($"Processing {heroNameActual}"); var voiceSetComponent = GetInstance <STUVoiceSetComponent>(heroStu.m_gameplayEntity); STUVoiceSetComponent baseComponent = default; Combo.ComboInfo baseInfo = default; if (SaveSet(flags, basePath, heroStu.m_gameplayEntity, heroNameActual, ref baseComponent, ref baseInfo)) { var skins = new ProgressionUnlocks(heroStu).GetUnlocksOfType(UnlockType.Skin); foreach (var unlock in skins) { TACTLib.Logger.Debug("Tool", $"Processing skin {unlock.Name}"); if (!(unlock.STU is STUUnlock_SkinTheme unlockSkinTheme)) { return; } if (unlockSkinTheme.m_0B1BA7C1 != 0) { continue; } var skinTheme = GetInstance <STUSkinTheme>(unlockSkinTheme.m_skinTheme); if (skinTheme == null) { continue; } STUVoiceSetComponent component = default; Combo.ComboInfo info = default; SaveSet(flags, basePath, heroStu.m_gameplayEntity, heroNameActual, ref component, ref info, baseComponent, baseInfo, SkinTheme.GetReplacements(skinTheme)); } } } }
public static void SaveItem(string basePath, string heroName, string containerName, string folderName, ICLIFlags flags, ItemInfo item, STUHero hero) { if (item == null) { return; } if (!(item.Unlock is STUUnlock_VoiceLine vl)) { return; } const string type = "VoiceLines"; string name = GetValidFilename(item.Name).Replace(".", ""); STUVoiceSetComponent soundSetComponentContainer = GetInstance <STUVoiceSetComponent>(hero.EntityMain); if (soundSetComponentContainer?.VoiceSet == null) { Debugger.Log(0, "DataTool.SaveLogic.Unlock.VoiceLine", "[DataTool.SaveLogic.Unlock.VoiceLine]: VoiceSet not found"); return; } FindLogic.Combo.ComboInfo info = new FindLogic.Combo.ComboInfo(); FindLogic.Combo.Find(info, soundSetComponentContainer.VoiceSet); FindLogic.Combo.VoiceSetInfo voiceSetInfo = info.VoiceSets[soundSetComponentContainer.VoiceSet]; List <FindLogic.Combo.VoiceLineInstanceInfo> voiceLineInstances = new List <FindLogic.Combo.VoiceLineInstanceInfo>(); using (Stream vlStream = OpenFile(vl.EffectResource)) { using (Chunked vlChunk = new Chunked(vlStream)) { foreach (SVCE svce in vlChunk.GetAllOfTypeFlat <SVCE>()) { if (svce == null) { continue; } if (voiceSetInfo.VoiceLineInstances.ContainsKey(svce.Data.VoiceStimulus)) { voiceLineInstances.AddRange(voiceSetInfo.VoiceLineInstances[svce.Data.VoiceStimulus]); } } } } string output = Path.Combine(basePath, containerName, heroName ?? "", type, folderName, name); Combo.SaveVoiceStimuli(flags, output, info, voiceLineInstances, false); }
public static void SaveSkin(ICLIFlags flags, ulong skinResource, string basePath, STUHero hero, string heroFileName, string name, STUVoiceSetComponent baseComponent, Combo.ComboInfo baseInfo) { STUSkinTheme skin = GetInstance <STUSkinTheme>(skinResource); if (skin == null) { return; } STUVoiceSetComponent component = default; Combo.ComboInfo info = default; SaveSet(flags, basePath, hero.m_gameplayEntity, heroFileName, GetValidFilename(name), ref component, ref info, baseComponent, baseInfo, SkinTheme.GetReplacements(skin)); }
public static void SaveSkin(ICLIFlags flags, ulong skinResource, string basePath, STUHero hero, string heroFileName, string name, STUVoiceSetComponent baseComponent, Combo.ComboInfo baseInfo) { STUSkinOverride skin = GetInstance <STUSkinOverride>(skinResource); if (skin == null) { return; } STUVoiceSetComponent component = default(STUVoiceSetComponent); Combo.ComboInfo info = default(Combo.ComboInfo); if (SaveSet(flags, basePath, hero.EntityMain, heroFileName, GetValidFilename(name), ref component, ref info, baseComponent, baseInfo, skin.ProperReplacements)) { return; } }
public VoiceSet(STUHero hero) { STUVoiceSetComponent voiceSetComponent = GetInstance <STUVoiceSetComponent>(hero.m_gameplayEntity); if (voiceSetComponent?.m_voiceDefinition == null) { Debugger.Log(0, "DataTool.DataModels.VoiceSet", "Hero VoiceSet not found"); return; } STUVoiceSet set = GetInstance <STUVoiceSet>(voiceSetComponent.m_voiceDefinition); if (set == null) { return; } Init(set); }
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(); 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(), "*"); 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, comboInfo); } } } } } }
public void SaveHeroSounds(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; } Dictionary <string, Dictionary <string, ParsedArg> > parsedTypes = ParseQuery(flags, QueryTypes, QueryNameOverrides); if (parsedTypes == null) { return; } foreach (ulong heroFile in TrackedFiles[0x75]) { STUHero hero = GetInstance <STUHero>(heroFile); if (hero == null) { continue; } string heroNameActual = (GetString(hero.Name) ?? $"Unknown{GUID.Index(heroFile)}").TrimEnd(' '); Log($"Processing data for {heroNameActual}"); Dictionary <string, ParsedArg> config = new Dictionary <string, ParsedArg>(); foreach (string key in new[] { heroNameActual.ToLowerInvariant(), "*" }) { if (!parsedTypes.ContainsKey(key)) { continue; } foreach (KeyValuePair <string, ParsedArg> parsedArg in parsedTypes[key]) { if (config.ContainsKey(parsedArg.Key)) { config[parsedArg.Key] = config[parsedArg.Key].Combine(parsedArg.Value); } else { config[parsedArg.Key] = parsedArg.Value.Combine(null); // clone for safety } } } if (config.Count == 0) { continue; } STUVoiceSetComponent baseComponent = default(STUVoiceSetComponent); Combo.ComboInfo baseInfo = default(Combo.ComboInfo); string heroFileName = GetValidFilename(heroNameActual); if (SaveSet(flags, basePath, hero.EntityMain, heroFileName, "Default", ref baseComponent, ref baseInfo)) { var unlocks = GetInstance <STUHeroUnlocks>(hero.LootboxUnlocks); if (unlocks == null) { continue; } bool npc = unlocks.LootboxUnlocks == null; var achievementUnlocks = GatherUnlocks(unlocks?.SystemUnlocks?.Unlocks?.Select(it => (ulong)it)).Where(item => item?.Unlock is STUUnlock_Skin).ToList(); foreach (ItemInfo itemInfo in achievementUnlocks) { if (itemInfo == null) { continue; } if ((itemInfo.Unlock as STUUnlock_Skin)?.LeagueTeam != 0) { continue; } SaveSkin(flags, (itemInfo.Unlock as STUUnlock_Skin)?.SkinResource, basePath, hero, heroFileName, itemInfo.Name, baseComponent, baseInfo); } if (npc) { foreach (STUHeroSkin skin in hero.Skins) { SaveSkin(flags, skin.SkinOverride, basePath, hero, heroFileName, GetFileName(skin.SkinOverride), baseComponent, baseInfo); } continue; } foreach (var defaultUnlocks in unlocks.Unlocks) { var dUnlocks = GatherUnlocks(defaultUnlocks.Unlocks.Select(it => (ulong)it)).Where(item => item?.Unlock is STUUnlock_Skin).ToList(); foreach (ItemInfo itemInfo in dUnlocks) { if (itemInfo == null) { continue; } if ((itemInfo.Unlock as STUUnlock_Skin)?.LeagueTeam != 0) { continue; } SaveSkin(flags, (itemInfo.Unlock as STUUnlock_Skin)?.SkinResource, basePath, hero, heroFileName, itemInfo.Name, baseComponent, baseInfo); } } foreach (var eventUnlocks in unlocks.LootboxUnlocks) { if (eventUnlocks?.Unlocks?.Unlocks == null) { continue; } var eUnlocks = eventUnlocks.Unlocks.Unlocks.Select(it => GatherUnlock(it)).Where(item => item?.Unlock is STUUnlock_Skin).ToList(); foreach (ItemInfo itemInfo in eUnlocks) { if (itemInfo == null) { continue; } if ((itemInfo.Unlock as STUUnlock_Skin)?.LeagueTeam != 0) { continue; } SaveSkin(flags, (itemInfo.Unlock as STUUnlock_Skin)?.SkinResource, basePath, hero, heroFileName, itemInfo.Name, baseComponent, baseInfo); } } } } }
public static bool SaveSet(ICLIFlags flags, string basePath, ulong entityMain, string heroFileName, string skin, ref STUVoiceSetComponent soundSetComponentContainer, ref Combo.ComboInfo info, STUVoiceSetComponent baseComponent = null, Combo.ComboInfo baseCombo = null, Dictionary <ulong, ulong> replacements = null) { soundSetComponentContainer = GetInstance <STUVoiceSetComponent>(Combo.GetReplacement(entityMain, replacements)); if (soundSetComponentContainer?.VoiceSet == 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(soundSetComponentContainer.VoiceSet, replacements), replacements); if (baseComponent != null && baseCombo != null) { if (!Combo.RemoveDuplicateVoiceSetEntries(baseCombo, ref info, baseComponent.VoiceSet, Combo.GetReplacement(soundSetComponentContainer.VoiceSet, replacements))) { return(false); } } Log("Saving {0}", skin); SaveLogic.Combo.SaveVoiceSet(flags, Path.Combine(basePath, Container, heroFileName, skin), info, Combo.GetReplacement(soundSetComponentContainer.VoiceSet, replacements)); return(true); }
public void SaveHeroSounds(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; } Dictionary <string, Dictionary <string, ParsedArg> > parsedTypes = ParseQuery(flags, QueryTypes, QueryNameOverrides); if (parsedTypes == null) { return; } foreach (ulong heroFile in TrackedFiles[0x75]) { STUHero hero = GetInstance <STUHero>(heroFile); if (hero == null) { continue; } string heroNameActual = (GetString(hero.m_0EDCE350) ?? $"Unknown{teResourceGUID.Index(heroFile)}").TrimEnd(' '); Dictionary <string, ParsedArg> config = GetQuery(parsedTypes, heroNameActual.ToLowerInvariant(), "*"); if (config.Count == 0) { continue; } Log($"Processing data for {heroNameActual}"); STUVoiceSetComponent baseComponent = default; Combo.ComboInfo baseInfo = default; string heroFileName = GetValidFilename(heroNameActual); if (SaveSet(flags, basePath, hero.m_gameplayEntity, heroFileName, "Default", ref baseComponent, ref baseInfo)) { if (hero.m_heroProgression == 0) { continue; } var progression = new ProgressionUnlocks(hero); bool npc = progression.LootBoxesUnlocks == null; foreach (Unlock itemInfo in progression.OtherUnlocks) { ProcessUnlock(itemInfo, flags, basePath, heroFileName, hero, baseComponent, baseInfo); } if (npc) { foreach (var skin in hero.m_skinThemes) { SaveSkin(flags, skin.m_5E9665E3, basePath, hero, heroFileName, GetFileName(skin.m_5E9665E3), baseComponent, baseInfo); } continue; } foreach (var defaultUnlocks in progression.LevelUnlocks) { foreach (Unlock unlock in defaultUnlocks.Unlocks) { ProcessUnlock(unlock, flags, basePath, heroFileName, hero, baseComponent, baseInfo); } } foreach (var eventUnlocks in progression.LootBoxesUnlocks) { if (eventUnlocks?.Unlocks == null) { continue; } foreach (Unlock unlock in eventUnlocks.Unlocks) { ProcessUnlock(unlock, flags, basePath, heroFileName, hero, baseComponent, baseInfo); } } } } }
public static void ProcessUnlock(Unlock unlock, ICLIFlags flags, string basePath, string heroFileName, STUHero hero, STUVoiceSetComponent baseComponent, Combo.ComboInfo baseInfo) { if (!(unlock.STU is STUUnlock_SkinTheme unlockSkinTheme)) { return; } if (unlockSkinTheme.m_0B1BA7C1 != 0) { return; } SaveSkin(flags, unlockSkinTheme.m_skinTheme, basePath, hero, heroFileName, unlock.Name, baseComponent, baseInfo); }
public static void Save(ICLIFlags flags, STUMapHeader mapHeader, ulong key, string basePath) { string name = GetString(mapHeader.m_displayName) ?? "Title Screen"; //string name = map.m_506FA8D8; var variantName = GetString(mapHeader.m_1C706502); if (variantName != null) { name = variantName; } LoudLog($"Extracting map {name}\\{teResourceGUID.Index(key):X}"); name = GetValidFilename(name); // TODO: MAP11 HAS CHANGED // TODO: MAP10 TOO? string mapPath = Path.Combine(basePath, "Maps", name, teResourceGUID.Index(key).ToString("X")) + Path.DirectorySeparatorChar; CreateDirectoryFromFile(mapPath); FindLogic.Combo.ComboInfo info = new FindLogic.Combo.ComboInfo(); LoudLog("\tFinding"); FindLogic.Combo.Find(info, mapHeader.m_map); //for (ushort i = 0; i < 255; i++) { // using (Stream mapChunkStream = OpenFile(mapHeader.GetChunkKey((byte)i))) { // if (mapChunkStream == null) continue; // WriteFile(mapChunkStream, Path.Combine(mapPath, $"{(Enums.teMAP_PLACEABLE_TYPE)i}.0BC")); // } //} //return; teMapPlaceableData placeableModelGroups = GetPlaceableData(mapHeader, Enums.teMAP_PLACEABLE_TYPE.MODEL_GROUP); teMapPlaceableData placeableSingleModels = GetPlaceableData(mapHeader, Enums.teMAP_PLACEABLE_TYPE.SINGLE_MODEL); teMapPlaceableData placeableModel = GetPlaceableData(mapHeader, Enums.teMAP_PLACEABLE_TYPE.MODEL); teMapPlaceableData placeableLights = GetPlaceableData(mapHeader, Enums.teMAP_PLACEABLE_TYPE.LIGHT); teMapPlaceableData placeableEntities = GetPlaceableData(mapHeader, Enums.teMAP_PLACEABLE_TYPE.ENTITY); teMapPlaceableData placeableSounds = GetPlaceableData(mapHeader, Enums.teMAP_PLACEABLE_TYPE.SOUND); teMapPlaceableData placeableEffects = GetPlaceableData(mapHeader, Enums.teMAP_PLACEABLE_TYPE.EFFECT); OverwatchMap exportMap = new OverwatchMap(name, info, placeableSingleModels, placeableModelGroups, placeableModel, placeableEntities, placeableLights, placeableSounds, placeableEffects); using (Stream outputStream = File.OpenWrite(Path.Combine(mapPath, $"{name}.{exportMap.Extension}"))) { exportMap.Write(outputStream); } { FindLogic.Combo.Find(info, mapHeader.m_86C1CFAB); FindLogic.Combo.Find(info, mapHeader.m_9386E669); FindLogic.Combo.Find(info, mapHeader.m_C6599DEB); if (mapHeader.m_D608E9F3 != null) { foreach (teResourceGUID gamemodeGUID in mapHeader.m_D608E9F3) { STUGameMode gameMode = GetInstance <STUGameMode>(gamemodeGUID); if (gameMode == null) { continue; } FindLogic.Combo.Find(info, gameMode.m_6EB38130); // 004 FindLogic.Combo.Find(info, gameMode.m_CF63B633); // 01B FindLogic.Combo.Find(info, gameMode.m_7F5B54B2); // game mode voice set foreach (STUGameModeTeam team in gameMode.m_teams) { FindLogic.Combo.Find(info, team.m_bodyScript); // 01B FindLogic.Combo.Find(info, team.m_controllerScript); // 01B } } } } FindLogic.Combo.Find(info, mapHeader.m_announcerWelcome); info.SetEffectName(mapHeader.m_announcerWelcome, "AnnouncerWelcome"); FindLogic.Combo.Find(info, mapHeader.m_musicTease); info.SetEffectName(mapHeader.m_musicTease, "MusicTease"); ulong announcerVoiceSet = 0; using (Stream stream = OpenFile(mapHeader.m_map)) { if (stream != null) { using (BinaryReader reader = new BinaryReader(stream)) { teMap map = reader.Read <teMap>(); STUVoiceSetComponent voiceSetComponent = GetInstance <STUVoiceSetComponent>(map.EntityDefinition); announcerVoiceSet = voiceSetComponent?.m_voiceDefinition; FindLogic.Combo.Find(info, announcerVoiceSet); info.SetEffectVoiceSet(mapHeader.m_announcerWelcome, announcerVoiceSet); } } } LoudLog("\tSaving"); Combo.Save(flags, mapPath, info); Combo.SaveLooseTextures(flags, Path.Combine(mapPath, "Textures"), info); if (mapHeader.m_7F5B54B2 != 0) // map voice set. not announcer { FindLogic.Combo.Find(info, mapHeader.m_7F5B54B2); } if (announcerVoiceSet != 0) // whole thing in env mode, not here { info.VoiceSets.Remove(announcerVoiceSet); } Combo.SaveAllVoiceSets(flags, Path.Combine(mapPath, "VoiceSets"), info); Combo.SaveAllSoundFiles(flags, Path.Combine(mapPath, "Sound"), info); LoudLog("\tDone"); }
public static void Save(ICLIFlags flags, STUMap map, ulong key, string basePath) { string name = GetValidFilename(GetString(map.DisplayName)) ?? "Title Screen"; if (GetString(map.VariantName) != null) { name = GetValidFilename(GetString(map.VariantName)); } LoudLog($"Extracting map {name}\\{GUID.Index(key):X}"); // if (map.Gamemodes != null) { // foreach (Common.STUGUID gamemodeGUID in map.Gamemodes) { // STUGamemode gamemode = GetInstance<STUGamemode>(gamemodeGUID); // } // } // TODO: MAP11 HAS CHANGED // TODO: MAP10 TOO? string mapPath = Path.Combine(basePath, "Maps", name, GUID.Index(key).ToString("X")) + Path.DirectorySeparatorChar; CreateDirectoryFromFile(mapPath); // if (map.UnknownArray != null) { // Dictionary<ulong, List<TextureInfo>> textures = new Dictionary<ulong, List<TextureInfo>>(); // foreach (STUMap.STU_7D6D8405 stu_7D6D8405 in map?.UnknownArray) { // ISTU overrideStu = OpenSTUSafe(stu_7D6D8405.Override); // STUSkinOverride @override = GetInstance<STUSkinOverride>(stu_7D6D8405.Override); // textures = FindLogic.Texture.FindTextures(textures, @override.SkinImage); // } // SaveLogic.Texture.Save(flags, Path.Combine(mapPath, "override"), textures); // } OWMDLWriter modelWriter = new OWMDLWriter(); OWMap14Writer owmap = new OWMap14Writer(); FindLogic.Combo.ComboInfo info = new FindLogic.Combo.ComboInfo(); LoudLog("\tFinding"); FindLogic.Combo.Find(info, map.MapDataResource1); MapEnvironment?env = null; using (Stream data = OpenFile(map.MapDataResource1)) { if (data != null) { using (BinaryReader dataReader = new BinaryReader(data)) { env = dataReader.Read <MapEnvironment>(); } } } using (Stream mapStream = OpenFile(map.GetDataKey(1))) { STULib.Types.Map.Map mapData = new STULib.Types.Map.Map(mapStream, BuildVersion); using (Stream map2Stream = OpenFile(map.GetDataKey(2))) { if (map2Stream == null) { return; } STULib.Types.Map.Map map2Data = new STULib.Types.Map.Map(map2Stream, BuildVersion); using (Stream map8Stream = OpenFile(map.GetDataKey(8))) { STULib.Types.Map.Map map8Data = new STULib.Types.Map.Map(map8Stream, BuildVersion); using (Stream mapEntitiesStream = OpenFile(map.GetDataKey(0xB))) { STULib.Types.Map.Map mapEntities = new STULib.Types.Map.Map(mapEntitiesStream, BuildVersion, true); mapEntitiesStream.Position = (long)(Math.Ceiling(mapEntitiesStream.Position / 16.0f) * 16); // Future proofing (?) for (int i = 0; i < mapEntities.Records.Length; ++i) { if (mapEntities.Records[i] != null && mapEntities.Records[i].GetType() != typeof(MapEntity)) { continue; } MapEntity mapEntity = (MapEntity)mapEntities.Records[i]; if (mapEntity == null) { continue; } FindLogic.Combo.Find(info, mapEntity.Header.Entity); STUModelComponent component = GetInstance <STUModelComponent>(mapEntity.Header.Entity); if (component == null) { continue; } mapEntity.ModelLook = component.Look; mapEntity.Model = component.Model; mapEntities.Records[i] = mapEntity; } using (Stream mapLStream = OpenFile(map.GetDataKey(9))) { STULib.Types.Map.Map mapLData = new STULib.Types.Map.Map(mapLStream, BuildVersion); using (Stream outputStream = File.Open(Path.Combine(mapPath, $"{name}.owmap"), FileMode.Create, FileAccess.Write)) { owmap.Write(outputStream, mapData, map2Data, map8Data, mapEntities, mapLData, name, modelWriter, info); } } } } } } FindLogic.Combo.Find(info, map.EffectAnnouncer); info.SetEffectName(map.EffectAnnouncer, "LoadAnnouncer"); FindLogic.Combo.Find(info, map.EffectMusic); info.SetEffectName(map.EffectMusic, "LoadMusic"); if (map.VoiceSet != null) { FindLogic.Combo.Find(info, map.VoiceSet); } if (env != null) { FindLogic.Combo.Find(info, env.Value.EntityDefinition); STUVoiceSetComponent voiceSetComponent = GetInstance <STUVoiceSetComponent>(env.Value.EntityDefinition); if (voiceSetComponent != null) { FindLogic.Combo.Find(info, voiceSetComponent.VoiceSet); info.SetEffectVoiceSet(map.EffectAnnouncer, voiceSetComponent.VoiceSet); info.SetEffectVoiceSet(map.EffectMusic, voiceSetComponent.VoiceSet); } } LoudLog("\tSaving"); Combo.Save(flags, mapPath, info); string soundPath = Path.Combine(mapPath, "Sound"); string voiceSetsPath = Path.Combine(soundPath, "VoiceSets"); string otherSoundsPath = Path.Combine(soundPath, "SFX"); Combo.SaveVoiceSets(flags, voiceSetsPath, info); foreach (KeyValuePair <ulong, FindLogic.Combo.SoundFileInfo> sound in info.SoundFiles) { Combo.SaveSoundFile(flags, otherSoundsPath, info, sound.Key, false); } LoudLog("\tDone"); }
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 SaveHeroSounds(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; } Dictionary <string, Dictionary <string, ParsedArg> > parsedTypes = ParseQuery(flags, QueryTypes, QueryNameOverrides); if (parsedTypes == null) { return; } foreach (ulong heroFile in TrackedFiles[0x75]) { STUHero hero = GetInstance <STUHero>(heroFile); if (hero == null) { continue; } string heroNameActual = (GetString(hero.Name) ?? $"Unknown{GUID.Index(heroFile)}").TrimEnd(' '); Log($"Processing data for {heroNameActual}"); Dictionary <string, ParsedArg> config = new Dictionary <string, ParsedArg>(); foreach (string key in new [] { heroNameActual.ToLowerInvariant(), "*" }) { if (!parsedTypes.ContainsKey(key)) { continue; } foreach (KeyValuePair <string, ParsedArg> parsedArg in parsedTypes[key]) { if (config.ContainsKey(parsedArg.Key)) { config[parsedArg.Key] = config[parsedArg.Key].Combine(parsedArg.Value); } else { config[parsedArg.Key] = parsedArg.Value.Combine(null); // clone for safety } } } if (config.Count == 0) { continue; } STUVoiceSetComponent soundSetComponentContainer = GetInstance <STUVoiceSetComponent>(hero.EntityMain); if (soundSetComponentContainer?.VoiceSet == null) { Debugger.Log(0, "DataTool.SaveLogic.Unlock.VoiceLine", "[DataTool.SaveLogic.Unlock.VoiceLine]: VoiceSet not found"); return; } string heroFileName = GetValidFilename(heroNameActual); Combo.ComboInfo info = new Combo.ComboInfo(); Combo.Find(info, soundSetComponentContainer.VoiceSet); SaveLogic.Combo.SaveVoiceSet(flags, Path.Combine(basePath, Container, heroFileName), info, soundSetComponentContainer.VoiceSet); } }
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); }