diff --git a/antigrief.lua b/antigrief.lua index 17943099..dfcd3035 100644 --- a/antigrief.lua +++ b/antigrief.lua @@ -1,12 +1,18 @@ local Event = require "utils.event" local Utils = require "utils.utils" +global.original_last_users_by_ent_pos = {} + Event.on_init(function() global.ag_surface=game.create_surface("antigrief",{autoplace_controls={coal={frequency="normal",richness="normal",size="none"},["copper-ore"]={frequency="normal",richness="normal",size="none"},["crude-oil"]={frequency="normal",richness="normal",size="none"},desert={frequency="normal",richness="normal",size="none"},dirt={frequency="normal",richness="normal",size="none"},["enemy-base"]={frequency="normal",richness="normal",size="none"},grass={frequency="normal",richness="normal",size="very-high"},["iron-ore"]={frequency="normal",richness="normal",size="none"},sand={frequency="normal",richness="normal",size="none"},stone={frequency="normal",richness="normal",size="none"},trees={frequency="normal",richness="normal",size="none"},["uranium-ore"]={frequency="normal",richness="normal",size="none"}},cliff_settings={cliff_elevation_0=1024,cliff_elevation_interval=10,name="cliff"},height=2000000,peaceful_mode=false,seed=3461559752,starting_area="very-low",starting_points={{x=0,y=0}},terrain_segmentation="normal",water="none",width=2000000}) global.ag_surface.always_day = true end) +local function is_mocked(entity) + return pcall(function() return entity.mock end) +end + local function place_entity_on_surface(entity, surface, replace, player) local new_entity = nil for _,e in pairs(surface.find_entities_filtered{position = entity.position}) do @@ -14,10 +20,16 @@ local function place_entity_on_surface(entity, surface, replace, player) e.destroy() end end - if (replace or surface.count_entities_filtered{position = entity.position} == 0) then + local entities_to_be_replaced = surface.find_entities_filtered{position = entity.position} + if (replace or #entities_to_be_replaced == 0 or entities_to_be_replaced[1].type == entity.type) then new_entity = surface.create_entity{name = entity.name, position = entity.position, force = entity.force, direction = entity.direction} - if player and new_entity then - new_entity.last_user = player + if new_entity then + if not is_mocked(entity) then + new_entity.copy_settings(entity) + end + if player then + new_entity.last_user = player + end end end return new_entity @@ -41,11 +53,46 @@ Event.add(defines.events.on_chunk_generated, function(event) end) Event.add(defines.events.on_robot_pre_mined, function(event) - if event.entity.force.name == "player" and event.entity.last_user then - place_entity_on_surface(event.entity, global.ag_surface, true, event.entity.last_user) - end + --The bot isnt the culprit! The last user is! They marked it for deconstruction! + event.player_index = Utils.ternary(event.last_user, entity.last_user.index) + on_entity_changed(event) end) +local function get_position_str(pos) + return string.format("%d|%d", pos.x, pos.y) +end + +local function on_entity_changed(event) + local entity = event.entity or event.destination + local player = game.players[event.player_index] + if player.admin then x=2 end --Freebees for admins + if true or entity.last_user ~= player and entity.force == player.force then --commented out to be able to debug + place_entity_on_surface(entity, global.ag_surface, true, event.player_index) + end + if entity.last_user then + global.original_last_users_by_ent_pos[get_position_str(entity.position)] = entity.last_user.index + end +end + +local function get_pre_rotate_direction(entity) + --Some entities have 8 rotation steps and some have 4. So a mathmatical reverse is not possible + entity.rotate{reverse=true} + local direction = entity.direction + entity.rotate() + return direction +end + +Event.add(defines.events.on_player_rotated_entity, function(event) + local entity = event.entity + --Mock entity us used because the api doesnt support pre_player_rotated entity. + --The mocked entity has the entity state before rotation + local mock_entity = {name = entity.name, position = entity.position, mock = true, + last_user = entity.last_user, force = entity.force, direction = get_pre_rotate_direction(entity)} + event.entity = mock_entity + on_entity_changed(event) +end) +Event.add(defines.events.on_pre_entity_settings_pasted, on_entity_changed) + Event.add(defines.events.on_entity_died, function(event) --is a player on the same force as the destroyed object if event.entity and event.entity.force.name == "player" and event.cause and @@ -61,10 +108,15 @@ Event.add(defines.events.on_entity_died, function(event) end end end) -Event.add(defines.events.on_player_mined_entity, function(event) - place_entity_on_surface(event.entity, global.ag_surface, true, event.player_index) + +Event.add(defines.events.on_player_mined_entity, on_entity_changed) + +Event.add(defines.events.on_marked_for_deconstruction, function(event) + global.original_last_users_by_ent_pos[get_position_str(event.entity.position)] = + event.entity.last_user.index end) + local Module = {} Module.undo = function(player) @@ -72,7 +124,7 @@ Module.undo = function(player) if type(player) == "nil" or type(player) == "string" then return --No support for strings! elseif type(player) == "number" then player = game.players[player] end - --Remove all items from all surfaces that player placed an entity + --Remove all items from all surfaces that player placed an entity on for _,surface in pairs(game.surfaces) do if surface ~= global.ag_surface then for _,e in pairs(surface.find_entities_filtered{force = player.force.name}) do @@ -86,7 +138,8 @@ Module.undo = function(player) for _,e in pairs(global.ag_surface.find_entities_filtered{}) do if e.last_user == player then --Place removed entity IF no collision is detected - local new_entity = place_entity_on_surface(e, game.surfaces.nauvis, false) + local last_user = global.original_last_users_by_ent_pos[get_position_str(e.position)] + local new_entity = place_entity_on_surface(e, game.surfaces.nauvis, false, last_user) --Transfere items if new_entity and e.type == "container" then local items = e.get_inventory(defines.inventory.chest).get_contents() @@ -115,3 +168,5 @@ Module.count_removed_entities = function(player) end return Module + +--TODO: Remove items from antigrief surface, override orientation, cause build event diff --git a/utils/utils.lua b/utils/utils.lua index 44e681c4..635e1e9d 100644 --- a/utils/utils.lua +++ b/utils/utils.lua @@ -59,5 +59,9 @@ Module.find_entities_by_last_user = function(player, surface, filters) end end return entities - end +end + +Module.ternary = function(c, t, f) + if c then return t else return f end +end return Module