From e814a9c6488f2138928a86067b86bcae20621ac8 Mon Sep 17 00:00:00 2001 From: Aaron Veden Date: Sun, 5 Dec 2021 10:19:04 -0800 Subject: [PATCH] potential desync fix and warding pheromone on attack path --- Upgrade.lua | 271 ++++++++++++++++++++---------------- changelog.txt | 4 +- control.lua | 148 ++------------------ info.json | 2 +- libs/AIAttackWave.lua | 6 +- libs/AIPlanning.lua | 2 +- libs/BaseUtils.lua | 7 +- libs/ChunkProcessor.lua | 112 ++++++++------- libs/ChunkPropertyUtils.lua | 262 +++++++++++++++++----------------- libs/ChunkUtils.lua | 13 +- libs/MapProcessor.lua | 79 ++++++----- libs/MapUtils.lua | 10 +- libs/MovementUtils.lua | 14 +- libs/PheromoneUtils.lua | 17 +-- libs/SquadAttack.lua | 46 +++--- 15 files changed, 469 insertions(+), 524 deletions(-) diff --git a/Upgrade.lua b/Upgrade.lua index e10a811..862c1ea 100644 --- a/Upgrade.lua +++ b/Upgrade.lua @@ -3,11 +3,8 @@ local upgrade = {} -- imports local constants = require("libs/Constants") -local mathUtils = require("libs/MathUtils") -local chunkPropertyUtils = require("libs/ChunkPropertyUtils") -local mapUtils = require("libs/MapUtils") -local baseUtils = require("libs/BaseUtils") local chunkProcessor = require("libs/ChunkProcessor") +local mapUtils = require("libs/MapUtils") -- constants @@ -31,37 +28,11 @@ local TRIPLE_CHUNK_SIZE = constants.TRIPLE_CHUNK_SIZE -- imported functions +local queueGeneratedChunk = mapUtils.queueGeneratedChunk local processPendingChunks = chunkProcessor.processPendingChunks -local queueGeneratedChunk = mapUtils.queueGeneratedChunk - -local getEnemyStructureCount = chunkPropertyUtils.getEnemyStructureCount -local getChunkBase = chunkPropertyUtils.getChunkBase -local removeChunkBase = chunkPropertyUtils.removeChunkBase - -local findNearbyBase = baseUtils.findNearbyBase -local createBase = baseUtils.createBase -local setChunkBase = chunkPropertyUtils.setChunkBase - -local euclideanDistancePoints = mathUtils.euclideanDistancePoints - -local mAbs = math.abs -local tSort = table.sort - -- module code -local function sorter(a, b) - if (a.dOrigin == b.dOrigin) then - if (a.x == b.x) then - return (mAbs(a.y) < mAbs(b.y)) - else - return (mAbs(a.x) < mAbs(b.x)) - end - end - - return (a.dOrigin < b.dOrigin) -end - local function addCommandSet(queriesAndCommands) -- preallocating memory to be used in code, making it fast by reducing garbage generated. queriesAndCommands.neighbors = { @@ -445,105 +416,165 @@ function upgrade.attempt(universe) universe.maxPoints = 0 end - if global.version < 122 then - global.version = 122 + if global.version < 200 then + global.version = 200 addCommandSet(universe) + universe.eventId = 0 universe.randomGenerator = nil - universe.random = game.create_random_generator(settings.startup["rampant--enemySeed"].value+game.map_gen_settings.seed) - if (universe.maps) then - local tick = game.tick - for _,map in pairs(universe.maps) do - map.random = universe.random - map.pendingUpgrades = {} - map.sentAggressiveGroups = 0 - map.maxAggressiveGroups = 1 - local basesToRemove = {} - for i=1,#map.processQueue do - local chunk = map.processQueue[i] - chunk.dOrigin = euclideanDistancePoints(chunk.x, chunk.y, 0, 0) - if universe.NEW_ENEMIES then - local base = getChunkBase(map, chunk) - if base then - if not map.bases[base.id] then - map.bases[base.id] = base - end - if not base.damagedBy then - base.damagedBy = {} - end - if not base.deathEvents then - base.deathEvents = 0 - end - if not base.chunkCount then - base.chunkCount = 0 - end - if not base.mutations then - base.mutations = 0 - end - if not base.alignment[1] then - basesToRemove[base.id] = true - end - end - end - end - tSort(map.processQueue, sorter) - map.pendingChunks = {} - map.chunkToNests = {} - map.chunkToNestIds = {} - map.chunkToHives = {} - map.chunkToHiveIds = {} - map.chunkToTraps = {} - map.chunkToTrapIds = {} - map.chunkToTurrets = {} - map.chunkToTurretIds = {} - map.chunkToUtilities = {} - map.chunkToUtilityIds = {} - for chunkXY in map.surface.get_chunks() do - if map.surface.is_chunk_generated(chunkXY) then - local x = chunkXY.x * 32 - local y = chunkXY.y * 32 - queueGeneratedChunk(universe, - { - surface = map.surface, - area = { - left_top = { - x = x, - y = y - } - } - } - ) - end - end - processPendingChunks(map, tick, true) - if universe.NEW_ENEMIES then - for baseId in pairs(basesToRemove) do - map.bases[baseId] = nil - end - map.chunkToBases = {} - for i=1,#map.processQueue do - local chunk = map.processQueue[i] - if (getEnemyStructureCount(map, chunk) > 0) then - local newBase = findNearbyBase(map, chunk) - if not newBase then - createBase(map, chunk, tick) - end - setChunkBase(map, chunk, newBase) - end - end - end - for _,squad in pairs(map.groupNumberToSquad) do - squad.commandTick = tick - end - end + universe.random = game.create_random_generator(settings.startup["rampant--enemySeed"].value+game.default_map_gen_settings.seed) + game.forces.enemy.kill_all_units() + universe.maps = {} + for _,surface in pairs(game.surfaces) do + upgrade.prepMap(universe, surface) end + universe.activeMap = nil + universe.mapIterator = nil - game.print("Rampant - Version 1.2.0") + game.print("Rampant - Version 2.0.0") end return (starting ~= global.version) and global.version end +function upgrade.prepMap(universe, surface) + game.print("Rampant - Indexing surface:" .. tostring(surface.index) .. ", please wait.") + + local surfaceIndex = surface.index + + if not universe.maps then + universe.maps = {} + end + + local map = {} + universe.maps[surfaceIndex] = map + + map.eventId = 1 + map.chunkId = 1 + map.maxAggressiveGroups = 1 + map.sentAggressiveGroups = 0 + map.processedChunks = 0 + map.processQueue = {} + map.processIndex = 1 + map.cleanupIndex = 1 + map.scanPlayerIndex = 1 + map.scanResourceIndex = 1 + map.scanEnemyIndex = 1 + map.processStaticIndex = 1 + map.outgoingScanWave = true + map.outgoingStaticScanWave = true + + map.pendingUpgrades = {} + map.pendingChunks = {} + map.chunkToBase = {} + map.chunkToNests = {} + map.chunkToTurrets = {} + map.chunkToTraps = {} + map.chunkToUtilities = {} + map.chunkToHives = {} + map.chunkToNestIds = {} + map.chunkToHiveIds = {} + map.chunkToTrapIds = {} + map.chunkToTurretIds = {} + map.chunkToUtilityIds = {} + + map.chunkToPlayerBase = {} + map.chunkToResource = {} + map.chunkToPlayerCount = {} + map.playerToChunk = {} + map.pendingChunks = {} + + map.chunkToPassScan = {} + map.chunkToSquad = {} + + map.chunkToRetreats = {} + map.chunkToRallys = {} + map.chunkIdToChunk = {} + + map.chunkToPassable = {} + map.chunkToPathRating = {} + map.chunkToDeathGenerator = {} + map.chunkToDrained = {} + map.chunkToVictory = {} + map.chunkToActiveNest = {} + map.chunkToActiveRaidNest = {} + + map.chunkToPassScanIterator = nil + map.pendingUpgradeIterator = nil + map.squadIterator = nil + map.regroupIterator = nil + map.deployVengenceIterator = nil + map.recycleBaseIterator = nil + map.processActiveSpawnerIterator = nil + map.processActiveRaidSpawnerIterator = nil + map.processMigrationIterator = nil + map.processNestIterator = nil + map.victoryScentIterator = nil + + map.chunkScanCounts = {} + + map.chunkRemovals = {} + map.processActiveNest = {} + map.tickActiveNest = {} + + map.emptySquadsOnChunk = {} + + map.surface = surface + map.universe = universe + + map.vengenceQueue = {} + map.bases = {} + map.baseIndex = 1 + map.baseIncrement = 0 + map.points = 0 + map.state = constants.AI_STATE_AGGRESSIVE + map.baseId = 0 + map.squads = nil + map.pendingAttack = nil + map.building = nil + + map.evolutionLevel = game.forces.enemy.evolution_factor + map.canAttackTick = 0 + map.drainPylons = {} + map.groupNumberToSquad = {} + map.activeRaidNests = 0 + map.activeNests = 0 + map.destroyPlayerBuildings = 0 + map.lostEnemyUnits = 0 + map.lostEnemyBuilding = 0 + map.rocketLaunched = 0 + map.builtEnemyBuilding = 0 + map.ionCannonBlasts = 0 + map.artilleryBlasts = 0 + + map.temperament = 0.5 + map.temperamentScore = 0 + map.stateTick = 0 + + map.random = universe.random + + -- queue all current chunks that wont be generated during play + local tick = game.tick + for chunk in surface.get_chunks() do + if surface.is_chunk_generated(chunk) then + queueGeneratedChunk(universe, + { + surface = surface, + tick = tick, + area = { + left_top = { + x = chunk.x * 32, + y = chunk.y * 32 + } + } + } + ) + end + end + + processPendingChunks(map, tick, true) +end + function upgrade.compareTable(entities, option, new) local changed = false if (entities[option] ~= new) then diff --git a/changelog.txt b/changelog.txt index 0ffce92..0296def 100644 --- a/changelog.txt +++ b/changelog.txt @@ -1,5 +1,5 @@ --------------------------------------------------------------------------------------------------- -Version: 1.2.0 +Version: 2.0.0 Date: 23. 11. 2021 Contributions: - Astorin has provide an updated RU locale up through Rampant 1.1.1 @@ -42,6 +42,8 @@ Date: 23. 11. 2021 - Fixed regional bases would not be corrected distributed or cleaned up on spawners - Fixed chunks that became impassable would not return an impassable chunk flag when pass scanned - Fixed kastorio creep code be spawned when the building failed to upgrade + - Potential desync fix in relation to reference comparison and deserialization + - Fixed squad attack move would not properly place warding pheromone on taken path Framework: - Fixed Rampant in-memory map visualization tool for debugging - Added debug mod settings for showing enemy structures being upgraded in place diff --git a/control.lua b/control.lua index ecc066c..3e6b265 100644 --- a/control.lua +++ b/control.lua @@ -41,6 +41,8 @@ local ENERGY_THIEF_LOOKUP = constants.ENERGY_THIEF_LOOKUP -- imported functions +local prepMap = upgrade.prepMap + local registerEnemyBaseStructure = chunkUtils.registerEnemyBaseStructure local queueGeneratedChunk = mapUtils.queueGeneratedChunk @@ -260,135 +262,6 @@ local function onModSettingsChange(event) return true end -local function prepMap(surface) - surface.print("Rampant - Indexing surface:" .. tostring(surface.index) .. ", please wait.") - - local surfaceIndex = surface.index - - if not universe.maps then - universe.maps = {} - end - - local map = universe.maps[surfaceIndex] - if not map then - map = {} - universe.maps[surfaceIndex] = map - end - - map.maxAggressiveGroups = 1 - map.sentAggressiveGroups = 0 - map.processedChunks = 0 - map.processQueue = {} - map.processIndex = 1 - map.cleanupIndex = 1 - map.scanPlayerIndex = 1 - map.scanResourceIndex = 1 - map.scanEnemyIndex = 1 - map.processStaticIndex = 1 - map.outgoingScanWave = true - map.outgoingStaticScanWave = true - - map.pendingUpgrades = {} - map.pendingChunks = {} - map.chunkToBase = {} - map.chunkToNests = {} - map.chunkToTurrets = {} - map.chunkToTraps = {} - map.chunkToUtilities = {} - map.chunkToHives = {} - map.chunkToNestIds = {} - map.chunkToHiveIds = {} - map.chunkToTrapIds = {} - map.chunkToTurretIds = {} - map.chunkToUtilityIds = {} - - map.chunkToPlayerBase = {} - map.chunkToResource = {} - map.chunkToPlayerCount = {} - map.playerToChunk = {} - map.pendingChunks = {} - - map.chunkToPassScan = {} - map.chunkToSquad = {} - - map.chunkToRetreats = {} - map.chunkToRallys = {} - - map.chunkToPassable = {} - map.chunkToPathRating = {} - map.chunkToDeathGenerator = {} - map.chunkToDrained = {} - map.chunkToVictory = {} - map.chunkToActiveNest = {} - map.chunkToActiveRaidNest = {} - - map.pendingUpgradeIterator = nil - map.squadIterator = nil - map.regroupIterator = nil - map.deployVengenceIterator = nil - map.recycleBaseIterator = nil - map.processActiveSpawnerIterator = nil - map.processActiveRaidSpawnerIterator = nil - map.processMigrationIterator = nil - map.processNestIterator = nil - map.victoryScentIterator = nil - - map.chunkScanCounts = {} - - map.chunkRemovals = {} - map.processActiveNest = {} - map.tickActiveNest = {} - - map.emptySquadsOnChunk = {} - - map.surface = surface - map.universe = universe - - map.vengenceQueue = {} - map.bases = {} - map.baseIndex = 1 - map.baseIncrement = 0 - map.points = 0 - map.state = constants.AI_STATE_AGGRESSIVE - map.baseId = 0 - map.squads = nil - map.pendingAttack = nil - map.building = nil - - map.evolutionLevel = game.forces.enemy.evolution_factor - map.canAttackTick = 0 - map.drainPylons = {} - map.groupNumberToSquad = {} - map.activeRaidNests = 0 - map.activeNests = 0 - map.destroyPlayerBuildings = 0 - map.lostEnemyUnits = 0 - map.lostEnemyBuilding = 0 - map.rocketLaunched = 0 - map.builtEnemyBuilding = 0 - map.ionCannonBlasts = 0 - map.artilleryBlasts = 0 - - map.temperament = 0.5 - map.temperamentScore = 0 - map.stateTick = 0 - - map.random = universe.random - - -- queue all current chunks that wont be generated during play - local tick = game.tick - for chunk in surface.get_chunks() do - if surface.is_chunk_generated(chunk) then - onChunkGenerated({ surface = surface, - tick = tick, - area = { left_top = { x = chunk.x * 32, - y = chunk.y * 32}}}) - end - end - - processPendingChunks(map, tick, true) -end - local function onConfigChanged() local version = upgrade.attempt(universe) if version then @@ -426,7 +299,7 @@ local function onConfigChanged() universe.maps = {} end if not universe.maps[surface.index] then - prepMap(surface) + prepMap(universe, surface) end end end @@ -520,13 +393,13 @@ local function onDeath(event) if pair then local target = pair[1] local pole = pair[2] - if target == entity then + if target.unit_number == entityUnitNumber then map.drainPylons[entityUnitNumber] = nil if pole.valid then map.drainPylons[pole.unit_number] = nil pole.die() end - elseif (pole == entity) then + elseif (pole.unit_number == entityUnitNumber) then map.drainPylons[entityUnitNumber] = nil if target.valid then map.drainPylons[target.unit_number] = nil @@ -576,11 +449,12 @@ local function onDeath(event) local creditNatives = false if (event.force ~= nil) and (event.force.name == "enemy") then creditNatives = true + local drained if (chunk ~= -1) then victoryScent(map, chunk, entityType) + drained = (entityType == "electric-turret") and map.chunkToDrained[chunk.id] end - local drained = (entityType == "electric-turret") and map.chunkToDrained[chunk] if cause or (drained and (drained - tick) > 0) then if ((cause and ENERGY_THIEF_LOOKUP[cause.name]) or (not cause)) then local conversion = ENERGY_THIEF_CONVERSION_TABLE[entityType] @@ -698,7 +572,7 @@ local function onSurfaceTileChange(event) local chunk = getChunkByPosition(map, position) if (chunk ~= -1) then - map.chunkToPassScan[chunk] = true + map.chunkToPassScan[chunk.id] = true else local x,y = positionToChunkXY(position) local addMe = true @@ -727,7 +601,7 @@ local function onSurfaceTileChange(event) local chunk = getChunkByPosition(map, position) if (chunk ~= -1) then - map.chunkToPassScan[chunk] = true + map.chunkToPassScan[chunk.id] = true else local x,y = positionToChunkXY(position) local addMe = true @@ -804,7 +678,7 @@ local function onTriggerEntityCreated(event) local map = universe.maps[event.surface_index] local chunk = getChunkByPosition(map, entity.position) if (chunk ~= -1) then - map.chunkToDrained[chunk] = event.tick + 60 + map.chunkToDrained[chunk.id] = event.tick + 60 end end end @@ -1003,7 +877,7 @@ local function onForceMerged(event) end local function onSurfaceCreated(event) - prepMap(game.surfaces[event.surface_index]) + prepMap(universe, game.surfaces[event.surface_index]) end local function onSurfaceDeleted(event) diff --git a/info.json b/info.json index 81a820c..f09ee18 100644 --- a/info.json +++ b/info.json @@ -1,7 +1,7 @@ { "name" : "Rampant", "factorio_version" : "1.1", - "version" : "1.2.0", + "version" : "2.0.0", "title" : "Rampant", "author" : "Veden", "homepage" : "https://forums.factorio.com/viewtopic.php?f=94&t=31445", diff --git a/libs/AIAttackWave.lua b/libs/AIAttackWave.lua index 7b0c209..226cd52 100644 --- a/libs/AIAttackWave.lua +++ b/libs/AIAttackWave.lua @@ -175,12 +175,12 @@ function aiAttackWave.rallyUnits(chunk, map, tick) if (x ~= cX) and (y ~= cY) then local rallyChunk = getChunkByXY(map, x, y) if (rallyChunk ~= -1) and (getNestCount(map, rallyChunk) > 0) then - local count = vengenceQueue[rallyChunk] + local count = vengenceQueue[rallyChunk.id] if not count then count = 0 - vengenceQueue[rallyChunk] = count + vengenceQueue[rallyChunk.id] = count end - vengenceQueue[rallyChunk] = count + 1 + vengenceQueue[rallyChunk.id] = count + 1 end end end diff --git a/libs/AIPlanning.lua b/libs/AIPlanning.lua index e1d9c4a..4c9b723 100644 --- a/libs/AIPlanning.lua +++ b/libs/AIPlanning.lua @@ -407,7 +407,7 @@ function aiPlanning.temperamentPlanner(map) map.temperament = ((map.temperamentScore + 10000) * 0.00005) if universe.debugTemperament then - if game.tick % 240 == 0 then + if game.tick % 243 == 0 then game.print("Rampant Stats:") game.print("aN:" .. map.activeNests .. ", aRN:" .. map.activeRaidNests .. ", dPB:" .. map.destroyPlayerBuildings .. ", lEU:" .. map.lostEnemyUnits .. ", lEB:" .. map.lostEnemyBuilding .. ", rL:" .. map.rocketLaunched .. ", bEB:" .. map.builtEnemyBuilding .. diff --git a/libs/BaseUtils.lua b/libs/BaseUtils.lua index 9e29480..d7c86e2 100644 --- a/libs/BaseUtils.lua +++ b/libs/BaseUtils.lua @@ -284,9 +284,10 @@ function baseUtils.upgradeEntity(entity, base, map, disPos, evolve, register) ["name"] = spawnerName, ["position"] = disPos, ["register"] = register, - ["base"] = base + ["base"] = base, + ["entity"] = entity } - map.pendingUpgrades[entity] = entityData + map.pendingUpgrades[entity.unit_number] = entityData return spawnerName end return nil @@ -299,7 +300,7 @@ local function pickMutationFromDamageType(map, damageType, roll, base) local mutation if (damageFactions and (#damageFactions > 0)) then - mutation = damageFactions[math.random(#damageFactions)] + mutation = damageFactions[mRandom(#damageFactions)] if baseAlignment[2] then if (roll < 0.05) then baseAlignment[2] = nil diff --git a/libs/ChunkProcessor.lua b/libs/ChunkProcessor.lua index 5f16d2a..0ed4847 100644 --- a/libs/ChunkProcessor.lua +++ b/libs/ChunkProcessor.lua @@ -49,7 +49,7 @@ end local function removeProcessQueueChunk(processQueue, chunk) local insertionPoint = findInsertionPoint(processQueue, chunk) for i=insertionPoint,1,-1 do - if (processQueue[i] == chunk) then + if (processQueue[i].id == chunk.id) then tRemove(processQueue, i) end end @@ -64,17 +64,20 @@ function chunkProcessor.processPendingChunks(map, tick, flush) local topOffset = area[1] local bottomOffset = area[2] - local event = map.chunkProcessorIterator - if not event then - event = next(pendingChunks, nil) + local eventId = map.chunkProcessorIterator + local event + if not eventId then + eventId, event = next(pendingChunks, nil) + else + event = pendingChunks[eventId] end local endCount = 1 if flush then endCount = table_size(pendingChunks) - event = next(pendingChunks, nil) + eventId, event = next(pendingChunks, nil) end for _=1,endCount do - if not event then + if not eventId then map.chunkProcessorIterator = nil if (table_size(pendingChunks) == 0) then -- this is needed as the next command remembers the max length a table has been @@ -83,7 +86,7 @@ function chunkProcessor.processPendingChunks(map, tick, flush) break else if not flush and (event.tick > tick) then - map.chunkProcessorIterator = event + map.chunkProcessorIterator = eventId return end local topLeft = event.area.left_top @@ -100,48 +103,52 @@ function chunkProcessor.processPendingChunks(map, tick, flush) end if map[x][y] then - local chunk = initialScan(map[x][y], map, tick) + local oldChunk = map[x][y] + local chunk = initialScan(oldChunk, map, tick) if (chunk == -1) then - removeProcessQueueChunk(processQueue, map[x][y]) + removeProcessQueueChunk(processQueue, oldChunk) + map.chunkIdToChunk[oldChunk.id] = nil map[x][y] = nil end else - local chunk = createChunk(x, y) - map[x][y] = chunk - chunk = initialScan(chunk, map, tick) + local initialChunk = createChunk(map, x, y) + map[x][y] = initialChunk + map.chunkIdToChunk[initialChunk.id] = initialChunk + local chunk = initialScan(initialChunk, map, tick) if (chunk ~= -1) then - map[x][y] = chunk tInsert( processQueue, findInsertionPoint(processQueue, chunk), chunk ) else + map.chunkIdToChunk[initialChunk.id] = nil map[x][y] = nil end end - local newEvent = next(pendingChunks, event) - pendingChunks[event] = nil + local newEventId, newEvent = next(pendingChunks, eventId) + pendingChunks[eventId] = nil + eventId = newEventId event = newEvent end end - map.chunkProcessorIterator = event + map.chunkProcessorIterator = eventId end function chunkProcessor.processPendingUpgrades(map, tick) - local pendingUpgrades = map.pendingUpgrades - local entity = map.pendingUpgradeIterator + local entityId = map.pendingUpgradeIterator local entityData - if not entity then - entity, entityData = next(pendingUpgrades, nil) + if not entityId then + entityId, entityData = next(map.pendingUpgrades, nil) else - entityData = pendingUpgrades[entity] + entityData = map.pendingUpgrades[entityId] end - if entity then + if entityId then + local entity = entityData.entity if entity.valid then - map.pendingUpgradeIterator = next(pendingUpgrades, entity) - pendingUpgrades[entity] = nil + map.pendingUpgradeIterator = next(map.pendingUpgrades, entityId) + map.pendingUpgrades[entityId] = nil local universe = map.universe local query = universe.upgradeEntityQuery query.position = entityData.position or entity.position @@ -157,47 +164,46 @@ function chunkProcessor.processPendingUpgrades(map, tick) end end else - map.pendingUpgradeIterator = next(pendingUpgrades, entity) - pendingUpgrades[entity] = nil + map.pendingUpgradeIterator = next(map.pendingUpgrades, entityId) + map.pendingUpgrades[entityId] = nil end end end + function chunkProcessor.processScanChunks(map) local area = map.universe.area local topOffset = area[1] local bottomOffset = area[2] - local removals = map.chunkRemovals - - local chunkCount = 0 - - local chunkToPassScan = map.chunkToPassScan - - for preScanChunk in pairs(chunkToPassScan) do - local x = preScanChunk.x - local y = preScanChunk.y - - topOffset[1] = x - topOffset[2] = y - bottomOffset[1] = x + CHUNK_SIZE - bottomOffset[2] = y + CHUNK_SIZE - - if (chunkPassScan(preScanChunk, map) == -1) then - map[x][y] = nil - - chunkCount = chunkCount + 1 - removals[chunkCount] = preScanChunk - end - - chunkToPassScan[preScanChunk] = nil + local chunkId = map.chunkToPassScanIterator + local chunk + if not chunkId then + chunkId, chunk = next(map.chunkToPassScan, nil) + else + chunk = map.chunkToPassScan[chunkId] end - if (chunkCount > 0) then - local processQueue = map.processQueue - for ri=chunkCount,1,-1 do - removeProcessQueueChunk(processQueue, removals[ri]) + if not chunkId then + map.chunkToPassScanIterator = nil + if (table_size(map.chunkToPassScan) == 0) then + -- this is needed as the next command remembers the max length a table has been + map.chunkToPassScan = {} + end + else + map.chunkToPassScanIterator = next(map.chunkToPassScan, chunkId) + map.chunkToPassScan[chunkId] = nil + + topOffset[1] = chunk.x + topOffset[2] = chunk.y + bottomOffset[1] = chunk.x + CHUNK_SIZE + bottomOffset[2] = chunk.y + CHUNK_SIZE + + if (chunkPassScan(chunk, map) == -1) then + removeProcessQueueChunk(map.processQueue, chunk) + map[chunk.x][chunk.y] = nil + map.chunkIdToChunk[chunk.id] = nil end end end diff --git a/libs/ChunkPropertyUtils.lua b/libs/ChunkPropertyUtils.lua index d82be85..cf7b6fe 100644 --- a/libs/ChunkPropertyUtils.lua +++ b/libs/ChunkPropertyUtils.lua @@ -22,130 +22,130 @@ local mMin = math.min -- module code function chunkPropertyUtils.getNestCount(map, chunk) - return map.chunkToNests[chunk] or 0 + return map.chunkToNests[chunk.id] or 0 end function chunkPropertyUtils.getTurretCount(map, chunk) - return map.chunkToTurrets[chunk] or 0 + return map.chunkToTurrets[chunk.id] or 0 end function chunkPropertyUtils.getTrapCount(map, chunk) - return map.chunkToTraps[chunk] or 0 + return map.chunkToTraps[chunk.id] or 0 end function chunkPropertyUtils.getUtilityCount(map, chunk) - return map.chunkToUtilities[chunk] or 0 + return map.chunkToUtilities[chunk.id] or 0 end function chunkPropertyUtils.getHiveCount(map, chunk) - return map.chunkToHives[chunk] or 0 + return map.chunkToHives[chunk.id] or 0 end function chunkPropertyUtils.addTurretCount(map, chunk, unitNumber) - if not map.chunkToTurretIds[chunk] then - map.chunkToTurretIds[chunk] = {} + if not map.chunkToTurretIds[chunk.id] then + map.chunkToTurretIds[chunk.id] = {} end - if not map.chunkToTurretIds[chunk][unitNumber] then - map.chunkToTurretIds[chunk][unitNumber] = true - map.chunkToTurrets[chunk] = (map.chunkToTurrets[chunk] or 0) + 1 + if not map.chunkToTurretIds[chunk.id][unitNumber] then + map.chunkToTurretIds[chunk.id][unitNumber] = true + map.chunkToTurrets[chunk.id] = (map.chunkToTurrets[chunk.id] or 0) + 1 end end function chunkPropertyUtils.removeTurretCount(map, chunk, unitNumber) - if map.chunkToTurretIds[chunk] and map.chunkToTurretIds[chunk][unitNumber] then - map.chunkToTurretIds[chunk][unitNumber] = nil - map.chunkToTurrets[chunk] = map.chunkToTurrets[chunk] - 1 - if map.chunkToTurrets[chunk] == 0 then - map.chunkToTurretIds[chunk] = nil - map.chunkToTurrets[chunk] = nil + if map.chunkToTurretIds[chunk.id] and map.chunkToTurretIds[chunk.id][unitNumber] then + map.chunkToTurretIds[chunk.id][unitNumber] = nil + map.chunkToTurrets[chunk.id] = map.chunkToTurrets[chunk.id] - 1 + if map.chunkToTurrets[chunk.id] == 0 then + map.chunkToTurretIds[chunk.id] = nil + map.chunkToTurrets[chunk.id] = nil end end end function chunkPropertyUtils.addTrapCount(map, chunk, unitNumber) - if not map.chunkToTrapIds[chunk] then - map.chunkToTrapIds[chunk] = {} + if not map.chunkToTrapIds[chunk.id] then + map.chunkToTrapIds[chunk.id] = {} end - if not map.chunkToTrapIds[chunk][unitNumber] then - map.chunkToTrapIds[chunk][unitNumber] = true - map.chunkToTraps[chunk] = (map.chunkToTraps[chunk] or 0) + 1 + if not map.chunkToTrapIds[chunk.id][unitNumber] then + map.chunkToTrapIds[chunk.id][unitNumber] = true + map.chunkToTraps[chunk.id] = (map.chunkToTraps[chunk.id] or 0) + 1 end end function chunkPropertyUtils.removeTrapCount(map, chunk, unitNumber) - if map.chunkToTrapIds[chunk] and map.chunkToTrapIds[chunk][unitNumber] then - map.chunkToTrapIds[chunk][unitNumber] = nil - map.chunkToTraps[chunk] = map.chunkToTraps[chunk] - 1 - if map.chunkToTraps[chunk] == 0 then - map.chunkToTrapIds[chunk] = nil - map.chunkToTraps[chunk] = nil + if map.chunkToTrapIds[chunk.id] and map.chunkToTrapIds[chunk.id][unitNumber] then + map.chunkToTrapIds[chunk.id][unitNumber] = nil + map.chunkToTraps[chunk.id] = map.chunkToTraps[chunk.id] - 1 + if map.chunkToTraps[chunk.id] == 0 then + map.chunkToTrapIds[chunk.id] = nil + map.chunkToTraps[chunk.id] = nil end end end function chunkPropertyUtils.addUtilitiesCount(map, chunk, unitNumber) - if not map.chunkToUtilityIds[chunk] then - map.chunkToUtilityIds[chunk] = {} + if not map.chunkToUtilityIds[chunk.id] then + map.chunkToUtilityIds[chunk.id] = {} end - if not map.chunkToUtilityIds[chunk][unitNumber] then - map.chunkToUtilityIds[chunk][unitNumber] = true - map.chunkToUtilities[chunk] = (map.chunkToUtilities[chunk] or 0) + 1 + if not map.chunkToUtilityIds[chunk.id][unitNumber] then + map.chunkToUtilityIds[chunk.id][unitNumber] = true + map.chunkToUtilities[chunk.id] = (map.chunkToUtilities[chunk.id] or 0) + 1 end end function chunkPropertyUtils.removeUtilitiesCount(map, chunk, unitNumber) - if map.chunkToUtilityIds[chunk] and map.chunkToUtilityIds[chunk][unitNumber] then - map.chunkToUtilityIds[chunk][unitNumber] = nil - map.chunkToUtilities[chunk] = map.chunkToUtilities[chunk] - 1 - if map.chunkToUtilities[chunk] == 0 then - map.chunkToUtilityIds[chunk] = nil - map.chunkToUtilities[chunk] = nil + if map.chunkToUtilityIds[chunk.id] and map.chunkToUtilityIds[chunk.id][unitNumber] then + map.chunkToUtilityIds[chunk.id][unitNumber] = nil + map.chunkToUtilities[chunk.id] = map.chunkToUtilities[chunk.id] - 1 + if map.chunkToUtilities[chunk.id] == 0 then + map.chunkToUtilityIds[chunk.id] = nil + map.chunkToUtilities[chunk.id] = nil end end end function chunkPropertyUtils.addHiveCount(map, chunk, unitNumber) - if not map.chunkToHiveIds[chunk] then - map.chunkToHiveIds[chunk] = {} + if not map.chunkToHiveIds[chunk.id] then + map.chunkToHiveIds[chunk.id] = {} end - if not map.chunkToHiveIds[chunk][unitNumber] then - map.chunkToHiveIds[chunk][unitNumber] = true - map.chunkToHives[chunk] = (map.chunkToHives[chunk] or 0) + 1 + if not map.chunkToHiveIds[chunk.id][unitNumber] then + map.chunkToHiveIds[chunk.id][unitNumber] = true + map.chunkToHives[chunk.id] = (map.chunkToHives[chunk.id] or 0) + 1 end end function chunkPropertyUtils.removeHiveCount(map, chunk, unitNumber) - if map.chunkToHiveIds[chunk] and map.chunkToHiveIds[chunk][unitNumber] then - map.chunkToHiveIds[chunk][unitNumber] = nil - map.chunkToHives[chunk] = map.chunkToHives[chunk] - 1 - if map.chunkToHives[chunk] == 0 then - map.chunkToHiveIds[chunk] = nil - map.chunkToHives[chunk] = nil + if map.chunkToHiveIds[chunk.id] and map.chunkToHiveIds[chunk.id][unitNumber] then + map.chunkToHiveIds[chunk.id][unitNumber] = nil + map.chunkToHives[chunk.id] = map.chunkToHives[chunk.id] - 1 + if map.chunkToHives[chunk.id] == 0 then + map.chunkToHiveIds[chunk.id] = nil + map.chunkToHives[chunk.id] = nil end end end function chunkPropertyUtils.addNestCount(map, chunk, unitNumber) - if not map.chunkToNestIds[chunk] then - map.chunkToNestIds[chunk] = {} + if not map.chunkToNestIds[chunk.id] then + map.chunkToNestIds[chunk.id] = {} end - if not map.chunkToNestIds[chunk][unitNumber] then - map.chunkToNestIds[chunk][unitNumber] = true - map.chunkToNests[chunk] = (map.chunkToNests[chunk] or 0) + 1 + if not map.chunkToNestIds[chunk.id][unitNumber] then + map.chunkToNestIds[chunk.id][unitNumber] = true + map.chunkToNests[chunk.id] = (map.chunkToNests[chunk.id] or 0) + 1 end end function chunkPropertyUtils.removeNestCount(map, chunk, unitNumber) - if map.chunkToNestIds[chunk] and map.chunkToNestIds[chunk][unitNumber] then - map.chunkToNestIds[chunk][unitNumber] = nil - map.chunkToNests[chunk] = map.chunkToNests[chunk] - 1 - if map.chunkToNests[chunk] == 0 then - map.chunkToNestIds[chunk] = nil - map.chunkToNests[chunk] = nil - if (map.processMigrationIterator == chunk) then + if map.chunkToNestIds[chunk.id] and map.chunkToNestIds[chunk.id][unitNumber] then + map.chunkToNestIds[chunk.id][unitNumber] = nil + map.chunkToNests[chunk.id] = map.chunkToNests[chunk.id] - 1 + if map.chunkToNests[chunk.id] == 0 then + map.chunkToNestIds[chunk.id] = nil + map.chunkToNests[chunk.id] = nil + if (map.processMigrationIterator == chunk.id) then map.processMigrationIterator = nil end - if (map.processNestIterator == chunk) then + if (map.processNestIterator == chunk.id) then map.processNestIterator = nil end end @@ -153,164 +153,164 @@ function chunkPropertyUtils.removeNestCount(map, chunk, unitNumber) end function chunkPropertyUtils.getNestCount(map, chunk) - return map.chunkToNests[chunk] or 0 + return map.chunkToNests[chunk.id] or 0 end function chunkPropertyUtils.getChunkBase(map, chunk) - return map.chunkToBase[chunk] + return map.chunkToBase[chunk.id] end function chunkPropertyUtils.removeChunkBase(map, chunk, base) - if map.chunkToBase[chunk] then + if map.chunkToBase[chunk.id] then base.chunkCount = base.chunkCount - 1 - map.chunkToBase[chunk] = nil + map.chunkToBase[chunk.id] = nil end end function chunkPropertyUtils.setChunkBase(map, chunk, base) - if not map.chunkToBase[chunk] then + if not map.chunkToBase[chunk.id] then base.chunkCount = base.chunkCount + 1 - map.chunkToBase[chunk] = base + map.chunkToBase[chunk.id] = base end end function chunkPropertyUtils.getEnemyStructureCount(map, chunk) - return (map.chunkToNests[chunk] or 0) + (map.chunkToTurrets[chunk] or 0) + (map.chunkToTraps[chunk] or 0) + - (map.chunkToUtilities[chunk] or 0) + (map.chunkToHives[chunk] or 0) + return (map.chunkToNests[chunk.id] or 0) + (map.chunkToTurrets[chunk.id] or 0) + (map.chunkToTraps[chunk.id] or 0) + + (map.chunkToUtilities[chunk.id] or 0) + (map.chunkToHives[chunk.id] or 0) end function chunkPropertyUtils.getRetreatTick(map, chunk) - return map.chunkToRetreats[chunk] or 0 + return map.chunkToRetreats[chunk.id] or 0 end function chunkPropertyUtils.getRallyTick(map, chunk) - return map.chunkToRallys[chunk] or 0 + return map.chunkToRallys[chunk.id] or 0 end function chunkPropertyUtils.setRallyTick(map, chunk, tick) - map.chunkToRallys[chunk] = tick + map.chunkToRallys[chunk.id] = tick end function chunkPropertyUtils.setRetreatTick(map, chunk, tick) - map.chunkToRetreats[chunk] = tick + map.chunkToRetreats[chunk.id] = tick end function chunkPropertyUtils.setResourceGenerator(map, chunk, resourceGenerator) if (resourceGenerator <= 0) then - map.chunkToResource[chunk] = nil + map.chunkToResource[chunk.id] = nil else - map.chunkToResource[chunk] = resourceGenerator + map.chunkToResource[chunk.id] = resourceGenerator end end function chunkPropertyUtils.getResourceGenerator(map, chunk) - return map.chunkToResource[chunk] or 0 + return map.chunkToResource[chunk.id] or 0 end function chunkPropertyUtils.addResourceGenerator(map, chunk, delta) - map.chunkToResource[chunk] = (map.chunkToResource[chunk] or 0) + delta + map.chunkToResource[chunk.id] = (map.chunkToResource[chunk.id] or 0) + delta end function chunkPropertyUtils.getDeathGenerator(map, chunk) - return map.chunkToDeathGenerator[chunk] or 0 + return map.chunkToDeathGenerator[chunk.id] or 0 end function chunkPropertyUtils.getPassable(map, chunk) - return map.chunkToPassable[chunk] or CHUNK_ALL_DIRECTIONS + return map.chunkToPassable[chunk.id] or CHUNK_ALL_DIRECTIONS end function chunkPropertyUtils.getRaidNestActiveness(map, chunk) - return map.chunkToActiveRaidNest[chunk] or 0 + return map.chunkToActiveRaidNest[chunk.id] or 0 end function chunkPropertyUtils.setRaidNestActiveness(map, chunk, value) if (value <= 0) then - if (map.chunkToActiveRaidNest[chunk] ~= nil) then + if map.chunkToActiveRaidNest[chunk.id] then map.activeRaidNests = map.activeRaidNests - 1 end - if (map.processActiveRaidSpawnerIterator == chunk) then + if (map.processActiveRaidSpawnerIterator == chunk.id) then map.processActiveRaidSpawnerIterator = nil end - map.chunkToActiveRaidNest[chunk] = nil + map.chunkToActiveRaidNest[chunk.id] = nil else - if (map.chunkToActiveRaidNest[chunk] == nil) then + if not map.chunkToActiveRaidNest[chunk.id] then map.activeRaidNests = map.activeRaidNests + 1 end - map.chunkToActiveRaidNest[chunk] = value + map.chunkToActiveRaidNest[chunk.id] = value end end function chunkPropertyUtils.getNestActiveTick(map, chunk) - return map.tickActiveNest[chunk] or 0 + return map.tickActiveNest[chunk.id] or 0 end function chunkPropertyUtils.setNestActiveTick(map, chunk, tick) if (tick == 0) then - map.tickActiveNest[chunk] = nil + map.tickActiveNest[chunk.id] = nil else - map.tickActiveNest[chunk] = tick + map.tickActiveNest[chunk.id] = tick end end function chunkPropertyUtils.getNestActiveness(map, chunk) - return map.chunkToActiveNest[chunk] or 0 + return map.chunkToActiveNest[chunk.id] or 0 end function chunkPropertyUtils.setNestActiveness(map, chunk, value) if (value <= 0) then - if (map.chunkToActiveNest[chunk] ~= nil) then + if map.chunkToActiveNest[chunk.id] then map.activeNests = map.activeNests - 1 end - if (map.processActiveSpawnerIterator == chunk) then + if (map.processActiveSpawnerIterator == chunk.id) then map.processActiveSpawnerIterator = nil end - map.chunkToActiveNest[chunk] = nil + map.chunkToActiveNest[chunk.id] = nil else - if (map.chunkToActiveNest[chunk] == nil) then + if not map.chunkToActiveNest[chunk.id] then map.activeNests = map.activeNests + 1 end - map.chunkToActiveNest[chunk] = value + map.chunkToActiveNest[chunk.id] = value end end function chunkPropertyUtils.setPassable(map, chunk, value) if (value == CHUNK_ALL_DIRECTIONS) then - map.chunkToPassable[chunk] = nil + map.chunkToPassable[chunk.id] = nil else - map.chunkToPassable[chunk] = value + map.chunkToPassable[chunk.id] = value end end function chunkPropertyUtils.getPathRating(map, chunk) - return map.chunkToPathRating[chunk] or 1 + return map.chunkToPathRating[chunk.id] or 1 end function chunkPropertyUtils.setPathRating(map, chunk, value) if (value == 1) then - map.chunkToPathRating[chunk] = nil + map.chunkToPathRating[chunk.id] = nil else - map.chunkToPathRating[chunk] = value + map.chunkToPathRating[chunk.id] = value end end function chunkPropertyUtils.addDeathGenerator(map, chunk, value) - map.chunkToDeathGenerator[chunk] = (map.chunkToDeathGenerator[chunk] or 0) + value + map.chunkToDeathGenerator[chunk.id] = (map.chunkToDeathGenerator[chunk.id] or 0) + value end function chunkPropertyUtils.addVictoryGenerator(map, chunk, value) - map.chunkToVictory[chunk] = (map.chunkToVictory[chunk] or 0) + value + map.chunkToVictory[chunk.id] = (map.chunkToVictory[chunk.id] or 0) + value end function chunkPropertyUtils.decayDeathGenerator(map, chunk) - local gen = map.chunkToDeathGenerator[chunk] + local gen = map.chunkToDeathGenerator[chunk.id] if gen then gen = gen * MOVEMENT_GENERATOR_PERSISTANCE if (gen >= -2) and (gen <= 2) then - map.chunkToDeathGenerator[chunk] = nil + map.chunkToDeathGenerator[chunk.id] = nil else - map.chunkToDeathGenerator[chunk] = gen + map.chunkToDeathGenerator[chunk.id] = gen end end end @@ -321,50 +321,50 @@ function chunkPropertyUtils.addPlayerToChunk(map, chunk, name) local playerChunk = playerChunks[name] if not playerChunk then playerChunks[name] = chunk - local playerCount = playerCountChunks[chunk] + local playerCount = playerCountChunks[chunk.id] if not playerCount then - playerCountChunks[chunk] = 1 + playerCountChunks[chunk.id] = 1 else - playerCountChunks[chunk] = playerCount + 1 + playerCountChunks[chunk.id] = playerCount + 1 end - elseif (playerChunk ~= chunk) then + elseif (playerChunk.id ~= chunk.id) then playerChunks[name] = chunk - local playerCount = playerCountChunks[playerChunk] + local playerCount = playerCountChunks[playerChunk.id] chunkPropertyUtils.setPlayersOnChunk(map, playerChunk, playerCount - 1) - playerCount = playerCountChunks[chunk] + playerCount = playerCountChunks[chunk.id] if not playerCount then - playerCountChunks[chunk] = 1 + playerCountChunks[chunk.id] = 1 else - playerCountChunks[chunk] = playerCount + 1 + playerCountChunks[chunk.id] = playerCount + 1 end end end function chunkPropertyUtils.setPlayersOnChunk(map, chunk, value) if (value <= 0) then - map.chunkToPlayerCount[chunk] = nil + map.chunkToPlayerCount[chunk.id] = nil else - map.chunkToPlayerCount[chunk] = value + map.chunkToPlayerCount[chunk.id] = value end end function chunkPropertyUtils.getPlayersOnChunk(map, chunk) - return map.chunkToPlayerCount[chunk] or 0 + return map.chunkToPlayerCount[chunk.id] or 0 end function chunkPropertyUtils.getPlayerBaseGenerator(map, chunk) - return map.chunkToPlayerBase[chunk] or 0 + return map.chunkToPlayerBase[chunk.id] or 0 end function chunkPropertyUtils.addSquadToChunk(map, chunk, squad) local chunkToSquad = map.chunkToSquad - if (chunk ~= -1) and (squad.chunk ~= chunk) then + if (chunk ~= -1) and ((squad.chunk == -1) or (squad.chunk.id ~= chunk.id)) then chunkPropertyUtils.removeSquadFromChunk(map, squad) - local squads = chunkToSquad[chunk] + local squads = chunkToSquad[chunk.id] if not squads then squads = {} - chunkToSquad[chunk] = squads + chunkToSquad[chunk.id] = squads end squads[squad.groupNumber] = squad squad.chunk = chunk @@ -374,29 +374,31 @@ end function chunkPropertyUtils.removeSquadFromChunk(map, squad) local chunkToSquad = map.chunkToSquad local chunk = squad.chunk - local squads = chunkToSquad[chunk] - if squads then - squads[squad.groupNumber] = nil - if (table_size(squads) == 0) then - chunkToSquad[chunk] = nil + if (chunk ~= -1) then + local squads = chunkToSquad[chunk.id] + if squads then + squads[squad.groupNumber] = nil + if (table_size(squads) == 0) then + chunkToSquad[chunk.id] = nil + end end end end function chunkPropertyUtils.getSquadsOnChunk(map, chunk) - return map.chunkToSquad[chunk] or map.emptySquadsOnChunk + return map.chunkToSquad[chunk.id] or map.emptySquadsOnChunk end function chunkPropertyUtils.setPlayerBaseGenerator(map, chunk, playerGenerator) if (playerGenerator <= 0) then - map.chunkToPlayerBase[chunk] = nil + map.chunkToPlayerBase[chunk.id] = nil else - map.chunkToPlayerBase[chunk] = playerGenerator + map.chunkToPlayerBase[chunk.id] = playerGenerator end end function chunkPropertyUtils.addPlayerBaseGenerator(map, chunk, playerGenerator) - map.chunkToPlayerBase[chunk] = (map.chunkToPlayerBase[chunk] or 0) + playerGenerator + map.chunkToPlayerBase[chunk.id] = (map.chunkToPlayerBase[chunk.id] or 0) + playerGenerator end function chunkPropertyUtils.processNestActiveness(map, chunk) @@ -409,12 +411,12 @@ function chunkPropertyUtils.processNestActiveness(map, chunk) if universe.attackUsePlayer and (chunk[PLAYER_PHEROMONE] > universe.attackPlayerThreshold) then chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20)) elseif (chunk[BASE_PHEROMONE] > 0) then - local position = universe.position if (surface.get_pollution(chunk) > 0) then chunkPropertyUtils.setNestActiveness(map, chunk, mMin(activeness + 5, 20)) else local x = chunk.x local y = chunk.y + local position = {x=0,y=0} position.x = x + 32 position.y = y if (surface.get_pollution(position) > 0) then diff --git a/libs/ChunkUtils.lua b/libs/ChunkUtils.lua index 7ecb43d..b7c9929 100644 --- a/libs/ChunkUtils.lua +++ b/libs/ChunkUtils.lua @@ -351,16 +351,23 @@ function chunkUtils.entityForPassScan(map, entity) for i=1,#overlapArray do local chunk = overlapArray[i] if (chunk ~= -1) then - map.chunkToPassScan[chunk] = true + map.chunkToPassScan[chunk.id] = chunk end end end -function chunkUtils.createChunk(topX, topY) +function chunkUtils.newChunkId(map) + local id = map.chunkId + map.chunkId = map.chunkId + 1 + return id +end + +function chunkUtils.createChunk(map, topX, topY) local chunk = { x = topX, y = topY, - dOrigin = euclideanDistancePoints(topX, topY, 0, 0) + dOrigin = euclideanDistancePoints(topX, topY, 0, 0), + id = chunkUtils.newChunkId(map) } chunk[BASE_PHEROMONE] = 0 chunk[PLAYER_PHEROMONE] = 0 diff --git a/libs/MapProcessor.lua b/libs/MapProcessor.lua index 8825078..62695d7 100644 --- a/libs/MapProcessor.lua +++ b/libs/MapProcessor.lua @@ -63,6 +63,7 @@ local formSettlers = aiAttackWave.formSettlers local getChunkByPosition = mapUtils.getChunkByPosition local getChunkByXY = mapUtils.getChunkByXY +local getChunkById = mapUtils.getChunkById local validPlayer = playerUtils.validPlayer @@ -253,7 +254,7 @@ function mapProcessor.processPlayers(players, map, tick) queueNestSpawners(map, chunk, tick) if vengence then - map.vengenceQueue[chunk] = (map.vengenceQueue[chunk] or 0) + 1 + map.vengenceQueue[chunk.id] = (map.vengenceQueue[chunk.id] or 0) + 1 end end end @@ -448,27 +449,28 @@ function mapProcessor.processActiveNests(map, tick) end function mapProcessor.processVengence(map) - local ss = map.vengenceQueue - local chunk = map.deployVengenceIterator - if not chunk then - chunk = next(ss, nil) + local vengence = map.vengenceQueue + local chunkId = map.deployVengenceIterator + if not chunkId then + chunkId = next(vengence, nil) end - if not chunk then + if not chunkId then map.deployVengenceIterator = nil - if (tableSize(ss) == 0) then + if (tableSize(vengence) == 0) then map.vengenceQueue = {} end else - map.deployVengenceIterator = next(ss, chunk) - formVengenceSquad(map, chunk) - ss[chunk] = nil + map.deployVengenceIterator = next(vengence, chunkId) + formVengenceSquad(map, getChunkById(map, chunkId)) + vengence[chunkId] = nil end end function mapProcessor.processNests(map, tick) - local chunk = next(map.chunkToNests, map.processNestIterator) - map.processNestIterator = chunk - if chunk then + local chunkId = next(map.chunkToNests, map.processNestIterator) + map.processNestIterator = chunkId + if chunkId then + local chunk = getChunkById(map, chunkId) processNestActiveness(map, chunk) queueNestSpawners(map, chunk, tick) @@ -481,10 +483,11 @@ function mapProcessor.processNests(map, tick) end end -local function processSpawners(map, iterator, chunks) - local chunk = next(chunks, map[iterator]) - map[iterator] = chunk - if chunk then +local function processSpawnersBody(map, iterator, chunks) + local chunkId = next(chunks, map[iterator]) + map[iterator] = chunkId + if chunkId then + local chunk = getChunkById(map, chunkId) local migrate = canMigrate(map) local attack = canAttack(map) if migrate then @@ -499,30 +502,30 @@ function mapProcessor.processSpawners(map) if (map.state ~= AI_STATE_PEACEFUL) then if (map.state == AI_STATE_MIGRATING) then - processSpawners(map, - "processMigrationIterator", - map.chunkToNests) + processSpawnersBody(map, + "processMigrationIterator", + map.chunkToNests) elseif (map.state == AI_STATE_AGGRESSIVE) then - processSpawners(map, - "processActiveSpawnerIterator", - map.chunkToActiveNest) + processSpawnersBody(map, + "processActiveSpawnerIterator", + map.chunkToActiveNest) elseif (map.state == AI_STATE_SIEGE) then - processSpawners(map, - "processActiveSpawnerIterator", - map.chunkToActiveNest) - processSpawners(map, - "processActiveRaidSpawnerIterator", - map.chunkToActiveRaidNest) - processSpawners(map, - "processMigrationIterator", - map.chunkToNests) + processSpawnersBody(map, + "processActiveSpawnerIterator", + map.chunkToActiveNest) + processSpawnersBody(map, + "processActiveRaidSpawnerIterator", + map.chunkToActiveRaidNest) + processSpawnersBody(map, + "processMigrationIterator", + map.chunkToNests) else - processSpawners(map, - "processActiveSpawnerIterator", - map.chunkToActiveNest) - processSpawners(map, - "processActiveRaidSpawnerIterator", - map.chunkToActiveRaidNest) + processSpawnersBody(map, + "processActiveSpawnerIterator", + map.chunkToActiveNest) + processSpawnersBody(map, + "processActiveRaidSpawnerIterator", + map.chunkToActiveRaidNest) end end end diff --git a/libs/MapUtils.lua b/libs/MapUtils.lua index 4582a0f..f723868 100644 --- a/libs/MapUtils.lua +++ b/libs/MapUtils.lua @@ -43,6 +43,10 @@ function mapUtils.getChunkByPosition(map, position) return -1 end +function mapUtils.getChunkById(map, chunkId) + return map.chunkIdToChunk[chunkId] or -1 +end + function mapUtils.positionToChunkXY(position) local chunkX = mFloor(position.x * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE local chunkY = mFloor(position.y * CHUNK_SIZE_DIVIDER) * CHUNK_SIZE @@ -51,7 +55,10 @@ end function mapUtils.queueGeneratedChunk(universe, event) event.tick = (event.tick or game.tick) + 20 - universe.maps[event.surface.index].pendingChunks[event] = true + local map = universe.maps[event.surface.index] + event.id = map.eventId + map.pendingChunks[event.id] = event + map.eventId = map.eventId + 1 end --[[ @@ -220,6 +227,5 @@ function mapUtils.positionFromDirectionAndFlat(direction, startPosition, endPosi endPosition.y = ly end - mapUtilsG = mapUtils return mapUtils diff --git a/libs/MovementUtils.lua b/libs/MovementUtils.lua index aab591a..20a6c25 100644 --- a/libs/MovementUtils.lua +++ b/libs/MovementUtils.lua @@ -51,7 +51,7 @@ function movementUtils.addMovementPenalty(squad, chunk) local penaltyCount = #penalties for i=1,penaltyCount do local penalty = penalties[i] - if (penalty.c == chunk) then + if (penalty.c.id == chunk.id) then penalty.v = penalty.v + 1 if (penalty.v > 2) then squad.kamikaze = true @@ -79,7 +79,7 @@ function movementUtils.scoreNeighborsForAttack(map, chunk, neighborDirectionChun for x=1,8 do local neighborChunk = neighborDirectionChunks[x] if (neighborChunk ~= -1) then - if canMoveChunkDirection(map, x, chunk, neighborChunk) or (chunk == -1) then + if (chunk == -1) or canMoveChunkDirection(map, x, chunk, neighborChunk) then local score = scoreFunction(map, neighborChunk) if (score > highestScore) then highestScore = score @@ -98,7 +98,7 @@ function movementUtils.scoreNeighborsForAttack(map, chunk, neighborDirectionChun neighborDirectionChunks = getNeighborChunks(map, highestChunk.x, highestChunk.y) for x=1,8 do local neighborChunk = neighborDirectionChunks[x] - if ((neighborChunk ~= -1) and (neighborChunk ~= chunk) and + if ((neighborChunk ~= -1) and ((chunk == -1) or (neighborChunk.id ~= chunk.id)) and canMoveChunkDirection(map, x, highestChunk, neighborChunk)) then local score = scoreFunction(map, neighborChunk) if (score > nextHighestScore) then @@ -125,7 +125,7 @@ function movementUtils.scoreNeighborsForSettling(map, chunk, neighborDirectionCh for x=1,8 do local neighborChunk = neighborDirectionChunks[x] if (neighborChunk ~= -1) then - if canMoveChunkDirection(map, x, chunk, neighborChunk) or (chunk == -1) then + if (chunk == -1) or canMoveChunkDirection(map, x, chunk, neighborChunk) then local score = scoreFunction(map, neighborChunk) if (score > highestScore) then highestScore = score @@ -148,7 +148,7 @@ function movementUtils.scoreNeighborsForSettling(map, chunk, neighborDirectionCh neighborDirectionChunks = getNeighborChunks(map, highestChunk.x, highestChunk.y) for x=1,8 do local neighborChunk = neighborDirectionChunks[x] - if ((neighborChunk ~= -1) and (neighborChunk ~= chunk) and + if ((neighborChunk ~= -1) and ((chunk == -1) or (neighborChunk.id ~= chunk.id)) and canMoveChunkDirection(map, x, highestChunk, neighborChunk)) then local score = scoreFunction(map, neighborChunk) if (score > nextHighestScore) then @@ -203,7 +203,7 @@ function movementUtils.scoreNeighborsForRetreat(chunk, neighborDirectionChunks, for x=1,8 do local neighborChunk = neighborDirectionChunks[x] if (neighborChunk ~= -1) then - if canMoveChunkDirection(map, x, chunk, neighborChunk) or (chunk == -1) then + if (chunk == -1) or canMoveChunkDirection(map, x, chunk, neighborChunk) then local score = scoreFunction(map, neighborChunk) if (score > highestScore) then highestScore = score @@ -223,7 +223,7 @@ function movementUtils.scoreNeighborsForRetreat(chunk, neighborDirectionChunks, for x=1,8 do local neighborChunk = neighborDirectionChunks[x] - if ((neighborChunk ~= -1) and (neighborChunk ~= chunk) and + if ((neighborChunk ~= -1) and ((chunk == -1) or (neighborChunk.id ~= chunk.id)) and canMoveChunkDirection(map, x, highestChunk, neighborChunk)) then local score = scoreFunction(map, neighborChunk) if (score > nextHighestScore) then diff --git a/libs/PheromoneUtils.lua b/libs/PheromoneUtils.lua index 6c0bec5..ccf3a12 100644 --- a/libs/PheromoneUtils.lua +++ b/libs/PheromoneUtils.lua @@ -37,6 +37,7 @@ local addVictoryGenerator = chunkPropertyUtils.addVictoryGenerator local getPlayersOnChunk = chunkPropertyUtils.getPlayersOnChunk local getNeighborChunks = mapUtils.getNeighborChunks +local getChunkById = mapUtils.getChunkById local getEnemyStructureCount = chunkPropertyUtils.getEnemyStructureCount local getPathRating = chunkPropertyUtils.getPathRating @@ -63,18 +64,20 @@ function pheromoneUtils.victoryScent(map, chunk, entityType) end function pheromoneUtils.disperseVictoryScent(map) - local chunk = map.victoryScentIterator + local chunkId = map.victoryScentIterator local chunkToVictory = map.chunkToVictory local pheromone - if not chunk then - chunk, pheromone = next(chunkToVictory, nil) + if not chunkId then + chunkId, pheromone = next(chunkToVictory, nil) else - pheromone = chunkToVictory[chunk] + pheromone = chunkToVictory[chunkId] end - if not chunk then + if not chunkId then map.victoryScentIterator = nil else - map.victoryScentIterator = next(chunkToVictory, chunk) + map.victoryScentIterator = next(chunkToVictory, chunkId) + chunkToVictory[chunkId] = nil + local chunk = getChunkById(map, chunkId) local chunkX = chunk.x local chunkY = chunk.y local i = 1 @@ -87,8 +90,6 @@ function pheromoneUtils.disperseVictoryScent(map) i = i + 1 end end - - chunkToVictory[chunk] = nil end end diff --git a/libs/SquadAttack.lua b/libs/SquadAttack.lua index 9a46f82..7bd3f35 100644 --- a/libs/SquadAttack.lua +++ b/libs/SquadAttack.lua @@ -118,9 +118,14 @@ local function settleMove(map, squad) elseif squad.kamikaze then scoreFunction = scoreResourceLocationKamikaze end - addDeathGenerator(map, chunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) - addSquadToChunk(map, chunk, squad) - addMovementPenalty(squad, chunk) + local squadChunk = squad.chunk + if squadChunk ~= -1 then + addDeathGenerator(map, squadChunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) + end + if chunk ~= -1 then + addSquadToChunk(map, chunk, squad) + addMovementPenalty(squad, chunk) + end local distance = euclideanDistancePoints(groupPosition.x, groupPosition.y, squad.originPosition.x, @@ -129,7 +134,8 @@ local function settleMove(map, squad) local position local surface = map.surface - if (distance >= squad.maxDistance) or ((getResourceGenerator(map, chunk) ~= 0) and (getNestCount(map, chunk) == 0)) + if (chunk ~= -1) and + ((distance >= squad.maxDistance) or ((getResourceGenerator(map, chunk) ~= 0) and (getNestCount(map, chunk) == 0))) then position = findMovementPosition(surface, groupPosition) @@ -244,9 +250,13 @@ local function attackMove(map, squad) attackScorer = scoreAttackKamikazeLocation end local squadChunk = squad.chunk - addDeathGenerator(map, squadChunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) - addSquadToChunk(map, chunk, squad) - addMovementPenalty(squad, chunk) + if squadChunk ~= -1 then + addDeathGenerator(map, squadChunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) + end + if chunk ~= -1 then + addSquadToChunk(map, chunk, squad) + addMovementPenalty(squad, chunk) + end squad.frenzy = (squad.frenzy and (euclideanDistanceNamed(groupPosition, squad.frenzyPosition) < 100)) local attackChunk, attackDirection, nextAttackChunk, nextAttackDirection = scoreNeighborsForAttack(map, @@ -275,7 +285,7 @@ local function attackMove(map, squad) else targetPosition.x = position.x targetPosition.y = position.y - if nextAttackChunk then + if (nextAttackChunk ~= -1) then addDeathGenerator(map, nextAttackChunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) else addDeathGenerator(map, attackChunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) @@ -322,26 +332,28 @@ end function squadAttack.cleanSquads(map, tick) local squads = map.groupNumberToSquad - local k = map.squadIterator + local groupId = map.squadIterator local squad - if not k then - k, squad = next(squads, k) + if not groupId then + groupId, squad = next(squads, groupId) else - squad = squads[k] + squad = squads[groupId] end - if not k then + if not groupId then map.squadIterator = nil if (table_size(squads) == 0) then -- this is needed as the next command remembers the max length a table has been map.groupNumberToSquad = {} end else - map.squadIterator = next(squads, k) + map.squadIterator = next(squads, groupId) local group = squad.group if not group.valid then - addDeathGenerator(map, squad.chunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) + if squad.chunk ~= -1 then + addDeathGenerator(map, squad.chunk, FIVE_DEATH_PHEROMONE_GENERATOR_AMOUNT) + end removeSquadFromChunk(map, squad) - if (map.regroupIterator == k) then + if (map.regroupIterator == groupId) then map.regroupIterator = nil end local universe = map.universe @@ -350,7 +362,7 @@ function squadAttack.cleanSquads(map, tick) else universe.squadCount = universe.squadCount - 1 end - squads[k] = nil + squads[groupId] = nil elseif (group.state == 4) then squadAttack.squadDispatch(map, squad, tick) elseif (squad.commandTick and (squad.commandTick < tick)) then