You've already forked ComfyFactorio
mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2026-04-26 21:02:59 +02:00
686 lines
21 KiB
Lua
686 lines
21 KiB
Lua
local Global = require 'utils.global'
|
|
local Task = require 'utils.task'
|
|
local Token = require 'utils.token'
|
|
local Event = require 'utils.event'
|
|
local Alert = require 'utils.alert'
|
|
local Surface = require 'utils.surface'
|
|
local Commands = require 'utils.commands'
|
|
|
|
local this =
|
|
{
|
|
settings =
|
|
{
|
|
player_refresh_index = nil,
|
|
force_removal_flag = -2000,
|
|
chunk_iter = nil,
|
|
world_eater_iter = nil,
|
|
timeout_ticks = 216000,
|
|
enabled = false,
|
|
remover_disabled = false,
|
|
_debug = false,
|
|
task_remover = false,
|
|
pollution_enabled = false
|
|
},
|
|
list =
|
|
{
|
|
map = {},
|
|
removal_list = {}
|
|
}
|
|
}
|
|
|
|
Global.register(
|
|
this,
|
|
function (tbl)
|
|
this = tbl
|
|
end
|
|
)
|
|
|
|
local cleaner = '[color=blue]Cleaner:[/color] '
|
|
local floor = math.floor
|
|
|
|
local Public = {}
|
|
|
|
local clear_chunk_token =
|
|
Token.register(
|
|
function (event)
|
|
local chunk = event.chunk
|
|
if not chunk then
|
|
return
|
|
end
|
|
|
|
local surface = game.get_surface(event.surface_index)
|
|
if not surface or not surface.valid then
|
|
return
|
|
end
|
|
|
|
if chunk and #chunk > 2 then
|
|
for _, c in pairs(chunk) do
|
|
surface.delete_chunk(c)
|
|
end
|
|
else
|
|
surface.delete_chunk(chunk)
|
|
end
|
|
end
|
|
)
|
|
|
|
local function debug(str)
|
|
if this.settings._debug then
|
|
print(str)
|
|
end
|
|
end
|
|
|
|
local function notify_all_players(msg)
|
|
local color = { r = 0, g = 255, b = 171 }
|
|
local players = game.connected_players
|
|
for i = 1, #players do
|
|
local player = players[i]
|
|
Alert.alert_player(player, 10, msg, color)
|
|
end
|
|
end
|
|
|
|
local function chunk_from_tile_pos(pos)
|
|
return { x = floor(pos.x / 32), y = floor(pos.y / 32) }
|
|
end
|
|
|
|
local function get_next_player()
|
|
if (not this.settings.player_refresh_index or not game.players[this.settings.player_refresh_index]) then
|
|
this.settings.player_refresh_index = 1
|
|
else
|
|
this.settings.player_refresh_index = this.settings.player_refresh_index + 1
|
|
end
|
|
|
|
if (this.settings.player_refresh_index > #game.players) then
|
|
this.settings.player_refresh_index = 1
|
|
end
|
|
|
|
return this.settings.player_refresh_index
|
|
end
|
|
|
|
local function chunk_is_safe(c_pos, permanent)
|
|
if (this.list.map[c_pos.x] == nil) then
|
|
this.list.map[c_pos.x] = {}
|
|
end
|
|
|
|
if (permanent) then
|
|
-- Make sure we don't overwrite...
|
|
this.list.map[c_pos.x][c_pos.y] = -2
|
|
elseif (this.list.map[c_pos.x][c_pos.y] and (this.list.map[c_pos.x][c_pos.y] ~= -2)) then
|
|
this.list.map[c_pos.x][c_pos.y] = -1
|
|
end
|
|
end
|
|
|
|
local function area_is_safe(c_pos, chunk_radius, permanent)
|
|
for i = -chunk_radius, chunk_radius do
|
|
for j = -chunk_radius, chunk_radius do
|
|
chunk_is_safe({ x = c_pos.x + i, y = c_pos.y + j }, permanent)
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Refreshes timers on all chunks around a certain area
|
|
local function refresh_area(pos, chunk_radius, bonus_time)
|
|
local c_pos = chunk_from_tile_pos(pos)
|
|
if not c_pos then
|
|
return
|
|
end
|
|
|
|
for i = -chunk_radius, chunk_radius do
|
|
local x = c_pos.x + i
|
|
for k = -chunk_radius, chunk_radius do
|
|
local y = c_pos.y + k
|
|
|
|
if (this.list.map[x] == nil) then
|
|
this.list.map[x] = {}
|
|
end
|
|
if ((this.list.map[x][y] == nil) or (this.list.map[x][y] >= 0)) then
|
|
this.list.map[x][y] = game.tick + bonus_time
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Refresh all chunks near a single player. Cyles through all connected players.
|
|
local function refresh_player_area()
|
|
local player_index = get_next_player()
|
|
if (player_index and game.connected_players[player_index]) then
|
|
local player = game.connected_players[player_index]
|
|
|
|
if (not player.character) then
|
|
return
|
|
end
|
|
|
|
local this_surface_index = Surface.get_surface_index()
|
|
|
|
if (player.surface.index ~= this_surface_index) then
|
|
return
|
|
end
|
|
|
|
refresh_area(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.
|
|
local function get_next_chunk()
|
|
local this_surface_index = Surface.get_surface_index()
|
|
local surface = game.get_surface(this_surface_index)
|
|
if not surface or not surface.valid then
|
|
debug('get_next_chunk - Surface was not valid?')
|
|
return
|
|
end
|
|
|
|
-- Make sure we have a valid iterator!
|
|
if (not this.settings.chunk_iter or not this.settings.chunk_iter.valid) then
|
|
this.settings.chunk_iter = surface.get_chunks()
|
|
end
|
|
|
|
local next_chunk = this.settings.chunk_iter()
|
|
|
|
-- Check if we reached the end
|
|
if (not next_chunk) then
|
|
this.settings.chunk_iter = surface.get_chunks()
|
|
next_chunk = this.settings.chunk_iter()
|
|
end
|
|
|
|
-- Do we have it in our map?
|
|
if (not this.list.map[next_chunk.x] or not this.list.map[next_chunk.x][next_chunk.y]) then
|
|
return -- Chunk isn't in our map so we don't care?
|
|
end
|
|
|
|
-- If the chunk has timed out, add it to the removal list
|
|
local c_timer = this.list.map[next_chunk.x][next_chunk.y]
|
|
if ((c_timer ~= nil) and (c_timer >= 0) and ((c_timer + this.settings.timeout_ticks) < game.tick)) then
|
|
-- Check chunk actually exists
|
|
if (surface.is_chunk_generated({ x = next_chunk.x, y = next_chunk.y })) then
|
|
this.list.removal_list[#this.list.removal_list + 1] = { pos = { x = next_chunk.x, y = next_chunk.y }, force = false }
|
|
this.list.map[next_chunk.x][next_chunk.y] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Remove all chunks at same time to reduce impact to FPS/UPS
|
|
local function try_remove_chunks()
|
|
local this_surface_index = Surface.get_surface_index()
|
|
local surface = game.get_surface(this_surface_index)
|
|
if not surface or not surface.valid then
|
|
debug('try_remove_chunks - Surface was not valid?')
|
|
return
|
|
end
|
|
local tick = 5
|
|
|
|
for key, c_remove in pairs(this.list.removal_list) do
|
|
tick = tick + 6
|
|
local c_pos = c_remove.pos
|
|
|
|
-- Confirm chunk is still expired
|
|
if (not this.list.map[c_pos.x] or not this.list.map[c_pos.x][c_pos.y]) then
|
|
-- If it is FORCE removal, then remove it regardless of pollution.
|
|
if (c_remove.force) then
|
|
-- If it is a normal timeout removal, don't do it if there is pollution in the chunk.
|
|
if not this.settings.task_remover then
|
|
surface.delete_chunk(c_pos)
|
|
else
|
|
Task.set_timeout_in_ticks(tick, clear_chunk_token, { chunk = c_pos, surface_index = surface.index })
|
|
end
|
|
elseif this.settings.pollution_enabled and (surface.get_pollution({ c_pos.x * 32, c_pos.y * 32 }) > 0) then
|
|
-- Else delete the chunk
|
|
this.list.map[c_pos.x][c_pos.y] = game.tick
|
|
else
|
|
if not this.settings.task_remover then
|
|
surface.delete_chunk(c_pos)
|
|
else
|
|
Task.set_timeout_in_ticks(tick, clear_chunk_token, { chunk = c_pos, surface_index = surface.index })
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Remove entry
|
|
this.list.removal_list[key] = nil
|
|
end
|
|
|
|
-- MUST GET A NEW CHUNK ITERATOR ON DELETE CHUNK!
|
|
this.settings.chunk_iter = nil
|
|
this.settings.world_eater_iter = nil
|
|
end
|
|
|
|
local function remove_chunks()
|
|
local this_surface_index = Surface.get_surface_index()
|
|
local surface = game.get_surface(this_surface_index)
|
|
if not surface or not surface.valid then
|
|
debug('remove_chunks - Surface was not valid?')
|
|
return
|
|
end
|
|
|
|
-- Make sure we have a valid iterator!
|
|
if (not this.settings.world_eater_iter or not this.settings.world_eater_iter.valid) then
|
|
this.settings.world_eater_iter = surface.get_chunks()
|
|
end
|
|
|
|
local next_chunk = this.settings.world_eater_iter()
|
|
|
|
-- Check if we reached the end
|
|
if (not next_chunk) then
|
|
this.settings.world_eater_iter = surface.get_chunks()
|
|
next_chunk = this.settings.world_eater_iter()
|
|
end
|
|
|
|
-- Do we have it in our map?
|
|
if (not this.list.map[next_chunk.x] or not this.list.map[next_chunk.x][next_chunk.y]) then
|
|
return -- Chunk isn't in our map so we don't care?
|
|
end
|
|
-- If the chunk isn't marked permament, then check if we can remove it
|
|
local c_timer = this.list.map[next_chunk.x][next_chunk.y]
|
|
if (c_timer == -1) then
|
|
local area =
|
|
{
|
|
left_top = { next_chunk.area.left_top.x - 8, next_chunk.area.left_top.y - 8 },
|
|
right_bottom = { next_chunk.area.right_bottom.x + 8, next_chunk.area.right_bottom.y + 8 }
|
|
}
|
|
|
|
local ents = surface.find_entities_filtered { area = area, force = { 'enemy', 'neutral' }, invert = true }
|
|
local total_count = #ents
|
|
local has_last_user_set = false
|
|
|
|
local t_type =
|
|
{
|
|
['character'] = true,
|
|
['construction-robot'] = true,
|
|
['logistic-robot'] = true
|
|
}
|
|
|
|
if (total_count > 0) then
|
|
for _, v in pairs(ents) do
|
|
if (v.last_user or t_type[v.type]) then
|
|
has_last_user_set = true
|
|
break -- This means we're done checking this chunk.
|
|
end
|
|
end
|
|
|
|
-- If all entities found have no last user, then KILL all entities!
|
|
if not has_last_user_set then
|
|
for _, v in pairs(ents) do
|
|
if (v and v.valid) then
|
|
v.die(nil)
|
|
end
|
|
end
|
|
-- notify_all_players(cleaner .. next_chunk.x .. "," .. next_chunk.y .. " WorldEaterSingleStep - ENTITIES FOUND")
|
|
this.list.map[next_chunk.x][next_chunk.y] = game.tick -- Set the timer on it.
|
|
end
|
|
else
|
|
-- notify_all_players(cleaner .. next_chunk.x .. "," .. next_chunk.y .. " WorldEaterSingleStep - NO ENTITIES FOUND")
|
|
this.list.map[next_chunk.x][next_chunk.y] = game.tick -- Set the timer on it.
|
|
end
|
|
end
|
|
end
|
|
|
|
|
|
local function remove_chunks_forced()
|
|
local this_surface_index = Surface.get_surface_index()
|
|
local surface = game.get_surface(this_surface_index)
|
|
if not surface or not surface.valid then
|
|
debug('remove_chunks_forced - Surface was not valid?')
|
|
return
|
|
end
|
|
|
|
notify_all_players(cleaner .. 'Manual map cleanup in progress - forced!')
|
|
|
|
local chunks = surface.get_chunks()
|
|
local tick = 0
|
|
|
|
local chunks_to_remove = {}
|
|
|
|
for chunk in chunks do
|
|
local can_delete = true
|
|
-- Do we have it in our map?
|
|
if surface.is_chunk_generated(chunk) then
|
|
local area =
|
|
{
|
|
left_top = { chunk.area.left_top.x - 64, chunk.area.left_top.y - 64 },
|
|
right_bottom = { chunk.area.right_bottom.x + 64, chunk.area.right_bottom.y + 64 }
|
|
}
|
|
|
|
local ents = surface.find_entities_filtered { area = area, force = { 'neutral', 'enemy' }, invert = true }
|
|
local total_count = #ents
|
|
|
|
if (total_count > 0) then
|
|
for _, v in pairs(ents) do
|
|
if (v.last_user) then
|
|
can_delete = false
|
|
end
|
|
if v.type == 'character' then
|
|
can_delete = false
|
|
end
|
|
end
|
|
|
|
if can_delete then
|
|
chunks_to_remove[#chunks_to_remove + 1] = chunk
|
|
-- Task.set_timeout_in_ticks(tick, clear_chunk_token, { chunk = chunk, surface_index = surface.index })
|
|
-- surface.delete_chunk(chunk)
|
|
end
|
|
else
|
|
-- surface.delete_chunk(chunk)
|
|
chunks_to_remove[#chunks_to_remove + 1] = chunk
|
|
-- Task.set_timeout_in_ticks(tick, clear_chunk_token, { chunk = chunk, surface_index = surface.index })
|
|
end
|
|
end
|
|
|
|
if chunks_to_remove and #chunks_to_remove >= 10 then
|
|
tick = tick + 2
|
|
Task.set_timeout_in_ticks(tick, clear_chunk_token,
|
|
{ chunk = chunks_to_remove, surface_index = surface.index })
|
|
|
|
chunks_to_remove = {}
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Marks a safe area around a TILE position to be relatively permanent.
|
|
local function mark_area_safe_tiles(pos, chunk_radius, permanent)
|
|
local c_pos = chunk_from_tile_pos(pos)
|
|
if not c_pos then
|
|
return
|
|
end
|
|
|
|
area_is_safe(c_pos, chunk_radius, permanent)
|
|
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.
|
|
local function on_tick()
|
|
local tick = game.tick
|
|
-- Every half a second, refresh all chunks near a single player
|
|
-- Cyles through all players. Tick is offset by 2
|
|
if ((tick % (30)) == 2) then
|
|
refresh_player_area()
|
|
end
|
|
|
|
-- Catch force remove flag
|
|
if (tick == this.settings.force_removal_flag + 60) then
|
|
notify_all_players(cleaner .. 'Manual map cleanup in progress!')
|
|
end
|
|
|
|
if (tick == this.settings.force_removal_flag + (60 * 30 + 60)) then
|
|
try_remove_chunks()
|
|
notify_all_players(cleaner .. 'Manual map cleanup done.')
|
|
return
|
|
end
|
|
|
|
-- Every tick, check a few points in the 2d array of the only active surface According to /measured-command this
|
|
-- shouldn't take more than 0.1ms on average
|
|
for _ = 1, 20 do
|
|
get_next_chunk()
|
|
end
|
|
|
|
if (not this.settings.remover_disabled) then
|
|
remove_chunks()
|
|
end
|
|
|
|
-- Allow enable/disable of auto cleanup, can change during runtime.
|
|
local interval_ticks = this.settings.timeout_ticks
|
|
-- Send a broadcast warning before it happens.
|
|
if ((tick % interval_ticks) == interval_ticks - (60 * 30 + 1)) then
|
|
if (#this.list.removal_list > 100) then
|
|
notify_all_players(cleaner .. 'Automated map cleanup in progress!')
|
|
end
|
|
end
|
|
|
|
-- Delete all listed chunks across all active surfaces
|
|
if ((tick % interval_ticks) == interval_ticks - 1) then
|
|
if (#this.list.removal_list > 100) then
|
|
try_remove_chunks()
|
|
notify_all_players(cleaner .. 'Automated map cleanup done.')
|
|
end
|
|
end
|
|
end
|
|
|
|
function Public.on_chunk_generated(event)
|
|
local c_pos = chunk_from_tile_pos(event.area.left_top)
|
|
|
|
-- Surface must be "added" first.
|
|
if (this.settings == nil) then
|
|
return
|
|
end
|
|
|
|
-- If this is the first chunk in that row:
|
|
if (this.list.map[c_pos.x] == nil) then
|
|
this.list.map[c_pos.x] = {}
|
|
end
|
|
|
|
-- Only update it if it isn't already set!
|
|
if (this.list.map[c_pos.x][c_pos.y] == nil) then
|
|
this.list.map[c_pos.x][c_pos.y] = game.tick
|
|
end
|
|
end
|
|
|
|
function Public.trigger()
|
|
this.settings.force_removal_flag = game.tick
|
|
end
|
|
|
|
-- Mark an area for "immediate" forced removal
|
|
function Public.mark_base_for_removal_forced(pos, chunk_radius)
|
|
local c_pos = chunk_from_tile_pos(pos)
|
|
for i = -chunk_radius, chunk_radius do
|
|
local x = c_pos.x + i
|
|
for k = -chunk_radius, chunk_radius do
|
|
local y = c_pos.y + k
|
|
|
|
if (this.list.map[x] ~= nil) then
|
|
this.list.map[x][y] = nil
|
|
end
|
|
this.list.removal_list[#this.list.removal_list + 1] = { pos = { x = x, y = y }, force = true }
|
|
end
|
|
if (table_size(this.list.map[x]) == 0) then
|
|
this.list.map[x] = nil
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Downgrades permanent flag to semi-permanent.
|
|
function Public.mark_base_for_removal_non_forced(pos, chunk_radius)
|
|
local c_pos = chunk_from_tile_pos(pos)
|
|
for i = -chunk_radius, chunk_radius do
|
|
local x = c_pos.x + i
|
|
for k = -chunk_radius, chunk_radius do
|
|
local y = c_pos.y + k
|
|
|
|
if (this.list.map[x] and this.list.map[x][y] and (this.list.map[x][y] == -2)) then
|
|
this.list.map[x][y] = -1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
-- Refreshes timers on a chunk containing position
|
|
function Public.refresh_chunk_timer(pos, bonus_time)
|
|
local c_pos = chunk_from_tile_pos(pos)
|
|
|
|
if (this.list.map[c_pos.x] == nil) then
|
|
this.list.map[c_pos.x] = {}
|
|
end
|
|
if (this.list.map[c_pos.x][c_pos.y] >= 0) then
|
|
this.list.map[c_pos.x][c_pos.y] = game.tick + bonus_time
|
|
end
|
|
end
|
|
|
|
-- Refreshes timers on all chunks near an ACTIVE radar
|
|
function Public.on_sector_scanned(event)
|
|
local this_surface_index = Surface.get_surface_index()
|
|
local radar = event.radar
|
|
local surface = radar.surface
|
|
|
|
if (surface.index ~= this_surface_index) then
|
|
return
|
|
end
|
|
|
|
refresh_area(radar.position, 14, 0)
|
|
end
|
|
|
|
function Public.toggle_chunk_removal(state)
|
|
this.settings.enabled = state or false
|
|
end
|
|
|
|
Event.add(
|
|
defines.events.on_built_entity,
|
|
function (event)
|
|
local entity = event.entity
|
|
if not entity or not entity.valid then
|
|
return
|
|
end
|
|
|
|
if this.settings.enabled then
|
|
local surface_index = Surface.get_surface_index()
|
|
|
|
if entity.surface.index ~= surface_index then
|
|
return
|
|
end
|
|
mark_area_safe_tiles(entity.position, 2, false)
|
|
end
|
|
end
|
|
)
|
|
|
|
Event.add(
|
|
defines.events.on_player_built_tile,
|
|
function (event)
|
|
local surface_index = event.surface_index
|
|
local tiles = event.tiles
|
|
|
|
if this.settings.enabled then
|
|
local this_surface_index = Surface.get_surface_index()
|
|
|
|
if surface_index ~= this_surface_index then
|
|
return
|
|
end
|
|
|
|
for _, tile in pairs(tiles) do
|
|
mark_area_safe_tiles(tile.position, 2, false)
|
|
end
|
|
end
|
|
end
|
|
)
|
|
|
|
Event.add(
|
|
defines.events.script_raised_built,
|
|
function (event)
|
|
local entity = event.entity
|
|
if not entity or not entity.valid then
|
|
return
|
|
end
|
|
|
|
if this.settings.enabled then
|
|
local this_surface_index = Surface.get_surface_index()
|
|
|
|
if entity.surface.index ~= this_surface_index then
|
|
return
|
|
end
|
|
|
|
mark_area_safe_tiles(entity.position, 2, false)
|
|
end
|
|
end
|
|
)
|
|
|
|
Event.add(
|
|
defines.events.on_tick,
|
|
function ()
|
|
if this.settings.enabled then
|
|
on_tick()
|
|
end
|
|
end
|
|
)
|
|
|
|
Event.add(
|
|
defines.events.on_robot_built_entity,
|
|
function (event)
|
|
local entity = event.entity
|
|
if this.settings.enabled then
|
|
local surface_index = Surface.get_surface_index()
|
|
|
|
if (entity.surface.index ~= surface_index) then
|
|
return
|
|
end
|
|
mark_area_safe_tiles(entity.position, 2, false)
|
|
end
|
|
end
|
|
)
|
|
|
|
Event.add(
|
|
defines.events.on_sector_scanned,
|
|
function (event)
|
|
if this.settings.enabled then
|
|
Public.on_sector_scanned(event)
|
|
end
|
|
end
|
|
)
|
|
|
|
Event.on_init(
|
|
function ()
|
|
local position = { x = 0, y = 0 }
|
|
mark_area_safe_tiles(position, 2, true)
|
|
end
|
|
)
|
|
|
|
|
|
Commands.new('chunk_removal_run', 'Chunk removal')
|
|
:require_role('remove_chunks')
|
|
:callback(function (player)
|
|
player.print('[Chunk removal] - Initiated force removal of chunks.')
|
|
remove_chunks_forced()
|
|
end
|
|
)
|
|
|
|
Commands.new('chunk_removal_debug', 'Chunk removal')
|
|
:require_role('remove_chunks')
|
|
:callback(function (player)
|
|
if this.settings._debug then
|
|
this.settings._debug = false
|
|
player.print('[Chunk removal] - Debug messages are now disabled.')
|
|
else
|
|
this.settings._debug = true
|
|
player.print('[Chunk removal] - Debug messages are now enabled.')
|
|
end
|
|
end
|
|
)
|
|
|
|
Commands.new('chunk_removal_toggle_task', 'Chunk removal')
|
|
:require_role('remove_chunks')
|
|
:callback(function (player)
|
|
if this.settings.task_remover then
|
|
this.settings.task_remover = false
|
|
player.print('[Chunk removal] - Tasks are now disabled when removing chunks.')
|
|
else
|
|
this.settings.task_remover = true
|
|
player.print('[Chunk removal] - Tasks are now enabled when removing chunks.')
|
|
end
|
|
end
|
|
)
|
|
|
|
Commands.new('chunk_removal_pollution_enabled', 'Chunk removal')
|
|
:require_role('remove_chunks')
|
|
:callback(function (player)
|
|
if this.settings.pollution_enabled then
|
|
this.settings.pollution_enabled = false
|
|
player.print('[Chunk removal] - Pollution is now disabled when removing chunks.')
|
|
else
|
|
this.settings.pollution_enabled = true
|
|
player.print('[Chunk removal] - Pollution is now enabled when removing chunks.')
|
|
end
|
|
end
|
|
)
|
|
|
|
Commands.new('chunk_removal_enabled', 'Chunk removal')
|
|
:require_role('remove_chunks')
|
|
:callback(function (player)
|
|
if this.settings.enabled then
|
|
this.settings.enabled = false
|
|
player.print('[Chunk removal] - is now disabled.')
|
|
else
|
|
this.settings.enabled = true
|
|
player.print('[Chunk removal] - is now enabled.')
|
|
end
|
|
end
|
|
)
|
|
|
|
Public.mark_area_safe_tiles = mark_area_safe_tiles
|
|
|
|
return Public
|