mirror of
https://github.com/Xevion/project-cybersyn.git
synced 2025-12-15 04:12:51 -06:00
1.2.8 (#28)
Version: 1.2.8
Date: 2022-1-5
Features:
- Improved placeholder cybernetic combinator art
- Added a wagon control setting to bar unfiltered slots in adjacent cargo wagons
- Added a setting and keybind for toggling on or off the central planner
Changes:
- Sped up the rate at which copy-paste by blueprint will be noticed
Bugfixes:
- Fixed a bug with combinators sometimes failing to connect with train stops
- Fixed wagon control combinators outputting wagon contents after inserters have already taken out items
- Fixed a rare crash on world migration
Scripting:
- Added missing return values to some interface functions
- Migrated to non-deprecated flib modules
This commit is contained in:
424
.vscode/flib/dictionary.lua
vendored
Normal file
424
.vscode/flib/dictionary.lua
vendored
Normal file
@@ -0,0 +1,424 @@
|
||||
local gui = require("__flib__/gui-lite")
|
||||
local mod_gui = require("__core__/lualib/mod-gui")
|
||||
local table = require("__flib__/table")
|
||||
|
||||
--- @diagnostic disable
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
local flib_dictionary = {}
|
||||
|
||||
local inner_separator = "" -- U+E000
|
||||
local separator = "" -- U+E001
|
||||
local translation_timeout = 600
|
||||
|
||||
-- Depending on the value of `use_local_storage`, this will be tied to `global` or will be re-generated during `on_load`
|
||||
local raw = { _total_strings = 0 }
|
||||
|
||||
local use_local_storage = false
|
||||
|
||||
local function key_value(key, value)
|
||||
return key .. inner_separator .. value .. separator
|
||||
end
|
||||
|
||||
local RawDictionary = {}
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function RawDictionary:add(internal, translation)
|
||||
local to_add = { "", internal, inner_separator, { "?", translation, "FLIB_TRANSLATION_FAILED" }, separator }
|
||||
|
||||
local ref = self.ref
|
||||
local i = self.batch_i + 1
|
||||
-- Due to network saturation concerns, only group five strings together
|
||||
-- See https://github.com/factoriolib/flib/issues/45
|
||||
if i < 5 then
|
||||
ref[i] = to_add --- @diagnostic disable-line
|
||||
self.batch_i = i
|
||||
else
|
||||
local s_i = self.dict_i + 1
|
||||
self.dict_i = s_i
|
||||
local new_set = { "", to_add }
|
||||
self.ref = new_set
|
||||
self.strings[s_i] = new_set
|
||||
self.batch_i = 2
|
||||
end
|
||||
self.total = self.total + 1
|
||||
raw._total_strings = raw._total_strings + 1
|
||||
end
|
||||
|
||||
--- @class RawDictionary
|
||||
function flib_dictionary.new(name, keep_untranslated, initial_contents)
|
||||
if raw[name] then
|
||||
error("Dictionary with the name `" .. name .. "` already exists.")
|
||||
end
|
||||
|
||||
--- @type LocalisedString
|
||||
local initial_string = { "" }
|
||||
--- @class RawDictionary
|
||||
local self = {
|
||||
-- Indices
|
||||
batch_i = 1,
|
||||
dict_i = 1,
|
||||
total = 1,
|
||||
-- Internal
|
||||
ref = initial_string,
|
||||
--- @type LocalisedString
|
||||
strings = { initial_string },
|
||||
-- Meta
|
||||
name = name,
|
||||
}
|
||||
setmetatable(self, { __index = RawDictionary })
|
||||
|
||||
for key, value in pairs(initial_contents or {}) do
|
||||
self:add(key, value)
|
||||
end
|
||||
--- @diagnostic disable-next-line
|
||||
raw[name] = { strings = self.strings, keep_untranslated = keep_untranslated }
|
||||
|
||||
return self
|
||||
end
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function flib_dictionary.init()
|
||||
if not global.__flib then
|
||||
global.__flib = {}
|
||||
end
|
||||
global.__flib.dictionary = {
|
||||
in_process = {},
|
||||
players = {},
|
||||
raw = { _total_strings = 0 },
|
||||
translated = {},
|
||||
}
|
||||
if use_local_storage then
|
||||
raw = { _total_strings = 0 }
|
||||
else
|
||||
raw = global.__flib.dictionary.raw
|
||||
end
|
||||
end
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function flib_dictionary.load()
|
||||
if not use_local_storage and global.__flib and global.__flib.dictionary then
|
||||
raw = global.__flib.dictionary.raw
|
||||
end
|
||||
end
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function flib_dictionary.translate(player)
|
||||
if not player.connected then
|
||||
error("Player must be connected to the game before this function can be called!")
|
||||
end
|
||||
|
||||
local player_data = global.__flib.dictionary.players[player.index]
|
||||
if player_data then
|
||||
return
|
||||
end
|
||||
global.__flib.dictionary.players[player.index] = {
|
||||
player = player,
|
||||
status = "get_language",
|
||||
requested_tick = game.tick,
|
||||
}
|
||||
|
||||
player.request_translation({ "", "FLIB_LOCALE_IDENTIFIER", separator, { "locale-identifier" } })
|
||||
end
|
||||
|
||||
local function request_translation(player_data)
|
||||
local string = raw[player_data.dictionary].strings[player_data.i]
|
||||
|
||||
-- We use `while` instead of `if` here just in case a dictionary doesn't have any strings in it
|
||||
while not string do
|
||||
local next_dictionary = next(raw, player_data.dictionary)
|
||||
if next_dictionary then
|
||||
-- Set the next dictionary and reset index
|
||||
player_data.dictionary = next_dictionary
|
||||
player_data.i = 1
|
||||
string = raw[next_dictionary].strings[1]
|
||||
else
|
||||
-- We're done!
|
||||
player_data.status = "finished"
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
player_data.player.request_translation({
|
||||
"",
|
||||
key_value("FLIB_DICTIONARY_MOD", script.mod_name),
|
||||
key_value("FLIB_DICTIONARY_NAME", player_data.dictionary),
|
||||
key_value("FLIB_DICTIONARY_LANGUAGE", player_data.language),
|
||||
key_value("FLIB_DICTIONARY_STRING_INDEX", player_data.i),
|
||||
string,
|
||||
})
|
||||
|
||||
player_data.requested_tick = game.tick
|
||||
end
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function flib_dictionary.check_skipped()
|
||||
local script_data = global.__flib.dictionary
|
||||
local tick = game.tick
|
||||
for _, player_data in pairs(script_data.players) do
|
||||
-- If it's been longer than the timeout, request the string again
|
||||
-- This is to solve a very rare edge case where translations requested on the same tick that a singleplayer game
|
||||
-- is saved will not be returned when that save is loaded
|
||||
if (player_data.requested_tick or 0) + translation_timeout <= tick then
|
||||
if player_data.status == "get_language" then
|
||||
player_data.player.request_translation({ "", "FLIB_LOCALE_IDENTIFIER", separator, { "locale-identifier" } })
|
||||
end
|
||||
if player_data.status == "translating" then
|
||||
request_translation(player_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- Escape match special characters
|
||||
local function match_literal(s)
|
||||
return string.gsub(s, "%-", "%%-")
|
||||
end
|
||||
|
||||
--- @param dict_lang string
|
||||
local function clean_gui(dict_lang)
|
||||
for _, player in pairs(game.players) do
|
||||
local window = mod_gui.get_frame_flow(player).flib_translation_progress
|
||||
if window then
|
||||
local pane = window.pane
|
||||
local mod_flow = pane[script.mod_name]
|
||||
if mod_flow then
|
||||
local lang_flow = mod_flow[dict_lang]
|
||||
if lang_flow then
|
||||
lang_flow.destroy()
|
||||
end
|
||||
if #mod_flow.children == 1 then
|
||||
mod_flow.destroy()
|
||||
end
|
||||
end
|
||||
if #pane.children == 0 then
|
||||
window.destroy()
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
local dictionary_match_string = key_value("^FLIB_DICTIONARY_MOD", match_literal(script.mod_name))
|
||||
.. key_value("FLIB_DICTIONARY_NAME", "(.-)")
|
||||
.. key_value("FLIB_DICTIONARY_LANGUAGE", "(.-)")
|
||||
.. key_value("FLIB_DICTIONARY_STRING_INDEX", "(%d-)")
|
||||
.. "(.*)$"
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function flib_dictionary.process_translation(event_data)
|
||||
if not event_data.translated then
|
||||
return
|
||||
end
|
||||
local script_data = global.__flib.dictionary
|
||||
if string.find(event_data.result, "FLIB_DICTIONARY_NAME") then
|
||||
local _, _, dict_name, dict_lang, string_index, translation =
|
||||
string.find(event_data.result, dictionary_match_string)
|
||||
|
||||
if dict_name and dict_lang and string_index and translation then
|
||||
local language_data = script_data.in_process[dict_lang]
|
||||
-- In some cases, this can fire before on_configuration_changed
|
||||
if not language_data then
|
||||
return
|
||||
end
|
||||
local dictionary = language_data.dictionaries[dict_name]
|
||||
if not dictionary then
|
||||
return
|
||||
end
|
||||
local dict_data = raw[dict_name]
|
||||
local player_data = script_data.players[event_data.player_index]
|
||||
|
||||
-- If this number does not match, this is a duplicate, so ignore it
|
||||
if tonumber(string_index) == player_data.i then
|
||||
-- Extract current string's translations
|
||||
for str in string.gmatch(translation, "(.-)" .. separator) do
|
||||
local _, _, key, value = string.find(str, "^(.-)" .. inner_separator .. "(.-)$")
|
||||
if key then
|
||||
-- If `keep_untranslated` is true, then use the key as the value if it failed
|
||||
local failed = string.find(value, "FLIB_TRANSLATION_FAILED")
|
||||
if failed and dict_data.keep_untranslated then
|
||||
value = key
|
||||
elseif failed then
|
||||
value = nil
|
||||
end
|
||||
if value then
|
||||
dictionary[key] = value
|
||||
end
|
||||
language_data.translated_i = language_data.translated_i + 1
|
||||
end
|
||||
end
|
||||
|
||||
-- Request next translation
|
||||
player_data.i = player_data.i + 1
|
||||
request_translation(player_data)
|
||||
|
||||
-- GUI
|
||||
for _, player in pairs(game.players) do
|
||||
--- @type LuaGuiElement
|
||||
local flow = mod_gui.get_frame_flow(player)
|
||||
if not flow.flib_translation_progress then
|
||||
gui.add(flow, {
|
||||
type = "frame",
|
||||
name = "flib_translation_progress",
|
||||
style = mod_gui.frame_style,
|
||||
style_mods = { width = 350 },
|
||||
direction = "vertical",
|
||||
{
|
||||
type = "label",
|
||||
style = "frame_title",
|
||||
caption = { "gui.flib-translating-dictionaries" },
|
||||
tooltip = { "gui.flib-translating-dictionaries-description" },
|
||||
},
|
||||
{
|
||||
type = "frame",
|
||||
name = "pane",
|
||||
style = "inside_shallow_frame_with_padding",
|
||||
style_mods = { top_padding = 8 },
|
||||
direction = "vertical",
|
||||
},
|
||||
})
|
||||
end
|
||||
local pane = flow.flib_translation_progress.pane --[[@as LuaGuiElement]]
|
||||
if not pane[script.mod_name] then
|
||||
gui.add(pane, {
|
||||
type = "flow",
|
||||
name = script.mod_name,
|
||||
direction = "vertical",
|
||||
{ type = "label", style = "caption_label", style_mods = { top_margin = 4 }, caption = script.mod_name },
|
||||
})
|
||||
end
|
||||
local mod_flow = pane[script.mod_name] --[[@as LuaGuiElement]]
|
||||
if not mod_flow[dict_lang] then
|
||||
gui.add(mod_flow, {
|
||||
type = "flow",
|
||||
name = dict_lang,
|
||||
style_mods = { vertical_align = "center", horizontal_spacing = 8 },
|
||||
{ type = "label", style = "bold_label", caption = dict_lang },
|
||||
{ type = "progressbar", name = "bar", style_mods = { horizontally_stretchable = true } },
|
||||
{ type = "label", name = "label", style = "bold_label" },
|
||||
})
|
||||
end
|
||||
local progress = language_data.translated_i / raw._total_strings
|
||||
mod_flow[dict_lang].bar.value = progress --[[@as double]]
|
||||
mod_flow[dict_lang].label.caption = tostring(math.ceil(progress * 100)) .. "%"
|
||||
mod_flow[dict_lang].label.tooltip = dict_name
|
||||
.. "\n"
|
||||
.. language_data.translated_i
|
||||
.. " / "
|
||||
.. raw._total_strings
|
||||
end
|
||||
|
||||
if player_data.status == "finished" then
|
||||
-- Clean up translation data
|
||||
script_data.translated[dict_lang] = language_data.dictionaries
|
||||
script_data.in_process[dict_lang] = nil
|
||||
for _, player_index in pairs(language_data.players) do
|
||||
script_data.players[player_index] = nil
|
||||
end
|
||||
|
||||
-- Clean up GUI
|
||||
clean_gui(dict_lang)
|
||||
|
||||
return { dictionaries = language_data.dictionaries, language = dict_lang, players = language_data.players }
|
||||
end
|
||||
end
|
||||
end
|
||||
elseif string.find(event_data.result, "^FLIB_LOCALE_IDENTIFIER") then
|
||||
local _, _, language = string.find(event_data.result, "^FLIB_LOCALE_IDENTIFIER" .. separator .. "(.*)$")
|
||||
if language then
|
||||
local player_data = script_data.players[event_data.player_index]
|
||||
-- Handle duplicates
|
||||
if not player_data or player_data.status ~= "get_language" then
|
||||
return
|
||||
end
|
||||
|
||||
player_data.language = language
|
||||
|
||||
-- Check if this language is already translated or being translated
|
||||
local dictionaries = script_data.translated[language]
|
||||
if dictionaries then
|
||||
script_data.players[event_data.player_index] = nil
|
||||
return { dictionaries = dictionaries, language = language, players = { event_data.player_index } }
|
||||
end
|
||||
local in_process = script_data.in_process[language]
|
||||
if in_process then
|
||||
table.insert(in_process.players, event_data.player_index)
|
||||
player_data.status = "waiting"
|
||||
return
|
||||
end
|
||||
|
||||
-- Set up player data for translating
|
||||
player_data.status = "translating"
|
||||
player_data.dictionary = next(raw, "_total_strings")
|
||||
player_data.i = 1
|
||||
|
||||
-- Add language to in process data
|
||||
script_data.in_process[language] = {
|
||||
dictionaries = table.map(raw, function(_, k)
|
||||
if k ~= "_total_strings" then
|
||||
return {}
|
||||
end
|
||||
end),
|
||||
players = { event_data.player_index },
|
||||
translated_i = 0,
|
||||
}
|
||||
|
||||
-- Start translating
|
||||
request_translation(player_data)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function flib_dictionary.cancel_translation(player_index)
|
||||
local script_data = global.__flib.dictionary
|
||||
local player_data = script_data.players[player_index]
|
||||
if not player_data then
|
||||
return
|
||||
end
|
||||
-- Delete this player's data from global
|
||||
script_data.players[player_index] = nil
|
||||
|
||||
local in_process = script_data.in_process[player_data.language]
|
||||
if not in_process then
|
||||
return
|
||||
end
|
||||
|
||||
-- Remove this player from the players table
|
||||
local i = table.find(in_process.players, player_index)
|
||||
if i then
|
||||
table.remove(in_process.players, i)
|
||||
end
|
||||
|
||||
if player_data.status ~= "translating" then
|
||||
return
|
||||
end
|
||||
|
||||
-- Find the next player in the list with valid data
|
||||
local next_player_data
|
||||
for _, player_index in pairs(in_process.players) do
|
||||
local player_data = script_data.players[player_index]
|
||||
if player_data then
|
||||
next_player_data = player_data
|
||||
break
|
||||
end
|
||||
end
|
||||
-- If there are no more valid players
|
||||
if not next_player_data then
|
||||
-- Completely cancel the translation
|
||||
script_data.in_process[player_data.language] = nil
|
||||
clean_gui(player_data.language)
|
||||
return
|
||||
end
|
||||
--Update player info
|
||||
next_player_data.status = "translating"
|
||||
next_player_data.dictionary = player_data.dictionary
|
||||
next_player_data.i = player_data.i
|
||||
-- Resume translating with the new player
|
||||
request_translation(next_player_data)
|
||||
end
|
||||
|
||||
--- @deprecated Use 'dictionary-lite' instead.
|
||||
function flib_dictionary.set_use_local_storage(value)
|
||||
use_local_storage = value
|
||||
end
|
||||
|
||||
return flib_dictionary
|
||||
Reference in New Issue
Block a user