1
0
mirror of https://github.com/Oarcinae/FactorioScenarioMultiplayerSpawn.git synced 2025-01-05 22:53:48 +02:00

Reverting regrowth back into a soft mod. Cleaning up and tweaking the example config.

This commit is contained in:
Oarcinae 2019-09-24 09:50:48 -05:00
parent 5fa7d4bd51
commit d7b7dca750
8 changed files with 459 additions and 20 deletions

View File

@ -33,6 +33,7 @@ require("lib/game_opts")
require("lib/player_list")
require("lib/rocket_launch")
require("lib/admin_commands")
require("lib/regrowth_map")
-- For Philip. I currently do not use this and need to add proper support for
-- commands like this in the future.
@ -55,6 +56,18 @@ require("lib/oarc_gui_tabs")
GAME_SURFACE_NAME="oarc"
-- I'm reverting my decision to turn the regrowth thing into a mod.
remote.add_interface("oarc_regrowth",
{area_offlimits_chunkpos = MarkAreaSafeGivenChunkPos,
area_offlimits_tilepos = MarkAreaSafeGivenTilePos,
area_removal_tilepos = MarkAreaForRemoval,
trigger_immediate_cleanup = TriggerCleanup,
add_surface = RegrowthAddSurface})
commands.add_command("trigger-map-cleanup",
"Force immediate removal of all expired chunks (unused chunk removal mod)",
ForceRemoveChunksCmd)
--------------------------------------------------------------------------------
-- ALL EVENT HANLDERS ARE HERE IN ONE PLACE!
--------------------------------------------------------------------------------
@ -68,6 +81,9 @@ script.on_init(function(event)
-- FIRST
InitOarcConfig()
-- Regrowth (always init so we can enable during play.)
RegrowthInit()
-- Create new game surface
CreateGameSurface()
@ -102,6 +118,9 @@ end)
----------------------------------------
script.on_event(defines.events.on_chunk_generated, function(event)
if global.ocfg.enable_regrowth then
RegrowthChunkGenerate(event)
end
if global.ocfg.enable_undecorator then
UndecorateOnChunkGenerate(event)
end
@ -201,6 +220,14 @@ script.on_event(defines.events.on_built_entity, function(event)
Autofill(event)
end
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
GAME_SURFACE_NAME,
event.created_entity.position,
2)
end
if ENABLE_ANTI_GRIEFING then
SetItemBlueprintTimeToLive(event)
end
@ -217,9 +244,15 @@ end)
-- place items that don't count as player_built and robot_built.
-- Specifically FARL.
----------------------------------------
-- script.on_event(defines.events.script_raised_built, function(event)
-- end)
script.on_event(defines.events.script_raised_built, function(event)
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
GAME_SURFACE_NAME,
event.entity.position,
2)
end
end)
----------------------------------------
@ -227,6 +260,10 @@ end)
-- Delayed events, delayed spawns, ...
----------------------------------------
script.on_event(defines.events.on_tick, function(event)
if global.ocfg.enable_regrowth then
RegrowthOnTick()
RegrowthForceRemovalOnTick()
end
DelayedSpawnOnTick()
@ -237,6 +274,11 @@ script.on_event(defines.events.on_tick, function(event)
end)
script.on_event(defines.events.on_sector_scanned, function (event)
if global.ocfg.enable_regrowth then
RegrowthSectorScan(event)
end
end)
-- script.on_event(defines.events.on_sector_scanned, function (event)
-- end)
@ -245,6 +287,13 @@ end)
--
----------------------------------------
script.on_event(defines.events.on_robot_built_entity, function (event)
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
GAME_SURFACE_NAME,
event.created_entity.position,
2)
end
if global.ocfg.frontier_rocket_silo then
BuildSiloAttempt(event)
end

View File

@ -1,5 +1,5 @@
-- example-config.lua (Rename this file to config.lua to use it)
-- July 24 2019 (updated on)
-- Sep 24 2019 (updated on)
-- Configuration Options
--
-- You should be able to leave most of the settings here as defaults.
@ -8,7 +8,6 @@
--------------------------------------------------------------------------------
-- Messages
-- You will want to change some of these to be your own.
-- Make sure SERVER_OWNER_IS_OARC = false
--------------------------------------------------------------------------------
-- This stuff is shown in the welcome GUI and Info panel. Make sure it's valid.
@ -18,7 +17,7 @@ SERVER_MSG = "Rules: Be polite. Ask before changing other players's stuff. Have
"This server is running a custom scenario that allows individual starting areas on the map."
SCENARIO_INFO_MSG = "Latest updates in this scenario version:\n"..
"0.17 experimental release. New fixes, tweaks and features!\n"..
"0.17 stable release. Regrowth back to softmod!\n"..
"This scenario gives you and/or your friends your own starting area.\n"..
"You can be on the main team or your own. All teams are friendly.\n"..
"If you leave in the first 15 minutes, your base and character will be deleted!"
@ -63,7 +62,7 @@ ENABLE_LONGREACH = true
ENABLE_AUTOFILL = true
-- Enable vanilla loaders
ENABLE_LOADERS = false
ENABLE_LOADERS = true
-- Enable Playerlist
ENABLE_PLAYER_LIST = true
@ -72,8 +71,11 @@ PLAYER_LIST_OFFLINE_PLAYERS = true -- List offline players as well.
-- Enable shared vision between teams (all teams are COOP regardless)
ENABLE_SHARED_TEAM_VISION = true
-- Cleans up unused chunks periodically. Helps keep map size down.
ENABLE_REGROWTH = true
-- Only works if you have the Unused Chunk Removal mod installed.
ENABLE_ABANDONED_BASE_REMOVAL = false
ENABLE_ABANDONED_BASE_REMOVAL = true
-- Enable the new 0.17 research queue by default for all forces.
ENABLE_RESEARCH_QUEUE = true
@ -205,18 +207,18 @@ OARC_CFG = {
{
-- Safe area has no aliens
-- This is the radius in tiles of safe area.
safe_radius = CHUNK_SIZE*20,
safe_radius = CHUNK_SIZE*8,
-- Warning area has significantly reduced aliens
-- This is the radius in tiles of warning area.
warn_radius = CHUNK_SIZE*30,
warn_radius = CHUNK_SIZE*16,
-- 1 : X (spawners alive : spawners destroyed) in this area
warn_reduction = 20,
-- Danger area has slightly reduce aliens
-- This is the radius in tiles of danger area.
danger_radius = CHUNK_SIZE*50,
danger_radius = CHUNK_SIZE*32,
-- 1 : X (spawners alive : spawners destroyed) in this area
danger_reduction = 5,
@ -253,7 +255,7 @@ OARC_CFG = {
{
["iron-ore"] =
{
amount = 1500,
amount = 1800,
size = 16,
x_offset = -29,
y_offset = 16
@ -337,7 +339,7 @@ MAIN_FORCE = "Main Force"
-- Enable if players can allow others to join their base.
-- And specify how many including the host are allowed.
ENABLE_SHARED_SPAWNS = true
MAX_PLAYERS_AT_SHARED_SPAWN = 0
MAX_PLAYERS_AT_SHARED_SPAWN = 3
-- Share local team chat with all teams
-- This makes it so you don't have to use /s
@ -405,11 +407,13 @@ AUTOFILL_TURRET_AMMO_QUANTITY = 10
-- ANTI-Griefing stuff ( I don't personally maintain this as I don't care for it.)
-- These things were added from other people's requests/changes and are disabled by default.
--------------------------------------------------------------------------------
-- Enable this to disable some basic things like friendly fire, deconstructing from map view, etc.
ENABLE_ANTI_GRIEFING = true
-- Enable this to disable deconstructing from map view, and setting a time limit
-- on ghost placements.
ENABLE_ANTI_GRIEFING = false
-- Makes blueprint ghosts dissapear if they have been placed longer than this
GHOST_TIME_TO_LIVE = 0 * TICKS_PER_MINUTE -- set to 0 for infinite ghost life
-- ONLY has an effect if ENABLE_ANTI_GRIEFING is true!
GHOST_TIME_TO_LIVE = 10 * TICKS_PER_MINUTE
--------------------------------------------------------------------------------
-- This turns on writing chat and certain events to specific files so that I can

View File

@ -127,7 +127,7 @@ local function CreateRocketSilo(surface, siloPosition, force)
icon={type="item",name="rocket-silo"}})
-- Make silo safe from being removed.
if (game.active_mods["unused-chunk-removal"]) then
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth",
"area_offlimits_tilepos",
surface.index,

View File

@ -80,6 +80,9 @@ function CreateGameOptionsTab(tab_container, player)
if (global.ocfg.enable_player_list) then
soft_mods_string = soft_mods_string .. ", Player List"
end
if (global.ocfg.enable_regrowth) then
soft_mods_string = soft_mods_string .. ", Regrowth"
end
local game_info_str = "Soft Mods Enabled: " .. soft_mods_string
@ -104,7 +107,7 @@ function CreateGameOptionsTab(tab_container, player)
if (global.ocfg.frontier_rocket_silo) then
game_info_str = game_info_str.."\n".."Silos are only placeable in certain areas on the map!"
end
if (game.active_mods["unused-chunk-removal"]) then
if (global.ocfg.enable_regrowth) then
game_info_str = game_info_str.."\n".."Old parts of the map will slowly be deleted over time (chunks without any player buildings)."
end
if (ENABLE_POWER_ARMOR_QUICK_START) then

View File

@ -38,6 +38,7 @@ function InitOarcConfig()
global.ocfg.enable_player_list = ENABLE_PLAYER_LIST
global.ocfg.list_offline_players = PLAYER_LIST_OFFLINE_PLAYERS
global.ocfg.enable_shared_team_vision = ENABLE_SHARED_TEAM_VISION
global.ocfg.enable_regrowth = ENABLE_REGROWTH
global.ocfg.enable_abandoned_base_removal = ENABLE_ABANDONED_BASE_REMOVAL
global.ocfg.enable_research_queue = ENABLE_RESEARCH_QUEUE
global.ocfg.lock_goodies_rocket_launch = LOCK_GOODIES_UNTIL_ROCKET_LAUNCH

View File

@ -481,7 +481,7 @@ function CreateGameSurface()
local s = game.create_surface(GAME_SURFACE_NAME, nauvis_settings)
-- Add surface and safe areas
if (game.active_mods["unused-chunk-removal"]) then
if global.ocfg.enable_regrowth then
remote.call("oarc_regrowth", "add_surface", s.index)
remote.call("oarc_regrowth", "area_offlimits_chunkpos", s.index, {x=0,y=0}, 10)
end

382
lib/regrowth_map.lua Normal file
View File

@ -0,0 +1,382 @@
-- regrowth_map.lua
-- Sep 2019
-- REVERTED BACK TO SOFT MOD
-- Code tracks all chunks generated and allows for deleting of inactive chunks.
--
-- Basic rules of regrowth:
-- 1. Area around player is safe for quite a large distance.
-- 2. Chunks with pollution won't be deleted.
-- 3. Chunks with any player buildings won't be deleted.
-- 4. 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.
-- 5. Chunks timeout after 1 hour-ish, configurable
require("lib/oarc_utils")
require("config")
REGROWTH_TIMEOUT_TICKS = TICKS_PER_HOUR
-- Init globals and set player join area to be off limits.
function RegrowthInit()
if (global.rg == nil) then
global.rg = {}
global.rg.surfaces_index = 1
global.rg.player_refresh_index = 1
global.rg.force_removal_flag = -1000
global.rg.active_surfaces = {}
end
end
function TriggerCleanup()
global.rg.force_removal_flag = game.tick
end
function ForceRemoveChunksCmd(cmd_table)
if (game.players[cmd_table.player_index].admin) then
TriggerCleanup()
end
end
function RegrowthAddSurface(s_index)
RegrowthInit()
if (global.rg[s_index] ~= nil) then
log("ERROR - Tried to add surface that was already added?")
return
end
log("Oarc Regrowth - ADD SURFACE " .. game.surfaces[s_index].name)
global.rg[s_index] = {}
table.insert(global.rg.active_surfaces, s_index)
global.rg[s_index].map = {}
global.rg[s_index].removal_list = {}
global.rg[s_index].min_x = 0
global.rg[s_index].max_x = 0
global.rg[s_index].x_index = 0
global.rg[s_index].min_y = 0
global.rg[s_index].max_y = 0
global.rg[s_index].y_index = 0
-- MarkAreaSafeGivenTilePos({x=0,y=0}, 10)
end
-- 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...)
function RegrowthChunkGenerate(event)
local s_index = event.surface.index
local c_pos = GetChunkPosFromTilePos(event.area.left_top)
-- Surface must be "added" first.
if (global.rg[s_index] == nil) then return end
-- If this is the first chunk in that row:
if (global.rg[s_index].map[c_pos.x] == nil) then
global.rg[s_index].map[c_pos.x] = {}
end
-- Confirm the chunk doesn't already have a value set:
if (global.rg[s_index].map[c_pos.x][c_pos.y] == nil) then
global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick
end
-- Store min/max values for x/y dimensions:
if (c_pos.x < global.rg[s_index].min_x) then
global.rg[s_index].min_x = c_pos.x
end
if (c_pos.x > global.rg[s_index].max_x) then
global.rg[s_index].max_x = c_pos.x
end
if (c_pos.y < global.rg[s_index].min_y) then
global.rg[s_index].min_y = c_pos.y
end
if (c_pos.y > global.rg[s_index].max_y) then
global.rg[s_index].max_y = c_pos.y
end
end
-- Mark an area for "immediate" forced removal
function MarkAreaForRemoval(s_index, pos, chunk_radius)
local c_pos = GetChunkPosFromTilePos(pos)
for i=-chunk_radius,chunk_radius do
for k=-chunk_radius,chunk_radius do
local x = c_pos.x+i
local y = c_pos.y+k
if (global.rg[s_index].map[x] == nil) then
global.rg[s_index].map[x] = {}
end
global.rg[s_index].map[x][y] = nil
table.insert(global.rg[s_index].removal_list,
{pos={x=x,y=y},force=true})
end
end
end
-- Marks a chunk containing a position that won't ever be deleted.
function MarkChunkSafe(s_index, c_pos)
if (global.rg[s_index].map[c_pos.x] == nil) then
global.rg[s_index].map[c_pos.x] = {}
end
global.rg[s_index].map[c_pos.x][c_pos.y] = -1
end
-- Marks a safe area around a TILE position that won't ever be deleted.
function MarkAreaSafeGivenTilePos(s_index, pos, chunk_radius)
if (global.rg[s_index] == nil) then return end
local c_pos = GetChunkPosFromTilePos(pos)
MarkAreaSafeGivenChunkPos(s_index, c_pos, chunk_radius)
end
-- Marks a safe area around a CHUNK position that won't ever be deleted.
function MarkAreaSafeGivenChunkPos(s_index, c_pos, chunk_radius)
if (global.rg[s_index] == nil) then return end
for i=-chunk_radius,chunk_radius do
for j=-chunk_radius,chunk_radius do
MarkChunkSafe(s_index, {x=c_pos.x+i,y=c_pos.y+j})
end
end
end
-- Refreshes timers on a chunk containing position
function RefreshChunkTimer(s_index, pos, bonus_time)
local c_pos = GetChunkPosFromTilePos(pos)
if (global.rg[s_index].map[c_pos.x] == nil) then
global.rg[s_index].map[c_pos.x] = {}
end
if (global.rg[s_index].map[c_pos.x][c_pos.y] ~= -1) then
global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick + bonus_time
end
end
-- Forcefully refreshes timers on a chunk containing position
-- Will overwrite -1 flag.
-- function OarcRegrowthForceRefreshChunk(s_index, pos, bonus_time)
-- local c_pos = GetChunkPosFromTilePos(pos)
-- if (global.rg[s_index].map[c_pos.x] == nil) then
-- global.rg[s_index].map[c_pos.x] = {}
-- end
-- global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick + bonus_time
-- end
-- Refreshes timers on all chunks around a certain area
function RefreshArea(s_index, pos, chunk_radius, bonus_time)
local c_pos = GetChunkPosFromTilePos(pos)
for i=-chunk_radius,chunk_radius do
for k=-chunk_radius,chunk_radius do
local x = c_pos.x+i
local y = c_pos.y+k
if (global.rg[s_index].map[x] == nil) then
global.rg[s_index].map[x] = {}
end
if (global.rg[s_index].map[x][y] ~= -1) then
global.rg[s_index].map[x][y] = game.tick + bonus_time
end
end
end
end
-- Refreshes timers on all chunks near an ACTIVE radar
function RegrowthSectorScan(event)
local s_index = event.radar.surface.index
if (global.rg[s_index] == nil) then return end
RefreshArea(s_index, event.radar.position, 14, 0)
RefreshChunkTimer(s_index, event.chunk_position, 0)
end
-- Refresh all chunks near a single player. Cyles through all connected players.
function RefreshPlayerArea()
global.rg.player_refresh_index = global.rg.player_refresh_index + 1
if (global.rg.player_refresh_index > #game.connected_players) then
global.rg.player_refresh_index = 1
end
if (game.connected_players[global.rg.player_refresh_index]) then
local player = game.connected_players[global.rg.player_refresh_index]
if (not player.character) then return end
local s_index = player.character.surface.index
if (global.rg[s_index] == nil) then return end
RefreshArea(s_index, player.position, 4, 0)
end
end
-- Gets the next chunk the array map and checks to see if it has timed out.
-- Adds it to the removal list if it has.
function RegrowthSingleStepArray(s_index)
-- Increment X and reset when we hit the end.
if (global.rg[s_index].x_index > global.rg[s_index].max_x) then
global.rg[s_index].x_index = global.rg[s_index].min_x
-- Increment Y and reset when we hit the end.
if (global.rg[s_index].y_index > global.rg[s_index].max_y) then
global.rg[s_index].y_index = global.rg[s_index].min_y
-- log("Finished checking regrowth array. "..
-- game.surfaces[s_index].name.." "..
-- global.rg[s_index].min_x.." "..
-- global.rg[s_index].max_x.." "..
-- global.rg[s_index].min_y.." "..
-- global.rg[s_index].max_y)
else
global.rg[s_index].y_index = global.rg[s_index].y_index + 1
end
else
global.rg[s_index].x_index = global.rg[s_index].x_index + 1
end
local xidx = global.rg[s_index].x_index
local yidx = global.rg[s_index].y_index
if (not xidx or not yidx) then
log("ERROR - xidx or yidx is nil?")
end
-- Check row exists, otherwise make one.
if (global.rg[s_index].map[xidx] == nil) then
global.rg[s_index].map[xidx] = {}
end
-- If the chunk has timed out, add it to the removal list
local c_timer = global.rg[s_index].map[xidx][yidx]
if ((c_timer ~= nil) and (c_timer ~= -1) and
((c_timer + REGROWTH_TIMEOUT_TICKS) < game.tick)) then
-- Check chunk actually exists
if (game.surfaces[s_index].is_chunk_generated({x=xidx, y=yidx})) then
table.insert(global.rg[s_index].removal_list, {pos={x=xidx,
y=yidx},
force=false})
global.rg[s_index].map[xidx][yidx] = nil
end
end
end
-- Remove all chunks at same time to reduce impact to FPS/UPS
function OarcRegrowthRemoveAllChunks()
for _,s_index in pairs(global.rg.active_surfaces) do
print(k,v)
while (#global.rg[s_index].removal_list > 0) do
local c_remove = table.remove(global.rg[s_index].removal_list)
local c_pos = c_remove.pos
local c_timer = global.rg[s_index].map[c_pos.x][c_pos.y]
if (game.surfaces[s_index] == nil) then
log("Error! game.surfaces[name] is nil?? WTF?")
return
end
-- Confirm chunk is still expired
if (c_timer == nil) then
-- If it is FORCE removal, then remove it regardless of pollution.
if (c_remove.force) then
game.surfaces[s_index].delete_chunk(c_pos)
global.rg[s_index].map[c_pos.x][c_pos.y] = nil
-- If it is a normal timeout removal, don't do it if there is pollution in the chunk.
elseif (game.surfaces[s_index].get_pollution({c_pos.x*32,c_pos.y*32}) > 0) then
global.rg[s_index].map[c_pos.x][c_pos.y] = game.tick
-- Else delete the chunk
else
game.surfaces[s_index].delete_chunk(c_pos)
global.rg[s_index].map[c_pos.x][c_pos.y] = nil
end
end
end
end
end
-- 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 RegrowthOnTick()
if (#global.rg.active_surfaces == 0) then return end
-- 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
RefreshPlayerArea()
end
-- Iterate through the active surfaces.
if (global.rg.surfaces_index > #global.rg.active_surfaces) then
global.rg.surfaces_index = 1
end
local s_index = global.rg.active_surfaces[global.rg.surfaces_index]
global.rg.surfaces_index = global.rg.surfaces_index+1
if (s_index == nil) then
log("ERROR - s_index = nil in OarcRegrowthOnTick?")
return
end
-- Every tick, check a few points in the 2d array of one of the active surfaces
-- According to /measured-command this shouldn't take more
-- than 0.1ms on average
for i=1,20 do
RegrowthSingleStepArray(s_index)
end
-- Allow enable/disable of auto cleanup, can change during runtime.
if (global.ocfg.enable_regrowth) then
local interval_ticks = REGROWTH_TIMEOUT_TICKS
-- Send a broadcast warning before it happens.
if ((game.tick % interval_ticks) == interval_ticks-601) then
if (#global.rg[s_index].removal_list > 100) then
SendBroadcastMsg("Map cleanup in 10 seconds... Unused and old map chunks will be deleted!")
end
end
-- Delete all listed chunks across all active surfaces
if ((game.tick % interval_ticks) == interval_ticks-1) then
if (#global.rg[s_index].removal_list > 100) then
OarcRegrowthRemoveAllChunks()
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
end
end
end
end
-- This function removes any chunks flagged but on demand.
-- Controlled by the global.rg.force_removal_flag
-- This function may be used outside of the normal regrowth modse.
function RegrowthForceRemovalOnTick()
-- Catch force remove flag
if (game.tick == global.rg.force_removal_flag+60) then
SendBroadcastMsg("Map cleanup (forced) in 10 seconds... Unused and old map chunks will be deleted!")
end
if (game.tick == global.rg.force_removal_flag+660) then
OarcRegrowthRemoveAllChunks()
SendBroadcastMsg("Map cleanup done, sorry for your loss.")
end
end
-- Broadcast messages to all connected players
function SendBroadcastMsg(msg)
for name,player in pairs(game.connected_players) do
player.print(msg)
end
end
-- Gets chunk position of a tile.
function GetChunkPosFromTilePos(tile_pos)
return {x=math.floor(tile_pos.x/32), y=math.floor(tile_pos.y/32)}
end

View File

@ -121,7 +121,7 @@ function FindUnusedSpawns(player, remove_player)
-- Unused Chunk Removal mod (aka regrowth)
if (global.ocfg.enable_abandoned_base_removal and
(not nearOtherSpawn) and
game.active_mods["unused-chunk-removal"]) then
global.ocfg.enable_regrowth) then
if (global.uniqueSpawns[player.name].vanilla) then
log("Returning a vanilla spawn back to available.")