2017-07-29 00:02:45 +02:00
|
|
|
-- regrowth_map.lua
|
|
|
|
-- July 2017
|
|
|
|
--
|
|
|
|
-- Code tracks all chunks generated and allows for deleting inactive chunks
|
|
|
|
-- Relies on some changes to RSO to provide random resource locations the next
|
|
|
|
-- time the land is regenerated.
|
|
|
|
--
|
|
|
|
-- Basic rules of regrowth:
|
|
|
|
-- 1. Area around player is safe for quite a large distance.
|
|
|
|
-- 2. Rocket silo won't be deleted. - PERMANENT
|
|
|
|
-- 3. Chunks with pollution won't be deleted.
|
|
|
|
-- 4. Chunks with railways won't be deleted.
|
|
|
|
-- 5. Anything within radar range won't be deleted, but radar MUST be active.
|
|
|
|
-- -- This works by refreshing all chunk timers within radar range using
|
|
|
|
-- the on_sector_scanned event.
|
|
|
|
-- 6. Chunks timeout after 1 hour-ish, configurable
|
|
|
|
-- 7. For now, oarc spawns are deletion safe as well, but only immediate area.
|
|
|
|
|
|
|
|
|
2017-08-05 21:50:26 +02:00
|
|
|
-- Time after which chunks should be cleared.
|
2017-08-05 15:45:37 +02:00
|
|
|
REGROWTH_TIMEOUT_TICKS = 60*60*60 -- 1 hour
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-08-05 21:50:26 +02:00
|
|
|
-- We can't delete chunks regularly without causing lag.
|
|
|
|
-- So we should save them up to delete them.
|
|
|
|
REGROWTH_CLEANING_INTERVAL_TICKS = REGROWTH_TIMEOUT_TICKS
|
|
|
|
|
|
|
|
|
|
|
|
|
2017-07-29 00:02:45 +02:00
|
|
|
-- Init globals and set player join area to be off limits.
|
|
|
|
function OarcRegrowthInit()
|
|
|
|
global.chunk_regrow = {}
|
|
|
|
global.chunk_regrow.map = {}
|
2017-07-30 19:14:54 +02:00
|
|
|
global.chunk_regrow.removal_list = {}
|
2017-07-29 00:02:45 +02:00
|
|
|
global.chunk_regrow.rso_region_roll_counter = 0
|
2017-07-29 18:14:51 +02:00
|
|
|
global.chunk_regrow.player_refresh_index = 1
|
2017-07-30 19:14:54 +02:00
|
|
|
global.chunk_regrow.min_x = 0
|
|
|
|
global.chunk_regrow.max_x = 0
|
|
|
|
global.chunk_regrow.x_index = 0
|
|
|
|
global.chunk_regrow.min_y = 0
|
|
|
|
global.chunk_regrow.max_y = 0
|
|
|
|
global.chunk_regrow.y_index = 0
|
2017-08-05 21:50:26 +02:00
|
|
|
global.chunk_regrow.force_removal_flag = 0
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-08-05 21:50:26 +02:00
|
|
|
OarcRegrowthOffLimits({x=0,y=0}, 10)
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
function GetChunkTopLeft(pos)
|
|
|
|
return {x=pos.x-(pos.x % 32), y=pos.y-(pos.y % 32)}
|
|
|
|
end
|
|
|
|
|
2017-08-05 21:50:26 +02:00
|
|
|
function GetChunkCoordsFromPos(pos)
|
|
|
|
return {x=math.floor(pos.x/32), y=math.floor(pos.y/32)}
|
2017-08-05 15:12:20 +02:00
|
|
|
end
|
|
|
|
|
2017-07-29 00:02:45 +02:00
|
|
|
|
|
|
|
-- Adds new chunks to the global table to track them.
|
|
|
|
-- This should always be called first in the chunk generate sequence
|
|
|
|
-- (Compared to other RSO & Oarc related functions...)
|
2017-07-30 19:14:54 +02:00
|
|
|
function OarcRegrowthChunkGenerate(pos)
|
|
|
|
|
2017-08-05 21:50:26 +02:00
|
|
|
c_pos = GetChunkCoordsFromPos(pos)
|
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- If this is the first chunk in that row:
|
2017-08-05 21:50:26 +02:00
|
|
|
if (global.chunk_regrow.map[c_pos.x] == nil) then
|
|
|
|
global.chunk_regrow.map[c_pos.x] = {}
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Confirm the chunk doesn't already have a value set:
|
2017-08-05 21:50:26 +02:00
|
|
|
if (global.chunk_regrow.map[c_pos.x][c_pos.y] == nil) then
|
|
|
|
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Store min/max values for x/y dimensions:
|
2017-08-05 21:50:26 +02:00
|
|
|
if (c_pos.x < global.chunk_regrow.min_x) then
|
|
|
|
global.chunk_regrow.min_x = c_pos.x
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
2017-08-05 21:50:26 +02:00
|
|
|
if (c_pos.x > global.chunk_regrow.max_x) then
|
|
|
|
global.chunk_regrow.max_x = c_pos.x
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
2017-08-05 21:50:26 +02:00
|
|
|
if (c_pos.y < global.chunk_regrow.min_y) then
|
|
|
|
global.chunk_regrow.min_y = c_pos.y
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
2017-08-05 21:50:26 +02:00
|
|
|
if (c_pos.y > global.chunk_regrow.max_y) then
|
|
|
|
global.chunk_regrow.max_y = c_pos.y
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Mark an area for immediate forced removal
|
2017-07-29 01:55:43 +02:00
|
|
|
function OarcRegrowthMarkForRemoval(pos, chunk_radius)
|
2017-08-05 21:50:26 +02:00
|
|
|
local c_pos = GetChunkCoordsFromPos(pos)
|
2017-07-29 01:55:43 +02:00
|
|
|
for i=-chunk_radius,chunk_radius do
|
|
|
|
for k=-chunk_radius,chunk_radius do
|
2017-08-05 21:50:26 +02:00
|
|
|
local x = c_pos.x+i
|
|
|
|
local y = c_pos.y+k
|
2017-07-29 01:55:43 +02:00
|
|
|
|
|
|
|
if (global.chunk_regrow.map[x] == nil) then
|
|
|
|
global.chunk_regrow.map[x] = {}
|
|
|
|
end
|
2017-07-30 19:14:54 +02:00
|
|
|
global.chunk_regrow.map[x][y] = nil
|
|
|
|
table.insert(global.chunk_regrow.removal_list, {x=x,y=y})
|
2017-07-29 01:55:43 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-07-29 18:14:51 +02:00
|
|
|
-- Marks a chunk a position that won't ever be deleted.
|
|
|
|
function OarcRegrowthOffLimitsChunk(pos)
|
2017-08-05 21:50:26 +02:00
|
|
|
local c_pos = GetChunkCoordsFromPos(pos)
|
2017-07-29 18:14:51 +02:00
|
|
|
|
|
|
|
if (global.chunk_regrow.map[c_pos.x] == nil) then
|
|
|
|
global.chunk_regrow.map[c_pos.y] = {}
|
|
|
|
end
|
|
|
|
global.chunk_regrow.map[c_pos.x][c_pos.y] = -1
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
|
|
-- Marks a safe area around a position that won't ever be deleted.
|
2017-07-29 00:02:45 +02:00
|
|
|
function OarcRegrowthOffLimits(pos, chunk_radius)
|
2017-08-05 21:50:26 +02:00
|
|
|
local c_pos = GetChunkCoordsFromPos(pos)
|
2017-07-29 00:02:45 +02:00
|
|
|
for i=-chunk_radius,chunk_radius do
|
|
|
|
for k=-chunk_radius,chunk_radius do
|
2017-08-05 21:50:26 +02:00
|
|
|
local x = c_pos.x+i
|
|
|
|
local y = c_pos.y+k
|
2017-07-29 00:02:45 +02:00
|
|
|
|
|
|
|
if (global.chunk_regrow.map[x] == nil) then
|
|
|
|
global.chunk_regrow.map[x] = {}
|
|
|
|
end
|
|
|
|
global.chunk_regrow.map[x][y] = -1
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2017-07-29 18:14:51 +02:00
|
|
|
-- Refreshes timers on a chunk containing position
|
2017-07-30 19:14:54 +02:00
|
|
|
function OarcRegrowthRefreshChunk(pos, bonus_time)
|
2017-08-05 21:50:26 +02:00
|
|
|
local c_pos = GetChunkCoordsFromPos(pos)
|
2017-07-29 18:14:51 +02:00
|
|
|
|
|
|
|
if (global.chunk_regrow.map[c_pos.x] == nil) then
|
|
|
|
global.chunk_regrow.map[c_pos.y] = {}
|
|
|
|
end
|
|
|
|
if (global.chunk_regrow.map[c_pos.x][c_pos.y] ~= -1) then
|
2017-07-30 19:14:54 +02:00
|
|
|
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick + bonus_time
|
2017-07-29 18:14:51 +02:00
|
|
|
end
|
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
|
|
|
-- Refreshes timers on all chunks around a certain area
|
2017-07-30 19:14:54 +02:00
|
|
|
function OarcRegrowthRefreshArea(pos, chunk_radius, bonus_time)
|
2017-08-05 21:50:26 +02:00
|
|
|
local c_pos = GetChunkCoordsFromPos(pos)
|
|
|
|
|
2017-07-29 00:02:45 +02:00
|
|
|
for i=-chunk_radius,chunk_radius do
|
|
|
|
for k=-chunk_radius,chunk_radius do
|
2017-08-05 21:50:26 +02:00
|
|
|
local x = c_pos.x+i
|
|
|
|
local y = c_pos.y+k
|
2017-07-29 00:02:45 +02:00
|
|
|
|
|
|
|
if (global.chunk_regrow.map[x] == nil) then
|
|
|
|
global.chunk_regrow.map[x] = {}
|
|
|
|
end
|
2017-07-29 18:14:51 +02:00
|
|
|
if (global.chunk_regrow.map[x][y] ~= -1) then
|
2017-07-30 19:14:54 +02:00
|
|
|
global.chunk_regrow.map[x][y] = game.tick + bonus_time
|
2017-07-29 18:14:51 +02:00
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Refreshes timers on all chunks near an ACTIVE radar
|
|
|
|
function OarcRegrowthSectorScan(event)
|
2017-08-05 15:12:20 +02:00
|
|
|
OarcRegrowthRefreshArea(event.radar.position, 4, 0)
|
2017-08-05 16:25:01 +02:00
|
|
|
OarcRegrowthRefreshChunk(event.chunk_position)
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Refresh all chunks near a single player. Cyles through all connected players.
|
|
|
|
function OarcRegrowthRefreshPlayerArea()
|
|
|
|
global.chunk_regrow.player_refresh_index = global.chunk_regrow.player_refresh_index + 1
|
|
|
|
if (global.chunk_regrow.player_refresh_index > #game.connected_players) then
|
|
|
|
global.chunk_regrow.player_refresh_index = 1
|
|
|
|
end
|
2017-08-05 15:12:20 +02:00
|
|
|
if (game.connected_players[global.chunk_regrow.player_refresh_index]) then
|
|
|
|
OarcRegrowthRefreshArea(game.connected_players[global.chunk_regrow.player_refresh_index].position, 4, 0)
|
2017-07-29 18:14:51 +02:00
|
|
|
end
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
2017-07-29 18:14:51 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Check each chunk in the 2d array for a timeout value
|
|
|
|
function OarcRegrowthCheckArray()
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Increment X
|
|
|
|
if (global.chunk_regrow.x_index > global.chunk_regrow.max_x) then
|
|
|
|
global.chunk_regrow.x_index = global.chunk_regrow.min_x
|
|
|
|
-- Increment Y
|
|
|
|
if (global.chunk_regrow.y_index > global.chunk_regrow.max_y) then
|
|
|
|
global.chunk_regrow.y_index = global.chunk_regrow.min_y
|
|
|
|
else
|
2017-08-05 21:50:26 +02:00
|
|
|
global.chunk_regrow.y_index = global.chunk_regrow.y_index + 1
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
|
|
|
else
|
2017-08-05 21:50:26 +02:00
|
|
|
global.chunk_regrow.x_index = global.chunk_regrow.x_index + 1
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Check row exists, otherwise make one.
|
|
|
|
if (global.chunk_regrow.map[global.chunk_regrow.x_index] == nil) then
|
|
|
|
global.chunk_regrow.map[global.chunk_regrow.x_index] = {}
|
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- If the chunk has timed out, add it to the removal list
|
|
|
|
local c_timer = global.chunk_regrow.map[global.chunk_regrow.x_index][global.chunk_regrow.y_index]
|
|
|
|
if ((c_timer ~= nil) and (c_timer ~= -1) and ((c_timer+REGROWTH_TIMEOUT_TICKS) < game.tick)) then
|
2017-08-05 21:50:26 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Check chunk actually exists
|
2017-08-05 21:50:26 +02:00
|
|
|
if (game.surfaces[GAME_SURFACE_NAME].is_chunk_generated({x=(global.chunk_regrow.x_index),
|
|
|
|
y=(global.chunk_regrow.y_index)})) then
|
2017-07-30 19:14:54 +02:00
|
|
|
table.insert(global.chunk_regrow.removal_list, {x=global.chunk_regrow.x_index,
|
|
|
|
y=global.chunk_regrow.y_index})
|
|
|
|
global.chunk_regrow.map[global.chunk_regrow.x_index][global.chunk_regrow.y_index] = nil
|
|
|
|
end
|
|
|
|
end
|
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-08-05 21:50:26 +02:00
|
|
|
-- Remove all chunks at same time to reduce impact to FPS/UPS
|
|
|
|
function OarcRegrowthRemoveAllChunks()
|
|
|
|
while (#global.chunk_regrow.removal_list > 0) do
|
2017-07-30 19:14:54 +02:00
|
|
|
local c_pos = table.remove(global.chunk_regrow.removal_list)
|
|
|
|
local c_timer = global.chunk_regrow.map[c_pos.x][c_pos.y]
|
2017-07-29 18:14:51 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Confirm chunk is still expired
|
|
|
|
if (c_timer == nil) then
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- Check for pollution
|
|
|
|
if (game.surfaces[GAME_SURFACE_NAME].get_pollution(c_pos) > 0) then
|
|
|
|
global.chunk_regrow.map[c_pos.x][c_pos.y] = game.tick
|
|
|
|
|
|
|
|
-- Else delete the chunk
|
|
|
|
else
|
2017-08-05 21:50:26 +02:00
|
|
|
game.surfaces[GAME_SURFACE_NAME].delete_chunk({c_pos.x,c_pos.y})
|
2017-07-30 19:14:54 +02:00
|
|
|
global.chunk_regrow.map[c_pos.x][c_pos.y] = nil
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
|
|
|
else
|
2017-08-05 21:50:26 +02:00
|
|
|
|
|
|
|
-- DebugPrint("Chunk no longer expired?")
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
2017-07-30 19:14:54 +02:00
|
|
|
end
|
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-07-30 19:14:54 +02:00
|
|
|
-- This is the main work function, it checks a single chunk in the list
|
|
|
|
-- per tick. It works according to the rules listed in the header of this
|
|
|
|
-- file.
|
|
|
|
function OarcRegrowthOnTick(event)
|
|
|
|
|
|
|
|
-- Every half a second, refresh all chunks near a single player
|
|
|
|
-- Cyles through all players. Tick is offset by 2
|
|
|
|
if ((game.tick % (30)) == 2) then
|
|
|
|
OarcRegrowthRefreshPlayerArea()
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Every tick, check a few points in the 2d array
|
2017-08-05 21:50:26 +02:00
|
|
|
-- According to /measured-command this shouldn't take more
|
|
|
|
-- than 0.1ms on average
|
|
|
|
for i=1,20 do
|
2017-07-30 19:14:54 +02:00
|
|
|
OarcRegrowthCheckArray()
|
|
|
|
end
|
2017-07-29 00:02:45 +02:00
|
|
|
|
2017-08-05 21:50:26 +02:00
|
|
|
-- Send a broadcast warning before it happens.
|
|
|
|
if ((game.tick % REGROWTH_TIMEOUT_TICKS) == REGROWTH_TIMEOUT_TICKS-601) then
|
|
|
|
if (#global.chunk_regrow.removal_list > 100) then
|
|
|
|
SendBroadcastMsg("Map cleanup in 10 seconds...")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Delete all listed chunks
|
|
|
|
if ((game.tick % REGROWTH_TIMEOUT_TICKS) == REGROWTH_TIMEOUT_TICKS-1) then
|
|
|
|
if (#global.chunk_regrow.removal_list > 100) then
|
|
|
|
OarcRegrowthRemoveAllChunks()
|
|
|
|
SendBroadcastMsg("Map cleanup done...")
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
-- Catch force remove flag
|
|
|
|
if (game.tick == global.chunk_regrow.force_removal_flag+60) then
|
|
|
|
OarcRegrowthRemoveAllChunks()
|
|
|
|
-- SendBroadcastMsg("Immediate map cleanup done...")
|
2017-07-29 00:02:45 +02:00
|
|
|
end
|
|
|
|
end
|