#define WORLD_ICON_SIZE 32 #define PIXEL_MULTIPLIER WORLD_ICON_SIZE/32 #define WORLD_MIN_SIZE 32 /* The initialization of the game happens roughly like this: 1. All global variables are initialized (including the global_init instance). 2. The map is initialized, and map objects are created. 3. world/New() runs, creating & starting the master controller. 4. The master controller initializes the rest of the game. */ var/global/datum/global_init/init = new () /* Pre-map initialization stuff should go here. */ /datum/global_init/New() generate_gameid() makeDatumRefLists() load_configuration() qdel(src) //we're done init = null /datum/global_init/Destroy() ..() return 3 // QDEL_HINT_HARDDEL ain't defined here, so magic number it is. /var/game_id = null /proc/generate_gameid() if(game_id != null) return game_id = "" var/list/c = list("a", "b", "c", "d", "e", "f", "g", "h", "i", "j", "k", "l", "m", "n", "o", "p", "q", "r", "s", "t", "u", "v", "w", "x", "y", "z", "A", "B", "C", "D", "E", "F", "G", "H", "I", "J", "K", "L", "M", "N", "O", "P", "Q", "R", "S", "T", "U", "V", "W", "X", "Y", "Z", "1", "2", "3", "4", "5", "6", "7", "8", "9", "0") var/l = c.len var/t = world.timeofday for(var/_ = 1 to 4) game_id = "[c[(t % l) + 1]][game_id]" t = round(t / l) game_id = "-[game_id]" t = round(world.realtime / (10 * 60 * 60 * 24)) for(var/_ = 1 to 3) game_id = "[c[(t % l) + 1]][game_id]" t = round(t / l) /world mob = /mob/abstract/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 maxx = WORLD_MIN_SIZE // So that we don't get map-window-popin at boot. DMMS will expand this. maxy = WORLD_MIN_SIZE #define RECOMMENDED_VERSION 510 /world/New() //logs diary_date_string = time2text(world.realtime, "YYYY/MM-Month/DD-Day") href_logfile = file("data/logs/[diary_date_string] hrefs.htm") diary = file("data/logs/[diary_date_string].log") diary << "[log_end]\n[log_end]\nStarting up. (ID: [game_id]) [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(config.log_runtime) diary_runtime = file("data/logs/_runtime/[diary_date_string]-runtime.log") if(byond_version < RECOMMENDED_VERSION) world.log << "Your server's byond version does not meet the recommended requirements for this server. Please update BYOND to [RECOMMENDED_VERSION]." 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]" callHook("startup") //Emergency Fix load_mods() //end-emergency fix . = ..() #ifdef UNIT_TEST log_unit_test("Unit Tests Enabled. This will destroy the world when testing is complete.") load_unit_test_changes() #endif // Do not add initialization stuff to this file, unless it *must* run before the MC initializes! // (hint: you generally won't need this) // To do things on server-start, create a subsystem or shove it into one of the miscellaneous init subsystems. Master.Initialize(10, FALSE) #undef RECOMMENDED_VERSION return var/list/world_api_rate_limit = list() /world/Topic(T, addr, master, key) var/list/response[] = list() var/list/queryparams[] try queryparams = json_decode(T) catch() queryparams = list() log_debug("API: Request Received - from:[addr], master:[master], key:[key]") diary << "TOPIC: \"[T]\", from:[addr], master:[master], key:[key], auth:[queryparams["auth"] ? queryparams["auth"] : "null"] [log_end]" if (!queryparams.len) log_debug("API - Bad Request - Invalid/no JSON data sent.") response["statuscode"] = 400 response["response"] = "Bad Request - Invalid/no JSON data sent." return json_encode(response) queryparams["addr"] = addr //Add the IP to the queryparams that are passed to the api functions var/query = queryparams["query"] var/auth = queryparams["auth"] /*if (!SSticker) //If the game is not started most API Requests would not work because of the throtteling response["statuscode"] = 500 response["response"] = "Game not started yet!" return json_encode(response)*/ if (isnull(query)) log_debug("API - Bad Request - No query specified") response["statuscode"] = 400 response["response"] = "Bad Request - No query specified" return json_encode(response) var/datum/topic_command/command = topic_commands[query] //Check if that command exists if (isnull(command)) log_debug("API: Unknown command called: [query]") response["statuscode"] = 501 response["response"] = "Not Implemented" return json_encode(response) var/unauthed = api_do_auth_check(addr,auth,command) if (unauthed) if (unauthed == 3) log_debug("API: Request denied - Auth Service Unavailable") response["statuscode"] = 503 response["response"] = "Auth Service Unavailable" return json_encode(response) else if (unauthed == 2) log_debug("API: Request denied - Throttled") response["statuscode"] = 429 response["response"] = "Throttled" return json_encode(response) else log_debug("API: Request denied - Bad Auth") response["statuscode"] = 401 response["response"] = "Bad Auth" return json_encode(response) log_debug("API: Auth valid") if(command.check_params_missing(queryparams)) log_debug("API: Mising Params - Status: [command.statuscode] - Response: [command.response]") response["statuscode"] = command.statuscode response["response"] = command.response response["data"] = command.data return json_encode(response) else command.run_command(queryparams) log_debug("API: Command called: [query] - Status: [command.statuscode] - Response: [command.response]") response["statuscode"] = command.statuscode response["response"] = command.response response["data"] = command.data return json_encode(response) /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 */ Master.Shutdown() 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 for(var/client/C in clients) C << link("byond://[config.server]") ..(reason) /world/Error(var/exception/e) var/static/inerror = 0 //runtime while processing runtimes if (inerror) inerror = 0 return ..(e) inerror = 1 // A horrible hack for unit tests but fuck runtiming timers. // They don't provide any useful information, and as such, are being suppressed. #ifdef UNIT_TEST if (findtextEx(e.name, "Invalid timer:") || findtextEx(e.desc, "Invalid timer:")) inerror = 0 return #endif // UNIT_TEST e.time_stamp() log_exception(e) inerror = 0 return ..(e) // We need this elsewhere! /exception/var/time_stamped = 0 /exception/proc/time_stamp() if (time_stamped) return //newline at start is because of the "runtime error" byond prints that can't be timestamped. name = "\n\[[time2text(world.timeofday,"hh:mm:ss")]\][name]" //this is done this way rather then replace text to pave the way for processing the runtime reports more thoroughly // (and because runtimes end with a newline, and we don't want to basically print an empty time stamp) var/list/split = splittext(desc, "\n") for (var/i in 1 to split.len) if (split[i] != "") split[i] = "\[[time2text(world.timeofday,"hh:mm:ss")]\][split[i]]" desc = jointext(split, "\n") time_stamped = 1 /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/initialize_greeting() world.initialize_greeting() return 1 /world/proc/initialize_greeting() server_greeting = new() /proc/load_configuration() config = new /datum/configuration() config.load("config/config.txt") config.load("config/game_options.txt","game_options") if (config.age_restrictions_from_file) config.load("config/age_restrictions.txt", "age_restrictions") /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/list/s = list() if (config && config.server_name) s += "[config.server_name] — " s += "[station_name()]"; s += " (" s += "" //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 += "" s += ")" var/list/features = list() if (Master.initialization_time_taken) // This is set at the end of initialization. if(master_mode) features += master_mode else features += "STARTING" 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" if (config && config.hostedby) features += "hosted by [config.hostedby]" if (features) s += ": [jointext(features, ", ")]" s = s.Join() /* 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. #ifdef UNIT_TEST // UTs are presumed public. Change this to hide your shit. error("Database connection failed with message:") error(con.ErrorMsg()) #else world.log << con.ErrorMsg() #endif 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) error("DB connection cutoff exceeded for a database object in establish_db_connection().") return 0 if (!con.IsConnected()) return setup_database_connection(con) else return 1 #undef FAILED_DB_CONNECTION_CUTOFF