[MIRROR] The Great Radio Rework: NTNET Part 1 of many. (#2384)

* The Great Radio Rework: NTNET Part 1 of many.

* Update airlock.dm

Co-authored-by: WarlockD <warlockd@gmail.com>
Co-authored-by: Gandalf2k15 <jzo123@hotmail.com>
This commit is contained in:
SkyratBot
2020-12-30 21:14:49 +00:00
committed by GitHub
co-authored by WarlockD Gandalf2k15
parent 12841a4c68
commit 4c5433d5cf
37 changed files with 1369 additions and 405 deletions
+14 -1
View File
@@ -806,8 +806,21 @@
//NTnet
///called on an object by its NTNET connection component on receive. (sending_id(number), sending_netname(text), data(datum/netdata))
///called on an object by its NTNET connection component on receive. (data(datum/netdata))
#define COMSIG_COMPONENT_NTNET_RECEIVE "ntnet_receive"
///called on an object by its NTNET connection component on a port update (hardware_id, port))
#define COMSIG_COMPONENT_NTNET_PORT_UPDATE "ntnet_port_update"
/// called when packet was accepted by the target (datum/netdata, error_code)
#define COMSIG_COMPONENT_NTNET_ACK "ntnet_ack"
/// called when packet was not acknoledged by the target (datum/netdata, error_code)
#define COMSIG_COMPONENT_NTNET_NAK "ntnet_nack"
// Some internal NTnet signals used on ports
///called on an object by its NTNET connection component on a port distruction (port, list/data))
#define COMSIG_COMPONENT_NTNET_PORT_DESTROYED "ntnet_port_destroyed"
///called on an object by its NTNET connection component on a port distruction (port, list/data))
#define COMSIG_COMPONENT_NTNET_PORT_UPDATED "ntnet_port_updated"
//Nanites
+91
View File
@@ -1,3 +1,94 @@
#define HID_RESTRICTED_END 101 //the first nonrestricted ID, automatically assigned on connection creation.
#define NETWORK_BROADCAST_ID "ALL"
/// To debug networks use this to check
//#define DEBUG_NETWORKS 1
/// We do some macro magic to make sure the strings are created at compile time rather than runtime
/// We do it this way so that if someone changes any of the names of networks we don't have to hunt down
/// all the constants though all the files for them. hurrah!
/// Ugh, couldn't get recursive stringafy to work in byond for some reason
#define NETWORK_NAME_COMBINE(L,R) ((L) + "." + (R))
/// Station network names. Used as the root networks for main parts of the station
#define __STATION_NETWORK_ROOT "SS13"
#define __CENTCOM_NETWORK_ROOT "CENTCOM"
#define __SYNDICATE_NETWORK_ROOT "SYNDI"
#define __LIMBO_NETWORK_ROOT "LIMBO" // Limbo is a dead network
/// various sub networks pieces
#define __NETWORK_LIMBO "LIMBO"
#define __NETWORK_TOOLS "TOOLS"
#define __NETWORK_REMOTES "REMOTES"
#define __NETWORK_AIRLOCKS "AIRLOCKS"
#define __NETWORK_DOORS "DOORS"
#define __NETWORK_ATMOS "ATMOS"
#define __NETWORK_SCUBBERS "AIRLOCKS"
#define __NETWORK_AIRALARMS "AIRALARMS"
#define __NETWORK_CONTROL "CONTROL"
#define __NETWORK_STORAGE "STORAGE"
#define __NETWORK_CARGO "CARGO"
#define __NETWORK_BOTS "BOTS"
#define __NETWORK_COMPUTER "COMPUTER"
#define __NETWORK_CARDS "CARDS"
/// Various combined subnetworks
#define NETWORK_DOOR_REMOTES NETWORK_NAME_COMBINE(__NETWORK_DOORS, __NETWORK_REMOTES)
#define NETWORK_DOOR_AIRLOCKS NETWORK_NAME_COMBINE(__NETWORK_DOORS, __NETWORK_AIRLOCKS)
#define NETWORK_ATMOS_AIRALARMS NETWORK_NAME_COMBINE(__NETWORK_ATMOS, __NETWORK_AIRALARMS)
#define NETWORK_ATMOS_SCUBBERS NETWORK_NAME_COMBINE(__NETWORK_ATMOS, __NETWORK_SCUBBERS)
#define NETWORK_CARDS NETWORK_NAME_COMBINE(__NETWORK_COMPUTER, __NETWORK_CARDS)
#define NETWORK_BOTS_CARGO NETWORK_NAME_COMBINE(__NETWORK_CARGO, __NETWORK_BOTS)
// Finally turn eveything into strings
#define STATION_NETWORK_ROOT __STATION_NETWORK_ROOT
#define CENTCOM_NETWORK_ROOT __CENTCOM_NETWORK_ROOT
#define SYNDICATE_NETWORK_ROOT __SYNDICATE_NETWORK_ROOT
#define LIMBO_NETWORK_ROOT __LIMBO_NETWORK_ROOT
/// Network name should be all caps and no punctuation except for _ and . between domains
/// This does a quick an dirty fix to a network name to make sure it works
/proc/simple_network_name_fix(name)
// can't make this as a define, some reason findtext(name,@"^[^\. ]+[A-Z0-9_\.]+[^\. ]+$") dosn't work
var/static/regex/check_regex = new(@"[ \-]{1}","g")
return check_regex.Replace(uppertext(name),"_")
/*
* Helper that verifies a network name is valid.
*
* A valid network name (ie, SS13.ATMOS.SCRUBBERS) is all caps, no spaces with periods between
* branches. Returns false if it doesn't meat this requirement
*
* Arguments:
* * name - network text name to check
*/
/proc/verify_network_name(name)
// can't make this as a define, some reason findtext(name,@"^[^\. ]+[A-Z0-9_\.]+[^\. ]+$") dosn't work
var/static/regex/check_regex = new(@"^(?=[^\. ]+)[A-Z0-9_\.]+[^\. ]+$")
return istext(name) && check_regex.Find(name)
/// Port protocol. A port is just a list with a few vars that are used to send signals
/// that something is refreshed or updated. These macros make it faster rather than
/// calling procs
#define NETWORK_PORT_DISCONNECTED(LIST) (!LIST || LIST["_disconnected"])
#define NETWORK_PORT_UPDATED(LIST) (LIST && !LIST["_disconnected"] && LIST["_updated"])
#define NETWORK_PORT_UPDATE(LIST) if(LIST) { LIST["_updated"] = TRUE }
#define NETWORK_PORT_CLEAR_UPDATE(LIST) if(LIST) { LIST["_updated"] = FALSE }
#define NETWORK_PORT_SET_UPDATE(LIST) if(LIST) { LIST["_updated"] = TRUE }
#define NETWORK_PORT_DISCONNECT(LIST) if(LIST) { LIST["_disconnected"] = TRUE }
/// Error codes
#define NETWORK_ERROR_OK null
#define NETWORK_ERROR_NOT_ON_NETWORK "network_error_not_on_network"
#define NETWORK_ERROR_BAD_NETWORK "network_error_bad_network"
#define NETWORK_ERROR_BAD_RECEIVER_ID "network_error_bad_receiver_id"
#define NETWORK_ERROR_UNAUTHORIZED "network_error_bad_unauthorized"
#define NETWORK_ERROR_BAD_TARGET_ID "network_error_bad_target_id"
+5 -4
View File
@@ -430,13 +430,14 @@ GLOBAL_LIST_EMPTY(colored_images)
GLOB.colored_images += shiny
/datum/controller/subsystem/air/proc/setup_template_machinery(list/atmos_machines)
for(var/A in atmos_machines)
var/obj/machinery/atmospherics/AM = A
var/obj/machinery/atmospherics/AM
for(var/A in 1 to atmos_machines.len)
AM = atmos_machines[A]
AM.atmosinit()
CHECK_TICK
for(var/A in atmos_machines)
var/obj/machinery/atmospherics/AM = A
for(var/A in 1 to atmos_machines.len)
AM = atmos_machines[A]
AM.build_network()
CHECK_TICK
+6 -5
View File
@@ -34,12 +34,13 @@ SUBSYSTEM_DEF(atoms)
var/count
var/list/mapload_arg = list(TRUE)
if(atoms)
count = atoms.len
for(var/I in atoms)
var/atom/A = I
for(var/I in 1 to count)
var/atom/A = atoms[I]
if(!(A.flags_1 & INITIALIZED_1))
InitAtom(I, mapload_arg)
InitAtom(A, mapload_arg)
CHECK_TICK
else
count = 0
@@ -55,8 +56,8 @@ SUBSYSTEM_DEF(atoms)
initialized = old_initialized
if(late_loaders.len)
for(var/I in late_loaders)
var/atom/A = I
for(var/I in 1 to late_loaders.len)
var/atom/A = late_loaders[I]
A.LateInitialize()
testing("Late initialized [late_loaders.len] atoms")
late_loaders.Cut()
+3 -2
View File
@@ -51,8 +51,9 @@ SUBSYSTEM_DEF(machines)
return
/datum/controller/subsystem/machines/proc/setup_template_powernets(list/cables)
for(var/A in cables)
var/obj/structure/cable/PC = A
var/obj/structure/cable/PC
for(var/A in 1 to cables.len)
PC = cables[A]
if(!PC.powernet)
var/datum/powernet/NewPN = new()
NewPN.add_cable(PC)
+511 -39
View File
@@ -1,51 +1,523 @@
PROCESSING_SUBSYSTEM_DEF(networks)
SUBSYSTEM_DEF(networks)
name = "Networks"
priority = FIRE_PRIORITY_NETWORKS
wait = 1
stat_tag = "NET"
wait = 5
flags = SS_KEEP_TIMING
init_order = INIT_ORDER_NETWORKS
var/datum/ntnet/station/station_network
var/assignment_hardware_id = HID_RESTRICTED_END
var/list/networks_by_id = list() //id = network
var/list/interfaces_by_id = list() //hardware id = component interface
var/resolve_collisions = TRUE
/datum/controller/subsystem/processing/networks/Initialize()
station_network = new
station_network.register_map_supremecy()
. = ..()
var/list/relays = list()
/// Legacy ntnet lookup for software. Should be changed latter so don't rely on this
/// being here.
var/datum/ntnet/station_root/station_network
var/datum/ntnet/station_root/syndie_network
var/list/network_initialize_queue = list()
/// all interfaces by their hardware address.
/// Do NOT use to verify a reciver_id is valid, use the network.root_devices for that
var/list/interfaces_by_hardware_id = list()
/// Area to network, network to area list
/// This is an associated list to quickly find an area using either its id or network
/// Used mainly to make sure all area id's are unique even if a mapper uses the same
/// area many times
var/list/area_network_lookup = list()
/datum/controller/subsystem/processing/networks/proc/register_network(datum/ntnet/network)
if(!networks_by_id[network.network_id])
networks_by_id[network.network_id] = network
return TRUE
/// List of networks using their fully qualified network name. Used for quick lookups
/// of networks for sending packets
var/list/networks = list()
/// List of the root networks starting at their root names. Used to find and/or build
/// network tress
var/list/root_networks = list()
// Why not list? Because its a Copy() every time we add a packet, and thats stupid.
var/datum/netdata/first = null // start of the queue. Pulled off in fire.
var/datum/netdata/last = null // end of the queue. pushed on by transmit
var/packet_count = 0
// packet stats
var/count_broadcasts_packets = 0 // count of broadcast packets sent
var/count_failed_packets = 0 // count of message fails
var/count_good_packets = 0
// Logs moved here
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
// High values make displaying logs much laggier.
var/setting_maxlogcount = 100
var/list/logs = list()
/// Random name search to make sure we have unique names.
/// DO NOT REMOVE NAMES HERE UNLESS YOU KNOW WHAT YOUR DOING
var/list/used_names = list()
/// You shouldn't need to do this. But mapping is async and there is no guarantee that Initialize
/// will run before these networks are dynamically created. So its here.
/datum/controller/subsystem/networks/PreInit()
/// Limbo network needs to be made at boot up for all error devices
new/datum/ntnet(LIMBO_NETWORK_ROOT)
station_network = new(STATION_NETWORK_ROOT)
syndie_network = new(SYNDICATE_NETWORK_ROOT)
/// As well as the station network incase something funny goes during startup
new/datum/ntnet(CENTCOM_NETWORK_ROOT)
/datum/controller/subsystem/networks/stat_entry(msg)
msg = "NET: QUEUE([packet_count]) FAILS([count_failed_packets]) BROADCAST([count_broadcasts_packets])"
return ..()
/datum/controller/subsystem/networks/Initialize()
station_network.register_map_supremecy() // sigh
assign_areas_root_ids(GLOB.sortedAreas) // setup area names before Initialize
station_network.build_software_lists()
syndie_network.build_software_lists()
// At round start, fix the network_id's so the station root is on them
initialized = TRUE
// Now when the objects Initialize they will join the right network
return ..()
/*
* Process incoming queued packet and return NAK/ACK signals
*
* This should only be called when you want the target object to process the NAK/ACK signal, usually
* during fire. At this point data.receiver_id has already been converted if it was a broadcast but
* is undefined in this function.
* Arguments:
* * receiver_id - text hardware id for the target device
* * data - packet to be sent
*/
/datum/controller/subsystem/networks/proc/_process_packet(receiver_id, datum/netdata/data)
/// Used only for sending NAK/ACK and error reply's
var/datum/component/ntnet_interface/sending_interface = interfaces_by_hardware_id[data.sender_id]
/// Check if the network_id is valid and if not send an error and return
var/datum/ntnet/target_network = networks[data.network_id]
if(!target_network)
count_failed_packets++
add_log("Bad target network '[data.network_id]'", null, data.sender_id)
if(!QDELETED(sending_interface))
SEND_SIGNAL(sending_interface.parent, COMSIG_COMPONENT_NTNET_NAK, data , NETWORK_ERROR_BAD_NETWORK)
return
/// Check if the receiver_id is in the network. If not send an error and return
var/datum/component/ntnet_interface/target_interface = target_network.root_devices[receiver_id]
if(QDELETED(target_interface))
count_failed_packets++
add_log("Bad target device '[receiver_id]'", target_network, data.sender_id)
if(!QDELETED(sending_interface))
SEND_SIGNAL(sending_interface.parent, COMSIG_COMPONENT_NTNET_NAK, data, NETWORK_ERROR_BAD_RECEIVER_ID)
return
// Check if we care about permissions. If we do check if we are allowed the message to be processed
if(data.passkey) // got to check permissions
var/obj/O = target_interface.parent
if(O)
if(!O.check_access_ntnet(data.passkey))
count_failed_packets++
add_log("Access denied to ([receiver_id]) from ([data.network_id])", target_network, data.sender_id)
if(!QDELETED(sending_interface))
SEND_SIGNAL(sending_interface.parent, COMSIG_COMPONENT_NTNET_NAK, data, NETWORK_ERROR_UNAUTHORIZED)
return
else
add_log("A access key message was sent to a non-device", target_network, data.sender_id)
if(!QDELETED(sending_interface))
SEND_SIGNAL(sending_interface.parent, COMSIG_COMPONENT_NTNET_NAK, data, NETWORK_ERROR_UNAUTHORIZED)
SEND_SIGNAL(target_interface.parent, COMSIG_COMPONENT_NTNET_RECEIVE, data)
// All is good, send the packet then send an ACK to the sender
if(!QDELETED(sending_interface))
SEND_SIGNAL(sending_interface.parent, COMSIG_COMPONENT_NTNET_ACK, data)
count_good_packets++
/// Helper define to make sure we pop the packet and qdel it
#define POP_PACKET(CURRENT) first = CURRENT.next; packet_count--; if(!first) { last = null; packet_count = 0; }; qdel(CURRENT);
/datum/controller/subsystem/networks/fire(resumed = 0)
var/datum/netdata/current
var/datum/component/ntnet_interface/target_interface
while(first)
current = first
/// Check if we are a list. If so process the list
if(islist(current.receiver_id)) // are we a broadcast list
var/list/receivers = current.receiver_id
var/receiver_id = receivers[receivers.len--] // pop it
_process_packet(receiver_id, current)
if(receivers.len == 0) // pop it if done
count_broadcasts_packets++
POP_PACKET(current)
else // else set up a broadcast or send a single targete
// check if we are sending to a network or to a single target
target_interface = interfaces_by_hardware_id[current.receiver_id]
if(target_interface) // a single sender id
_process_packet(current.receiver_id, current) // single target
POP_PACKET(current)
else // ok so lets find the network to send it too
var/datum/ntnet/net = networks[current.network_id] // get the sending network
net = net?.networks[current.receiver_id] // find the target network to broadcast
if(net) // we found it
current.receiver_id = net.collect_interfaces() // make a list of all the sending targets
else
// We got an error, the network is bad so send a NAK
target_interface = interfaces_by_hardware_id[current.sender_id]
if(!QDELETED(target_interface))
SEND_SIGNAL(target_interface.parent, COMSIG_COMPONENT_NTNET_NAK, current , NETWORK_ERROR_BAD_NETWORK)
POP_PACKET(current) // and get rid of it
if (MC_TICK_CHECK)
return
#undef POP_PACKET
/*
* Main function to queue a packet. As long as we have valid receiver_id and network_id we will take it
*
* Main queuing function for any message sent. if the data.receiver_id is null, then it will be broadcasted
* error checking is only done during the process this just throws it on the queue.
* Arguments:
* * data - packet to be sent
*/
/datum/controller/subsystem/networks/proc/transmit(datum/netdata/data)
data.next = null // sanity check
if(!last)
first = last = data
else
last.next = data
last = data
packet_count++
// We do error checking when the packet is sent
return NETWORK_ERROR_OK
/datum/controller/subsystem/networks/proc/check_relay_operation(zlevel=0) //can be expanded later but right now it's true/false.
for(var/i in relays)
var/obj/machinery/ntnet_relay/n = i
if(zlevel && n.z != zlevel)
continue
if(n.is_operational)
return TRUE
return FALSE
/datum/controller/subsystem/processing/networks/proc/unregister_network(datum/ntnet/network)
networks_by_id -= network.network_id
return TRUE
/datum/controller/subsystem/networks/proc/log_data_transfer( datum/netdata/data)
logs += "[station_time_timestamp()] - [data.generate_netlog()]"
if(logs.len > setting_maxlogcount)
logs = logs.Copy(logs.len - setting_maxlogcount, 0)
/datum/controller/subsystem/processing/networks/proc/register_interface(datum/component/ntnet_interface/D)
if(!interfaces_by_id[D.hardware_id])
interfaces_by_id[D.hardware_id] = D
return TRUE
return FALSE
/**
* Records a message into the station logging system for the network
*
* This CAN be read in station by personal so do not use it for game debugging
* during fire. At this point data.receiver_id has already been converted if it was a broadcast but
* is undefined in this function. It is also dumped to normal logs but remember players can read/intercept
* these messages
* Arguments:
* * log_string - message to log
* * network - optional, It can be a ntnet or just the text equivalent
* * hardware_id = optional, text, will look it up and return with the parent.name as well
*/
/datum/controller/subsystem/networks/proc/add_log(log_string, network = null , hardware_id = null)
set waitfor = FALSE // so process keeps running
var/list/log_text = list()
log_text += "\[[station_time_timestamp()]\]"
if(network)
var/datum/ntnet/net = network
if(!net)
net = networks[network]
if(net) // bad network?
log_text += "{[net.network_id]}"
else // bad network?
log_text += "{[network] *BAD*}"
/datum/controller/subsystem/processing/networks/proc/unregister_interface(datum/component/ntnet_interface/D)
interfaces_by_id -= D.hardware_id
return TRUE
if(hardware_id)
var/datum/component/ntnet_interface/conn = interfaces_by_hardware_id[hardware_id]
if(conn)
log_text += " ([hardware_id])[conn.parent]"
else
log_text += " ([hardware_id])*BAD ID*"
else
log_text += "*SYSTEM*"
log_text += " - "
log_text += log_string
log_string = log_text.Join()
/datum/controller/subsystem/processing/networks/proc/get_next_HID()
var/string = "[num2text(assignment_hardware_id++, 12)]"
return make_address(string)
logs.Add(log_string)
//log_telecomms("NetLog: [log_string]") // causes runtime on startup humm
/datum/controller/subsystem/processing/networks/proc/make_address(string)
if(!string)
return resolve_collisions? make_address("[num2text(rand(HID_RESTRICTED_END, 999999999), 12)]"):null
var/hex = md5(string)
if(!hex)
return //errored
. = "[copytext_char(hex, 1, 9)]" //16 ^ 8 possibilities I think.
if(interfaces_by_id[.])
return resolve_collisions? make_address("[num2text(rand(HID_RESTRICTED_END, 999999999), 12)]"):null
// We have too many logs, remove the oldest entries until we get into the limit
if(logs.len > setting_maxlogcount)
logs = logs.Copy(logs.len-setting_maxlogcount,0)
/**
* Removes all station logs for the current game
*/
/datum/controller/subsystem/networks/proc/purge_logs()
logs = list()
add_log("-!- LOGS DELETED BY SYSTEM OPERATOR -!-")
/**
* Updates the maximum amount of logs and purges those that go beyond that number
*
* Shouldn't been needed to be run by players but maybe admins need it?
* Arguments:
* * lognumber - new setting_maxlogcount count
*/
/datum/controller/subsystem/networks/proc/update_max_log_count(lognumber)
if(!lognumber)
return FALSE
// Trim the value if necessary
lognumber = max(MIN_NTNET_LOGS, min(lognumber, MAX_NTNET_LOGS))
setting_maxlogcount = lognumber
add_log("Configuration Updated. Now keeping [setting_maxlogcount] logs in system memory.")
/**
* Gives an area a root and a network_area_id
*
* When a device is added to the network on map load, it needs to know where it is.
* So that it is added to that ruins/base's network instead of the general station network
* This way people on the station cannot just hack Charlie's doors and visa versa. All area's
* "should" have this information and if not one is created from existing map tags or
* ruin template id's. This SHOULD run before the Initialize of a atom, or the root will not
* be put in the object.area
*
* An example on what the area.network_root_id does/
* Before Init: obj.network_id = "ATMOS.SCRUBBER" area.network_root_id="SS13_STATION" area.network_area_id = "BRIDGE"
* After Init: obj.network_id = "SS13_STATION.ATMOS.SCRUBBER" also obj.network_id = "SS13_STATION.AREA.BRIDGE"
*
* Arguments:
* * area - Area to modify the root id.
* * template - optional, map_template of that area
*/
/datum/controller/subsystem/networks/proc/lookup_area_root_id(area/A, datum/map_template/M=null)
/// Check if the area is valid and if it doesn't have a network root id.
if(!istype(A) || A.network_root_id != null)
return
/// If we are a ruin or a shuttle, we get our own network
if(M)
/// if we have a template, try to get the network id from the template
if(M.station_id && M.station_id != LIMBO_NETWORK_ROOT) // check if the template specifies it
A.network_root_id = simple_network_name_fix(M.station_id)
else if(istype(M, /datum/map_template/shuttle)) // if not, then check if its a shuttle type
var/datum/map_template/shuttle/T = M // we are a shuttle so use shuttle id
A.network_root_id = simple_network_name_fix(T.shuttle_id)
else if(istype(M,/datum/map_template/ruin)) // if not again, check if its a ruin type
var/datum/map_template/ruin/R = M
A.network_root_id = simple_network_name_fix(R.id)
if(!A.network_root_id) // not assigned? Then lets use some defaults
// Anything in Centcom is completely isolated
// Special case for holodecks.
if(istype(A,/area/holodeck))
A.network_root_id = "HOLODECK" // isolated from the station network
else if(SSmapping.level_trait(A.z, ZTRAIT_CENTCOM))
A.network_root_id = CENTCOM_NETWORK_ROOT
// Otherwise the default is the station
else
A.network_root_id = STATION_NETWORK_ROOT
/datum/controller/subsystem/networks/proc/assign_area_network_id(area/A, datum/map_template/M=null)
if(!istype(A))
return
if(!A.network_root_id)
lookup_area_root_id(A, M)
// finally set the network area id, bit copy paste from area Initialize
// This is done in case we have more than one area type, each area instance has its own network name
if(!A.network_area_id)
A.network_area_id = A.network_root_id + ".AREA." + simple_network_name_fix(A.name) // Make the string
if(!(A.area_flags & UNIQUE_AREA)) // if we aren't a unique area, make sure our name is different
A.network_area_id = SSnetworks.assign_random_name(5, A.network_area_id + "_") // tack on some garbage incase there are two area types
/datum/controller/subsystem/networks/proc/assign_areas_root_ids(list/areas, datum/map_template/M=null)
for(var/area/A in areas)
assign_area_network_id(A, M)
/**
* Converts a list of string's into a full network_id
*
* Converts a list of individual branches into a proper network id. Validates
* individual parts to make sure they are clean.
*
* ex. list("A","B","C") -> A.B.C
*
* Arguments:
* * tree - List of strings
*/
/datum/controller/subsystem/networks/proc/network_list_to_string(list/tree)
#ifdef DEBUG_NETWORKS
ASSERT(tree && tree.len > 0) // this should be obvious but JUST in case.
for(var/part in tree)
if(!verify_network_name(part) || findtext(name,".")!=0) // and no stray dots
stack_trace("network_list_to_string: Cannot create network with ([part]) of ([tree.Join(".")])")
break
#endif
return tree.Join(".")
/**
* Converts string into a list of network branches
*
* Converts a a proper network id into a list of the individual branches
*
* ex. A.B.C -> list("A","B","C")
*
* Arguments:
* * tree - List of strings
*/
/datum/controller/subsystem/networks/proc/network_string_to_list(name)
#ifdef DEBUG_NETWORKS
if(!verify_network_name(name))
stack_trace("network_string_to_list: [name] IS INVALID")
#endif
return splittext(name,".") // should we do a splittext_char? I doubt we really need unicode in network names
/**
* Hard creates a network. Helper function for create_network_simple and create_network
*
* Hard creates a using a list of branches and returns. No error checking as it should
* of been done before this call
*
* Arguments:
* * network_tree - list,text List of branches of network
*/
/datum/controller/subsystem/networks/proc/_hard_create_network(list/network_tree)
var/network_name_part = network_tree[1]
var/network_id = network_name_part
var/datum/ntnet/parent = root_networks[network_name_part]
var/datum/ntnet/network
if(!parent) // we have no network root? Must be mapload of a ruin or such
parent = new(network_name_part)
// go up the branches, creating nodes
for(var/i in 2 to network_tree.len)
network_name_part = network_tree[i]
network = parent.children[network_name_part]
network_id += "." + network_name_part
if(!network)
network = new(network_id, network_name_part, parent)
parent = network
return network
/**
* Creates or finds a network anywhere in the world using a fully qualified name
*
* This is the simple case finding of a network in the world. It must take a full
* qualified network name and it will either return an existing network or build
* a new one from scratch. We must be able to create names on the fly as there is
* no way for the map loader to tell us ahead of time what networks to create or
* use for any maps or templates. So this thing will throw silent mapping errors
* and log them, but will always return a network for something.
*
* Arguments:
* * network_id - text, Fully qualified network name
*/
/datum/controller/subsystem/networks/proc/create_network_simple(network_id)
var/datum/ntnet/network = networks[network_id]
if(network!=null)
return network // don't worry about it
/// Checks to make sure the network is valid. We log BOTH to mapping and telecoms
/// so if your checking for network errors you can find it in mapping to (because its their fault!)
if(!verify_network_name(network_id))
log_mapping("create_network_simple: [network_id] IS INVALID, replacing with LIMBO")
log_telecomms("create_network_simple: [network_id] IS INVALID, replacing with LIMBO")
return networks[LIMBO_NETWORK_ROOT]
var/list/network_tree = network_string_to_list(network_id)
if(!network_tree || network_tree.len == 0)
log_mapping("create_network_simple: [network_id] IS INVALID, replacing with LIMBO")
log_telecomms("create_network_simple: [network_id] IS INVALID, replacing with LIMBO")
return networks[LIMBO_NETWORK_ROOT]
network = _hard_create_network(network_tree)
#ifdef DEBUG_NETWORKS
if(!network)
CRASH("NETWORK CANNOT BE NULL")
#endif
log_telecomms("create_network_simple: created final [network.network_id]")
return network // and we are done!
/**
* Creates or finds a network anywhere in the world using bits of text
*
* This works the same as create_network_simple however it allows the addition
* of qualified network names. So you can call it with a root_id and a sub
* network. However this function WILL return null if it cannot be created
* so it should be used with error checking is involved.
*
* ex. create_network("ROOT_NETWORK", "ATMOS.SCRUBBERS") -> ROOT_NETWORK.ATMOS.SCRUBBERS
*
* Arguments:
* * tree - List of string
*/
/datum/controller/subsystem/networks/proc/create_network(...)
var/list/network_tree = list()
for(var/i in 1 to args.len)
var/part = args[i]
#ifdef DEBUG_NETWORKS
if(!part || !istext(part))
/// stack trace here because this is a bad error
stack_trace("create_network: We only take text on [part] index [i]")
return null
#endif
network_tree += network_string_to_list(part)
var/datum/ntnet/network = _hard_create_network(network_tree)
log_telecomms("create_network: created final [network.network_id]")
return network
/**
* Generate a hardware id for devices.
*
* Creates a 32 bit hardware id for network devices. This is random so masking
* the number won't make routing "easier" (Think Ethernet) It does check if
* an existing device has the number but will NOT assign it as thats
* up to the collar
*
* Returns (string) The generated name
*/
/datum/controller/subsystem/networks/proc/get_next_HID()
do
var/string = md5("[num2text(rand(HID_RESTRICTED_END, 999999999), 12)]")
if(!string)
log_runtime("Could not generagea m5 hash from address, problem with md5?")
return //errored
. = "[copytext_char(string, 1, 9)]" //16 ^ 8 possibilities I think.
while(interfaces_by_hardware_id[.])
/**
* Generate a name devices
*
* Creates a randomly generated tag or name for devices or anything really
* it keeps track of a special list that makes sure no name is used more than
* once
*
* args:
* * len (int)(Optional) Default=5 The length of the name
* * prefix (string)(Optional) static text in front of the random name
* * postfix (string)(Optional) static text in back of the random name
* Returns (string) The generated name
*/
/datum/controller/subsystem/networks/proc/assign_random_name(len=5, prefix="", postfix="")
var/static/valid_chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789"
var/list/new_name = list()
var/text
// machine id's should be fun random chars hinting at a larger world
do
new_name.Cut()
new_name += prefix
for(var/i = 1 to len)
new_name += valid_chars[rand(1,length(valid_chars))]
new_name += postfix
text = new_name.Join()
while(used_names[text])
used_names[text] = TRUE
return text
+134 -57
View File
@@ -1,66 +1,143 @@
//Thing meant for allowing datums and objects to access an NTnet network datum.
/datum/proc/ntnet_receive(datum/netdata/data)
return
/datum/proc/ntnet_receive_broadcast(datum/netdata/data)
return
/datum/proc/ntnet_send(datum/netdata/data, netid)
/*
* Helper function that does 90% of the work in sending a packet
*
* This function gets the component and builds a packet so the sending
* person doesn't have to lift a finger. Just create a netdata datum or even
* just a list and it will send it on its merry way.
*
* Arguments:
* * packet_data - Either a list() or a /datum/netdata. If its netdata, the other args are ignored
* * target_id - Target hardware id or network_id for this packet. If we are a network id, then its
broadcasted to that network.
* * passkey - Authentication for the packet. If the target doesn't authenticate the packet is dropped
*/
/datum/proc/ntnet_send(packet_data, target_id = null, passkey = null)
var/datum/netdata/data = packet_data
if(!data) // check for easy case
if(!islist(packet_data) || target_id == null)
stack_trace("ntnet_send: Bad packet creation") // hard fail as its runtime fault
return
data = new(packet_data)
data.receiver_id = target_id
data.passkey = passkey
if(data.receiver_id == null)
return NETWORK_ERROR_BAD_TARGET_ID
var/datum/component/ntnet_interface/NIC = GetComponent(/datum/component/ntnet_interface)
if(!NIC)
return FALSE
return NIC.__network_send(data, netid)
return NETWORK_ERROR_NOT_ON_NETWORK
data.sender_id = NIC.hardware_id
data.network_id = NIC.network.network_id
return SSnetworks.transmit(data)
/*
* # /datum/component/ntnet_interface
*
* This component connects a obj/datum to the station network.
*
* Anything can be connected to the station network. Any obj can auto connect as long as its network_id
* var is set before the parent new is called. This allows map objects to be connected. Technically the
* component only handles getting you on the network while SSnetwork and datum/ntnet does all the real work.
* There are quite a few stack_traces in here. This is because error checking should be done before this component is
* added. Also, there never should be a component that has no network. If it needs a network assign it to LIMBO
*
*/
/datum/component/ntnet_interface
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_receive. NOT RECOMMENDED.
var/hardware_id = null // text. this is the true ID. do not change this. stuff like ID forgery can be done manually.
var/id_tag = null // named tag, mainly used to look up mapping objects
var/datum/ntnet/network = null // network we are on, we MUST be on a network or there is no point in this component
var/list/registered_sockets = list()// list of ports opened up on devices
var/list/alias = list() // if we live in more than one network branch
/**
* Initialize for the interface
*
* Assigns a hardware id and gets your object onto the network
*
* Arguments:
* * network_name - Fully qualified network id of the network we are joining
* * network_tag - The objects id_tag. Used for finding the device at mapload time
*/
/datum/component/ntnet_interface/Initialize(network_name, network_tag = null)
if(network_name == null || !istext(network_name))
log_telecomms("ntnet_interface/Initialize: Bad network '[network_name]' for '[parent]', going to limbo it")
network_name = LIMBO_NETWORK_ROOT
// Tags cannot be numbers and must be unique over the world
if(network_tag != null && !istext(network_tag))
// numbers are not allowed as lookups for interfaces
log_telecomms("Tag cannot be a number? '[network_name]' for '[parent]', going to limbo it")
network_tag = "BADTAG_" + network_tag
hardware_id = SSnetworks.get_next_HID()
id_tag = network_tag
SSnetworks.interfaces_by_hardware_id[hardware_id] = src
network = SSnetworks.create_network_simple(network_name)
network.add_interface(src)
/**
* Create a port for this interface
*
* A port is basicity a shared associated list() with some values that
* indicated its been updated. (see _DEFINES/network.dm). By using a shared
* we don't have to worry about qdeling this object if it goes out of scope.
*
* Once a port is created any number of devices can use the port, however only
* the creating interface can disconnect it.
*
* Arguments:
* * port - text, Name of the port installed on this interface
* * data - list, shared list of data. Don't put objects in this
*/
/datum/component/ntnet_interface/proc/register_port(port, list/data)
if(!port || !length(data))
stack_trace("port is null or data is empty")
return
if(registered_sockets[port])
stack_trace("port already regestered")
return
data["_updated"] = FALSE
registered_sockets[port] = data
/**
* Disconnects an existing port in the interface
*
* Removes a port from this interface and marks it that its
* has been disconnected
*
* Arguments:
* * port - text, Name of the port installed on this interface
* * data - list, shared list of data. Don't put objects in this
*/
/datum/component/ntnet_interface/proc/deregister_port(port)
if(registered_sockets[port]) // should I runtime if this isn't in here?
var/list/datalink = registered_sockets[port]
NETWORK_PORT_DISCONNECT(datalink)
// this should remove all outstanding ports
registered_sockets.Remove(port)
/**
* Connect to a port on this interface
*
* Returns the shared list that this interface uses to send
* data though a port.
*
* Arguments:
* * port - text, Name of the port installed on this interface
*/
/datum/component/ntnet_interface/proc/connect_port(port)
return registered_sockets[port]
/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
if(!SSnetworks.register_interface(src))
. = COMPONENT_INCOMPATIBLE
CRASH("Unable to register NTNet interface. Interface deleted.")
if(autoconnect_station_network)
register_connection(SSnetworks.station_network)
/datum/component/ntnet_interface/Destroy()
unregister_all_connections()
SSnetworks.unregister_interface(src)
network.remove_interface(src, TRUE)
SSnetworks.interfaces_by_hardware_id.Remove(hardware_id)
for(var/port in registered_sockets)
var/list/datalink = registered_sockets[port]
NETWORK_PORT_DISCONNECT(datalink)
registered_sockets.Cut()
return ..()
/datum/component/ntnet_interface/proc/__network_receive(datum/netdata/data) //Do not directly proccall!
SEND_SIGNAL(parent, COMSIG_COMPONENT_NTNET_RECEIVE, data)
if(differentiate_broadcast && data.broadcast)
parent.ntnet_receive_broadcast(data)
else
parent.ntnet_receive(data)
/datum/component/ntnet_interface/proc/__network_send(datum/netdata/data, netid) //Do not directly proccall!
if(netid)
if(networks_connected_by_id[netid])
var/datum/ntnet/net = networks_connected_by_id[netid]
return net.process_data_transmit(src, data)
return FALSE
for(var/i in networks_connected_by_id)
var/datum/ntnet/net = networks_connected_by_id[i]
net.process_data_transmit(src, data)
return TRUE
/datum/component/ntnet_interface/proc/register_connection(datum/ntnet/net)
if(net.interface_connect(src))
networks_connected_by_id[net.network_id] = net
return TRUE
/datum/component/ntnet_interface/proc/unregister_all_connections()
for(var/i in networks_connected_by_id)
unregister_connection(networks_connected_by_id[i])
return TRUE
/datum/component/ntnet_interface/proc/unregister_connection(datum/ntnet/net)
net.interface_disconnect(src)
networks_connected_by_id -= net.network_id
return TRUE
+1
View File
@@ -1321,6 +1321,7 @@ NOTE: there are two lists of areas in the end of this file: centcom and station
ambientsounds = list('sound/ambience/ambisin2.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/signal.ogg', 'sound/ambience/ambigen10.ogg', 'sound/ambience/ambitech.ogg',\
'sound/ambience/ambitech2.ogg', 'sound/ambience/ambitech3.ogg', 'sound/ambience/ambimystery.ogg')
airlock_wires = /datum/wires/airlock/engineering
network_root_id = STATION_NETWORK_ROOT // They should of unpluged the router before they left
/area/tcommsat/computer
name = "Telecomms Control Room"
+13 -3
View File
@@ -71,10 +71,14 @@
///This datum, if set, allows terrain generation behavior to be ran on Initialize()
var/datum/map_generator/map_generator
/// Default network root for this area aka station, lavaland, etc
var/network_root_id = null
/// Area network id when you want to find all devices hooked up to this area
var/network_area_id = null
///Used to decide what kind of reverb the area makes sound have
var/sound_environment = SOUND_ENVIRONMENT_NONE
/**
* A list of teleport locations
*
@@ -120,7 +124,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
power_usage = new /list(AREA_USAGE_LEN) // Some atoms would like to use power in Initialize()
return ..()
/**
/*
* Initalize this area
*
* intializes the dynamic area lighting and also registers the area with the z level via
@@ -128,7 +132,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
*
* returns INITIALIZE_HINT_LATELOAD
*/
/area/Initialize()
/area/Initialize(mapload)
icon_state = ""
if(requires_power)
@@ -146,6 +150,7 @@ GLOBAL_LIST_EMPTY(teleportlocs)
if(dynamic_lighting == DYNAMIC_LIGHTING_IFSTARLIGHT)
dynamic_lighting = CONFIG_GET(flag/starlight) ? DYNAMIC_LIGHTING_ENABLED : DYNAMIC_LIGHTING_DISABLED
. = ..()
blend_mode = BLEND_MULTIPLY // Putting this in the constructor so that it stops the icons being screwed up in the map editor.
@@ -155,6 +160,11 @@ GLOBAL_LIST_EMPTY(teleportlocs)
reg_in_areas_in_z()
if(!mapload)
if(!network_root_id)
network_root_id = STATION_NETWORK_ROOT // default to station root because this might be created with a blueprint
SSnetworks.assign_area_network_id(src)
return INITIALIZE_HINT_LATELOAD
/**
+1
View File
@@ -31,3 +31,4 @@ Unused icons for new areas are "awaycontent1" ~ "awaycontent30"
dynamic_lighting = DYNAMIC_LIGHTING_DISABLED
var/pacifist = TRUE // if when you enter this zone, you become a pacifist or not
var/death = FALSE // if when you enter this zone, you die
network_root_id = "VR"
+10 -2
View File
@@ -1,6 +1,10 @@
// CENTCOM
// Side note, be sure to change the network_root_id of any areas that are not a part of centcom
// and just using the z space as safe harbor. It shouldn't matter much as centcom z is isolated
// from everything anyway
/area/centcom
name = "CentCom"
icon_state = "centcom"
@@ -47,7 +51,7 @@
var/loading_id = ""
/area/centcom/supplypod/loading/Initialize()
. = ..()
. = ..()
if(!loading_id)
CRASH("[type] created without a loading_id")
if(GLOB.supplypod_loading_bays[loading_id])
@@ -121,6 +125,7 @@
has_gravity = STANDARD_GRAVITY
area_flags = VALID_TERRITORY | UNIQUE_AREA | NOTELEPORT
flags_1 = NONE
network_root_id = "MAGIC_NET"
//Abductors
/area/abductor_ship
@@ -130,6 +135,7 @@
area_flags = VALID_TERRITORY | UNIQUE_AREA | NOTELEPORT
has_gravity = STANDARD_GRAVITY
flags_1 = NONE
network_root_id = "ALIENS"
//Syndicates
/area/syndicate_mothership
@@ -140,16 +146,18 @@
area_flags = VALID_TERRITORY | UNIQUE_AREA | NOTELEPORT
flags_1 = NONE
ambientsounds = HIGHSEC
network_root_id = SYNDICATE_NETWORK_ROOT
/area/syndicate_mothership/control
name = "Syndicate Control Room"
icon_state = "syndie-control"
dynamic_lighting = DYNAMIC_LIGHTING_FORCED
network_root_id = SYNDICATE_NETWORK_ROOT
/area/syndicate_mothership/elite_squad
name = "Syndicate Elite Squad"
icon_state = "syndie-elite"
network_root_id = SYNDICATE_NETWORK_ROOT
//CAPTURE THE FLAG
/area/ctf
+1 -1
View File
@@ -8,7 +8,7 @@
var/obj/machinery/computer/holodeck/linked
var/restricted = FALSE // if true, program goes on emag list
network_root_id = "HOLODECK"
/*
Power tracking: Use the holodeck computer's power grid
Asserts are to avoid the inevitable infinite loops
+1 -22
View File
@@ -718,28 +718,6 @@
return TRUE
return ..()
/**
* Generate a name devices
*
* Creates a randomly generated tag or name for devices5
* The length of the generated name can be set by passing in an int
* args:
* * len (int)(Optional) Default=5 The length of the name
* Returns (string) The generated name
*/
/obj/machinery/proc/assign_random_name(len=5)
var/list/new_name = list()
// machine id's should be fun random chars hinting at a larger world
for(var/i = 1 to len)
switch(rand(1,3))
if(1)
new_name += ascii2text(rand(65, 90)) // A - Z
if(2)
new_name += ascii2text(rand(97,122)) // a - z
if(3)
new_name += ascii2text(rand(48, 57)) // 0 - 9
return new_name.Join()
/**
* Alerts the AI that a hack is in progress.
*
@@ -750,3 +728,4 @@
var/alertstr = "<span class='userdanger'>Network Alert: Hacking attempt detected[get_area(src)?" in [get_area_name(src, TRUE)]":". Unable to pinpoint location"].</span>"
for(var/mob/living/silicon/ai/AI in GLOB.player_list)
to_chat(AI, alertstr)
-2
View File
@@ -2,7 +2,6 @@
// This code allows for airlocks to be controlled externally by setting an id_tag and comm frequency (disables ID access)
/obj/machinery/door/airlock
var/id_tag
var/frequency
var/datum/radio_frequency/radio_connection
@@ -92,7 +91,6 @@
power_channel = AREA_USAGE_ENVIRON
var/id_tag
var/master_tag
var/frequency = FREQ_AIRLOCK_CONTROL
@@ -10,7 +10,6 @@
var/on = TRUE
var/id_tag
var/frequency = FREQ_ATMOS_STORAGE
var/datum/radio_frequency/radio_connection
+22 -19
View File
@@ -15,6 +15,20 @@
shock - has a chance of electrocuting its target.
*/
/// Overlay cache. Why isn't this just in /obj/machinery/door/airlock? Because its used just a
/// tiny bit in door_assembly.dm Refactored so you don't have to make a null copy of airlock
/// to get to the damn thing
/// Someone, for the love of god, profile this. Is there a reason to cache mutable_appearance
/// if so, why are we JUST doing the airlocks when we can put this in mutable_appearance.dm for
/// everything
/proc/get_airlock_overlay(icon_state, icon_file)
var/static/list/airlock_overlays = list()
var/iconkey = "[icon_state][icon_file]"
if((!(. = airlock_overlays[iconkey])))
. = airlock_overlays[iconkey] = mutable_appearance(icon_file, icon_state)
// Before you say this is a bad implmentation, look at what it was before then ask yourself
// "Would this be better with a global var"
// Wires for the airlock are located in the datum folder, inside the wires datum folder.
#define AIRLOCK_CLOSED 1
@@ -101,7 +115,7 @@
flags_1 = RAD_PROTECT_CONTENTS_1 | RAD_NO_CONTAMINATE_1
rad_insulation = RAD_MEDIUM_INSULATION
var/static/list/airlock_overlays = list()
network_id = NETWORK_DOOR_AIRLOCKS
/obj/machinery/door/airlock/Initialize()
. = ..()
@@ -127,6 +141,7 @@
diag_hud_set_electrified()
RegisterSignal(src, COMSIG_MACHINERY_BROKEN, .proc/on_break)
RegisterSignal(src, COMSIG_COMPONENT_NTNET_RECEIVE, .proc/ntnet_receive)
return INITIALIZE_HINT_LATELOAD
@@ -159,9 +174,6 @@
wires.cut(WIRE_AI)
update_icon()
/obj/machinery/door/airlock/ComponentInitialize()
. = ..()
AddComponent(/datum/component/ntnet_interface)
/obj/machinery/door/airlock/connect_to_shuttle(obj/docking_port/mobile/port, obj/docking_port/stationary/dock)
if(id_tag)
@@ -204,18 +216,14 @@
/obj/machinery/door/airlock/check_access_ntnet(datum/netdata/data)
return !requiresID() || ..()
/obj/machinery/door/airlock/ntnet_receive(datum/netdata/data)
/obj/machinery/door/airlock/proc/ntnet_receive(datum/source, datum/netdata/data)
// Check if the airlock is powered and can accept control packets.
if(!hasPower() || !canAIControl())
return
// Check packet access level.
if(!check_access_ntnet(data))
return
// Handle received packet.
var/command = lowertext(data.data["data"])
var/command_value = lowertext(data.data["data_secondary"])
var/command = data.data["data"]
var/command_value = data.data["data_secondary"]
switch(command)
if("open")
if(command_value == "on" && !density)
@@ -243,6 +251,7 @@
if("emergency")
if(command_value == "on" && emergency)
return
if(command_value == "off" && !emergency)
@@ -586,14 +595,6 @@
check_unres()
*/
/proc/get_airlock_overlay(icon_state, icon_file)
var/obj/machinery/door/airlock/A
pass(A) //suppress unused warning
var/list/airlock_overlays = A.airlock_overlays
var/iconkey = "[icon_state][icon_file]"
if((!(. = airlock_overlays[iconkey])))
. = airlock_overlays[iconkey] = mutable_appearance(icon_file, icon_state)
//SKYRAT EDIT CHANGE BEGIN - AESTHETICS
/obj/machinery/door/airlock/proc/check_unres() //unrestricted sides. This overlay indicates which directions the player can access even without an ID
if(hasPower() && unres_sides)
@@ -615,6 +616,8 @@
add_overlay(I)
/* - SKYRAT ORIGINAL
=======
>>>>>>> 56345975ba6 (The Great Radio Rework: NTNET Part 1 of many. (#54462))
/obj/machinery/door/airlock/proc/check_unres() //unrestricted sides. This overlay indicates which directions the player can access even without an ID
if(hasPower() && unres_sides)
if(unres_sides & NORTH)
+5 -10
View File
@@ -16,6 +16,7 @@
pass_flags_self = PASSGLASS
CanAtmosPass = ATMOS_PASS_PROC
interaction_flags_machine = INTERACT_MACHINE_WIRES_IF_OPEN | INTERACT_MACHINE_ALLOW_SILICON | INTERACT_MACHINE_OPEN_SILICON | INTERACT_MACHINE_REQUIRES_SILICON | INTERACT_MACHINE_OPEN
network_id = NETWORK_DOOR_AIRLOCKS
var/obj/item/electronics/airlock/electronics = null
var/reinf = 0
var/shards = 2
@@ -38,9 +39,7 @@
if(cable)
debris += new /obj/item/stack/cable_coil(src, cable)
/obj/machinery/door/window/ComponentInitialize()
. = ..()
AddComponent(/datum/component/ntnet_interface)
RegisterSignal(src, COMSIG_COMPONENT_NTNET_RECEIVE, .proc/ntnet_receive)
/obj/machinery/door/window/Destroy()
density = FALSE
@@ -309,18 +308,14 @@
/obj/machinery/door/window/check_access_ntnet(datum/netdata/data)
return !requiresID() || ..()
/obj/machinery/door/window/ntnet_receive(datum/netdata/data)
/obj/machinery/door/window/proc/ntnet_receive(datum/source, datum/netdata/data)
// Check if the airlock is powered.
if(!hasPower())
return
// Check packet access level.
if(!check_access_ntnet(data))
return
// Handle received packet.
var/command = lowertext(data.data["data"])
var/command_value = lowertext(data.data["data_secondary"])
var/command = data.data["data"]
var/command_value = data.data["data_secondary"]
switch(command)
if("open")
if(command_value == "on" && !density)
@@ -204,7 +204,6 @@
power_channel = AREA_USAGE_ENVIRON
// Setup parameters only
var/id_tag
var/exterior_door_tag
var/interior_door_tag
var/airpump_tag
+27 -17
View File
@@ -1,6 +1,6 @@
#define WAND_OPEN "Open Door"
#define WAND_BOLT "Toggle Bolts"
#define WAND_EMERGENCY "Toggle Emergency Access"
#define WAND_OPEN "open"
#define WAND_BOLT "bolt"
#define WAND_EMERGENCY "emergency"
/obj/item/door_remote
icon_state = "gangtool-white"
@@ -14,13 +14,31 @@
var/mode = WAND_OPEN
var/region_access = 1 //See access.dm
var/list/access_list
network_id = NETWORK_DOOR_REMOTES
/obj/item/door_remote/Initialize()
. = ..()
access_list = get_region_accesses(region_access)
AddComponent(/datum/component/ntnet_interface)
RegisterSignal(src, COMSIG_COMPONENT_NTNET_NAK, .proc/bad_signal)
RegisterSignal(src, COMSIG_COMPONENT_NTNET_ACK, .proc/good_signal)
/obj/item/door_remote/proc/bad_signal(datum/source, datum/netdata/data, error_code)
if(QDELETED(data.user))
return // can't send a message to a missing user
if(error_code == NETWORK_ERROR_UNAUTHORIZED)
to_chat(data.user, "<span class='notice'>This remote is not authorized to modify this door.</span>")
else
to_chat(data.user, "<span class='notice'>Error: [error_code]</span>")
/obj/item/door_remote/proc/good_signal(datum/source, datum/netdata/data, error_code)
if(QDELETED(data.user))
return
var/toggled = data.data["data"]
to_chat(data.user, "<span class='notice'>Door [toggled] toggled</span>")
/obj/item/door_remote/attack_self(mob/user)
var/static/list/desc = list(WAND_OPEN = "Open Door", WAND_BOLT = "Toggle Bolts", WAND_EMERGENCY = "Toggle Emergency Access")
switch(mode)
if(WAND_OPEN)
mode = WAND_BOLT
@@ -28,7 +46,7 @@
mode = WAND_EMERGENCY
if(WAND_EMERGENCY)
mode = WAND_OPEN
to_chat(user, "<span class='notice'>Now in mode: [mode].</span>")
to_chat(user, "<span class='notice'>Now in mode: [desc[mode]].</span>")
// Airlock remote works by sending NTNet packets to whatever it's pointed at.
/obj/item/door_remote/afterattack(atom/A, mob/user)
@@ -38,20 +56,12 @@
if(!target_interface)
return
user.set_machine(user)
// Generate a control packet.
var/datum/netdata/data = new
data.recipient_ids = list(target_interface.hardware_id)
switch(mode)
if(WAND_OPEN)
data.data["data"] = "open"
if(WAND_BOLT)
data.data["data"] = "bolt"
if(WAND_EMERGENCY)
data.data["data"] = "emergency"
data.data["data_secondary"] = "toggle"
var/datum/netdata/data = new(list("data" = mode,"data_secondary" = "toggle"))
data.receiver_id = target_interface.hardware_id
data.passkey = access_list
data.user = user // for responce message
ntnet_send(data)
+22 -1
View File
@@ -39,13 +39,20 @@
vis_flags = VIS_INHERIT_PLANE //when this be added to vis_contents of something it inherit something.plane, important for visualisation of obj in openspace.
/// Map tag for something. Tired of it being used on snowflake items. Moved here for some semblance of a standard.
/// Next pr after the network fix will have me refactor door interactions, so help me god.
var/id_tag = null
/// Network id. If set it can be found by either its hardware id or by the id tag if thats set. It can also be
/// broadcasted to as long as the other guys network is on the same branch or above.
var/network_id = null
/obj/vv_edit_var(vname, vval)
if(vname == NAMEOF(src, obj_flags))
if ((obj_flags & DANGEROUS_POSSESSION) && !(vval & DANGEROUS_POSSESSION))
return FALSE
return ..()
/obj/Initialize()
/obj/Initialize(mapload)
if (islist(armor))
armor = getArmor(arglist(armor))
else if (!armor)
@@ -70,6 +77,20 @@
var/turf/T = loc
T.add_blueprints_preround(src)
if(network_id)
var/area/A = get_area(src)
if(A)
if(!A.network_root_id)
log_telecomms("Area '[A.name]([REF(A)])' has no network network_root_id, force assigning in object [src]([REF(src)])")
SSnetworks.lookup_area_root_id(A)
network_id = NETWORK_NAME_COMBINE(A.network_root_id, network_id) // I regret nothing!!
else
log_telecomms("Created [src]([REF(src)] in nullspace, assuming network to be in station")
network_id = NETWORK_NAME_COMBINE(STATION_NETWORK_ROOT, network_id) // I regret nothing!!
AddComponent(/datum/component/ntnet_interface, network_id, id_tag)
/// Needs to run before as ComponentInitialize runs after this statement...why do we have ComponentInitialize again?
/obj/Destroy(force=FALSE)
if(!ismachinery(src))
STOP_PROCESSING(SSobj, src) // TODO: Have a processing bitflag to reduce on unnecessary loops through the processing lists
+95 -13
View File
@@ -1,20 +1,102 @@
/datum/netdata //this requires some thought later on but for now it's fine.
var/network_id
// This netlink class shares a list to two devices
// This allows skipping of sending many many packets
// just to update simple data
/datum/netlink
var/server_id
var/server_network
var/port
var/passkey = null // sends auth data used to check if we can connect or send data to a device
var/list/data
var/autopasskey = TRUE
/datum/netlink/New(datum/component/ntnet_interface/conn, port)
data = conn.registered_sockets[port]
ASSERT(data != null)
server_id = conn.hardware_id
server_network = conn.network.network_id
src.port = port
RegisterSignal(conn, COMSIG_COMPONENT_NTNET_PORT_DESTROYED, .proc/_server_disconnected)
..()
var/list/recipient_ids = list()
/datum/netlink/proc/_server_disconnected(datum/component/com)
SIGNAL_HANDLER
data = null
/datum/netlink/Destroy()
passkey = null
data = null
return ..()
// If you don't want to use this fine, but this just shows how the system works
// I hate you all. I want to operator overload []
// So fuck you all, Do NOT access data directly you freaks
// or this breaks god knows what.
// FINE, you don't have to use get, is dirty or even clean
// proc overhead is WAY more important than fucking clarity or
// sealed classes. But for the LOVE OF GOD make sure _updated
// is set if your going to do this.
/datum/netlink/proc/get(idx)
return data ? data[idx] : null
/datum/netlink/proc/put(idx, V)
// is it posable to do this async without worry about racing conditions?
if(data && data[idx] != V)
data["_updated"] = TRUE
data[idx] = V
/datum/netlink/proc/is_dirty()
return data && data["_updated"]
/datum/netlink/proc/clean()
if(data)
data["_updated"] = FALSE
/datum/netlink/proc/is_connected()
return data != null
/datum/netdata
//this requires some thought later on but for now it's fine. (WarlockD) ARRRRG
// Packets are kind of shaped like IPX. IPX had a network, a node (aka id) and a port.
// Special case with receiver_id == null, that wil broadcast to the network_id
// Also, if the network id is not the same for both sender and receiver the packet is dropped.
var/sender_id
var/broadcast = FALSE //Whether this is a broadcast packet.
var/receiver_id
var/network_id
var/passkey = null // sends auth data used to check if we can connect or send data to a device
var/list/data = list()
// Used for packet queuing
var/datum/netdata/next = null
var/mob/user = null // used for sending error messages
var/list/passkey
/datum/netdata/New(list/data = null)
if(!data)
data = list()
src.data = data
/datum/netdata/proc/standard_format_data(primary, secondary, passkey)
data["data"] = primary
data["data_secondary"] = secondary
data["encrypted_passkey"] = passkey
/datum/netdata/Destroy()
data = null
passkey = null
next = null
user = null
return ..()
/datum/netdata/proc/clone(deep_copy=FALSE)
var/datum/netdata/C = new
C.sender_id = sender_id
C.receiver_id = receiver_id
C.network_id = network_id
C.passkey = passkey
C.user = user
C.next = null
if(deep_copy)
C.data = deepCopyList(data)
else
C.data = data
return C
/datum/netdata/proc/json_to_data(json)
data = json_decode(json)
@@ -32,12 +114,12 @@
/datum/netdata/proc/json_list_generation()
. = list()
. |= json_list_generation_netlog()
.["network_id"] = network_id
/datum/netdata/proc/json_list_generation_netlog()
. = list()
.["recipient_ids"] = recipient_ids
.["network_id"] = network_id
.["sender_id"] = sender_id
.["receiver_id"] = receiver_id
.["data_list"] = data
/datum/netdata/proc/generate_netlog()
+271 -123
View File
@@ -1,21 +1,247 @@
/*
* # /datum/ntnet
*
* This class defines each network of the world. Each root network is accessible by any device
* on the same network but NOT accessible to any other "root" networks. All normal devices only have
* one network and one network_id.
*
* This thing replaces radio. Think of wifi but better, bigger and bolder! The idea is that any device
* on a network can reach any other device on that same network if it knows the hardware_id. You can also
* search or broadcast to devices if you know what branch you wish. That is to say you can broadcast to all
* devices on "SS13.ATMOS.SCRUBBERS" to change the settings of all the scrubbers on the station or to
* "SS13.AREA.FRED_HOME.SCRUBBERS" to all the scrubbers at one area. However devices CANNOT communicate cross
* networks normality.
*
*/
/datum/ntnet
var/network_id = "Network"
var/list/connected_interfaces_by_id = list() //id = datum/component/ntnet_interface
/// The full network name for this network ex. SS13.ATMOS.SCRUBBERS
var/network_id
/// The network name part of this leaf ex ATMOS
var/network_node_id
/// All devices on this network. ALL devices on this network, not just this branch.
/// This list is shared between all leaf networks so we don't have to keep going to the
/// parents on lookups. It is an associated list of hardware_id AND tag_id's
var/list/root_devices
/// This lists has all the networks in this node. Each name is fully qualified
/// ie. SS13.ATMOS.SCRUBBERS, SS13.ATMOS.VENTS, etc
var/list/networks
/// All the devices on this branch of the network
var/list/linked_devices
/// Network children. Associated list using the network_node_id of the child as the key
var/list/children
/// Parrnt of the network. If this is null, we are a oot network
var/datum/ntnet/parent
/*
* Creates a new network
*
* Used for /datum/controller/subsystem/networks/proc/create_network so do not
* call yourself as new doesn't do any checking itself
*
* Arguments:
* * net_id - Fully qualified network id for this network
* * net_part_id - sub part of a network if this is a child of P
* * P - Parent network, this will be attached to that network.
*/
/datum/ntnet/New(net_id, net_part_id, datum/ntnet/P = null)
linked_devices = list()
children = list()
network_id = net_id
if(P)
network_node_id = net_part_id
parent = P
parent.children[network_node_id] = src
root_devices = parent.root_devices
networks = parent.networks
else
network_node_id = net_id
parent = null
networks = list()
root_devices = list()
SSnetworks.root_networks[network_id] = src
SSnetworks.networks[network_id] = src
SSnetworks.add_log("Network was created: [network_id]")
return ..()
/// A network should NEVER be deleted. If you don't want to show it exists just check if its
/// empty
/datum/ntnet/Destroy()
if(children.len > 0 || linked_devices.len > 0)
CRASH("Trying to delete a network with devices still in them")
if(parent)
parent.children.Remove(network_id)
parent = null
else
SSnetworks.root_networks.Remove(network_id)
SSnetworks.networks.Remove(network_id)
root_devices = null
networks = null
network_node_id = null
SSnetworks.add_log("Network was destroyed: [network_id]")
network_id = null
return ..()
/*
* Collects all the devices on this branch of the network and maybe its
* children
*
* Used for broadcasting, this will collect all the interfaces on this
* network and by default everything below this branch. Will return an
* empty list if no devices were found
*
* Arguments:
* * include_children - Include the children of all branches below this
*/
/datum/ntnet/proc/collect_interfaces(include_children=TRUE)
if(!include_children || children.len == 0)
return linked_devices.Copy()
else
/// Please no recursion. Byond hates recursion
var/list/devices = list()
var/list/queue = list(src) // add ourselves
while(queue.len)
var/datum/ntnet/net = queue[queue.len--]
if(net.children.len > 0)
for(var/net_id in net.children)
queue += networks[net_id]
devices += net.linked_devices
return devices
/*
* Find if an interface exists on this network
*
* Used to look up a device on the network.
*
* Arguments:
* * tag_or_hid - Ither the hardware id or the id_tag
*/
/datum/ntnet/proc/find_interface(tag_or_hid)
return root_devices[tag_or_hid]
/**
* Add this interface to this branch of the network.
*
* This will add a network interface to this branch of the network.
* If the interface already exists on the network it will add it and
* give the alias list in the interface this branch name. If the interface
* has an id_tag it will add that name to the root_devices for map lookup
*
* Arguments:
* * interface - ntnet component of the device to add to the network
*/
/datum/ntnet/proc/add_interface(datum/component/ntnet_interface/interface)
if(interface.network)
if(!networks[interface.network.network_id])
/// If we are doing a hard jump to a new network, log it
log_telecomms("The device {[interface.hardware_id]} is jumping networks from '[interface.network.network_id]' to '[network_id]'")
interface.network.remove_interface(interface, TRUE)
else // we are on the same network so we just want to be aliased to another branch
if(!interface.alias[network_id])
interface.alias[network_id] = src // add to the alias list
linked_devices[interface.hardware_id] = interface
else
log_telecomms("The device {[interface.hardware_id]} is trying to join '[network_id]' for a second time!")
return
// we have no network
interface.network = src // now we do!
interface.alias[network_id] = src // add to the alias just to make removing easier.
linked_devices[interface.hardware_id] = interface
root_devices[interface.hardware_id] = interface
if(interface.id_tag != null) // could be a type, never know
root_devices[interface.id_tag] = interface
/*
* Remove this interface from the network
*
* This will remove an interface from this network and null the network field on the
* interface. Be sure that add_interface is run as soon as posable as an interface MUST
* have a network
*
* Arguments:
* * interface - ntnet component of the device to remove to the network
* * remove_all_alias - remove ALL references to this device on this network
*/
/datum/ntnet/proc/remove_interface(datum/component/ntnet_interface/interface, remove_all_alias=FALSE)
if(!interface.alias[network_id])
log_telecomms("The device {[interface.hardware_id]} is trying to leave a '[network_id]'' when its on '[interface.network.network_id]'")
return
// just cashing it
var/hardware_id = interface.hardware_id
// Handle the quick case
interface.alias.Remove(network_id)
linked_devices.Remove(hardware_id)
if(remove_all_alias)
var/datum/ntnet/net
for(var/id in interface.alias)
net = interface.alias[id]
net.linked_devices.Remove(hardware_id)
// Now check if there are more than meets the eye
if(interface.network == src || remove_all_alias)
// Ok, so we got to remove this network, but if we have an alias we are still "on" the network
// so we need to shift down to one of the other networks on the alias list. If the alias list
// is empty, fuck it and remove it from the network.
if(interface.alias.len > 0)
interface.network = interface.alias[1] // ... whatever is there.
else
// ok, hard remove from everything then
root_devices.Remove(interface.hardware_id)
if(interface.id_tag != null) // could be a type, never know
root_devices.Remove(interface.id_tag)
interface.network = null
/*
* Move interface to another branch of the network
*
* This function is a lightweight way of moving an interface from one branch to another like a gps
* device going from one area to another. Target network MUST be this network or it will fail
*
* Arguments:
* * interface - ntnet component of the device to move
* * target_network - qualified network id to move to
* * original_network - qualified network id from the original network if not this one
*/
/datum/ntnet/proc/move_interface(datum/component/ntnet_interface/interface, target_network, original_network = null)
var/datum/ntnet/net = original_network == null ? src : networks[original_network]
var/datum/ntnet/target = networks[target_network]
if(!target || !net)
log_telecomms("The device {[interface.hardware_id]} is trying to move to a network ([target_network]) that is not on ([network_id])")
return
if(target.linked_devices[interface.hardware_id])
log_telecomms("The device {[interface.hardware_id]} is trying to move to a network ([target_network]) it is already on.")
return
if(!net.linked_devices[interface.hardware_id])
log_telecomms("The device {[interface.hardware_id]} is trying to move to a network ([target_network]) but its not on ([net.network_id]) ")
return
net.linked_devices.Remove(interface.hardware_id)
target.linked_devices[interface.hardware_id] = interface
interface.alias.Remove(net.network_id)
interface.alias[target.network_id] = target
/datum/ntnet/station_root
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()
var/list/available_station_software = list()
var/list/available_antag_software = list()
var/list/chat_channels = list()
var/list/fileservers = list()
// Amount of logs the system tries to keep in memory. Keep below 999 to prevent byond from acting weirdly.
// High values make displaying logs much laggier.
var/setting_maxlogcount = 100
// These only affect wireless. LAN (consoles) are unaffected since it would be possible to create scenario where someone turns off NTNet, and is unable to turn it back on since it refuses connections
var/setting_softwaredownload = TRUE
@@ -28,44 +254,28 @@
var/intrusion_detection_alarm = FALSE // Set when there is an IDS warning due to malicious (antag) software.
// If new NTNet datum is spawned, it replaces the old one.
/datum/ntnet/New(_netid)
build_software_lists()
add_log("NTNet logging system activated.")
if(_netid)
network_id = _netid
if(!SSnetworks.register_network(src))
stack_trace("Network [type] with ID [network_id] failed to register and has been deleted.")
qdel(src)
/datum/ntnet/station_root/New(root_name)
. = ..()
SSnetworks.add_log("NTNet logging system activated for [root_name]")
/datum/ntnet/Destroy()
for(var/i in connected_interfaces_by_id)
var/datum/component/ntnet_interface/I = i
I.unregister_connection(src)
#ifdef NTNET_SERVICE
/datum/ntnet/station_root/Destroy()
for(var/i in services_by_id)
var/datum/ntnet_service/S = i
var/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
/datum/ntnet/proc/interface_disconnect(datum/component/ntnet_interface/I)
connected_interfaces_by_id -= I.hardware_id
return TRUE
/datum/ntnet/proc/find_interface_id(id)
return connected_interfaces_by_id[id]
/datum/ntnet/proc/find_service_id(id)
/datum/ntnet/station_root/proc/find_service_id(id)
return services_by_id[id]
/datum/ntnet/proc/find_service_path(path)
/datum/ntnet/station_root/proc/find_service_path(path)
return services_by_path[path]
/datum/ntnet/proc/register_service(datum/ntnet_service/S)
/datum/ntnet/station_root/proc/register_service(datum/ntnet_service/S)
if(!istype(S))
return FALSE
if(services_by_path[S.type] || services_by_id[S.id])
@@ -74,14 +284,14 @@
services_by_id[S.id] = S
return TRUE
/datum/ntnet/proc/unregister_service(datum/ntnet_service/S)
/datum/ntnet/station_root/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)
/datum/ntnet/station_root/proc/create_service(type)
var/datum/ntnet_service/S = new type
if(!istype(S))
return FALSE
@@ -89,7 +299,7 @@
if(!.)
qdel(S)
/datum/ntnet/proc/destroy_service(type)
/datum/ntnet/station_root/proc/destroy_service(type)
var/datum/ntnet_service/S = find_service_path(type)
if(!istype(S))
return FALSE
@@ -97,69 +307,21 @@
if(.)
qdel(src)
/datum/ntnet/proc/process_data_transmit(datum/component/ntnet_interface/sender, datum/netdata/data)
if(!check_relay_operation())
return FALSE
data.network_id = src
log_data_transfer(data)
var/list/datum/component/ntnet_interface/receiving = 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)
receiving |= connected_interfaces_by_id[i]
else
for(var/i in data.recipient_ids)
var/datum/component/ntnet_interface/receiver = find_interface_id(i)
receiving |= receiver
for(var/i in receiving)
var/datum/component/ntnet_interface/receiver = i
if(receiver)
receiver.__network_receive(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.
for(var/i in relays)
var/obj/machinery/ntnet_relay/n = i
if(zlevel && n.z != zlevel)
continue
if(n.is_operational)
return TRUE
return FALSE
/datum/ntnet/proc/log_data_transfer(datum/netdata/data)
logs += "[station_time_timestamp()] - [data.generate_netlog()]"
if(logs.len > setting_maxlogcount)
logs = logs.Copy(logs.len - setting_maxlogcount, 0)
return
// Simplified logging: Adds a log. log_string is mandatory parameter, source is optional.
/datum/ntnet/proc/add_log(log_string, obj/item/computer_hardware/network_card/source = null)
var/log_text = "[station_time_timestamp()] - "
if(source)
log_text += "[source.get_network_tag()] - "
else
log_text += "*SYSTEM* - "
log_text += log_string
logs.Add(log_text)
// We have too many logs, remove the oldest entries until we get into the limit
if(logs.len > setting_maxlogcount)
logs = logs.Copy(logs.len-setting_maxlogcount,0)
/datum/ntnet/station_root/proc/process_data_transmit(datum/component/ntnet_interface/sender, datum/netdata/data)
if(..())
for(var/i in services_by_id)
var/datum/ntnet_service/serv = services_by_id[i]
serv.ntnet_intercept(data, src, sender)
return TRUE
#endif
// Checks whether NTNet operates. If parameter is passed checks whether specific function is enabled.
/datum/ntnet/proc/check_function(specific_action = 0)
if(!relays || !relays.len) // No relays found. NTNet is down
/datum/ntnet/station_root/proc/check_function(specific_action = 0)
if(!SSnetworks.relays || !SSnetworks.relays.len) // No relays found. NTNet is down
return FALSE
// Check all relays. If we have at least one working relay, network is up.
if(!check_relay_operation())
if(!SSnetworks.check_relay_operation())
return FALSE
if(setting_disabled)
@@ -177,7 +339,7 @@
return TRUE
// Builds lists that contain downloadable software.
/datum/ntnet/proc/build_software_lists()
/datum/ntnet/station_root/proc/build_software_lists()
available_station_software = list()
available_antag_software = list()
for(var/F in typesof(/datum/computer_file/program))
@@ -192,7 +354,7 @@
available_antag_software.Add(prog)
// Attempts to find a downloadable file according to filename var
/datum/ntnet/proc/find_ntnet_file_by_name(filename)
/datum/ntnet/station_root/proc/find_ntnet_file_by_name(filename)
for(var/N in available_station_software)
var/datum/computer_file/program/P = N
if(filename == P.filename)
@@ -202,55 +364,41 @@
if(filename == P.filename)
return P
/datum/ntnet/proc/get_chat_channel_by_id(id)
/datum/ntnet/station_root/proc/get_chat_channel_by_id(id)
for(var/datum/ntnet_conversation/chan in chat_channels)
if(chan.id == id)
return chan
// Resets the IDS alarm
/datum/ntnet/proc/resetIDS()
/datum/ntnet/station_root/proc/resetIDS()
intrusion_detection_alarm = FALSE
/datum/ntnet/proc/toggleIDS()
/datum/ntnet/station_root/proc/toggleIDS()
resetIDS()
intrusion_detection_enabled = !intrusion_detection_enabled
// Removes all logs
/datum/ntnet/proc/purge_logs()
logs = list()
add_log("-!- LOGS DELETED BY SYSTEM OPERATOR -!-")
// Updates maximal amount of stored logs. Use this instead of setting the number, it performs required checks.
/datum/ntnet/proc/update_max_log_count(lognumber)
if(!lognumber)
return FALSE
// Trim the value if necessary
lognumber = max(MIN_NTNET_LOGS, min(lognumber, MAX_NTNET_LOGS))
setting_maxlogcount = lognumber
add_log("Configuration Updated. Now keeping [setting_maxlogcount] logs in system memory.")
/datum/ntnet/proc/toggle_function(function)
/datum/ntnet/station_root/proc/toggle_function(function)
if(!function)
return
function = text2num(function)
switch(function)
if(NTNET_SOFTWAREDOWNLOAD)
setting_softwaredownload = !setting_softwaredownload
add_log("Configuration Updated. Wireless network firewall now [setting_softwaredownload ? "allows" : "disallows"] connection to software repositories.")
SSnetworks.add_log("Configuration Updated. Wireless network firewall now [setting_softwaredownload ? "allows" : "disallows"] connection to software repositories.")
if(NTNET_PEERTOPEER)
setting_peertopeer = !setting_peertopeer
add_log("Configuration Updated. Wireless network firewall now [setting_peertopeer ? "allows" : "disallows"] peer to peer network traffic.")
SSnetworks.add_log("Configuration Updated. Wireless network firewall now [setting_peertopeer ? "allows" : "disallows"] peer to peer network traffic.")
if(NTNET_COMMUNICATION)
setting_communication = !setting_communication
add_log("Configuration Updated. Wireless network firewall now [setting_communication ? "allows" : "disallows"] instant messaging and similar communication services.")
SSnetworks.add_log("Configuration Updated. Wireless network firewall now [setting_communication ? "allows" : "disallows"] instant messaging and similar communication services.")
if(NTNET_SYSTEMCONTROL)
setting_systemcontrol = !setting_systemcontrol
add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of station's systems.")
SSnetworks.add_log("Configuration Updated. Wireless network firewall now [setting_systemcontrol ? "allows" : "disallows"] remote control of station's systems.")
/datum/ntnet/station
network_id = "SS13-NTNET"
/datum/ntnet/station/proc/register_map_supremecy() //called at map init to make this what station networks use.
/datum/ntnet/station_root/proc/register_map_supremecy() //called at map init to make this what station networks use.
for(var/obj/machinery/ntnet_relay/R in GLOB.machines)
relays.Add(R)
SSnetworks.relays.Add(R)
R.NTNet = src
+8 -8
View File
@@ -79,12 +79,12 @@
if((dos_overload > dos_capacity) && !dos_failure)
set_dos_failure(TRUE)
update_icon()
SSnetworks.station_network.add_log("Quantum relay switched from normal operation mode to overload recovery mode.")
SSnetworks.add_log("Quantum relay switched from normal operation mode to overload recovery mode.")
// If the DoS buffer reaches 0 again, restart.
if((dos_overload == 0) && dos_failure)
set_dos_failure(FALSE)
update_icon()
SSnetworks.station_network.add_log("Quantum relay switched from overload recovery mode to normal operation mode.")
SSnetworks.add_log("Quantum relay switched from overload recovery mode to normal operation mode.")
..()
/obj/machinery/ntnet_relay/ui_interact(mob/user, datum/tgui/ui)
@@ -110,11 +110,11 @@
dos_overload = 0
set_dos_failure(FALSE)
update_icon()
SSnetworks.station_network.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.")
SSnetworks.add_log("Quantum relay manually restarted from overload recovery mode to normal operation mode.")
return TRUE
if("toggle")
set_relay_enabled(!relay_enabled)
SSnetworks.station_network.add_log("Quantum relay manually [relay_enabled ? "enabled" : "disabled"].")
SSnetworks.add_log("Quantum relay manually [relay_enabled ? "enabled" : "disabled"].")
update_icon()
return TRUE
@@ -123,15 +123,15 @@
component_parts = list()
if(SSnetworks.station_network)
SSnetworks.station_network.relays.Add(src)
SSnetworks.relays.Add(src)
NTNet = SSnetworks.station_network
SSnetworks.station_network.add_log("New quantum relay activated. Current amount of linked relays: [NTNet.relays.len]")
SSnetworks.add_log("New quantum relay activated. Current amount of linked relays: [SSnetworks.relays.len]")
. = ..()
/obj/machinery/ntnet_relay/Destroy()
if(SSnetworks.station_network)
SSnetworks.station_network.relays.Remove(src)
SSnetworks.station_network.add_log("Quantum relay connection severed. Current amount of linked relays: [NTNet.relays.len]")
SSnetworks.relays.Remove(src)
SSnetworks.add_log("Quantum relay connection severed. Current amount of linked relays: [SSnetworks.relays.len]")
NTNet = null
for(var/datum/computer_file/program/ntnet_dos/D in dos_sources)
-38
View File
@@ -1,38 +0,0 @@
/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
var/datum/component/ntnet_interface/interface = GetComponent(/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
var/datum/component/ntnet_interface/interface = GetComponent(/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
@@ -18,7 +18,6 @@
hide = TRUE
shift_underlay_only = FALSE
var/id_tag = null
var/pump_direction = RELEASING
var/pressure_checks = EXT_BOUND
@@ -36,9 +35,9 @@
pipe_state = "uvent"
/obj/machinery/atmospherics/components/unary/vent_pump/New()
..()
if(!id_tag)
id_tag = assign_uid_vents()
id_tag = SSnetworks.assign_random_name()
. = ..()
/obj/machinery/atmospherics/components/unary/vent_pump/Destroy()
var/area/vent_area = get_area(src)
@@ -164,7 +163,7 @@
if(!GLOB.air_vent_names[id_tag])
// If we do not have a name, assign one.
// Produces names like "Port Quarter Solar vent pump hZ2l6".
name = "\proper [vent_area.name] vent pump [assign_random_name()]"
name = "\proper [vent_area.name] vent pump [id_tag]"
GLOB.air_vent_names[id_tag] = name
vent_area.air_vent_info[id_tag] = signal.data
@@ -15,7 +15,6 @@
hide = TRUE
shift_underlay_only = FALSE
var/id_tag = null
var/scrubbing = SCRUBBING //0 = siphoning, 1 = scrubbing
var/filter_types = list(/datum/gas/carbon_dioxide)
@@ -31,10 +30,9 @@
pipe_state = "scrubber"
/obj/machinery/atmospherics/components/unary/vent_scrubber/New()
..()
if(!id_tag)
id_tag = assign_uid_vents()
id_tag = SSnetworks.assign_random_name()
. = ..()
for(var/f in filter_types)
if(istext(f))
filter_types -= f
@@ -120,7 +118,7 @@
var/area/scrub_area = get_area(src)
if(!GLOB.air_scrub_names[id_tag])
// If we do not have a name, assign one
name = "\proper [scrub_area.name] air scrubber [assign_random_name()]"
name = "\proper [scrub_area.name] air scrubber [id_tag]"
GLOB.air_scrub_names[id_tag] = name
scrub_area.air_scrub_info[id_tag] = signal.data
@@ -12,7 +12,6 @@
armor = list(MELEE = 0, BULLET = 0, LASER = 0, ENERGY = 100, BOMB = 0, BIO = 100, RAD = 100, FIRE = 40, ACID = 0)
var/frequency = 0
var/atom/target
var/id_tag
var/target_layer = PIPING_LAYER_DEFAULT
/obj/machinery/meter/atmos
+11 -2
View File
@@ -90,8 +90,17 @@
return FALSE
return TRUE
/obj/proc/check_access_ntnet(datum/netdata/data)
return check_access_list(data.passkey)
/*
* Checks if this packet can access this device
*
* Normally just checks the access list however you can override it for
* hacking proposes or if wires are cut
*
* Arguments:
* * passkey - passkey from the datum/netdata packet
*/
/obj/proc/check_access_ntnet(list/passkey)
return check_access_list(passkey)
/proc/get_centcom_access(job)
switch(job)
+21 -4
View File
@@ -6,6 +6,7 @@
var/loaded = 0 // Times loaded this round
var/datum/parsed_map/cached_map
var/keep_cached_map = FALSE
var/station_id = null // used to override the root id when generating
/datum/map_template/New(path = null, rename = null, cache = FALSE)
if(path)
@@ -25,7 +26,9 @@
cached_map = parsed
return bounds
/datum/parsed_map/proc/initTemplateBounds()
/datum/parsed_map/proc/initTemplateBounds(datum/map_template/template)
var/list/obj/machinery/atmospherics/atmos_machines = list()
var/list/obj/structure/cable/cables = list()
var/list/atom/atoms = list()
@@ -45,7 +48,11 @@
)
for(var/L in turfs)
var/turf/B = L
areas |= B.loc
var/area/G = B.loc
areas |= G
if(!SSatoms.initialized)
continue
for(var/A in B)
atoms += A
if(istype(A, /obj/structure/cable))
@@ -54,7 +61,17 @@
if(istype(A, /obj/machinery/atmospherics))
atmos_machines += A
// Not sure if there is some importance here to make sure the area is in z
// first or not. Its defined In Initialize yet its run first in templates
// BEFORE so... hummm
SSmapping.reg_in_areas_in_z(areas)
// We have to do this hack here because its the ONLY place we can get the
// meta data from the template so we can properly set up the area
SSnetworks.assign_areas_root_ids(areas, template)
// If the world is starting up stop here and the world will do the rest
if(!SSatoms.initialized)
return
SSatoms.InitializeAtoms(areas + turfs + atoms)
// NOTE, now that Initialize and LateInitialize run correctly, do we really
// need these two below?
@@ -92,7 +109,7 @@
repopulate_sorted_areas()
//initialize things that are normally initialized after map load
parsed.initTemplateBounds()
parsed.initTemplateBounds(src)
smooth_zlevel(world.maxz)
log_game("Z-level [name] loaded at [x],[y],[world.maxz]")
@@ -129,7 +146,7 @@
repopulate_sorted_areas()
//initialize things that are normally initialized after map load
parsed.initTemplateBounds()
parsed.initTemplateBounds(src)
log_game("[name] loaded at [T.x],[T.y],[T.z]")
return bounds
@@ -32,6 +32,7 @@
bot_core_type = /obj/machinery/bot_core/mulebot
hud_possible = list(DIAG_STAT_HUD, DIAG_BOT_HUD, DIAG_HUD, DIAG_BATT_HUD, DIAG_PATH_HUD = HUD_LIST_LIST) //Diagnostic HUD views
var/network_id = NETWORK_BOTS_CARGO
/// unique identifier in case there are multiple mulebots.
var/id
@@ -55,6 +56,8 @@
var/bloodiness = 0 ///If we've run over a mob, how many tiles will we leave tracks on while moving
var/num_steps = 0 ///The amount of steps we should take until we rest for a time.
/mob/living/simple_animal/bot/mulebot/Initialize(mapload)
. = ..()
if(prob(0.666) && mapload)
@@ -73,9 +76,9 @@
AddElement(/datum/element/ridable, /datum/component/riding/creature/mulebot)
diag_hud_set_mulebotcell()
/mob/living/simple_animal/bot/mulebot/ComponentInitialize()
. = ..()
AddComponent(/datum/component/ntnet_interface)
if(network_id)
AddComponent(/datum/component/ntnet_interface, network_id)
/mob/living/simple_animal/bot/mulebot/handle_atom_del(atom/A)
if(A == load)
@@ -367,7 +367,8 @@
if(!get_ntnet_status())
return FALSE
var/obj/item/computer_hardware/network_card/network_card = all_components[MC_NET]
return SSnetworks.station_network.add_log(text, network_card)
return SSnetworks.add_log(text, network_card.network_id, network_card.hardware_id)
/obj/item/modular_computer/proc/shutdown_computer(loud = 1)
kill_program(forced = TRUE)
@@ -45,7 +45,7 @@
return
switch(action)
if("PRG_target_relay")
for(var/obj/machinery/ntnet_relay/R in SSnetworks.station_network.relays)
for(var/obj/machinery/ntnet_relay/R in SSnetworks.relays)
if("[R.uid]" == params["targid"])
target = R
break
@@ -63,7 +63,7 @@
target.dos_sources.Add(src)
if(SSnetworks.station_network.intrusion_detection_enabled)
var/obj/item/computer_hardware/network_card/network_card = computer.all_components[MC_NET]
SSnetworks.station_network.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]")
SSnetworks.add_log("IDS WARNING - Excess traffic flood targeting relay [target.uid] detected from device: [network_card.get_network_tag()]")
SSnetworks.station_network.intrusion_detection_alarm = TRUE
return TRUE
@@ -83,7 +83,7 @@
else
data["target"] = FALSE
data["relays"] = list()
for(var/obj/machinery/ntnet_relay/R in SSnetworks.station_network.relays)
for(var/obj/machinery/ntnet_relay/R in SSnetworks.relays)
data["relays"] += list(list("id" = R.uid))
data["focus"] = target ? target.uid : null
@@ -36,12 +36,12 @@
return TRUE
if("purgelogs")
if(SSnetworks.station_network)
SSnetworks.station_network.purge_logs()
SSnetworks.purge_logs()
return TRUE
if("updatemaxlogs")
var/logcount = params["new_number"]
if(SSnetworks.station_network)
SSnetworks.station_network.update_max_log_count(logcount)
SSnetworks.update_max_log_count(logcount)
return TRUE
if("toggle_function")
if(!SSnetworks.station_network)
@@ -55,7 +55,7 @@
var/list/data = get_header_data()
data["ntnetstatus"] = SSnetworks.station_network.check_function()
data["ntnetrelays"] = SSnetworks.station_network.relays.len
data["ntnetrelays"] = SSnetworks.relays.len
data["idsstatus"] = SSnetworks.station_network.intrusion_detection_enabled
data["idsalarm"] = SSnetworks.station_network.intrusion_detection_alarm
@@ -68,8 +68,8 @@
data["minlogs"] = MIN_NTNET_LOGS
data["maxlogs"] = MAX_NTNET_LOGS
for(var/i in SSnetworks.station_network.logs)
for(var/i in SSnetworks.logs)
data["ntnetlogs"] += list(list("entry" = i))
data["ntnetmaxlogs"] = SSnetworks.station_network.setting_maxlogcount
data["ntnetmaxlogs"] = SSnetworks.setting_maxlogcount
return data
@@ -3,17 +3,18 @@
desc = "A basic wireless network card for usage with standard NTNet frequencies."
power_usage = 50
icon_state = "radio_mini"
var/identification_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
network_id = NETWORK_CARDS // Network we are on
var/hardware_id = null // Identification ID. Technically MAC address of this device. Can't be changed by user.
var/identification_string = "" // Identification string, technically nickname seen in the network. Can be set by user.
var/long_range = 0
var/ethernet = 0 // Hard-wired, therefore always on, ignores NTNet wireless checks.
malfunction_probability = 1
device_type = MC_NET
var/static/ntnet_card_uid = 1
/obj/item/computer_hardware/network_card/diagnostics(mob/user)
..()
to_chat(user, "NIX Unique ID: [identification_id]")
to_chat(user, "NIX Unique ID: [hardware_id]")
to_chat(user, "NIX User Tag: [identification_string]")
to_chat(user, "Supported protocols:")
to_chat(user, "511.m SFS (Subspace) - Standard Frequency Spread")
@@ -22,13 +23,10 @@
if(ethernet)
to_chat(user, "OpenEth (Physical Connection) - Physical network connection port")
/obj/item/computer_hardware/network_card/New(l)
..()
identification_id = ntnet_card_uid++
// Returns a string identifier of this network card
/obj/item/computer_hardware/network_card/proc/get_network_tag()
return "[identification_string] (NID [identification_id])"
return "[identification_string] (NID [hardware_id])"
// 0 - No signal, 1 - Low signal, 2 - High signal. 3 - Wired Connection
/obj/item/computer_hardware/network_card/proc/get_signal(specific_action = 0)
+1
View File
@@ -50,6 +50,7 @@
#include "medical_wounds.dm"
#include "merge_type.dm"
#include "metabolizing.dm"
#include "ntnetwork_tests.dm"
#include "outfit_sanity.dm"
#include "pills.dm"
#include "plantgrowth_tests.dm"
@@ -0,0 +1,68 @@
/datum/unit_test/ntnetwork
var/list/valid_network_names = list("SS13.ATMOS.SCRUBBERS.SM", "DEEPSPACE.HYDRO.PLANT", "SINDIE.STINKS.BUTT")
var/list/invalid_network_names = list(".SS13.BOB", "SS13.OHMAN.", "SS13.HAS A SPACE" )
var/list/valid_network_trees = list(list("SS13","ATMOS","SCRUBBERS","SM"),list("DEEPSPACE","HYDRO","PLANT"), list("SINDIE","STINKS","BUTT"))
var/list/network_roots = list(
__STATION_NETWORK_ROOT,
__CENTCOM_NETWORK_ROOT,
__SYNDICATE_NETWORK_ROOT,
__LIMBO_NETWORK_ROOT)
var/list/random_words_for_testing = list(
__NETWORK_TOOLS, __NETWORK_REMOTES, __NETWORK_AIRLOCKS,
__NETWORK_DOORS, __NETWORK_ATMOS, __NETWORK_SCUBBERS,
__NETWORK_AIRALARMS, __NETWORK_CONTROL, __NETWORK_STORAGE,
__NETWORK_CARGO, __NETWORK_BOTS, __NETWORK_COMPUTER,
__NETWORK_CARDS)
var/number_of_names_to_test = 50
var/length_of_test_network = 5
/datum/unit_test/proc/mangle_word(word)
var/len = length(word)
var/space_pos = round(len/2)
word = copytext(word,1,space_pos) + " " + copytext(word,space_pos,len)
return word
/datum/unit_test/ntnetwork/Run()
// First check if name checks work
for(var/name in valid_network_names)
TEST_ASSERT(verify_network_name(name), "Network name ([name]) marked as invalid but supposed to valid")
for(var/name in invalid_network_names)
TEST_ASSERT(!verify_network_name(name), "Network name ([name]) marked as valid but supposed to be invalid")
// Next check if we can pack and unpack network names
for(var/i in 1 to valid_network_names.len)
var/name = valid_network_names[i]
var/list/name_list = SSnetworks.network_string_to_list(name)
TEST_ASSERT(compare_list(name_list, valid_network_trees[i]), "Network name ([name]) did not unpack into a proper list")
for(var/i in 1 to valid_network_trees.len)
var/list/name_list = valid_network_trees[i]
var/name = SSnetworks.network_list_to_string(name_list)
TEST_ASSERT_EQUAL(name, valid_network_names[i], "Network name ([name]) did not pack into a proper string")
// Ok, we know we can verify network names now, and that we can pack and unpack. Lets try making some random good names
var/list/generated_network_names = list()
var/test_string
for(var/i in 1 to number_of_names_to_test)
var/list/builder = list()
builder += pick(network_roots)
for(var/j in 1 to length_of_test_network)
builder += pick(random_words_for_testing)
test_string = SSnetworks.network_list_to_string(builder)
var/name_fix = simple_network_name_fix(test_string)
TEST_ASSERT_EQUAL(name_fix, test_string, "Network name ([test_string]) was not fixed correctly to ([name_fix])")
generated_network_names += name_fix // save for future
// test badly generated names
for(var/i in 1 to number_of_names_to_test)
var/list/builder = list()
builder += mangle_word(pick(network_roots))
for(var/j in 1 to length_of_test_network)
builder += mangle_word(pick(random_words_for_testing))
test_string = builder.Join(".")
var/name_fix = simple_network_name_fix(test_string)
TEST_ASSERT(verify_network_name(name_fix), "Network name ([test_string]) was not fixed correctly ([name_fix]) with bad name")
-1
View File
@@ -2690,7 +2690,6 @@
#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\paperwork\carbonpaper.dm"
#include "code\modules\paperwork\clipboard.dm"
#include "code\modules\paperwork\contract.dm"