Added protection control

This commit is contained in:
Cooldude2606
2021-04-24 01:43:58 +01:00
parent f195635dc3
commit 43cb24f396
2 changed files with 158 additions and 7 deletions

19
config/protection.lua Normal file
View File

@@ -0,0 +1,19 @@
return {
ignore_admins = true, --- @setting ignore_admins If admins are ignored by the protection filter
ignore_role = 'Regular', --- @setting ignore_role This role will be ignored by the protection filter, leave nil if expcore.roles is not used
repeat_count = 5, --- @setting repeat_count Number of protected entities to be removed to count as repeated
repeat_lifetime = 3600*20, --- @setting repeat_lifetime How old repeats must be before being removed
refresh_rate = 3600*5, --- @setting refresh_rate How often old repeats will be removed
always_protected_names = { --- @setting always_protected_names Names of entities which are always protected
},
always_protected_types = { --- @setting always_protected_types Types of entities which are always protected
'boiler', 'generator', 'offshore-pump', 'power-switch', 'reactor', 'rocket-silo'
},
skip_repeat_names = { --- @setting skip_repeat_names Names of entities which always trigger protection repeated
},
skip_repeat_types = { --- @setting skip_repeat_types Types of entities which trigger protection repeated
'reactor', 'rocket-silo'
}
}

View File

@@ -6,7 +6,39 @@
local Global = require 'utils.global' --- @dep utils.global
local Event = require 'utils.event' --- @dep utils.event
local EntityProtection = {}
local config = require 'config.protection' --- @dep config.protection
local EntityProtection = {
events = {
--- When a player mines a protected entity
-- @event on_player_mined_protected
-- @tparam number player_index the player index of the player who got mined the entity
-- @tparam LuaEntity entity the entity which was mined
on_player_mined_protected = script.generate_event_name(),
--- When a player mines a many protected entities
-- @event on_repeat_violation
-- @tparam number player_index the player index of the player who got mined the entities
-- @tparam LuaEntity entity the last entity which was mined
on_repeat_violation = script.generate_event_name(),
}
}
-- convert config tables into lookup tables
for _, config_key in ipairs{'always_protected_names', 'always_protected_types', 'skip_repeat_names', 'skip_repeat_types'} do
local tbl = config[config_key]
for key, value in ipairs(tbl) do
tbl[key] = nil
tbl[value] = true
end
end
-- convert ignore role if present
if config.ignore_role then
local Roles = require 'expcore.roles'
local role = Roles.get_role_by_name(config.ignore_role)
config.ignore_role = function(player)
return Roles.player_has_role(player, role)
end
end
----- Global Variables -----
--- Variables stored in the global table
@@ -28,35 +60,135 @@ end)
----- Local Functions -----
--- Functions used internally to search and add to the protected array
--- Get the key used in protected_entities
local function get_entity_key(entity)
return string.format('%i,%i', entity.position.x, entity.position.y)
end
--- Get the key used in protected_areas
local function get_area_key(area)
return string.format('%i,%i', area.left_top.x, area.left_top.y)
end
--- Check if an entity is always protected
local function check_always_protected(entity)
return config.always_protected_names[entity.name] or config.always_protected_types[entity.type] or false
end
--- Check if an entity skips repeated
local function check_skip_repeat(entity)
return config.skip_repeat_names[entity.name] or config.skip_repeat_types[entity.type] or false
end
----- Public Functions -----
--- Functions used to add and remove protected entities
--- Add an entity to the protected list
function EntityProtection.add_entity(entity)
local entities = protected_entities[entity.surface.index]
if not entities then
entities = {}
protected_entities[entity.surface.index] = entities
end
entities[get_entity_key(entity)] = entity
end
--- Remove an entity from the protected list
function EntityProtection.remove_entity(entity)
local entities = protected_entities[entity.surface.index]
if not entities then return end
entities[get_entity_key(entity)] = nil
end
--- Get all protected entities on a surface
function EntityProtection.get_entities(surface)
return protected_entities[surface.index]
end
--- Check if an entity is protected
function EntityProtection.is_entity_protected(entity)
local entities = protected_entities[entity.surface.index]
if not entities then return false end
return entities[get_entity_key(entity)] == entity
end
--- Add an area to the protected list
function EntityProtection.add_area(area)
function EntityProtection.add_area(surface, area)
local areas = protected_areas[surface.index]
if not areas then
areas = {}
protected_areas[surface.index] = areas
end
areas[get_area_key(area)] = area
end
--- Remove an area from the protected list
function EntityProtection.remove_area(area)
function EntityProtection.remove_area(surface, area)
local areas = protected_areas[surface.index]
if not areas then return end
areas[get_area_key(area)] = nil
end
--- Get all protected areas on a surface
function EntityProtection.get_areas(surface)
return protected_areas[surface.index]
end
--- Check if an entity is protected
function EntityProtection.is_position_protected(surface, position)
local areas = protected_areas[surface.index]
if not areas then return false end
for _, area in pairs(areas) do
if area.left_top.x <= position.x and area.left_top.y <= position.y
and area.right_bottom.x >= position.x and area.right_bottom.y >= position.y
then
return true
end
end
return false
end
----- Events -----
--- All events registered by this module
Event.add(defines.events.on_player_mined_item, function(event)
--- Raise events for protected entities
Event.add(defines.events.on_pre_player_mined_item, function(event)
local entity = event.entity
local player = game.get_player(event.player_index)
-- Check if the player should be ignored
if config.ignore_admins and player.admin then return end
if config.ignore_role and config.ignore_role(player) then return end
-- Check if the entity is protected
if check_always_protected(entity) or EntityProtection.is_entity_protected(entity)
or EntityProtection.is_position_protected(entity.surface, entity.position)
then
-- Update repeats
local player_repeats = repeats[player.name]
if not player_repeats then
player_repeats = { last = game.tick, count = 0 }
repeats[player.name] = player_repeats
end
player_repeats.last = game.tick
player_repeats.count = player_repeats.count + 1
-- Send events
event.name = EntityProtection.events.on_player_mined_protected
script.raise_event(EntityProtection.events.on_player_mined_protected, event)
if check_skip_repeat(entity) or player_repeats.count >= config.repeat_count then
event.name = EntityProtection.events.on_repeat_violation
script.raise_event(EntityProtection.events.on_repeat_violation, event)
end
end
end)
--- Remove old repeats
Event.on_nth_tick(config.refresh_rate, function()
local old = game.tick - config.repeat_lifetime
for player_name, player_repeats in pairs(repeats) do
if player_repeats.last <= old then
repeats[player_name] = nil
end
end
end)
return EntityProtection