예제 #1
0
        public static Blueprint FindRandomBlueprintWithParameters(out string filename, int minArea = 100, float minDensity = 0.01f, int minCost = 0, int maxAttemptsCount = 5, bool removeNonQualified = false)
        {
            Blueprint bp = null;

            filename = null;
            int attemptCount = 0;

            while (attemptCount < maxAttemptsCount)
            {
                attemptCount++;
                filename = SnapshotStoreManager.Instance.RandomSnapshotFilename();
                bp       = BlueprintLoader.LoadWholeBlueprintAtPath(filename);


                if (bp == null)
                {
                    Debug.Error(Debug.Store, "Corrupted XML at path {0}, removing", filename);
                    SnapshotStoreManager.Instance.RemoveBlueprintWithName(filename);
                    continue;
                }

                bp.UpdateBlueprintStats(includeCost: true);

                //Debug.Message("size: {0}x{1} (needed {2}). density {3} (needed {4}). cost {5} (needed {6})", bp.width, bp.height, minArea, bp.itemsDensity, minDensity, bp.totalCost, minCost);

                if (bp.height * bp.width > minArea && bp.itemsDensity > minDensity && bp.totalCost >= minCost)
                {
                    //Debug.Message("Qualified, using.");
                    return(bp);
                }
                else if (removeNonQualified)
                {
                    Debug.Warning(Debug.Store, "Non-qualified XML at path {0}, removing", filename);
                    SnapshotStoreManager.Instance.RemoveBlueprintWithName(filename);
                }
            }
            filename = null;
            return(null);
        }
예제 #2
0
        public void Analyze()
        {
            Debug.Log("analyzing blueprint {0} with options {1}", blueprint, options);
            blueprint.FindRooms();
            Debug.Log("Rooms found");
            BlueprintPreprocessor.ProcessBlueprint(blueprint, options);
            Debug.Log("Blueprint processed");

            result            = new BlueprintAnalyzerResult();
            result.totalArea  = blueprint.width * blueprint.height;
            result.roomsCount = blueprint.roomAreas.Count() - 2;

            result.internalArea = 0;
            for (int index = 2; index < blueprint.roomAreas.Count; index++)
            {
                result.internalArea += blueprint.roomAreas[index];
            }

            blueprint.UpdateBlueprintStats(includeCost: true);
            Debug.Log(Debug.Analyzer, "Analyzing map");
            for (int y = 0; y < blueprint.height; y++)
            {
                for (int x = 0; x < blueprint.width; x++)
                {
                    List <ItemTile> tiles = blueprint.itemsMap[x, y] ?? new List <ItemTile>();
                    foreach (ItemTile itemTile in tiles)
                    {
                        ProcessTile(itemTile, new IntVec3(x, 0, y));
                    }
                }
            }

            this.mannableCount = result.mannableCount;
            determinedType     = supposedType();
            Debug.Log(Debug.Analyzer, "Type is {0} by {1}", determinedType, result.ToString());
        }
예제 #3
0
        public static void ProcessBlueprint(Blueprint blueprint, ScatterOptions options)
        {
            if (blueprint == null)
            {
                return;
            }


            //Each item should be checked if it can be placed or not. This should help preventing situations when simulated scavenging removes things which anyway won't be placed.
            //For each placed item it's cost should be calculated
            for (int x = 0; x < blueprint.width; x++)
            {
                for (int z = 0; z < blueprint.height; z++)
                {
                    List <ItemTile> items      = blueprint.itemsMap[x, z];
                    TerrainTile     terrain    = blueprint.terrainMap[x, z];
                    TerrainDef      terrainDef = null;

                    if (terrain != null)
                    {
                        terrainDef = DefDatabase <TerrainDef> .GetNamed(terrain.defName, false);

                        if (terrainDef == null)
                        {
                            blueprint.terrainMap[x, z] = null; //remove unloadable terrain
                            terrain = null;
                        }
                    }



                    List <ItemTile> itemsToRemove = new List <ItemTile>();
                    if (items == null)
                    {
                        continue;
                    }

                    foreach (ItemTile item in items)
                    {
                        if (item.defName == "Corpse")
                        {
                            continue;                           //TODO: make some better way of handling corpses
                        }
                        //We can't move further with corpse item, because this item's thingDef is always null (actual corpse's def name depends on it's kind)

                        ThingDef thingDef = DefDatabase <ThingDef> .GetNamed(item.defName, false);

                        if (thingDef == null)
                        {
                            itemsToRemove.Add(item);
                            continue;
                        }

                        //remove items we don't want to see in the ruins
                        if (thingDef == ThingDefOf.Campfire || thingDef == ThingDefOf.TorchLamp)
                        {
                            itemsToRemove.Add(item);
                            continue;
                        }

                        if (options.wallsDoorsOnly)   //eleminate almost everything if "doors & walls" setting is active
                        {
                            if (!thingDef.IsDoor && !item.defName.ToLower().Contains("wall"))
                            {
                                itemsToRemove.Add(item);
                                continue;
                            }
                        }

                        if (options.disableSpawnItems)   //eleminate haulables if corresponding tick is set
                        {
                            if (thingDef.EverHaulable)
                            {
                                itemsToRemove.Add(item);
                                continue;
                            }
                        }

                        if (thingDef.defName.Contains("Animal") || thingDef.defName.Contains("Spot"))
                        {
                            itemsToRemove.Add(item);
                            continue; //remove animal sleeping beds and spots as wild animals tend to concentrate around. remove wedding, butchering and party spots, caravan spots as well
                        }


                        if (thingDef.IsCorpse || thingDef.Equals(ThingDefOf.MinifiedThing))   //check if corpses and minified things contain inner data, otherwise ignore
                        {
                            if ((item.innerItems?.Count() ?? 0) == 0 && item.itemXml == null)
                            {
                                itemsToRemove.Add(item);
                                continue;
                            }
                        }
                    }

                    foreach (ItemTile item in itemsToRemove)
                    {
                        if (item.isWall || item.isDoor)
                        {
                            blueprint.RemoveWall(item.location.x, item.location.z);
                        }

                        items.Remove(item);
                    }
                }
            }

            //Recalculate cost data after removing some items (should speed up, as cost calculation seems to be cpu-expensive process)
            blueprint.UpdateBlueprintStats(true);

            //Perform removing all items exceeding maximum cost
            for (int x = 0; x < blueprint.width; x++)
            {
                for (int z = 0; z < blueprint.height; z++)
                {
                    List <ItemTile> items   = blueprint.itemsMap[x, z];
                    TerrainTile     terrain = blueprint.terrainMap[x, z];

                    List <ItemTile> itemsToRemove = new List <ItemTile>();
                    if (terrain != null)
                    {
                        if (terrain.cost > options.itemCostLimit)
                        {
                            blueprint.terrainMap[x, z] = null;
                        }
                    }

                    if (items == null)
                    {
                        continue;
                    }
                    foreach (ItemTile item in items)
                    {
                        if (options.itemCostLimit > 0 && options.itemCostLimit < 1000) //filter too expensive items. limit of 1000 means "no limit" actually
                        {
                            if (item.cost > options.itemCostLimit)                     //removes only items where at least one item is more expensive than limit we have. limiting stacks is done later.
                            {
                                itemsToRemove.Add(item);
                            }
                        }
                    }

                    foreach (ItemTile item in itemsToRemove)
                    {
                        if (item.isWall || item.isDoor)
                        {
                            blueprint.RemoveWall(item.location.x, item.location.z);
                        }
                        items.Remove(item);
                    }
                }
            }
        }
예제 #4
0
        //ResolveParams's GetCustom/SetCustom is broken now, and it is a sealed (WHY??!) struct (WHY??!?!?) so I neither can fix it, nor make a dirty hack.
        //Seems like I have to abandon this approach and make direct calls.
        static public void Scatter(ResolveParams rp, ScatterOptions options, CoverageMap coverage, List <AbstractDefenderForcesGenerator> generators)
        {
            Debug.Log(Debug.Scatter, "Running stand-alone scatterer");
            if (options == null)
            {
                Debug.Warning(Debug.Scatter, "Scatter options are null, aborting");
                return;
            }

            DateTime start = DateTime.UtcNow;

            Debug.Log(Debug.Scatter, "[0 s]: Loading blueprint of size {0} - {1} to deploy at {2}, {3}", options.minRadius, options.maxRadius, rp.rect.minX, rp.rect.minZ);

            Blueprint bp  = null;
            Map       map = BaseGen.globalSettings.map;

            //probably should split scattering options into several distinct objects
            string filename = options.blueprintFileName;

            if (string.IsNullOrEmpty(filename) || !BlueprintLoader.CanLoadBlueprintAtPath(filename))
            {
                bp = BlueprintFinder.FindRandomBlueprintWithParameters(out filename, options.minimumAreaRequired, options.minimumDensityRequired, 15, removeNonQualified: options.deleteLowQuality);
                if (string.IsNullOrEmpty(filename))
                {
                    //still null = no suitable blueprints, fail.
                    Debug.Warning(Debug.Scatter, "Blueprint name was null and could not find another suitable blueprint, skipping");
                    return;
                }
            }

            if (!options.shouldLoadPartOnly) //should not cut => load whole
            {
                if (bp == null)              //if not loaded yet
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename);
                }
            }
            else
            {
                int radius = Rand.Range(options.minRadius, options.maxRadius);
                if (bp == null)
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename).RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
                else
                {
                    bp = bp.RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
            }

            if (bp == null)
            {
                Debug.Warning(Debug.Scatter, "Blueprint is still null after attempting to load any qualifying, returning");
                return;
            }


            Debug.Extra(Debug.Scatter, "Blueprint loaded, cutting and searching for rooms");
            bp.CutIfExceedsBounds(map.Size);

            // Here we have our blueprint loaded and ready to action. Doing stuff:
            BlueprintPreprocessor.ProcessBlueprint(bp, options); //Preprocess: remove missing and unnecessary items according to options
            bp.FindRooms();                                      //Traverse blueprint and construct rooms map
            options.roomMap = bp.wallMap;

            //Debug.PrintIntMap(bp.wallMap, delta: 1);
            Debug.Extra(Debug.Scatter, "Rooms traversed, initializing transfer utility");

            BlueprintTransferUtility btu = new BlueprintTransferUtility(bp, map, rp, options); //prepare blueprint transferrer

            Debug.Extra(Debug.Scatter, "Initialized, removing incompatible items...");

            btu?.RemoveIncompatibleItems(); //remove incompatible items
            Debug.Extra(Debug.Scatter, "Recalculating stats...");

            bp.UpdateBlueprintStats(true); //Update total cost, items count, etc

            Debug.Extra(Debug.Scatter, "Deteriorating...");
            DeteriorationProcessor.Process(bp, options); //create deterioration maps and do deterioration

            Debug.Extra(Debug.Scatter, "Scavenging...");
            ScavengingProcessor sp = new ScavengingProcessor();

            sp.RaidAndScavenge(bp, options); //scavenge remaining items according to scavenge options

            Debug.Extra(Debug.Scatter, "[{0} s] Prepared, about to start transferring.", DateTime.UtcNow.Subtract(start).TotalSeconds);
            try {
                btu.Transfer(coverage); //transfer blueprint
                Debug.Extra(Debug.Scatter, "[{0} s] Transferred.", DateTime.UtcNow.Subtract(start).TotalSeconds);
            } catch (Exception e) {
                Debug.Error(Debug.BlueprintTransfer, "Failed to transfer blueprint due to {0}", e);
            }

            if (generators != null)
            {
                foreach (AbstractDefenderForcesGenerator generator in generators)
                {
                    try {
                        generator.GenerateForces(map, rp, options);
                    } catch (Exception e) {
                        Debug.Error(Debug.BlueprintTransfer, "Failed to generate forces: {0}", e);
                    }
                }
            }
            Debug.Log(Debug.Scatter, "[{0} s] Generated forces.", DateTime.UtcNow.Subtract(start).TotalSeconds);

            if (options.shouldAddFilth)
            {
                try {
                    btu.AddFilthAndRubble(); //add filth and rubble
                } catch (Exception e) {
                    Debug.Warning(Debug.BlueprintTransfer, "Failed to add filth and rubble: {0}", e);
                }
            }
            Debug.Extra(Debug.Scatter, "[{0} s] Spiced up with rubble. Completed.", DateTime.UtcNow.Subtract(start).TotalSeconds);

            Debug.Log(Debug.Scatter, "Chunk scattering finished, moving");
        }
예제 #5
0
        public void RemoveIncompatibleItems()
        {
            //Each item should be checked if it can be placed or not. This should help preventing situations when simulated scavenging removes things which anyway won't be placed.
            //For each placed item it's cost should be calculated
            if (blueprint.roofMap == null)
            {
                Debug.Log(Debug.BlueprintTransfer, "Trying to process blueprint with empty roof map");
            }
            if (map == null)
            {
                Debug.Log(Debug.BlueprintTransfer, "Trying to process blueprint but map is still null");
            }

            try {
                int totalItems   = 0;
                int removedItems = 0;
                for (int x = 0; x < blueprint.width; x++)
                {
                    for (int z = 0; z < blueprint.height; z++)
                    {
                        Debug.Extra(Debug.BlueprintTransfer, "Starting cell {0} {1}...", x, z);
                        if (blueprint.itemsMap[x, z] == null)
                        {
                            blueprint.itemsMap[x, z] = new List <ItemTile>();
                        }                                                                                         //to make thngs easier add empty list to every cell

                        IntVec3 mapLocation = new IntVec3(x + mapOriginX, 0, z + mapOriginZ);
                        if (!mapLocation.InBounds(map))
                        {
                            continue;
                        }

                        List <ItemTile> items      = blueprint.itemsMap[x, z];
                        TerrainTile     terrain    = blueprint.terrainMap[x, z];
                        TerrainDef      terrainDef = null;

                        if (terrain != null)
                        {
                            terrainDef = DefDatabase <TerrainDef> .GetNamed(terrain.defName, false);

                            if (terrainDef == null)
                            {
                                blueprint.terrainMap[x, z] = null; //no terrain def means terrain can't be generated.
                                terrain = null;
                            }
                        }

                        TerrainDef existingTerrain = map.terrainGrid?.TerrainAt(mapLocation);
                        if (existingTerrain != null && terrainDef != null &&
                            existingTerrain.affordances != null &&
                            terrainDef.terrainAffordanceNeeded != null && !existingTerrain.affordances.Contains(terrainDef.terrainAffordanceNeeded))
                        {
                            terrainDef = null;
                            blueprint.terrainMap[x, z] = null;  //erase terrain if underlying terrain can't support it.
                            blueprint.roofMap[x, z]    = false; //removing roof as well just in case
                        }

                        Debug.Extra(Debug.BlueprintTransfer, "Preprocessed cell {0} {1}, moving to items...", x, z);
                        List <ItemTile> itemsToRemove = new List <ItemTile>();
                        foreach (ItemTile item in items)
                        {
                            totalItems++;

                            ThingDef thingDef = DefDatabase <ThingDef> .GetNamed(item.defName, false);

                            if (thingDef == null)
                            {
                                itemsToRemove.Add(item);
                                continue;
                            }

                            Debug.Extra(Debug.BlueprintTransfer, "Making thorough check for thing {0}", item.defName);
                            if (!options.overwritesEverything && thingDef.terrainAffordanceNeeded != null)
                            {
                                if (thingDef.EverTransmitsPower && options.shouldKeepDefencesAndPower)
                                {
                                    continue;                                                                    //ignore affordances for power transmitters if we need to keep defence systems
                                }
                                if (terrainDef != null && terrainDef.terrainAffordanceNeeded != null && existingTerrain.affordances.Contains(terrainDef.terrainAffordanceNeeded))
                                {
                                    if (!terrainDef.affordances.Contains(thingDef.terrainAffordanceNeeded))   //if new terrain can be placed over existing terrain, checking if an item can be placed over a new terrain
                                    {
                                        itemsToRemove.Add(item);
                                        blueprint.roofMap[x, z] = false;
                                    }
                                }
                                else
                                {
                                    if (!(existingTerrain.affordances?.Contains(thingDef.terrainAffordanceNeeded) ?? true))  //otherwise checking if the item can be placed over the existing terrain.
                                    {
                                        itemsToRemove.Add(item);
                                        blueprint.roofMap[x, z] = false;
                                    }
                                }
                            }
                        }

                        foreach (ItemTile item in itemsToRemove)
                        {
                            if (item.isWall || item.isDoor)
                            {
                                blueprint.RemoveWall(item.location.x, item.location.z);
                            }

                            items.Remove(item);
                            removedItems++;
                        }
                    }
                }


                Debug.Extra(Debug.BlueprintTransfer, "Finished check, recalculating stats");
                blueprint.UpdateBlueprintStats(true);
                Debug.Log(Debug.BlueprintTransfer, "Blueprint transfer utility did remove {0}/{1} incompatible items. New cost: {2}", removedItems, totalItems, blueprint.totalCost);
            } catch (Exception e) {
                Debug.Error(Debug.BlueprintTransfer, "Exception while trying to cleanup blueprint details. This should not normally happen, so please report this case: {0}", e.ToString());
            }
        }
예제 #6
0
        public override void Resolve(ResolveParams rp)
        {
            ScatterOptions options = rp.GetCustom <ScatterOptions>(Constants.ScatterOptions);

            if (options == null)
            {
                return;
            }

            //Debug.Message("Loading blueprint of size {0} - {1} to deploy at {2}, {3}", options.minRadius, options.maxRadius, rp.rect.minX, rp.rect.minZ);

            Blueprint bp  = null;
            Map       map = BaseGen.globalSettings.map;

            //probably should split scattering options into several distinct objects
            string filename = options.blueprintFileName;

            if (string.IsNullOrEmpty(filename))
            {
                bp = BlueprintFinder.FindRandomBlueprintWithParameters(out filename, options.minimumAreaRequired, options.minimumDensityRequired, 15, removeNonQualified: true);
                if (string.IsNullOrEmpty(filename))
                {
                    //still null = no suitable blueprints, fail.
                    return;
                }
            }

            if (!options.shouldLoadPartOnly) //should not cut => load whole
            {
                if (bp == null)              //if not loaded yet
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename);
                }
            }
            else
            {
                int radius = Rand.Range(options.minRadius, options.maxRadius);
                if (bp == null)
                {
                    bp = BlueprintLoader.LoadWholeBlueprintAtPath(filename).RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
                else
                {
                    bp = bp.RandomPartCenteredAtRoom(new IntVec3(radius, 0, radius));
                }
            }

            if (bp == null)
            {
                Debug.Warning(Debug.Scatter, "Blueprint is still null after attempting to load any qualifying, returning");
                return;
            }
            bp.CutIfExceedsBounds(map.Size);

            // Here we have our blueprint loaded and ready to action. Doing stuff:
            BlueprintPreprocessor.ProcessBlueprint(bp, options); //Preprocess: remove missing and unnecessary items according to options
            bp.FindRooms();                                      //Traverse blueprint and construct rooms map
            options.roomMap = bp.wallMap;

            //Debug.PrintIntMap(bp.wallMap, delta: 1);

            BlueprintTransferUtility btu = new BlueprintTransferUtility(bp, map, rp); //prepare blueprint transferrer

            btu.RemoveIncompatibleItems();                                            //remove incompatible items
            bp.UpdateBlueprintStats(true);                                            //Update total cost, items count, etc

            DeteriorationProcessor.Process(bp, options);                              //create deterioration maps and do deterioration

            ScavengingProcessor sp = new ScavengingProcessor();

            sp.RaidAndScavenge(bp, options); //scavenge remaining items according to scavenge options

            btu.Transfer();                  //transfer blueprint

            List <AbstractDefenderForcesGenerator> generators = rp.GetCustom <List <AbstractDefenderForcesGenerator> >(Constants.ForcesGenerators);

            if (generators != null)
            {
                foreach (AbstractDefenderForcesGenerator generator in generators)
                {
                    generator.GenerateForces(map, rp);
                }
            }

            if (options.shouldAddFilth)
            {
                btu.AddFilthAndRubble(); //add filth and rubble
                                         //rp.GetCustom<CoverageMap>(Constants.CoverageMap).DebugPrint();
            }
        }
        public void RemoveIncompatibleItems()
        {
            //Each item should be checked if it can be placed or not. This should help preventing situations when simulated scavenging removes things which anyway won't be placed.
            //For each placed item it's cost should be calculated
            int totalItems   = 0;
            int removedItems = 0;

            for (int x = 0; x < blueprint.width; x++)
            {
                for (int z = 0; z < blueprint.height; z++)
                {
                    if (blueprint.itemsMap[x, z] == null)
                    {
                        blueprint.itemsMap[x, z] = new List <ItemTile>();
                    }                                                                                         //to make thngs easier add empty list to every cell

                    IntVec3 mapLocation = new IntVec3(x + mapOriginX, 0, z + mapOriginZ);
                    if (!mapLocation.InBounds(map))
                    {
                        continue;
                    }

                    List <ItemTile> items      = blueprint.itemsMap[x, z];
                    TerrainTile     terrain    = blueprint.terrainMap[x, z];
                    TerrainDef      terrainDef = null;

                    if (terrain != null)
                    {
                        terrainDef = DefDatabase <TerrainDef> .GetNamed(terrain.defName, false);

                        if (terrainDef == null)
                        {
                            blueprint.terrainMap[x, z] = null; //no terrain def means terrain can't be generated.
                            terrain = null;
                        }
                    }

                    TerrainDef existingTerrain = map.terrainGrid.TerrainAt(mapLocation);
                    if (terrainDef != null && terrainDef.terrainAffordanceNeeded != null && !existingTerrain.affordances.Contains(terrainDef.terrainAffordanceNeeded))
                    {
                        terrainDef = null;
                        blueprint.terrainMap[x, z] = null;  //erase terrain if underlying terrain can't support it.
                        blueprint.roofMap[x, z]    = false; //removing roof as well just in case
                    }

                    List <ItemTile> itemsToRemove = new List <ItemTile>();
                    foreach (ItemTile item in items)
                    {
                        totalItems++;

                        ThingDef thingDef = DefDatabase <ThingDef> .GetNamed(item.defName, false);

                        if (thingDef == null)
                        {
                            itemsToRemove.Add(item);
                            continue;
                        }

                        if (!options.overwritesEverything && thingDef.terrainAffordanceNeeded != null)
                        {
                            if (thingDef.EverTransmitsPower && options.shouldKeepDefencesAndPower)
                            {
                                continue;                                                                    //ignore affordances for power transmitters if we need to keep defence systems
                            }
                            if (terrainDef != null && terrainDef.terrainAffordanceNeeded != null && existingTerrain.affordances.Contains(terrainDef.terrainAffordanceNeeded))
                            {
                                if (!terrainDef.affordances.Contains(thingDef.terrainAffordanceNeeded))   //if new terrain can be placed over existing terrain, checking if an item can be placed over a new terrain
                                {
                                    itemsToRemove.Add(item);
                                    blueprint.roofMap[x, z] = false;
                                }
                            }
                            else
                            {
                                if (!existingTerrain.affordances.Contains(thingDef.terrainAffordanceNeeded))  //otherwise checking if the item can be placed over the existing terrain.
                                {
                                    itemsToRemove.Add(item);
                                    blueprint.roofMap[x, z] = false;
                                }
                            }
                        }
                    }

                    foreach (ItemTile item in itemsToRemove)
                    {
                        if (item.isWall || item.isDoor)
                        {
                            blueprint.RemoveWall(item.location.x, item.location.z);
                        }

                        items.Remove(item);
                        removedItems++;
                    }
                }
            }

            blueprint.UpdateBlueprintStats(true);
            //Debug.Message("Blueprint transfer utility did remove {0}/{1} incompatible items. New cost: {2}", removedItems, totalItems, blueprint.totalCost);
        }