Changed usage of globals, worked around edge cases

This commit is contained in:
danielv authored and Daniel committed 2021-07-12 22:05:54 +02:00
1 parent f9ef2ebbe1
commit 98f801e244
11 files changed
+124 -62

No files matched your search

+3 -2
View File
@@ -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({
+6 -5
View File
@@ -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})`);
}
}
}
+4 -3
View File
@@ -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
+3
View File
@@ -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",