internal void _Serialize(MSBS.Part part, GameObject parent) { part.Name = parent.name; part.Placeholder = Placeholder; part.ModelName = ModelName; part.Position = new System.Numerics.Vector3(parent.transform.position.x, parent.transform.position.y, parent.transform.position.z); // :trashcat: //part.Rotation.X = parent.transform.rotation.eulerAngles.x; //part.Rotation.Y = parent.transform.rotation.eulerAngles.z; //part.Rotation.Z = -parent.transform.rotation.eulerAngles.y; //part.Rotation = ConvertEuler(parent.transform.eulerAngles); //part.Rotation = new System.Numerics.Vector3(Rotation.x, Rotation.y, Rotation.z); part.Rotation = EulerUtils.quaternion2EulerDeg(parent.transform.rotation.normalized, EulerUtils.RotSeq.yzx); //print($@"{part.Name}: {parent.transform.eulerAngles}, {parent.transform.localEulerAngles} -> {part.Rotation}"); part.Scale = new System.Numerics.Vector3(parent.transform.localScale.x, parent.transform.localScale.y, parent.transform.localScale.z); part.EntityID = EntityID; part.UnkE18 = UnkE18; part.UnkE3C = UnkE3C; part.UnkE40 = UnkE40; part.EntityGroupIDs[0] = EntityGroupID1; part.EntityGroupIDs[1] = EntityGroupID2; part.EntityGroupIDs[2] = EntityGroupID3; part.EntityGroupIDs[3] = EntityGroupID4; part.EntityGroupIDs[4] = EntityGroupID5; part.EntityGroupIDs[5] = EntityGroupID6; part.EntityGroupIDs[6] = EntityGroupID7; part.EntityGroupIDs[7] = EntityGroupID8; part.LanternID = LanternID; part.LodParamID = LodParamID; part.EnableOnAboveShadow = EnableOnAboveShadow; part.IsStaticShadowSrc = IsStaticShadowSrc; part.IsCascade3ShadowSrc = IsCascade3ShadowSrc; part.UnkE04 = UnkE04; part.UnkE05 = UnkE05; part.UnkE06 = UnkE06; part.UnkE09 = UnkE09; part.UnkE0B = UnkE0B; part.UnkE0F = UnkE0F; part.UnkE10 = UnkE10; part.UnkE17 = UnkE17; part.IsPointLightShadowSrc = IsPointLightShadowSrc; part.IsShadowSrc = IsShadowSrc; part.IsShadowDest = IsShadowDest; part.IsShadowOnly = IsShadowOnly; part.DrawByReflectCam = DrawByReflectCam; part.DrawOnlyReflectCam = DrawOnlyReflectCam; part.DisablePointLightEffect = DisablePointLightEffect; }
public void setBasePart(MSBS.Part part) { Placeholder = part.Placeholder; ModelName = part.ModelName; Rotation = new UnityEngine.Vector3(part.Rotation.X, part.Rotation.Y, part.Rotation.Z); EntityID = part.EntityID; UnkE18 = part.UnkE18; UnkE3C = part.UnkE3C; UnkE40 = part.UnkE40; EntityGroupID1 = part.EntityGroupIDs[0]; EntityGroupID2 = part.EntityGroupIDs[1]; EntityGroupID3 = part.EntityGroupIDs[2]; EntityGroupID4 = part.EntityGroupIDs[3]; EntityGroupID5 = part.EntityGroupIDs[4]; EntityGroupID6 = part.EntityGroupIDs[5]; EntityGroupID7 = part.EntityGroupIDs[6]; EntityGroupID8 = part.EntityGroupIDs[7]; LanternID = part.LanternID; LodParamID = part.LodParamID; EnableOnAboveShadow = part.EnableOnAboveShadow; IsStaticShadowSrc = part.IsStaticShadowSrc; IsCascade3ShadowSrc = part.IsCascade3ShadowSrc; UnkE04 = part.UnkE04; UnkE05 = part.UnkE05; UnkE06 = part.UnkE06; UnkE09 = part.UnkE09; UnkE0B = part.UnkE0B; UnkE0F = part.UnkE0F; UnkE10 = part.UnkE10; UnkE17 = part.UnkE17; IsPointLightShadowSrc = part.IsPointLightShadowSrc; IsShadowSrc = part.IsShadowSrc; IsShadowDest = part.IsShadowDest; IsShadowOnly = part.IsShadowOnly; DrawByReflectCam = part.DrawByReflectCam; DrawOnlyReflectCam = part.DrawOnlyReflectCam; DisablePointLightEffect = part.DisablePointLightEffect; }
public bool ScrapeMaps(Universe u) { if (spec.MsbDir == null) { return(false); } if (spec.Game == FromGame.SDT) { Dictionary <string, MSBS> maps = editor.Load(spec.MsbDir, path => MSBS.Read(path)); foreach (KeyValuePair <string, MSBS> entry in maps) { string location = entry.Key; MSBS msb = entry.Value; Obj map = Obj.Map(location); int treasureIndex = 0; foreach (MSBS.Event.Treasure treasure in msb.Events.Treasures) { if (treasure.TreasurePartName != null && treasure.ItemLotID != -1) { Obj treasureObj = Obj.Treasure(location, treasureIndex); Obj part = Obj.Part(location, treasure.TreasurePartName); u.Add(Verb.PRODUCES, part, treasureObj); u.Add(Verb.PRODUCES, treasureObj, Obj.Lot(treasure.ItemLotID)); } treasureIndex++; } foreach (MSBS.Event.Talk talk in msb.Events.Talks) { for (int i = 0; i < 2; i++) { string enemyName = talk.EnemyNames[i]; int esdId = talk.TalkIDs[i]; if (enemyName == null || esdId < 0) { continue; } Obj part = Obj.Part(location, enemyName); u.Add(Verb.CONTAINS, part, Obj.Esd(esdId)); } } foreach (MSBS.Entry obj in msb.Parts.GetEntries()) { MSBS.Part part = obj as MSBS.Part; if (part == null) { continue; } Obj partObj = Obj.Part(location, part.Name); if (part.EntityID != -1) { u.Add(Verb.CONTAINS, Obj.Entity(part.EntityID), partObj); } foreach (int groupId in part.EntityGroupIDs.Where(groupID => groupID > 0)) { u.Add(Verb.CONTAINS, Obj.Entity(groupId), partObj); } if (part is MSBS.Part.Enemy enemy) { string model = part.Name.Split('_')[0]; u.Add(Verb.CONTAINS, partObj, Obj.ChrModel(model)); if (enemy.NPCParamID != -1) { u.Add(Verb.CONTAINS, partObj, Obj.Npc(enemy.NPCParamID)); } } else if (part is MSBS.Part.Object) { string model = part.Name.Split('_')[0]; u.Add(Verb.CONTAINS, partObj, Obj.ObjModel(model)); } // This gets a bit noisy, so don't add part to map unless it's already in universe if (u.Nodes.ContainsKey(partObj)) { u.Add(Verb.CONTAINS, map, partObj); } } } } else if (spec.Game == FromGame.DS1 || spec.Game == FromGame.DS1R) { Dictionary <string, MSB1> maps = editor.Load(spec.MsbDir, path => path.Contains("m99") ? null : MSB1.Read(path), "*.msb"); foreach (KeyValuePair <string, MSB1> entry in maps) { string location = entry.Key; Obj map = Obj.Map(location); MSB1 msb = entry.Value; if (msb == null) { continue; } // For now, just load talk data foreach (MSB1.Entry obj in msb.Parts.GetEntries()) { MSB1.Part part = obj as MSB1.Part; if (part == null) { continue; } Obj partObj = Obj.Part(location, part.Name); if (part.EntityID != -1) { u.Add(Verb.CONTAINS, Obj.Entity(part.EntityID), partObj); } if (part is MSB1.Part.Enemy enemy) { string model = part.Name.Split('_')[0]; u.Add(Verb.CONTAINS, partObj, Obj.ChrModel(model)); if (enemy.NPCParamID != -1 && model == "c0000") { u.Add(Verb.CONTAINS, partObj, Obj.Human(enemy.NPCParamID)); } if (enemy.TalkID != -1) { u.Add(Verb.CONTAINS, partObj, Obj.Esd(enemy.TalkID)); } } else if (part is MSB1.Part.Object) { string model = part.Name.Split('_')[0]; u.Add(Verb.CONTAINS, partObj, Obj.ObjModel(model)); } // This gets a bit noisy, so don't add part to map unless it's already in universe if (u.Nodes.ContainsKey(partObj)) { u.Add(Verb.CONTAINS, map, partObj); } } } } else if (spec.Game == FromGame.DS3) { Dictionary <string, MSB3> maps = editor.Load(spec.MsbDir, path => path.Contains("m99") ? null : MSB3.Read(path)); foreach (KeyValuePair <string, MSB3> entry in maps) { string location = entry.Key; Obj map = Obj.Map(location); MSB3 msb = entry.Value; if (msb == null) { continue; } // For now, just load talk data foreach (MSB3.Entry obj in msb.Parts.GetEntries()) { MSB3.Part part = obj as MSB3.Part; if (part == null) { continue; } Obj partObj = Obj.Part(location, part.Name); if (part.EventEntityID != -1) { u.Add(Verb.CONTAINS, Obj.Entity(part.EventEntityID), partObj); } if (part is MSB3.Part.Enemy enemy) { string model = part.Name.Split('_')[0]; u.Add(Verb.CONTAINS, partObj, Obj.ChrModel(model)); if (enemy.CharaInitID > 0) { u.Add(Verb.CONTAINS, partObj, Obj.Human(enemy.CharaInitID)); } if (enemy.TalkID != -1) { u.Add(Verb.CONTAINS, partObj, Obj.Esd(enemy.TalkID)); } } else if (part is MSB3.Part.Object) { string model = part.Name.Split('_')[0]; u.Add(Verb.CONTAINS, partObj, Obj.ObjModel(model)); } // This gets a bit noisy, so don't add part to map unless it's already in universe if (u.Nodes.ContainsKey(partObj)) { u.Add(Verb.CONTAINS, map, partObj); } } } } else { return(false); } return(true); }
private ItemLocs FindItemLocs(GameData game) { PARAM itemLots = game.Param("ItemLotParam"); PARAM npcs = game.Param("NpcParam"); ItemLocs ret = new ItemLocs { usedItemLots = new SortedDictionary <int, List <EntityId> >(), usedBaseShops = new SortedDictionary <int, List <EntityId> >(), baseLotsToCreate = new Dictionary <int, int>(), // TODO: See if we can have a reasaonable processing step newEntityLots = new Dictionary <int, int>(), }; Dictionary <EntityId, EntityId> objects = new Dictionary <EntityId, EntityId>(); Dictionary <int, List <EntityId> > usedNpcs = new Dictionary <int, List <EntityId> >(); Dictionary <int, List <EntityId> > usedEntities = new Dictionary <int, List <EntityId> >(); Dictionary <int, List <EntityId> > usedEsds = new Dictionary <int, List <EntityId> >(); // Map from item lot to ESD id, hackily extracted from ESD. Dictionary <int, HashSet <int> > talkItemLocations = new Dictionary <int, HashSet <int> >(); // This is a bit intensive. Ideally just dump this somewhere else HashSet <int> debugEsd = new HashSet <int>(); IEnumerable <ESD.Condition> GetCommands(List <ESD.Condition> condList) => Enumerable.Concat(condList, condList.SelectMany(cond => GetCommands(cond.Subconditions))); foreach (KeyValuePair <string, Dictionary <string, ESD> > entry in game.Talk) { string location = game.Locations.ContainsKey(entry.Key) ? game.Locations[entry.Key] : ""; // 62210 foreach (KeyValuePair <string, ESD> esdEntry in entry.Value) { ESD esd = esdEntry.Value; int esdId = int.Parse(esdEntry.Key.Substring(1)); foreach ((int, int, ESD.State)stateDesc in esd.StateGroups.SelectMany(stateGroup => stateGroup.Value.Select(state => (stateGroup.Key, state.Key, state.Value)))) { (int groupId, int id, ESD.State state) = stateDesc; foreach (ESD.CommandCall cmd in new[] { state.EntryCommands, state.WhileCommands, state.ExitCommands, GetCommands(state.Conditions).SelectMany(c => c.PassCommands) }.SelectMany(c => c)) { foreach (byte[] arg in cmd.Arguments) { if (arg.Length == 6 && arg[0] == 0x82 && arg[5] == 0xA1) { int opt = BitConverter.ToInt32(arg, 1); if (opt >= 60000 && opt <= 69900 && itemLots[opt] != null) { AddMulti(talkItemLocations, opt, esdId); } } } } } } } bool logEntities = false; foreach (KeyValuePair <string, MSBS> entry in game.Smaps) { string location = game.Locations[entry.Key]; MSBS msb = entry.Value; Dictionary <string, int> partEsds = new Dictionary <string, int>(); List <MSBS.Part.Enemy> enemies = msb.Parts.Enemies; // TODO: Update SoulsFormat and migrate to new names foreach (MSBS.Event.Talk ev in entry.Value.Events.Talks) { for (int i = 0; i < 2; i++) { string part = ev.EnemyNames[i]; int esdId = ev.TalkIDs[i]; if (esdId < 0 || part == null) { continue; } partEsds[part] = esdId; } } foreach (MSBS.Entry obj in entry.Value.Parts.GetEntries()) { MSBS.Part part = obj as MSBS.Part; if (part == null) { continue; } EntityId id; int esdId = 0; List <int> groupIDs = part.EntityGroupIDs.Where(groupID => groupID > 0).ToList(); if (part is MSBS.Part.Enemy enemy) { esdId = partEsds.ContainsKey(enemy.Name) ? partEsds[enemy.Name] : -1; id = new EntityId(location, enemy.Name, enemy.EntityID, enemy.NPCParamID, enemy.CharaInitID, groupIDs); } else if (part is MSBS.Part.Object || logEntities) { id = new EntityId(location, part.Name, part.EntityID, GroupIds: groupIDs); } else { continue; } objects[id] = id; if (id.EventEntityID > 0) { AddMulti(usedEntities, id.EventEntityID, id); } foreach (int groupID in groupIDs) { AddMulti(usedEntities, groupID, id); } if (id.NPCParamID > 0) { AddMulti(usedNpcs, id.NPCParamID, id); } if (esdId > 0) { if (debugEsd.Contains(esdId)) { Console.WriteLine($"ESD {esdId} belongs to {game.EntityName(id, true)} in {location}, entity id {id.EventEntityID}"); } AddMulti(usedEsds, esdId, id); } } } if (logEntities) { foreach (KeyValuePair <int, List <EntityId> > entry in usedEntities.OrderBy(e => e.Key)) { Console.WriteLine($"{entry.Key}: {string.Join(", ", entry.Value.Select(e => $"{game.EntityName(e, true)} in {e.MapName}"))}"); } } List <EntityId> unusedEsd = new List <EntityId> { new EntityId("", "Unknown Dialogue") }; foreach (KeyValuePair <int, HashSet <int> > entry in talkItemLocations) { List <EntityId> talkIds; if (addUnused) { talkIds = entry.Value.SelectMany(esd => usedEsds.ContainsKey(esd) ? usedEsds[esd] : unusedEsd).ToList(); } else { talkIds = entry.Value.Where(esd => usedEsds.ContainsKey(esd)).SelectMany(esd => usedEsds[esd]).ToList(); if (talkIds.Count == 0) { continue; } } AddMulti(ret.usedItemLots, entry.Key, talkIds); } foreach (KeyValuePair <int, int> entry in shopEsds) { if (!usedEsds.ContainsKey(entry.Value) && !addUnused) { continue; } AddMulti(ret.usedBaseShops, entry.Key, usedEsds.ContainsKey(entry.Value) ? usedEsds[entry.Value] : unusedEsd); } foreach (KeyValuePair <string, MSBS> entry in game.Smaps) { string location = game.Locations[entry.Key]; foreach (MSBS.Event.Treasure treasure in entry.Value.Events.Treasures) { if (treasure.TreasurePartName != null) { EntityId id = new EntityId(location, treasure.TreasurePartName); if (!objects.ContainsKey(id)) { if (logUnused) { Console.WriteLine($"Missing entity for treasure {treasure.Name} with entity {treasure.TreasurePartName} and lot {treasure.ItemLotID}"); } continue; } AddMulti(ret.usedItemLots, treasure.ItemLotID, objects[id]); } } } foreach (PARAM.Row row in npcs.Rows) { int npcID = (int)row.ID; PARAM.Cell cell = row["ItemLotId1"]; if (cell == null || (int)cell.Value == -1) { continue; } int itemLot = (int)cell.Value; if (itemLots[itemLot] == null) { if (logUnused) { Console.WriteLine($"Invalid NPC lot item for {npcID} with lot {itemLot}"); } continue; } if (!usedNpcs.ContainsKey(npcID)) { if (logUnused) { Console.WriteLine($"Unused NPC: {npcID}"); } if (addUnused) { AddMulti(ret.usedItemLots, itemLot, new EntityId("", "Unused NPC")); } continue; } AddMulti(ret.usedItemLots, itemLot, usedNpcs[npcID]); } foreach (KeyValuePair <int, int> entry in entityItemLots) { int entityId = entry.Key; List <int> itemLot = new List <int> { entry.Value }; if (additionalEntityItemLots.ContainsKey(entityId)) { itemLot.AddRange(additionalEntityItemLots[entityId]); } List <EntityId> id; if (usedEntities.ContainsKey(entityId)) { id = usedEntities[entityId]; } else { Console.WriteLine($"XX Missing entity {entityId} with item lot {String.Join(", ", itemLot)}"); id = new List <EntityId> { new EntityId("", "from entity") }; } foreach (int lot in itemLot) { if (logUnused && (int)itemLots[lot]["getItemFlagId"].Value == -1 && id[0].GetModelID() != 2150) { Console.WriteLine($"Eventless entity drop, not crystal lizard, for {String.Join(", ", id)} item lot {lot}"); } AddMulti(ret.usedItemLots, lot, id); } } Dictionary <int, int> syntheticLotBase = new Dictionary <int, int>(); foreach (KeyValuePair <int, int> entry in treasureCarpDrops) { int entityId = entry.Key; int baseLot = entry.Value; List <EntityId> id; if (usedEntities.ContainsKey(entityId)) { id = usedEntities[entityId]; } else { Console.WriteLine($"XX Missing entity {entityId} with item lot {baseLot}"); id = new List <EntityId> { new EntityId("", "from entity") }; } if (syntheticLotBase.ContainsKey(baseLot)) { syntheticLotBase[baseLot] += 5; } else { syntheticLotBase[baseLot] = baseLot; } int itemLot = syntheticLotBase[baseLot]; ret.baseLotsToCreate[itemLot] = baseLot; // TODO: See if this info can be extracted anywhere else ret.newEntityLots[entityId] = itemLot; AddMulti(ret.usedItemLots, itemLot, id); } foreach (KeyValuePair <int, string> entry in scriptLots) { int itemLot = entry.Key; if ((int)itemLots[itemLot]["getItemFlagId"].Value == -1) { // TODO: Make sure there are all classified... // Console.WriteLine($"XX No event id attached to script event {itemLot}"); } AddMulti(ret.usedItemLots, itemLot, new EntityId(entry.Value, "Scripted")); } foreach (int itemLot in talkLots) { if ((int)itemLots[itemLot]["getItemFlagId"].Value == -1) { Console.WriteLine($"XX No event id attached to talk event {itemLot}"); } AddMulti(ret.usedItemLots, itemLot, new EntityId("", "from talk")); } int lastLot = 0; bool lastConnected = false; foreach (PARAM.Row lot in itemLots.Rows) { int itemLot = (int)lot.ID; bool connected = (byte)lot["LotItemNum1"].Value == 1; if (itemLot == lastLot + 1) { // Don't require groups of item lots to be connected, only the base lot } else if (connected && lastConnected && (itemLot - lastLot) % 10 == 0 && (itemLot - lastLot) <= 40) { // This is also fine.... aaaa. Bell Demon drops. } else { if (!ret.usedItemLots.ContainsKey(itemLot)) { if (logUnused) { Console.WriteLine($"Unconnected item lot {itemLot}: {game.LotName(itemLot)}"); } if (addUnused) { AddMulti(ret.usedItemLots, itemLot, new EntityId("", "unknown")); } } } lastLot = itemLot; lastConnected = connected; } return(ret); }