protected override void RunCommand(IEnumerable <string> args)
 {
     listImpl(animal => !TeamTypes.ForTeam(animal.GetPropertyValue <int>("TargetingTeam")).IsTamed(), args);
 }
Example #2
0
        protected override void RunCommand(IEnumerable <string> args)
        {
            List <string> argsList = args.ToList();

            if (showCommandHelp(argsList))
            {
                return;
            }

            bool itemsLong      = withItems == "long";
            bool inventoryLong  = withInventory == "long";
            bool tamedLong      = tamed == "long";
            bool structuresLong = withStructures == "long";

            Stopwatch stopwatch = new Stopwatch(GlobalOptions.UseStopWatch);

            bool mapNeeded = withItems != null || tamed != null || withStructures != null || withInventory != null;

            if (!GlobalOptions.Quiet && mapNeeded)
            {
                Console.WriteLine("Need to load map, this may take some time...");
            }

            string saveGame        = argsList.Count > 0 ? argsList[0] : Path.Combine(GlobalOptions.ArkToolsConfiguration.BasePath, GlobalOptions.ArkToolsConfiguration.ArkSavegameFilename);
            string outputDirectory = argsList.Count > 1 ? argsList[1] : Path.Combine(GlobalOptions.ArkToolsConfiguration.BasePath, GlobalOptions.ArkToolsConfiguration.TribesPath);
            string saveDir         = Path.GetDirectoryName(saveGame);

            Dictionary <int, HashSet <TribeBase> > baseMap;
            CustomDataContext context = new CustomDataContext();

            if (mapNeeded)
            {
                ArkDataManager.LoadData(GlobalOptions.Language);

                ArkSavegame mapSave = new ArkSavegame().ReadBinary <ArkSavegame>(saveGame, ReadingOptions.Create().WithBuildComponentTree(true));
                context.Savegame = mapSave;
                context.MapData  = LatLonCalculator.ForSave(context.Savegame);
                stopwatch.Stop("Loading map data");
                if (withBases)
                {
                    baseMap = new Dictionary <int, HashSet <TribeBase> >();
                    foreach (GameObject gameObject in mapSave)
                    {
                        // Skip items and stuff without a location
                        if (gameObject.IsItem || gameObject.Location == null)
                        {
                            continue;
                        }

                        string signText      = gameObject.GetPropertyValue <string>("SignText");
                        long?  targetingTeam = gameObject.GetPropertyValue <long?>("TargetingTeam");

                        if (signText != null && targetingTeam != null)
                        {
                            // Might be a 'Base' sign
                            MatchCollection matcher = basePattern.Matches(signText);
                            if (matcher.Any())
                            {
                                // Found a base sign, add it to the set, automatically replacing duplicates
                                int          tribeId  = (int)targetingTeam;
                                LocationData location = gameObject.Location;
                                string       baseName = matcher[1].Value;
                                float        size     = float.Parse(matcher[2].Value);

                                TribeBase tribeBase = new TribeBase(baseName, location.X, location.Y, location.Z, size);

                                if (!baseMap.ContainsKey(tribeId))
                                {
                                    baseMap[tribeId] = new HashSet <TribeBase>();
                                }

                                baseMap[tribeId].Add(tribeBase);
                            }
                        }
                    }

                    stopwatch.Stop("Collecting bases");
                }
                else
                {
                    baseMap = null;
                }

                if (mapSave.HibernationEntries.Any() && tamed != null)
                {
                    List <GameObject> combinedObjects = context.Savegame.Objects.ToList();

                    foreach (HibernationEntry entry in context.Savegame.HibernationEntries)
                    {
                        ObjectCollector collector = new ObjectCollector(entry, 1);
                        combinedObjects.AddRange(collector.Remap(combinedObjects.Count));
                    }

                    context.ObjectContainer = new GameObjectContainer(combinedObjects);
                }
                else
                {
                    context.ObjectContainer = mapSave;
                }
            }
            else
            {
                baseMap = null;
            }

            List <Action> tasks = GlobalOptions.Parallel ? new List <Action>() : null;

            void mapWriter(JsonTextWriter generator, int tribeId)
            {
                if (!mapNeeded)
                {
                    return;
                }
                List <GameObject>  structures   = new List <GameObject>();
                List <GameObject>  creatures    = new List <GameObject>();
                List <Item>        items        = new List <Item>();
                List <Item>        blueprints   = new List <Item>();
                List <DroppedItem> droppedItems = new List <DroppedItem>();
                // Apparently there is a behavior in ARK causing certain structures to exist twice within a save
                HashSet <ArkName> processedList = new HashSet <ArkName>();
                // Bases
                HashSet <TribeBase> bases = withBases ? baseMap[tribeId] : null;

                foreach (GameObject gameObject in context.ObjectContainer)
                {
                    if (gameObject.IsItem)
                    {
                        continue;
                    }

                    int targetingTeam = gameObject.GetPropertyValue <int>("TargetingTeam", defaultValue: -1);
                    if (targetingTeam == -1)
                    {
                        continue;
                    }

                    TeamType teamType = TeamTypes.ForTeam(targetingTeam);
                    if (tribeId == -1 && teamType != TeamType.Player)
                    {
                        continue;
                    }

                    if (tribeId == 0 && teamType != TeamType.NonPlayer)
                    {
                        continue;
                    }

                    if (tribeId > 0 && tribeId != targetingTeam)
                    {
                        continue;
                    }

                    // Determine base if we have bases
                    TribeBase tribeBase;
                    if (bases != null && gameObject.Location != null)
                    {
                        TribeBase matchedBase = null;
                        foreach (TribeBase potentialBase in bases)
                        {
                            if (potentialBase.InsideBounds(gameObject.Location))
                            {
                                matchedBase = potentialBase;
                                break;
                            }
                        }

                        tribeBase = matchedBase;
                    }
                    else
                    {
                        tribeBase = null;
                    }

                    if (gameObject.IsCreature())
                    {
                        if (!processedList.Contains(gameObject.Names[0]))
                        {
                            if (tribeBase != null)
                            {
                                tribeBase.Creatures.Add(gameObject);
                            }
                            else
                            {
                                creatures.Add(gameObject);
                            }

                            processedList.Add(gameObject.Names[0]);
                        }
                        else
                        {
                            // Duped Creature
                            continue;
                        }
                    }
                    else if (!gameObject.IsPlayer() && !gameObject.IsWeapon() && !gameObject.IsDroppedItem())
                    {
                        // LinkedPlayerDataID: Players ain't structures
                        // AssociatedPrimalItem: Items equipped by sleeping players
                        // MyItem: dropped item
                        if (!processedList.Contains(gameObject.Names[0]))
                        {
                            if (tribeBase != null)
                            {
                                tribeBase.Structures.Add(gameObject);
                            }
                            else
                            {
                                structures.Add(gameObject);
                            }

                            processedList.Add(gameObject.Names[0]);
                        }
                        else
                        {
                            // Duped Structure
                            continue;
                        }
                    }
                    else
                    {
                        if (!processedList.Contains(gameObject.Names[0]))
                        {
                            processedList.Add(gameObject.Names[0]);
                        }
                        else
                        {
                            // Duped Player or dropped Item or weapon
                            continue;
                        }
                    }

                    void itemHandler(ObjectReference itemReference)
                    {
                        GameObject item = itemReference.GetObject(context.Savegame);

                        if (item != null && !Item.isDefaultItem(item))
                        {
                            if (processedList.Contains(item.Names[0]))
                            {
                                // happens for players having items in their quick bar
                                return;
                            }

                            processedList.Add(item.Names[0]);

                            if (item.HasAnyProperty("bIsBlueprint"))
                            {
                                if (tribeBase != null)
                                {
                                    tribeBase.Blueprints.Add(new Item(item));
                                }
                                else
                                {
                                    blueprints.Add(new Item(item));
                                }
                            }
                            else
                            {
                                if (tribeBase != null)
                                {
                                    tribeBase.Items.Add(new Item(item));
                                }
                                else
                                {
                                    items.Add(new Item(item));
                                }
                            }
                        }
                    }

                    void droppedItemHandler(GameObject droppedItemObject)
                    {
                        DroppedItem droppedItem = new DroppedItem(droppedItemObject, context.Savegame);

                        if (tribeBase != null)
                        {
                            tribeBase.DroppedItems.Add(droppedItem);
                        }
                        else
                        {
                            droppedItems.Add(droppedItem);
                        }
                    }

                    if (withItems != null && withInventory == null)
                    {
                        foreach (GameObject inventory in gameObject.Components.Values)
                        {
                            if (!inventory.IsInventory())
                            {
                                continue;
                            }

                            List <ObjectReference> inventoryItems = inventory.GetPropertyValue <IArkArray, ArkArrayObjectReference>("InventoryItems");
                            foreach (ObjectReference itemReference in inventoryItems ?? Enumerable.Empty <ObjectReference>())
                            {
                                itemHandler(itemReference);
                            }

                            List <ObjectReference> equippedItems = inventory.GetPropertyValue <IArkArray, ArkArrayObjectReference>("EquippedItems");
                            foreach (ObjectReference itemReference in equippedItems ?? Enumerable.Empty <ObjectReference>())
                            {
                                itemHandler(itemReference);
                            }
                        }
                    }

                    ObjectReference myItem = gameObject.GetPropertyValue <ObjectReference>("MyItem");

                    if (myItem != null)
                    {
                        if (withItems != null && withInventory == null)
                        {
                            itemHandler(myItem);
                        }
                        else if (withInventory != null)
                        {
                            droppedItemHandler(gameObject);
                        }
                    }
                }

                void writeStructures(IEnumerable <GameObject> structList)
                {
                    if (withStructures == null)
                    {
                        return;
                    }
                    generator.WriteArrayFieldStart("structures");

                    if (structuresLong)
                    {
                        foreach (GameObject structureObject in structList)
                        {
                            Structure structure = new Structure(structureObject, context.Savegame);

                            generator.WriteStartObject();

                            structure.writeAllProperties(generator, context, writeAllFields);

                            if (withInventory != null)
                            {
                                structure.writeInventory(generator, context, writeAllFields, !inventoryLong);
                            }

                            generator.WriteEndObject();
                        }
                    }
                    else
                    {
                        Dictionary <ArkName, long> structMap = structList.GroupBy(o => o.ClassName).ToDictionary(objects => objects.Key, objects => objects.LongCount());
                        foreach (KeyValuePair <ArkName, long> entry in structMap.OrderByDescending(pair => pair.Value))
                        {
                            generator.WriteStartObject();

                            string name = entry.Key.ToString();
                            if (ArkDataManager.HasStructure(name))
                            {
                                name = ArkDataManager.GetStructure(name).Name;
                            }

                            generator.WriteField("name", name);
                            generator.WriteField("count", entry.Value);

                            generator.WriteEndObject();
                        }
                    }

                    generator.WriteEndArray();
                }

                void writeCreatures(List <GameObject> creaList)
                {
                    if (tamed == null)
                    {
                        return;
                    }
                    generator.WriteArrayFieldStart("tamed");

                    if (tamedLong)
                    {
                        foreach (GameObject creatureObject in creaList)
                        {
                            Creature creature = new Creature(creatureObject, context.Savegame);

                            generator.WriteStartObject();

                            creature.writeAllProperties(generator, context, writeAllFields);

                            if (withInventory != null)
                            {
                                creature.writeInventory(generator, context, writeAllFields, !inventoryLong);
                            }

                            generator.WriteEndObject();
                        }
                    }
                    else
                    {
                        Dictionary <ArkName, long> creaMap = creaList.GroupBy(o => o.ClassName).ToDictionary(objects => objects.Key, objects => objects.LongCount());
                        foreach (KeyValuePair <ArkName, long> entry in creaMap.OrderByDescending(pair => pair.Value))
                        {
                            generator.WriteStartObject();

                            string name = entry.Key.ToString();
                            if (ArkDataManager.HasCreature(name))
                            {
                                name = ArkDataManager.GetCreature(name).Name;
                            }

                            generator.WriteField("name", name);
                            generator.WriteField("count", entry.Value);

                            generator.WriteEndObject();
                        }
                    }

                    generator.WriteEndArray();
                }

                void writeDroppedItems(List <DroppedItem> droppedList)
                {
                    if (withInventory == null)
                    {
                        return;
                    }
                    generator.WriteArrayFieldStart("droppedItems");

                    foreach (DroppedItem droppedItem in droppedList)
                    {
                        generator.WriteStartObject();

                        droppedItem.writeAllProperties(generator, context, writeAllFields);
                        droppedItem.writeInventory(generator, context, writeAllFields, !inventoryLong);

                        generator.WriteEndObject();
                    }

                    generator.WriteEndArray();
                }

                if (withBases && bases != null)
                {
                    generator.WriteArrayFieldStart("bases");

                    foreach (TribeBase tribeBase in bases)
                    {
                        generator.WriteStartObject();

                        generator.WriteField("name", tribeBase.Name);
                        generator.WriteField("x", tribeBase.X);
                        generator.WriteField("y", tribeBase.Y);
                        generator.WriteField("z", tribeBase.Z);
                        generator.WriteField("lat", context.MapData.CalculateLat(tribeBase.Y));
                        generator.WriteField("lon", context.MapData.CalculateLon(tribeBase.X));
                        generator.WriteField("radius", tribeBase.Size);
                        writeCreatures(tribeBase.Creatures);
                        writeStructures(tribeBase.Structures);
                        writeDroppedItems(tribeBase.DroppedItems);
                        if (itemsLong)
                        {
                            generator.WritePropertyName("items");
                            Inventory.writeInventoryLong(generator, context, tribeBase.Items, writeAllFields);
                            generator.WritePropertyName("blueprints");
                            Inventory.writeInventoryLong(generator, context, tribeBase.Blueprints, writeAllFields);
                        }
                        else
                        {
                            generator.WritePropertyName("items");
                            Inventory.writeInventorySummary(generator, tribeBase.Items);
                            generator.WritePropertyName("blueprints");
                            Inventory.writeInventorySummary(generator, tribeBase.Blueprints);
                        }

                        generator.WriteEndObject();
                    }

                    generator.WriteStartObject();
                }

                writeCreatures(creatures);
                writeStructures(structures);
                writeDroppedItems(droppedItems);
                if (itemsLong)
                {
                    generator.WritePropertyName("items");
                    Inventory.writeInventoryLong(generator, context, items, writeAllFields);
                    generator.WritePropertyName("blueprints");
                    Inventory.writeInventoryLong(generator, context, blueprints, writeAllFields);
                }
                else
                {
                    generator.WritePropertyName("items");
                    Inventory.writeInventorySummary(generator, items);
                    generator.WritePropertyName("blueprints");
                    Inventory.writeInventorySummary(generator, blueprints);
                }

                if (withBases && bases != null)
                {
                    generator.WriteEndObject();

                    generator.WriteEndArray();
                }
            }

            foreach (string path in Directory.EnumerateFiles(saveDir).Where(path => tribePattern.IsMatch(path)))
            {
                Action task = () => {
                    try {
                        Tribe tribe = new Tribe(path, ReadingOptions.Create());

                        string tribeFileName = tribe.tribeId + ".json";

                        string tribePath = Path.Combine(outputDirectory, tribeFileName);

                        CommonFunctions.WriteJson(tribePath, (generator, writingOptions) => {
                            generator.WriteStartObject();

                            tribe.writeAllProperties(generator, context, writeAllFields);

                            mapWriter(generator, tribe.tribeId);

                            generator.WriteEndObject();
                        }, writingOptions);
                    } catch (Exception ex) {
                        Console.Error.WriteLine("Found potentially corrupt ArkTribe: " + path);
                        if (GlobalOptions.Verbose)
                        {
                            Console.Error.WriteLine(ex.Message);
                            Console.Error.WriteLine(ex.StackTrace);
                        }
                    }
                };

                if (tasks != null)
                {
                    tasks.Add(task);
                }
                else
                {
                    task();
                }
            }

            if (tasks != null)
            {
                Parallel.ForEach(tasks, task => task());
            }

            if (tribeless)
            {
                string tribePath = Path.Combine(outputDirectory, "tribeless.json");

                CommonFunctions.WriteJson(tribePath, (generator, writingOptions) => {
                    generator.WriteStartObject();

                    mapWriter(generator, -1);

                    generator.WriteEndObject();
                }, writingOptions);
            }

            if (nonPlayers)
            {
                string tribePath = Path.Combine(outputDirectory, "non-players.json");

                CommonFunctions.WriteJson(tribePath, (generator, writingOptions) => {
                    generator.WriteStartObject();

                    mapWriter(generator, 0);

                    generator.WriteEndObject();
                }, writingOptions);
            }

            stopwatch.Stop("Loading tribes and writing info");
            stopwatch.Print();
        }