diff --git a/code/modules/wiremod/components/admin/animate.dm b/code/modules/wiremod/components/admin/animate.dm index cbdd622c5d9..921cc8ff6de 100644 --- a/code/modules/wiremod/components/admin/animate.dm +++ b/code/modules/wiremod/components/admin/animate.dm @@ -64,6 +64,9 @@ return var/atom/target_atom = target.value + if(!isatom(target_atom)) + return + var/target_for_animation = target_atom if(atom_or_filter.value == COMP_ANIMATE_FILTER) target_for_animation = target_atom.get_filter(filter_target.value) @@ -71,6 +74,10 @@ if(!target_for_animation) return + if(!isatom(target_atom)) + return + target_atom.datum_flags |= DF_VAR_EDITED + var/extra_flags = NONE if(parallel.value) extra_flags |= ANIMATION_PARALLEL diff --git a/code/modules/wiremod/components/admin/getvar.dm b/code/modules/wiremod/components/admin/getvar.dm index 87b26855434..c742dbe89ef 100644 --- a/code/modules/wiremod/components/admin/getvar.dm +++ b/code/modules/wiremod/components/admin/getvar.dm @@ -8,6 +8,9 @@ desc = "A component that gets a variable on an object." circuit_flags = CIRCUIT_FLAG_INPUT_SIGNAL|CIRCUIT_FLAG_OUTPUT_SIGNAL|CIRCUIT_FLAG_ADMIN + /// Whether to grab a global variable or a variable from this entity. + var/datum/port/input/option/getvar_options + /// Entity to get variable of var/datum/port/input/entity @@ -21,21 +24,30 @@ var/datum/port/output/output_value /obj/item/circuit_component/get_variable/populate_options() + getvar_options = add_option_port("Variable Options", list("Object", "Global")) expected_output_type = add_option_port("Expected Output Type", GLOB.wiremod_fundamental_types) /obj/item/circuit_component/get_variable/populate_ports() entity = add_input_port("Target", PORT_TYPE_DATUM) - variable_name = add_input_port("Variable Name", PORT_TYPE_STRING) - - output_value = add_output_port("Output Value", PORT_TYPE_ANY) + variable_name = add_input_port("Variable Name", PORT_TYPE_STRING, order = 2) + output_value = add_output_port("Output Value", PORT_TYPE_ANY, order = 2) /obj/item/circuit_component/get_variable/pre_input_received(datum/port/input/port) + if(port == getvar_options) + remove_input_port(entity) + entity = null + if(getvar_options.value == "Object") + entity = add_input_port("Target", PORT_TYPE_DATUM) + if(port == expected_output_type) if(output_value.datatype != expected_output_type.value) output_value.set_datatype(expected_output_type.value) /obj/item/circuit_component/get_variable/input_received(datum/port/input/port) - var/atom/object = entity.value + var/atom/object = entity?.value + if(getvar_options.value == "Global") + object = GLOB + var/var_name = variable_name.value if(!var_name || !object) output_value.set_output(null) diff --git a/code/modules/wiremod/components/admin/save_shell.dm b/code/modules/wiremod/components/admin/save_shell.dm index d2b7ff6fe8a..b60e32e4b83 100644 --- a/code/modules/wiremod/components/admin/save_shell.dm +++ b/code/modules/wiremod/components/admin/save_shell.dm @@ -11,6 +11,8 @@ /// Returns the output from the proccall var/datum/port/output/on_loaded + var/atom/movable/loaded_shell + /obj/item/circuit_component/save_shell/populate_ports() on_loaded = add_output_port("On Loaded", PORT_TYPE_SIGNAL) @@ -25,6 +27,7 @@ /obj/item/circuit_component/save_shell/proc/on_post_load(datum/source) SIGNAL_HANDLER + loaded_shell.AddComponent(/datum/component/shell, starting_circuit = parent) on_loaded.set_output(COMPONENT_SIGNAL) /obj/item/circuit_component/save_shell/proc/on_pre_save_to_json(datum/source, list/general_data) @@ -41,8 +44,6 @@ var/variable_data = shell.vars[variable] if(!istext(variable_data) && !isnum(variable_data)) continue - if(initial(shell.vars[variable]) == variable_data) - continue shell_variables[variable] = variable_data component_data["shell_variables"] = shell_variables @@ -52,14 +53,16 @@ return var/shell_type = text2path(component_data["shell_type"]) - if(!shell_type) + if(!shell_type || !ispath(shell_type, /atom)) return ..() - var/atom/movable/shell = new shell_type(drop_location()) + loaded_shell = new shell_type(drop_location()) + if(!loaded_shell) + return + loaded_shell.datum_flags |= DF_VAR_EDITED + var/list/shell_variables = component_data["shell_variables"] for(var/variable in shell_variables - GLOB.duplicate_forbidden_vars) var/variable_data = shell_variables[variable] - shell.vv_edit_var(variable, variable_data) - var/datum/component/shell/shell_component = shell.AddComponent(/datum/component/shell) - shell_component.attach_circuit(parent) + loaded_shell.vv_edit_var(variable, variable_data) return ..() diff --git a/code/modules/wiremod/components/admin/signal_handler/signal_handler.dm b/code/modules/wiremod/components/admin/signal_handler/signal_handler.dm index 12a32dded12..3ba404ca6ac 100644 --- a/code/modules/wiremod/components/admin/signal_handler/signal_handler.dm +++ b/code/modules/wiremod/components/admin/signal_handler/signal_handler.dm @@ -8,7 +8,7 @@ */ /obj/item/circuit_component/signal_handler display_name = "Signal Handler" - desc = "A component that listens for signals on an object. Registering a new object will automatically unregister the old." + desc = "A component that listens for signals on an object." circuit_flags = CIRCUIT_FLAG_ADMIN|CIRCUIT_FLAG_INSTANT /// Whether it is a global or object signal @@ -17,14 +17,19 @@ /// The list of signal IDs that can be selected as an option. var/datum/port/input/option/signal_id + /// Whether this executes instantly or not. If set to 0, this will not execute instantly. + var/datum/port/input/instant + var/list/signal_map /// Entity to register the signal on var/datum/port/input/target /// Registers the signal var/datum/port/input/register - /// Unregisters the signal from the current registered entity. + /// Unregisters the signal on the target. var/datum/port/input/unregister + /// Unregisters the signal from everyone. + var/datum/port/input/unregister_all /// The custom signal ports from the current signal type. Used for saving and loading. var/list/signal_ports @@ -38,8 +43,8 @@ /// The event has been triggered var/datum/port/output/event_triggered - /// The current entity that has the signal registered on it - var/datum/weakref/current_registered_entity + /// The current entities that have the signal registered on it + var/list/datum/weakref/registered_entities = list() /// The current registered signal var/registered_signal @@ -57,8 +62,10 @@ signal_map = GLOB.integrated_circuit_signal_ids /obj/item/circuit_component/signal_handler/populate_ports() + instant = add_input_port("Instant", PORT_TYPE_NUMBER, order = 0.5, trigger = null, default = 1) register = add_input_port("Register", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/register_signals) - unregister = add_input_port("Unregister Current", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/unregister_signals) + unregister = add_input_port("Unregister", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/unregister_signals) + unregister_all = add_input_port("Unregister All", PORT_TYPE_SIGNAL, order = 2, trigger = .proc/unregister_signals_all) add_source_entity() event_triggered = add_output_port("Triggered", PORT_TYPE_INSTANT_SIGNAL, order = 2) @@ -86,19 +93,13 @@ /obj/item/circuit_component/signal_handler/pre_input_received(datum/port/input/port) - if(signal_id == port) + if(signal_id.value != registered_signal) custom_signal = FALSE - if(current_registered_entity) - unregister_signals(port) - - var/last_registered_signal = registered_signal + unregister_signals_all(port) registered_signal = signal_id.value - - if(registered_signal != last_registered_signal) - var/list/data = signal_map[registered_signal] - if(data) - load_new_ports(data) - unregister_signals(port) + var/list/data = signal_map[registered_signal] + if(data) + load_new_ports(data) if(signal_handler_options == port) set_signal_options(port) @@ -112,6 +113,8 @@ signal_map = GLOB.integrated_circuit_global_signal_ids remove_output_port(entity) remove_input_port(target) + target = null + entity = null if(COMP_SIGNAL_HANDLER_OBJECT) signal_id.possible_options = GLOB.integrated_circuit_signal_ids signal_map = GLOB.integrated_circuit_signal_ids @@ -119,20 +122,18 @@ if(!custom_signal) signal_id.set_value(null, TRUE) - unregister_signals() + unregister_signals_all(port) /obj/item/circuit_component/signal_handler/proc/register_signals(datum/port/input/port) CIRCUIT_TRIGGER - if(current_registered_entity) - unregister_signals(port) - - var/datum/target_datum = target.value + var/datum/target_datum = target?.value if(signal_handler_options.value == COMP_SIGNAL_HANDLER_GLOBAL) target_datum = SSdcs if(target_datum) - RegisterSignal(target_datum, registered_signal, .proc/handle_signal_received) - current_registered_entity = WEAKREF(target_datum) + // We override because an admin may try registering a signal on the same object/datum again, so this prevents any runtimes from occuring + RegisterSignal(target_datum, registered_signal, .proc/handle_signal_received, override = TRUE) + registered_entities |= WEAKREF(target_datum) /obj/item/circuit_component/signal_handler/proc/load_new_ports(list/ports_to_load) for(var/datum/port/input/input_port as anything in input_signal_ports) @@ -145,26 +146,51 @@ signal_ports = ports_to_load for(var/list/data in signal_ports) if(data["is_response"]) - var/datum/port/input/bitflag_input = add_input_port(data["name"], PORT_TYPE_RESPONSE_SIGNAL, order = 1, trigger = .proc/handle_bitflag_received) + var/datum/port/input/bitflag_input = add_input_port(data["name"], PORT_TYPE_SIGNAL, order = 3, trigger = .proc/handle_bitflag_received) input_signal_ports[bitflag_input] = data["bitflag"] else output_signal_ports += add_output_port(data["name"], data["type"], order = 1) +/obj/item/circuit_component/signal_handler/proc/unregister_signals_all(datum/port/input/port) + CIRCUIT_TRIGGER + for(var/datum/weakref/weakref_of_object as anything in registered_entities) + var/datum/datum_to_unregister = weakref_of_object.resolve() + if(!datum_to_unregister) + continue + UnregisterSignal(datum_to_unregister, registered_signal) + registered_entities.Cut() + /obj/item/circuit_component/signal_handler/proc/unregister_signals(datum/port/input/port) CIRCUIT_TRIGGER - var/datum/registered_datum = current_registered_entity?.resolve() + var/datum/registered_datum = target?.value + if(signal_handler_options.value == COMP_SIGNAL_HANDLER_GLOBAL) + registered_datum = SSdcs + if(!registered_datum) return UnregisterSignal(registered_datum, registered_signal) - current_registered_entity = null + registered_entities -= WEAKREF(registered_datum) + +/obj/item/circuit_component/signal_handler/proc/run_ports_on_args(list/arguments) + var/first_arg = popleft(arguments) + if(entity) + entity.set_output(first_arg) + + for(var/datum/port/output/port as anything in output_signal_ports) + port.set_output(popleft(arguments)) + event_triggered.set_output(COMPONENT_SIGNAL) /obj/item/circuit_component/signal_handler/proc/handle_signal_received(...) SIGNAL_HANDLER var/list/arguments = args.Copy() + if(!instant.value) + run_ports_on_args(arguments) + return + // usr is not supposed to be defined whilst these execute, which it can be for some signal IDs. // Especially if you try to proccall something - it'll fail because of this reason. // No other way to solve this problem without refactoring proccall code, but it's admin tooling so it's whatever. @@ -172,13 +198,7 @@ usr = null SScircuit_component.queue_instant_run() - var/first_arg = popleft(arguments) - if(entity) - entity.set_output(first_arg) - - for(var/datum/port/output/port as anything in output_signal_ports) - port.set_output(popleft(arguments)) - event_triggered.set_output(COMPONENT_SIGNAL) + run_ports_on_args(arguments) var/list/output = SScircuit_component.execute_instant_run() usr = temp_usr diff --git a/code/modules/wiremod/core/duplicator.dm b/code/modules/wiremod/core/duplicator.dm index 332310e3429..ce56a048544 100644 --- a/code/modules/wiremod/core/duplicator.dm +++ b/code/modules/wiremod/core/duplicator.dm @@ -47,6 +47,10 @@ GLOBAL_LIST_INIT(circuit_dupe_whitelisted_types, list( port = port_to_check break + if(!port) + LOG_ERROR(errors, "Port '[port_name]' not found on [component.type] when trying to set it to a value of [port_data["stored_data"]]!") + continue + port.set_input(port_data["stored_data"]) var/list/external_objects = general_data["external_objects"]