mirror of
https://github.com/PHIDIAS0303/ExpCluster.git
synced 2026-09-21 17:04:00 +00:00
Merge branch 'main' into feature/remove-warnings
This commit is contained in:
@@ -9,7 +9,7 @@ local ExpUtil = require("modules/exp_util")
|
||||
local Gui = require("modules/exp_gui")
|
||||
local Roles = require("modules/exp_roles")
|
||||
local Reports = require("modules.exp_legacy.modules.control.reports") --- @dep modules.control.reports
|
||||
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
|
||||
local Jail = require("modules/exp_scenario/control/jail")
|
||||
local Colors = require("modules/exp_util/include/color")
|
||||
local format_player_name = ExpUtil.format_player_name_locale
|
||||
|
||||
@@ -104,7 +104,7 @@ end
|
||||
local jail_player = new_button("utility/multiplayer_waiting_icon", { "exp-gui_player-list.jail-player" })
|
||||
:on_click(function(def, player, element)
|
||||
local selected_player, selected_player_color = get_action_player(player)
|
||||
if Jail.is_jailed(selected_player.name) then
|
||||
if Jail.is_jailed(selected_player) then
|
||||
player.print({ "exp-commands_jail.already-jailed", selected_player_color }, Colors.orange_red)
|
||||
else
|
||||
set_selected_action(player, "exp_scenario.command.jail")
|
||||
@@ -115,7 +115,7 @@ local function jail_player_callback(player, reason)
|
||||
local selected_player, selected_player_color = get_action_player(player)
|
||||
local by_player_name_color = format_player_name(player)
|
||||
game.print{ "exp-commands_jail.jailed", selected_player_color, by_player_name_color, reason }
|
||||
Jail.jail_player(selected_player.name, player.name, reason)
|
||||
Jail.jail_player(selected_player, player.name, reason)
|
||||
end
|
||||
|
||||
--- Kicks the action player, requires a reason
|
||||
|
||||
@@ -1,119 +0,0 @@
|
||||
--[[-- Control Module - Jail
|
||||
- Adds a way to jail players.
|
||||
@control Jail
|
||||
@alias Jail
|
||||
|
||||
@usage
|
||||
-- import the module from the control modules
|
||||
local Jail = require("modules.exp_legacy.modules.control.jail") --- @dep modules.control.jail
|
||||
|
||||
-- This will give 'MrBiter' the jail role, which suppresses all of their other roles
|
||||
-- the player name and reason are only so they can be included in the event for user feedback
|
||||
Jail.jail_player('MrBiter', 'Cooldude2606', 'Likes biters too much')
|
||||
|
||||
-- This will remove the jail role from 'MrBiter', restoring their other roles
|
||||
-- again as above the player name is only used in the event for user feedback
|
||||
Jail.unjail_player('MrBiter', 'Cooldude2606')
|
||||
]]
|
||||
|
||||
local Roles = require("modules/exp_roles")
|
||||
|
||||
local valid_player = function(p) return type(p) == "userdata" and p or game.get_player(p) end
|
||||
|
||||
--- The role given to jailed players, it has a higher priority than every other role
|
||||
local function jail_role()
|
||||
return assert(Roles.get_role_by_name("Jail"), "The Jail role does not exist")
|
||||
end
|
||||
|
||||
local Jail = {
|
||||
events = {
|
||||
--- When a player is assigned to jail
|
||||
-- @event on_player_jailed
|
||||
-- @tparam number player_index the index of the player who was jailed
|
||||
-- @tparam string by_player_name the name of the player who jailed the other player
|
||||
-- @tparam string reason the reason that the player was jailed
|
||||
on_player_jailed = script.generate_event_name(),
|
||||
--- When a player is unassigned from jail
|
||||
-- @event on_player_unjailed
|
||||
-- @tparam number player_index the index of the player who was unjailed
|
||||
-- @tparam string by_player_name the name of the player who unjailed the other player
|
||||
on_player_unjailed = script.generate_event_name(),
|
||||
},
|
||||
}
|
||||
|
||||
--- Used to emit the jail related events
|
||||
-- @tparam number event the name of the event that will be emited
|
||||
-- @tparam LuaPlayer player the player who is being acted on
|
||||
-- @tparam string by_player_name the player who is doing the action
|
||||
-- @tparam string reason the reason for the action (jail)
|
||||
local function event_emit(event, player, by_player_name, reason)
|
||||
script.raise_event(event, {
|
||||
name = event,
|
||||
tick = game.tick,
|
||||
player_index = player.index,
|
||||
by_player_name = by_player_name,
|
||||
reason = reason,
|
||||
})
|
||||
end
|
||||
|
||||
--- Jail.
|
||||
-- Functions related to jail
|
||||
-- @section jail-functions
|
||||
|
||||
--- Checks if the player is currently in jail
|
||||
-- @tparam LuaPlayer player the player to check if they are in jail
|
||||
-- @treturn boolean whether the player is currently in jail
|
||||
function Jail.is_jailed(player)
|
||||
local valid = valid_player(player)
|
||||
return valid ~= nil and jail_role():has_player(valid)
|
||||
end
|
||||
|
||||
--- Moves a player to jail, which suppresses all of their other roles
|
||||
-- @tparam LuaPlayer player the player who will be jailed
|
||||
-- @tparam string by_player_name the name of the player who is doing the jailing
|
||||
-- @tparam[opt='Non given.'] string reason the reason that the player is being jailed
|
||||
-- @treturn boolean wheather the user was jailed successfully
|
||||
function Jail.jail_player(player, by_player_name, reason)
|
||||
player = valid_player(player)
|
||||
if not player then return end
|
||||
if not by_player_name then return end
|
||||
|
||||
reason = reason or "Non given."
|
||||
|
||||
local role = jail_role()
|
||||
if role:has_player(player) then return end
|
||||
|
||||
player.walking_state = { walking = false, direction = player.walking_state.direction }
|
||||
player.riding_state = { acceleration = defines.riding.acceleration.nothing, direction = player.riding_state.direction }
|
||||
player.mining_state = { mining = false }
|
||||
player.shooting_state = { state = defines.shooting.not_shooting, position = player.shooting_state.position }
|
||||
player.picking_state = false
|
||||
player.repair_state = { repairing = false, position = player.repair_state.position }
|
||||
|
||||
role:assign(player, { by_player_name = by_player_name, silent = true })
|
||||
|
||||
event_emit(Jail.events.on_player_jailed, player, by_player_name, reason)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
--- Moves a player out of jail, which restores all of their other roles
|
||||
-- @tparam LuaPlayer player the player that will be unjailed
|
||||
-- @tparam string by_player_name the name of the player that is doing the unjail
|
||||
-- @treturn boolean whether the player was unjailed successfully
|
||||
function Jail.unjail_player(player, by_player_name)
|
||||
player = valid_player(player)
|
||||
if not player then return end
|
||||
if not by_player_name then return end
|
||||
|
||||
local role = jail_role()
|
||||
if not role:has_player(player) then return end
|
||||
|
||||
role:unassign(player, { by_player_name = by_player_name, silent = true })
|
||||
|
||||
event_emit(Jail.events.on_player_unjailed, player, by_player_name)
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
return Jail
|
||||
@@ -1,204 +0,0 @@
|
||||
--[[-- Control Module - Protection
|
||||
- Controls protected entities
|
||||
@control Protection
|
||||
@alias Protection
|
||||
]]
|
||||
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
||||
local config = require("modules.exp_legacy.config.protection") --- @dep config.protection
|
||||
local EntityProtection = {
|
||||
protected_entity_names = table.deep_copy(config.always_protected_names),
|
||||
protected_entity_types = table.deep_copy(config.always_protected_types),
|
||||
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 repeatedly mines 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", "always_trigger_repeat_names", "always_trigger_repeat_types" } do
|
||||
local tbl = config[config_key]
|
||||
for key, value in ipairs(tbl) do
|
||||
tbl[key] = nil
|
||||
tbl[value] = true
|
||||
end
|
||||
end
|
||||
|
||||
local Roles = require("modules/exp_roles")
|
||||
|
||||
----- Storage Variables -----
|
||||
--- Variables stored in the global table
|
||||
|
||||
local protected_entities = {} -- All entities which are protected
|
||||
local protected_areas = {} -- All areas which are protected
|
||||
local repeats = {} -- Stores repeat removals by players
|
||||
|
||||
Storage.register({
|
||||
protected_entities = protected_entities,
|
||||
protected_areas = protected_areas,
|
||||
repeats = repeats,
|
||||
}, function(tbl)
|
||||
protected_entities = tbl.protected_entities
|
||||
protected_areas = tbl.protected_areas
|
||||
repeats = tbl.repeats
|
||||
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", math.floor(entity.position.x), math.floor(entity.position.y))
|
||||
end
|
||||
|
||||
--- Get the key used in protected_areas
|
||||
local function get_area_key(area)
|
||||
return string.format("%i,%i", math.floor(area.left_top.x), math.floor(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 always triggers repeat protection
|
||||
local function check_always_trigger_repeat(entity)
|
||||
return config.always_trigger_repeat_names[entity.name] or config.always_trigger_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] or {}
|
||||
end
|
||||
|
||||
--- Check if an entity is protected
|
||||
function EntityProtection.is_entity_protected(entity)
|
||||
if check_always_protected(entity) then return true end
|
||||
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(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(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] or {}
|
||||
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
|
||||
|
||||
--- Raise events for protected entities
|
||||
Event.add(defines.events.on_pre_player_mined_item, function(event)
|
||||
local entity = event.entity
|
||||
local player = game.players[event.player_index]
|
||||
-- Check if the player should be ignored
|
||||
if config.ignore_admins and player.admin then return end
|
||||
if entity.last_user == nil or entity.last_user.index == player.index then return end
|
||||
if config.ignore_permission and Roles.player_has_permission(player, config.ignore_permission) then return end
|
||||
|
||||
-- Check if the entity is protected
|
||||
if 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_always_trigger_repeat(entity) or player_repeats.count >= config.repeat_count then
|
||||
player_repeats.count = 0 -- Reset to avoid spamming of events
|
||||
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)
|
||||
|
||||
--- When an entity is removed remove it from the protection list
|
||||
local function event_remove_entity(event)
|
||||
EntityProtection.remove_entity(event.entity)
|
||||
end
|
||||
|
||||
Event.add(defines.events.on_space_platform_pre_mined, event_remove_entity)
|
||||
Event.add(defines.events.on_pre_player_mined_item, event_remove_entity)
|
||||
Event.add(defines.events.on_robot_pre_mined, event_remove_entity)
|
||||
Event.add(defines.events.on_entity_died, event_remove_entity)
|
||||
Event.add(defines.events.script_raised_destroy, event_remove_entity)
|
||||
|
||||
return EntityProtection
|
||||
@@ -1,173 +0,0 @@
|
||||
local Storage = require("modules/exp_util/storage")
|
||||
local Gui = require("modules/exp_gui")
|
||||
|
||||
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
|
||||
|
||||
----- Locals -----
|
||||
local follow_label --- @type ExpElement Gui constructor
|
||||
local following = {}
|
||||
local spectating = {}
|
||||
local Public = {}
|
||||
|
||||
----- Storage data -----
|
||||
Storage.register({
|
||||
following = following,
|
||||
spectating = spectating,
|
||||
}, function(tbl)
|
||||
following = tbl.following
|
||||
spectating = tbl.spectating
|
||||
end)
|
||||
|
||||
----- Public Functions -----
|
||||
|
||||
--- Test if a player is in spectator mode
|
||||
-- @tparam LuaPlayer player The player to test the controller type of
|
||||
-- @treturn boolean Returns true if the player is in spectator mode
|
||||
function Public.is_spectating(player)
|
||||
assert(player and player.valid, "Invalid player given to follower")
|
||||
return player.controller_type == defines.controllers.spectator
|
||||
end
|
||||
|
||||
--- Puts a player into spectator mode while maintaining an association to their character
|
||||
-- @tparam LuaPlayer player The player that will be placed into spectator mode
|
||||
-- @treturn boolean Returns false if the player was already in spectator mode
|
||||
function Public.start_spectate(player)
|
||||
assert(player and player.valid, "Invalid player given to follower")
|
||||
if spectating[player.index] or not player.character then return false end
|
||||
local character = player.character
|
||||
local opened = player.opened
|
||||
player.set_controller{ type = defines.controllers.spectator }
|
||||
player.associate_character(character)
|
||||
spectating[player.index] = character
|
||||
if opened then player.opened = opened end -- Maintain opened after controller change
|
||||
return true
|
||||
end
|
||||
|
||||
--- Return a player from spectator mode back to their character, if their character was killed then respawn them
|
||||
-- @tparam LuaPlayer player The player that will leave spectator mode
|
||||
function Public.stop_spectate(player)
|
||||
assert(player and player.valid, "Invalid player given to follower")
|
||||
local character = spectating[player.index]
|
||||
spectating[player.index] = nil
|
||||
if character and character.valid then
|
||||
local opened = player.opened
|
||||
player.teleport(character.position, character.surface)
|
||||
player.set_controller{ type = defines.controllers.character, character = character }
|
||||
if opened then player.opened = opened end -- Maintain opened after controller change
|
||||
else
|
||||
player.ticks_to_respawn = 300
|
||||
end
|
||||
end
|
||||
|
||||
--- Test if a player is in follow mode
|
||||
-- @tparam LuaPlayer player The player to test the follow mode of
|
||||
-- @treturn boolean Returns true if the player is in follow mode
|
||||
function Public.is_following(player)
|
||||
assert(player and player.valid, "Invalid player given to follower")
|
||||
return following[player.index] ~= nil
|
||||
end
|
||||
|
||||
--- Puts a player into spectator mode and follows an entity as it moves
|
||||
-- @tparam LuaPlayer player The player that will follow the entity
|
||||
-- @tparam ?LuaPlayer|LuaEntity entity The player or entity that will be followed
|
||||
function Public.start_follow(player, entity)
|
||||
assert(player and player.valid, "Invalid player given to follower")
|
||||
assert(entity and entity.valid, "Invalid entity given to follower")
|
||||
local spectate = Public.start_spectate(player)
|
||||
|
||||
player.close_map()
|
||||
follow_label(player.gui.screen, entity)
|
||||
player.teleport(entity.position, entity.surface)
|
||||
following[player.index] = { player, entity, entity.position, spectate }
|
||||
end
|
||||
|
||||
--- Returns camera control to the player, will return a player to their character if start_follow placed them into spectator mode
|
||||
-- @tparam LuaPlayer player The player that will regain control of their camera
|
||||
function Public.stop_follow(player)
|
||||
assert(player and player.valid, "Invalid player given to follower")
|
||||
if following[player.index] and following[player.index][4] and Public.is_spectating(player) then
|
||||
Public.stop_spectate(player)
|
||||
end
|
||||
|
||||
Gui.destroy_if_valid(player.gui.screen.follow_label)
|
||||
following[player.index] = nil
|
||||
end
|
||||
|
||||
--- Returns camera control to all players, will return a player to their character if start_follow placed them into spectator mode
|
||||
function Public.stop_all()
|
||||
for key, data in pairs(following) do
|
||||
Public.stop_follow(data[1])
|
||||
end
|
||||
end
|
||||
|
||||
----- Gui -----
|
||||
|
||||
--- Label used to show that the player is following, also used to allow esc to stop following
|
||||
follow_label = Gui.define("follow-label")
|
||||
:draw(function(def, parent, target)
|
||||
Gui.destroy_if_valid(parent.follow_label)
|
||||
|
||||
local label = parent.add{
|
||||
type = "label",
|
||||
name = "follow_label",
|
||||
style = "frame_title",
|
||||
caption = "Following " .. target.name .. ".\nClick here or press esc to stop following.",
|
||||
}
|
||||
|
||||
local player = Gui.get_player(parent)
|
||||
local res = player.display_resolution
|
||||
label.location = { 0, res.height - 150 }
|
||||
label.style.width = res.width
|
||||
label.style.horizontal_align = "center"
|
||||
player.opened = label
|
||||
|
||||
return label
|
||||
end)
|
||||
:on_click(function(def, player, element)
|
||||
Public.stop_follow(player)
|
||||
end)
|
||||
:on_closed(function(def, player, element)
|
||||
-- Don't call set_controller during on_close as it invalidates the controller
|
||||
-- Setting an invalid position (as to not equal their current) will call stop_follow on the next tick
|
||||
following[player.index][3] = {}
|
||||
end)
|
||||
|
||||
----- Events -----
|
||||
|
||||
--- Updates the location of the player as well as doing some sanity checks
|
||||
-- @tparam LuaPlayer player The player to update the position of
|
||||
-- @tparam ?LuaPlayer|LuaEntity entity The player or entity being followed
|
||||
local function update_player_location(player, entity, old_position)
|
||||
if player.character or not entity.valid then
|
||||
Public.stop_follow(player)
|
||||
elseif player.position.x ~= old_position.x or player.position.y ~= old_position.y then
|
||||
Public.stop_follow(player)
|
||||
else
|
||||
player.teleport(entity.position, entity.surface)
|
||||
end
|
||||
end
|
||||
|
||||
--- Updates the locations of all players currently following something
|
||||
local function update_all()
|
||||
for _, data in pairs(following) do
|
||||
update_player_location(data[1], data[2], data[3])
|
||||
data[3] = data[1].position
|
||||
end
|
||||
end
|
||||
|
||||
-- Update the location of all players each tick
|
||||
Event.add(defines.events.on_tick, update_all)
|
||||
|
||||
-- Check for player leaving
|
||||
Event.add(defines.events.on_pre_player_left_game, function(event)
|
||||
local player = game.players[event.player_index]
|
||||
Public.stop_follow(player)
|
||||
for _, data in pairs(following) do
|
||||
if data[2] == player then
|
||||
Public.stop_follow(data[1])
|
||||
end
|
||||
end
|
||||
end)
|
||||
|
||||
----- Module Return -----
|
||||
return Public
|
||||
Reference in New Issue
Block a user