diff --git a/code/__DEFINES/networks.dm b/code/__DEFINES/networks.dm
index 0aec59db9b..4d1e626fef 100644
--- a/code/__DEFINES/networks.dm
+++ b/code/__DEFINES/networks.dm
@@ -1 +1,7 @@
+<<<<<<< HEAD
#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"
+>>>>>>> 19ce08f... More integrated circuits and NTNET upgrade! (#37165)
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 5c4f485cfa..0369fd8cde 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 a61dc18d34..d6b4c16e9e 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."
@@ -688,8 +688,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,
@@ -700,19 +700,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()
@@ -723,20 +724,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 ad59ce7e34..eb39ef81de 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 cef4e37a84..9afff97f00 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"