Beispiel #1
0
    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;
    }
Beispiel #2
0
 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;
 }
Beispiel #3
0
 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);
        }