Added watch to allow optimistion

This commit is contained in:
Cooldude2606
2019-05-05 20:50:21 +01:00
parent 6b14fe9649
commit 34fcb94200
5 changed files with 96 additions and 14 deletions

View File

@@ -38,4 +38,5 @@ return {
'config.command_auth_runtime_disable', -- allows commands to be enabled and disabled during runtime
'config.permission_groups', -- loads some predefined permission groups
'config.roles', -- loads some predefined roles
'expcore.store_test'
}

View File

@@ -30,7 +30,7 @@ local errors = {}
for index,path in pairs(files) do
-- Loads the next file in the list
log(string.format('[INFO] Loading files %3d/%s',index,total_file_count))
log(string.format('[INFO] Loading files %3d/%s (%s)',index,total_file_count,path))
local success,file = pcall(require,path)
-- Error Checking

View File

@@ -8,6 +8,7 @@
Public.param_check(value,test_type,param_name,param_number) --- Raises an error when the value is the incorrect type, uses a consistent error message format
Public.player_return(value,colour,player) --- Will return a value of any type to the player/server console, allows colour for in-game players
Public.write_json(path,tbl) --- Writes a table object to a file in json format
Public.opt_require(path) --- Calls a require that will not error if the file is not found
Public.ext_require(path,...) --- Calls a require and returns only the keys given, file must return a table
@@ -94,8 +95,8 @@ function Public.player_return(value,colour,player)
player = player or game.player
-- converts the value to a string
local returnAsString
if Public.type_check(value,'table') then
if Public.type_check(value.__self,'userdata') then
if Public.type_check(value,'table') or type(value) == 'userdata' then
if Public.type_check(value.__self,'userdata') or type(value) == 'userdata' then
-- value is userdata
returnAsString = 'Cant Display Userdata'
elseif Public.type_check(value[1],'string') and string.find(value[1],'.+[.].+') and not string.find(value[1],'%s') then
@@ -475,6 +476,9 @@ function Public.enum(tbl)
table.insert(rtn,v)
end
end
for k,v in pairs(rtn) do
rtn[v]=k
end
return rtn
end

View File

@@ -50,10 +50,21 @@
In a similar way get can be used to get the current value that is stored, if no value is stored then the getter function is called to get the value, this
function is more useful when you have custom settings since they would be no other way to access them.
>>>> Optimise the watching
When you use player,force or surface you will be checking alot of values for updates for this reason you might want to limit which sub_locations are checked
for updates because by default every player/force/surface is checked. You might also want to do this if you want a sub_location that is nil but still want to
check for it being updated (because by deafult it only checks non nil sub_locations). To do both these things you will use Store.watch
Store.watch('force.mining_speed','player')
For our force example we dont care about the enemy or neutral force only the player force, so we tell it to watch player and these means that the values for
the other forces are not be watched for updates (although Store.get and Store.set will still work). Store.watch will also accept a table of sub_locations in
case you want more than one thing to be watch.
>>>> Functions:
Store.register(location,store_type,getter,setter,no_error) --- Register a new location to store a value, the valu returned from getter will be watched for updates
Store.set(location,sub_location,value) --- Sets the stored values at the location, will call the setter function
Store.get(location,sub_location) --- Gets the value at the location, if the value is nil then the getter function is called
Store.watch(location,sub_location,state) --- If used then only sub_locations marked to be watched will be watched for updates, this will also midigate the nil value problem
Store.check(location,sub_location) --- Checks if the store value needs updating, and if true will update it calling the setter function
]]
@@ -61,10 +72,11 @@
local Global = require 'utils.global'
local Event = require 'utils.event'
local Game = require 'utils.game'
local Enum,write_json = ext_require('expcore.common','enum','write_json')
local Enum,write_json,table_keys = ext_require('expcore.common','enum','write_json','table_keys')
local Store = {
data={},
watching={},
locations={},
types = Enum{
'local', -- data is not stored with any sub_location, updates caused only by set
@@ -75,8 +87,9 @@ local Store = {
'global' -- data is stored externaly with any sub_location, updates casued by watch, set and the external source
}
}
Global.register(Store.data,function(tbl)
Store.data = table
Global.register({Store.data,Store.watching},function(tbl)
Store.data = tbl[1]
Store.watching = tbl[2]
end)
--- Returns a factorio object for the sub_location
@@ -96,6 +109,14 @@ local function get_sub_location_object(store_type,sub_location)
end
end
--- Returns three common parts that are used
local function get_location_parts(location,sub_location)
location = Store.locations[location]
local sub_location_object = get_sub_location_object(location.store_type,sub_location)
sub_location = sub_location_object and sub_location_object.name or sub_location
return location, sub_location, sub_location_object
end
--- Emits an event to the external store that a value was updated
local function set_global_location_value(location,sub_location,value)
write_json('log/store.log',{
@@ -132,8 +153,7 @@ function Store.set(location,sub_location,value)
if not Store.locations[location] then
return error('The location is not registed: '..location)
end
location = Store.locations[location]
local sub_location_object = get_sub_location_object(location.store_type,sub_location)
local location, sub_location, sub_location_object = get_location_parts(location,sub_location)
if location.store_type ~= Store.types['local'] then
if not Store.data[location.location] then Store.data[location.location] = {} end
Store.data[location.location][sub_location] = value
@@ -142,6 +162,7 @@ function Store.set(location,sub_location,value)
set_global_location_value(location.location,value)
end
location.setter(sub_location_object or sub_location,value)
return true
end
--- Gets the value at the location, if the value is nil then the getter function is called
@@ -150,13 +171,33 @@ end
-- @treturn any the value that was at this location
function Store.get(location,sub_location)
if not Store.locations[location] then return end
location = Store.locations[location]
local sub_location_object = get_sub_location_object(location.store_type,sub_location)
local location, sub_location, sub_location_object = get_location_parts(location,sub_location)
local rtn = Store.data[location.location][sub_location]
if rtn == nil then rtn = location.getter(sub_location_object or sub_location) end
if rtn == nil or Store.watching[location.location] and not Store.watching[location.location][sub_location] then
rtn = location.getter(sub_location_object or sub_location)
end
return rtn
end
--- If used then only sub_locations marked to be watched will be watched for updates, this will also midigate the nil value problem
-- @tparam location string the location to be returned, must be registed
-- @tparam sub_location string sub_location to watch, either string,player,force or surface depending on store type, can be a table of sub_locations
-- @tparam[opt=true] state boolean when true it will be marked to be watched, when false it will be removed
function Store.watch(location,sub_location,state)
if not Store.locations[location] then
return error('The location is not registed: '..location)
end
if type(sub_location) ~= 'table' or type(sub_location.__self) == 'userdata' then
sub_location = {sub_location}
end
for _,v in pairs(sub_location) do
if not Store.watching[location] then Store.watching[location] = {} end
if state == false then Store.watching[location][v] = nil
else Store.watching[location][v] = true end
end
if #table_keys(Store.watching[location]) == 0 then Store.watching[location] = nil end
end
--- Checks if the store value needs updating, and if true will update it calling the setter function
-- @tparam location string the location to be check, must be registed
-- @tparam sub_location string sub_location to check, either string,player,force or surface depending on store type
@@ -165,6 +206,7 @@ function Store.check(location,sub_location)
if not Store.locations[location] then return false end
location = Store.locations[location]
local sub_location_object = get_sub_location_object(location.store_type,sub_location)
sub_location = sub_location_object and sub_location_object.name or sub_location
local store,getter = Store.data[location.location][sub_location],location.getter(sub_location_object or sub_location)
if store ~= getter then
if not Store.data[location.location] then Store.data[location.location] = {} end
@@ -177,11 +219,36 @@ end
--- Checks once per second for changes to the store values
Event.on_nth_tick(60,function()
local types = {}
for _,location in pairs(Store.locations) do
if location.store_type ~= Store.types['local'] then
if not Store.data[location.location] then Store.data[location.location] = {} end
for sub_location,_ in pairs(Store.data[location.location]) do
Store.check(location,sub_location)
if not types[location.store_type] then types[location.store_type] = {} end
table.insert(types[location.store_type],location)
end
end
for store_type,locations in pairs(types) do
local keys
if store_type == Store.types.player then keys = game.players
elseif store_type == Store.types.force then keys = game.forces
elseif store_type == Store.types.surface then keys = game.surfaces
end
if keys then
for _,sub_location in pairs(keys) do
for _,location in pairs(locations) do
if not Store.watching[location.location] or Store.watching[location.location][sub_location.name] then
if not Store.data[location.location] then Store.data[location.location] = {} end
Store.check(location.location,sub_location)
end
end
end
else
for _,location in pairs(locations) do
if not Store.data[location.location] then Store.data[location.location] = {} end
if Store.watching[location.location] then keys = Store.watching[location.location]
else keys = table_keys(Store.data[location.location]) end
for _,sub_location in pairs(keys) do
Store.check(location.location,sub_location)
end
end
end
end

10
expcore/store_test.lua Normal file
View File

@@ -0,0 +1,10 @@
local Store = require 'expcore.store'
Store.register('force.mining_speed','force',function(force)
return force.manual_mining_speed_modifier
end,function(force,value)
force.manual_mining_speed_modifier = value
game.print(force.name..' how has '..value..' mining speed')
end)
Store.watch('force.mining_speed','player')