mirror of
https://github.com/clusterio/clusterio.git
synced 2026-11-14 23:24:52 +09:00
Changed usage of globals, worked around edge cases
This commit is contained in:
1 parent
f9ef2ebbe1
commit
98f801e244
11 files changed
+124
-62
No files matched your search
@@ -57,7 +57,7 @@ module.exports = {
|
||||
"instance_id": { type: "integer" },
|
||||
"instance_name": { type: "string" },
|
||||
"player_name": { type: "string" },
|
||||
"inventory": { type: "string" },
|
||||
"inventory": { type: "object" },
|
||||
},
|
||||
responseProperties: {
|
||||
"success": { type: "boolean" },
|
||||
@@ -72,7 +72,8 @@ module.exports = {
|
||||
},
|
||||
responseProperties: {
|
||||
"player_name": { type: "string" },
|
||||
"inventory": { type: "string" },
|
||||
"inventory": { type: "object" },
|
||||
"new_player": { type: "boolean" },
|
||||
},
|
||||
}),
|
||||
databaseStats: new libLink.Request({
|
||||
|
||||
@@ -34,7 +34,7 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
|
||||
instance_id: this.instance.id,
|
||||
instance_name: this.instance.name,
|
||||
player_name: player.name,
|
||||
inventory: JSON.stringify(player),
|
||||
inventory: player,
|
||||
});
|
||||
}
|
||||
|
||||
@@ -43,14 +43,15 @@ class InstancePlugin extends libPlugin.BaseInstancePlugin {
|
||||
let response = await this.info.messages.download.send(this.instance, {
|
||||
player_name: player.player_name,
|
||||
});
|
||||
if (response.inventory) {
|
||||
if (response.new_player) {
|
||||
await this.sendRcon(`/sc inventory_sync.welcome_new_player('${response.player_name}')`)
|
||||
} else if (response.inventory) {
|
||||
const chunkSize = this.instance.config.get("inventory_sync.rcon_chunk_size");
|
||||
const chunks = chunkify(chunkSize, response.inventory);
|
||||
const chunks = chunkify(chunkSize, JSON.stringify(response.inventory));
|
||||
this.logger.verbose(`Sending inventory for ${player.player_name} in ${chunks.length} chunks`);
|
||||
for (let i = 0; i < chunks.length; i++) {
|
||||
// this.logger.verbose(`Sending chunk ${i+1} of ${chunks.length}`)
|
||||
await this.sendRcon(`/sc inventory_sync.downloadInventory('${response.player_name}', '
|
||||
${libLuaTools.escapeString(response.inventory)}', ${i + 1}, ${chunks.length})`);
|
||||
await this.sendRcon(`/sc inventory_sync.download_inventory('${response.player_name}', '${libLuaTools.escapeString(chunks[i])}', ${i + 1}, ${chunks.length})`);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
"use strict";
|
||||
const fs = require("fs").promises;
|
||||
const fs = require("fs-extra");
|
||||
const path = require("path");
|
||||
|
||||
const libPlugin = require("@clusterio/lib/plugin");
|
||||
@@ -50,7 +50,8 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
|
||||
this.logger.verbose(`Downloading inventory for ${message.data.player_name}`);
|
||||
return {
|
||||
player_name: message.data.player_name,
|
||||
inventory: this.inventories[message.data.player_name],
|
||||
inventory: this.inventories[message.data.player_name] || {},
|
||||
new_player: !this.inventories[message.data.player_name],
|
||||
};
|
||||
}
|
||||
|
||||
@@ -63,7 +64,7 @@ class MasterPlugin extends libPlugin.BaseMasterPlugin {
|
||||
let inventories = Object.keys(this.inventories)
|
||||
.map(name => ({
|
||||
name,
|
||||
length: this.inventories[name].length,
|
||||
length: JSON.stringify(this.inventories[name]).length,
|
||||
}))
|
||||
.sort((a, b) => a.stringified.length - b.stringified.length);
|
||||
return {
|
||||
|
||||
@@ -2,16 +2,20 @@ local progress_dialog = require("modules/inventory_sync/progress_dialog")
|
||||
local serialize = require("modules/clusterio/serialize")
|
||||
local load_crafting_queue = require("modules/inventory_sync/load_crafting_queue")
|
||||
local inventories = require("modules/inventory_sync/define_player_inventories")
|
||||
local ensure_character = require("modules/inventory_sync/ensure_character")
|
||||
|
||||
function download_inventory(playerName, data, number, total)
|
||||
local player = game.get_player(playerName)
|
||||
if player == nil then return end
|
||||
function download_inventory(player_name, data, number, total)
|
||||
local player = game.get_player(player_name)
|
||||
if player == nil then
|
||||
log("Player not found! "..player_name)
|
||||
return
|
||||
end
|
||||
if number then
|
||||
if global.download_cache[playerName] == nil then
|
||||
global.download_cache[playerName] = ""
|
||||
if global.inventory_sync.download_cache[player_name] == nil then
|
||||
global.inventory_sync.download_cache[player_name] = ""
|
||||
end
|
||||
-- Append data to download cache
|
||||
global.download_cache[playerName] = global.download_cache[playerName] .. data
|
||||
global.inventory_sync.download_cache[player_name] = global.inventory_sync.download_cache[player_name] .. data
|
||||
end
|
||||
|
||||
if number ~= total then
|
||||
@@ -24,13 +28,19 @@ function download_inventory(playerName, data, number, total)
|
||||
rcon.print("Segment downloaded")
|
||||
else
|
||||
-- Recreate player character
|
||||
player.set_controller {
|
||||
type = defines.controllers.god,
|
||||
}
|
||||
player.create_character()
|
||||
ensure_character(player)
|
||||
|
||||
-- Remove freeplay skip cutscene label
|
||||
if player.gui.screen.skip_cutscene_label then
|
||||
player.gui.screen.skip_cutscene_label.destroy()
|
||||
end
|
||||
|
||||
local character = player.character or player.cutscene_character
|
||||
|
||||
-- Load downloaded inventory
|
||||
local serialized_player = game.json_to_table(global.download_cache[playerName])
|
||||
global.download_cache[playerName] = nil -- remove data to lower mapsize
|
||||
local serialized_player = game.json_to_table(global.inventory_sync.download_cache[player_name])
|
||||
global.inventory_sync.download_cache[player_name] = nil -- remove data to lower mapsize
|
||||
|
||||
-- Load inventories
|
||||
for _, inv in pairs(inventories) do
|
||||
local inventory = player.get_inventory(inv)
|
||||
@@ -64,21 +74,21 @@ function download_inventory(playerName, data, number, total)
|
||||
player.color = serialized_player.color
|
||||
player.chat_color = serialized_player.chat_color
|
||||
|
||||
player.character_crafting_speed_modifier = serialized_player.character_crafting_speed_modifier
|
||||
player.character_mining_speed_modifier = serialized_player.character_mining_speed_modifier
|
||||
player.character_additional_mining_categories = serialized_player.character_additional_mining_categories
|
||||
player.character_running_speed_modifier = serialized_player.character_running_speed_modifier
|
||||
player.character_build_distance_bonus = serialized_player.character_build_distance_bonus
|
||||
player.character_item_drop_distance_bonus = serialized_player.character_item_drop_distance_bonus
|
||||
player.character_reach_distance_bonus = serialized_player.character_reach_distance_bonus
|
||||
player.character_resource_reach_distance_bonus = serialized_player.character_resource_reach_distance_bonus
|
||||
player.character_item_pickup_distance_bonus = serialized_player.character_item_pickup_distance_bonus
|
||||
player.character_loot_pickup_distance_bonus = serialized_player.character_loot_pickup_distance_bonus
|
||||
player.character_inventory_slots_bonus = serialized_player.character_inventory_slots_bonus
|
||||
player.character_trash_slot_count_bonus = serialized_player.character_trash_slot_count_bonus
|
||||
player.character_maximum_following_robot_count_bonus = serialized_player.character_maximum_following_robot_count_bonus
|
||||
player.character_health_bonus = serialized_player.character_health_bonus
|
||||
player.character_personal_logistic_requests_enabled = serialized_player.character_personal_logistic_requests_enabled
|
||||
character.character_crafting_speed_modifier = serialized_player.character_crafting_speed_modifier
|
||||
character.character_mining_speed_modifier = serialized_player.character_mining_speed_modifier
|
||||
character.character_additional_mining_categories = serialized_player.character_additional_mining_categories
|
||||
character.character_running_speed_modifier = serialized_player.character_running_speed_modifier
|
||||
character.character_build_distance_bonus = serialized_player.character_build_distance_bonus
|
||||
character.character_item_drop_distance_bonus = serialized_player.character_item_drop_distance_bonus
|
||||
character.character_reach_distance_bonus = serialized_player.character_reach_distance_bonus
|
||||
character.character_resource_reach_distance_bonus = serialized_player.character_resource_reach_distance_bonus
|
||||
character.character_item_pickup_distance_bonus = serialized_player.character_item_pickup_distance_bonus
|
||||
character.character_loot_pickup_distance_bonus = serialized_player.character_loot_pickup_distance_bonus
|
||||
character.character_inventory_slots_bonus = serialized_player.character_inventory_slots_bonus
|
||||
character.character_trash_slot_count_bonus = serialized_player.character_trash_slot_count_bonus
|
||||
character.character_maximum_following_robot_count_bonus = serialized_player.character_maximum_following_robot_count_bonus
|
||||
character.character_health_bonus = serialized_player.character_health_bonus
|
||||
character.character_personal_logistic_requests_enabled = serialized_player.character_personal_logistic_requests_enabled
|
||||
|
||||
if serialized_player.flashlight then
|
||||
player.enable_flashlight()
|
||||
@@ -86,8 +96,8 @@ function download_inventory(playerName, data, number, total)
|
||||
player.disable_flashlight()
|
||||
end
|
||||
|
||||
local startTick = global["inv_sync_download_start_tick "..player.name]
|
||||
local log_line = "Imported inventory for "..playerName.." in "..game.tick - startTick.." ticks"
|
||||
local startTick = global.inventory_sync.download_start_tick[player.name]
|
||||
local log_line = "Imported inventory for "..player_name.." in "..game.tick - startTick.." ticks"
|
||||
player.print(log_line)
|
||||
log("[inventory_sync] "..log_line)
|
||||
end
|
||||
|
||||
@@ -0,0 +1,13 @@
|
||||
local function ensure_character(player)
|
||||
if player.character == nil then
|
||||
log("Character define:")
|
||||
log(player.controller_type)
|
||||
log(serpent.block(defines.controllers))
|
||||
player.set_controller {
|
||||
type = defines.controllers.god,
|
||||
}
|
||||
player.create_character()
|
||||
end
|
||||
end
|
||||
|
||||
return ensure_character
|
||||
@@ -5,6 +5,7 @@ When a player leaves the game, serialize their inventory and upload it to the ma
|
||||
When a player joins the game, send a request to the master server for the players inventory.
|
||||
|
||||
When the master sends an inventory, parse it and give it to the player.
|
||||
If the master responds that its a new player, show a welcome message.
|
||||
|
||||
]]
|
||||
|
||||
@@ -12,42 +13,62 @@ local clusterio_api = require("modules/clusterio/api")
|
||||
local add_commands = require("modules/inventory_sync/commands")
|
||||
local upload_inventory = require("modules/inventory_sync/upload_inventory")
|
||||
local download_inventory = require("modules/inventory_sync/download_inventory")
|
||||
local welcome_new_player = require("modules/inventory_sync/welcome_new_player")
|
||||
|
||||
inventory_sync = {}
|
||||
inventory_sync.welcome_new_player = welcome_new_player
|
||||
-- This function is called by instance.js as /sc inventory_sync.download_inventory("danielv", Escaped JSON string, package_number, total_packages_count) with data from the master
|
||||
inventory_sync.download_inventory = download_inventory
|
||||
-- This function is called internally when a player leaves the game for their inventory to upload to the master
|
||||
inventory_sync.upload_inventory = upload_inventory
|
||||
|
||||
inventory_sync.add_commands = add_commands
|
||||
inventory_sync.events = {}
|
||||
inventory_sync.events[clusterio_api.events.on_server_startup] = function(event)
|
||||
-- set up global table
|
||||
if not global.inventory_sync then
|
||||
global.inventory_sync = {
|
||||
download_start_tick = {},
|
||||
saved_crafting_queue = {},
|
||||
download_cache = {},
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- Cleanup
|
||||
inventory_sync.events[defines.events.on_player_removed] = function(event)
|
||||
local player = game.get_player(event.player_index)
|
||||
|
||||
-- Remove inventory download performance counter
|
||||
global["inv_sync_download_start_tick "..player.name] = nil
|
||||
global.inventory_sync.download_start_tick[player.name] = nil
|
||||
-- Remove stored crafting queue
|
||||
global["saved_crafting_queue_"..player.name] = nil
|
||||
global.inventory_sync.saved_crafting_queue[player.name] = nil
|
||||
end
|
||||
|
||||
-- Download inventory from master
|
||||
inventory_sync.events[defines.events.on_player_joined_game] = function(event)
|
||||
local playerIndex = event.player_index
|
||||
inventory_sync.initiateInventoryDownload(playerIndex)
|
||||
inventory_sync.initiate_inventory_download(playerIndex)
|
||||
end
|
||||
|
||||
-- Upload inventory when a player leaves the game. Triggers on restart after crash if player was online during crash.
|
||||
inventory_sync.events[defines.events.on_pre_player_left_game] = function(event)
|
||||
local playerIndex = event.player_index
|
||||
inventory_sync.uploadInventory(playerIndex)
|
||||
global.download_cache[playerIndex] = "" -- Clear cache to avoid leaking memory to people quitting during download
|
||||
-- for some reason, on_pre_player_left_game gets called before on_server_startup so global isn't ready yet
|
||||
if not global.inventory_sync then
|
||||
log("ERROR: Global inventory sync not defined")
|
||||
return
|
||||
end
|
||||
|
||||
local player_index = event.player_index
|
||||
inventory_sync.upload_inventory(player_index)
|
||||
global.inventory_sync.download_cache[player_index] = "" -- Clear cache to avoid leaking memory to people quitting during download
|
||||
end
|
||||
|
||||
function inventory_sync.initiateInventoryDownload(playerIndex)
|
||||
function inventory_sync.initiate_inventory_download(playerIndex)
|
||||
local player = game.get_player(playerIndex)
|
||||
player.print("Initiating inventory download...")
|
||||
global["inv_sync_download_start_tick "..player.name] = game.tick
|
||||
if global.download_cache == nil then
|
||||
global.download_cache = {}
|
||||
end
|
||||
global.download_cache[playerIndex] = ""
|
||||
global.inventory_sync.download_start_tick[player.name] = game.tick
|
||||
global.inventory_sync.download_cache[playerIndex] = ""
|
||||
clusterio_api.send_json("inventory_sync_download", {
|
||||
player_name = player.name
|
||||
})
|
||||
@@ -60,9 +81,4 @@ function inventory_sync.initiateInventoryDownload(playerIndex)
|
||||
if character ~= nil then character.destroy() end
|
||||
end
|
||||
|
||||
-- This function is called by instance.js as /sc inventory_sync.downloadInventory("danielv", Escaped JSON string, package_number, total_packages_count) with data from the master
|
||||
inventory_sync.downloadInventory = download_inventory
|
||||
-- This function is called internally when a player leaves the game for their inventory to upload to the master
|
||||
inventory_sync.uploadInventory = upload_inventory
|
||||
|
||||
return inventory_sync
|
||||
@@ -3,7 +3,7 @@ local load_crafting_queue = require("modules/inventory_sync/load_crafting_queue"
|
||||
function restore_crafts(event)
|
||||
if event.player_index then
|
||||
local player = game.get_player(event.player_index)
|
||||
local crafting_queue = global["saved_crafting_queue_"..player.name]
|
||||
local crafting_queue = global.inventory_sync.saved_crafting_queue[player.name]
|
||||
|
||||
if crafting_queue == nil then
|
||||
player.print("No saved crafting queue")
|
||||
@@ -12,7 +12,7 @@ function restore_crafts(event)
|
||||
|
||||
load_crafting_queue(crafting_queue, player)
|
||||
|
||||
global["saved_crafting_queue_"..player.name] = nil
|
||||
global.inventory_sync.saved_crafting_queue[player.name] = nil
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -4,7 +4,7 @@ function save_crafts(event)
|
||||
local crafting_queue = {}
|
||||
|
||||
-- Avoid overwriting old save
|
||||
if global["saved_crafting_queue_"..player.name] ~= nil then
|
||||
if global.inventory_sync.saved_crafting_queue[player.name] ~= nil then
|
||||
player.print("You already have a saved crafting queue, restore it with /restore-crafts")
|
||||
return
|
||||
end
|
||||
@@ -86,7 +86,7 @@ function save_crafts(event)
|
||||
-- Remove extra inventory slots
|
||||
player.character_inventory_slots_bonus = player.character_inventory_slots_bonus - 1000
|
||||
|
||||
global["saved_crafting_queue_"..player.name] = {
|
||||
global.inventory_sync.saved_crafting_queue[player.name] = {
|
||||
crafting_queue = crafting_queue,
|
||||
ingredients = difference,
|
||||
}
|
||||
|
||||
@@ -2,10 +2,14 @@ local clusterio_api = require("modules/clusterio/api")
|
||||
local serialize = require("modules/clusterio/serialize")
|
||||
local inventories = require("modules/inventory_sync/define_player_inventories")
|
||||
local save_crafts = require("modules/inventory_sync/save_crafts")
|
||||
local ensure_character = require("modules/inventory_sync/ensure_character")
|
||||
|
||||
function upload_inventory(playerIndex)
|
||||
local player = game.get_player(playerIndex)
|
||||
|
||||
-- Force player to have a character to prevent access errors
|
||||
ensure_character(player)
|
||||
|
||||
local serialized_player = {
|
||||
name = player.name,
|
||||
inventories = {},
|
||||
@@ -71,7 +75,7 @@ function upload_inventory(playerIndex)
|
||||
|
||||
-- Serialize crafting queue saved by /csc or /save-crafts OR automatically
|
||||
save_crafts({player_index = player.name})
|
||||
serialized_player.crafting_queue = global["saved_crafting_queue_"..player.name]
|
||||
serialized_player.crafting_queue = global.inventory_sync.saved_crafting_queue[player.name]
|
||||
if serialized_player.crafting_queue == nil then
|
||||
serialized_player.crafting_queue = {}
|
||||
end
|
||||
@@ -79,7 +83,7 @@ function upload_inventory(playerIndex)
|
||||
clusterio_api.send_json("inventory_sync_upload", serialized_player)
|
||||
|
||||
-- Clear saved crafting queue
|
||||
global["saved_crafting_queue_"..player.name] = nil
|
||||
global.inventory_sync.saved_crafting_queue[player.name] = nil
|
||||
end
|
||||
|
||||
return upload_inventory
|
||||
@@ -0,0 +1,13 @@
|
||||
local ensure_character = require("modules/inventory_sync/ensure_character")
|
||||
|
||||
local function welcome_new_player(player_name)
|
||||
local player = game.get_player(player_name)
|
||||
if player == nil then return end
|
||||
player.print("Welcome to the server!")
|
||||
player.print("Your inventory will be automatically synchronized between servers in this cluster.")
|
||||
player.print("To improve sync performance, please avoid storing blueprints in your inventory.")
|
||||
|
||||
ensure_character(player)
|
||||
end
|
||||
|
||||
return welcome_new_player
|
||||
@@ -19,6 +19,9 @@
|
||||
"peerDependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"fs-extra": "^8.1.0"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@clusterio/lib": "^2.0.0-alpha.6",
|
||||
"@clusterio/web_ui": "^2.0.0-alpha.6",
|
||||
|
||||
Reference in new issue
Block a user