diff --git a/Upgrade.lua b/Upgrade.lua index 24cd3c5..35b767a 100644 --- a/Upgrade.lua +++ b/Upgrade.lua @@ -418,11 +418,12 @@ function upgrade.attempt(universe) game.print("Rampant - Version 1.1.4") end - if global.version < 118 then - global.version = 118 + if global.version < 120 then + global.version = 120 if (universe.maps) then for _,map in pairs(universe.maps) do + map.pendingUpgrades = {} for _,base in pairs(map.bases) do base.mutations = 0 end diff --git a/changelog.txt b/changelog.txt index d85c986..0805982 100644 --- a/changelog.txt +++ b/changelog.txt @@ -8,6 +8,7 @@ Date: 23. 11. 2021 - Limited base faction mutations to 2 (configurable) with a small probability to be granted additional mutations or be locked into those factions forever - Readded regional bases going dormant in regards to upgrading structures to allow for a buildup of base points to upgrade larger structures like hives. DOES NOT EFFECT ATTACK WAVES. - Number of groups that can be active in aggressive AI state now scales with the number of active nests. Rougly for every 30 pollution covered nests you will get an additional attack group. + - Optimized regional base upgrades so that the work is spread over many ticks reducing lag spikes Tweaks: - Doubled the processing rate of regional faction bases with new enemies - Added a small chance (0.5%) that Hives can spawn outside resource patches (Thank you Dimm2101) diff --git a/control.lua b/control.lua index 9c2e459..d1aaebb 100644 --- a/control.lua +++ b/control.lua @@ -44,8 +44,10 @@ local ENERGY_THIEF_LOOKUP = constants.ENERGY_THIEF_LOOKUP -- imported functions +local queueGeneratedChunk = mapUtils.queueGeneratedChunk local isRampantSetting = stringUtils.isRampantSetting +local processPendingUpgrades = chunkUtils.processPendingUpgrades local canMigrate = aiPredicates.canMigrate local convertTypeToDrainCrystal = unitUtils.convertTypeToDrainCrystal @@ -102,7 +104,6 @@ local retreatUnits = squadDefense.retreatUnits local accountPlayerEntity = chunkUtils.accountPlayerEntity local unregisterEnemyBaseStructure = chunkUtils.unregisterEnemyBaseStructure -local registerEnemyBaseStructure = chunkUtils.registerEnemyBaseStructure local makeImmortalEntity = chunkUtils.makeImmortalEntity local registerResource = chunkUtils.registerResource @@ -159,8 +160,7 @@ local function onChunkGenerated(event) -- queue generated chunk for delayed processing, queuing is required because -- some mods (RSO) mess with chunk as they are generated, which messes up the -- scoring. - event.tick = (event.tick or game.tick) + 120 - universe.maps[event.surface.index].pendingChunks[event] = true + queueGeneratedChunk(universe, event) end local function onModSettingsChange(event) @@ -296,6 +296,7 @@ local function prepMap(surface) map.outgoingScanWave = true map.outgoingStaticScanWave = true + map.pendingUpgrades = {} map.pendingChunks = {} map.chunkToBase = {} map.chunkToNests = {} @@ -325,6 +326,7 @@ local function prepMap(surface) map.nextChunkSort = 0 map.nextChunkSortTick = 0 + map.pendingUpgradeIterator = nil map.squadIterator = nil map.regroupIterator = nil map.deployVengenceIterator = nil @@ -661,14 +663,12 @@ local function onEnemyBaseBuild(event) chunk, event.tick) end - entity = upgradeEntity(entity, - base.alignment, - map, - nil, - true) - end - if entity and entity.valid then - event.entity = registerEnemyBaseStructure(map, entity, base) + upgradeEntity(entity, + base.alignment, + map, + nil, + true, + true) end else local x,y = positionToChunkXY(entity.position) @@ -832,14 +832,12 @@ local function onEntitySpawned(event) event.tick) end - entity = upgradeEntity(entity, - base.alignment, - map, - disPos) - - if entity and entity.valid then - event.entity = registerEnemyBaseStructure(map, entity, base) - end + upgradeEntity(entity, + base.alignment, + map, + disPos, + true, + true) else local x,y = positionToChunkXY(entity.position) onChunkGenerated({ @@ -1081,6 +1079,7 @@ script.on_event(defines.events.on_tick, end processActiveNests(map, tick) + processPendingUpgrades(map, tick) cleanSquads(map) -- game.print({"", "--dispatch4 ", profiler, ", ", pick, ", ", game.tick, " ", mRandom()}) diff --git a/libs/BaseUtils.lua b/libs/BaseUtils.lua index 8bf3b74..29cceeb 100644 --- a/libs/BaseUtils.lua +++ b/libs/BaseUtils.lua @@ -257,11 +257,9 @@ function baseUtils.recycleBases(map, tick) end end -function baseUtils.upgradeEntity(entity, baseAlignment, map, disPos, evolve) - local surface = map.surface +function baseUtils.upgradeEntity(entity, baseAlignment, map, disPos, evolve, register) local position = entity.position local currentEvo = entity.prototype.build_base_evolution_requirement or 0 - local universe = map.universe if not baseAlignment[1] then entity.destroy() @@ -279,18 +277,16 @@ function baseUtils.upgradeEntity(entity, baseAlignment, map, disPos, evolve) evolve) if spawnerName and (spawnerName ~= entity.name) then - entity.destroy() - local name = universe.buildingSpaceLookup[spawnerName] or spawnerName - local query = universe.upgradeEntityQuery - query.name = name - query.position = disPos or position - query.name = spawnerName - if remote.interfaces["kr-creep"] then - remote.call("kr-creep", "spawn_creep_at_position", surface, query.position) - end - return surface.create_entity(query) + local entityData = { + ["name"] = spawnerName, + ["position"] = disPos, + ["register"] = register + } + map.pendingUpgrades[entity] = entityData + return spawnerName end - return entity + + return nil end local function pickMutationFromDamageType(map, damageType, roll, base) diff --git a/libs/ChunkUtils.lua b/libs/ChunkUtils.lua index e64bd85..24da111 100644 --- a/libs/ChunkUtils.lua +++ b/libs/ChunkUtils.lua @@ -78,7 +78,9 @@ local setChunkBase = chunkPropertyUtils.setChunkBase local setPassable = chunkPropertyUtils.setPassable local setPathRating = chunkPropertyUtils.setPathRating +local getChunkByPosition = mapUtils.getChunkByPosition local getChunkByXY = mapUtils.getChunkByXY +local queueGeneratedChunk = mapUtils.queueGeneratedChunk local mMin = math.min local mMax = math.max @@ -87,7 +89,7 @@ local mFloor = math.floor -- module code local function getEntityOverlapChunks(map, entity) - local boundingBox = entity.prototype.collision_box or entity.prototype.selection_box; + local boundingBox = entity.prototype.collision_box or entity.prototype.selection_box local overlapArray = map.universe.chunkOverlapArray overlapArray[1] = -1 --LeftTop @@ -246,7 +248,7 @@ function chunkUtils.initialScan(chunk, map, tick) if not buildingHiveTypeLookup[enemyBuilding.name] then local newEntity = upgradeEntity(enemyBuilding, alignment, map, nil, true) if newEntity then - local hiveType = buildingHiveTypeLookup[newEntity.name] + local hiveType = buildingHiveTypeLookup[newEntity] counts[hiveType] = counts[hiveType] + 1 end else @@ -415,6 +417,67 @@ function chunkUtils.colorXY(x, y, surface, color) }) end +function chunkUtils.processPendingUpgrades(map, tick) + local pendingUpgrades = map.pendingUpgrades + local entity = map.pendingUpgradeIterator + local entityData + if not entity then + entity, entityData = next(pendingUpgrades, nil) + else + entityData = pendingUpgrades[entity] + end + if entity then + if entity.valid then + -- print("upgrading", entity.unit_number, tick, table_size(pendingUpgrades)) + -- constants.gpsDebug(entity.position.x, entity.position.y, entity.unit_number) + map.pendingUpgradeIterator = next(pendingUpgrades, entity) + pendingUpgrades[entity] = nil + local universe = map.universe + local query = universe.upgradeEntityQuery + query.position = entityData.position or entity.position + query.name = entityData.name + local surface = entity.surface + entity.destroy() + if remote.interfaces["kr-creep"] then + remote.call("kr-creep", "spawn_creep_at_position", surface, query.position) + end + local createdEntity = surface.create_entity(query) + if createdEntity and createdEntity.valid and entityData.register then + local chunk = getChunkByPosition(map, createdEntity.position) + if (chunk ~= -1) then + local base = findNearbyBase(map, chunk) + if not base then + base = createBase(map, + chunk, + tick) + end + if base then + -- print("registering", tick) + -- constants.gpsDebug(entity.position.x, entity.position.y, "registered") + chunkUtils.registerEnemyBaseStructure(map, createdEntity, base) + end + else + queueGeneratedChunk( + universe, + { + surface = createdEntity.surface, + area = { + left_top = { + x = createdEntity.position.x, + y = createdEntity.position.y + } + } + } + ) + end + end + else + -- print("skipping invalid", tick) + map.pendingUpgradeIterator = next(pendingUpgrades, entity) + pendingUpgrades[entity] = nil + end + end +end function chunkUtils.registerEnemyBaseStructure(map, entity, base) local entityType = entity.type diff --git a/libs/Constants.lua b/libs/Constants.lua index 69838f1..7ba8120 100644 --- a/libs/Constants.lua +++ b/libs/Constants.lua @@ -1624,7 +1624,7 @@ constants.FACTION_MUTATION_MAPPING["trap"] = {"turret"} constants.FACTION_MUTATION_MAPPING["utility"] = {"hive", "biter-spawner", "spitter-spawner"} function constants.gpsDebug(x, y, msg) - game.print("[gps=".. x .. "," .. y .. "]", msg) + game.print("[gps=".. x .. "," .. y .. "]" .. msg) end constantsG = constants diff --git a/libs/MapUtils.lua b/libs/MapUtils.lua index f8fe598..d4073fc 100644 --- a/libs/MapUtils.lua +++ b/libs/MapUtils.lua @@ -51,6 +51,11 @@ function mapUtils.positionToChunkXY(position) return chunkX, chunkY end +function mapUtils.queueGeneratedChunk(universe, event) + event.tick = (event.tick or game.tick) + 120 + universe.maps[event.surface.index].pendingChunks[event] = true +end + --[[ 1 2 3 \|/