public void ListAnimBlendTrees() { List <ulong> blendTreeSets = new List <ulong>(); // this is posthash foreach (ulong heroKey in TrackedFiles[0x75]) { STUHero hero = GetInstance <STUHero>(heroKey); if (GetString(hero?.Name) != "Tracer") { continue; } foreach (Common.STUGUID heroEntity in new [] { hero.EntityHeroSelect, hero.EntityHighlightIntro, hero.EntityMain, hero.EntityPlayable, hero.EntityThirdPerson }) { STUModelComponent modelComponent = GetInstance <STUModelComponent>(heroEntity); if (modelComponent?.AnimBlendTreeSet == null) { continue; } blendTreeSets.Add(modelComponent.AnimBlendTreeSet); } } // add breakpoint and copy from posthash thing (yes I'm sorry) // blendTreeSets = new List<ulong> { // 18014398509483732, 18014398509483760, 18014398509483769, 18014398509483562, 18014398509483771 // orisa // }; blendTreeSets = new List <ulong> { 18014398509482072, 18014398509483458, 18014398509483479, 18014398509481986, 18014398509483575 // tracer }; // this is prehash // foreach (ulong key in TrackedFiles[0x21]) { // if (!blendTreeSets.Contains(key)) continue; // STUAnimBlendTreeSet animBlendTreeSet = GetInstance<STUAnimBlendTreeSet>(key); // // if (animBlendTreeSet?.BlendTreeItems == null) continue; // foreach (STUAnimBlendTreeSet_BlendTreeItem blendTreeItem in animBlendTreeSet.BlendTreeItems) { // if (blendTreeItem.m_45C6E995 == null) continue; // STUAnimNode_Strafe8Way strafe8Way = GetInstance<STUAnimNode_Strafe8Way>(blendTreeItem.m_45C6E995); // if (strafe8Way != null) Debugger.Break(); // } // } }
public static void Save(ICLIFlags flags, string skinName, string basePath, STUHero hero, string rarity, STUSkinOverride skinOverride, List <ItemInfo> weaponSkins, List <STULoadout> abilities, bool quiet = true) { string heroName = GetString(hero.Name); string heroNamePath = GetValidFilename(heroName) ?? "Unknown"; heroNamePath = heroNamePath.TrimEnd(' '); string path = Path.Combine(basePath, $"{heroNamePath}\\Skins\\{rarity}\\{GetValidFilename(skinName)}"); Dictionary <uint, ItemInfo> realWeaponSkins = new Dictionary <uint, ItemInfo>(); if (weaponSkins != null) { foreach (ItemInfo weaponSkin in weaponSkins) { realWeaponSkins[((STUUnlock_Weapon)weaponSkin.Unlock).Index] = weaponSkin; } } Dictionary <ulong, ulong> replacements = skinOverride.ProperReplacements; LoudLog("\tFinding"); FindLogic.Combo.ComboInfo info = new FindLogic.Combo.ComboInfo(); FindLogic.Combo.Find(info, hero.EntityMain, replacements); FindLogic.Combo.Find(info, hero.EntityHeroSelect, replacements); FindLogic.Combo.Find(info, hero.EntityHighlightIntro, replacements); FindLogic.Combo.Find(info, hero.EntityPlayable, replacements); FindLogic.Combo.Find(info, hero.EntityThirdPerson, replacements); info.Config.DoExistingEntities = true; uint replacementIndex = 0; foreach (Common.STUGUID weaponOverrideGUID in skinOverride.Weapons) { STUHeroWeapon weaponOverride = GetInstance <STUHeroWeapon>(weaponOverrideGUID); if (weaponOverride == null) { continue; } string weaponSkinName = null; if (realWeaponSkins.ContainsKey(replacementIndex)) { weaponSkinName = GetValidFilename(GetString(realWeaponSkins[replacementIndex].Unlock.CosmeticName)); } Dictionary <ulong, ulong> weaponReplacements = weaponOverride.ProperReplacements?.ToDictionary(x => x.Key, y => y.Value) ?? new Dictionary <ulong, ulong>(); List <STUHeroWeaponEntity> weaponEntities = new List <STUHeroWeaponEntity>(); if (hero.WeaponComponents1 != null) { weaponEntities.AddRange(hero.WeaponComponents1); } if (hero.WeaponComponents2 != null) { weaponEntities.AddRange(hero.WeaponComponents2); } foreach (STUHeroWeaponEntity heroWeapon in weaponEntities) { FindLogic.Combo.Find(info, heroWeapon.Entity, weaponReplacements); STUModelComponent modelComponent = GetInstance <STUModelComponent>(heroWeapon.Entity); if (modelComponent?.Look == null || weaponSkinName == null) { continue; } ulong modelLook = FindLogic.Combo.GetReplacement(modelComponent.Look, weaponReplacements); if (!info.ModelLooks.ContainsKey(modelLook)) { continue; } FindLogic.Combo.ModelLookInfo modelLookInfo = info.ModelLooks[modelLook]; modelLookInfo.Name = weaponSkinName; } replacementIndex++; } info.Config.DoExistingEntities = false; foreach (Common.STUGUID guiImage in new[] { hero.ImageResource1, hero.ImageResource2, hero.ImageResource3, hero.ImageResource3, hero.ImageResource4, skinOverride.SkinImage, hero.SpectatorIcon }) { FindLogic.Combo.Find(info, guiImage, replacements); } Combo.SaveLooseTextures(flags, Path.Combine(path, "GUI"), info); info.SetEntityName(hero.EntityHeroSelect, $"{heroName}-HeroSelect"); info.SetEntityName(hero.EntityPlayable, $"{heroName}-Playable-ThirdPerson"); info.SetEntityName(hero.EntityThirdPerson, $"{heroName}-ThirdPerson"); info.SetEntityName(hero.EntityMain, $"{heroName}-Base"); info.SetEntityName(hero.EntityHighlightIntro, $"{heroName}-HighlightIntro"); string soundDirectory = Path.Combine(path, "Sound"); FindLogic.Combo.ComboInfo diffInfoBefore = new FindLogic.Combo.ComboInfo(); FindLogic.Combo.ComboInfo diffInfoAfter = new FindLogic.Combo.ComboInfo(); if (replacements != null) { foreach (KeyValuePair <ulong, ulong> replacement in replacements) { uint diffReplacementType = GUID.Type(replacement.Value); if (diffReplacementType != 0x2C && diffReplacementType != 0x5F && diffReplacementType != 0x3F && diffReplacementType != 0xB2) { continue; } FindLogic.Combo.Find(diffInfoAfter, replacement.Value); FindLogic.Combo.Find(diffInfoBefore, replacement.Key); } diffInfoAfter.SaveRuntimeData = new FindLogic.Combo.ComboSaveRuntimeData { Threads = false }; foreach (KeyValuePair <ulong, FindLogic.Combo.SoundFileInfo> soundFile in diffInfoAfter.SoundFiles) { if (diffInfoBefore.SoundFiles.ContainsKey(soundFile.Key)) { continue; } Combo.SaveSoundFile(flags, soundDirectory, diffInfoAfter, soundFile.Key, false); } foreach (KeyValuePair <ulong, FindLogic.Combo.SoundFileInfo> soundFile in diffInfoAfter.VoiceSoundFiles) { if (diffInfoBefore.VoiceSoundFiles.ContainsKey(soundFile.Key)) { continue; } Combo.SaveSoundFile(flags, soundDirectory, diffInfoAfter, soundFile.Key, true); } } LoudLog("\tSaving"); Combo.Save(flags, path, info); LoudLog("\tDone"); }
public void Write(Stream output) { using (BinaryWriter writer = new BinaryWriter(output)) { writer.Write((ushort)1); // version major writer.Write((ushort)2); // version minor if (Name.Length == 0) { writer.Write((byte)0); } else { writer.Write(Name); } writer.Write(ModelGroups.Header.PlaceableCount); // nr objects int entitiesWithModelCount = 0; STUModelComponent[][] modelComponentSets = new STUModelComponent[Entities.Header.PlaceableCount][]; for (int i = 0; i < Entities.Header.PlaceableCount; i++) { // todo: wtf is this code teMapPlaceableEntity entity = (teMapPlaceableEntity)Entities.Placeables[i]; var modelComponents = GetInstances <STUModelComponent>(entity.Header.EntityDefinition).Where(component => teResourceGUID.Index(component.m_model) > 1); if (modelComponents.Count() == 0) { foreach (STUComponentInstanceData instanceData in entity.InstanceData) { if (instanceData is STUStatescriptComponentInstanceData statescriptComponentInstanceData) { if (statescriptComponentInstanceData.m_6D10093E != null) { foreach (STUStatescriptGraphWithOverrides graphWithOverrides in statescriptComponentInstanceData.m_6D10093E) { FindLogic.Combo.Find(Info, graphWithOverrides); } } if (statescriptComponentInstanceData.m_2D9815BA != null) { // todo: ?? } } } continue; } modelComponentSets[i] = new STUModelComponent[modelComponents.Count()]; entitiesWithModelCount += modelComponentSets[i].Length; modelComponentSets[i] = modelComponents.ToArray(); } writer.Write((uint)(SingleModels.Header.PlaceableCount + Models.Header.PlaceableCount + entitiesWithModelCount)); // nr details writer.Write(Lights.Header.PlaceableCount); // nr Lights foreach (IMapPlaceable mapPlaceable in ModelGroups.Placeables ?? Array.Empty <IMapPlaceable>()) { teMapPlaceableModelGroup modelGroup = (teMapPlaceableModelGroup)mapPlaceable; FindLogic.Combo.Find(Info, modelGroup.Header.Model); FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[modelGroup.Header.Model]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; writer.Write(modelFn); writer.Write(modelGroup.Header.GroupCount); for (int j = 0; j < modelGroup.Header.GroupCount; ++j) { teMapPlaceableModelGroup.Group group = modelGroup.Groups[j]; FindLogic.Combo.Find(Info, group.ModelLook, null, new FindLogic.Combo.ComboContext { Model = modelGroup.Header.Model }); FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[group.ModelLook]; string materialFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; writer.Write(materialFn); writer.Write(group.EntryCount); for (int k = 0; k < group.EntryCount; ++k) { teMapPlaceableModelGroup.Entry record = modelGroup.Entries[j][k]; writer.Write(record.Translation); writer.Write(record.Scale); writer.Write(record.Rotation); } } } foreach (IMapPlaceable mapPlaceable in SingleModels.Placeables ?? Array.Empty <IMapPlaceable>()) { teMapPlaceableSingleModel singleModel = (teMapPlaceableSingleModel)mapPlaceable; FindLogic.Combo.Find(Info, singleModel.Header.Model); FindLogic.Combo.Find(Info, singleModel.Header.ModelLook, null, new FindLogic.Combo.ComboContext { Model = singleModel.Header.Model }); FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[singleModel.Header.Model]; FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[singleModel.Header.ModelLook]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; string matFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; writer.Write(modelFn); writer.Write(matFn); writer.Write(singleModel.Header.Translation); writer.Write(singleModel.Header.Scale); writer.Write(singleModel.Header.Rotation); } foreach (IMapPlaceable mapPlaceable in Models.Placeables ?? Array.Empty <IMapPlaceable>()) { teMapPlaceableModel placeableModel = (teMapPlaceableModel)mapPlaceable; FindLogic.Combo.Find(Info, placeableModel.Header.Model); FindLogic.Combo.Find(Info, placeableModel.Header.ModelLook, null, new FindLogic.Combo.ComboContext { Model = placeableModel.Header.Model }); FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[placeableModel.Header.Model]; FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[placeableModel.Header.ModelLook]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; string matFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; writer.Write(modelFn); writer.Write(matFn); writer.Write(placeableModel.Header.Translation); writer.Write(placeableModel.Header.Scale); writer.Write(placeableModel.Header.Rotation); } for (int i = 0; i < Entities.Placeables?.Length; i++) { var entity = (teMapPlaceableEntity)Entities.Placeables[i]; STUModelComponent[] modelComponents = modelComponentSets[i]; if (modelComponents == null) { continue; } FindLogic.Combo.Find(Info, entity.Header.EntityDefinition); foreach (var modelComponent in modelComponents) { ulong model = modelComponent.m_model; var modelLookSet = new List <ulong> { modelComponent.m_look }; foreach (STUComponentInstanceData instanceData in entity.InstanceData) { if (!(instanceData is STUModelComponentInstanceData modelComponentInstanceData)) { continue; } if (modelComponentInstanceData.m_look != 0) { modelLookSet.Add(modelComponentInstanceData.m_look); } } FindLogic.Combo.Find(Info, model); foreach (var modelLook in modelLookSet) { FindLogic.Combo.Find(Info, modelLook, null, new FindLogic.Combo.ComboContext { Model = model }); } FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[model]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; if (Info.Entities.ContainsKey(entity.Header.EntityDefinition)) { modelFn = $"Entities\\{Info.Entities[entity.Header.EntityDefinition].GetName()}\\{Info.Entities[entity.Header.EntityDefinition].GetName()}.owentity"; } string matFn = "null"; try { FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[modelLookSet.First(x => x > 0)]; matFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; } catch { } writer.Write(modelFn); writer.Write(matFn); writer.Write(entity.Header.Translation); writer.Write(entity.Header.Scale); writer.Write(entity.Header.Rotation); } } // Extension 1.1 - Lights foreach (IMapPlaceable mapPlaceable in Lights.Placeables ?? Array.Empty <IMapPlaceable>()) { var light = (teMapPlaceableLight)mapPlaceable; writer.Write(light.Header.Translation); writer.Write(light.Header.Rotation); writer.Write((uint)light.Header.Type); writer.Write(light.Header.LightFOV); writer.Write(light.Header.Color); writer.Write(light.Header.Unknown1A); writer.Write(light.Header.Unknown1B); writer.Write(light.Header.Unknown2A); writer.Write(light.Header.Unknown2B); writer.Write(light.Header.Unknown2C); writer.Write(light.Header.Unknown2D); writer.Write(light.Header.Unknown3A); writer.Write(light.Header.Unknown3B); writer.Write(light.Header.UnknownPos1); writer.Write(light.Header.UnknownQuat1); writer.Write(light.Header.UnknownPos2); writer.Write(light.Header.UnknownQuat2); writer.Write(light.Header.UnknownPos3); writer.Write(light.Header.UnknownQuat3); writer.Write(light.Header.Unknown4A); writer.Write(light.Header.Unknown4B); writer.Write(light.Header.Unknown5); writer.Write(light.Header.Unknown6A); writer.Write(light.Header.Unknown6B); writer.Write(light.Header.Unknown7A); writer.Write(light.Header.Unknown7B); } writer.Write(Sounds.Header.PlaceableCount); // nr Sounds // Extension 1.2 - Sounds foreach (IMapPlaceable mapPlaceable in Sounds.Placeables ?? Array.Empty <IMapPlaceable>()) { var sound = (teMapPlaceableSound)mapPlaceable; FindLogic.Combo.Find(Info, sound.Header.Sound); writer.Write(sound.Header.Translation); if (!Info.Sounds.ContainsKey(sound.Header.Sound) || Info.Sounds[sound.Header.Sound].SoundFiles == null) { writer.Write(0); continue; } writer.Write(Info.Sounds[sound.Header.Sound].SoundFiles.Count); foreach (var soundfile in Info.Sounds[sound.Header.Sound].SoundFiles?.Values) { writer.Write($@"Sounds\{Info.SoundFiles[soundfile].GetName()}.ogg"); } } // Extension 1.3 - Effects foreach (IMapPlaceable mapPlaceable in Effects.Placeables ?? Array.Empty <IMapPlaceable>()) { var effect = (teMapPlaceableEffect)mapPlaceable; FindLogic.Combo.Find(Info, effect.Header.Effect); // todo: wtf } } }
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"); }
public void Write(Stream output) { using (BinaryWriter writer = new BinaryWriter(output)) { writer.Write((ushort)1); // version major writer.Write((ushort)1); // version minor if (Name.Length == 0) { writer.Write((byte)0); } else { writer.Write(Name); } writer.Write(ModelGroups.Header.PlaceableCount); // nr objects int entitiesWithModelCount = 0; STUModelComponent[] modelComponents = new STUModelComponent[Entities.Header.PlaceableCount]; for (int i = 0; i < Entities.Header.PlaceableCount; i++) { teMapPlaceableEntity entity = (teMapPlaceableEntity)Entities.Placeables[i]; STUModelComponent component = GetInstance <STUModelComponent>(entity.Header.EntityDefinition); if (component != null && teResourceGUID.Index(component.m_model) > 1 && teResourceGUID.Index(component.m_look) > 1) { entitiesWithModelCount++; modelComponents[i] = component; } } writer.Write((uint)(SingleModels.Header.PlaceableCount + Models.Header.PlaceableCount + entitiesWithModelCount)); // nr details writer.Write(Lights.Header.PlaceableCount); // nr Lights foreach (IMapPlaceable mapPlaceable in ModelGroups.Placeables ?? Array.Empty <IMapPlaceable>()) { teMapPlaceableModelGroup modelGroup = (teMapPlaceableModelGroup)mapPlaceable; FindLogic.Combo.Find(Info, modelGroup.Header.Model); FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[modelGroup.Header.Model]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; writer.Write(modelFn); writer.Write(modelGroup.Header.GroupCount); for (int j = 0; j < modelGroup.Header.GroupCount; ++j) { teMapPlaceableModelGroup.Group group = modelGroup.Groups[j]; FindLogic.Combo.Find(Info, group.ModelLook, null, new FindLogic.Combo.ComboContext { Model = modelGroup.Header.Model }); FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[group.ModelLook]; string materialFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; writer.Write(materialFn); writer.Write(group.EntryCount); for (int k = 0; k < group.EntryCount; ++k) { teMapPlaceableModelGroup.Entry record = modelGroup.Entries[j][k]; writer.Write(record.Translation); writer.Write(record.Scale); writer.Write(record.Rotation); } } } foreach (IMapPlaceable mapPlaceable in SingleModels.Placeables ?? Array.Empty <IMapPlaceable>()) { teMapPlaceableSingleModel singleModel = (teMapPlaceableSingleModel)mapPlaceable; FindLogic.Combo.Find(Info, singleModel.Header.Model); FindLogic.Combo.Find(Info, singleModel.Header.ModelLook, null, new FindLogic.Combo.ComboContext { Model = singleModel.Header.Model }); FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[singleModel.Header.Model]; FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[singleModel.Header.ModelLook]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; string matFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; writer.Write(modelFn); writer.Write(matFn); writer.Write(singleModel.Header.Translation); writer.Write(singleModel.Header.Scale); writer.Write(singleModel.Header.Rotation); } foreach (IMapPlaceable mapPlaceable in Models.Placeables ?? Array.Empty <IMapPlaceable>()) { teMapPlaceableModel placeableModel = (teMapPlaceableModel)mapPlaceable; FindLogic.Combo.Find(Info, placeableModel.Header.Model); FindLogic.Combo.Find(Info, placeableModel.Header.ModelLook, null, new FindLogic.Combo.ComboContext { Model = placeableModel.Header.Model }); FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[placeableModel.Header.Model]; FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[placeableModel.Header.ModelLook]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; string matFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; writer.Write(modelFn); writer.Write(matFn); writer.Write(placeableModel.Header.Translation); writer.Write(placeableModel.Header.Scale); writer.Write(placeableModel.Header.Rotation); } for (int i = 0; i < Entities.Placeables?.Length; i++) { var entity = (teMapPlaceableEntity)Entities.Placeables[i]; STUModelComponent modelComponent = modelComponents[i]; if (modelComponent == null) { continue; } ulong model = modelComponent.m_model; ulong modelLook = modelComponent.m_look; foreach (STUComponentInstanceData instanceData in entity.InstanceData) { if (!(instanceData is STUModelComponentInstanceData modelComponentInstanceData)) { continue; } if (modelComponentInstanceData.m_look != 0) { modelLook = modelComponentInstanceData.m_look; } } FindLogic.Combo.Find(Info, model); FindLogic.Combo.Find(Info, modelLook, null, new FindLogic.Combo.ComboContext { Model = model }); FindLogic.Combo.ModelInfoNew modelInfo = Info.Models[model]; FindLogic.Combo.ModelLookInfo modelLookInfo = Info.ModelLooks[modelLook]; string modelFn = $"Models\\{modelInfo.GetName()}\\{modelInfo.GetNameIndex()}.owmdl"; string matFn = $"Models\\{modelInfo.GetName()}\\ModelLooks\\{modelLookInfo.GetNameIndex()}.owmat"; writer.Write(modelFn); writer.Write(matFn); writer.Write(entity.Header.Translation); writer.Write(entity.Header.Scale); writer.Write(entity.Header.Rotation); } // Extension 1.1 - Lights foreach (IMapPlaceable mapPlaceable in Lights.Placeables ?? Array.Empty <IMapPlaceable>()) { var light = (teMapPlaceableLight)mapPlaceable; writer.Write(light.Header.Translation); writer.Write(light.Header.Rotation); writer.Write((uint)light.Header.Type); writer.Write(light.Header.LightFOV); writer.Write(light.Header.Color); writer.Write(light.Header.Unknown1A); writer.Write(light.Header.Unknown1B); writer.Write(light.Header.Unknown2A); writer.Write(light.Header.Unknown2B); writer.Write(light.Header.Unknown2C); writer.Write(light.Header.Unknown2D); writer.Write(light.Header.Unknown3A); writer.Write(light.Header.Unknown3B); writer.Write(light.Header.UnknownPos1); writer.Write(light.Header.UnknownQuat1); writer.Write(light.Header.UnknownPos2); writer.Write(light.Header.UnknownQuat2); writer.Write(light.Header.UnknownPos3); writer.Write(light.Header.UnknownQuat3); writer.Write(light.Header.Unknown4A); writer.Write(light.Header.Unknown4B); writer.Write(light.Header.Unknown5); writer.Write(light.Header.Unknown6A); writer.Write(light.Header.Unknown6B); writer.Write(light.Header.Unknown7A); writer.Write(light.Header.Unknown7B); } } }