ID:151517
 
database
var
keys = list()
banned_keys = list()
banned_ips = list()
banned_ids = list()
unbanned_keys = list()
unbanned_ips = list()
unbanned_ids = list()

proc
process_account(client/M)
if( !(M) )return
if( !(M.ckey in keys) )
keys += M.ckey
keys[M.ckey] = list(M.ckey, "Ips" = list(), "Ids" = list())
keys[M.ckey]["Ips"] += M.address
keys[M.ckey]["Ids"] += M.computer_id

if( !(M.computer_id in keys[M.ckey]["Ids"]) )
keys[M.ckey]["Ids"] += M.computer_id

if( !(M.address in keys[M.ckey]["Ips"]) )
keys[M.ckey]["Ips"] += M.address

link_accounts(mob/M)
if( !(M) )return
var
html = null
for(var/a in database.keys) if( database.keys[a] != database.keys[M.ckey])
for( var/i in 1 to length(database.keys[M.ckey]["Ips"]) )
if( database.keys[M.ckey]["Ips"][i] in database.keys[a]["Ips"])
html += " [database.keys[a][1]]<br>"

for( var/i in 1 to length(database.keys[M.ckey]["Ids"]) )
if( database.keys[M.ckey]["Ids"][i] in database.keys[a]["Ids"] && !( findtext(html, database.keys[a][1])) )
html += " [database.keys[a][1]]<br>"

if( html == null)
html += " No one is associated with this person."
return html

chain_ban_accounts(db)
if( (db in unbanned_keys) )
chain_unban_accounts(db)

banned_keys += db
unbanned_keys -= db

for(var/a in database.keys)
if( !(database.keys[a] in banned_keys) && database.keys[a] != database.keys[db] )
banned_keys += database.keys[a][1]

for( var/i in 1 to length(database.keys[db]["Ips"]) )
if( database.keys[db]["Ips"][i] in database.keys[a]["Ips"])
if( !(database.keys[a]["Ips"] in banned_ips) )
banned_ips += database.keys[a]["Ips"]
unbanned_ips -= database.keys[a]["Ips"]

for( var/i in 1 to length(database.keys[db]["Ids"]) )
if( database.keys[db]["Ids"][i] in database.keys[a]["Ids"])
if( !(database.keys[a]["Ids"] in banned_ids) )
banned_ids += database.keys[a]["Ids"]
unbanned_ids -= database.keys[a]["Ids"]


Now I have this code snippet here that links accounts together based on computer ID and IP Addresses(I also conveniently use this for handling any ban system). This code snippet works fine, but I was thinking and I'm going to come across a huge problem in the future. Once there are thousands and thousands of entries in this list it's going to take a long time to index through all of the entires in the keys list(and each entry even has lists of it's own).

Is there any better way of doing it, or a more efficient way?
First, when you're declaring vars that contain lists (especially a bunch of them), you should generally define them as of the /list type, in case you'll want to access some list properties (len, Copy(), etc) of those lists later.
database
var/list
keys = list()
banned_keys = list()
banned_ips = list()
banned_ids = list()
unbanned_keys = list()
unbanned_ips = list()
unbanned_ids = list()


Done.

As for simplifying it. You can't really just eliminate the looping, but you can make things cleaner by encapsulating the logic in a datum. I'll assume you don't care about only IP-banning or only key-banning a certain person, so in other words, whoever you ban, you use all methods to do so.
A way to do it is to set up a small "identity system". Each player will have an identity datum that represents his identity. It would be saved in a separate savefile and kept track of.
client
var/identity/identity
var/list/identities
world
New()
load all identities.
Del()
save all identities.
you should also save the identities periodically or \
if you really want to be safe, after every change. \
relying on only world/Del() to save something is \
... well, unreliable.

identity
var
//identification
tmp/owner //the client of the owner, if he's logged in
list
ckeys
IPs
var/computer_id //this may be a list as well.

//stuff you want to do with this person
list
messages
punishments
proc/Match(ckey,addr,c_id)
if((c_id && c_id == src.computer_id) || (ckey && ckey in src.ckeys) || (addr && addr in src.IPs))
return 1
else return 0
//or, compactified:
return (c_id && c_id == src.computer_id) || (ckey && ckey in src.ckeys) || (addr && addr in src.IPs) //parentheses around everything might be needed.
New(ckey,ip,c_id,client/C)
if(ckey)
if(!src.ckeys) src.ckeys = new
src.ckeys += ckey
if(ip)
if(!src.IPs) src.IPs = new
src.IPs += IP
src.computer_id = c_id
src.owner = C
identities += src

proc/GetIdentity(client/C,addr,c_id)
/*
Format: GetIdentity(client)
GetIdentity(mob)
GetIdentity(key,addr,c_id) //all 3 args optional

first argument is either client, mob or key:
*/


var/ckey
if(istype(C,/mob))
var/mob/M = C
C = M.client
if(istype(C,/client))
if(C.identity) return C.identity
ckey = C.ckey
addr = C.address
c_id = C.computer_id
else
if(istext(C))
ckey = ckey(C)
C = null
else CRASH("GetIdentity(): bad argument '[C]'")

for(var/identity/I as anything in identities)
if(I.Match(ckey,addr,c_id))
if(C)
I.owner = C
C.identity = I
return I
//if none was found, create a new one...
return new /identity(ckey,addr,c_id,C)

proc/BanSomeone(client/C,addr,c_id) //again C can be ckey
var/identity/I = GetIdentity(C,addr,c_id)
if(!I.punishments) I.punishments = new
I.punishments += "banned"

proc/IsSomeoneBanned(client/C,addr,c_id)
var/identity/I = GetIdentity(C,addr,c_id)
return ("banned" in I.punishments)


Hmm, ended up longer than I expected, so I rushed a bit. At any case, that should give you the idea.
In response to Kaioken
Thanks for your help Kaioken, i've created this.

identity
var
tmp
client/owner

list
ckeys
ips
ids

is_banned = 0
owner_name = "" // just in case if the owner isn't online

New(ckey, ip, id, client/C)
if(ckey)
if( !(ckeys) )ckeys = new
ckeys += ckey

if(ip)
if( !(ips) ) ips = new

ips += ip

if(id)
if( !(ids) ) ids = new

ids += id

if(C) owner = C
identities += src

proc
Match(txt) return ( (txt in ids) || (txt in ips) || (txt in ckeys) )

proc
get_identities(client/C)
if( C && istype(C, /client) )
var
html = ""
assoc_ips = ""
assoc_ids = ""
assoc_keys = ""

for(var/identity/I as anything in identites)
if( I.Match(C.ckey) ) for(var/a in I.ckeys)
if(I.ckeys[a] != C.ckey && !(I.ckeys[a] in assoc_keys) ) assoc_keys += "[I.ckeys[a]]<br>"

if( I.Match(C.address) ) for(var/a in I.ips)
if(I.ips[a] != C.address && !(I.ips[a] in assoc_ips) ) assoc_ips += "[I.ips[a]]<br>"

if( I.Match(C.computer_id) ) for(var/a in I.ids)
if(I.ids[a] != C.address && !(I.ids[a] in assoc_ids) ) assoc_ids += "[I.ids[a]]<br>"

html += "List of IPs associated with this account<br>[assoc_ips]<br>List of IDs associated with this account<br>[assoc_ids]<br>List of accounts associated with this account<br>[assoc_keys]<br>"
return html

chain_ban_identity(client/C, client/user)
if( !(C) ) return

C.identity.is_banned = 1
for(var/identity/A as anything in identites) if(A != C.identity)
if(A.Match(C.ckey) || A.Match(C.address) || A.Match(C.computer_id) )
A.is_banned = 1
if(user) << "Banned the associated account [A.owner_name]"


I've still got a bit of work to do to it, but yeah.