diff --git a/control.lua b/control.lua index e2a90da..bb68e3a 100644 --- a/control.lua +++ b/control.lua @@ -4,3 +4,4 @@ require "src.NetworkChest" require "src.NetworkSensor" require "src.NetworkViewUi" require "src.NetworkViewUi_test" +require "src.NetworkTankGui" diff --git a/data.lua b/data.lua index c646a56..39cbf57 100644 --- a/data.lua +++ b/data.lua @@ -237,7 +237,7 @@ function M.add_network_tank() }, se_allow_in_space = true, allow_copy_paste = true, - additional_pastable_entities = { "network-tank" }, + additional_pastable_entities = { name }, max_health = 200, } diff --git a/src/GlobalState.lua b/src/GlobalState.lua index f6f522f..6dbbd52 100644 --- a/src/GlobalState.lua +++ b/src/GlobalState.lua @@ -970,8 +970,6 @@ function M.update_queue_lists(update_entity) -- nil means entity is invalid. if pri_adj ~= nil then M.queue_insert(unit_number, old_pri + pri_adj) - else - clog("Dropped: G unum %s", unit_number) end end end diff --git a/src/GuiManager.lua b/src/GuiManager.lua new file mode 100644 index 0000000..5af0c30 --- /dev/null +++ b/src/GuiManager.lua @@ -0,0 +1,182 @@ +--[[ +Some helpers for managing the UI persistant data. + +At the top of the UI file, do something like: + M.mgr = GuiManager.new("my_unique_tag") +]] +local GlobalState = require "src.GlobalState" +local clog = require("src.log_console").log + +local GuiManager = {} +function GuiManager.new(name) + local self = { name=name } + return setmetatable(self, { __index = GuiManager }) +end + +function GuiManager:get(player_index) + return GlobalState.get_ui_state(player_index)[self.name] +end + +function GuiManager:set(player_index, value) + GlobalState.get_ui_state(player_index)[self.name] = value +end + +function GuiManager:destroy(player_index) + local ui = GlobalState.get_ui_state(player_index) + local inst = ui[self.name] + if inst ~= nil then + -- break the link to prevent future events + ui[self.name] = nil + + -- call destructor on any child classes + if type(inst.children) == 'table' then + for _, ch in pairs(inst.children) do + if type(ch.destroy) == "function" then + ch.destroy(ch) + end + end + end + + if inst.elems ~= nil and inst.elems.main_window ~= nil then + -- remove player focus + local player = inst.player or game.get_player(player_index) + if player ~= nil and player.opened == inst.elems.main_window then + player.opened = nil + end + + -- destroy the UI + inst.elems.main_window.destroy() + end + end +end + +-- returns a function that can be attached to an event +function GuiManager:wrap(func) + -- callback takes an event, calls get() and passes that to the function + return function (event) + local inst = self:get(event.player_index) + --clog("wrap event %s", serpent.line(inst)) + if inst ~= nil then + func(inst, event) + end + end +end + +--[[ +Creates a new top-level window and returns the table of elements. +This sets the window as the current + @player is the player that gets the GUI + @title is the name to put in the title bar + @opts selects the extra buttons to enable + 'window_name' = unqiue name for the window (uses title if omitted) + 'refresh_button' = unique name for the refresh button (not created if omitted) + 'close_button' = unique name for the close button (not created if omitted) + 'pin_button' = unique name for the pin button (not created if omitted) + + retval.elems.body is set to a vertical flow where the GUI elements should be added. +]] +function GuiManager:create_window(player, title, opts) + local elems = {} + + -- create the main window + local main_window = player.gui.screen.add({ + type = "frame", + name = opts.window_name or title, + style = "inset_frame_container_frame", + }) + main_window.auto_center = true + main_window.style.horizontally_stretchable = true + main_window.style.vertically_stretchable = true + elems.main_window = main_window + + -- create a vertical flow to cover the entire window body + local vert_flow = main_window.add({ + type = "flow", + direction = "vertical", + }) + vert_flow.style.horizontally_stretchable = true + vert_flow.style.vertically_stretchable = true + + -- add the header/toolbar flow + local title_flow = vert_flow.add({ + type = "flow", + direction = "horizontal", + }) + title_flow.drag_target = main_window + elems.title_flow = title_flow + + -- add the window title + title_flow.add { + type = "label", + caption = title, + style = "frame_title", + ignored_by_interaction = true, + } + + -- add the drag space + local header_drag = title_flow.add { + type = "empty-widget", + style = "draggable_space_header", + ignored_by_interaction = true, + } + header_drag.style.horizontally_stretchable = true + header_drag.style.vertically_stretchable = true + header_drag.style.height = 24 + + local name = opts.refresh_button + if name ~= nil then + elems.refresh_button = title_flow.add { + name = name, + type = "sprite-button", + sprite = "utility/refresh", + style = "frame_action_button", + tooltip = { "gui.refresh" }, + } + end + + name = opts.close_button + if name ~= nil then + elems.close_button = title_flow.add { + name = name, + type = "sprite-button", + sprite = "utility/close_white", + hovered_sprite = "utility/close_black", + clicked_sprite = "utility/close_black", + style = "close_button", + } + end + + name = opts.pin_button + if name ~= nil then + elems.pin_button = title_flow.add { + name = name, + type = "sprite-button", + sprite = "flib_pin_white", + hovered_sprite = "flib_pin_black", + clicked_sprite = "flib_pin_black", + style = "frame_action_button", + } + end + + -- create the window body flow + elems.body = vert_flow.add({ + type = "flow", + direction = "vertical", + }) + + -- give focus to the window (make optional?) + player.opened = main_window + + -- start the UI data + local inst = { + elems = elems, + player = player, + -- children = nil, + } + + self:set(player.index, inst) + + return inst +end + +return GuiManager diff --git a/src/NetworkChest.lua b/src/NetworkChest.lua index f33d686..eddc398 100644 --- a/src/NetworkChest.lua +++ b/src/NetworkChest.lua @@ -3,7 +3,6 @@ local NetworkChestGui = require "src.NetworkChestGui" local UiHandlers = require "src.UiHandlers" local NetworkViewUi = require "src.NetworkViewUi" local UiConstants = require "src.UiConstants" -local NetworkTankGui = require "src.NetworkTankGui" local Event = require('__stdlib__/stdlib/event/event') local util = require("util") -- from core/lualib local clog = require("src.log_console").log @@ -40,7 +39,7 @@ local function generic_create_handler(event) M.on_create(event, entity) elseif entity.name == "network-chest-requester" then M.on_create(event, entity) - elseif entity.name == "network-tank" then + elseif constants.NETWORK_TANK_NAMES[entity.name] ~= nil then local config = nil if event.tags ~= nil then local config_tag = event.tags.config @@ -78,7 +77,7 @@ function M.on_entity_cloned(event) if source_info ~= nil and dest_info ~= nil then dest_info.requests = source_info.requests end - elseif name == "network-tank" then + elseif constants.NETWORK_TANK_NAMES[name] ~= nil then GlobalState.register_tank_entity(event.source) GlobalState.register_tank_entity(event.destination) GlobalState.copy_tank_config( @@ -124,7 +123,8 @@ function M.generic_destroy_handler(event, opts) global.mod.network_chest_gui.frame.destroy() global.mod.network_chest_gui = nil end - elseif entity.name == "network-tank" then + + elseif constants.NETWORK_TANK_NAMES[entity.name] ~= nil then GlobalState.put_tank_contents_in_network(entity) if not opts.do_not_delete_entity then GlobalState.delete_tank_entity(unit_number) @@ -162,7 +162,7 @@ end function M.on_marked_for_deconstruction(event) if event.entity.name == "network-chest" then GlobalState.put_chest_contents_in_network(event.entity) - elseif event.entity.name == "network-tank" then + elseif constants.NETWORK_TANK_NAMES[event.entity.name] ~= nil then GlobalState.put_tank_contents_in_network(event.entity) end end @@ -248,9 +248,9 @@ function M.on_player_setup_blueprint(event) ) end end - elseif entity.name == "network-tank" then + elseif constants.NETWORK_TANK_NAMES[entity.name] ~= nil then local real_entity = event.surface.find_entity( - "network-tank", + entity.name, entity.position ) if real_entity ~= nil then @@ -323,8 +323,8 @@ function M.on_entity_settings_pasted(event) end end - elseif dest.name == "network-tank" then - if source.name == "network-tank" then + elseif constants.NETWORK_TANK_NAMES[dest.name] ~= nil then + if source.name == dest.name then GlobalState.copy_tank_config(source.unit_number, dest.unit_number) end @@ -1129,8 +1129,7 @@ local function update_entity(unit_number, priority) return retval end - -- unknown/invalid unit_number - clog("Dropped: unknown unum %s", unit_number) + -- unknown/invalid unit_number (probably already removed) return nil end @@ -1345,16 +1344,6 @@ function M.on_gui_opened(event) end NetworkChestGui.on_gui_opened(player, entity) - elseif event.gui_type == defines.gui_type.entity and event.entity.name == "network-tank" then - local entity = event.entity - assert(GlobalState.get_tank_info(entity.unit_number) ~= nil) - - local player = game.get_player(event.player_index) - if player == nil then - return - end - - NetworkTankGui.on_gui_opened(player, entity) end end @@ -1362,8 +1351,6 @@ function M.on_gui_closed(event) local frame = event.element if frame ~= nil and frame.name == UiConstants.NV_FRAME then NetworkViewUi.on_gui_closed(event) - elseif frame ~= nil and frame.name == UiConstants.NT_MAIN_FRAME then - NetworkTankGui.on_gui_closed(event) elseif frame ~= nil and (frame.name == UiConstants.MAIN_FRAME_NAME or frame.name == UiConstants.MODAL_FRAME_NAME) then NetworkChestGui.on_gui_closed(event) end diff --git a/src/NetworkTankGui.lua b/src/NetworkTankGui.lua index 17580a8..ea19a4e 100644 --- a/src/NetworkTankGui.lua +++ b/src/NetworkTankGui.lua @@ -1,14 +1,30 @@ local GlobalState = require "src.GlobalState" local UiConstants = require "src.UiConstants" local Constants = require "src.constants" +local Event = require('__stdlib__/stdlib/event/event') +local Gui = require('__stdlib__/stdlib/event/gui') +local GuiManager = require('src.GuiManager') +local clog = require("src.log_console").log +-- this is the fake metatable - all functions take an instance created via +-- network_tank_on_gui_opened() as the first parameter. local M = {} -function M.on_gui_opened(player, entity) - local ui = GlobalState.get_ui_state(player.index) +local my_mgr = GuiManager.new("network_tank") - -- delete previous frames if exist - M.reset(player, ui) +-- Destroy the GUI for a player +-- this can be a generic function +local function gui_destroy(player_index) + my_mgr:destroy(player_index) +end + +--[[ +This is called when the system opens a diaglog for the tank. +It replaces the dialog with one of our own. +]] +local function network_tank_on_gui_opened(player, entity) + -- need to start clean each time; there can be only one open at a time + gui_destroy(player.index) local tank_info = GlobalState.get_tank_info(entity.unit_number) if tank_info == nil then @@ -29,165 +45,160 @@ function M.on_gui_opened(player, entity) default_temp = tank_info.config.temperature end - local width = 600 - local height = 500 + local self = my_mgr:create_window(player, entity.localised_name, { + window_name = UiConstants.NT_MAIN_FRAME, + close_button = UiConstants.NT_CLOSE_BTN, + }) + local elems = self.elems + + local frame = elems.body + + local frame_flow = frame.add({ type = "flow", direction = "horizontal" }) + local inner_frame = frame_flow.add({ type = "frame", style = "inside_shallow_frame_with_padding" }) - local frame = player.gui.screen.add({ + local side_flow = inner_frame.add({ type = "flow", direction = "horizontal" }) + + local preview_frame = side_flow.add({ type = "frame", - caption = "Configure Network Tank", - name = UiConstants.NT_MAIN_FRAME, + style = "deep_frame_in_shallow_frame", + }) + local entity_preview = preview_frame.add({ + type = "entity-preview", + style = "wide_entity_button", }) - player.opened = frame - frame.style.size = { width, height } - frame.auto_center = true + entity_preview.style.horizontally_stretchable = false + entity_preview.style.minimal_width = 100 + entity_preview.style.natural_height = 100 + entity_preview.style.height = 100 + entity_preview.entity = entity - local main_flow = frame.add({ type = "flow", direction = "vertical" }) + local main_flow = side_flow.add({ type = "flow", direction = "vertical" }) - local type_flow = main_flow.add({ type = "flow", direction = "horizontal" }) - type_flow.add({ type = "label", caption = "Type:" }) - local choose_take_btn = type_flow.add({ + local auto_flow = main_flow.add({ type = "flow", direction = "horizontal" }) + auto_flow.add({ + name = UiConstants.NT_BTN_AUTO, + type = "button", + caption = "AUTO", + }) + auto_flow.style.horizontally_stretchable = true + auto_flow.style.horizontal_align = "center" + auto_flow.style.vertical_align = "center" + + elems.type_flow = main_flow.add({ type = "flow", direction = "horizontal" }) + + elems.type_flow.add({ type = "label", caption = "Type:" }) + elems.choose_take_btn = elems.type_flow.add({ + name = UiConstants.NT_CHOOSE_TAKE_BTN, type = "radiobutton", state = default_is_take, - tags = { event = UiConstants.NT_CHOOSE_TAKE_BTN }, }) - type_flow.add({ type = "label", caption = "Request" }) - local choose_give_btn = type_flow.add({ + elems.type_flow.add({ type = "label", caption = "Request" }) + + elems.choose_give_btn = elems.type_flow.add({ + name = UiConstants.NT_CHOOSE_GIVE_BTN, type = "radiobutton", state = not default_is_take, - tags = { event = UiConstants.NT_CHOOSE_GIVE_BTN }, }) - type_flow.add({ type = "label", caption = "Provide" }) + elems.type_flow.add({ type = "label", caption = "Provide" }) + + elems.request_flow = main_flow.add({ type = "flow", direction = "vertical" }) - local fluid_flow = main_flow.add({ type = "flow", direction = "horizontal" }) - fluid_flow.add({ type = "label", caption = "Fluid:" }) - local fluid_picker = fluid_flow.add({ + elems.fluid_flow = elems.request_flow.add({ type = "flow", direction = "horizontal" }) + elems.fluid_flow.add({ type = "label", caption = "Fluid:" }) + elems.fluid_picker = elems.fluid_flow.add({ + name = UiConstants.NT_FLUID_PICKER, type = "choose-elem-button", elem_type = "fluid", elem_value = default_fluid, - tags = { event = UiConstants.NT_FLUID_PICKER }, }) - fluid_picker.elem_value = default_fluid + elems.fluid_picker.elem_value = default_fluid - local temp_flow = main_flow.add({ type = "flow", direction = "horizontal" }) - temp_flow.add({ type = "label", caption = "Temperature:" }) - local temperature_input = temp_flow.add({ + elems.temp_flow = elems.request_flow.add({ type = "flow", direction = "horizontal" }) + elems.temp_flow.add({ type = "label", caption = "Temperature:" }) + elems.temperature_input = elems.temp_flow.add({ + name = UiConstants.NT_TEMP_FIELD, type = "textfield", numeric = true, allow_decimal = false, allow_negative = true, - tags = { event = UiConstants.NT_TEMP_FIELD }, }) if default_temp ~= nil then - temperature_input.text = string.format("%s", default_temp) + elems.temperature_input.text = string.format("%s", default_temp) end - temperature_input.style.width = 100 + elems.temperature_input.style.width = 100 - local buffer_flow = main_flow.add({ type = "flow", direction = "horizontal" }) - buffer_flow.add({ type = "label", caption = "Buffer:" }) - local buffer_size_input = buffer_flow.add({ + elems.buffer_flow = elems.request_flow.add({ type = "flow", direction = "horizontal" }) + elems.buffer_flow.add({ type = "label", caption = "Buffer:" }) + elems.buffer_size_input = elems.buffer_flow.add({ + name = UiConstants.NT_BUFFER_FIELD, type = "textfield", numeric = true, allow_decimal = false, allow_negative = false, - tags = { event = UiConstants.NT_BUFFER_FIELD }, }) if default_buffer ~= nil then - buffer_size_input.text = string.format("%s", default_buffer) + elems.buffer_size_input.text = string.format("%s", default_buffer) end - buffer_size_input.style.width = 100 + elems.buffer_size_input.style.width = 100 + -- this is always shown local limit_flow = main_flow.add({ type = "flow", direction = "horizontal" }) limit_flow.add({ type = "label", caption = "Limit:" }) - local limit_input = limit_flow.add({ + elems.limit_input = limit_flow.add({ + name = UiConstants.NT_LIMIT_FIELD, type = "textfield", numeric = true, allow_decimal = false, allow_negative = false, - tags = { event = UiConstants.NT_LIMIT_FIELD }, }) if default_limit ~= nil then - limit_input.text = string.format("%s", default_limit) + elems.limit_input.text = string.format("%s", default_limit) end - limit_input.style.width = 100 + elems.limit_input.style.width = 100 local save_cancel_flow = main_flow.add({ type = "flow", direction = "horizontal", }) save_cancel_flow.add({ + name = UiConstants.NT_CONFIRM_EVENT, type = "button", caption = "Save", - tags = { - event = UiConstants.NT_CONFIRM_EVENT, - }, }) save_cancel_flow.add({ + name = UiConstants.NT_CANCEL_EVENT, type = "button", caption = "Cancel", - tags = { - event = UiConstants.NT_CANCEL_EVENT, - }, }) - ui.network_tank = { - frame = frame, - unit_number = entity.unit_number, - choose_take_btn = choose_take_btn, - choose_give_btn = choose_give_btn, - buffer_size_input = buffer_size_input, - temperature_input = temperature_input, - limit_input = limit_input, - type = default_is_take and "take" or "give", - fluid = default_fluid, - buffer = default_buffer, - limit = default_limit, - temperature = default_temp, - fluid_flow = fluid_flow, - temp_flow = temp_flow, - buffer_flow = buffer_flow, - } - M.update_input_visibility(player.index) -end - -function M.on_gui_closed(event) - local ui = GlobalState.get_ui_state(event.player_index) - - local player = game.get_player(event.player_index) - if player == nil then - return - end - - M.reset(player, ui) -end + -- NOTE: we could store entity, but then we'd need to check valid before accessing unit_number + self.unit_number = entity.unit_number + self.type = default_is_take and "take" or "give" + self.fluid = default_fluid + self.buffer = default_buffer + self.limit = default_limit + self.temperature = default_temp -function M.reset(player, ui) - M.destroy_frame(player, UiConstants.NT_MAIN_FRAME) - ui.network_tank = nil + M.update_input_visibility(self) end -function M.destroy_frame(player, frame_name) - local frame = player.gui.screen[frame_name] - if frame ~= nil then - frame.destroy() - end +function M.reset(self) + gui_destroy(self.player.index) end -function M.update_input_visibility(player_index) - local nt_ui = GlobalState.get_ui_state(player_index).network_tank - local visible = nt_ui.type == "take" - nt_ui.fluid_flow.visible = visible - nt_ui.temp_flow.visible = visible - nt_ui.buffer_flow.visible = visible +function M.update_input_visibility(self) + local visible = self.type == "take" + self.elems.request_flow.visible = visible + --self.elems.fluid_flow.visible = visible + --self.elems.temp_flow.visible = visible + --self.elems.buffer_flow.visible = visible end -function M.set_default_buffer_and_limit(player_index) - local ui = GlobalState.get_ui_state(player_index) - local nt_ui = ui.network_tank - - local fluid = nt_ui.fluid - local type = nt_ui.type +function M.set_default_buffer_and_limit(self) + local fluid = self.fluid + local type = self.type if type == "give" then - M.set_limit(Constants.MAX_TANK_SIZE, nt_ui) + M.set_limit(self, Constants.MAX_TANK_SIZE) elseif fluid ~= nil and type ~= nil then local limit if type == "take" then @@ -195,36 +206,33 @@ function M.set_default_buffer_and_limit(player_index) else limit = Constants.MAX_TANK_SIZE end - M.set_temperature( - game.fluid_prototypes[fluid].default_temperature, - nt_ui - ) - M.set_buffer(Constants.MAX_TANK_SIZE, nt_ui) - M.set_limit(limit, nt_ui) + M.set_temperature(self, game.fluid_prototypes[fluid].default_temperature) + M.set_buffer(self, Constants.MAX_TANK_SIZE) + M.set_limit(self, limit) end end -function M.set_temperature(temperature, nt_ui) - nt_ui.temperature = temperature - nt_ui.temperature_input.text = string.format("%d", temperature) +function M.set_temperature(self, temperature) + self.temperature = temperature + self.elems.temperature_input.text = string.format("%d", temperature) end -function M.set_buffer(buffer, nt_ui) - nt_ui.buffer = buffer - nt_ui.buffer_size_input.text = string.format("%d", buffer) +function M.set_buffer(self, buffer) + self.buffer = buffer + self.elems.buffer_size_input.text = string.format("%d", buffer) end -function M.set_limit(limit, nt_ui) - nt_ui.limit = limit - nt_ui.limit_input.text = string.format("%d", limit) +function M.set_limit(self, limit) + self.limit = limit + self.elems.limit_input.text = string.format("%d", limit) end -local function get_config_from_network_tank_ui(nt_ui) - local type = nt_ui.type - local fluid = nt_ui.fluid - local buffer = nt_ui.buffer - local limit = nt_ui.limit - local temperature = nt_ui.temperature +function M.get_config_from_network_tank_ui(self) + local type = self.type + local fluid = self.fluid + local buffer = self.buffer + local limit = self.limit + local temperature = self.temperature if type == "take" then if type == nil or fluid == nil or temperature == nil or buffer == nil or limit == nil then @@ -262,23 +270,282 @@ local function get_config_from_network_tank_ui(nt_ui) end end -function M.try_to_confirm(player_index) - local ui = GlobalState.get_ui_state(player_index) - local nt_ui = ui.network_tank - - local config = get_config_from_network_tank_ui(nt_ui) +function M.try_to_confirm(self) + local config = M.get_config_from_network_tank_ui(self) if config == nil then return end - local info = GlobalState.get_tank_info(nt_ui.unit_number) + -- may have been removed since the dialog was opened + local info = GlobalState.get_tank_info(self.unit_number) if info == nil then return end info.config = config - M.reset(game.get_player(player_index), ui) + M.reset(self) +end + +------------------------------------------------------------------------------- +-- REVISIT: move the fluid search to a separate file? + +--[[ +Check the fluidbox on the entity. We start with a network tank, so there should only be 1 fluidbox. +Search connected fluidboxes to find all filters. +That gives what the system should contain. +]] +local function search_fluid_system(entity, sysid, visited) + if entity == nil or not entity.valid then + return + end + local unum = entity.unit_number + local fluidbox = entity.fluidbox + -- visited contains [unit_number]=true, ['locked'= { names }, 'min_temp'=X, max_temp=X}] + visited = visited or { filter={} } + if unum == nil or fluidbox == nil or visited[unum] ~= nil then + return + end + visited[unum] = true + + -- special case for generators: they allow steam up to 1000 C, but it is a waste, so limit to the real max + local max_temp + if entity.type == 'generator' then + max_temp = entity.prototype.maximum_temperature + end + + -- scan, locking onto the first fluid_system_id. + --clog('fluid visiting [%s] name=%s type=%s #fluidbox=%s', unum, entity.name, entity.type, #fluidbox) + for idx = 1, #fluidbox do + local fluid = fluidbox[idx] + local id = fluidbox.get_fluid_system_id(idx) + if id ~= nil and (sysid == nil or id == sysid) then + sysid = id + local conn = fluidbox.get_connections(idx) + local filt = fluidbox.get_filter(idx) + local pipes = fluidbox.get_pipe_connections(idx) + --[[ + clog(" [%s] id=%s capacity=%s fluid=%s filt=%s lock=%s #conn=%s #pipes=%s", idx, + id, + fluidbox.get_capacity(idx), + serpent.line(fluid), + serpent.line(filt), + serpent.line(fluidbox.get_locked_fluid(idx)), + #conn, + #pipes) + ]] + if fluid ~= nil then + local tt = visited.contents[fluid.name] + if tt == nil then + tt = {} + visited.contents[fluid.name] = tt + end + tt[fluid.temperature] = (tt[fluid.temperature] or 0) + fluid.amount + end + + -- only care about a fluidbox with pipe connections + if #pipes > 0 then + -- only update the flow_direction if there is a filter + if filt ~= nil then + local f = visited.filter + local old = f[filt.name] + if old == nil then + old = { minimum_temperature=filt.minimum_temperature, maximum_temperature=filt.maximum_temperature } + f[filt.name] = old + else + old.minimum_temperature = math.max(old.minimum_temperature, filt.minimum_temperature) + old.maximum_temperature = math.min(old.maximum_temperature, filt.maximum_temperature) + end + -- correct the max steam temp for generators + if max_temp ~= nil and max_temp < old.maximum_temperature then + old.maximum_temperature = max_temp + end + for _, pip in ipairs(pipes) do + visited.flows[pip.flow_direction] = true + end + end + + for ci = 1, #conn do + search_fluid_system(conn[ci].owner, sysid, visited) + end + end + end + end +end + +--[[ +Autoconfigure a network tank. +]] +function M.auto_config(self, event) + -- grab the info and do some sanity checking + local info = GlobalState.get_tank_info(self.unit_number) + if info == nil then + return + end + local entity = info.entity + if not entity.valid then + return + end + local fluidbox = entity.fluidbox + if fluidbox == nil or #fluidbox ~= 1 then + return + end + + --clog("[%s] auto config %s @ %s", self.unit_number, entity.name, serpent.line(entity.position)) + + local sysid = fluidbox.get_fluid_system_id(1) + local visited = { filter={}, flows={}, contents={} } + + search_fluid_system(entity, sysid, visited) + --clog(" ==> filt=%s flow=%s cont=%s", serpent.line(visited.filter), serpent.line(visited.flows), serpent.line(visited.contents)) + + -- if there are no filters, then we can't auto-config + if next(visited.filter) == nil then + clog("network-tank: AUTO: Connect to a fluid provider or consumer") + return + end + + -- if there are multitple filters, then we can't auto-config + if table_size(visited.filter) ~= 1 then + clog("network-tank: AUTO: Too many fluids: %s", serpent.line(visited.filter)) + return + end + + -- if there are multiple flow types, then we can't auto-config + if table_size(visited.flows) ~= 1 then + clog("network-tank: AUTO: Too many connections.") + return + end + + if visited.flows.output == true then + M.set_mode_give(self) + else + -- single input or input-output, find the best fluid temperature + local name, filt = next(visited.filter) + self.fluid = name + self.elems.fluid_picker.elem_value = name + M.set_mode_take(self) + + -- pick a temperature, stick with the default if none available + local temps = GlobalState.get_fluids()[name] + if temps ~= nil then + local max_temp + for temp, _ in pairs(temps) do + if temp >= filt.minimum_temperature and temp <= filt.maximum_temperature then + if max_temp == nil or temp > max_temp then + max_temp = temp + end + end + end + if max_temp ~= nil then + M.set_temperature(self, max_temp) + end + end + end end -return M +function M.set_mode_give(self) + self.type = "give" + self.elems.choose_take_btn.state = false + M.set_default_buffer_and_limit(self) + M.update_input_visibility(self) +end + +function M.set_mode_take(self) + self.type = "take" + self.elems.choose_give_btn.state = false + M.set_default_buffer_and_limit(self) + M.update_input_visibility(self) +end + +------------------------------------------------------------------------------- +-- GUI: event functions + +Gui.on_click(UiConstants.NT_CHOOSE_TAKE_BTN, my_mgr:wrap(function (self, event) + M.set_mode_take(self) +end)) + +Gui.on_click(UiConstants.NT_CHOOSE_GIVE_BTN, my_mgr:wrap(function (self, event) + M.set_mode_give(self) +end)) + +Gui.on_elem_changed(UiConstants.NT_FLUID_PICKER, my_mgr:wrap(function (self, event) + local fluid = event.element.elem_value + self.fluid = fluid + M.set_default_buffer_and_limit(self) +end)) + +Gui.on_confirmed(UiConstants.NT_TEMP_FIELD, my_mgr:wrap(function (self, event) + M.try_to_confirm(self) +end)) + +Gui.on_confirmed(UiConstants.NT_BUFFER_FIELD, my_mgr:wrap(function (self, event) + M.try_to_confirm(self) +end)) + +Gui.on_confirmed(UiConstants.NT_LIMIT_FIELD, my_mgr:wrap(function (self, event) + M.try_to_confirm(self) +end)) + +Gui.on_text_changed(UiConstants.NT_TEMP_FIELD, my_mgr:wrap(function (self, event) + self.temperature = tonumber(event.element.text) +end)) + +Gui.on_text_changed(UiConstants.NT_BUFFER_FIELD, my_mgr:wrap(function (self, event) + self.buffer = tonumber(event.element.text) +end)) + +Gui.on_text_changed(UiConstants.NT_LIMIT_FIELD, my_mgr:wrap(function (self, event) + self.limit = tonumber(event.element.text) +end)) + +Gui.on_click(UiConstants.NT_CONFIRM_EVENT, my_mgr:wrap(function (self, event) + M.try_to_confirm(self) +end)) + +Gui.on_click(UiConstants.NT_CANCEL_EVENT, my_mgr:wrap(function (self, event) + gui_destroy(event.player_index) +end)) + +Gui.on_click(UiConstants.NT_CLOSE_BTN, my_mgr:wrap(function (self, event) + M.try_to_confirm(self) +end)) + +Gui.on_click(UiConstants.NT_BTN_AUTO, my_mgr:wrap(function (self, event) + M.auto_config(self, event) +end)) + +------------------------------------------------------------------------------- + +-- when the player left-clicks on an entity, the default dialog is created and then +-- this is called. This replaces the default dialog. +Event.on_event( + defines.events.on_gui_opened, + function (event) + if event.gui_type == defines.gui_type.entity then + local val = Constants.NETWORK_TANK_NAMES[event.entity.name] + if val ~= nil and val ~= false then + local entity = event.entity + assert(GlobalState.get_tank_info(entity.unit_number) ~= nil) + local player = game.get_player(event.player_index) + if player == nil then + return + end + network_tank_on_gui_opened(player, entity) + end + end + end +) + +Event.on_event( + defines.events.on_gui_closed, + my_mgr:wrap(function (self, event) + local frame = event.element + if frame ~= nil and frame.name == UiConstants.NT_MAIN_FRAME then + M.reset(self) + end + end) +) + +-- dummy return -- nothing is exported anymore +return {} diff --git a/src/UiConstants.lua b/src/UiConstants.lua index 7b4b97b..c6d608f 100644 --- a/src/UiConstants.lua +++ b/src/UiConstants.lua @@ -66,6 +66,7 @@ M.NETLIMIT_SELECT_FLUID = "3efefed250417d87ad194b92db66cddf" M.NETLIMIT_SAVE = "ddddfed250417d87ad194b92db66cdda" M.NT_MAIN_FRAME = "60748f39885806b9020db621a7bb065c" +M.NT_CLOSE_BTN = "60748f39885806b9020db621a7bb065d" M.NT_CHOOSE_TAKE_BTN = "42f33f2eea8bb3623d85f3d689cfd6e9" M.NT_CHOOSE_GIVE_BTN = "e915d74177491a57b62ff2a4244105ca" M.NT_FLUID_PICKER = "2db585fdec1823060520b19fb0e74b97" @@ -74,5 +75,6 @@ M.NT_BUFFER_FIELD = "b48fcd26547d2331bc0a1f3248c1525c" M.NT_LIMIT_FIELD = "2e7f32029527b499f36dc4181dce5cfd" M.NT_CONFIRM_EVENT = "2aeb6458481cb17d443e0743858eec78" M.NT_CANCEL_EVENT = "ccd188f96dbd5d80ead57ac11f2a4315" +M.NT_BTN_AUTO = "item_network.tank.btn_auto" return M diff --git a/src/UiHandlers.lua b/src/UiHandlers.lua index de5a5db..55ca86f 100644 --- a/src/UiHandlers.lua +++ b/src/UiHandlers.lua @@ -1,10 +1,7 @@ local UiConstants = require "src.UiConstants" local NetworkChestGui = require "src.NetworkChestGui" local GlobalState = require "src.GlobalState" -local NetworkTankGui = require "src.NetworkTankGui" -local NetworkViewUi = require "src.NetworkViewUi" -local NetworkViewUi_test = require "src.NetworkViewUi_test" -local log = require("src.log_console").log +local clog = require("src.log_console").log local M = {} @@ -158,6 +155,7 @@ M.event_handlers = { NetworkChestGui.open_modal(player, "edit", request_id) end, }, + --[[ { name = UiConstants.NT_CHOOSE_TAKE_BTN, event = "on_gui_click", @@ -235,6 +233,13 @@ M.event_handlers = { nt_ui.limit = tonumber(element.text) end, }, + { + name = UiConstants.NT_BTN_AUTO, + event = "on_gui_click", + handler = function(event, element) + NetworkTankGui.auto_config(event.player_index) + end, + }, { name = UiConstants.NT_CONFIRM_EVENT, event = "on_gui_click", @@ -251,6 +256,7 @@ M.event_handlers = { NetworkTankGui.reset(player, ui) end, }, + ]] } M.handler_map = {} diff --git a/src/constants.lua b/src/constants.lua index 805f5af..884c538 100644 --- a/src/constants.lua +++ b/src/constants.lua @@ -15,4 +15,10 @@ M.QUEUE_TICKS = 10 -- should be like 10 -- has to be small enough to be in the constant combinator M.UNLIMITED = 2000000000 -- "2G" +M.NETWORK_TANK_NAMES = { + ["network-tank"] = "no", -- not created by network-tanks.lua + -- ["network-tank-requester"] = true, -- from network to pipes + -- ["network-tank-provider"] = false, -- from pipes to network + } + return M