diff --git a/code/__DEFINES/networks.dm b/code/__DEFINES/networks.dm index 0aec59db9b..09b9e4cadf 100644 --- a/code/__DEFINES/networks.dm +++ b/code/__DEFINES/networks.dm @@ -1 +1,3 @@ -#define HID_RESTRICTED_END 101 //the first nonrestricted ID, automatically assigned on connection creation. +#define HID_RESTRICTED_END 101 //the first nonrestricted ID, automatically assigned on connection creation. + +#define NETWORK_BROADCAST_ID "ALL" diff --git a/code/datums/components/ntnet_interface.dm b/code/datums/components/ntnet_interface.dm index f06e89b49d..14462f2774 100644 --- a/code/datums/components/ntnet_interface.dm +++ b/code/datums/components/ntnet_interface.dm @@ -2,6 +2,9 @@ /datum/proc/ntnet_recieve(datum/netdata/data) return +/datum/proc/ntnet_recieve_broadcast(datum/netdata/data) + return + /datum/proc/ntnet_send(datum/netdata/data, netid) GET_COMPONENT(NIC, /datum/component/ntnet_interface) if(!NIC) @@ -9,14 +12,17 @@ return NIC.__network_send(data, netid) /datum/component/ntnet_interface - var/hardware_id //text + var/hardware_id //text. this is the true ID. do not change this. stuff like ID forgery can be done manually. var/network_name = "" //text var/list/networks_connected_by_id = list() //id = datum/ntnet + var/differentiate_broadcast = TRUE //If false, broadcasts go to ntnet_recieve. NOT RECOMMENDED. /datum/component/ntnet_interface/Initialize(force_name = "NTNet Device", autoconnect_station_network = TRUE) //Don't force ID unless you know what you're doing! hardware_id = "[SSnetworks.get_next_HID()]" network_name = force_name - SSnetworks.register_interface(src) + if(!SSnetworks.register_interface(src)) + . = COMPONENT_INCOMPATIBLE + CRASH("Unable to register NTNet interface. Interface deleted.") if(autoconnect_station_network) register_connection(SSnetworks.station_network) @@ -27,7 +33,10 @@ /datum/component/ntnet_interface/proc/__network_recieve(datum/netdata/data) //Do not directly proccall! parent.SendSignal(COMSIG_COMPONENT_NTNET_RECIEVE, data) - parent.ntnet_recieve(data) + if(differentiate_broadcast && data.broadcast) + parent.ntnet_recieve_broadcast(data) + else + parent.ntnet_recieve(data) /datum/component/ntnet_interface/proc/__network_send(datum/netdata/data, netid) //Do not directly proccall! // Process data before sending it diff --git a/code/game/machinery/doors/airlock.dm b/code/game/machinery/doors/airlock.dm index c45866af4c..880f0fe8c8 100644 --- a/code/game/machinery/doors/airlock.dm +++ b/code/game/machinery/doors/airlock.dm @@ -202,8 +202,8 @@ return // Handle recieved packet. - var/command = lowertext(data.plaintext_data) - var/command_value = lowertext(data.plaintext_data_secondary) + var/command = lowertext(data.data["data"]) + var/command_value = lowertext(data.data["data_secondary"]) switch(command) if("open") if(command_value == "on" && !density) diff --git a/code/game/objects/items/control_wand.dm b/code/game/objects/items/control_wand.dm index ce674ceb94..d389679e2b 100644 --- a/code/game/objects/items/control_wand.dm +++ b/code/game/objects/items/control_wand.dm @@ -43,13 +43,13 @@ switch(mode) if(WAND_OPEN) - data.plaintext_data = "open" + data.data["data"] = "open" if(WAND_BOLT) - data.plaintext_data = "bolt" + data.data["data"] = "bolt" if(WAND_EMERGENCY) - data.plaintext_data = "emergency" + data.data["data"] = "emergency" - data.plaintext_data_secondary = "toggle" + data.data["data_secondary"] = "toggle" data.passkey = access_list ntnet_send(data) diff --git a/code/modules/NTNet/netdata.dm b/code/modules/NTNet/netdata.dm index a5d7cc0efa..857869fc21 100644 --- a/code/modules/NTNet/netdata.dm +++ b/code/modules/NTNet/netdata.dm @@ -1,31 +1,46 @@ /datum/netdata //this requires some thought later on but for now it's fine. var/network_id + var/autopasskey = TRUE + var/list/recipient_ids = list() var/sender_id + var/broadcast = FALSE //Whether this is a broadcast packet. - var/plaintext_data - var/plaintext_data_secondary - var/encrypted_passkey + var/list/data = list() var/list/passkey // Process data before sending it /datum/netdata/proc/pre_send(datum/component/ntnet_interface/interface) // Decrypt the passkey. - if(encrypted_passkey && !passkey) - var/result = XorEncrypt(hextostr(encrypted_passkey, TRUE), SScircuit.cipherkey) - if(length(result) > 1) - passkey = json_decode(XorEncrypt(hextostr(encrypted_passkey, TRUE), SScircuit.cipherkey)) + if(autopasskey) + if(data["encrypted_passkey"] && !passkey) + var/result = XorEncrypt(hextostr(data["encrypted_passkey"], TRUE), SScircuit.cipherkey) + if(length(result) > 1) + passkey = json_decode(XorEncrypt(hextostr(data["encrypted_passkey"], TRUE), SScircuit.cipherkey)) - // Encrypt the passkey. - if(!encrypted_passkey && passkey) - encrypted_passkey = strtohex(XorEncrypt(json_encode(passkey), SScircuit.cipherkey)) + // Encrypt the passkey. + if(!data["encrypted_passkey"] && passkey) + data["encrypted_passkey"] = strtohex(XorEncrypt(json_encode(passkey), SScircuit.cipherkey)) // If there is no sender ID, set the default one. if(!sender_id && interface) sender_id = interface.hardware_id +/datum/netdata/proc/standard_format_data(primary, secondary, passkey) + data["data"] = primary + data["data_secondary"] = secondary + data["encrypted_passkey"] = passkey + +/datum/netdata/proc/json_to_data(json) + data = json_decode(json) + +/datum/netdata/proc/json_append_to_data(json) + data |= json_decode(json) + +/datum/netdata/proc/data_to_json() + return json_encode(data) /datum/netdata/proc/json_list_generation_admin() //for admin logs and such. . = list() @@ -40,9 +55,7 @@ . = list() .["recipient_ids"] = recipient_ids .["sender_id"] = sender_id - .["data"] = plaintext_data - .["data_secondary"] = plaintext_data_secondary - .["passkey"] = encrypted_passkey + .["data_list"] = data /datum/netdata/proc/generate_netlog() return "[json_encode(json_list_generation_netlog())]" diff --git a/code/modules/NTNet/network.dm b/code/modules/NTNet/network.dm index aee0dc1a2d..68b158dd65 100644 --- a/code/modules/NTNet/network.dm +++ b/code/modules/NTNet/network.dm @@ -1,6 +1,11 @@ /datum/ntnet var/network_id = "Network" - var/connected_interfaces_by_id = list() //id = datum/component/ntnet_interface + var/list/connected_interfaces_by_id = list() //id = datum/component/ntnet_interface + var/list/services_by_path = list() //type = datum/ntnet_service + var/list/services_by_id = list() //id = datum/ntnet_service + + var/list/autoinit_service_paths = list() //typepaths + var/list/relays = list() var/list/logs = list() @@ -32,7 +37,18 @@ stack_trace("Network [type] with ID [network_id] failed to register and has been deleted.") qdel(src) +/datum/ntnet/Destroy() + for(var/i in connected_interfaces_by_id) + var/datum/component/ntnet_interface/I = i + I.unregister_connection(src) + for(var/i in services_by_id) + var/datum/ntnet_service/S = i + S.disconnect(src, TRUE) + return ..() + /datum/ntnet/proc/interface_connect(datum/component/ntnet_interface/I) + if(connected_interfaces_by_id[I.hardware_id]) + return FALSE connected_interfaces_by_id[I.hardware_id] = I return TRUE @@ -43,15 +59,68 @@ /datum/ntnet/proc/find_interface_id(id) return connected_interfaces_by_id[id] +/datum/ntnet/proc/find_service_id(id) + return services_by_id[id] + +/datum/ntnet/proc/find_service_path(path) + return services_by_path[path] + +/datum/ntnet/proc/register_service(datum/ntnet_service/S) + if(!istype(S)) + return FALSE + if(services_by_path[S.type] || services_by_id[S.id]) + return FALSE + services_by_path[S.type] = S + services_by_id[S.id] = S + return TRUE + +/datum/ntnet/proc/unregister_service(datum/ntnet_service/S) + if(!istype(S)) + return FALSE + services_by_path -= S.type + services_by_id -= S.id + return TRUE + +/datum/ntnet/proc/create_service(type) + var/datum/ntnet_service/S = new type + if(!istype(S)) + return FALSE + . = S.connect(src) + if(!.) + qdel(S) + +/datum/ntnet/proc/destroy_service(type) + var/datum/ntnet_service/S = find_service_path(type) + if(!istype(S)) + return FALSE + . = S.disconnect(src) + if(.) + qdel(src) + /datum/ntnet/proc/process_data_transmit(datum/component/ntnet_interface/sender, datum/netdata/data) - data.network_id = src - log_data_transfer(data) if(!check_relay_operation()) return FALSE - for(var/i in data.recipient_ids) - var/datum/component/ntnet_interface/reciever = find_interface_id(i) + data.network_id = src + log_data_transfer(data) + var/list/datum/component/ntnet_interface/recieving = list() + if((length(data.recipient_ids == 1) && data.recipient_ids[1] == NETWORK_BROADCAST_ID) || data.recipient_ids == NETWORK_BROADCAST_ID) + data.broadcast = TRUE + for(var/i in connected_interfaces_by_id) + recieving |= connected_interfaces_by_id[i] + else + for(var/i in data.recipient_ids) + var/datum/component/ntnet_interface/reciever = find_interface_id(i) + recieving |= reciever + + for(var/i in recieving) + var/datum/component/ntnet_interface/reciever = i if(reciever) reciever.__network_recieve(data) + + for(var/i in services_by_id) + var/datum/ntnet_service/serv = services_by_id[i] + serv.ntnet_intercept(data, src, sender) + return TRUE /datum/ntnet/proc/check_relay_operation(zlevel) //can be expanded later but right now it's true/false. diff --git a/code/modules/NTNet/services/_service.dm b/code/modules/NTNet/services/_service.dm new file mode 100644 index 0000000000..8611c2d25d --- /dev/null +++ b/code/modules/NTNet/services/_service.dm @@ -0,0 +1,38 @@ +/datum/ntnet_service + var/name = "Unidentified Network Service" + var/id + var/list/networks_by_id = list() //Yes we support multinetwork services! + +/datum/ntnet_service/New() + var/datum/component/ntnet_interface/N = AddComponent(/datum/component/ntnet_interface, id, name, FALSE) + id = N.hardware_id + +/datum/ntnet_service/Destroy() + for(var/i in networks_by_id) + var/datum/ntnet/N = i + disconnect(N, TRUE) + networks_by_id = null + return ..() + +/datum/ntnet_service/proc/connect(datum/ntnet/net) + if(!istype(net)) + return FALSE + GET_COMPONENT(interface, /datum/component/ntnet_interface) + if(!interface.register_connection(net)) + return FALSE + if(!net.register_service(src)) + interface.unregister_connection(net) + return FALSE + networks_by_id[net.network_id] = net + return TRUE + +/datum/ntnet_service/proc/disconnect(datum/ntnet/net, force = FALSE) + if(!istype(net) || (!net.unregister_service(src) && !force)) + return FALSE + GET_COMPONENT(interface, /datum/component/ntnet_interface) + interface.unregister_connection(net) + networks_by_id -= net.network_id + return TRUE + +/datum/ntnet_service/proc/ntnet_intercept(datum/netdata/data, datum/ntnet/net, datum/component/ntnet_interface/sender) + return diff --git a/code/modules/integrated_electronics/subtypes/input.dm b/code/modules/integrated_electronics/subtypes/input.dm index 0309fcd55a..042d6a3616 100644 --- a/code/modules/integrated_electronics/subtypes/input.dm +++ b/code/modules/integrated_electronics/subtypes/input.dm @@ -150,7 +150,7 @@ /obj/item/integrated_circuit/input/slime_scanner name = "slime_scanner" - desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime." + desc = "A very small version of the xenobio analyser. This allows the machine to know every needed properties of slime. Output mutation list is non associative." icon_state = "medscan_adv" complexity = 12 inputs = list("target" = IC_PINTYPE_REF) @@ -259,7 +259,7 @@ /obj/item/integrated_circuit/input/gene_scanner name = "gene scanner" - desc = "This circuit will scan plant for traits and reagent genes." + desc = "This circuit will scan plant for traits and reagent genes. Output is non-associative." extended_desc = "This allows the machine to scan plants in trays for reagent and trait genes. \ It cannot scan seeds nor fruits, only plants." inputs = list( @@ -501,7 +501,7 @@ complexity = 6 name = "list advanced locator" desc = "This is needed for certain devices that demand list of names for a targets to act upon. This type locates something \ - that is standing in given radius up to 8 meters" + that is standing in given radius up to 8 meters. Output is non-associative. Input will only consider keys if associative." extended_desc = "The first pin requires a list of kinds of objects that you want the locator to acquire. It will locate nearby objects by name and description, \ and will then provide a list of all found objects which are similar. \ The second pin is a radius." @@ -700,8 +700,8 @@ will pulse whatever's connected to it. Pulsing the first activation pin will send a message. Message \ can be send to multiple recepients. Addresses must be separated with ; symbol." icon_state = "signal" - complexity = 4 - cooldown_per_use = 5 + complexity = 2 + cooldown_per_use = 1 inputs = list( "target NTNet addresses"= IC_PINTYPE_STRING, "data to send" = IC_PINTYPE_STRING, @@ -712,19 +712,20 @@ "address received" = IC_PINTYPE_STRING, "data received" = IC_PINTYPE_STRING, "secondary text received" = IC_PINTYPE_STRING, - "passkey" = IC_PINTYPE_STRING + "passkey" = IC_PINTYPE_STRING, + "is_broadcast" = IC_PINTYPE_BOOLEAN ) activators = list("send data" = IC_PINTYPE_PULSE_IN, "on data received" = IC_PINTYPE_PULSE_OUT) spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH action_flags = IC_ACTION_LONG_RANGE power_draw_per_use = 50 - var/datum/ntnet_connection/exonet = null var/address /obj/item/integrated_circuit/input/ntnet_packet/Initialize() . = ..() var/datum/component/ntnet_interface/net = LoadComponent(/datum/component/ntnet_interface) address = net.hardware_id + net.differentiate_broadcast = FALSE desc += "
This circuit's NTNet hardware address is: [address]" /obj/item/integrated_circuit/input/ntnet_packet/do_work() @@ -735,20 +736,63 @@ var/datum/netdata/data = new data.recipient_ids = splittext(target_address, ";") - data.plaintext_data = message - data.plaintext_data_secondary = text - data.encrypted_passkey = key + data.standard_format_data(message, text, key) ntnet_send(data) /obj/item/integrated_circuit/input/ntnet_recieve(datum/netdata/data) set_pin_data(IC_OUTPUT, 1, data.sender_id) - set_pin_data(IC_OUTPUT, 2, data.plaintext_data) - set_pin_data(IC_OUTPUT, 3, data.plaintext_data_secondary) - set_pin_data(IC_OUTPUT, 4, data.encrypted_passkey) + set_pin_data(IC_OUTPUT, 2, data.data["data"]) + set_pin_data(IC_OUTPUT, 3, data.data["data_secondary"]) + set_pin_data(IC_OUTPUT, 4, data.data["encrypted_passkey"]) + set_pin_data(IC_OUTPUT, 5, data.broadcast) push_data() activate_pin(2) +/obj/item/integrated_circuit/input/ntnet_advanced + name = "Low level NTNet transreciever" + desc = "Enables the sending and receiving of messages on NTNet via packet data protocol. Allows advanced control of message contents and signalling. Must use associative lists. Outputs associative list. Has a slower transmission rate than normal NTNet circuits, due to increased data processing complexity.." + extended_desc = "Data can be send or received using the second pin on each side, \ + with additonal data reserved for the third pin. When a message is received, the second activation pin \ + will pulse whatever's connected to it. Pulsing the first activation pin will send a message. Message \ + can be send to multiple recepients. Addresses must be separated with ; symbol." + icon_state = "signal" + complexity = 4 + cooldown_per_use = 10 + inputs = list( + "target NTNet addresses"= IC_PINTYPE_STRING, + "data" = IC_PINTYPE_LIST, + ) + outputs = list("recieved data" = IC_PINTYPE_LIST, "is_broadcast" = IC_PINTYPE_BOOLEAN) + activators = list("send data" = IC_PINTYPE_PULSE_IN, "on data received" = IC_PINTYPE_PULSE_OUT) + spawn_flags = IC_SPAWN_DEFAULT|IC_SPAWN_RESEARCH + action_flags = IC_ACTION_LONG_RANGE + power_draw_per_use = 50 + var/address + +/obj/item/integrated_circuit/input/ntnet_advanced/Initialize() + . = ..() + var/datum/component/ntnet_interface/net = LoadComponent(/datum/component/ntnet_interface) + address = net.hardware_id + net.differentiate_broadcast = FALSE + desc += "
This circuit's NTNet hardware address is: [address]" + +/obj/item/integrated_circuit/input/ntnet_advanced/do_work() + var/target_address = get_pin_data(IC_INPUT, 1) + var/list/message = get_pin_data(IC_INPUT, 2) + if(!islist(message)) + message = list() + var/datum/netdata/data = new + data.recipient_ids = splittext(target_address, ";") + data.data = message + ntnet_send(data) + +/obj/item/integrated_circuit/input/ntnet_advanced/ntnet_recieve(datum/netdata/data) + set_pin_data(IC_OUTPUT, 1, data.data) + set_pin_data(IC_OUTPUT, 2, data.broadcast) + push_data() + activate_pin(2) + //This circuit gives information on where the machine is. /obj/item/integrated_circuit/input/gps name = "global positioning system" diff --git a/code/modules/mob/living/simple_animal/bot/mulebot.dm b/code/modules/mob/living/simple_animal/bot/mulebot.dm index 64810424c1..4bbabbe1bb 100644 --- a/code/modules/mob/living/simple_animal/bot/mulebot.dm +++ b/code/modules/mob/living/simple_animal/bot/mulebot.dm @@ -61,6 +61,10 @@ set_id(suffix || id || "#[mulebot_count]") suffix = null +/mob/living/simple_animal/bot/mulebot/ComponentInitialize() + . = ..() + AddComponent(/datum/component/ntnet_interface) + /mob/living/simple_animal/bot/mulebot/Destroy() unload(0) qdel(wires) diff --git a/tgstation.dme b/tgstation.dme index 3c02f56858..2a5f1d1f8f 100755 --- a/tgstation.dme +++ b/tgstation.dme @@ -2140,6 +2140,7 @@ #include "code\modules\NTNet\netdata.dm" #include "code\modules\NTNet\network.dm" #include "code\modules\NTNet\relays.dm" +#include "code\modules\NTNet\services\_service.dm" #include "code\modules\orbit\orbit.dm" #include "code\modules\paperwork\clipboard.dm" #include "code\modules\paperwork\contract.dm"