Merge pull request #504 from bbassie/refactor/remove-exp-legacy

Remove the exp_legacy plugin
This commit is contained in:
Bastiaan authored and GitHub committed 2026-10-15 14:07:01 +01:00
1 parent 98c3173807
commit 55bdf72fff
27 files changed
+39 -1697

No files matched your search

-1
View File
@@ -1 +0,0 @@
# Without an .npmignore pnpm packs using the repository .gitignore, which leaves out dist/
-8
View File
@@ -1,8 +0,0 @@
import * as lib from "@clusterio/lib";
export const plugin: lib.PluginDeclaration = {
name: "exp_legacy",
title: "ExpGaming - Legacy",
description: "Clusterio plugin implementing the legacy v6 scenario updated for factorio 2.0",
instanceEntrypoint: "./dist/node/instance.js",
};
-3
View File
@@ -1,3 +0,0 @@
// Empty because an instance entrypoint must be defined for a module to be injected
// This requirement may change in the future to allow for standalone modules
export default async function () {}
@@ -1,8 +0,0 @@
--- This contains a list of all files that will be loaded and the order they are loaded in;
-- to stop a file from loading add "--" in front of it, remove the "--" to have the file be loaded;
-- config files should be loaded after all modules are loaded;
-- core files should be required by modules and not be present in this list;
-- @config File-Loader
return {
"expcore.player_data", -- must be loaded first to register event handlers
}
-46
View File
@@ -1,46 +0,0 @@
--- Please go to ./config if you want to change settings, each file is commented with what it does
-- if it is not in ./config then you should not attempt to change it unless you know what you are doing
-- all files which are loaded (including the config files) are present in ./config/file_loader.lua
-- this file is the landing point for all scenarios please DO NOT edit directly, further comments are to aid development
log("[START] -----| Explosive Gaming Scenario Loader |-----")
log("[INFO] Setting up lua environment")
-- Please go to config/file_loader.lua to edit the files that are loaded
log("[INFO] Reading loader config")
local files = require("modules.exp_legacy.config._file_loader")
-- Error handler for loading files
local errors = {}
local error_count = 0
local error_format = "[ERROR] %s :: %s"
local currently_loading = nil
local function error_handler(err)
error_count = error_count + 1
if err:find("module " .. currently_loading .. " not found;", nil, true) then
log("[ERROR] File not found: " .. currently_loading)
errors[error_count] = error_format:format(currently_loading, err)
else
log("[ERROR] Failed to load: " .. currently_loading)
errors[error_count] = debug.traceback(error_format:format(currently_loading, err))
end
return err
end
-- Loads all files from the config and logs that they are loaded
local total_file_count = string.format("%3d", #files)
for index, path in pairs(files) do
currently_loading = path
log(string.format("[INFO] Loading file %3d/%s (%s)", index, total_file_count, path))
xpcall(require, error_handler, "modules.exp_legacy." .. path)
end
-- Logs all errors again to make it make it easy to find
log("[INFO] All files loaded with " .. error_count .. " errors:")
for _, error in ipairs(errors) do log(error) end
log("[END] -----| Explosive Gaming Scenario Loader |-----")
--- Register all event handlers via event handler
local Event = require("modules/exp_legacy/utils/event")
return Event.real_handlers
-884
View File
@@ -1,884 +0,0 @@
--[[-- Core Module - Datastore
- A module used to store data in the global table with the option to have it sync to an external source.
@core Datastore
@alias DatastoreManager
@usage-- Types of Datastore
-- This datastore will not save data externally and can be used to watch for updates on values within it
-- A common use might be to store data for a gui and only update the gui when a value changes
local LocalDatastore = Datastore.connect('LocalDatastore')
-- This datastore will allow you to use the save and request method, this allows you to have persistent data
-- Should be used over auto save as it creates less save requests, but this means you need to tell the data to be saved
-- We use this type for player data as we know the data only needs to be saved when the player leaves
local PersistentDatastore = Datastore.connect('PersistentDatastore', true) -- save_to_disk
-- This datastore is the same as above but the save method will be called automatically when ever you change a value
-- An auto save datastore should be used if the data does not change often, this can be global settings and things of that sort
-- If it is at all possible to setup events to unload and/or save the data then this is preferable
local AutosaveDatastore = Datastore.connect('AutosaveDatastore', true, true) -- save_to_disk, auto_save
-- Finally you can have a datastore that propagates its changes to all other connected servers, this means request does not need to be used
-- This should be used when you might have data conflicts while saving, this is done by pushing the saved value to all active servers
-- The request method has little use after server start as any external changes to the value will be pushed automatically
-- Auto save can also be used with this type and you should follow the same guidelines above for when this should be avoided
local PropagateDatastore = Datastore.connect('PropagateDatastore', true, false, true) -- save_to_disk, propagate_changes
@usage-- Using Datastores Locally
-- Once you have your datastore connection setup, any further requests with connect will return the same datastore
-- This is important to know because the settings passed as parameters you have an effect when it is first created
-- One useful thing that you might want to set up before runtime is a serializer, this will convert non string keys into strings
-- This serializer will allow use to pass a player object and still have it serialized to the players name
local ExampleData = Datastore.connect('ExampleData')
ExampleData:set_serializer(function(rawKey)
return rawKey.name
end)
-- If we want to get data from the datastore we can use get or get_all
local value = ExampleData:get(player, defaultValue)
local values = ExampleData:get_all()
-- If we want to set data then we can use set, increment, update, or update_all
ExampleData:set(player, 10)
ExampleData:increment(player)
ExampleData:update(player, function(player_name, value)
return value * 2
end)
ExampleData:update_all(function(player_name, value)
return value * 2
end)
-- If we want to remove data then we use remove
ExampleData:remove(player)
-- We can also listen for updates to a value done by any of the above methods with on_update
ExampleData:on_update(function(player_name, value)
game.print(player_name..' has had their example data updated to '..tostring(value))
end)
@usage-- Using Datastore Externally
-- If save_to_disk is used then this opens up the option for persistent data which you can request, save, and remove
-- All of the local methods are still usable put now there is the option for extra events
-- In order for this to work there must be an external script to read datastore.pipe and inject with Datastore.ingest
-- To request data you would use request and the on_load event, this event can be used to modify data before it is used
ExampleData:request(player)
ExampleData:on_load(function(player_name, value)
game.print('Loaded example data for '..player_name)
-- A value can be returned here to overwrite the received value
end)
-- To save data you would use save and the on_save event, this event can be used to modify data before it is saved
ExampleData:save(player)
ExampleData:on_save(function(player_name, value)
game.print('Saved example data for '..player_name)
-- A value can be returned here to overwrite the value which is saved
end)
-- To remove data locally but not externally, like if a player logs off, you would use unload and on_unload
ExampleData:unload(player)
ExampleData:on_unload(function(player_name, value)
game.print('Unloaded example data for '..player_name)
-- Any return is ignored, this is event is for cleaning up other data
end)
@usage-- Using Datastore Messaging
-- The message action can be used regardless of save_to_disk being set as no data is saved, but an external script is still required
-- These messages can be used to send data to other servers which doesnt need to be saved such as shouts or commands
-- Using messages is quite simple only using message and on_message
ExampleData:message(key, message)
ExampleData:on_message(function(key, message)
game.print('Received message '..message)
end)
@usage-- Combined Datastores
-- A combined datastore is a datastore which stores its data inside of another datastore
-- This means that the data is stored more efficiently in the external database and less requests need to be made
-- To understand how combined datastores work think of each key in the parent as a table where the sub datastore is a key in that table
-- Player data is the most used version of the combined datastore, below is how the player data module is setup
local PlayerData = Datastore.connect('PlayerData', true) -- saveToDisk
PlayerData:set_serializer(Datastore.name_serializer) -- use player name as key
PlayerData:combine('Statistics')
PlayerData:combine('Settings')
PlayerData:combine('Required')
-- You can then further combine datastores to any depth, below we add some possible settings and statistics that we might use
-- Although we dont in this example, each of these functions returns the datastore object which you should use as a local value
PlayerData.Settings:combine('Color')
PlayerData.Settings:combine('Quickbar')
PlayerData.Settings:combine('JoinMessage')
PlayerData.Statistics:combine('Playtime')
PlayerData.Statistics:combine('JoinCount')
-- Because sub datastore work just like a normal datastore you dont need any special code, using get and set will still return as if it wasnt a sub datastore
-- Things like the serializer and the datastore settings are always the same as the parent so you dont need to worry about setting up the serializer each time
-- And because save, request, and unload methods all point to the root datastore you are able to request and save your data as normal
-- If you used get_all on PlayerData this is what you would get:
{
Cooldude2606 = {
Settings = {
Color = 'ColorValue',
Quickbar = 'QuickbarValue',
JoinMessage = 'JoinMessageValue'
},
Statistics = {
Playtime = 'PlaytimeValue',
JoinCount = 'JoinCountValue'
}
}
}
-- If you used get_all on PlayerData.Settings this is what you would get:
{
Cooldude2606 = {
Color = 'ColorValue',
Quickbar = 'QuickbarValue',
JoinMessage = 'JoinMessageValue'
}
}
-- If you used get_all on PlayerData.Settings.Color this is what you would get:
{
Cooldude2606 = 'ColorValue'
}
]]
local Storage = require("modules/exp_util/storage")
local DatastoreManager = {}
local Datastores = {} --- @type table<string, Datastore>
local Data = {}
--- @class Datastore
--- @field name string
--- @field value_name string
--- @field auto_save boolean
--- @field save_to_disk boolean
--- @field propagate_changes boolean
--- @field serializer function | false
--- @field parent Datastore | false
--- @field children table<string, Datastore>
--- @field metadata table
--- @field events table<string, function[]>
--- @field data table
local Datastore = {}
local copy = table.deep_copy
local trace = debug.traceback
local table_to_json = helpers.table_to_json
local json_to_table = helpers.json_to_table
local write_file = helpers.write_file
--- Save datastores in the global table
Storage.register(Data, function(tbl)
Data = tbl
for name, datastore in pairs(Datastores) do
datastore.data = Data[name]
end
end, function(tbl)
for name in pairs(Datastores) do
tbl[name] = tbl[name] or {}
end
end)
----- Datastore Manager
-- @section datastoreManager
--- Metatable used on datastores
DatastoreManager.metatable = {
__index = function(self, key) return rawget(self.children, key) or rawget(Datastore, key) end,
__newidnex = function(_, _, _) error("Datastore can not be modified", 2) end,
__call = function(self, ...) return self:get(...) end,
}
--[[-- Make a new datastore connection, if a connection already exists then it is returned
@tparam string datastore_name The name that you want the new datastore to have, this can not have any whitespace
@tparam[opt=false] boolean saveToDisk When set to true, using the save method with write the data to datastore.pipe
@tparam[opt=false] boolean autoSave When set to true, using any method which modifies data will cause the data to be saved
@tparam[opt=false] boolean propagateChanges When set to true, using the save method will send the data to all other connected servers
@treturn table The new datastore connection that can be used to access and modify data in the datastore
@usage-- Connecting to the test datastore which will allow saving to disk
local ExampleData = Datastore.connect('ExampleData', true) -- saveToDisk
]]
function DatastoreManager.connect(datastore_name, save_to_disk, autosave, propagate_changes)
if Datastores[datastore_name] then return Datastores[datastore_name] end
if package.lifecycle ~= package.lifecycle_stage.control then
-- Only allow this function to be called during the control stage
error("New datastore connection can not be created during runtime", 2)
end
local new_datastore = {
name = datastore_name,
value_name = datastore_name,
auto_save = autosave or false,
save_to_disk = save_to_disk or false,
propagate_changes = propagate_changes or false,
serializer = false,
parent = false,
children = {},
metadata = {},
events = {},
data = {},
}
Data[datastore_name] = new_datastore.data
Datastores[datastore_name] = new_datastore
return setmetatable(new_datastore, DatastoreManager.metatable)
end
--[[-- Make a new datastore that stores its data inside of another one
@tparam string datastore_name The name of the datastore that will contain the data for the new datastore
@tparam string subdatastore_name The name of the new datastore, this name will also be used as the key inside the parent datastore
@treturn table The new datastore connection that can be used to access and modify data in the datastore
@usage-- Setting up a datastore which stores its data inside of another datastore
local BarData = Datastore.combine('ExampleData', 'Bar')
]]
function DatastoreManager.combine(datastore_name, subdatastore_name)
local datastore = assert(Datastores[datastore_name], "Datastore not found " .. tostring(datastore_name))
return datastore:combine(subdatastore_name)
end
--[[-- Ingest the result from a request, this is used through a rcon interface to sync data
@tparam string action The action that should be done, can be: remove, message, propagate, or request
@tparam string datastore_name The name of the datastore that should have the action done to it
@tparam string key The key of that datastore that is having the action done to it
@tparam string valueJson The json string for the value being ingested, remove does not require a value
@usage-- Replying to a data request
Datastore.ingest('request', 'ExampleData', 'TestKey', 'Foo')
]]
function DatastoreManager.ingest(action, datastore_name, key, value_json)
local datastore = assert(Datastores[datastore_name], "Datastore ingest error, Datastore not found " .. tostring(datastore_name))
assert(type(action) == "string", "Datastore ingest error, Action is not a string got: " .. type(action))
assert(type(key) == "string", "Datastore ingest error, Key is not a string got: " .. type(key))
if action == "remove" then
datastore:raw_set(key)
elseif action == "message" then
local success, value = pcall(json_to_table, value_json)
if not success or value == nil then value = tonumber(value_json) or value_json end
datastore:raise_event("on_message", key, value)
elseif action == "propagate" or action == "request" then
local success, value = pcall(json_to_table, value_json)
if not success or value == nil then value = tonumber(value_json) or value_json end
local old_value = datastore:raw_get(key)
value = datastore:raise_event("on_load", key, value, old_value)
datastore:set(key, value)
end
end
--[[-- Debug, Use to get all datastores, or return debug info on a datastore
@tparam[opt] string datastore_name The name of the datastore to get the debug info of
@usage-- Get all the datastores
local datastores = Datastore.debug()
@usage-- Getting the debug info for a datastore
local debug_info = Datastore.debug('ExampleData')
]]
function DatastoreManager.debug(datastore_name)
if not datastore_name then return Datastores end
local datastore = assert(Datastores[datastore_name], "Datastore not found " .. tostring(datastore_name))
return datastore:debug()
end
--[[-- Commonly used serializer, returns the name of the object
@tparam any rawKey The raw key that will be serialized, this can be things like player, force, surface, etc
@treturn string The name of the object that was passed
@usage-- Using the name serializer for your datastore
local ExampleData = Datastore.connect('ExampleData')
ExampleData:set_serializer(Datastore.name_serializer)
]]
function DatastoreManager.name_serializer(raw_key)
return raw_key.name
end
----- Datastore Internal
-- @section datastore-internal
--[[-- Debug, Get the debug info for this datastore
@treturn table The debug info for this datastore, contains stuff like parent, settings, children, etc
@usage-- Get the debug info for a datastore
local ExampleData = Datastore.connect('ExampleData')
local debug_info = ExampleData:debug()
]]
function Datastore:debug()
local debug_info = {}
if self.parent then
debug_info.parent = self.parent.name
else
debug_info.settings = { auto_save = self.auto_save, save_to_disk = self.save_to_disk, propagate_changes = self.propagate_changes, serializer = not not self.serializer }
end
local children = {}
for name in pairs(self.children) do children[#children + 1] = name end
if #children > 0 then debug_info.children = children end
local events = {}
for name, handlers in pairs(self.events) do events[name] = #handlers end
if next(events) then debug_info.events = events end
if next(self.metadata) then debug_info.metadata = self.metadata end
debug_info.data = self:get_all()
return debug_info
end
--[[-- Internal, Get data following combine logic
@tparam string key The key to get the value of from this datastore
@tparam[opt=false] boolean fromChild If the get request came from a child of this datastore
@treturn any The value that was stored at this key in this datastore
@usage-- Internal, Get the data from a datastore
local value = self:raw_get('TestKey')
]]
function Datastore:raw_get(key, from_child)
local data = self.data
if self.parent then
data = self.parent:raw_get(key, true)
key = self.value_name
end
local value = data[key]
if value ~= nil then return value end
if from_child then value = {} end
data[key] = value
return value
end
--[[-- Internal, Set data following combine logic
@tparam string key The key to set the value of in this datastore
@tparam any value The value that will be set at this key
@usage-- Internal, Set the value in a datastore
self:raw_set('TestKey', 'Foo')
]]
function Datastore:raw_set(key, value)
if self.parent then
local data = self.parent:raw_get(key, true)
data[self.value_name] = value
else
self.data[key] = value
end
end
local function serialize_error(err) error("An error ocurred in a datastore serializer: " .. trace(err)) end
--[[-- Internal, Return the serialized key
@tparam any rawKey The key that needs to be serialized, if it is already a string then it is returned
@treturn string The key after it has been serialized
@usage-- Internal, Ensure that the key is a string
key = self:serialize(key)
]]
function Datastore:serialize(raw_key)
if type(raw_key) == "string" then return raw_key end
assert(self.serializer, "Datastore does not have a serializer and received non string key")
local success, key = xpcall(self.serializer, serialize_error, raw_key)
return success and key or nil
end
--[[-- Internal, Writes an event to the output file to be saved and/or propagated
@tparam string action The action that should be wrote to datastore.pipe, can be request, remove, message, save, propagate
@tparam string key The key that the action is being preformed on
@tparam any value The value that should be used with the action
@usage-- Write a data request to datastore.pipe
self:write_action('request', 'TestKey')
@usage-- Write a data save to datastore.pipe
self:write_action('save', 'TestKey', 'Foo')
]]
function Datastore:write_action(action, key, value)
local data = { action, self.name, key }
if value ~= nil then
data[4] = type(value) == "table" and table_to_json(value) or value
end
write_file("ext/datastore.out", table.concat(data, " ") .. "\n", true, 0)
end
----- Datastore Local
-- @section datastore-local
--[[-- Create a new datastore which is stores its data inside of this datastore
@tparam string subdatastore_name The name of the datastore that will have its data stored in this datastore
@treturn table The new datastore that was created inside of this datastore
@usage-- Add a new sub datastore
local ExampleData = Datastore.connect('ExampleData')
local BarData = ExampleData:combine('Bar')
]]
function Datastore:combine(subdatastore_name)
local new_datastore = DatastoreManager.connect(self.name .. "." .. subdatastore_name)
self.children[subdatastore_name] = new_datastore
new_datastore.value_name = subdatastore_name
new_datastore.serializer = self.serializer
new_datastore.auto_save = self.auto_save
new_datastore.parent = self
Data[new_datastore.name] = nil
new_datastore.data = nil
return new_datastore
end
--[[-- Set a callback that will be used to serialize keys which aren't strings
@tparam function callback The function that will be used to serialize non string keys passed as an argument
@usage-- Set a custom serializer, this would be the same as Datastore.name_serializer
local ExampleData = Datastore.connect('ExampleData')
ExampleData:set_serializer(function(rawKey)
return rawKey.name
end)
]]
function Datastore:set_serializer(callback)
assert(type(callback) == "function", "Callback must be a function")
self.serializer = callback
end
--[[-- Set a default value to be returned by get if no other default is given, using will mean get will never return nil, set using the default will set to nil to save space
@tparam any value The value that will be deep copied by get if the value is nil and no other default is given
@tparam boolean allowSet When true if the default is passed as the value for set it will be set rather than setting nil
@usage-- Set a default value to be returned by get
local ExampleData = Datastore.connect('ExampleData')
ExampleData:set_default('Foo')
]]
function Datastore:set_default(value, allow_set)
self.default = value
self.allow_set_to_default = allow_set
end
--[[-- Set metadata tags on this datastore which can be accessed by other scripts
@tparam table tags A table of tags that you want to set in the metadata for this datastore
@usage-- Adding metadata that could be used by a gui to help understand the stored data
local ExampleData = Datastore.connect('ExampleData')
ExampleData:set_metadata{
caption = 'Test Data',
tooltip = 'Data used for testing datastores',
type = 'table'
}
]]
function Datastore:set_metadata(tags)
local metadata = self.metadata
for key, value in pairs(tags) do
metadata[key] = value
end
end
--[[-- Get a value from local storage, option to have a default value, do not edit the data returned as changes may not save, use update if you want to make changes
@tparam any key The key that you want to get the value of, must be a string unless a serializer is set
@tparam[opt] any default The default value that will be returned if no value is found in the datastore
@usage-- Get a key from the datastore, the default will be deep copied if no value exists in the datastore
local ExampleData = Datastore.connect('ExampleData')
local value = ExampleData:get('TestKey')
]]
function Datastore:get(key, default)
key = self:serialize(key)
local value = self:raw_get(key)
if value ~= nil then return value end
return copy(default or self.default)
end
--[[-- Set a value in local storage, will trigger on_update then on_save, save_to_disk and auto_save is required for on_save
@tparam any key The key that you want to set the value of, must be a string unless a serializer is set
@tparam any value The value that you want to set for this key
@usage-- Set a value in the datastore, this will trigger on_update, if auto_save is true then will trigger save
local ExampleData = Datastore.connect('ExampleData')
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, old_value)
if self.auto_save then self:save(key) end
return value
end
--[[-- Increment the value in local storage, only works for number values, will trigger on_update then on_save, save_to_disk and auto_save is required for on_save
@tparam any key The key that you want to increment the value of, must be a string unless a serializer is set
@tparam[opt=1] number delta The amount that you want to increment the value by, can be negative or a decimal
@usage-- Increment a value in a datastore, the value must be a number or nil, if nil 0 is used as the start value
local ExampleData = Datastore.connect('ExampleData')
ExampleData:increment('TestNumber')
]]
function Datastore:increment(key, delta)
key = self:serialize(key)
local value = self:raw_get(key) or 0
return self:set(key, value + (delta or 1))
end
local function update_error(err) log("An error occurred in datastore update:\n\t" .. trace(err)) end
--[[-- Use a function to update the value locally, will trigger on_update then on_save, save_to_disk and auto_save is required for on_save
@tparam any key The key that you want to apply the update to, must be a string unless a serializer is set
@tparam function callback The function that will be used to update the value at this key
@usage-- Using a function to update a value, if a value is returned then this will be the new value
local ExampleData = Datastore.connect('ExampleData')
ExampleData:increment('TestKey', function(key, value)
return value..value
end)
]]
function Datastore:update(key, callback)
key = self:serialize(key)
local value = self:get(key)
local raw_value = self:raw_get(key)
local old_value = copy(self:raw_get(key))
local success, new_value = xpcall(callback, update_error, key, value)
if not success then
self:raw_set(key, old_value)
elseif new_value ~= nil then
self:set(key, new_value)
elseif raw_value == nil then
self:set(key, value)
else
self:raise_event("on_update", key, value, old_value)
if self.auto_save then self:save(key) end
end
end
--[[-- Remove a value locally and on the external source, works regardless of propagateChanges, requires save_to_disk for external changes
@tparam any key The key that you want to remove locally and externally, must be a string unless a serializer is set
@usage-- Remove a key locally and externally
local ExampleData = Datastore.connect('ExampleData')
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, 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
local function filter_error(err) log("An error ocurred in a datastore filter:\n\t" .. trace(err)) end
--[[-- Internal, Used to filter elements from a table
@tparam table tbl The table that will have the filter applied to it
@tparam[opt] function callback The function that will be used as a filter, if none giving then the provided table is returned
@treturn table The table which has only the key values pairs which passed the filter
@usage-- Internal, Filter a table by the values it contains, return true to keep the key value pair
local filtered_table = filter({5,3,4,1,2}, function(key, value)
return value > 2
end)
]]
local function filter(tbl, callback)
if not callback then return tbl end
local rtn = {}
for key, value in pairs(tbl) do
local success, add = xpcall(callback, filter_error, key, value)
if success and add then rtn[key] = value end
end
return rtn
end
--[[-- Get all keys in this datastore, optional filter callback
@tparam[opt] function callback The filter function that can be used to filter the results returned
@treturn table All the data that is in this datastore, filtered if a filter was provided
@usage-- Get all the data in this datastore
local ExampleData = Datastore.connect('ExampleData')
local data = ExampleData:get_all()
@usage-- Get all the data in this datastore, with a filter
local ExampleData = Datastore.connect('ExampleData')
local data = ExampleData:get_all(function(key, value)
return type(value) == 'string'
end)
]]
function Datastore:get_all(callback)
if not self.parent then
return filter(self.data, callback)
else
local data, value_name = {}, self.value_name
for key, value in pairs(self.parent:get_all()) do
data[key] = value[value_name]
end
return filter(data, callback)
end
end
--[[-- Update all keys in this datastore using the same update function
@tparam function callback The update function that will be applied to each key
@usage-- Get all the data in this datastore, with a filter
local ExampleData = Datastore.connect('ExampleData')
ExampleData:update_all(function(key, value)
return value..value
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, old_value)
if self.auto_save then self:save(key) end
end
end
end
----- Datastore External
-- @section datastore-external
--[[-- Request a value from an external source, will trigger on_load when data is received
@tparam any key The key that you want to request from an external source, must be a string unless a serializer is set
@usage-- Request a key from an external source, on_load is triggered when data is received
local ExampleData = Datastore.connect('ExampleData')
ExampleData:request('TestKey')
]]
function Datastore:request(key)
if self.parent then return self.parent:request(key) end
key = self:serialize(key)
self:write_action("request", key)
end
--[[-- Save a value to an external source, will trigger on_save before data is saved, save_to_disk must be set to true
@tparam any key The key that you want to save to an external source, must be a string unless a serializer is set
@usage-- Save a key to an external source, save_to_disk must be set to true for there to be any effect
local ExampleData = Datastore.connect('ExampleData')
ExampleData:save('TestKey')
]]
function Datastore:save(key)
if self.parent then self.parent:save(key) end
if not self.save_to_disk then return end
key = self:serialize(key)
local value = self:raise_event("on_save", key, copy(self:raw_get(key)))
local action = self.propagate_changes and "propagate" or "save"
self:write_action(action, key, value)
end
--[[-- Save a value to an external source and remove locally, will trigger on_unload then on_save, save_to_disk is not required for on_unload
@tparam any key The key that you want to unload from the datastore, must be a string unless a serializer is set
@usage-- Unload a key from the datastore, get will now return nil and value will be saved externally if save_to_disk is set to true
local ExampleData = Datastore.connect('ExampleData')
ExampleData:unload('TestKey')
]]
function Datastore:unload(key)
if self.parent then return self.parent:unload(key) end
key = self:serialize(key)
self:raise_event("on_unload", key, copy(self:raw_get(key)))
self:save(key)
self:raw_set(key)
end
--[[-- Use to send a message over the connection, works regardless of saveToDisk and propagateChanges
@tparam any key The key that you want to send a message over, must be a string unless a serializer is set
@tparam any message The message that you want to send to other connected servers, or external source
@usage-- Send a message to other servers on this key, can listen for messages with on_message
local ExampleData = Datastore.connect('ExampleData')
ExampleData:message('TestKey', 'Foo')
]]
function Datastore:message(key, message)
key = self:serialize(key)
self:write_action("message", key, message)
end
--[[-- Save all the keys in the datastore, optional filter callback
@tparam[opt] function callback The filter function that can be used to filter the keys saved
@usage-- Save all the data in this datastore
local ExampleData = Datastore.connect('ExampleData')
local data = ExampleData:save_all()
@usage-- Save all the data in this datastore, with a filter
local ExampleData = Datastore.connect('ExampleData')
ExampleData:save_all(function(key, value)
return type(value) == 'string'
end)
]]
function Datastore:save_all(callback)
local data = self:get_all(callback)
for key in pairs(data) do self:save(key) end
end
--[[-- Unload all the keys in the datastore, optional filter callback
@tparam[opt] function callback The filter function that can be used to filter the keys unloaded
@usage-- Unload all the data in this datastore
local ExampleData = Datastore.connect('ExampleData')
ExampleData:unload_all()
@usage-- Unload all the data in this datastore, with a filter
local ExampleData = Datastore.connect('ExampleData')
ExampleData:unload_all(function(key, value)
return type(value) == 'string'
end)
]]
function Datastore:unload_all(callback)
local data = self:get_all(callback)
for key in pairs(data) do self:unload(key) end
end
----- Events
-- @section events
local function event_error(err) log("An error ocurred in a datastore event handler:\n\t" .. trace(err)) end
--[[-- Internal, Raise an event on this datastore
@tparam string event_name The name of the event to raise for this datastore
@tparam string key The key that this event is being raised for
@tparam[opt] any value The current value that this key has, might be a deep copy of the value
@tparam[opt] any old_value The previous value that this key has, might be a deep copy of the value
@tparam[opt] string source Where this call came from, used to do event recursion so can be parent or child
@treturn any The value that is left after being passed through all the event handlers
@usage-- Internal, Getting the value that should be saved
value = self:raise_event('on_save', key, value)
]]
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
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
-- Raise the event for this datastore
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, 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
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
if event_name == "on_save" and next(self.children) and not next(value) then return end
return value
end
--[[-- Internal, Returns a function which will add a callback to an event
@tparam string event_name The name of the event that this should create a handler adder for
@treturn function The function that can be used to add handlers to this event
@usage-- Internal, Get the function to add handlers to on_load
Datastore.on_load = event_factory('on_load')
]]
local function event_factory(event_name)
return function(self, callback)
assert(type(callback) == "function", "Handler must be a function")
local handlers = self.events[event_name]
if not handlers then
self.events[event_name] = { callback }
else
handlers[#handlers + 1] = callback
end
end
end
--[[-- Register a callback that triggers when data is loaded from an external source, returned value is saved locally
@tparam function callback The handler that will be registered to the on_load event
@usage-- Adding a handler to on_load, returned value will be saved locally, can be used to deserialize the value beyond a normal json
local ExampleData = Datastore.connect('ExampleData')
ExampleData:on_load(function(key, value)
game.print('Test data loaded for: '..key)
end)
]]
Datastore.on_load = event_factory("on_load")
--[[-- Register a callback that triggers before data is saved, returned value is saved externally
@tparam function callback The handler that will be registered to the on_load event
@usage-- Adding a handler to on_save, returned value will be saved externally, can be used to serialize the value beyond a normal json
local ExampleData = Datastore.connect('ExampleData')
ExampleData:on_save(function(key, value)
game.print('Test data saved for: '..key)
end)
]]
Datastore.on_save = event_factory("on_save")
--[[-- Register a callback that triggers before data is unloaded, returned value is ignored
@tparam function callback The handler that will be registered to the on_load event
@usage-- Adding a handler to on_unload, returned value is ignored, can be used to clean up guis or local values related to this data
local ExampleData = Datastore.connect('ExampleData')
ExampleData:on_load(function(key, value)
game.print('Test data unloaded for: '..key)
end)
]]
Datastore.on_unload = event_factory("on_unload")
--[[-- Register a callback that triggers when a message is received, returned value is ignored
@tparam function callback The handler that will be registered to the on_load event
@usage-- Adding a handler to on_message, returned value is ignored, can be used to receive messages from other connected servers without saving data
local ExampleData = Datastore.connect('ExampleData')
ExampleData:on_message(function(key, value)
game.print('Test data message for: '..key)
end)
]]
Datastore.on_message = event_factory("on_message")
--[[-- Register a callback that triggers any time a value is changed, returned value is ignored
@tparam function callback The handler that will be registered to the on_load event
@usage-- Adding a handler to on_update, returned value is ignored, can be used to update guis or send messages when data is changed
local ExampleData = Datastore.connect('ExampleData')
ExampleData:on_update(function(key, value)
game.print('Test data updated for: '..key)
end)
]]
Datastore.on_update = event_factory("on_update")
----- Module Return
return DatastoreManager
-152
View File
@@ -1,152 +0,0 @@
--[[-- Core Module - PlayerData
- A module used to store player data in a central datastore to minimize data requests and saves.
@core PlayerData
@usage-- Adding a colour setting for players
local PlayerData = require("modules.exp_legacy.expcore.player_data")
local PlayerColors = PlayerData.Settings:combine('Color')
-- Set the players color when their data is loaded
PlayerColors:on_load(function(player_name, color)
local player = game.players[player_name]
player.color = color
end)
-- Overwrite the saved color with the players current color
PlayerColors:on_save(function(player_name, _)
local player = game.players[player_name]
return player.color -- overwrite existing data with the current color
end)
@usage-- Add a playtime statistic for players
local Event = require("modules/exp_legacy/utils/event")
local PlayerData = require("modules.exp_legacy.expcore.player_data")
local Playtime = PlayerData.Statistics:combine('Playtime')
-- When playtime reaches an hour interval tell the player and say thanks
Playtime:on_update(function(player_name, playtime)
if playtime % 60 == 0 then
local hours = playtime / 60
local player = game.players[player_name]
player.print('Thanks for playing on our servers, you have played for '..hours..' hours!')
end
end)
-- Update playtime for players, data is only loaded for online players so update_all can be used
Event.add_on_nth_tick(3600, function()
Playtime:update_all(function(player_name, playtime)
return playtime + 1
end)
end)
]]
local Async = require("modules/exp_util/async")
local Event = require("modules/exp_legacy/utils/event") --- @dep utils.event
local Datastore = require("modules.exp_legacy.expcore.datastore") --- @dep expcore.datastore
local Commands = require("modules/exp_commands")
local table_to_json = helpers.table_to_json
local write_file = helpers.write_file
--- Common player data that acts as the root store for player data
local PlayerData = Datastore.connect("PlayerData", true) -- saveToDisk
PlayerData:set_serializer(Datastore.name_serializer) -- use player name
--- Store and enum for the data saving preference
local DataSavingPreference = PlayerData:combine("DataSavingPreference")
local PreferenceEnum = { "All", "Statistics", "Settings", "Required" } --- @type table<string | number, string | number>
for k, v in ipairs(PreferenceEnum) do PreferenceEnum[v] = k end
DataSavingPreference:set_default("All")
DataSavingPreference:set_metadata{
name = { "expcore-data.preference" },
tooltip = { "expcore-data.preference-tooltip" },
value_tooltip = { "expcore-data.preference-value-tooltip" },
}
--- Sets your data saving preference
Commands.new("data-preference", { "expcore-data.description-preference" })
:optional("option", { "expcore-data.arg-option" }, Commands.types.enum(PreferenceEnum))
:register(function(player, option)
--- @cast option "All" | "Statistics" | "Settings" | "Required" | nil
if option then
DataSavingPreference:set(player, option)
return Commands.status.success{ "expcore-data.set-preference", option }
else
return Commands.status.success{ "expcore-data.get-preference", DataSavingPreference:get(player) }
end
end)
--- Gets your data and writes it to a file
Commands.new("save-data", { "expcore-data.description-data" })
:register(function(player)
player.print{ "expcore-data.get-data" }
write_file("expgaming_player_data.json", table_to_json(PlayerData:get(player, {})), false, player.index)
end)
--- Async function called after 5 seconds with no player data loaded
local check_data_loaded_async =
Async.register(function(player)
local player_data = PlayerData:get(player)
if not player_data or not player_data.valid then
player.print{ "expcore-data.data-failed" }
Datastore.ingest("request", "PlayerData", player.name, '{"valid":false}')
end
end)
--- When player data loads tell the player if the load had failed previously
PlayerData:on_load(function(player_name, player_data, existing_data)
if not player_data or player_data.valid == false then return end
if existing_data and existing_data.valid == false then
game.players[player_name].print{ "expcore-data.data-restore" }
end
player_data.valid = true
end)
--- Remove data that the player doesnt want to have stored
PlayerData:on_save(function(player_name, player_data)
local data_preference = DataSavingPreference:get(player_name)
data_preference = PreferenceEnum[data_preference]
if data_preference == PreferenceEnum.All then
player_data.valid = nil
return player_data
end
local saved_player_data = { PlayerRequired = player_data.PlayerRequired, DataSavingPreference = PreferenceEnum[data_preference] }
if data_preference <= PreferenceEnum.Settings then saved_player_data["PlayerSettings"] = player_data.PlayerSettings end
if data_preference <= PreferenceEnum.Statistics then saved_player_data["PlayerStatistics"] = player_data.PlayerStatistics end
return saved_player_data
end)
--- Display your data preference when your data loads
DataSavingPreference:on_load(function(player_name, data_preference)
game.players[player_name].print{ "expcore-data.get-preference", data_preference or DataSavingPreference.default }
end)
--- Load player data when they join
Event.add(defines.events.on_player_joined_game, function(event)
local player = game.players[event.player_index]
check_data_loaded_async:start_after(300, player)
PlayerData:request(player)
end)
--- Unload player data when they leave
Event.add(defines.events.on_player_left_game, function(event)
local player = game.players[event.player_index]
local player_data = PlayerData:get(player)
if player_data and player_data.valid == true then
PlayerData:unload(player)
end
end)
----- Module Return -----
return {
All = PlayerData, -- Root for all of a players data
Statistics = PlayerData:combine("Statistics"), -- Common place for stats
Settings = PlayerData:combine("Settings"), -- Common place for settings
Required = PlayerData:combine("Required"), -- Common place for required data
DataSavingPreference = DataSavingPreference, -- Stores what data groups will be saved
PreferenceEnum = PreferenceEnum, -- Enum for the allowed options for data saving preference
}
-81
View File
@@ -1,81 +0,0 @@
# addons
[info]
players-online=There are __1__ players online
total-map-time=This map has been on for __1__
discord=Join us on our discord at: __1__
website=Please visit our website at: __1__
status=Want to check if out servers are down? Visit: __1__
github=Want to help improve our server with some extra features? Help us at: __1__
patreon=Consider supporting our server at: __1__
custom-commands=We use custom commands, such as /tag and /me, use /chelp for more info.
read-readme=Make sure you have read the information gui (It can be found through the info mark on the top left)
softmod=We run a softmod on our servers. A softmod is a custom scenario that runs on this server, an example is the player list.
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
lhd=All trains must be LHD! This is a long standing rule on our servers, please respect this.
# data
[exp-settings]
Bonus=Player Bonus
Bonus-tooltip=The bonus given to your character
Bonus-value-tooltip=Change by using /bonus
# expcore
[expcore-data]
description-preference=Allows you to set/get your data saving preference.
description-data=Writes all your player data to a file on your computer.
arg-option=One of "All", "Statistics", "Settings", "Required"
set-preference=You data saving preference has been set to __1__. Existing data will not be effected until you rejoin.
get-preference=You data saving preference is __1__. Use /set-preference to change this. Use /save-data to get a local copy of your data.
get-data=Your player data has been writen to file, location: factorio/script_output/expgaming_player_data.json
data-failed=Your player data has failed to load. Any changes to your data will not be saved.
data-restore=Your player data has been restored and changes will now save when you leave.
preference=Saving Preference
preference-tooltip=Which categories will be saved when you leave the game
preference-value-tooltip=Change by using /set-preference
preference-All=All data will be saved
preference-Statistics=Only statistics, settings, and required data will be saved
preference-Settings=Only settings and required data will be saved
preference-Required=Only required data will be saved
# gui
[player-list]
main-tooltip=Player List
open-action-bar=Options
close-action-bar=Close Options
reason-confirm=Confirm Reason
reason-entry=Enter Reason
goto-player=Goto player
bring-player=Bring player
report-player=Report player
jail-player=Jail player
kick-player=Kick player
ban-player=Ban player
afk-time=__1__% of total map time\nLast moved __2__ ago
open-map=__1__ __2__\n__3__\nClick to open map
[bonus]
description=Get / Set the amount of bonus you receive.
arg-amount=Amount to set your bonus to, 0 will disable bonus.
set=Your bonus has been set to __1__.
get=Your bonus is __1__.
perm=You dont have enough permission to set more than __1__.
display-fmms=Mining
display-fmms-tooltip=Force manual mining speed
display-frs=Running
display-frs-tooltip=Force running speed
display-fcs=Crafting
display-fcs-tooltip=Force crafting speed
display-fisb=Inventory
display-fisb-tooltip=Force inventory slots bonus
display-fhb=Health
display-fhb-tooltip=Force health bonus
display-frdb=Reach
display-frdb-tooltip=Force reach distance bonus
display-fwrsm=Robot Speed
display-fwrsm-tooltip=Force worker robots speed modifier
display-fwrbm=Robot Battery
display-fwrbm-tooltip=Force worker robots battery modifier
display-fwrsb=Robot Storage
display-fwrsb-tooltip=Force worker robots storage bonus
display-ffrlm=Robot Lifetime
display-ffrlm-tooltip=Force following robots lifetime modifier
-89
View File
@@ -1,89 +0,0 @@
# addons
[info]
players-online=現在有 __1__ 人在線
total-map-time=地圖時間為 __1__
discord=加入社群: __1__
website=訪問網站: __1__
status=伺服器狀態: __1__
github=增加功能或回報錯誤: __1__
patreon=支持我們: __1__
custom-commands=這裹使用了自制指令,如 /tag 和 /me。可使用 /chelp 查看更多。
read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看
softmod=這裹用了自設情境,是一種軟裝模組。
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
# data
[exp-settings]
Bonus=人物附加屬性
Bonus-tooltip=你的人物附加屬性
Bonus-value-tooltip=使用 /bonus 來更改
# expcore
[expcore-data]
description-preference=允許寫入資料。
description-data=把用戶資料寫入電腦。
arg-option="All", "Statistics", "Settings", "Required" 之中
set-preference=你的喜好已設定為 __1__ 。在你重新加入前將不會有任何改動。
get-preference=你的喜好為 __1__ 。使用 /set-preference 來更改,使用 /save-data 來獲得一份資料副本。
get-data=你的個人資料已寫入: factorio/script_output/expgaming_player_data.json
data-failed=無法載入你的個人資料,任何改動將不會保存。
data-restore=已載入你的個人資料,所有改動將會被保存。
preference=儲存喜好
preference-tooltip=那種資料將在退出時保存
preference-value-tooltip=使用 /set-preference 來更換儲存喜好
preference-All=所有資料都會被儲存
preference-Statistics=只有數據, 設定和資料會被儲存
preference-Settings=只有設定和資料會被儲存
preference-Required=只有需要的資料會被儲存
# gui
[player-list]
main-tooltip=用戶名單
open-action-bar=選項
close-action-bar=關閉選項
reason-confirm=確認原因
reason-entry=輸入原因
goto-player=傳送到用戶
bring-player=傳送用戶到自己
report-player=舉報用戶
jail-player=監禁用戶
kick-player=踢除用戶
ban-player=封禁用戶
afk-time=__1__% 地圖時間\n上次移動: __2__
open-map=__1__ __2__\n__3__\n按下打開地圖
[bonus]
description=取得 / 設定 Bonus 量。
arg-amount=Bonus 數量, 0 來停用。
set=你的 Bonus 已設為 __1__。
get=你的 Bonus 為 __1__。
perm=你沒有足夠權限設多過 __1__。
display-fmms=挖掘速度
display-fmms-tooltip=勢力挖掘速度
display-frs=跑步速度
display-frs-tooltip=勢力跑步速度
display-fcs=合成速度
display-fcs-tooltip=勢力合成速度
display-fisb=儲存位
display-fisb-tooltip=勢力儲存位
display-fhb=生命
display-fhb-tooltip=勢力生命
display-frdb=到達距離
display-frdb-tooltip=勢力到達距離
display-fwrsm=機械人速度
display-fwrsm-tooltip=勢力機械人速度
display-fwrbm=機械人電力
display-fwrbm-tooltip=勢力機械人電力
display-fwrsb=械人儲存
display-fwrsb-tooltip=勢力機械人儲存
display-ffrlm=機械人生命
display-ffrlm-tooltip=勢力戰鬥機械人生命時間
[toolbar]
main-caption=工具箱
main-tooltip=工具箱設定\n選上來設定喜好
reset=重設
toggle=啟用喜好
move-up=向上
move-down=向下
-89
View File
@@ -1,89 +0,0 @@
# addons
[info]
players-online=現在有 __1__ 人在線
total-map-time=地圖時間為 __1__
discord=加入社群: __1__
website=訪問網站: __1__
status=伺服器狀態: __1__
github=增加功能或回報錯誤: __1__
patreon=支持我們: __1__
custom-commands=這裹使用了自制指令,如 /tag 和 /me。可使用 /chelp 查看更多。
read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看
softmod=這裹用了自設情境,是一種軟裝模組。
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
# data
[exp-settings]
Bonus=人物附加屬性
Bonus-tooltip=你的人物附加屬性
Bonus-value-tooltip=使用 /bonus 來更改
# expcore
[expcore-data]
description-preference=允許寫入資料。
description-data=把用戶資料寫入電腦。
arg-option="All", "Statistics", "Settings", "Required" 之中
set-preference=你的喜好已設定為 __1__ 。在你重新加入前將不會有任何改動。
get-preference=你的喜好為 __1__ 。使用 /set-preference 來更改,使用 /save-data 來獲得一份資料副本。
get-data=你的個人資料已寫入: factorio/script_output/expgaming_player_data.json
data-failed=無法載入你的個人資料,任何改動將不會保存。
data-restore=已載入你的個人資料,所有改動將會被保存。
preference=儲存喜好
preference-tooltip=那種資料將在退出時保存
preference-value-tooltip=使用 /set-preference 來更換儲存喜好
preference-All=所有資料都會被儲存
preference-Statistics=只有數據, 設定和資料會被儲存
preference-Settings=只有設定和資料會被儲存
preference-Required=只有需要的資料會被儲存
# gui
[player-list]
main-tooltip=用戶名單
open-action-bar=選項
close-action-bar=關閉選項
reason-confirm=確認原因
reason-entry=輸入原因
goto-player=傳送到用戶
bring-player=傳送用戶到自己
report-player=舉報用戶
jail-player=監禁用戶
kick-player=踢除用戶
ban-player=封禁用戶
afk-time=__1__% 地圖時間\n上次移動: __2__
open-map=__1__ __2__\n__3__\n按下打開地圖
[bonus]
description=取得 / 設定 Bonus 量。
arg-amount=Bonus 數量, 0 來停用。
set=你的 Bonus 已設為 __1__。
get=你的 Bonus 為 __1__。
perm=你沒有足夠權限設多過 __1__。
display-fmms=挖掘速度
display-fmms-tooltip=勢力挖掘速度
display-frs=跑步速度
display-frs-tooltip=勢力跑步速度
display-fcs=合成速度
display-fcs-tooltip=勢力合成速度
display-fisb=儲存位
display-fisb-tooltip=勢力儲存位
display-fhb=生命
display-fhb-tooltip=勢力生命
display-frdb=到達距離
display-frdb-tooltip=勢力到達距離
display-fwrsm=機械人速度
display-fwrsm-tooltip=勢力機械人速度
display-fwrbm=機械人電力
display-fwrbm-tooltip=勢力機械人電力
display-fwrsb=械人儲存
display-fwrsb-tooltip=勢力機械人儲存
display-ffrlm=機械人生命
display-ffrlm-tooltip=勢力戰鬥機械人生命時間
[toolbar]
main-caption=工具箱
main-tooltip=工具箱設定\n選上來設定喜好
reset=重設
toggle=啟用喜好
move-up=向上
move-down=向下
-13
View File
@@ -1,13 +0,0 @@
{
"name": "exp_legacy",
"load": [
"control.lua"
],
"require": [
],
"dependencies": {
"clusterio": "*",
"exp_util": "*",
"exp_gui": "*"
}
}
-3
View File
@@ -1,3 +0,0 @@
--- Can contain anything you want to allow other plugins to have access to, this example exposes the control file
-- Access the exports from other modules using require("modules/exp_legacy")
return require("modules/exp_legacy/control")
-86
View File
@@ -1,86 +0,0 @@
local ExpUtil = require("modules/exp_util")
local Event = {
real_handlers = {
events = {},
on_nth_tick = {},
on_init = nil,
on_load = nil,
},
handlers = {
events = {},
on_nth_tick = {},
on_init = nil,
on_load = nil,
},
}
local function call_handlers_factory(handlers)
return function(event)
for _, handler in ipairs(handlers) do
handler(event)
end
end
end
function Event.add(event_name, handler)
ExpUtil.assert_not_runtime()
ExpUtil.assert_argument_type(event_name, "number", 1, "event_name")
ExpUtil.assert_argument_type(handler, "function", 2, "handler")
local handlers = Event.handlers.events[event_name]
if not handlers then
handlers = {}
Event.handlers.events[event_name] = handlers
Event.real_handlers.events[event_name] = call_handlers_factory(handlers)
end
handlers[#handlers + 1] = handler
end
function Event.on_nth_tick(tick, handler)
ExpUtil.assert_not_runtime()
ExpUtil.assert_argument_type(tick, "number", 1, "tick")
ExpUtil.assert_argument_type(handler, "function", 2, "handler")
local handlers = Event.handlers.on_nth_tick[tick]
if not handlers then
handlers = {}
Event.handlers.on_nth_tick[tick] = handlers
Event.real_handlers.on_nth_tick[tick] = call_handlers_factory(handlers)
end
handlers[#handlers + 1] = handler
end
function Event.on_init(handler)
ExpUtil.assert_not_runtime()
ExpUtil.assert_argument_type(handler, "function", 1, "handler")
local handlers = Event.handlers.on_init
if not handlers then
handlers = {}
Event.handlers.on_init = handlers
Event.real_handlers.on_init = call_handlers_factory(handlers)
end
handlers[#handlers + 1] = handler
Event.add(defines.events.on_singleplayer_init, handler)
Event.add(defines.events.on_multiplayer_init, handler)
end
function Event.on_load(handler)
ExpUtil.assert_not_runtime()
ExpUtil.assert_argument_type(handler, "function", 1, "handler")
local handlers = Event.handlers.on_load
if not handlers then
handlers = {}
Event.handlers.on_load = handlers
Event.real_handlers.on_load = call_handlers_factory(handlers)
end
handlers[#handlers + 1] = handler
end
return Event
-51
View File
@@ -1,51 +0,0 @@
{
"name": "@expcluster/legacy",
"version": "7.0.1",
"description": "Clusterio plugin implementing the legacy v6 scenario updated for factorio 2.0",
"author": "Cooldude2606 <https://github.com/Cooldude2606>",
"license": "MIT",
"repository": "explosivegaming/ExpCluster",
"type": "module",
"main": "dist/node/index.js",
"scripts": {
"prepare": "tsc --build && webpack-cli --env production"
},
"engines": {
"node": ">=22"
},
"peerDependencies": {
"@clusterio/controller": "workspace:^",
"@clusterio/host": "workspace:^",
"@clusterio/lib": "workspace:^"
},
"peerDependenciesMeta": {
"@clusterio/controller": {
"optional": true
},
"@clusterio/host": {
"optional": true
}
},
"devDependencies": {
"@clusterio/lib": "workspace:^",
"@types/node": "catalog:",
"typescript": "catalog:",
"webpack": "catalog:",
"webpack-cli": "catalog:",
"webpack-merge": "catalog:"
},
"dependencies": {
"@expcluster/lib_commands": "workspace:^",
"@expcluster/lib_util": "workspace:^",
"@expcluster/lib_gui": "workspace:^",
"@sinclair/typebox": "catalog:"
},
"publishConfig": {
"access": "public"
},
"keywords": [
"clusterio",
"clusterio-plugin",
"factorio"
]
}
-4
View File
@@ -1,4 +0,0 @@
{
"extends": "../tsconfig.browser.json",
"include": [ "web/**/*.tsx", "web/**/*.ts", "package.json" ],
}
-7
View File
@@ -1,7 +0,0 @@
{
"files": [],
"references": [
{ "path": "./tsconfig.node.json" },
{ "path": "./tsconfig.browser.json" }
]
}
-5
View File
@@ -1,5 +0,0 @@
{
"extends": "../tsconfig.node.json",
"include": ["./**/*.ts"],
"exclude": ["test/*", "./dist/*"],
}
View File
Whitespace-only changes.
-29
View File
@@ -1,29 +0,0 @@
"use strict";
const path = require("path");
const webpack = require("webpack");
const { merge } = require("webpack-merge");
const common = require("@clusterio/web_ui/webpack.common");
module.exports = (env = {}) => merge(common(env), {
context: __dirname,
entry: "./web/index.tsx",
output: {
path: path.resolve(__dirname, "dist", "web"),
},
plugins: [
new webpack.container.ModuleFederationPlugin({
name: "exp_legacy",
library: { type: "window", name: "plugin_exp_legacy" },
exposes: {
"./": "./index.ts",
"./package.json": "./package.json",
"./web": "./web/index.tsx",
},
shared: {
"@clusterio/lib": { import: false },
"@clusterio/web_ui": { import: false },
},
}),
],
});
+2 -3
View File
@@ -1,5 +1,5 @@
--[[-- Command Rcon - ExpCore --[[-- Command Rcon - ExpGaming
Adds rcon interfaces for the legacy exp core Adds rcon statics for the ExpGaming modules
]] ]]
local Commands = require("modules/exp_commands") local Commands = require("modules/exp_commands")
@@ -8,5 +8,4 @@ local add_static, add_dynamic = Commands.add_rcon_static, Commands.add_rcon_dyna
add_static("Gui", require("modules/exp_gui")) add_static("Gui", require("modules/exp_gui"))
add_static("Roles", require("modules/exp_roles")) add_static("Roles", require("modules/exp_roles"))
add_static("Datastore", require("modules.exp_legacy.expcore.datastore"))
add_static("ExpServerList", require("modules/exp_server_list")) add_static("ExpServerList", require("modules/exp_server_list"))
@@ -1,132 +0,0 @@
local Gui = require("modules/exp_scenario/gui/debug/shim")
local Datastore = require("modules.exp_legacy.expcore.datastore")
local Color = require("modules/exp_util/include/color")
local Model = require("modules/exp_scenario/gui/debug/model")
local dump = Model.dump
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 = "Datastore"
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 name in pairs(table.key_sort(Datastore.debug())) do
local header = left_panel.add{ type = "flow" }.add{ type = "label", name = header_name, caption = name }
Gui.set_data(header, name)
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 table_name = 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 = table_name
input_text_box.style.font_color = Color.black
local content = Datastore.debug(table_name)
local content_string = {}
for key, value in pairs(content) do
content_string[#content_string + 1] = key:gsub("^%l", string.upper) .. " = " .. dump(value)
end
right_panel.text = concat(content_string, "\n")
end
)
local function update_dump(text_input, data)
local content = Datastore.debug(text_input.text)
local content_string = {}
for key, value in pairs(content) do
content_string[#content_string + 1] = key:gsub("^%l", string.upper) .. " = " .. dump(value)
end
data.right_panel.text = concat(content_string, "\n")
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)
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)
end
)
return Public
@@ -5,7 +5,6 @@ local Public = {}
local pages = { local pages = {
require("modules/exp_scenario/gui/debug/redmew_global_view"), require("modules/exp_scenario/gui/debug/redmew_global_view"),
require("modules/exp_scenario/gui/debug/expcore_datastore_view"),
require("modules/exp_scenario/gui/debug/expcore_gui_view"), require("modules/exp_scenario/gui/debug/expcore_gui_view"),
require("modules/exp_scenario/gui/debug/global_view"), require("modules/exp_scenario/gui/debug/global_view"),
require("modules/exp_scenario/gui/debug/package_view"), require("modules/exp_scenario/gui/debug/package_view"),
+12
View File
@@ -528,6 +528,18 @@ tooltip-goto-disabled=You are not on a warp point, walk to a warp point
[exp_afk-kick] [exp_afk-kick]
kick-message=All players were kicked because everyone was AFK. kick-message=All players were kicked because everyone was AFK.
[info]
discord=Join us on our discord at: __1__
website=Please visit our website at: __1__
status=Want to check if out servers are down? Visit: __1__
github=Want to help improve our server with some extra features? Help us at: __1__
patreon=Consider supporting our server at: __1__
custom-commands=We use custom commands, such as /tag and /me, use /chelp for more info.
read-readme=Make sure you have read the information gui (It can be found through the info mark on the top left)
softmod=We run a softmod on our servers. A softmod is a custom scenario that runs on this server, an example is the player list.
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
lhd=All trains must be LHD! This is a long standing rule on our servers, please respect this.
[exp_chat-auto-reply] [exp_chat-auto-reply]
chat-reply=[Compilatron] __1__ chat-reply=[Compilatron] __1__
chat-disallowed=You can't use global chat commands chat-disallowed=You can't use global chat commands
+12
View File
@@ -518,6 +518,18 @@ message-research=你要研究 [technology=__1__] 在 __2__ 級 才可使用太
[exp_afk-kick] [exp_afk-kick]
kick-message=因地圖中沒有活躍玩家,所以所有人都已被請離。 kick-message=因地圖中沒有活躍玩家,所以所有人都已被請離。
[info]
discord=加入社群: __1__
website=訪問網站: __1__
status=伺服器狀態: __1__
github=增加功能或回報錯誤: __1__
patreon=支持我們: __1__
custom-commands=這裹使用了自制指令,如 /tag 和 /me。可使用 /chelp 查看更多。
read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看
softmod=這裹用了自設情境,是一種軟裝模組。
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
[exp_chat-auto-reply] [exp_chat-auto-reply]
chat-reply=[Compilatron] __1__ chat-reply=[Compilatron] __1__
chat-disallowed=You can't use global chat commands chat-disallowed=You can't use global chat commands
+12
View File
@@ -518,6 +518,18 @@ message-research=你要研究 [technology=__1__] 在 __2__ 級 才可使用太
[exp_afk-kick] [exp_afk-kick]
kick-message=因地圖中沒有活躍玩家,所以所有人都已被請離。 kick-message=因地圖中沒有活躍玩家,所以所有人都已被請離。
[info]
discord=加入社群: __1__
website=訪問網站: __1__
status=伺服器狀態: __1__
github=增加功能或回報錯誤: __1__
patreon=支持我們: __1__
custom-commands=這裹使用了自制指令,如 /tag 和 /me。可使用 /chelp 查看更多。
read-readme=確保你已閱讀相關資訊。按左上 i 圖標可再次查看
softmod=這裹用了自設情境,是一種軟裝模組。
redmew=We don't talk about redmew here; they beat us to 1000 members ;-;
lhd=列車必須是左則通行。這是本服務器長久以來的規則。
[exp_chat-auto-reply] [exp_chat-auto-reply]
chat-reply=[Compilatron] __1__ chat-reply=[Compilatron] __1__
chat-disallowed=You can't use global chat commands chat-disallowed=You can't use global chat commands
+1 -1
View File
@@ -1,6 +1,6 @@
# ExpGaming - Server List # ExpGaming - Server List
Shares the details of every instance with every other instance. Replaces `expcore/external` from exp_legacy, which read the same data from a file written by an outside service. Shares the details of every instance with every other instance.
The controller keeps one record per instance with its name, mod pack, Factorio version, players online, status and address. The address is the public address of the host and the game port of the instance, the same one the web UI shows. Whether the server has a game password is sent, the password is not. Nothing is saved, the records are rebuilt from the instances when the controller starts. The controller keeps one record per instance with its name, mod pack, Factorio version, players online, status and address. The address is the public address of the host and the game port of the instance, the same one the web UI shows. Whether the server has a game password is sent, the password is not. Nothing is saved, the records are rebuilt from the instances when the controller starts.
-1
View File
@@ -6,7 +6,6 @@
{ "path": "./exp_discord_auth/" }, { "path": "./exp_discord_auth/" },
{ "path": "./exp_groups/" }, { "path": "./exp_groups/" },
{ "path": "./exp_gui/" }, { "path": "./exp_gui/" },
{ "path": "./exp_legacy/" },
{ "path": "./exp_reports/" }, { "path": "./exp_reports/" },
{ "path": "./exp_roles/" }, { "path": "./exp_roles/" },
{ "path": "./exp_scenario/" }, { "path": "./exp_scenario/" },