Renames in Store

This commit is contained in:
Cooldude2606
2019-08-23 21:41:43 +01:00
parent 70c60ddb5c
commit 5e1be09b3c
99 changed files with 820 additions and 755 deletions

View File

@@ -4,119 +4,68 @@
@alias Store
@usage
---- Basic Use
-- At the most basic level this allows for the naming of locations to store in the global table, the second feature is that you are
-- able to listen for updates of this value, which means that when ever the set function is called it will trigger the update callback.
-- The data store module is designed to be an alterative way to store data in the global table
-- each piece of data is stored at a location and optional key of that location
-- it is recomented that you use a local varible to store the location
local scenario_difficuly = Store.uid_location()
local team_scores = 'team-scores'
-- This may be useful when storing config values and when they get set you want to make sure it is taken care of, or maybe you want
-- to have a value that you can trigger an update of from different places.
-- Setting and getting data is then as simple as
Store.set(scenario_difficuly,'Hard')
Store.set(team_scores,game.player.force.name,20)
-- This will register a new location called 'scenario.difficulty'
-- note that setting a start value is optional and we could take nil to mean normal
Store.register('scenario.difficulty',function(value)
game.print('The scenario difficulty has be set to: '..value)
end)
Store.get(scenario_difficuly) -- returns 'Hard'
Store.get(team_scores,game.player.force.name) -- returns 20
-- This will set the value in the store to 'hard' and will trigger the update callback which will print a message to the game
Store.set('scenario.difficulty','hard')
-- The reason for using stores over global is the abilty to watch for updates
-- for stores to work you must register them, often at the end of the file
-- note that storing a table value may cause issues as a key changing does not cause the set function to trigger
Store.register(scenario_difficuly,function(value)
game.print('Scenario difficulty has been set to: '..value)
end)
-- This will return 'hard'
Store.get('scenario.difficulty')
Store.register(team_scores,function(value,key)
game.print('Team '..key..' now has a score of '..value)
end)
@usage
---- Using Children
-- One limitation of store is that all locations must be registered to avoid desyncs, to get round this issue "children" can be used.
-- When you set the value of a child it does not have its own update callback so rather the "parent" location which has been registered
-- will have its update value called with a second param of the name of that child.
-- This may be useful when you want a value of each player or force and since you cant register every player at the start you must use
-- the players name as the child name.
-- This will register the location 'scenario.score' where we plan to use force names as the child
Store.register('scenario.score',function(value,child)
game.print(child..' now has a score of '..value)
end)
-- This will return nil, but will not error as children don't need to be registered
Store.get('scenario.score','player')
-- This will set 'player' to have a value of 10 for 'scenario.score' and trigger the game message print
Store.set('scenario.score','player',10)
-- This would be the similar to Store.get however this will return the names of all the children
Store.get_children('scenario.score')
@usage
---- Using Sync
-- There is the option to use synced values which is the same as a normal value however you can combine this with an external script
-- which can read the output from 'script-output/log/store.log' and have it send rcon commands back to the game allowing for cross instance
-- syncing of values.
-- This may be useful when you want to have a value change effect multiple instances or even if you just want a database to store values so
-- you can sync data between map resets.
-- This example will register the location 'statistics.total-play-time' where we plan to use plan names as the child
-- note that the location must be the same across instances
Store.register('statistics.total-play-time',true,function(value,child)
game.print(child..' now has now played for '..value)
end)
-- Use of set and are all the same as non synced but you should include from_sync as true
@usage
---- Alternative method
-- Some people may prefer to use a variable rather than a string for formating reasons here is an example. Also for any times when
-- there will be little external input Store.uid_location() can be used to generate non conflicting locations, uid_location will also
-- be used if you give a nil location.
local store_game_speed =
Store.register(function(value)
game.print('The game speed has been set to: '..value)
end)
-- This can be very powerful when working with data that can be changed for a number of locations
-- with this module you can enable any location to output its changes to a file
-- say we wanted team scores to be synced across servers or between saves
-- although you will need to set up a method of storing the data outside the game
Store.register(team_scores,true,function(value,key)
game.print('Team '..key..' now has a score of '..value)
end)
]]
local Global = require 'utils.global' --- @dep utils.global
local Event = require 'utils.event' --- @dep utils.event
local table_keys,write_json = ext_require('expcore.common','table_keys','write_json') --- @dep expcore.common
local table_keys,write_json,get_file_path = ext_require('expcore.common','table_keys','write_json','get_file_path') --- @dep expcore.common
local Token = require 'utils.token' --- @dep utils.token
local Store = {
data={},
registered={},
synced={},
callbacks={},
events = {
on_value_update=script.generate_event_name()
on_value_changed=script.generate_event_name()
}
}
local store_data = {}
Global.register(Store.data,function(tbl)
Store.data = tbl
store_data = tbl
end)
local function error_not_table(value)
if type(value) ~= 'table' then
error('Location is not a table can not use child locations',3)
error('Location is not a table can not use key locations',3)
end
end
--- Check for if a location is registered
-- @tparam string location the location to test for
-- @treturn boolean true if registered
function Store.is_registered(location)
return Store.registered[location]
end
--- Returns a unique name that can be used for a store
-- @treturn string a unique name
function Store.uid_location()
return tostring(Token.uid())
end
--- Registers a new location with an update callback which is triggered when the value updates
-- @tparam[opt] string location string a unique that points to the data, string used rather than token to allow migration
-- @tparam[opt] boolean synced when true will output changes to a file so it can be synced
-- @tparam[opt=false] boolean synced when true will output changes to a file so it can be synced
-- @tparam[opt] function callback when given the callback will be automatically registered to the update of the value
-- @treturn string the location that is being used
function Store.register(location,synced,callback)
@@ -136,10 +85,10 @@ function Store.register(location,synced,callback)
location = type(location) == 'string' and location or Store.uid_location()
if Store.registered[location] then
return error('Location is already registered', 2)
return error('Location '..location..' is already registered by '..Store.registered[location], 2)
end
Store.registered[location] = true
Store.registered[location] = get_file_path(1)
Store.synced[location] = synced and true or nil
Store.callbacks[location] = callback or nil
@@ -148,18 +97,17 @@ end
--- Gets the value stored at a location, this location must be registered
-- @tparam string location the location to get the data from
-- @tparam[opt] string child the child location if required
-- @tparam[opt=false] boolean allow_unregistered when true no error is returned if the location is not registered
-- @tparam[opt] string key the key location if used
-- @treturn any the data which was stored at the location
function Store.get(location,child,allow_unregistered)
if not Store.callbacks[location] and not allow_unregistered then
function Store.get(location,key)
if not Store.registered[location] then
return error('Location is not registered', 2)
end
local data = Store.data[location]
if child and data then
local data = store_data[location]
if key and data then
error_not_table(data)
return data[child]
return data[key]
end
return data
@@ -167,94 +115,120 @@ end
--- Sets the value at a location, this location must be registered
-- @tparam string location the location to set the data to
-- @tparam[opt] string child the child location if required
-- @tparam[opt] string key the key location if used
-- @tparam any value the new value to set at the location, value may be reverted if there is a watch callback, cant be nil
-- @tparam[opt] boolean from_sync set this true to avoid an output to the sync file
-- @tparam[opt=false] boolean from_sync set this true to avoid an output to the sync file
-- @treturn boolean true if it was successful
function Store.set(location,child,value,from_sync)
function Store.set(location,key,value,from_sync)
if not Store.callbacks[location] then
return error('Location is not registered', 2)
end
if child == nil or value == nil then
value = child or value
child = nil
if key == nil or value == nil then
value = key or value
key = nil
end
local data = Store.data
if child then
data = data[location]
if key then
local data = store_data[location]
if not data then
data = {}
Store.data[location] = data
store_data[location] = data
end
error_not_table(data)
data[child] = value
data[key] = value
else
data[location] = value
store_data[location] = value
end
script.raise_event(Store.events.on_value_update,{
script.raise_event(Store.events.on_value_changed,{
tick=game.tick,
location=location,
child=child,
key=key,
value=value,
from_sync=from_sync
from_sync=from_sync or false
})
return true
end
--- Triggers the change handler manually
-- @tparam string location the location to set the data to
-- @tparam[opt] string key the key location if required
function Store.update(location,key)
local value = Store.get(location,key)
script.raise_event(Store.events.on_value_changed,{
tick=game.tick,
location=location,
key=key,
value=value,
from_sync=false
})
end
--- Sets the value at a location to nil, this location must be registered
-- @tparam string location the location to set the data to
-- @tparam[opt] string child the child location if required
-- @tparam[opt] boolean from_sync set this true to avoid an output to the sync file
-- @tparam[opt] string key the key location if used
-- @tparam[opt=false] boolean from_sync set this true to avoid an output to the sync file
-- @treturn boolean true if it was successful
function Store.clear(location,child,from_sync)
function Store.clear(location,key,from_sync)
if not Store.callbacks[location] then
return error('Location is not registered', 2)
end
local data = Store.data
if child then
data = data[location]
if key then
local data = store_data[location]
if not data then return end
error_not_table(data)
data[child] = nil
data[key] = nil
else
data[location] = nil
store_data[location] = nil
end
script.raise_event(Store.events.on_value_update,{
script.raise_event(Store.events.on_value_changed,{
tick=game.tick,
location=location,
child=child,
from_sync=from_sync
key=key,
from_sync=from_sync or false
})
return true
end
--- Gets all non nil children at a location, children can be added and removed during runtime
--- Gets all non nil keys at a location, keys can be added and removed during runtime
-- this is similar to Store.get but will always return a table even if it is empty
-- @tparam string location the location to get the children of
-- @treturn table a table containing all the children names
function Store.get_children(location)
-- @tparam string location the location to get the keys of
-- @treturn table a table containing all the keys names
function Store.get_keys(location)
local data = Store.get(location)
return type(data) == 'table' and table_keys(data) or {}
end
--- Check for if a location is registered
-- @tparam string location the location to test for
-- @treturn boolean true if registered
function Store.is_registered(location)
return Store.registered[location]
end
--- Returns a unique name that can be used for a store
-- @treturn string a unique name
function Store.uid_location()
return tostring(Token.uid())
end
-- Handles syncing
Event.add(Store.events.on_value_update,function(event)
Event.add(Store.events.on_value_changed,function(event)
if Store.callbacks[event.location] then
Store.callbacks[event.location](event.value,event.child)
Store.callbacks[event.location](event.value,event.key)
end
if not event.from_sync and Store.synced[event.location] then
write_json('log/store.log',{
tick=event.tick,
location=event.location,
child=event.child,
key=event.key,
value=event.value,
})
end