diff --git a/cybersyn/changelog.txt b/cybersyn/changelog.txt index 37bbf6a..01df86f 100644 --- a/cybersyn/changelog.txt +++ b/cybersyn/changelog.txt @@ -3,3 +3,9 @@ Version: 0.1.0 Date: 2022-11-04 Features: - Pre-Alpha release +--------------------------------------------------------------------------------------------------- +Version: 0.2.0 +Date: 2022-11-04 + Features: + - Removed provide-threshold + - Added ability to specify station type on a cybernetic combinator diff --git a/cybersyn/control.lua b/cybersyn/control.lua index de63f60..a1bce50 100644 --- a/cybersyn/control.lua +++ b/cybersyn/control.lua @@ -2,6 +2,7 @@ require("scripts.constants") require("scripts.global") +require("scripts.combinator") require("scripts.central-planning") require("scripts.layout") require("scripts.gui") diff --git a/cybersyn/data.lua b/cybersyn/data.lua index 7b95676..5d2a820 100644 --- a/cybersyn/data.lua +++ b/cybersyn/data.lua @@ -16,7 +16,6 @@ data:extend({ cybersyn_tech, subgroup_signal, priority_signal, - p_threshold_signal, r_threshold_signal, locked_slots_signal, missing_train_icon, diff --git a/cybersyn/graphics/icons/provide-threshold.png b/cybersyn/graphics/icons/provide-threshold.png deleted file mode 100644 index d5d937a..0000000 Binary files a/cybersyn/graphics/icons/provide-threshold.png and /dev/null differ diff --git a/cybersyn/locale/en/base.cfg b/cybersyn/locale/en/base.cfg index 4a39218..4507c8f 100644 --- a/cybersyn/locale/en/base.cfg +++ b/cybersyn/locale/en/base.cfg @@ -1,20 +1,18 @@ [mod-setting-name] cybersyn-ticks-per-second=Dispatcher updates per second cybersyn-request-threshold=Default requester threshold -cybersyn-provide-threshold=Default provider threshold cybersyn-network-flag=Default network flags [mod-setting-description] cybersyn-ticks-per-second=How many times per second the dispather should check for new deliveries. Deliveries are made one at a time per update. This value will be rounded up to a divisor of 60. cybersyn-request-threshold=The default request threshold when a request threshold signal is not given to a station. Huge values will prevent stations from taking requests from the network unless an explicit threshold is set. -cybersyn-provide-threshold=The default provide threshold when a provide threshold signal is not given to a station. Huge values will prevent stations from providing to the network unless an explicit threshold is set. cybersyn-network-flag=The default set of networks a station will service when no network signal is given to a station. This integer is interpretted bit-wise to give 32 possible network flags to choose from. [item-name] cybersyn-combinator=Cybernetic combinator [item-description] -cybersyn-combinator=Place next to a train stop to add it to the cybersyn train network. This stop can now request or provide items using the circuit network. Be sure to set a threshold signal. +cybersyn-combinator=Place next to a train stop to add it to the cybersyn train network. This stop can now request or provide items that are reported to it by the circuit network. [entity-name] cybersyn-combinator=Cybernetic combinator @@ -32,7 +30,6 @@ cybersyn-train-network=Train stop controllers capable of coordinating the inputs [virtual-signal-name] cybersyn-priority=Station priority -cybersyn-provide-threshold=Provide threshold cybersyn-request-threshold=Request threshold cybersyn-locked-slots=Locked slots per cargo wagon @@ -49,4 +46,10 @@ comb2=Optional station control depot=Depot control wagon-manifest=Wagon control network=Network -auto-description=Station automatically decides which trains in the network it can service (all trains are allowed by default) +network-tooltip=A signal is used to identify which network this combinator is a member of. Trains will only be dispatched from depots to provide and request stations if they are all identified with the same signal. +auto-tooltip=When checked trains in the network are automatically blacklisted if they are not able to interact with all of the loading and unloading machines present along the station. When unchecked the blacklist is empty and all trains are allowed. +auto-description=Allow automatic train blacklist +switch-provide=Provide only +switch-request=Request only +switch-provide-tooltip=Lock this station to only provide items to the network. By default it both requests and provides. +switch-request-tooltip=Lock this station to only request items from the network. By default it both requests and provides. diff --git a/cybersyn/prototypes/signal.lua b/cybersyn/prototypes/signal.lua index 0390528..b8819f6 100644 --- a/cybersyn/prototypes/signal.lua +++ b/cybersyn/prototypes/signal.lua @@ -14,15 +14,6 @@ priority_signal = { subgroup = "cybersyn-signal", order = "a" } -p_threshold_signal = { - type = "virtual-signal", - name = PROVIDE_THRESHOLD, - icon = "__cybersyn__/graphics/icons/provide-threshold.png", - icon_size = 64, - icon_mipmaps = 4, - subgroup = "cybersyn-signal", - order = "b" -} r_threshold_signal = { type = "virtual-signal", name = REQUEST_THRESHOLD, diff --git a/cybersyn/scripts/central-planning.lua b/cybersyn/scripts/central-planning.lua index 087e8b3..89bac8e 100644 --- a/cybersyn/scripts/central-planning.lua +++ b/cybersyn/scripts/central-planning.lua @@ -70,49 +70,6 @@ function create_manifest_schedule(depot_name, p_stop, r_stop, manifest) }} end ----@param station Station -local function get_signals(station) - local comb = station.entity_comb1 - if comb.valid and (comb.status == defines.entity_status.working or comb.status == defines.entity_status.low_power) then - return comb.get_merged_signals(defines.circuit_connector_id.combinator_input) - else - return nil - end -end - ----@param map_data MapData ----@param comb LuaEntity ----@param signals ConstantCombinatorParameters[]? -function set_combinator_output(map_data, comb, signals) - local out = map_data.to_output[comb.unit_number] - if out.valid then - out.get_or_create_control_behavior().parameters = signals - end -end ----@param comb LuaEntity ----@param op string -function set_combinator_operation(comb, op) - local a = comb.get_or_create_control_behavior()--[[@as LuaArithmeticCombinatorControlBehavior]] - local control = a.parameters - control.operation = op - a.parameters = control -end - ----@param map_data MapData ----@param station Station -local function set_comb2(map_data, station) - if station.entity_comb2 then - local deliveries = station.deliveries - local signals = {} - for item_name, count in pairs(deliveries) do - local i = #signals + 1 - local is_fluid = game.item_prototypes[item_name] == nil--NOTE: this is expensive - signals[i] = {index = i, signal = {type = is_fluid and "fluid" or "item", name = item_name}, count = -count} - end - set_combinator_output(map_data, station.entity_comb2, signals) - end -end - ---@param map_data MapData ---@param station Station ---@param manifest Manifest @@ -128,20 +85,6 @@ function remove_manifest(map_data, station, manifest, sign) station.deliveries_total = station.deliveries_total - 1 end ----@param map_data MapData ----@param signal SignalID -local function get_thresholds(map_data, station, signal) - local comb2 = station.entity_comb2 - if comb2 and comb2.valid then - local count = comb2.get_merged_signal(signal, defines.circuit_connector_id.combinator_input) - if count > 0 then - return station.r_threshold, count - elseif count < 0 then - return -count, station.p_threshold - end - end - return station.r_threshold, station.p_threshold -end ---@param stop0 LuaEntity ---@param stop1 LuaEntity @@ -150,12 +93,12 @@ local function get_stop_dist(stop0, stop1) end - ---@param map_data MapData ---@param r_station_id uint ---@param p_station_id uint ---@param item_type string -local function get_valid_train(map_data, r_station_id, p_station_id, item_type) +---@param min_amount_to_move int +local function get_valid_train(map_data, r_station_id, p_station_id, item_type, min_amount_to_move) --NOTE: this code is the critical section for run-time optimization local r_station = map_data.stations[r_station_id] local p_station = map_data.stations[p_station_id] @@ -185,10 +128,10 @@ local function get_valid_train(map_data, r_station_id, p_station_id, item_type) --check layout validity for both stations local capacity = (is_fluid and train.fluid_capacity) or train.item_slot_capacity if - capacity > 0 and + capacity > min_amount_to_move and btest(netand, depot.network_flag) and - (r_station.is_all or r_station.accepted_layouts[layout_id]) and - (p_station.is_all or p_station.accepted_layouts[layout_id]) + (r_station.allows_all_trains or r_station.accepted_layouts[layout_id]) and + (p_station.allows_all_trains or p_station.accepted_layouts[layout_id]) then valid_train_exists = true --check if exists valid path @@ -227,48 +170,35 @@ local function send_train_between(map_data, r_station_id, p_station_id, depot, p ---@type string local network_name = depot.network_name - local requests = {} local manifest = {} - local r_signals = r_station.tick_signals - if r_signals then - for k, v in pairs(r_signals) do - ---@type string - local item_name = v.signal.name - local item_count = v.count - local effective_item_count = item_count + (r_station.deliveries[item_name] or 0) - if effective_item_count < 0 and item_count < 0 then - requests[item_name] = -effective_item_count - end - end - end - - local p_signals = p_station.tick_signals - if p_signals then - for k, v in pairs(p_signals) do - local item_name = v.signal.name - local item_count = v.count - local item_type = v.signal.type - local effective_item_count = item_count + (p_station.deliveries[item_name] or 0) - if effective_item_count > 0 and item_count > 0 then - local r = requests[item_name] - if r then - local item = {name = item_name, type = item_type, count = min(r, effective_item_count)} - if item_name == primary_item_name then - manifest[#manifest + 1] = manifest[1] - manifest[1] = item - else - manifest[#manifest + 1] = item - end + for k, v in pairs(r_station.tick_signals) do + ---@type string + local item_name = v.signal.name + local item_type = v.signal.type + local r_item_count = v.count + local r_effective_item_count = r_item_count + (r_station.deliveries[item_name] or 0) + if r_effective_item_count < 0 and r_item_count < 0 then + local r_threshold = r_station.p_count_or_r_threshold_per_item[item_name] + local p_effective_item_count = p_station.p_count_or_r_threshold_per_item[item_name] + if p_effective_item_count and p_effective_item_count >= r_threshold then + local item = {name = item_name, type = item_type, count = min(-r_effective_item_count, p_effective_item_count)} + if item_name == primary_item_name then + manifest[#manifest + 1] = manifest[1] + manifest[1] = item + else + manifest[#manifest + 1] = item end end end end - local locked_slots = max(p_station.locked_slots, r_station.locked_slots) + --locked slots is only taken into account after the train is already approved for dispatch + local locked_slots = p_station.locked_slots local total_slots_left = train.item_slot_capacity if locked_slots > 0 then - total_slots_left = max(total_slots_left - #train.entity.cargo_wagons*locked_slots, min(total_slots_left, #train.entity.cargo_wagons)) + local total_cw = #train.entity.cargo_wagons + total_slots_left = min(total_slots_left, max(total_slots_left - total_cw*locked_slots, total_cw)) end local total_liquid_left = train.fluid_capacity @@ -307,7 +237,6 @@ local function send_train_between(map_data, r_station_id, p_station_id, depot, p r_station.deliveries_total = r_station.deliveries_total + 1 p_station.deliveries_total = p_station.deliveries_total + 1 - assert(manifest[1].name == primary_item_name) for item_i, item in ipairs(manifest) do assert(item.count > 0, "main.lua error, transfer amount was not positive") @@ -420,12 +349,12 @@ local function tick_poll_station(map_data, mod_settings) if station.network_name and station.deliveries_total < station.entity_stop.trains_limit then station.r_threshold = mod_settings.r_threshold - station.p_threshold = mod_settings.p_threshold station.priority = 0 station.locked_slots = 0 station.network_flag = mod_settings.network_flag local signals = get_signals(station) station.tick_signals = signals + table_clear(station.p_count_or_r_threshold_per_item) if signals then for k, v in pairs(signals) do local item_name = v.signal.name @@ -436,10 +365,8 @@ local function tick_poll_station(map_data, mod_settings) if item_name == SIGNAL_PRIORITY then station.priority = item_count elseif item_name == REQUEST_THRESHOLD and item_count ~= 0 then - --NOTE: thresholds must be >0 or they will cause a crash + --NOTE: thresholds must be >0 or they can cause a crash station.r_threshold = abs(item_count) - elseif item_name == PROVIDE_THRESHOLD and item_count ~= 0 then - station.p_threshold = abs(item_count) elseif item_name == LOCKED_SLOTS then station.locked_slots = max(item_count, 0) end @@ -453,12 +380,13 @@ local function tick_poll_station(map_data, mod_settings) end end for k, v in pairs(signals) do + ---@type string local item_name = v.signal.name local item_count = v.count local effective_item_count = item_count + (station.deliveries[item_name] or 0) - local r_threshold, p_threshold = get_thresholds(map_data, station, v.signal) + local r_threshold = get_threshold(map_data, station, v.signal) - if -effective_item_count >= r_threshold and -item_count >= r_threshold then + if station.is_r and -effective_item_count >= r_threshold and -item_count >= r_threshold then local item_network_name = station.network_name..":"..item_name local stations = all_r_stations[item_network_name] if stations == nil then @@ -468,7 +396,8 @@ local function tick_poll_station(map_data, mod_settings) all_names[#all_names + 1] = v.signal end stations[#stations + 1] = station_id - elseif effective_item_count >= p_threshold and item_count >= p_threshold then + station.p_count_or_r_threshold_per_item[item_name] = r_threshold + elseif station.is_p and effective_item_count > 0 and item_count > 0 then local item_network_name = station.network_name..":"..item_name local stations = all_p_stations[item_network_name] if stations == nil then @@ -476,6 +405,7 @@ local function tick_poll_station(map_data, mod_settings) all_p_stations[item_network_name] = stations end stations[#stations + 1] = station_id + station.p_count_or_r_threshold_per_item[item_name] = effective_item_count else signals[k] = nil end @@ -544,6 +474,10 @@ local function tick_dispatch(map_data, mod_settings) end local r_station_id = table_remove(r_stations--[[@as uint[] ]]) + local r_station = stations[r_station_id] + local item_name = tick_data.item_name + local item_type = tick_data.item_type + local r_threshold = r_station.p_count_or_r_threshold_per_item[item_name] local best = 0 local best_depot = nil @@ -551,24 +485,27 @@ local function tick_dispatch(map_data, mod_settings) local highest_prior = -INF local could_have_been_serviced = false for j, p_station_id in ipairs(p_stations) do - local depot, d = get_valid_train(map_data, r_station_id, p_station_id, tick_data.item_type) - local prior = stations[p_station_id].priority - if prior > highest_prior or (prior == highest_prior and d < best_dist) then - if depot then - best = j - best_dist = d - best_depot = depot - highest_prior = prior - elseif d < INF then - could_have_been_serviced = true - best = j + local p_station = stations[p_station_id] + if p_station.p_count_or_r_threshold_per_item[item_name] >= r_threshold then + local prior = p_station.priority + local depot, d = get_valid_train(map_data, r_station_id, p_station_id, item_type, r_threshold) + if prior > highest_prior or (prior == highest_prior and d < best_dist) then + if depot then + best = j + best_dist = d + best_depot = depot + highest_prior = prior + elseif d < INF then + could_have_been_serviced = true + best = j + end end end end if best_depot then - send_train_between(map_data, r_station_id, table_remove(p_stations, best), best_depot, tick_data.item_name) + send_train_between(map_data, r_station_id, table_remove(p_stations, best), best_depot, item_name) elseif could_have_been_serviced then - send_missing_train_alert_for_stops(stations[r_station_id].entity_stop, stations[p_stations[best]].entity_stop) + send_missing_train_alert_for_stops(r_station.entity_stop, stations[p_stations[best]].entity_stop) end return false end diff --git a/cybersyn/scripts/combinator.lua b/cybersyn/scripts/combinator.lua new file mode 100644 index 0000000..265a194 --- /dev/null +++ b/cybersyn/scripts/combinator.lua @@ -0,0 +1,100 @@ +--By Mami +local abs = math.abs +local floor = math.floor + +---@param param ArithmeticCombinatorParameters +function get_comb_secondary_state(param) + local bits = param.second_constant or 0 + return bits%2 == 1, floor(bits/2)%3 +end +---@param depot Depot +function set_depot_from_comb_state(depot) + local param = depot.entity_comb.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] + local signal = param.first_signal + depot.network_name = signal and signal.name or nil +end +---@param station Station +function set_station_from_comb_state(station) + --NOTE: this does nothing to update currently active deliveries + local param = station.entity_comb1.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] + local bits = param.second_constant or 0 + local is_pr_state = floor(bits/2)%3 + local signal = param.first_signal + station.network_name = signal and signal.name or nil + station.allows_all_trains = bits%2 == 1 + station.is_p = is_pr_state == 0 or is_pr_state == 1 + station.is_r = is_pr_state == 0 or is_pr_state == 2 +end +---@param control LuaArithmeticCombinatorControlBehavior +function set_comb_allows_all_trains(control, allows_all_trains) + local param = control.parameters + local bits = param.second_constant or 0 + param.second_constant = (bits - bits%2) + (allows_all_trains and 1 or 0) + control.parameters = param +end +---@param control LuaArithmeticCombinatorControlBehavior +function set_comb_is_pr_state(control, is_pr_state) + local param = control.parameters + local bits = param.second_constant or 0 + param.second_constant = (bits%2) + (2*is_pr_state) + control.parameters = param +end + + +---@param map_data MapData +---@param comb LuaEntity +---@param signals ConstantCombinatorParameters[]? +function set_combinator_output(map_data, comb, signals) + local out = map_data.to_output[comb.unit_number] + if out.valid then + out.get_or_create_control_behavior().parameters = signals + end +end +---@param comb LuaEntity +---@param op string +function set_combinator_operation(comb, op) + local a = comb.get_or_create_control_behavior()--[[@as LuaArithmeticCombinatorControlBehavior]] + local control = a.parameters + control.operation = op + a.parameters = control +end + + +---@param station Station +function get_signals(station) + local comb = station.entity_comb1 + if comb.valid and (comb.status == defines.entity_status.working or comb.status == defines.entity_status.low_power) then + return comb.get_merged_signals(defines.circuit_connector_id.combinator_input) + else + return nil + end +end + +---@param map_data MapData +---@param station Station +function set_comb2(map_data, station) + if station.entity_comb2 then + local deliveries = station.deliveries + local signals = {} + for item_name, count in pairs(deliveries) do + local i = #signals + 1 + local is_fluid = game.item_prototypes[item_name] == nil--NOTE: this is expensive + signals[i] = {index = i, signal = {type = is_fluid and "fluid" or "item", name = item_name}, count = -count} + end + set_combinator_output(map_data, station.entity_comb2, signals) + end +end + +---@param map_data MapData +---@param station Station +---@param signal SignalID +function get_threshold(map_data, station, signal) + local comb2 = station.entity_comb2 + if comb2 and comb2.valid then + local count = comb2.get_merged_signal(signal, defines.circuit_connector_id.combinator_input) + if count ~= 0 then + return abs(count) + end + end + return station.r_threshold +end diff --git a/cybersyn/scripts/constants.lua b/cybersyn/scripts/constants.lua index bdce530..cf75555 100644 --- a/cybersyn/scripts/constants.lua +++ b/cybersyn/scripts/constants.lua @@ -6,7 +6,6 @@ NONEMPTY_TRAIN_NAME = "cybersyn-nonempty-train" SIGNAL_PRIORITY = "cybersyn-priority" REQUEST_THRESHOLD = "cybersyn-request-threshold" -PROVIDE_THRESHOLD = "cybersyn-provide-threshold" LOCKED_SLOTS = "cybersyn-locked-slots" COMBINATOR_NAME = "cybersyn-combinator" @@ -16,6 +15,7 @@ COMBINATOR_CLOSE_SOUND = "entity-close/cybersyn-combinator" OPERATION_DEFAULT = "*" OPERATION_PRIMARY_IO = "/" OPERATION_PRIMARY_IO_ACTIVE = "^" +OPERATION_PRIMARY_IO_NOT_FOUND = "<<" OPERATION_SECONDARY_IO = "%" OPERATION_DEPOT = "+" OPERATION_WAGON_MANIFEST = "-" diff --git a/cybersyn/scripts/global.lua b/cybersyn/scripts/global.lua index 6f8ba23..bb0fdfe 100644 --- a/cybersyn/scripts/global.lua +++ b/cybersyn/scripts/global.lua @@ -16,11 +16,12 @@ ---@field public economy Economy ---@class Station +---@field public is_p boolean +---@field public is_r boolean ---@field public deliveries_total int ---@field public last_delivery_tick int ---@field public priority int --transient ---@field public r_threshold int >= 0 --transient ----@field public p_threshold int >= 0 --transient ---@field public locked_slots int >= 0 --transient ---@field public entity_stop LuaEntity ---@field public entity_comb1 LuaEntity @@ -29,10 +30,11 @@ ---@field public deliveries {[string]: int} ---@field public network_name string? ---@field public network_flag int --transient ----@field public is_all boolean +---@field public allows_all_trains boolean ---@field public accepted_layouts TrainClass ---@field public layout_pattern string? ---@field public tick_signals {[uint]: Signal}? --transient +---@field public p_count_or_r_threshold_per_item {[string]: int}? --transient ---@class Depot ---@field public priority int --transient @@ -67,12 +69,18 @@ ---@class CybersynModSettings ---@field public tps int ---@field public r_threshold int ----@field public p_threshold int ---@field public network_flag int ---@type CybersynModSettings mod_settings = {} +local pairs = pairs +function table_clear(tab) + for k, _ in pairs(tab) do + tab[k] = nil + end +end + function init_global() global.total_ticks = 0 global.tick_state = STATE_INIT diff --git a/cybersyn/scripts/gui.lua b/cybersyn/scripts/gui.lua index 1749b68..7945bfe 100644 --- a/cybersyn/scripts/gui.lua +++ b/cybersyn/scripts/gui.lua @@ -30,10 +30,21 @@ STATUS_NAMES_DEFAULT = "entity-status.disabled" ---@param player LuaPlayer function gui_opened(comb, player) local rootgui = player.gui.screen - local selected_index = 0 local control = comb.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] local op = control.operation - if op == OPERATION_PRIMARY_IO or op == OPERATION_PRIMARY_IO_ACTIVE then + + local selected_index = 0 + local switch_state = "none" + local allows_all_trains, is_pr_state = get_comb_secondary_state(control) + if is_pr_state == 0 then + switch_state = "none" + elseif is_pr_state == 1 then + switch_state = "left" + elseif is_pr_state == 2 then + switch_state = "right" + end + + if op == OPERATION_PRIMARY_IO or op == OPERATION_PRIMARY_IO_ACTIVE or op == OPERATION_PRIMARY_IO_NOT_FOUND then selected_index = 1 elseif op == OPERATION_SECONDARY_IO then selected_index = 2 @@ -43,61 +54,67 @@ function gui_opened(comb, player) selected_index = 4 end -local window = flib_gui.build(rootgui, { - {type="frame", direction="vertical", ref={"main_window"}, name=COMBINATOR_NAME, children={ - --title bar - {type="flow", ref={"titlebar"}, children={ - {type="label", style="frame_title", caption={"cybersyn-gui.combinator-title"}, elem_mods={ignored_by_interaction=true}}, - {type="empty-widget", style="flib_titlebar_drag_handle", elem_mods={ignored_by_interaction=true}}, - {type="sprite-button", style="frame_action_button", mouse_button_filter={"left"}, sprite="utility/close_white", hovered_sprite="utility/close_black", name=COMBINATOR_NAME, actions={ - on_click = {"close", comb.unit_number} - }} - }}, - {type="frame", style="inside_shallow_frame_with_padding", style_mods={padding=12}, children={ - {type="flow", direction="vertical", style_mods={horizontal_align="left"}, children={ - --status - {type="flow", style="status_flow", direction="horizontal", style_mods={vertical_align="center", horizontally_stretchable=true, bottom_padding=4}, children={ - {type="sprite", sprite=STATUS_SPRITES[comb.status] or STATUS_SPRITES_DEFAULT, style="status_image", ref={"status_icon"}, style_mods={stretch_image_to_widget_size=true}}, - {type="label", caption={STATUS_NAMES[comb.status] or STATUS_NAMES_DEFAULT}, ref={"status_label"}} - }}, - --preview - {type="frame", style="deep_frame_in_shallow_frame", style_mods={minimal_width=0, horizontally_stretchable=true, padding=0}, children={ - {type="entity-preview", style="wide_entity_button", ref={"preview"}}, - }}, - --drop down - {type="label", style="heading_3_label", caption={"cybersyn-gui.operation"}, style_mods={top_padding=8}}, - {type="drop-down", style_mods={top_padding=3}, ref={"operation"}, actions={ - on_selection_state_changed={"drop-down", comb.unit_number} - }, selected_index=selected_index, items={ - {"cybersyn-gui.comb1"}, - {"cybersyn-gui.comb2"}, - {"cybersyn-gui.depot"}, - {"cybersyn-gui.wagon-manifest"}, - }}, - ---choose-elem-button - {type="line", style_mods={top_padding=10}}, - {type="label", name="network_label", ref={"network_label"}, style="heading_3_label", caption={"cybersyn-gui.network"}, style_mods={top_padding=7}}, - {type="flow", name="bottom", direction="horizontal", children={ - {type="choose-elem-button", name="network", style="slot_button_in_shallow_frame", ref={"network"}, elem_type="signal", signal=control.first_signal, style_mods={bottom_margin=2, right_margin=6}, actions={ - on_elem_changed={"choose-elem-button", comb.unit_number} + local window = flib_gui.build(rootgui, { + {type="frame", direction="vertical", ref={"main_window"}, name=COMBINATOR_NAME, children={ + --title bar + {type="flow", ref={"titlebar"}, children={ + {type="label", style="frame_title", caption={"cybersyn-gui.combinator-title"}, elem_mods={ignored_by_interaction=true}}, + {type="empty-widget", style="flib_titlebar_drag_handle", elem_mods={ignored_by_interaction=true}}, + {type="sprite-button", style="frame_action_button", mouse_button_filter={"left"}, sprite="utility/close_white", hovered_sprite="utility/close_black", name=COMBINATOR_NAME, actions={ + on_click = {"close", comb.unit_number} + }} + }}, + {type="frame", style="inside_shallow_frame_with_padding", style_mods={padding=12}, children={ + {type="flow", direction="vertical", style_mods={horizontal_align="left"}, children={ + --status + {type="flow", style="status_flow", direction="horizontal", style_mods={vertical_align="center", horizontally_stretchable=true, bottom_padding=4}, children={ + {type="sprite", sprite=STATUS_SPRITES[comb.status] or STATUS_SPRITES_DEFAULT, style="status_image", ref={"status_icon"}, style_mods={stretch_image_to_widget_size=true}}, + {type="label", caption={STATUS_NAMES[comb.status] or STATUS_NAMES_DEFAULT}, ref={"status_label"}} }}, - {type="checkbox", name="radiobutton", ref={"radiobutton"}, state=control.second_constant ~= 1, style_mods={top_margin=4}, actions={ - on_checked_state_changed={"radiobutton", comb.unit_number} + --preview + {type="frame", style="deep_frame_in_shallow_frame", style_mods={minimal_width=0, horizontally_stretchable=true, padding=0}, children={ + {type="entity-preview", style="wide_entity_button", ref={"preview"}}, }}, - {type="label", name="radiolabel", style_mods={single_line=false, maximal_width=330, left_padding=3}, ref={"radiolabel"}, caption={"cybersyn-gui.auto-description"}}, + --drop down + {type="label", style="heading_3_label", caption={"cybersyn-gui.operation"}, style_mods={top_padding=8}}, + {type="flow", name="top", direction="horizontal", style_mods={vertical_align="center"}, children={ + {type="drop-down", style_mods={top_padding=3, right_margin=8}, ref={"operation"}, actions={ + on_selection_state_changed={"drop-down", comb.unit_number} + }, selected_index=selected_index, items={ + {"cybersyn-gui.comb1"}, + {"cybersyn-gui.comb2"}, + {"cybersyn-gui.depot"}, + {"cybersyn-gui.wagon-manifest"}, + }}, + {type="switch", name="switch", ref={"switch"}, allow_none_state=true, switch_state=switch_state, left_label_caption={"cybersyn-gui.switch-provide"}, right_label_caption={"cybersyn-gui.switch-request"}, left_label_tooltip={"cybersyn-gui.switch-provide-tooltip"}, right_label_tooltip={"cybersyn-gui.switch-request-tooltip"}, actions={ + on_switch_state_changed={"switch", comb.unit_number} + }} + }}, + ---choose-elem-button + {type="line", style_mods={top_padding=10}}, + {type="label", name="network_label", ref={"network_label"}, style="heading_3_label", caption={"cybersyn-gui.network"}, style_mods={top_padding=8}}, + {type="flow", name="bottom", direction="horizontal", style_mods={vertical_align="center"}, children={ + {type="choose-elem-button", name="network", style="slot_button_in_shallow_frame", ref={"network"}, elem_type="signal", tooltip={"cybersyn-gui.network-tooltip"}, signal=control.first_signal, style_mods={bottom_margin=1, right_margin=6}, actions={ + on_elem_changed={"choose-elem-button", comb.unit_number} + }}, + {type="checkbox", name="radio_button", ref={"radio_button"}, state=not allows_all_trains, tooltip={"cybersyn-gui.auto-tooltip"}, actions={ + on_checked_state_changed={"radio_button", comb.unit_number} + }}, + {type="label", name="radio_label", style_mods={left_padding=3}, ref={"radio_label"}, caption={"cybersyn-gui.auto-description"}}, + }} }} }} }} - }} -}) + }) window.preview.entity = comb window.titlebar.drag_target = window.main_window window.main_window.force_auto_center() window.network.visible = selected_index == 1 or selected_index == 3 window.network_label.visible = selected_index == 1 or selected_index == 3 - window.radiobutton.visible = selected_index == 1 - window.radiolabel.visible = selected_index == 1 + window.radio_button.visible = selected_index == 1 + window.radio_label.visible = selected_index == 1 + window.switch.visible = selected_index == 1 player.opened = window.main_window end @@ -142,31 +159,37 @@ function register_gui_actions() local comb = global.to_comb[msg[2]] if not comb or not comb.valid then return end - local parent = element.parent.bottom + local top_flow = element.parent + local all_flow = top_flow.parent + local bottom_flow = all_flow.bottom if element.selected_index == 1 then set_combinator_operation(comb, OPERATION_PRIMARY_IO) - element.parent["network_label"].visible = true - parent["network"].visible = true - parent["radiobutton"].visible = true - parent["radiolabel"].visible = true + top_flow["switch"].visible = true + all_flow["network_label"].visible = true + bottom_flow["network"].visible = true + bottom_flow["radio_button"].visible = true + bottom_flow["radio_label"].visible = true elseif element.selected_index == 2 then set_combinator_operation(comb, OPERATION_SECONDARY_IO) - element.parent["network_label"].visible = false - parent["network"].visible = false - parent["radiobutton"].visible = false - parent["radiolabel"].visible = false + top_flow["switch"].visible = false + all_flow["network_label"].visible = false + bottom_flow["network"].visible = false + bottom_flow["radio_button"].visible = false + bottom_flow["radio_label"].visible = false elseif element.selected_index == 3 then set_combinator_operation(comb, OPERATION_DEPOT) - element.parent["network_label"].visible = true - parent["network"].visible = true - parent["radiobutton"].visible = false - parent["radiolabel"].visible = false + top_flow["switch"].visible = false + all_flow["network_label"].visible = true + bottom_flow["network"].visible = true + bottom_flow["radio_button"].visible = false + bottom_flow["radio_label"].visible = false elseif element.selected_index == 4 then set_combinator_operation(comb, OPERATION_WAGON_MANIFEST) - element.parent["network_label"].visible = false - parent["network"].visible = false - parent["radiobutton"].visible = false - parent["radiolabel"].visible = false + top_flow["switch"].visible = false + all_flow["network_label"].visible = false + bottom_flow["network"].visible = false + bottom_flow["radio_button"].visible = false + bottom_flow["radio_label"].visible = false else return end @@ -188,28 +211,43 @@ function register_gui_actions() else control.first_signal = signal end - a.parameters = control + on_combinator_network_updated(global, comb, signal and signal.name or nil) - elseif msg[1] == "radiobutton" then + elseif msg[1] == "radio_button" then local element = event.element if not element then return end local comb = global.to_comb[msg[2]] if not comb or not comb.valid then return end local a = comb.get_or_create_control_behavior()--[[@as LuaArithmeticCombinatorControlBehavior]] - local control = a.parameters - local is_auto = element.state - control.second_constant = is_auto and 0 or 1 - - a.parameters = control + local allows_all_trains = element.state + set_comb_allows_all_trains(a, allows_all_trains) local stop = global.to_stop[comb.unit_number] if stop then local station = global.stations[stop.unit_number] if station then - set_station_train_class(global, station, not is_auto) + set_station_train_class(global, station, allows_all_trains) + end + end + elseif msg[1] == "switch" then + local element = event.element + if not element then return end + local comb = global.to_comb[msg[2]] + if not comb or not comb.valid then return end + + local is_pr_state = (element.switch_state == "none" and 0) or (element.switch_state == "left" and 1) or 2 + local a = comb.get_or_create_control_behavior()--[[@as LuaArithmeticCombinatorControlBehavior]] + set_comb_is_pr_state(a, is_pr_state) + + local stop = global.to_stop[comb.unit_number] + if stop then + local station = global.stations[stop.unit_number] + if station then + station.is_p = is_pr_state == 0 or is_pr_state == 1 + station.is_r = is_pr_state == 0 or is_pr_state == 2 end end end diff --git a/cybersyn/scripts/layout.lua b/cybersyn/scripts/layout.lua index 9a8238e..9b71a35 100644 --- a/cybersyn/scripts/layout.lua +++ b/cybersyn/scripts/layout.lua @@ -447,11 +447,11 @@ end ---@param map_data MapData ---@param station Station ----@param is_all boolean -function set_station_train_class(map_data, station, is_all) - if station.is_all ~= is_all then - station.is_all = is_all - if not is_all then +---@param allows_all_trains boolean +function set_station_train_class(map_data, station, allows_all_trains) + if station.allows_all_trains ~= allows_all_trains then + station.allows_all_trains = allows_all_trains + if not allows_all_trains then reset_station_layout(map_data, station, nil) end end @@ -461,7 +461,7 @@ end ---@param station Station ---@param forbidden_entity LuaEntity? function update_station_if_auto(map_data, station, forbidden_entity) - if not station.is_all then + if not station.allows_all_trains then reset_station_layout(map_data, station, forbidden_entity) end end diff --git a/cybersyn/scripts/main.lua b/cybersyn/scripts/main.lua index eacbf12..05db3ed 100644 --- a/cybersyn/scripts/main.lua +++ b/cybersyn/scripts/main.lua @@ -91,15 +91,16 @@ end ---@param map_data MapData ---@param stop LuaEntity ---@param comb LuaEntity -local function on_depot_built(map_data, stop, comb, control) +local function on_depot_built(map_data, stop, comb) local depot = { entity_stop = stop, entity_comb = comb, - network_name = control.first_signal and control.first_signal.name or nil, + --network_name = nil, priority = 0, network_flag = 0, } map_data.depots[stop.unit_number] = depot + set_depot_from_comb_state(depot) end local function on_depot_broken(map_data, depot) @@ -117,8 +118,7 @@ end ---@param stop LuaEntity ---@param comb1 LuaEntity ---@param comb2 LuaEntity ----@param control ArithmeticCombinatorParameters -local function on_station_built(map_data, stop, comb1, comb2, control) +local function on_station_built(map_data, stop, comb1, comb2) local station = { entity_stop = stop, entity_comb1 = comb1, @@ -130,13 +130,14 @@ local function on_station_built(map_data, stop, comb1, comb2, control) r_threshold = 0, p_threshold = 0, locked_slots = 0, - network_name = control.first_signal and control.first_signal.name or nil, + --network_name = param.first_signal and param.first_signal.name or nil, network_flag = 0, deliveries = {}, - is_all = control.second_constant == 1, + --allows_all_trains = param.second_constant == 1, accepted_layouts = {}, layout_pattern = nil, } + set_station_from_comb_state(station) map_data.stations[stop.unit_number] = station update_station_if_auto(map_data, station, nil) @@ -244,18 +245,18 @@ local function on_combinator_built(map_data, comb) map_data.to_output[comb.unit_number] = out map_data.to_stop[comb.unit_number] = stop - local a = comb.get_or_create_control_behavior()--[[@as LuaArithmeticCombinatorControlBehavior]] - local control = a.parameters - local op = control.operation + local control = comb.get_or_create_control_behavior()--[[@as LuaArithmeticCombinatorControlBehavior]] + local param = control.parameters + local op = param.operation if op == OPERATION_DEFAULT then op = OPERATION_PRIMARY_IO - control.operation = op - control.first_signal = NETWORK_SIGNAL_DEFAULT - a.parameters = control - elseif op == OPERATION_PRIMARY_IO_ACTIVE then + param.operation = op + param.first_signal = NETWORK_SIGNAL_DEFAULT + control.parameters = param + elseif op == OPERATION_PRIMARY_IO_ACTIVE or op == OPERATION_PRIMARY_IO_NOT_FOUND then op = OPERATION_PRIMARY_IO - control.operation = op - a.parameters = control + param.operation = op + control.parameters = param end if op == OPERATION_WAGON_MANIFEST then if rail then @@ -269,7 +270,7 @@ local function on_combinator_built(map_data, comb) if depot or station then --NOTE: repeated combinators are ignored else - on_depot_built(map_data, stop, comb, control) + on_depot_built(map_data, stop, comb) end end elseif op == OPERATION_SECONDARY_IO then @@ -279,23 +280,23 @@ local function on_combinator_built(map_data, comb) station.entity_comb2 = comb end end - elseif stop then - control.operation = OPERATION_PRIMARY_IO - local station = map_data.stations[stop.unit_number] - local depot = map_data.depots[stop.unit_number] - if station then - --NOTE: repeated combinators are ignored - else - if depot then - --NOTE: this will disrupt deliveries in progress that where dispatched from this station in a minor way - map_data.depots[stop.unit_number] = nil + elseif op == OPERATION_PRIMARY_IO then + if stop then + local station = map_data.stations[stop.unit_number] + if station then + --NOTE: repeated combinators are ignored + else + local depot = map_data.depots[stop.unit_number] + if depot then + on_depot_broken(map_data, depot) + end + --no station or depot + --add station + + local comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, comb) + + on_station_built(map_data, stop, comb, comb2) end - --no station or depot - --add station - - local comb2 = search_for_station_combinator(map_data, stop, OPERATION_SECONDARY_IO, comb) - - on_station_built(map_data, stop, comb, comb2, control) end end end @@ -341,14 +342,12 @@ local function on_combinator_broken(map_data, comb) local comb1 = search_for_station_combinator(map_data, stop, OPERATION_PRIMARY_IO, comb) if comb1 then station.entity_comb1 = comb1 - local control = comb1.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] - station.network_name = control.first_signal and control.first_signal.name + set_station_from_comb_state(station) else on_station_broken(map_data, stop.unit_number, station) local depot_comb = search_for_station_combinator(map_data, stop, OPERATION_DEPOT, comb) if depot_comb then - local control = depot_comb.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] - on_depot_built(map_data, stop, depot_comb, control.first_signal) + on_depot_built(map_data, stop, depot_comb) end end elseif station.entity_comb2 == comb then @@ -360,9 +359,8 @@ local function on_combinator_broken(map_data, comb) --NOTE: this will disrupt deliveries in progress that where dispatched from this station in a minor way local depot_comb = search_for_station_combinator(map_data, stop, OPERATION_DEPOT, comb) if depot_comb then - local control = depot_comb.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] depot.entity_comb = depot_comb - depot.network_name = control.first_signal and control.first_signal.name + set_depot_from_comb_state(depot) else on_depot_broken(map_data, depot) end @@ -404,7 +402,7 @@ local function on_stop_built(map_data, stop) map_data.to_stop[entity.unit_number] = stop local control = entity.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]] local op = control.operation - if op == OPERATION_PRIMARY_IO then + if op == OPERATION_PRIMARY_IO or op == OPERATION_PRIMARY_IO_ACTIVE or op == OPERATION_PRIMARY_IO_NOT_FOUND then comb1 = entity elseif op == OPERATION_SECONDARY_IO then comb2 = entity @@ -414,9 +412,9 @@ local function on_stop_built(map_data, stop) end end if comb1 then - on_station_built(map_data, stop, comb1, comb2, comb1.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]]) + on_station_built(map_data, stop, comb1, comb2) elseif depot_comb then - on_depot_built(map_data, stop, depot_comb, depot_comb.get_or_create_control_behavior().parameters--[[@as ArithmeticCombinatorParameters]]) + on_depot_built(map_data, stop, depot_comb) end end ---@param map_data MapData @@ -743,7 +741,6 @@ end local function on_settings_changed(event) mod_settings.tps = settings.global["cybersyn-ticks-per-second"].value --[[@as int]] mod_settings.r_threshold = settings.global["cybersyn-request-threshold"].value--[[@as int]] - mod_settings.p_threshold = settings.global["cybersyn-provide-threshold"].value--[[@as int]] mod_settings.network_flag = settings.global["cybersyn-network-flag"].value--[[@as int]] if event.setting == "cybersyn-ticks-per-second" then local nth_tick = math.ceil(60/mod_settings.tps); @@ -773,7 +770,6 @@ local filter_broken = { local function main() mod_settings.tps = settings.global["cybersyn-ticks-per-second"].value --[[@as int]] mod_settings.r_threshold = settings.global["cybersyn-request-threshold"].value--[[@as int]] - mod_settings.p_threshold = settings.global["cybersyn-provide-threshold"].value--[[@as int]] mod_settings.network_flag = settings.global["cybersyn-network-flag"].value--[[@as int]] --NOTE: There is a concern that it is possible to build or destroy important entities without one of these events being triggered, in which case the mod will have undefined behavior diff --git a/cybersyn/settings.lua b/cybersyn/settings.lua index b31e060..f25ed54 100644 --- a/cybersyn/settings.lua +++ b/cybersyn/settings.lua @@ -14,16 +14,7 @@ data:extend({ name = "cybersyn-request-threshold", order = "ab", setting_type = "runtime-global", - default_value = 2000000000, - minimum_value = 1, - maximum_value = 2147483647, - }, - { - type = "int-setting", - name = "cybersyn-provide-threshold", - order = "ac", - setting_type = "runtime-global", - default_value = 2000000000, + default_value = 2000, minimum_value = 1, maximum_value = 2147483647, },