mirror of
https://github.com/Aurorastation/Aurora.3.git
synced 2026-01-04 14:33:10 +00:00
Passes an empty DBConnection object whenever no config exists. This way, you don't need the config to be defined to run the server without runtime spam.
746 lines
21 KiB
Plaintext
746 lines
21 KiB
Plaintext
var/global/datum/global_init/init = new ()
|
|
|
|
/*
|
|
Pre-map initialization stuff should go here.
|
|
*/
|
|
/datum/global_init/New()
|
|
|
|
makeDatumRefLists()
|
|
load_configuration()
|
|
|
|
qdel(src)
|
|
|
|
|
|
/world
|
|
mob = /mob/new_player
|
|
turf = /turf/space
|
|
area = /area/space
|
|
view = "15x15"
|
|
cache_lifespan = 0 //stops player uploaded stuff from being kept in the rsc past the current session
|
|
|
|
|
|
|
|
#define RECOMMENDED_VERSION 501
|
|
/world/New()
|
|
//logs
|
|
var/date_string = time2text(world.realtime, "YYYY/MM-Month/DD-Day")
|
|
href_logfile = file("data/logs/[date_string] hrefs.htm")
|
|
diary = file("data/logs/[date_string].log")
|
|
diary << "[log_end]\n[log_end]\nStarting up. [time2text(world.timeofday, "hh:mm.ss")][log_end]\n---------------------[log_end]"
|
|
changelog_hash = md5('html/changelog.html') //used for telling if the changelog has changed recently
|
|
|
|
if(byond_version < RECOMMENDED_VERSION)
|
|
world.log << "Your server's byond version does not meet the recommended requirements for this server. Please update BYOND"
|
|
|
|
config.post_load()
|
|
|
|
if(config && config.server_name != null && config.server_suffix && world.port > 0)
|
|
// dumb and hardcoded but I don't care~
|
|
config.server_name += " #[(world.port % 1000) / 100]"
|
|
|
|
if(config && config.log_runtime)
|
|
log = file("data/logs/runtime/[time2text(world.realtime,"YYYY-MM-DD-(hh-mm-ss)")]-runtime.log")
|
|
|
|
callHook("startup")
|
|
//Emergency Fix
|
|
load_mods()
|
|
//end-emergency fix
|
|
|
|
src.update_status()
|
|
|
|
. = ..()
|
|
|
|
sleep_offline = 1
|
|
|
|
// Set up roundstart seed list.
|
|
plant_controller = new()
|
|
|
|
// This is kinda important. Set up details of what the hell things are made of.
|
|
populate_material_list()
|
|
|
|
//Create the asteroid Z-level.
|
|
if(config.generate_asteroid)
|
|
new /datum/random_map(null,13,32,5,217,223)
|
|
|
|
// Create autolathe recipes, as above.
|
|
populate_lathe_recipes()
|
|
|
|
// Create robolimbs for chargen.
|
|
populate_robolimb_list()
|
|
|
|
processScheduler = new
|
|
master_controller = new /datum/controller/game_controller()
|
|
spawn(1)
|
|
processScheduler.deferSetupFor(/datum/controller/process/ticker)
|
|
processScheduler.setup()
|
|
master_controller.setup()
|
|
|
|
spawn(3000) //so we aren't adding to the round-start lag
|
|
if(config.ToRban)
|
|
ToRban_autoupdate()
|
|
|
|
#undef RECOMMENDED_VERSION
|
|
|
|
return
|
|
|
|
var/world_topic_spam_protect_ip = "0.0.0.0"
|
|
var/world_topic_spam_protect_time = world.timeofday
|
|
|
|
/world/Topic(T, addr, master, key)
|
|
diary << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key][log_end]"
|
|
|
|
if (T == "ping")
|
|
var/x = 1
|
|
for (var/client/C)
|
|
x++
|
|
return x
|
|
|
|
else if(T == "players")
|
|
var/n = 0
|
|
for(var/mob/M in player_list)
|
|
if(M.client)
|
|
n++
|
|
return n
|
|
|
|
else if (T == "admins")
|
|
var/n = 0
|
|
for (var/client/client in clients)
|
|
if (client.holder && client.holder.rights & (R_MOD|R_ADMIN))
|
|
n++
|
|
|
|
return n
|
|
|
|
else if (T == "cciaa")
|
|
var/n = 0
|
|
for (var/client/client in clients)
|
|
if (client.holder && (client.holder.rights & R_CCIAA) && !(client.holder.rights & R_ADMIN))
|
|
n++
|
|
|
|
return n
|
|
|
|
else if (T == "gamemode")
|
|
return master_mode
|
|
|
|
else if (T == "who")
|
|
var/list/players = list()
|
|
for (var/client/C in clients)
|
|
players += C.key
|
|
|
|
return list2params(players)
|
|
|
|
else if (copytext(T,1,7) == "status")
|
|
var/input[] = params2list(T)
|
|
var/list/s = list()
|
|
s["version"] = game_version
|
|
s["mode"] = master_mode
|
|
s["respawn"] = config.abandon_allowed
|
|
s["enter"] = config.enter_allowed
|
|
s["vote"] = config.allow_vote_mode
|
|
s["ai"] = config.allow_ai
|
|
s["host"] = host ? host : null
|
|
|
|
// This is dumb, but spacestation13.com's banners break if player count isn't the 8th field of the reply, so... this has to go here.
|
|
s["players"] = 0
|
|
s["stationtime"] = worldtime2text()
|
|
s["roundduration"] = round_duration()
|
|
|
|
if(input["status"] == "2")
|
|
var/list/players = list()
|
|
var/list/admins = list()
|
|
|
|
for(var/client/C in clients)
|
|
if(C.holder)
|
|
if(C.holder.fakekey)
|
|
continue
|
|
admins[C.key] = C.holder.rank
|
|
players += C.key
|
|
|
|
s["players"] = players.len
|
|
s["playerlist"] = list2params(players)
|
|
s["admins"] = admins.len
|
|
s["adminlist"] = list2params(admins)
|
|
else
|
|
var/n = 0
|
|
var/admins = 0
|
|
|
|
for(var/client/C in clients)
|
|
if(C.holder)
|
|
if(C.holder.fakekey)
|
|
continue //so stealthmins aren't revealed by the hub
|
|
admins++
|
|
s["player[n]"] = C.key
|
|
n++
|
|
|
|
s["players"] = n
|
|
s["admins"] = admins
|
|
|
|
return list2params(s)
|
|
|
|
else if(T == "manifest")
|
|
if (!ticker)
|
|
return "Game not started yet!"
|
|
|
|
var/list/positions = list()
|
|
var/list/set_names = list(
|
|
"heads" = command_positions,
|
|
"sec" = security_positions,
|
|
"eng" = engineering_positions,
|
|
"med" = medical_positions,
|
|
"sci" = science_positions,
|
|
"civ" = civilian_positions,
|
|
"bot" = nonhuman_positions
|
|
)
|
|
|
|
for(var/datum/data/record/t in data_core.general)
|
|
var/name = t.fields["name"]
|
|
var/rank = t.fields["rank"]
|
|
var/real_rank = make_list_rank(t.fields["real_rank"])
|
|
|
|
var/department = 0
|
|
for(var/k in set_names)
|
|
if(real_rank in set_names[k])
|
|
if(!positions[k])
|
|
positions[k] = list()
|
|
positions[k][name] = rank
|
|
department = 1
|
|
if(!department)
|
|
if(!positions["misc"])
|
|
positions["misc"] = list()
|
|
positions["misc"][name] = rank
|
|
|
|
for(var/k in positions)
|
|
positions[k] = list2params(positions[k]) // converts positions["heads"] = list("Bob"="Captain", "Bill"="CMO") into positions["heads"] = "Bob=Captain&Bill=CMO"
|
|
|
|
return list2params(positions)
|
|
|
|
else if(copytext(T,1,5) == "mute")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
for (var/client/C in clients)
|
|
if (C.ckey == ckey(input["mute"]))
|
|
C.mute_discord = !C.mute_discord
|
|
|
|
switch (C.mute_discord)
|
|
if (1)
|
|
C << "<b><font color='red'>You have been muted from replying to Discord PMs by [input["admin"]]!</font></b>"
|
|
log_and_message_admins("[C] has been muted from Discord PMs by [input["admin"]].")
|
|
return "[C.key] is now muted from replying to Discord PMs."
|
|
if (0)
|
|
C << "<b><font color='red'>You have been unmuted from replying to Discord PMs by [input["admin"]]!</font></b>"
|
|
log_and_message_admins("[C] has been unmuted from Discord PMs by [input["admin"]].")
|
|
return "[C.key] is now unmuted from replying to Discord PMs."
|
|
|
|
return "I couldn't find that ckey!"
|
|
|
|
else if(copytext(T,1,5) == "info")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
var/list/search = params2list(input["info"])
|
|
var/list/ckeysearch = list()
|
|
for(var/text in search)
|
|
ckeysearch += ckey(text)
|
|
|
|
var/list/match = list()
|
|
|
|
for(var/mob/M in mob_list)
|
|
var/strings = list(M.name, M.ckey)
|
|
if(M.mind)
|
|
strings += M.mind.assigned_role
|
|
strings += M.mind.special_role
|
|
for(var/text in strings)
|
|
if(ckey(text) in ckeysearch)
|
|
match[M] += 10 // an exact match is far better than a partial one
|
|
else
|
|
for(var/searchstr in search)
|
|
if(findtext(text, searchstr))
|
|
match[M] += 1
|
|
|
|
var/maxstrength = 0
|
|
for(var/mob/M in match)
|
|
maxstrength = max(match[M], maxstrength)
|
|
for(var/mob/M in match)
|
|
if(match[M] < maxstrength)
|
|
match -= M
|
|
|
|
if(!match.len)
|
|
return "No matches"
|
|
else if(match.len == 1)
|
|
var/mob/M = match[1]
|
|
var/info = list()
|
|
info["key"] = M.key
|
|
if (M.client)
|
|
var/client/C = M.client
|
|
info["discordmuted"] = C.mute_discord ? "Yes" : "No"
|
|
info["name"] = M.name == M.real_name ? M.name : "[M.name] ([M.real_name])"
|
|
info["role"] = M.mind ? (M.mind.assigned_role ? M.mind.assigned_role : "No role") : "No mind"
|
|
var/turf/MT = get_turf(M)
|
|
info["loc"] = M.loc ? "[M.loc]" : "null"
|
|
info["turf"] = MT ? "[MT] @ [MT.x], [MT.y], [MT.z]" : "null"
|
|
info["area"] = MT ? "[MT.loc]" : "null"
|
|
info["antag"] = M.mind ? (M.mind.special_role ? M.mind.special_role : "Not antag") : "No mind"
|
|
info["hasbeenrev"] = M.mind ? M.mind.has_been_rev : "No mind"
|
|
info["stat"] = M.stat
|
|
info["type"] = M.type
|
|
if(isliving(M))
|
|
var/mob/living/L = M
|
|
info["damage"] = list2params(list(
|
|
oxy = L.getOxyLoss(),
|
|
tox = L.getToxLoss(),
|
|
fire = L.getFireLoss(),
|
|
brute = L.getBruteLoss(),
|
|
clone = L.getCloneLoss(),
|
|
brain = L.getBrainLoss()
|
|
))
|
|
else
|
|
info["damage"] = "non-living"
|
|
info["gender"] = M.gender
|
|
return list2params(info)
|
|
else
|
|
return "Multiple matches found!"
|
|
|
|
else if(copytext(T,1,9) == "adminmsg")
|
|
/*
|
|
We got an adminmsg from IRC bot lets split the input then validate the input.
|
|
expected output:
|
|
1. adminmsg = ckey of person the message is to
|
|
2. msg = contents of message, parems2list requires
|
|
3. validatationkey = the key the bot has, it should match the gameservers commspassword in it's configuration.
|
|
4. sender = the ircnick that send the message.
|
|
*/
|
|
|
|
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
var/client/C
|
|
var/req_ckey = ckey(input["adminmsg"])
|
|
|
|
for(var/client/K in clients)
|
|
if(K.ckey == req_ckey)
|
|
C = K
|
|
break
|
|
if(!C)
|
|
return "No client with that name on server"
|
|
|
|
var/rank = input["rank"]
|
|
if(!rank)
|
|
rank = "Admin"
|
|
|
|
var/message = "<font color='red'>Discord-[rank] PM from <b><a href='?discord_msg=[input["sender"]]'>Discord-[input["sender"]]</a></b>: [input["msg"]]</font>"
|
|
var/amessage = "<font color='blue'>Discord-[rank] PM from <a href='?discord_msg=[input["sender"]]'>Discord-[input["sender"]]</a> to <b>[key_name(C)]</b> : [input["msg"]]</font>"
|
|
|
|
C.received_discord_pm = world.time
|
|
C.discord_admin = input["sender"]
|
|
|
|
C << 'sound/effects/adminhelp.ogg'
|
|
C << message
|
|
|
|
|
|
for(var/client/A in admins)
|
|
if(A != C)
|
|
A << amessage
|
|
|
|
return "Message Successful"
|
|
|
|
else if(copytext(T,1,6) == "notes")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
return show_player_info_discord(ckey(input["notes"]))
|
|
|
|
else if(copytext(T,1,4) == "age")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
var/age = get_player_age(input["age"])
|
|
if(isnum(age))
|
|
if(age >= 0)
|
|
return "[age]"
|
|
else
|
|
return "Ckey not found"
|
|
else
|
|
return "Database connection failed or not set up"
|
|
|
|
else if (copytext(T, 1, 8) == "restart")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
log_and_message_admins("Remote restart attempted and stopped. Dumping topic call data.")
|
|
log_and_message_admins("TOPIC: \"[T]\", from: [addr], master: [master], key: [key].")
|
|
return bad_key
|
|
|
|
world << "<font size=4 color='#ff2222'>Server restarting by remote command.</font>"
|
|
log_and_message_admins("World restart initiated remotely by [input["restart"]].")
|
|
feedback_set_details("end_error","remote restart")
|
|
|
|
if (blackbox)
|
|
blackbox.save_all_data_to_sql()
|
|
|
|
sleep(50)
|
|
log_game("Rebooting due to remote command.")
|
|
world.Reboot(2)
|
|
|
|
return "Server successfully restarted."
|
|
|
|
else if (copytext(T, 1, 9) == "announce")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
var/message = replacetext(input["msg"], "\n", "<br>")
|
|
world << "<span class=notice><b>[input["announce"] ? input["announce"] : "Administrator"] Announces via Discord:</b><p style='text-indent: 50px'>[message]</p></span>"
|
|
log_and_message_admins("[input["announce"]] announced remotely: [input["msg"]].")
|
|
|
|
return "Announcement successfully sent."
|
|
|
|
else if (copytext(T, 1, 8) == "faxlist")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
if (!ticker)
|
|
return "Round hasn't started yet! No faxes to display!"
|
|
|
|
var/list/faxes = list()
|
|
switch (input["faxlist"])
|
|
if ("received")
|
|
faxes = arrived_faxes
|
|
if ("sent")
|
|
faxes = sent_faxes
|
|
|
|
if (!faxes || !faxes.len)
|
|
return "No faxes found!"
|
|
|
|
var/list/output = list()
|
|
for (var/i = 1, i <= faxes.len, i++)
|
|
var/obj/item/a = faxes[i]
|
|
output += "ID [i]"
|
|
output["ID [i]"] = a.name ? a.name : "Untitled Fax"
|
|
|
|
return list2params(output)
|
|
|
|
else if (copytext(T, 1, 7) == "getfax")
|
|
var/input[] = params2list(T)
|
|
var/bad_key = do_topic_spam_protection(addr, input["key"])
|
|
|
|
if (bad_key)
|
|
return bad_key
|
|
|
|
var/list/faxes = list()
|
|
switch (input["received"])
|
|
if ("received")
|
|
faxes = arrived_faxes
|
|
if ("sent")
|
|
faxes = sent_faxes
|
|
|
|
if (!faxes || !faxes.len)
|
|
return "No faxes found!"
|
|
|
|
var/fax_id = text2num(input["getfax"])
|
|
if (fax_id > faxes.len || fax_id < 1)
|
|
return "Invalid fax ID!"
|
|
|
|
var/output = list()
|
|
if (istype(faxes[fax_id], /obj/item/weapon/paper))
|
|
var/obj/item/weapon/paper/a = faxes[fax_id]
|
|
output["title"] = a.name ? a.name : "Untitled Fax"
|
|
|
|
var/content = replacetext(a.info, "<br>", "\n")
|
|
content = strip_html_properly(content, 0)
|
|
output["content"] = content
|
|
|
|
return list2params(output)
|
|
else if (istype(faxes[fax_id], /obj/item/weapon/photo))
|
|
return "The fax is a photo. I cannot send images, unfortunately..."
|
|
else if (istype(faxes[fax_id], /obj/item/weapon/paper_bundle))
|
|
var/obj/item/weapon/paper_bundle/b = faxes[fax_id]
|
|
output["title"] = b.name ? b.name : "Untitled Paper Bundle"
|
|
|
|
if (!b.pages || !b.pages.len)
|
|
return "The bundle was empty! How is that even possible?"
|
|
|
|
var/i = 0
|
|
for (var/obj/item/weapon/paper/c in b.pages)
|
|
i++
|
|
var/content = replacetext(c.info, "<br>", "\n")
|
|
content = strip_html_properly(content, 0)
|
|
output["content"] += "Page [i]:\n[content]\n\n"
|
|
|
|
return list2params(output)
|
|
|
|
return "Unable to recognize the fax type. Cannot send contents!"
|
|
|
|
/world/Reboot(var/reason)
|
|
/*spawn(0)
|
|
world << sound(pick('sound/AI/newroundsexy.ogg','sound/misc/apcdestroyed.ogg','sound/misc/bangindonk.ogg')) // random end sounds!! - LastyBatsy
|
|
*/
|
|
|
|
processScheduler.stop()
|
|
|
|
for(var/client/C in clients)
|
|
if(config.server) //if you set a server location in config.txt, it sends you there instead of trying to reconnect to the same world address. -- NeoFite
|
|
C << link("byond://[config.server]")
|
|
|
|
..(reason)
|
|
|
|
/hook/startup/proc/loadMode()
|
|
world.load_mode()
|
|
return 1
|
|
|
|
/world/proc/load_mode()
|
|
var/list/Lines = file2list("data/mode.txt")
|
|
if(Lines.len)
|
|
if(Lines[1])
|
|
master_mode = Lines[1]
|
|
log_misc("Saved mode is '[master_mode]'")
|
|
|
|
/world/proc/save_mode(var/the_mode)
|
|
var/F = file("data/mode.txt")
|
|
fdel(F)
|
|
F << the_mode
|
|
|
|
|
|
/hook/startup/proc/loadMOTD()
|
|
world.load_motd()
|
|
return 1
|
|
|
|
/world/proc/load_motd()
|
|
join_motd = file2text("config/motd.txt")
|
|
|
|
|
|
/proc/load_configuration()
|
|
config = new /datum/configuration()
|
|
config.load("config/config.txt")
|
|
config.load("config/game_options.txt","game_options")
|
|
|
|
/hook/startup/proc/loadMods()
|
|
world.load_mods()
|
|
world.load_mentors() // no need to write another hook.
|
|
return 1
|
|
|
|
/world/proc/load_mods()
|
|
if(config.admin_legacy_system)
|
|
var/text = file2text("config/moderators.txt")
|
|
if (!text)
|
|
error("Failed to load config/mods.txt")
|
|
else
|
|
var/list/lines = text2list(text, "\n")
|
|
for(var/line in lines)
|
|
if (!line)
|
|
continue
|
|
|
|
if (copytext(line, 1, 2) == ";")
|
|
continue
|
|
|
|
var/title = "Moderator"
|
|
var/rights = admin_ranks[title]
|
|
|
|
var/ckey = copytext(line, 1, length(line)+1)
|
|
var/datum/admins/D = new /datum/admins(title, rights, ckey)
|
|
D.associate(directory[ckey])
|
|
|
|
/world/proc/load_mentors()
|
|
if(config.admin_legacy_system)
|
|
var/text = file2text("config/mentors.txt")
|
|
if (!text)
|
|
error("Failed to load config/mentors.txt")
|
|
else
|
|
var/list/lines = text2list(text, "\n")
|
|
for(var/line in lines)
|
|
if (!line)
|
|
continue
|
|
if (copytext(line, 1, 2) == ";")
|
|
continue
|
|
|
|
var/title = "Mentor"
|
|
var/rights = admin_ranks[title]
|
|
|
|
var/ckey = copytext(line, 1, length(line)+1)
|
|
var/datum/admins/D = new /datum/admins(title, rights, ckey)
|
|
D.associate(directory[ckey])
|
|
|
|
/world/proc/update_status()
|
|
var/s = ""
|
|
|
|
if (config && config.server_name)
|
|
s += "<b>[config.server_name]</b> — "
|
|
|
|
s += "<b>[station_name()]</b>";
|
|
s += " ("
|
|
s += "<a href=\"[config.forumurl]\">" //Change this to wherever you want the hub to link to.
|
|
// s += "[game_version]"
|
|
s += "Forums" //Replace this with something else. Or ever better, delete it and uncomment the game version.
|
|
s += "</a>"
|
|
s += ")"
|
|
|
|
var/list/features = list()
|
|
|
|
if(ticker)
|
|
if(master_mode)
|
|
features += master_mode
|
|
else
|
|
features += "<b>STARTING</b>"
|
|
|
|
if (!config.enter_allowed)
|
|
features += "closed"
|
|
|
|
features += config.abandon_allowed ? "respawn" : "no respawn"
|
|
|
|
if (config && config.allow_vote_mode)
|
|
features += "vote"
|
|
|
|
if (config && config.allow_ai)
|
|
features += "AI allowed"
|
|
|
|
var/n = 0
|
|
for (var/mob/M in player_list)
|
|
if (M.client)
|
|
n++
|
|
|
|
if (n > 1)
|
|
features += "~[n] players"
|
|
else if (n > 0)
|
|
features += "~[n] player"
|
|
|
|
/*
|
|
is there a reason for this? the byond site shows 'hosted by X' when there is a proper host already.
|
|
if (host)
|
|
features += "hosted by <b>[host]</b>"
|
|
*/
|
|
|
|
if (!host && config && config.hostedby)
|
|
features += "hosted by <b>[config.hostedby]</b>"
|
|
|
|
if (features)
|
|
s += ": [list2text(features, ", ")]"
|
|
|
|
/* does this help? I do not know */
|
|
if (src.status != s)
|
|
src.status = s
|
|
|
|
#define FAILED_DB_CONNECTION_CUTOFF 5
|
|
|
|
/hook/startup/proc/load_databases()
|
|
//Construct the database object from an init file.
|
|
dbcon = initialize_database_object("config/dbconfig.txt")
|
|
|
|
if (!setup_database_connection(dbcon))
|
|
world.log << "Your server failed to establish a connection with the feedback database."
|
|
else
|
|
world.log << "Feedback database connection established."
|
|
return 1
|
|
|
|
/proc/initialize_database_object(var/filename)
|
|
if (!filename)
|
|
// The code is written in a manner that is spasses out whenever dbcon = null, so we just make a dummy DB object.
|
|
return new/DBConnection()
|
|
|
|
var/list/data = list("address", "port", "database", "login", "password")
|
|
|
|
var/list/Lines = file2list(filename)
|
|
|
|
if (!Lines)
|
|
// Return dummy object for safety.
|
|
return new/DBConnection()
|
|
|
|
for (var/t in Lines)
|
|
if (!t)
|
|
continue
|
|
|
|
t = trim(t)
|
|
if (length(t) == 0)
|
|
continue
|
|
else if (copytext(t, 1, 2) == "#")
|
|
continue
|
|
|
|
var/pos = findtext(t, " ")
|
|
var/name = null
|
|
var/value = null
|
|
|
|
name = lowertext(copytext(t, 1, pos))
|
|
value = copytext(t, pos + 1)
|
|
|
|
if (!name)
|
|
continue
|
|
|
|
if (name in data)
|
|
data[name] = value
|
|
else
|
|
log_misc("Unknown setting while setting up database connection. Filename: '[filename]', value: '[value]'.")
|
|
|
|
return new/DBConnection(data["address"], data["port"], data["database"], data["login"], data["password"])
|
|
|
|
/proc/setup_database_connection(var/DBConnection/con)
|
|
if (!con)
|
|
error("No DBConnection object passed to setup_database_connection().")
|
|
return 0
|
|
|
|
if (con.failed_connections > FAILED_DB_CONNECTION_CUTOFF) //If it failed to establish a connection more than 5 times in a row, don't bother attempting to conenct anymore.
|
|
return 0
|
|
|
|
con.Connect()
|
|
. = con.IsConnected()
|
|
if ( . )
|
|
con.failed_connections = 0 //If this connection succeeded, reset the failed connections counter.
|
|
else
|
|
con.failed_connections++ //If it failed, increase the failed connections counter.
|
|
world.log << con.ErrorMsg()
|
|
|
|
return .
|
|
|
|
//This proc ensures that the connection to the feedback database (global variable dbcon) is established
|
|
/proc/establish_db_connection(var/DBConnection/con)
|
|
if (!con)
|
|
error("No DBConnection object passed to establish_db_connection() proc.")
|
|
return 0
|
|
|
|
if (con.failed_connections > FAILED_DB_CONNECTION_CUTOFF)
|
|
return 0
|
|
|
|
if (!con.IsConnected())
|
|
return setup_database_connection(con)
|
|
else
|
|
return 1
|
|
|
|
#undef FAILED_DB_CONNECTION_CUTOFF
|
|
|
|
/world/proc/do_topic_spam_protection(var/addr, var/key)
|
|
if (!config.comms_password || config.comms_password == "")
|
|
return "No comms password configured, aborting."
|
|
|
|
if (key == config.comms_password)
|
|
return 0
|
|
else
|
|
if (world_topic_spam_protect_ip == addr && abs(world_topic_spam_protect_time - world.time) < 50)
|
|
|
|
spawn(50)
|
|
world_topic_spam_protect_time = world.time
|
|
return "Bad Key (Throttled)"
|
|
|
|
world_topic_spam_protect_time = world.time
|
|
world_topic_spam_protect_ip = addr
|
|
|
|
return "Bad Key"
|