From 88176f44a342bc8759064732c952259206b062a2 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Sat, 30 May 2020 21:06:07 +0100 Subject: [PATCH 1/5] Fixed player data issue --- expcore/player_data.lua | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/expcore/player_data.lua b/expcore/player_data.lua index 9d8ea963..b49331e6 100644 --- a/expcore/player_data.lua +++ b/expcore/player_data.lua @@ -133,7 +133,7 @@ Event.add(defines.events.on_player_left_game, function(event) local player_data = PlayerData:get(player) if player_data.valid == true then PlayerData:unload(player) - else PlayerData:raw_set(player) end + else PlayerData:raw_set(player.name) end end) ----- Module Return ----- From c7f2eb604756070202646b7f0b5d12f1a87ed935 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Sat, 30 May 2020 22:47:01 +0100 Subject: [PATCH 2/5] Converted Warps --- config/gui/warps.lua | 2 +- expcore/datastore.lua | 25 ++- expcore/player_data.lua | 3 +- modules/control/warps.lua | 59 +++--- modules/gui/warp-list.lua | 401 +++++++++++++++++++------------------- 5 files changed, 245 insertions(+), 245 deletions(-) diff --git a/config/gui/warps.lua b/config/gui/warps.lua index d1710ba8..3e8b272b 100644 --- a/config/gui/warps.lua +++ b/config/gui/warps.lua @@ -10,7 +10,7 @@ return { -- Warp cooldowns bypass_warp_cooldown = 'expcore.roles', --- @setting bypass_warp_cooldown dictates who the warp cooldown is applied to; values: all, admin, expcore.roles, none expcore_roles_bypass_warp_cooldown = 'gui/warp-list/bypass-cooldown', --- @setting expcore_roles_bypass_warp_cooldown if expcore.roles is used then this is the required permission - cooldown_duraction = 60, --- @setting cooldown_duraction the duration of the warp cooldown in seconds + cooldown_duration = 60, --- @setting cooldown_duration the duration of the warp cooldown in seconds -- Warp proximity bypass_warp_proximity = 'expcore.roles', --- @setting bypass_warp_proximity dictates who the warp proximity is applied to; values: all, admin, expcore.roles, none diff --git a/expcore/datastore.lua b/expcore/datastore.lua index ffa23f99..0a471b07 100644 --- a/expcore/datastore.lua +++ b/expcore/datastore.lua @@ -251,7 +251,8 @@ function DatastoreManager.ingest(action, datastoreName, key, valueJson) elseif action == 'propagate' or action == 'request' then local success, value = pcall(game.json_to_table, valueJson) if not success or value == nil then value = tonumber(valueJson) or valueJson end - value = datastore:raise_event('on_load', key, value) + local old_value = datastore:raw_get(key) + value = datastore:raise_event('on_load', key, value, old_value) datastore:set(key, value) end @@ -495,12 +496,13 @@ ExampleData:set('TestKey', 'Foo') ]] function Datastore:set(key, value) key = self:serialize(key) + local old_value = self:raw_get(key) if value == self.default and not self.allow_set_to_default then self:raw_set(key) else self:raw_set(key, value) end - self:raise_event('on_update', key, value) + self:raise_event('on_update', key, value, old_value) if self.auto_save then self:save(key) end return value end @@ -535,11 +537,12 @@ end) function Datastore:update(key, callback) key = self:serialize(key) local value = self:raw_get(key) + local old_value = copy(self:raw_get(key)) local success, new_value = xpcall(callback, update_error, key, value) if success and new_value ~= nil then self:set(key, new_value) else - self:raise_event('on_update', key, value) + self:raise_event('on_update', key, value, old_value) if self.auto_save then self:save(key) end end end @@ -554,8 +557,9 @@ ExampleData:remove('TestKey') ]] function Datastore:remove(key) key = self:serialize(key) + local old_value = self:raw_get(key) self:raw_set(key) - self:raise_event('on_update', key) + self:raise_event('on_update', key, old_value) if self.save_to_disk then self:write_action('remove', key) end if self.parent and self.parent.auto_save then return self.parent:save(key) end end @@ -622,11 +626,12 @@ end) function Datastore:update_all(callback) local data = self:get_all() for key, value in pairs(data) do + local old_value = copy(value) local success, new_value = xpcall(callback, update_error, key, value) if success and new_value ~= nil then self:set(key, new_value) else - self:raise_event('on_update', key, value) + self:raise_event('on_update', key, value, old_value) if self.auto_save then self:save(key) end end end @@ -749,12 +754,13 @@ local function event_error(err) log('An error ocurred in a datastore event handl value = self:raise_event('on_save', key, value) ]] -function Datastore:raise_event(event_name, key, value, source) +function Datastore:raise_event(event_name, key, value, old_value, source) -- Raise the event for the children of this datastore if source ~= 'child' and next(self.children) then if type(value) ~= 'table' then value = {} end for value_name, child in pairs(self.children) do - value[value_name] = child:raise_event(event_name, key, value[value_name], 'parent') + local old_child_value = old_value and old_value[value_name] or nil + value[value_name] = child:raise_event(event_name, key, value[value_name], old_child_value, 'parent') end end @@ -762,14 +768,15 @@ function Datastore:raise_event(event_name, key, value, source) local handlers = self.events[event_name] if handlers then for _, handler in ipairs(handlers) do - local success, new_value = xpcall(handler, event_error, key, value) + local success, new_value = xpcall(handler, event_error, key, value, old_value) if success and new_value ~= nil then value = new_value end end end -- Raise the event for the parent of this datastore if source ~= 'parent' and self.parent then - self.parent:raise_event(event_name, key, self.parent:raw_get(key, true), 'child') + local parent_value = self.parent:raw_get(key, true) + self.parent:raise_event(event_name, key, parent_value, parent_value, 'child') end -- If this is the save event and the table is empty then return nil diff --git a/expcore/player_data.lua b/expcore/player_data.lua index b49331e6..ba9a127c 100644 --- a/expcore/player_data.lua +++ b/expcore/player_data.lua @@ -90,9 +90,8 @@ local check_data_loaded = Async.register(function(player) end) --- When player data loads tell the player if the load had failed previously -PlayerData:on_load(function(player_name, player_data) +PlayerData:on_load(function(player_name, player_data, existing_data) if not player_data or player_data.valid == false then return end - local existing_data = PlayerData:get(player_name) if existing_data and existing_data.valid == false then game.players[player_name].print{'expcore-data.data-restore'} end diff --git a/modules/control/warps.lua b/modules/control/warps.lua index 7e7a12e6..a61e80d4 100644 --- a/modules/control/warps.lua +++ b/modules/control/warps.lua @@ -21,25 +21,24 @@ Warps.make_warp_tag(warp_id) ]] -local Store = require 'expcore.store' --- @dep expcore.store +local Datastore = require 'expcore.datastore' --- @dep expcore.datastore local Global = require 'utils.global' --- @dep utils.global -local Token = require 'utils.token' --- @dep utils.token local config = require 'config.gui.warps' --- @dep config.warps +--- Stores all data for the warp gui +local WrapData = Datastore.connect('WrapData') +WrapData:set_serializer(function(raw_key) return raw_key.warp_id end) + local Warps = {} -- Global lookup table for force name to task ids -local force_warps = {} +local force_warps = {_uid=1} Global.register(force_warps, function(tbl) force_warps = tbl end) --- Warp store is keyed by warp id, value is a table -local warp_store = Store.register() -Warps.store = warp_store - -- When a warp is updated change its chat tag and resort the warp order -Store.watch(warp_store, function(warp, warp_id) +WrapData:on_update(function(warp_id, warp, old_warp) if warp then -- Update the map chart tag if there is one if warp.tag then @@ -47,7 +46,7 @@ Store.watch(warp_store, function(warp, warp_id) end -- Check that the name of the warp has been changed - if warp.name == warp.old_name then return end + if not old_warp or warp.name == old_warp.name then return end -- Get the names of all the warp points for this force local force_name = warp.force_name @@ -56,7 +55,7 @@ Store.watch(warp_store, function(warp, warp_id) local warp_names = {} for _, next_warp_id in pairs(warp_ids) do - local next_warp = Store.get(warp_store, next_warp_id) + local next_warp = WrapData:get(next_warp_id) if next_warp_id ~= spawn_id then warp_names[next_warp.name..next_warp_id] = next_warp_id end @@ -70,9 +69,9 @@ Store.watch(warp_store, function(warp, warp_id) end end) ---- Map Intergration. +--- Map Integration. -- functions used to create and alter warps with in the map --- @section mapIntergration +-- @section mapIntegration --[[-- Add or update the chat tag for this warp @tparam string warp_id the uid of the warp you want the chart tag for @@ -83,7 +82,7 @@ local tag_added = Warps.make_warp_tag(warp_id) ]] function Warps.make_warp_tag(warp_id) - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) local name = warp.name local icon = warp.icon @@ -120,7 +119,7 @@ local removed = Warps.remove_warp_tag(warp_id) ]] function Warps.remove_warp_tag(warp_id) - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) -- Check there is a tag to remove local tag = warp.tag @@ -144,7 +143,7 @@ Warps.make_warp_area(warp_id) ]] function Warps.make_warp_area(warp_id) - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) local surface = warp.surface local position = warp.position local posx = position.x @@ -170,7 +169,7 @@ function Warps.make_warp_area(warp_id) end surface.set_tiles(base_tiles) - -- Add a tile patern ontop of the base + -- Add a tile pattern on top of the base local tiles = {} for _, pos in pairs(config.tiles) do table.insert(tiles, {name=base_tile, position={pos[1]+posx, pos[2]+posy}}) @@ -199,7 +198,7 @@ Warps.remove_warp_area(warp_id) ]] function Warps.remove_warp_area(warp_id) - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) local position = warp.position local surface = warp.surface local radius = config.standard_proximity_radius @@ -222,7 +221,7 @@ function Warps.remove_warp_area(warp_id) end surface.set_tiles(tiles) - -- Remove all the entites that are in the area + -- Remove all the entities that are in the area local entities = surface.find_entities_filtered{ force='neutral', area={ @@ -243,7 +242,7 @@ Warps.set_spawn_warp(warp_id, game.player.force) ]] function Warps.set_spawn_warp(warp_id, force) -- Check the force owns this warp - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) if warp.force_name ~= force.name then return end -- Set this warp as the spawn @@ -267,7 +266,7 @@ Warps.teleport_player(warp_id, game.player) ]] function Warps.teleport_player(warp_id, player) - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) local surface = warp.surface local position = { x=warp.position.x+0.5, @@ -299,7 +298,8 @@ local warp_id = Warps.add_warp(player.force.name, player.surface, player.positio ]] function Warps.add_warp(force_name, surface, position, player_name, warp_name) -- Get new warp id - local warp_id = tostring(Token.uid()) + local warp_id = tostring(force_warps._uid) + force_warps._uid = force_warps._uid + 1 warp_name = warp_name or 'New warp' -- Get the existing warps for this force @@ -319,7 +319,7 @@ function Warps.add_warp(force_name, surface, position, player_name, warp_name) end -- Add the new warp to the store - Store.set(warp_store, warp_id, { + WrapData:set(warp_id, { warp_id = warp_id, force_name = force_name, name = warp_name, @@ -345,11 +345,11 @@ Warps.remove_warp(warp_id) ]] function Warps.remove_warp(warp_id) - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) local force_name = warp.force_name Warps.remove_warp_tag(warp_id) Warps.remove_warp_area(warp_id) - Store.clear(warp_store, warp_id) + WrapData:remove(warp_id) table.remove_element(force_warps[force_name], warp_id) end @@ -364,10 +364,9 @@ Warps.update_warp(warp_id, 'My Warp', 'iron-plate', game.player.name) ]] function Warps.update_warp(warp_id, new_name, new_icon, player_name) - Store.update(warp_store, warp_id, function(warp) + WrapData:update(warp_id, function(_, warp) warp.last_edit_name = player_name or '' warp.last_edit_time = game.tick - warp.old_name = warp.name warp.name = new_name or warp.name warp.icon = new_icon or warp.icon end) @@ -383,7 +382,7 @@ Warps.set_editing(warp_id, game.player.name, true) ]] function Warps.set_editing(warp_id, player_name, state) - Store.update(warp_store, warp_id, function(warp) + WrapData:update(warp_id, function(_, warp) warp.currently_editing[player_name] = state end) end @@ -398,7 +397,7 @@ end) ]] function Warps.on_update(handler) - Store.watch(warp_store, handler) + WrapData:on_update(handler) end --- Getters. @@ -414,7 +413,7 @@ local warp = Warps.get_warp(warp_id) ]] function Warps.get_warp(warp_id) - return Store.get(warp_store, warp_id) + return WrapData:get(warp_id) end --[[-- Gets all the warp ids that a force has @@ -452,7 +451,7 @@ local editing = Warps.get_editing(warp_id, game.player.name) ]] function Warps.get_editing(warp_id, player_name) - local warp = Store.get(warp_store, warp_id) + local warp = WrapData:get(warp_id) return warp.currently_editing[player_name] end diff --git a/modules/gui/warp-list.lua b/modules/gui/warp-list.lua index 4736679e..50f98d7e 100644 --- a/modules/gui/warp-list.lua +++ b/modules/gui/warp-list.lua @@ -5,33 +5,30 @@ ]] local Gui = require 'expcore.gui' --- @dep expcore.gui -local Store = require 'expcore.store' --- @dep expcore.store +local Datastore = require 'expcore.datastore' --- @dep expcore.datastore local Global = require 'utils.global' --- @dep utils.global local Event = require 'utils.event' --- @dep utils.event -local Game = require 'utils.game' --- @dep utils.game local Roles = require 'expcore.roles' --- @dep expcore.roles local Colors = require 'utils.color_presets' --- @dep utils.color_presets local config = require 'config.gui.warps' --- @dep config.gui.warps local Warps = require 'modules.control.warps' --- @dep modules.control.warps local format_time = _C.format_time --- @dep expcore.common --- Stores a boolean value indexed by player name -local player_in_range_store = Store.register(function(player) - return player.name -end) +--- Stores all data for the warp gui +local WrapGuiData = Datastore.connect('WrapGuiData') +WrapGuiData:set_serializer(Datastore.name_serializer) +local PlayerInRange = WrapGuiData:combine('PlayerInRange') +PlayerInRange:set_default(false) +local PlayerCooldown = WrapGuiData:combine('PlayerCooldown') +PlayerCooldown:set_default(0) --- Stores the time remaing for a players warp cooldown -local player_warp_cooldown_store = Store.register(function(player) - return player.name -end) - --- Table that stores a boolean value of weather to keep the warp gui open +--- Table that stores a boolean value of weather to keep the warp gui open local keep_gui_open = {} Global.register(keep_gui_open, function(tbl) keep_gui_open = tbl end) --- Styles used for sprite buttons +--- Styles used for sprite buttons local Styles = { sprite20 = Gui.sprite_style(20), sprite22 = Gui.sprite_style(20, nil, { right_margin = -3 }), @@ -55,7 +52,7 @@ local function check_player_permissions(player, action, warp) end end - -- Check player has permisison based on value in the config + -- Check player has permission based on value in the config local action_config = config[action] if action_config == 'all' then return true @@ -65,7 +62,7 @@ local function check_player_permissions(player, action, warp) return Roles.player_allowed(player, config['expcore_roles_'..action]) end - -- Return false as all other condidtions have not been met + -- Return false as all other conditions have not been met return false end @@ -187,7 +184,7 @@ Gui.element{ Warps.set_editing(warp_id, player.name) end) ---- Editing state for a warp, contrins a text field and the two edit buttons +--- Editing state for a warp, contains a text field and the two edit buttons -- @element warp_editing warp_editing = Gui.element(function(event_trigger, parent, warp) @@ -246,7 +243,7 @@ end) player.zoom_to_world(position, 1.5) end) - +local update_wrap_buttons --- Default state for the warp icon, when pressed teleports the player -- @element warp_icon_button warp_icon_button = @@ -269,8 +266,8 @@ end) -- Reset the warp cooldown if the player does not have unlimited warps if not check_player_permissions(player, 'bypass_warp_cooldown') then - Store.set(player_warp_cooldown_store, player, config.cooldown_duraction) - Store.trigger(player_in_range_store, player) + PlayerCooldown:set(player, config.cooldown_duration) + update_wrap_buttons(player) end end) @@ -293,15 +290,43 @@ end) local warp_timer = Gui.element{ type = 'progressbar', - tooltip = {'warp-list.timer-tooltip', config.cooldown_duraction}, + tooltip = {'warp-list.timer-tooltip', config.cooldown_duration}, minimum_value = 0, - maximum_value = config.cooldown_duraction*config.update_smoothing + maximum_value = config.cooldown_duration*config.update_smoothing } :style{ horizontally_stretchable = true, color = Colors.light_blue } +local warp_list_container +--- Update the warp buttons for a player +function update_wrap_buttons(player, timer, in_range) + -- Get the warp table + local frame = Gui.get_left_element(player, warp_list_container) + local scroll_table = frame.container.scroll.table + + -- Check if the buttons should be active + timer = timer or PlayerCooldown:get(player) + in_range = in_range or PlayerInRange:get(player) + local button_disabled = timer > 0 or not in_range + + -- Change the enabled state of the warp buttons + local warp_ids = Warps.get_force_warp_ids(player.force.name) + for _, warp_id in pairs(warp_ids) do + local element = scroll_table['icon-'..warp_id][warp_icon_button.name] + if element and element.valid then + element.enabled = not button_disabled + if button_disabled then + element.tooltip = {'warp-list.goto-disabled'} + else + local position = Warps.get_warp(warp_id).position + element.tooltip = {'warp-list.goto-tooltip', position.x, position.y} + end + end + end +end + --- Updates a warp for a player local function update_warp(player, warp_table, warp_id) local warp = Warps.get_warp(warp_id) @@ -358,10 +383,10 @@ local function update_warp(player, warp_table, warp_id) icon_flow.clear() local warp_icon_element = warp_icon_button(icon_flow, warp) - local timer = Store.get(player_warp_cooldown_store, player) - local in_range = Store.get(player_in_range_store, player) + local timer = PlayerCooldown:get(player) + local in_range = PlayerInRange:get(player) local apply_proximity = not check_player_permissions(player, 'bypass_warp_proximity') - if (timer and timer > 0) or (apply_proximity and not in_range) then + if timer > 0 or (apply_proximity and not in_range) then warp_icon_element.enabled = false warp_icon_element.tooltip = {'warp-list.goto-disabled'} end @@ -381,7 +406,20 @@ end -- Update all the warps for a player local function update_all_warps(player, warp_table) local warp_ids = Warps.get_force_warp_ids(player.force.name) - if #warp_ids > 0 then + warp_table.clear() + for _, warp_id in ipairs(warp_ids) do + update_warp(player, warp_table, warp_id) + end +end + +-- Update all warps for all players on a force +local function update_all_wrap_force(force) + local warp_ids = Warps.get_force_warp_ids(force.name) + for _, player in pairs(force.connected_players) do + local frame = Gui.get_left_element(player, warp_list_container) + local warp_table = frame.container.scroll.table + + warp_table.clear() for _, warp_id in ipairs(warp_ids) do update_warp(player, warp_table, warp_id) end @@ -390,7 +428,7 @@ end --- Main warp list container for the left flow -- @element warp_list_container -local warp_list_container = +warp_list_container = Gui.element(function(event_trigger, parent) -- Draw the internal container local container = Gui.container(parent, event_trigger, 200) @@ -399,7 +437,7 @@ Gui.element(function(event_trigger, parent) local header = Gui.header( container, {'warp-list.main-caption'}, - {'warp-list.sub-tooltip', config.cooldown_duraction, config.standard_proximity_radius}, + {'warp-list.sub-tooltip', config.cooldown_duration, config.standard_proximity_radius}, true ) @@ -421,16 +459,16 @@ Gui.element(function(event_trigger, parent) -- Change the progress of the warp timer local progress = 1 - local timer = Store.get(player_warp_cooldown_store, player) - if timer and timer > 0 then - progress = 1 - (timer/config.cooldown_duraction) + local timer = PlayerCooldown:get(player) + if timer > 0 then + progress = 1 - (timer/config.cooldown_duration) end warp_timer_element.value = progress -- Add any existing warps update_all_warps(player, scroll_table) - -- Return the exteral container + -- Return the external container return container.parent end) :add_to_left_flow() @@ -446,26 +484,140 @@ end) end) --- When the name of a warp is updated this is triggered -Warps.on_update(function(warp, _,removed_warp) +Warps.on_update(function(_, warp, old_warp) -- Get the force to update, warp is nil when removed - local force if warp then - force = game.forces[warp.force_name] + update_all_wrap_force(game.forces[warp.force_name]) else - force = game.forces[removed_warp.force_name] + update_all_wrap_force(game.forces[old_warp.force_name]) + end +end) + +--- When the player leaves or enters range of a warp this is triggered +PlayerInRange:on_update(function(player_name, player_in_range) + local player = game.players[player_name] + + -- Change if the frame is visible based on if the player is in range + if not keep_gui_open[player.name] then + Gui.toggle_left_element(player, warp_list_container, player_in_range) end - -- Update the gui for selected players - local warp_ids = Warps.get_force_warp_ids(force.name) - for _, player in pairs(force.connected_players) do - local frame = Gui.get_left_element(player, warp_list_container) - local scroll_table = frame.container.scroll.table + -- Check if the player requires proximity + if not check_player_permissions(player, 'bypass_warp_proximity') then + update_wrap_buttons(player, nil, player_in_range) + end +end) - -- Update the gui - scroll_table.clear() - for _, next_warp_id in ipairs(warp_ids) do - update_warp(player, scroll_table, next_warp_id) +--- Update the warp cooldown progress bars to match the current cooldown +PlayerCooldown:on_update(function(player_name, player_cooldown) + -- Get the progress bar element + local player = game.players[player_name] + local frame = Gui.get_left_element(player, warp_list_container) + local warp_timer_element = frame.container[warp_timer.name] + + -- Set the progress + local progress = 1 + if player_cooldown and player_cooldown > 0 then + progress = 1 - (player_cooldown/config.cooldown_duration) + end + warp_timer_element.value = progress + + -- Trigger update of buttons if cooldown is now 0 + if player_cooldown == 0 then + update_wrap_buttons(player, player_cooldown, nil) + end +end) + +--- Handles updating the timer and checking distance from a warp +local r2 = config.standard_proximity_radius^2 +local rs2 = config.spawn_proximity_radius^2 +local mr2 = config.minimum_distance^2 +Event.on_nth_tick(math.floor(60/config.update_smoothing), function() + PlayerCooldown:update_all(function(_, player_cooldown) + if player_cooldown > 0 then return player_cooldown - 1 end + end) + + local force_warps = {} + local warps = {} + for _, player in pairs(game.connected_players) do + local was_in_range = PlayerInRange:get(player) + + -- Get the ids of all the warps on the players force + local force_name = player.force.name + local warp_ids = force_warps[force_name] + if not warp_ids then + warp_ids = Warps.get_force_warp_ids(force_name) + force_warps[force_name] = warp_ids end + + -- Check if the force has any warps + local closest_warp + local closest_distance + if #warp_ids > 0 then + local surface = player.surface + local pos = player.position + local px, py = pos.x, pos.y + + -- Loop over each warp + for _, warp_id in ipairs(warp_ids) do + -- Check if warp id is cached + local warp = warps[warp_id] + if not warp then + warp = Warps.get_warp(warp_id) + warps[warp_id] = warp + end + + -- Check if the player is within range + local warp_pos = warp.position + if warp.surface == surface then + local dx, dy = px-warp_pos.x, py-warp_pos.y + local dist = (dx*dx)+(dy*dy) + if closest_distance == nil or dist < closest_distance then + closest_warp = warp + closest_distance = dist + if dist < r2 then break end + end + end + end + + -- Check the dist to the closest warp + local in_range = closest_warp.warp_id == warp_ids.spawn and closest_distance < rs2 or closest_distance < r2 + if was_in_range and not in_range then + PlayerInRange:set(player, false) + elseif not was_in_range and in_range then + PlayerInRange:set(player, true) + end + + -- Change the enabled state of the add warp button + local frame = Gui.get_left_element(player, warp_list_container) + local add_warp_element = frame.container.header.alignment[add_new_warp.name] + local was_able_to_make_warp = add_warp_element.enabled + local can_make_warp = closest_distance > mr2 + if can_make_warp and not was_able_to_make_warp then + add_warp_element.enabled = true + add_warp_element.tooltip = {'warp-list.add-tooltip'} + elseif not can_make_warp and was_able_to_make_warp then + add_warp_element.enabled = false + add_warp_element.tooltip = {'warp-list.too-close', closest_warp.name} + end + + end + + end + +end) + +--- When a player is created make sure that there is a spawn warp created +Event.add(defines.events.on_player_created, function(event) + -- If the force has no spawn then make a spawn warp + local player = game.players[event.player_index] + local force = player.force + local spawn_id = Warps.get_spawn_warp_id(force.name) + if not spawn_id then + local spawn_position = force.get_spawn_position(player.surface) + spawn_id = Warps.add_warp(force.name, player.surface, spawn_position, nil, 'Spawn') + Warps.set_spawn_warp(spawn_id, force) + Warps.make_warp_tag(spawn_id) end end) @@ -494,163 +646,6 @@ end Event.add(Roles.events.on_role_assigned, role_update_event) Event.add(Roles.events.on_role_unassigned, role_update_event) ---- When the player leaves or enters range of a warp this is triggered -Store.watch(player_in_range_store, function(value, player_name) - local player = game.players[player_name] - local force = player.force - - -- Change if the frame is visible based on if the player is in range - if not keep_gui_open[player.name] then - Gui.toggle_left_element(player, warp_list_container, value) - end - - -- Check if the player requires proximity - if check_player_permissions(player, 'bypass_warp_proximity') then - return - end - - -- Get the warp table - local frame = Gui.get_left_element(player, warp_list_container) - local scroll_table = frame.container.scroll.table - - -- Check if the buttons should be active - local timer = Store.get(player_warp_cooldown_store, player) - local button_disabled = timer and timer > 0 or not value - - -- Change the enabled state of the warp buttons - local warp_ids = Warps.get_force_warp_ids(force.name) - for _, warp_id in pairs(warp_ids) do - local element = scroll_table['icon-'..warp_id][warp_icon_button.name] - if element and element.valid then - element.enabled = not button_disabled - if button_disabled then - element.tooltip = {'warp-list.goto-disabled'} - else - local position = Warps.get_warp(warp_id).position - element.tooltip = {'warp-list.goto-tooltip', position.x, position.y} - end - end - end -end) - ---- Update the warp cooldown progress bars to match the store -Store.watch(player_warp_cooldown_store, function(value, player_name, old_value) - if value == old_value then return end - -- Get the progress bar element - local player = game.players[player_name] - local frame = Gui.get_left_element(player, warp_list_container) - local warp_timer_element = frame.container[warp_timer.name] - - -- Set the progress - local progress = 1 - local timer = Store.get(player_warp_cooldown_store, player) - if timer and timer > 0 then - progress = 1 - (timer/config.cooldown_duraction) - end - warp_timer_element.value = progress - - -- Trigger update of buttons if cooldown is now 0 - if value == 0 then - Store.trigger(player_in_range_store, player_name) - end -end) - ---- Handles updating the timer and checking distance from a warp -local r2 = config.standard_proximity_radius^2 -local rs2 = config.spawn_proximity_radius^2 -local mr2 = config.minimum_distance^2 -Event.on_nth_tick(math.floor(60/config.update_smoothing), function() - Store.map(player_warp_cooldown_store, function(value) - if value > 0 then - return value - 1 - end - end) - - local force_warps = {} - local warps = {} - for _, player in pairs(game.connected_players) do - local was_in_range = Store.get(player_in_range_store, player) - - -- Get the ids of all the warps on the players force - local force_name = player.force.name - local warp_ids = force_warps[force_name] - if not warp_ids then - warp_ids = Warps.get_force_warp_ids(force_name) - force_warps[force_name] = warp_ids - end - - -- Check if the force has any warps - local closest_warp - local closest_distance - if #warp_ids > 0 then - local surface = player.surface - local pos = player.position - local px, py = pos.x, pos.y - - -- Loop over each warp - for _, warp_id in ipairs(warp_ids) do - -- Check if warp id is chached - local warp = warps[warp_id] - if not warp then - warp = Warps.get_warp(warp_id) - warps[warp_id] = warp - end - - -- Check if the player is within range - local warp_pos = warp.position - if warp.surface == surface then - local dx, dy = px-warp_pos.x, py-warp_pos.y - local dist = (dx*dx)+(dy*dy) - if closest_distance == nil or dist < closest_distance then - closest_warp = warp - closest_distance = dist - if dist < r2 then break end - end - end - end - - -- Check the dist to the closest warp - local in_range = closest_warp.warp_id == warp_ids.spawn and closest_distance < rs2 or closest_distance < r2 - if was_in_range and not in_range then - Store.set(player_in_range_store, player, false) - elseif not was_in_range and in_range then - Store.set(player_in_range_store, player, true) - end - - -- Change the enabled state of the add warp button - local frame = Gui.get_left_element(player, warp_list_container) - local add_warp_element = frame.container.header.alignment[add_new_warp.name] - local was_able_to_make_warp = add_warp_element.enabled - local can_make_warp = closest_distance > mr2 - if can_make_warp and not was_able_to_make_warp then - add_warp_element.enabled = true - add_warp_element.tooltip = {'warp-list.add-tooltip'} - elseif not can_make_warp and was_able_to_make_warp then - add_warp_element.enabled = false - add_warp_element.tooltip = {'warp-list.too-close', closest_warp.name} - end - - end - - end - -end) - ---- When a player is created make sure that there is a spawn warp created -Event.add(defines.events.on_player_created, function(event) - -- If the force has no spawn then make a spawn warp - local player = Game.get_player_by_index(event.player_index) - local force = player.force - local spawn_id = Warps.get_spawn_warp_id(force.name) - if not spawn_id then - local spawn_position = force.get_spawn_position(player.surface) - spawn_id = Warps.add_warp(force.name, player.surface, spawn_position, nil, 'Spawn') - Warps.set_spawn_warp(spawn_id, force) - Store.trigger(Warps.store, spawn_id) - Warps.make_warp_tag(spawn_id) - end -end) - --- When a chart tag is removed or edited make sure it is not one that belongs to a warp local function maintain_tag(event) if not event.player_index then return end @@ -659,8 +654,8 @@ local function maintain_tag(event) local warp_ids = Warps.get_force_warp_ids(force_name) for _, warp_id in pairs(warp_ids) do local warp = Warps.get_warp(warp_id) - local wtag = warp.tag - if not wtag or not wtag.valid or wtag == tag then + local warp_tag = warp.tag + if not warp_tag or not warp_tag.valid or warp_tag == tag then if event.name == defines.events.on_chart_tag_removed then warp.tag = nil end From 4a31011a2649b57530fc45f5b45e2a9937023724 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Sat, 30 May 2020 23:02:59 +0100 Subject: [PATCH 3/5] Updated Tasks --- expcore/datastore.lua | 2 +- modules/control/tasks.lua | 38 +++++++++++++++++++------------------- modules/control/warps.lua | 2 +- modules/gui/task-list.lua | 10 +++++----- 4 files changed, 26 insertions(+), 26 deletions(-) diff --git a/expcore/datastore.lua b/expcore/datastore.lua index 0a471b07..f0d5baa9 100644 --- a/expcore/datastore.lua +++ b/expcore/datastore.lua @@ -559,7 +559,7 @@ function Datastore:remove(key) key = self:serialize(key) local old_value = self:raw_get(key) self:raw_set(key) - self:raise_event('on_update', key, old_value) + self:raise_event('on_update', key, nil, old_value) if self.save_to_disk then self:write_action('remove', key) end if self.parent and self.parent.auto_save then return self.parent:save(key) end end diff --git a/modules/control/tasks.lua b/modules/control/tasks.lua index 0e8fb941..ec0f8c38 100644 --- a/modules/control/tasks.lua +++ b/modules/control/tasks.lua @@ -10,22 +10,21 @@ Tasks.update_task(task_id, 'We need more iron!', game.player.name) ]] -local Store = require 'expcore.store' --- @dep expcore.store +local Datastore = require 'expcore.datastore' --- @dep expcore.datastore local Global = require 'utils.global' --- @dep utils.global -local Token = require 'utils.token' --- @dep utils.token + +--- Stores all data for the warp gui +local TaskData = Datastore.connect('TaskData') +TaskData:set_serializer(function(raw_key) return raw_key.task_id end) local Tasks = {} -- Global lookup table for force name to task ids -local force_tasks = {} +local force_tasks = {_uid=1} Global.register(force_tasks, function(tbl) force_tasks = tbl end) --- Task store is keyed by task id, value is a table -local task_store = Store.register() -Tasks.store = task_store - --- Setters. -- functions used to created and alter tasks -- @section setters @@ -43,8 +42,9 @@ local task_id = Tasks.add_task(game.player.force.name, nil, game.player.name) ]] function Tasks.add_task(force_name, task_number, player_name, task_message) -- Get a new task id - local task_id = tostring(Token.uid()) + local task_id = tostring(force_tasks._uid) task_message = task_message or 'New Task' + force_tasks._uid = force_tasks._uid + 1 -- Get the existing tasks for this force local tasks = force_tasks[force_name] @@ -67,13 +67,13 @@ function Tasks.add_task(force_name, task_number, player_name, task_message) end -- Add the new task to the store - Store.set(task_store, task_id, { + TaskData:set(task_id, { task_id = task_id, force_name = force_name, message = task_message, last_edit_name = player_name or '', last_edit_time = game.tick, - curently_editing = editing + currently_editing = editing }) return task_id @@ -87,10 +87,10 @@ Tasks.remove_task(task_id) ]] function Tasks.remove_task(task_id) - local task = Store.get(task_store, task_id) + local task = TaskData:get(task_id) local force_name = task.force_name table.remove_element(force_tasks[force_name], task_id) - Store.clear(task_store, task_id) + TaskData:remove(task_id) end --[[-- Update the message and last edited information for a task @@ -103,7 +103,7 @@ Task.update_task(task_id, 'We need more iron!', game.player.name) ]] function Tasks.update_task(task_id, new_message, player_name) - Store.update(task_store, task_id, function(task) + TaskData:update(task_id, function(_, task) task.last_edit_name = player_name or '' task.last_edit_time = game.tick task.message = new_message @@ -120,8 +120,8 @@ Tasks.set_editing(task_id, game.player.name, true) ]] function Tasks.set_editing(task_id, player_name, state) - Store.update(task_store, task_id, function(task) - task.curently_editing[player_name] = state + TaskData:update(task_id, function(_, task) + task.currently_editing[player_name] = state end) end @@ -135,7 +135,7 @@ end) ]] function Tasks.on_update(handler) - Store.watch(task_store, handler) + TaskData:on_update(handler) end --- Getters. @@ -151,7 +151,7 @@ local task = Tasks.get_task(task_id) ]] function Tasks.get_task(task_id) - return Store.get(task_store, task_id) + return TaskData:get(task_id) end --[[-- Gets all the task ids that a force has @@ -176,8 +176,8 @@ local editing = Tasks.get_editing(task_id, game.player.name) ]] function Tasks.get_editing(task_id, player_name) - local task = Store.get(task_store, task_id) - return task.curently_editing[player_name] + local task = TaskData:get(task_id) + return task.currently_editing[player_name] end -- Module Return diff --git a/modules/control/warps.lua b/modules/control/warps.lua index a61e80d4..07be1b0f 100644 --- a/modules/control/warps.lua +++ b/modules/control/warps.lua @@ -25,7 +25,7 @@ local Datastore = require 'expcore.datastore' --- @dep expcore.datastore local Global = require 'utils.global' --- @dep utils.global local config = require 'config.gui.warps' --- @dep config.warps ---- Stores all data for the warp gui +--- Stores all data for the warp system local WrapData = Datastore.connect('WrapData') WrapData:set_serializer(function(raw_key) return raw_key.warp_id end) diff --git a/modules/gui/task-list.lua b/modules/gui/task-list.lua index bdc57818..a83b3aa5 100644 --- a/modules/gui/task-list.lua +++ b/modules/gui/task-list.lua @@ -240,7 +240,7 @@ local function update_task(player, task_table, task_id) -- Update the edit flow local edit_flow = task_table['edit-'..task_id] local player_allowed_edit = check_player_permissions(player, task) - local players_editing = table.get_keys(task.curently_editing) + local players_editing = table.get_keys(task.currently_editing) local edit_task_element = edit_flow[edit_task.name] local discard_task_element = edit_flow[discard_task.name] @@ -257,7 +257,7 @@ local function update_task(player, task_table, task_id) -- Check if the player is was editing and/or currently editing local task_entry = task_flow[task_editing.name] or task_label(task_flow, task) local player_was_editing = task_entry.type == 'textfield' - local player_is_editing = task.curently_editing[player.name] + local player_is_editing = task.currently_editing[player.name] -- Update the task flow if not player_was_editing and not player_is_editing then @@ -361,14 +361,14 @@ Gui.left_toolbar_button('utility/not_enough_repair_packs_icon', {'task-list.main return Roles.player_allowed(player, 'gui/task-list') end) ---- When a new task is added it will udpate the task list for everyone on that force -Tasks.on_update(function(task, task_id, removed_task) +--- When a new task is added it will update the task list for everyone on that force +Tasks.on_update(function(task_id, task, old_task) -- Get the force to update, task is nil when removed local force if task then force = game.forces[task.force_name] else - force = game.forces[removed_task.force_name] + force = game.forces[old_task.force_name] end -- Update the task for all the players on the force From 54987bd8f1e12df17ecdd622b17627ac80703036 Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Sat, 30 May 2020 23:12:00 +0100 Subject: [PATCH 4/5] Updated Player List --- config/gui/player_list_actions.lua | 27 +++-- modules/commands/interface.lua | 1 - modules/gui/debug/expcore_store_view.lua | 128 ----------------------- modules/gui/debug/main_view.lua | 1 - modules/gui/player-list.lua | 68 ++++++------ 5 files changed, 44 insertions(+), 181 deletions(-) delete mode 100644 modules/gui/debug/expcore_store_view.lua diff --git a/config/gui/player_list_actions.lua b/config/gui/player_list_actions.lua index 1bd19bbf..611cd0f0 100644 --- a/config/gui/player_list_actions.lua +++ b/config/gui/player_list_actions.lua @@ -7,7 +7,6 @@ local Gui = require 'expcore.gui' --- @dep expcore.gui local Roles = require 'expcore.roles' --- @dep expcore.roles -local Store = require 'expcore.store' --- @dep expcore.store local Game = require 'utils.game' --- @dep utils.game local Reports = require 'modules.control.reports' --- @dep modules.control.reports local Warnings = require 'modules.control.warnings' --- @dep modules.control.warnings @@ -15,11 +14,9 @@ local Jail = require 'modules.control.jail' --- @dep modules.control.jail local Colors = require 'utils.color_presets' --- @dep utils.color_presets local format_chat_player_name = _C.format_chat_player_name --- @dep expcore.common -local selected_player_store = '' -local selected_action_store = '' -local function set_store_uids(player,action) - selected_player_store = player - selected_action_store = action +local SelectedPlayer, SelectedAction +local function set_datastores(player, action) + SelectedPlayer, SelectedAction = player, action end -- auth that will only allow when on player's of lower roles @@ -33,13 +30,13 @@ end -- gets the action player and a coloured name for the action to be used on local function get_action_player_name(player) - local selected_player_name = Store.get(selected_player_store,player) + local selected_player_name = SelectedPlayer:get(player) local selected_player = Game.get_player_from_any(selected_player_name) local selected_player_color = format_chat_player_name(selected_player) return selected_player_name, selected_player_color end --- telports one player to another +-- teleports one player to another local function teleport(from_player,to_player) local surface = to_player.surface local position = surface.find_non_colliding_position('character',to_player.position,32,1) @@ -109,7 +106,7 @@ local report_player = new_button('utility/spawn_flag',{'player-list.report-playe if Reports.is_reported(selected_player_name,player.name) then player.print({'expcom-report.already-reported'},Colors.orange_red) else - Store.set(selected_action_store,player,'command/report') + SelectedAction:set(player, 'command/report') end end) @@ -125,7 +122,7 @@ end -- @element warn_player local warn_player = new_button('utility/spawn_flag',{'player-list.warn-player'}) :on_click(function(player) - Store.set(selected_action_store,player,'command/give-warning') + SelectedAction:set(player, 'command/give-warning') end) local function warn_player_callback(player,reason) @@ -143,7 +140,7 @@ local jail_player = new_button('utility/multiplayer_waiting_icon',{'player-list. if Jail.is_jailed(selected_player_name) then player.print({'expcom-jail.already-jailed', selected_player_color},Colors.orange_red) else - Store.set(selected_action_store,player,'command/jail') + SelectedAction:set(player, 'command/jail') end end) @@ -162,7 +159,7 @@ local temp_ban_player = new_button('utility/warning_white',{'player-list.temp-ba if Jail.is_jailed(selected_player_name) then player.print({'expcom-jail.already-banned', selected_player_color},Colors.orange_red) else - Store.set(selected_action_store,player,'command/temp-ban') + SelectedAction:set(player, 'command/temp-ban') end end) @@ -177,7 +174,7 @@ end -- @element kick_player local kick_player = new_button('utility/warning_icon',{'player-list.kick-player'}) :on_click(function(player) - Store.set(selected_action_store,player,'command/kick') + SelectedAction:set(player, 'command/kick') end) local function kick_player_callback(player,reason) @@ -189,7 +186,7 @@ end -- @element ban_player local ban_player = new_button('utility/danger_icon',{'player-list.ban-player'}) :on_click(function(player) - Store.set(selected_action_store,player,'command/ban') + SelectedAction:set(player, 'command/ban') end) local function ban_player_callback(player,reason) @@ -198,7 +195,7 @@ local function ban_player_callback(player,reason) end return { - set_store_uids = set_store_uids, + set_datastores = set_datastores, buttons = { ['command/teleport'] = { auth=function(player,selected_player) diff --git a/modules/commands/interface.lua b/modules/commands/interface.lua index c6291970..9b73be17 100644 --- a/modules/commands/interface.lua +++ b/modules/commands/interface.lua @@ -15,7 +15,6 @@ local interface_modules = { ['output']=Common.player_return, ['Group']='expcore.permission_groups', ['Roles']='expcore.roles', - ['Store']='expcore.store', ['Gui']='expcore.gui', ['Async']='expcore.async', ['Datastore']='expcore.datastore' diff --git a/modules/gui/debug/expcore_store_view.lua b/modules/gui/debug/expcore_store_view.lua deleted file mode 100644 index 36ab8027..00000000 --- a/modules/gui/debug/expcore_store_view.lua +++ /dev/null @@ -1,128 +0,0 @@ -local Gui = require 'utils.gui' --- @dep utils.gui -local Store = require 'expcore.store' --- @dep utils.global -local Color = require 'utils.color_presets' --- @dep utils.color_presets -local Model = require 'modules.gui.debug.model' --- @dep modules.gui.debug.model - -local dump = Model.dump -local dump_text = Model.dump_text -local concat = table.concat - -local Public = {} - -local header_name = Gui.uid_name() -local left_panel_name = Gui.uid_name() -local right_panel_name = Gui.uid_name() -local input_text_box_name = Gui.uid_name() -local refresh_name = Gui.uid_name() - -Public.name = 'Store' - -function Public.show(container) - local main_flow = container.add {type = 'flow', direction = 'horizontal'} - - local left_panel = main_flow.add {type = 'scroll-pane', name = left_panel_name} - local left_panel_style = left_panel.style - left_panel_style.width = 300 - - for store_id, file_path in pairs(Store.file_paths) do - local header = left_panel.add({type = 'flow'}).add {type = 'label', name = header_name, caption = store_id..' - '..file_path} - Gui.set_data(header, store_id) - end - - local right_flow = main_flow.add {type = 'flow', direction = 'vertical'} - - local right_top_flow = right_flow.add {type = 'flow', direction = 'horizontal'} - - local input_text_box = right_top_flow.add {type = 'text-box', name = input_text_box_name} - local input_text_box_style = input_text_box.style - input_text_box_style.horizontally_stretchable = true - input_text_box_style.height = 32 - input_text_box_style.maximal_width = 1000 - - local refresh_button = - right_top_flow.add {type = 'sprite-button', name = refresh_name, sprite = 'utility/reset', tooltip = 'refresh'} - local refresh_button_style = refresh_button.style - refresh_button_style.width = 32 - refresh_button_style.height = 32 - - local right_panel = right_flow.add {type = 'text-box', name = right_panel_name} - right_panel.read_only = true - right_panel.selectable = true - - local right_panel_style = right_panel.style - right_panel_style.vertically_stretchable = true - right_panel_style.horizontally_stretchable = true - right_panel_style.maximal_width = 1000 - right_panel_style.maximal_height = 1000 - - local data = { - right_panel = right_panel, - input_text_box = input_text_box, - selected_header = nil - } - - Gui.set_data(input_text_box, data) - Gui.set_data(left_panel, data) - Gui.set_data(refresh_button, data) -end - -Gui.on_click( - header_name, - function(event) - local element = event.element - local store_id = Gui.get_data(element) - - local left_panel = element.parent.parent - local data = Gui.get_data(left_panel) - local right_panel = data.right_panel - local selected_header = data.selected_header - local input_text_box = data.input_text_box - - if selected_header then - selected_header.style.font_color = Color.white - end - - element.style.font_color = Color.orange - data.selected_header = element - - input_text_box.text = concat {'global.data_store[', store_id, ']'} - input_text_box.style.font_color = Color.black - - local content = dump(Store.get(store_id)) or 'nil' - right_panel.text = content - end -) - -local function update_dump(text_input, data, player) - local suc, ouput = dump_text(text_input.text, player) - if not suc then - text_input.style.font_color = Color.red - else - text_input.style.font_color = Color.black - data.right_panel.text = ouput - end -end - -Gui.on_text_changed( - input_text_box_name, - function(event) - local element = event.element - local data = Gui.get_data(element) - - update_dump(element, data, event.player) - end -) - -Gui.on_click( - refresh_name, - function(event) - local element = event.element - local data = Gui.get_data(element) - - local input_text_box = data.input_text_box - - update_dump(input_text_box, data, event.player) - end -) - -return Public diff --git a/modules/gui/debug/main_view.lua b/modules/gui/debug/main_view.lua index bdc93f43..6fef9c16 100644 --- a/modules/gui/debug/main_view.lua +++ b/modules/gui/debug/main_view.lua @@ -6,7 +6,6 @@ local Public = {} local pages = { require 'modules.gui.debug.redmew_global_view', require 'modules.gui.debug.expcore_datastore_view', - require 'modules.gui.debug.expcore_store_view', require 'modules.gui.debug.expcore_gui_view', require 'modules.gui.debug.global_view', require 'modules.gui.debug.package_view', diff --git a/modules/gui/player-list.lua b/modules/gui/player-list.lua index 497c6793..83c37431 100644 --- a/modules/gui/player-list.lua +++ b/modules/gui/player-list.lua @@ -7,25 +7,21 @@ -- luacheck:ignore 211/Colors local Gui = require 'expcore.gui' --- @dep expcore.gui local Roles = require 'expcore.roles' --- @dep expcore.roles -local Store = require 'expcore.store' --- @dep expcore.store +local Datastore = require 'expcore.datastore' --- @dep expcore.datastore local Game = require 'utils.game' --- @dep utils.game local Event = require 'utils.event' --- @dep utils.event local config = require 'config.gui.player_list_actions' --- @dep config.gui.player_list_actions local Colors = require 'utils.color_presets' --- @dep utils.color_presets local format_time = _C.format_time --- @dep expcore.common --- Stores the name of the player a player has selected -local selected_player_store = Store.register(function(player) - return player.name -end) - --- Stores the current action that a player wants to do -local selected_action_store = Store.register(function(player) - return player.name -end) +--- Stores all data for the warp gui +local PlayerListData = Datastore.connect('PlayerListData') +PlayerListData:set_serializer(Datastore.name_serializer) +local SelectedPlayer = PlayerListData:combine('SelectedPlayer') +local SelectedAction = PlayerListData:combine('SelectedAction') -- Set the config to use these stores -config.set_store_uids(selected_player_store, selected_action_store) +config.set_datastores(SelectedPlayer, SelectedAction) --- Button used to open the action bar -- @element open_action_bar @@ -43,11 +39,11 @@ Gui.element{ } :on_click(function(player, element, _) local selected_player_name = element.parent.name - local old_selected_player_name = Store.get(selected_player_store, player) + local old_selected_player_name = SelectedPlayer:get(player) if selected_player_name == old_selected_player_name then - Store.clear(selected_player_store, player) + SelectedPlayer:remove(player) else - Store.set(selected_player_store, player, selected_player_name) + SelectedPlayer:set(player, selected_player_name) end end) @@ -62,8 +58,8 @@ Gui.element{ } :style(Gui.sprite_style(30, -1, { top_margin = -1, right_margin = -1 })) :on_click(function(player, _) - Store.clear(selected_player_store, player) - Store.clear(selected_action_store, player) + SelectedPlayer:remove(player) + SelectedAction:remove(player) end) --- Button used to confirm a reason @@ -78,11 +74,11 @@ Gui.element{ :style(Gui.sprite_style(30, -1, { left_margin = -2, right_margin = -1 })) :on_click(function(player, element) local reason = element.parent.entry.text or 'Non Given' - local action_name = Store.get(selected_action_store, player) + local action_name = SelectedAction:get(player) local reason_callback = config.buttons[action_name].reason_callback reason_callback(player, reason) - Store.clear(selected_player_store, player) - Store.clear(selected_action_store, player) + SelectedPlayer:remove(player) + SelectedAction:remove(player) element.parent.entry.text = '' end) @@ -126,12 +122,12 @@ end) event.player.zoom_to_world(position, 1.75) else -- RMB will toggle the settings - local old_selected_player_name = Store.get(selected_player_store, player) + local old_selected_player_name = SelectedPlayer:get(player) if selected_player_name == old_selected_player_name then - Store.clear(selected_player_store, player) - Store.clear(selected_action_store, player) + SelectedPlayer:remove(player) + SelectedAction:remove(player) else - Store.set(selected_player_store, player, selected_player_name) + SelectedPlayer:set(player, selected_player_name) end end end) @@ -174,7 +170,7 @@ end) --- Updates the visible state of the action bar buttons local function update_action_bar(element) local player = Gui.get_player_from_element(element) - local selected_player_name = Store.get(selected_player_store, player) + local selected_player_name = SelectedPlayer:get(player) if not selected_player_name then -- Hide the action bar when no player is selected @@ -185,8 +181,8 @@ local function update_action_bar(element) if not selected_player.connected then -- If the player is offline then reest stores element.visible = false - Store.clear(selected_player_store, player) - Store.clear(selected_action_store, player) + SelectedPlayer:remove(player) + SelectedAction:remove(player) else -- Otherwise check what actions the player is allowed to use @@ -367,10 +363,10 @@ Event.add(defines.events.on_player_left_game, function(event) local scroll_table = frame.container.scroll.table remove_player_base(scroll_table, remove_player) - local selected_player_name = Store.get(selected_player_store, player) + local selected_player_name = SelectedPlayer:get(player) if selected_player_name == remove_player.name then - Store.clear(selected_player_store, player) - Store.clear(selected_action_store, player) + SelectedPlayer:remove(player) + SelectedAction:remove(player) end end end) @@ -393,7 +389,7 @@ Event.add(Roles.events.on_role_assigned, redraw_player_list) Event.add(Roles.events.on_role_unassigned, redraw_player_list) --- When the action player is changed the action bar will update -Store.watch(selected_player_store, function(value, player_name) +SelectedPlayer:on_update(function(player_name, selected_player) local player = Game.get_player_from_any(player_name) local frame = Gui.get_left_element(player, player_list_container) local scroll_table = frame.container.scroll.table @@ -401,7 +397,7 @@ Store.watch(selected_player_store, function(value, player_name) for _, next_player in pairs(game.connected_players) do local element = scroll_table[next_player.name][open_action_bar.name] local style = 'frame_button' - if next_player.name == value then + if next_player.name == selected_player then style = 'tool_button' end element.style = style @@ -413,20 +409,20 @@ Store.watch(selected_player_store, function(value, player_name) end) --- When the action name is changed the reason input will update -Store.watch(selected_action_store, function(value, player_name) +SelectedAction:on_update(function(player_name, selected_action) local player = Game.get_player_from_any(player_name) local frame = Gui.get_left_element(player, player_list_container) local element = frame.container.reason_bar - if value then + if selected_action then -- if there is a new value then check the player is still online - local selected_player_name = Store.get(selected_player_store, player_name) + local selected_player_name = SelectedPlayer:get(player_name) local selected_player = Game.get_player_from_any(selected_player_name) if selected_player.connected then element.visible = true else -- Clear if the player is offline - Store.clear(selected_player_store, player_name) - Store.clear(selected_action_store, player_name) + SelectedPlayer:remove(player) + SelectedAction:remove(player) end else From 8ff06ece1f37dad4114403ffe9a39e97ad7b241c Mon Sep 17 00:00:00 2001 From: Cooldude2606 Date: Sat, 30 May 2020 23:12:55 +0100 Subject: [PATCH 5/5] Removed Store From Core --- expcore/store.lua | 523 ------------------------------------ modules/data/statistics.lua | 2 +- 2 files changed, 1 insertion(+), 524 deletions(-) delete mode 100644 expcore/store.lua diff --git a/expcore/store.lua b/expcore/store.lua deleted file mode 100644 index c6353d64..00000000 --- a/expcore/store.lua +++ /dev/null @@ -1,523 +0,0 @@ ---[[-- Core Module - Store -- Used to store and watch for updates for values in the global table -@core Store -@alias Store - -@usage-- Require the module and add a store with no keys --- Store with no keys does not need a serializer -local Store = require 'expcore.store' --- @dep expcore.store -local scenario_diffculty = Store.register() - --- When the store is changed this function will trigger -Store.watch(scenario_diffculty, function(value) - game.print('The scenario diffculty has been set to '..value) -end) - -Store.set(scenario_diffculty, 'hard') -- Set the value stored to 'hard' -Store.get(scenario_diffculty) -- Returns 'hard' -Store.update(scenario_diffculty, function(value) -- Will set value to 'normal' if no value is present - return not value and 'normal' -end) - -@usage-- Require the module and add a store with keys --- Store with keys does not require a serializer but it can be helpful -local Store = require 'expcore.store' --- @dep expcore.store -local player_scores = Store.register(function(player) -- Use player name as the key - return player.name -end) - --- When any key in the store is changed this function will trigger -Store.watch(player_scores, function(value, key, old_value) - game.print(key..' now has a score of '..value) -end) - -Store.set(player_scores, game.player, 10) -- Set your score to 10 -Store.get(scenario_diffculty, game.player) -- Returns 10 -Store.update(scenario_diffculty, game.player, function(value) -- Add 1 to your score - return value + 1 -end) - -]] - -local Event = require 'utils.event' --- @dep utils.event - -local Store = { - --- The current highest uid that is being used, will not increase during runtime - -- @field uid - uid = 0, - --- An array of the serializers that stores are using, key is store uids - -- @table serializers - serializers = {}, - --- An array of watchers that stores will trigger, key is store uids - -- @table watchers - watchers = {}, - --- An index used for debuging to find the file where different stores where registered - -- @table file_paths - file_paths = {} -} - --- All data is stored in global.data_store and is accessed here with data_store -local data_store = {} -global.data_store = data_store -Event.on_load(function() - data_store = global.data_store -end) - ---- Store Setup. --- @section setup - ---[[-- An error checking and serializing function for checking store uids and keys, note key is not required -@tparam number store the uid of the store that you want to check is valid -@tparam[opt] ?string|any key the key that you want to serialize or check is a string -@tparam[opt=1] number error_stack the position in the stack relative to the current function (1) to raise this error on -@treturn string if key is given and a serializer is registered, or key was already a string, then the key is returned - -@usage-- Registering a new store and checking that it is valid --- New store will use player names as the keys -local player_scores = Store.register(function(player) - return player.name -end) - --- player_scores is a valid store and key will be your player name -local key = Store.validate(player_scores, game.player) - -]] -function Store.validate(store, key, error_stack) - error_stack = error_stack or 1 - - if type(store) ~= 'number' then - -- Store is not a number and so if not valid - error('Store uid given is not a number; recived type '..type(store), error_stack+1) - elseif store > Store.uid then - -- Store is a number but it is out of range, ie larger than the current highest uid - error('Store uid is out of range; recived '..tostring(store), error_stack+1) - elseif key ~= nil and type(key) ~= 'string' and Store.serializers[store] == nil then - -- Key is present but is not a string and there is no serializer registered - error('Store key is not a string and no serializer has been registered; recived '..type(key), error_stack+1) - elseif key ~= nil then - -- Key is present and so it is serialized and returned - local serializer = Store.serializers[store] - if type(key) ~= 'string' then - local success, serialized_key = pcall(serializer, key) - - if not success then - -- Serializer casued an error while serializing the key - error('Store watcher casued an error:\n\t'..key, error_stack+1) - elseif type(serialized_key) ~= 'string' then - -- Serializer was successful but failed to return a string value - error('Store key serializer did not return a string; recived type '..type(key), error_stack+1) - end - - return serialized_key - end - - return key - end - -end - ---[[-- Required to create new stores and register an serializer to a store, serializer not required -@tparam[opt] function serializer the function used to convert non string keys into strings to be used in the store -@treturn number the uid for the new store that you have created, use this as the first param to all other functions - -@usage-- Creating a store with no serializer -local scenario_diffculty = Store.register() - -@usage-- Creating a store which can take LuaPlayer -local player_scores = Store.register(function(player) - return player.name -end) - -]] -function Store.register(serializer) - if _LIFECYCLE ~= _STAGE.control then - -- Only allow this function to be called during the control stage - error('Store can not be registered durring runtime', 2) - end - - -- Increment the uid counter - local uid = Store.uid + 1 - Store.uid = uid - - -- Register the serializer if given - if serializer then - Store.serializers[uid] = serializer - end - - -- Add entry in the debug table - local file_path = debug.getinfo(2, 'S').source:match('^.+/currently%-playing/(.+)$'):sub(1, -5) - Store.file_paths[uid] = file_path - - -- Return the new uid - return uid -end - ---[[-- Register a watch function to a store that is called when the value in the store is changed, triggers for any key -@tparam number store the uid of the store that you want to watch for changes to -@tparam function watcher the function that will be called when there is a change to the store - -@usage-- Printing the changed value to all players, no keys --- Register the new store, we are not using keys so we dont need a serializer -local scenario_diffculty = Store.register() - --- Register the watcher so that when we change the value the message is printed -Store.watch(scenario_diffculty, function(value) - game.print('The scenario diffculty has been set to '..value) -end) - --- Set a new value for the diffculty and see that it has printed to the game -Store.set(scenario_diffculty, 'hard') - -@usage-- Printing the changed value to all players, with keys --- Register the new store, we are not using player names as the keys so it would be useful to accept LuaPlayer objects -local player_scores = Store.register(function(player) - return player.name -end) - --- Register the watcher so that when we change the value the message is printed -Store.watch(player_scores, function(value, key, old_value) - game.print(key..' now has a score of '..value) -end) - --- Set a new value for your score and see that it has printed to the game -Store.set(player_scores, game.player, 10) - -]] -function Store.watch(store, watcher) - if _LIFECYCLE ~= _STAGE.control then - -- Only allow this function to be called during the control stage - error('Store watcher can not be registered durring runtime', 2) - end - - Store.validate(store, nil, 2) - - -- Add the watchers table if it does not exist - local watchers = Store.watchers[store] - if not watchers then - watchers = {} - Store.watchers[store] = watchers - end - - -- Append the new watcher function - watchers[#watchers+1] = watcher -end - ---- Store Data Management. --- @section data - ---[[-- Used to retrive the current data that is stored, key is optional depending on if you are using them -@tparam number store the uid of the store that you want to get the value from -@tparam[opt] ?string|any key the key that you want to get the value of, must be a string unless you have a serializer -@treturn any the data that is stored - -@usage-- Getting the value of a store with no keys --- Register the new store, we are not using keys so we dont need a serializer -local scenario_diffculty = Store.register() - --- Get the current diffculty for the scenario -local diffculty = Store.get(scenario_diffculty) - -@usage-- Getting the data from a store with keys --- Register the new store, we are not using player names as the keys so it would be useful to accept LuaPlayer objects -local player_scores = Store.register(function(player) - return player.name -end) - --- Get your current score -local my_score = Store.get(player_scores, game.player) - --- Get all scores -lcoal scores = Store.get(player_scores) - -]] -function Store.get(store, key) - key = Store.validate(store, key, 2) - - -- Get the data from the data store - local data = data_store[store] - if key then - if type(data) ~= 'table' then - data_store[store] = {_value = data_store[store]} - return nil - else - return data[key] - end - end - - -- Return all data if there is no key - return data -end - ---[[-- Used to clear the data in a store, will trigger any watchers, key is optional depending on if you are using them -@tparam number store the uid of the store that you want to clear -@tparam[opt] ?string|any key the key that you want to clear, must be a string unless you have a serializer - -@usage-- Clear a store which does not use keys --- Register the new store, we are not using keys so we dont need a serializer -local scenario_diffculty = Store.register() - --- Clear the scenario diffculty -Store.clear(scenario_diffculty) - -@usage-- Clear data that is in a store with keys --- Register the new store, we are not using player names as the keys so it would be useful to accept LuaPlayer objects -local player_scores = Store.register(function(player) - return player.name -end) - --- Clear your score -Store.clear(player_scores, game.player) - --- Clear all scores -Store.clear(player_scores) - -]] -function Store.clear(store, key) - key = Store.validate(store, key, 2) - local old_value - - -- Check if there is a key being used - if key then - if type(data_store[store]) == 'table' then - old_value = data_store[store][key] - data_store[store][key] = nil - end - else - old_value = data_store[store] - data_store[store] = nil - end - - -- Trigger any watch functions - Store.raw_trigger(store, key, nil, old_value) -end - ---[[-- Used to set the data in a store, will trigger any watchers, key is optional depending on if you are using them -@tparam number store the uid of the store that you want to set -@tparam[opt] ?string|any key the key that you want to set, must be a string unless you have a serializer -@tparam any value the value that you want to set - -@usage-- Setting a store which does not use keys --- Register the new store, we are not using keys so we dont need a serializer -local scenario_diffculty = Store.register() - --- Set the new scenario diffculty -Store.set(scenario_diffculty, 'hard') - -@usage-- Set data in a store with keys --- Register the new store, we are not using player names as the keys so it would be useful to accept LuaPlayer objects -local player_scores = Store.register(function(player) - return player.name -end) - --- Set your current score -Store.set(player_scores, game.player, 10) - --- Set all scores, note this might not have much use -Store.set(player_scores, { - [game.player.name] = 10, - ['SomeOtherPlayer'] = 0 -}) - -]] -function Store.set(store, key, value) - -- Allow for key to be optional - if value == nil then - value = key - key = nil - end - - -- Check the store is valid - key = Store.validate(store, key, 2) - local old_value - - -- If there is a key being used then the store must be a able - if key then - if type(data_store[store]) ~= 'table' then - data_store[store] = {_value = data_store[store]} - end - old_value = data_store[store][key] - data_store[store][key] = value - else - old_value = data_store[store] - data_store[store] = value - end - - -- Trigger any watchers - Store.raw_trigger(store, key, value, old_value) -end - ---[[-- Used to update the data in a store, use this with tables, will trigger any watchers, key is optional depending on if you are using them -@tparam number store the uid of the store that you want to update -@tparam[opt] ?string|any key the key that you want to update, must be a string unless you have a serializer -@tparam function updater the function which is called to make changes to the value, such as changing table keys, if a value is returned it will replace the current value in the store - -@usage-- Incrementing a global score --- Because we are only going to have one score so we will not need keys or a serializer -local game_score = Store.register() - --- Setting a default value -Store.set(game_score, 0) - --- We now will update the game score by one, we return the value so that it is set as the new value in the store -Store.update(game_score, function(value) - return value + 1 -end) - -@usage-- Updating keys in a table of data --- Register the new store, we are not using player names as the keys so it would be useful to accept LuaPlayer objects -local player_data = Store.register(function(player) - return player.name -end) - --- Setting a default value for your player, used to show the table structure -Store.set(player_data, game.player, { - group = 'Admin', - role = 'Owner', - show_group_config = false -}) - --- Updating the show_group_config key in your player data, note that it would be harder to call set every time --- We do not need to return anything in this case as we are not replacing all the data -Store.update(player_data, game.player, function(data) - data.show_group_config = not data.show_group_config -end) - -]] -function Store.update(store, key, updater) - -- Allow for key to be nil - if updater == nil then - updater = key - key = nil - end - - -- Check the store is valid - key = Store.validate(store, key, 2) - local value, old_value - - -- If a key is used then the store must be a table - if key then - if type(data_store[store]) ~= 'table' then - data_store[store] = {_value = data_store[store]} - end - - -- Call the updater and if it returns a value then set this value - local rtn = updater(data_store[store][key]) - if rtn then - old_value = data_store[store][key] - data_store[store][key] = rtn - end - value = data_store[store][key] - - else - -- Call the updater and if it returns a value then set this value - local rtn = updater(data_store[store]) - if rtn then - old_value = data_store[store][key] - data_store[store] = rtn - end - value = data_store[store] - - end - - -- Trigger any watchers - Store.raw_trigger(store, key, value, old_value) -end - ---[[-- Used to update all values that are in a store, similar to Store.update but acts on all keys at once, will trigger watchers for every key present -@tparam number store the uid of the store that you want to map -@tparam function updater the function that is called on every key in this store - -@usage-- Updating keys in a table of data --- Register the new store, we are not using player names as the keys so it would be useful to accept LuaPlayer objects -local player_data = Store.register(function(player) - return player.name -end) - --- Setting a default value for your player, used to show the table structure -Store.set(player_data, game.player, { - group = 'Admin', - role = 'Owner', - show_group_config = false -}) - --- Updating the show_group_config key for all players, note that it would be harder to call set every time --- We do not need to return anything in this case as we are not replacing all the data --- We also have access to the current key being updated if needed -Store.map(player_data, function(data, key) - data.show_group_config = not data.show_group_config -end) - -]] -function Store.map(store, updater) - Store.validate(store, nil, 2) - - -- Get all that data in the store and check its a table - local data = data_store[store] - if type(data) ~= 'table' then - return - end - - -- Loop over all the keys and call the updater, setting value if returned, and calling watcher functions - for key, value in pairs(data) do - local rtn = updater(value, key) - if rtn then - data[key] = rtn - end - Store.raw_trigger(store, key, data[key], value) - end -end - ---[[-- Used to trigger watcher functions, this may be used to trigger them if you did not use Store.update or Store.set -@tparam number store the uid of the store that you want to trigger -@tparam[opt] ?string|any key the key that you want to trigger, must be a string unless you have a serializer -@usage-- Faking the update to a store --- The type of store we use does not really matter for this as long as you pass it what you watchers are expecting -local scenario_diffculty = Store.register() - --- Trigger the watchers with a fake change of diffculty -Store.trigger(scenario_diffculty) - -]] -function Store.trigger(store, key) - key = Store.validate(store, key, 2) - - -- Get the data from the data store - local data = data_store[store] - if key then - data = data[key] - Store.raw_trigger(store, key, data, data) - else - Store.raw_trigger(store, key, data, data) - end -end - ---[[-- Used to trigger watcher functions, the value and key are passed directly to the watchers regardless if the value is correct -@tparam number store the uid of the store that you want to trigger -@tparam[opt] ?string|any key the key that you want to trigger, must be a string unless you have a serializer -@tparam[opt] any value the new value that is at this key or store, passed directly to the watcher -@tparam[opt] any old_value the old value that was at this key or store often the same if value is a table, passed directly to the watcher - -@usage-- Triggering a manule call of the watchers --- The type of store we use does not really matter for this as long as you pass it what you watchers are expecting -local scenario_diffculty = Store.register() - --- Trigger the watchers with a fake change of diffculty --- This is mostly used internally but it can be useful in other cases -Store.raw_trigger(scenario_diffculty, nil, 'normal', 'normal') - -]] -function Store.raw_trigger(store, key, value, old_value) - key = Store.validate(store, key, 2) - - -- Get the watchers and then loop over them - local watchers = Store.watchers[store] or {} - for _, watcher in pairs(watchers) do - local success, err = pcall(watcher, value, key, old_value) - if not success then - error('Store watcher casued an error:\n\t'..err) - end - end -end - --- Module return -return Store \ No newline at end of file diff --git a/modules/data/statistics.lua b/modules/data/statistics.lua index fd554b8b..5aa305fa 100644 --- a/modules/data/statistics.lua +++ b/modules/data/statistics.lua @@ -89,7 +89,7 @@ if config.DamageDealt then local stat = Statistics:combine('Kills') Event.add(defines.events.on_entity_died, function(event) local character = event.cause -- Check character is valid - if not character.valid or character.type ~= 'character' then return end + if not character or not character.valid or character.type ~= 'character' then return end local player = character.player -- Check player is valid if not player.valid or not player.connected then return end local entity = event.entity -- Check entity is valid