ID:2379074   Jun 24 2018, 7:37 pm Sometimes you want to hang on to a reference to something without actually intending to keep that thing from deleting itself. Weak references are a good way to do this. Otherwise, referencing another object will require to to manage your references and circularize the relationship. datum var/tmp __weakrefs = 0 proc __weakref(weakref/r) if(__weakrefs<=0) global.__weakrefs[r.id] = list(r) __weakrefs = 1 else global.__weakrefs[r.id] += r ++__weakrefs __weakderef(weakref/r) if(__weakrefs<=1) global.__weakrefs -= r.id __weakrefs = 0 else global.__weakrefs[r.id] -= r --__weakrefs r.id = null Weakref() var/weakref/r = new/weakref(src) __weakref(r) return r Del() if(__weakrefs) var/ref = "\ref[src]" var/list/l = global.__weakrefs[ref] for(var/weakref/r in l) r.id = null __weakrefs = 0 global.__weakrefs -= ref ..()var list/__weakrefs = list()weakref var/tmp id proc ref() if(id) return locate(id) else return null New(datum/ref) if(ref) id = "\ref[ref]" Del() if(id) ref()?.__weakderef(src) if(id) id = null ..()  An example for a potential use of this snippet: ui_element var weakref/owner New(mob/owner) src.owner = owner.Weakref() owner.client.screen += src loc = null ..()  if you ever need to get the owner, you can do this quickly in a local variable via the weakref datum's ref() proc. Thanks to 512's proc chaining, you can operate directly on the result, or you can cache the result in a local variable: owner.ref().client.screen += contents  or: var/mob/m = owner.ref()m.client.screen += contents  Be aware that ref() can return null if the object you are weak referencing gets deleted, and weakrefs will not be fully destroyed if this is the case. They will simply no longer resolve after the relationship is broken.
 <-> Jun 26 2018, 6:13 am This is cool as shit. How does this work?
 <-> Jun 26 2018, 11:23 am Alright, so if you aren't familiar with the "\ref[]" text macro, you should look into it. The idea is that internally, objects are stored in what can be thought of as a big ass table. In reality, there are a number of different tables. Each object has an internal typeid that determines where that object is stored. This means that obj, mobs, turfs, areas, datums, icons, etc. all have their own unique 1-byte id. Every item is identified by 4 bytes. the first byte is the typeid, the other 3 are the unique id for that type. Mind you, this isn't the same as a "type". These are internal types. Everything derived from /obj is the same internal type, even if it has a crazy type path in DM. Since it uses 3 bytes per unique id, that means that you can't have more than 16 million some-odd of any one internal type. This is the value that the \ref[] text macro returns. It converts that typeid into hexadecimal notation, meaning an item's refid will look something like this: "0x0C0000FF" This is called a text ref, or an embedded object reference. locate() isn't a single function. It does a number of things, depending on how it is used in context. The basic formats are as follows: locate(type) locate(tag) locate(x,y,z) locate(textref) locate(type) in list is actually shorthand for something like this: `proc locate_type(type,list) if(!list) list = world.contents var/datum/found, count = 0, len = length(__filter_list) while(count++
 <-> Jun 27 2018, 12:30 am That's really interesting. I've never really actually read the documentation on the ref macro before. I remember using it with Topic a lot and I'm surprised I never looked up what it was before.