You've already forked ComfyFactorio
mirror of
https://github.com/ComfyFactory/ComfyFactorio.git
synced 2025-11-23 22:22:34 +02:00
344 lines
14 KiB
Lua
344 lines
14 KiB
Lua
local Server = require 'utils.server'
|
|
local Event = require 'utils.event'
|
|
local CustomEvents = require 'utils.created_events'
|
|
local Global = require 'utils.global'
|
|
local Commands = require 'utils.commands'
|
|
local Task = require 'utils.task_token'
|
|
local Discord = require 'utils.discord_handler'
|
|
|
|
local module_name = '[Undo actions] '
|
|
local undo_polls = {}
|
|
local Public = {}
|
|
|
|
Global.register(
|
|
{
|
|
undo_polls = undo_polls
|
|
},
|
|
function (tbl)
|
|
undo_polls = tbl.undo_polls
|
|
end
|
|
)
|
|
|
|
local make_entity_destructible_token =
|
|
Task.register(
|
|
function (event)
|
|
local entity = event.entity
|
|
if not entity or not entity.valid then
|
|
return
|
|
end
|
|
|
|
entity.destructible = true
|
|
end
|
|
)
|
|
|
|
local function check_undo_queue(player)
|
|
if not type(player) == 'userdata' then
|
|
error('Player is not userdata.')
|
|
end
|
|
|
|
local undo_redo_stack = player.undo_redo_stack
|
|
if undo_redo_stack and undo_redo_stack.get_undo_item_count() > 0 then
|
|
return undo_redo_stack.get_undo_item_count()
|
|
end
|
|
end
|
|
|
|
local function do_action_poll(player)
|
|
if player and type(player) ~= 'userdata' then
|
|
Server.output_script_data(module_name .. 'Player is not userdata. Getting player from name ' .. player)
|
|
player = game.get_player(player)
|
|
end
|
|
|
|
if not player or not player.valid then
|
|
Server.output_script_data(module_name .. 'Player is not valid. Not doing action poll.')
|
|
return
|
|
end
|
|
|
|
local undo_count = check_undo_queue(player)
|
|
if not undo_count or undo_count <= 0 then
|
|
Server.output_script_data(module_name .. 'No undo count found for ' .. player.name .. '. Not doing action poll.')
|
|
return
|
|
end
|
|
Server.output_script_data(module_name .. 'Doing action poll for ' .. player.name .. ' with undo count ' .. undo_count)
|
|
if undo_count > 0 then
|
|
game.print(module_name .. player.name .. ' has ' .. undo_count .. ' entities in the undo queue. Creating poll before restoring them.')
|
|
local unique_id = player.name .. '_' .. 'undo_poll'
|
|
|
|
Event.raise(CustomEvents.events.on_poll_created,
|
|
{
|
|
question = player.name .. ' removed ' .. undo_count .. ' entities before getting dealt with. Proceed with restoration?',
|
|
answers = { 'Yes, restore the entities!', 'No, do not restore the entities!' },
|
|
duration = 30,
|
|
custom_data =
|
|
{
|
|
unique_id = unique_id,
|
|
player_name = player.name,
|
|
surface_index = player.surface.index
|
|
}
|
|
})
|
|
|
|
Server.output_script_data(module_name .. 'Poll created for ' .. player.name .. ' with id ' .. unique_id)
|
|
|
|
undo_polls[#undo_polls + 1] =
|
|
{
|
|
unique_id = unique_id,
|
|
player_index = player.index,
|
|
player_name = player.name,
|
|
surface_index = player.surface.index
|
|
}
|
|
end
|
|
end
|
|
|
|
local converted_entities =
|
|
{
|
|
['straight-rail'] = 'rail',
|
|
['curved-rail'] = 'rail',
|
|
}
|
|
|
|
local function check_undo_redo_stack(player)
|
|
if not type(player) == 'userdata' then
|
|
error('Player is not userdata.')
|
|
end
|
|
|
|
local valid_undos = {}
|
|
local restored_entities = 0
|
|
local to_remove_items = 0
|
|
|
|
local undo_redo_stack = player.undo_redo_stack
|
|
if undo_redo_stack and undo_redo_stack.get_undo_item_count() > 0 then
|
|
for i = 1, undo_redo_stack.get_undo_item_count() do
|
|
local actions = undo_redo_stack.get_undo_item(i)
|
|
|
|
if actions and #actions > 0 then
|
|
valid_undos[#valid_undos + 1] = actions
|
|
|
|
for _, action in pairs(actions) do
|
|
if not action.surface_index then
|
|
Server.output_script_data(module_name .. 'Action has no surface index. Not restoring entity.')
|
|
goto continue_action
|
|
end
|
|
|
|
local surface = game.get_surface(action.surface_index)
|
|
if not (surface and surface.valid) then
|
|
Server.output_script_data(module_name .. 'Invalid surface for action.')
|
|
goto continue_action
|
|
end
|
|
|
|
local target = action.target
|
|
if not (target and target.name and target.position) then
|
|
Server.output_script_data(module_name .. 'Invalid target data.')
|
|
goto continue_action
|
|
end
|
|
|
|
target.force = player.force
|
|
local entity = surface.create_entity(target)
|
|
if entity and entity.valid then
|
|
restored_entities = restored_entities + 1
|
|
|
|
local name = converted_entities[target.name]
|
|
or (string.find(target.name, 'curved') and 'rail')
|
|
or target.name
|
|
|
|
player.remove_item
|
|
{
|
|
name = name,
|
|
quality = target.quality,
|
|
count = 999
|
|
}
|
|
|
|
if action.insert_plan and next(action.insert_plan) then
|
|
for _, plan in pairs(action.insert_plan) do
|
|
for _, items in pairs(plan.items.in_inventory) do
|
|
if entity.get_module_inventory().index == items.inventory then
|
|
to_remove_items = to_remove_items + 1
|
|
entity.get_module_inventory().insert
|
|
{
|
|
name = plan.id.name,
|
|
quality = plan.id.quality,
|
|
count = 1
|
|
}
|
|
end
|
|
end
|
|
if to_remove_items > 0 then
|
|
player.remove_item
|
|
{
|
|
name = plan.id.name,
|
|
quality = plan.id.quality,
|
|
count = to_remove_items
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
::continue_action::
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
Server.output_script_data(module_name .. 'Restored ' .. restored_entities .. ' entities for ' .. player.name)
|
|
|
|
if #valid_undos > 0 then
|
|
while player.undo_redo_stack.get_undo_item_count() > 0 do
|
|
player.undo_redo_stack.remove_undo_item(player.undo_redo_stack.get_undo_item_count())
|
|
end
|
|
end
|
|
end
|
|
|
|
Event.add(CustomEvents.events.on_poll_complete, function (event)
|
|
if not event.winning_answer or not event.winning_answer.text then
|
|
return
|
|
end
|
|
|
|
local custom_data = event.custom_data
|
|
if not custom_data then
|
|
Server.output_script_data(module_name .. 'Custom data is not set. Not checking undo redo stack.')
|
|
return
|
|
end
|
|
|
|
local player_name = custom_data.player_name
|
|
if not player_name then
|
|
return
|
|
end
|
|
|
|
Server.output_script_data(module_name .. 'Poll complete for ' .. player_name .. ' with winning answer ' .. event.winning_answer.text)
|
|
|
|
|
|
if not undo_polls or not next(undo_polls) then
|
|
Server.output_script_data(module_name .. 'No undo polls found. Not checking undo redo stack.')
|
|
return
|
|
end
|
|
|
|
for i = 1, #undo_polls do
|
|
local poll_action = undo_polls[i]
|
|
if poll_action and poll_action.unique_id == custom_data.unique_id then
|
|
local surface = game.get_surface(poll_action.surface_index)
|
|
if not surface or not surface.valid then
|
|
Server.output_script_data(module_name .. 'Surface is not valid. Not checking undo redo stack.')
|
|
return
|
|
end
|
|
local player = game.get_player(player_name)
|
|
if not player or not player.valid then
|
|
Server.output_script_data(module_name .. 'Player is not valid. Not checking undo redo stack.')
|
|
return
|
|
end
|
|
if string.find(event.winning_answer.text, 'Yes') then
|
|
check_undo_redo_stack(player)
|
|
Server.output_script_data(module_name .. 'Undo redo stack checked for ' .. player_name)
|
|
else
|
|
Server.output_script_data(module_name .. 'Not restore entities. Adding all items to a chest near spawn.')
|
|
local spawn_position = game.forces.player.get_spawn_position(surface)
|
|
local non_collidin_position = surface.find_non_colliding_position('blue-chest', spawn_position, 10, 5)
|
|
local e = surface.create_entity({ name = 'blue-chest', position = non_collidin_position or spawn_position, force = 'player' })
|
|
if e and e.valid then
|
|
Task.set_timeout_in_ticks(1000, make_entity_destructible_token, { entity = e })
|
|
e.set_inventory_size_override(defines.inventory.chest, 1000)
|
|
game.print(module_name .. 'Adding all items have been transferred to a chest near spawn.')
|
|
game.print('Located here: [gps=' .. e.position.x .. ',' .. e.position.y .. ',' .. e.surface.name .. ']')
|
|
local main_inventory = player.get_main_inventory()
|
|
if main_inventory and main_inventory.valid then
|
|
for _, item in pairs(main_inventory.get_contents()) do
|
|
e.insert({ name = item.name, count = item.count })
|
|
end
|
|
end
|
|
player.clear_items_inside()
|
|
end
|
|
end
|
|
Server.output_script_data(module_name .. 'Poll removed from undo polls for ' .. player_name)
|
|
undo_polls[i] = nil
|
|
break
|
|
end
|
|
end
|
|
end)
|
|
|
|
Event.add(CustomEvents.events.on_player_banned, function (event)
|
|
if not event.player_name then
|
|
return
|
|
end
|
|
local player = game.get_player(event.player_name)
|
|
if not player or not player.valid then
|
|
Server.output_script_data(module_name .. 'Player is not valid. Not checking undo redo stack.')
|
|
return
|
|
end
|
|
|
|
Server.output_script_data(module_name .. 'Player event received for ' .. player.name)
|
|
local undo_count = check_undo_queue(player)
|
|
if not undo_count or undo_count <= 0 then
|
|
Server.output_script_data(module_name .. 'No undo count found for ' .. player.name .. '. Not checking undo redo stack.')
|
|
return
|
|
end
|
|
|
|
check_undo_redo_stack(player)
|
|
Server.output_script_data(module_name .. 'Undo redo stack checked for ' .. player.name)
|
|
end)
|
|
|
|
Commands.new('undo_player_actions', 'Undoes the actions of a player as a player by creating a poll.')
|
|
:add_parameter('player', false, 'player')
|
|
:require_validation('Only utilize this command if the player is jailed and has entities in the undo queue.')
|
|
:require_playtime(60 * 60 * 60 * 24 * 40) -- 30 days
|
|
:callback(function (player, target_player)
|
|
if not target_player or not target_player.valid then
|
|
return player.print('Player is not valid.')
|
|
end
|
|
|
|
local undo_count = check_undo_queue(target_player)
|
|
if not undo_count or undo_count <= 0 then
|
|
return player.print('No undo count found for ' .. target_player.name .. '.')
|
|
end
|
|
|
|
do_action_poll(target_player)
|
|
player.print('Logging your actions to discord.')
|
|
Discord.send_notification(
|
|
{
|
|
title = 'Undo actions',
|
|
description = 'Undone ' .. undo_count .. ' actions for ' .. target_player.name .. ' by ' .. player.name .. '.',
|
|
color = 'success',
|
|
fields =
|
|
{
|
|
{
|
|
title = "Server",
|
|
description = Server.get_server_name() or 'CommandHandler',
|
|
inline = "false"
|
|
}
|
|
}
|
|
})
|
|
end)
|
|
|
|
Commands.new('undo_player_actions_admin', 'Undoes the actions of a player as an admin.')
|
|
:add_parameter('player', false, 'player')
|
|
:require_validation('Only utilize this command if the player is jailed and has entities in the undo queue.')
|
|
:require_admin()
|
|
:callback(function (player, target_player)
|
|
if not target_player or not target_player.valid then
|
|
return player.print('Player is not valid.')
|
|
end
|
|
|
|
local undo_count = check_undo_queue(target_player)
|
|
if not undo_count or undo_count <= 0 then
|
|
return player.print('No undo count found for ' .. target_player.name .. '.')
|
|
end
|
|
|
|
check_undo_redo_stack(target_player)
|
|
player.print('Logging your actions to discord.')
|
|
player.print('Undone ' .. undo_count .. ' actions for ' .. target_player.name .. '.')
|
|
Discord.send_notification(
|
|
{
|
|
title = 'Undo actions',
|
|
description = 'Undone ' .. undo_count .. ' actions for ' .. target_player.name .. ' by ' .. player.name .. '.',
|
|
color = 'success',
|
|
fields =
|
|
{
|
|
{
|
|
title = "Server",
|
|
description = Server.get_server_name() or 'CommandHandler',
|
|
inline = "false"
|
|
}
|
|
}
|
|
})
|
|
end)
|
|
|
|
Public.check_undo_redo_stack = check_undo_redo_stack
|
|
Public.do_action_poll = do_action_poll
|
|
|
|
return Public
|