From 815c35f19fff727485df36c1969bb5a02a772a50 Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Thu, 20 Jul 2023 15:08:31 -0500 Subject: [PATCH 01/13] Update some TGS stuff (#73414) - Make names version independent - Version .yml file (Will I write the code to ever use it, who tf knows?) - Add WatchdogLaunch.sh to .yml - Remove defunct PreSynchronize script. - Cargo isn't needed in WatchdogLaunch - Why are we running apt outside of the if? - grep was only needed for the LinuxOneShot (old tool) - Bring common code into one file TODO: - [x] Test this shit - Added a test app, ran locally, verified the scripts work, added it to CI --------- Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: san7890 --- code/__DEFINES/spaceman_dmm.dm | 6 -- code/_debugger.dm | 13 ++++ code/controllers/failsafe.dm | 71 +++++++++++++++++++++- code/controllers/master.dm | 26 ++++++-- code/controllers/subsystem.dm | 7 ++- code/controllers/subsystem/air.dm | 13 ++++ code/controllers/subsystem/assets.dm | 4 ++ code/controllers/subsystem/autotransfer.dm | 4 ++ code/controllers/subsystem/jukeboxes.dm | 5 ++ code/controllers/subsystem/mapping.dm | 15 ++++- code/controllers/subsystem/overmap.dm | 17 +++--- code/controllers/subsystem/shuttle.dm | 3 + code/controllers/subsystem/ticker.dm | 17 +++--- code/controllers/subsystem/timer.dm | 2 +- code/game/world.dm | 2 - code/modules/events/fugitive_spawning.dm | 17 +++--- code/modules/events/pirates.dm | 19 ++---- shiptest.dme | 1 + 18 files changed, 180 insertions(+), 62 deletions(-) create mode 100644 code/_debugger.dm diff --git a/code/__DEFINES/spaceman_dmm.dm b/code/__DEFINES/spaceman_dmm.dm index 89b635f76d5e..6d87700f3d24 100644 --- a/code/__DEFINES/spaceman_dmm.dm +++ b/code/__DEFINES/spaceman_dmm.dm @@ -37,12 +37,6 @@ /proc/auxtools_expr_stub() CRASH("auxtools not loaded") -/world/proc/enable_debugger() - var/dll = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") - if (dll) - call(dll, "auxtools_init")() - enable_debugging() - /world/Del() var/debug_server = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") if (debug_server) diff --git a/code/_debugger.dm b/code/_debugger.dm new file mode 100644 index 000000000000..dafc759ec563 --- /dev/null +++ b/code/_debugger.dm @@ -0,0 +1,13 @@ +//Datum used to init Auxtools debugging as early as possible +//Datum gets created in master.dm because for whatever reason global code in there gets runs first +//In case we ever figure out how to manipulate global init order please move the datum creation into this file +/datum/debugger + +/datum/debugger/New() + enable_debugger() + +/datum/debugger/proc/enable_debugger() + var/dll = world.GetConfig("env", "AUXTOOLS_DEBUG_DLL") + if (dll) + call(dll, "auxtools_init")() + enable_debugging() diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index ef78fb623386..df49e15c76e2 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -33,6 +33,22 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) /datum/controller/failsafe/Initialize() set waitfor = 0 Failsafe.Loop() + if (!Master || defcon == 0) //Master is gone/not responding and Failsafe just exited its loop + defcon = 3 //Reset defcon level as its used inside the emergency loop + while (defcon > 0) + var/recovery_result = emergency_loop() + if (recovery_result == 1) //Exit emergency loop and delete self if it was able to recover MC + break + else if (defcon == 1) //Exit Failsafe if we weren't able to recover the MC in the last stage + log_game("FailSafe: Failed to recover MC while in emergency state. Failsafe exiting.") + message_admins(span_boldannounce("Failsafe failed criticaly while trying to recreate broken MC. Please manually fix the MC or reboot the server. Failsafe exiting now.")) + message_admins(span_boldannounce("You can try manually calling these two procs:.")) + message_admins(span_boldannounce("/proc/recover_all_SS_and_recreate_master: Most stuff should still function but expect instability/runtimes/broken stuff.")) + message_admins(span_boldannounce("/proc/delete_all_SS_and_recreate_master: Most stuff will be broken but basic stuff like movement and chat should still work.")) + else if (recovery_result == -1) //Failed to recreate MC + defcon-- + sleep(initial(processing_interval)) //Wait a bit until the next try + if(!QDELETED(src)) qdel(src) //when Loop() returns, we delete ourselves and let the mc recreate us @@ -45,8 +61,8 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) while(running) lasttick = world.time if(!Master) - // Replace the missing Master! This should never, ever happen. - new /datum/controller/master() + // Break out of the main loop so we go into emergency state + break // Only poke it if overrides are not in effect. if(processing_interval > 0) if(Master.processing && Master.iteration) @@ -106,6 +122,57 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) defcon = 5 sleep(initial(processing_interval)) +//Emergency loop used when Master got deleted or the main loop exited while Defcon == 0 +//Loop is driven externally so runtimes only cancel the current recovery attempt +/datum/controller/failsafe/proc/emergency_loop() + //The code in this proc should be kept as simple as possible, anything complicated like to_chat might rely on master existing and runtime + //The goal should always be to get a new Master up and running before anything else + . = -1 + switch (defcon) //The lower defcon goes the harder we try to fix the MC + if (2 to 3) //Try to normally recreate the MC two times + . = Recreate_MC() + if (1) //Delete the old MC first so we don't transfer any info, in case that caused any issues + del(Master) + . = Recreate_MC() + + if (. == 1) //We were able to create a new master + master_iteration = 0 + SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set + Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this + to_chat(GLOB.admins, span_adminnotice("Failsafe recovered MC while in emergency state [defcon_pretty()]")) + else + log_game("FailSafe: Failsafe in emergency state and was unable to recreate MC while in defcon state [defcon_pretty()].") + message_admins(span_boldannounce("Failsafe in emergency state and master down, trying to recreate MC while in defcon level [defcon_pretty()] failed.")) + +///Recreate all SSs which will still cause data survive due to Recover(), the new Master will then find and take them from global.vars +/proc/recover_all_SS_and_recreate_master() + del(Master) + var/list/subsytem_types = subtypesof(/datum/controller/subsystem) + sortTim(subsytem_types, /proc/cmp_subsystem_init) + for(var/I in subsytem_types) + new I + . = Recreate_MC() + if (. == 1) //We were able to create a new master + SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set + Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this + to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after recovering all subsystems!")) + else + message_admins(span_boldannounce("Failed to create new MC!")) + +///Delete all existing SS to basically start over +/proc/delete_all_SS_and_recreate_master() + del(Master) + for(var/global_var in global.vars) + if (istype(global.vars[global_var], /datum/controller/subsystem)) + del(global.vars[global_var]) + . = Recreate_MC() + if (. == 1) //We were able to create a new master + SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set + Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this + to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after deleting and recreating all subsystems!")) + else + message_admins(span_boldannounce("Failed to create new MC!")) + /datum/controller/failsafe/proc/defcon_pretty() return defcon diff --git a/code/controllers/master.dm b/code/controllers/master.dm index f72f706c5bca..ef833467a63a 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -7,6 +7,11 @@ * **/ +//Init the debugger datum first so we can debug Master +//You might wonder why not just create the debugger datum global in its own file, since its loaded way earlier than this DM file +//Well for whatever reason then the Master gets created first and then the debugger when doing that +//So thats why this code lives here now, until someone finds out how Byond inits globals +GLOBAL_REAL(Debugger, /datum/debugger) = new //This is the ABSOLUTE ONLY THING that should init globally like this //2019 update: the failsafe,config and Global controllers also do it GLOBAL_REAL(Master, /datum/controller/master) = new @@ -88,15 +93,27 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/list/_subsystems = list() subsystems = _subsystems if (Master != src) - if (istype(Master)) + if (istype(Master)) //If there is an existing MC take over his stuff and delete it Recover() qdel(Master) + Master = src else + //Code used for first master on game boot or if existing master got deleted + Master = src var/list/subsytem_types = subtypesof(/datum/controller/subsystem) sortTim(subsytem_types, /proc/cmp_subsystem_init) + //Find any abandoned subsystem from the previous master (if there was any) + var/list/existing_subsystems = list() + for(var/global_var in global.vars) + if (istype(global.vars[global_var], /datum/controller/subsystem)) + existing_subsystems += global.vars[global_var] + //Either init a new SS or if an existing one was found use that for(var/I in subsytem_types) - _subsystems += new I - Master = src + var/datum/controller/subsystem/existing_subsystem = locate(I) in existing_subsystems + if (istype(existing_subsystem)) + _subsystems += existing_subsystem + else + _subsystems += new I if(!GLOB) new /datum/controller/global_vars @@ -127,7 +144,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new var/delay = 50 * ++Master.restart_count Master.restart_timeout = world.time + delay Master.restart_clear = world.time + (delay * 2) - Master.processing = FALSE //stop ticking this one + if (Master) //Can only do this if master hasn't been deleted + Master.processing = FALSE //stop ticking this one try new/datum/controller/master() catch diff --git a/code/controllers/subsystem.dm b/code/controllers/subsystem.dm index 8de4c62eddd3..f6e35bec6e59 100644 --- a/code/controllers/subsystem.dm +++ b/code/controllers/subsystem.dm @@ -128,7 +128,8 @@ dequeue() can_fire = 0 flags |= SS_NO_FIRE - Master.subsystems -= src + if (Master) + Master.subsystems -= src return ..() //Queue it to run. @@ -197,9 +198,9 @@ queue_next.queue_prev = queue_prev if (queue_prev) queue_prev.queue_next = queue_next - if (src == Master.queue_tail) + if (Master && (src == Master.queue_tail)) Master.queue_tail = queue_prev - if (src == Master.queue_head) + if (Master && (src == Master.queue_head)) Master.queue_head = queue_next queued_time = 0 if (state == SS_QUEUED) diff --git a/code/controllers/subsystem/air.dm b/code/controllers/subsystem/air.dm index e8f31f6fe343..4351ad863ea9 100644 --- a/code/controllers/subsystem/air.dm +++ b/code/controllers/subsystem/air.dm @@ -264,6 +264,19 @@ SUBSYSTEM_DEF(air) */ currentpart = SSAIR_PIPENETS +/datum/controller/subsystem/air/Recover() + hotspots = SSair.hotspots + networks = SSair.networks + rebuild_queue = SSair.rebuild_queue + expansion_queue = SSair.expansion_queue + atmos_machinery = SSair.atmos_machinery + atmos_air_machinery = SSair.atmos_air_machinery + pipe_init_dirs_cache = SSair.pipe_init_dirs_cache + gas_reactions = SSair.gas_reactions + high_pressure_delta = SSair.high_pressure_delta + currentrun = SSair.currentrun + deferred_airs = SSair.deferred_airs + string_mixes = SSair.string_mixes /** * Adds a given machine to the processing system for SSAIR_ATMOSMACHINERY processing. diff --git a/code/controllers/subsystem/assets.dm b/code/controllers/subsystem/assets.dm index 4b43f982909e..ef79e55dbe5a 100644 --- a/code/controllers/subsystem/assets.dm +++ b/code/controllers/subsystem/assets.dm @@ -31,3 +31,7 @@ SUBSYSTEM_DEF(assets) transport.Initialize(cache) ..() + +/datum/controller/subsystem/assets/Recover() + cache = SSassets.cache + preload = SSassets.preload diff --git a/code/controllers/subsystem/autotransfer.dm b/code/controllers/subsystem/autotransfer.dm index 926bfb4a0fe0..1cb5e7851c13 100644 --- a/code/controllers/subsystem/autotransfer.dm +++ b/code/controllers/subsystem/autotransfer.dm @@ -15,3 +15,7 @@ SUBSYSTEM_DEF(autotransfer) if (world.time > targettime) SSvote.initiate_vote("transfer",null, FALSE) //WS Edit - Ghost Vote Rework targettime = targettime + CONFIG_GET(number/vote_autotransfer_interval) + +/datum/controller/subsystem/autotransfer/Recover() + starttime = SSautotransfer.starttime + targettime = SSautotransfer.targettime diff --git a/code/controllers/subsystem/jukeboxes.dm b/code/controllers/subsystem/jukeboxes.dm index ba776e5b18a4..b0d774219a38 100644 --- a/code/controllers/subsystem/jukeboxes.dm +++ b/code/controllers/subsystem/jukeboxes.dm @@ -43,6 +43,11 @@ SUBSYSTEM_DEF(jukeboxes) M.playsound_local(M, null, 100, channel = youvegotafreejukebox[2], S = song_to_init) return activejukeboxes.len +/datum/controller/subsystem/jukeboxes/Recover() + songs = SSjukeboxes.songs + activejukeboxes = SSjukeboxes.activejukeboxes + freejukeboxchannels = SSjukeboxes.freejukeboxchannels + /datum/controller/subsystem/jukeboxes/proc/removejukebox(IDtoremove) if(islist(activejukeboxes[IDtoremove])) var/jukechannel = activejukeboxes[IDtoremove][2] diff --git a/code/controllers/subsystem/mapping.dm b/code/controllers/subsystem/mapping.dm index 5a38e511b873..117fe4a79e02 100644 --- a/code/controllers/subsystem/mapping.dm +++ b/code/controllers/subsystem/mapping.dm @@ -37,7 +37,6 @@ SUBSYSTEM_DEF(mapping) var/station_start // should only be used for maploading-related tasks var/space_levels_so_far = 0 var/list/datum/space_level/z_list - var/datum/space_level/empty_space /// List of all map zones var/list/map_zones = list() @@ -88,6 +87,7 @@ SUBSYSTEM_DEF(mapping) ruins_templates = SSmapping.ruins_templates ruin_types_list = SSmapping.ruin_types_list + ruin_types_probabilities = SSmapping.ruin_types_probabilities shuttle_templates = SSmapping.shuttle_templates shelter_templates = SSmapping.shelter_templates @@ -95,6 +95,19 @@ SUBSYSTEM_DEF(mapping) outpost_templates = SSmapping.outpost_templates + shuttle_templates = SSmapping.shuttle_templates + shelter_templates = SSmapping.shelter_templates + holodeck_templates = SSmapping.holodeck_templates + + areas_in_z = SSmapping.areas_in_z + map_zones = SSmapping.map_zones + biomes = SSmapping.biomes + planet_types = SSmapping.planet_types + + maplist = SSmapping.maplist + ship_purchase_list = SSmapping.ship_purchase_list + + virtual_z_translation = SSmapping.virtual_z_translation z_list = SSmapping.z_list #define INIT_ANNOUNCE(X) to_chat(world, "[X]"); log_world(X) diff --git a/code/controllers/subsystem/overmap.dm b/code/controllers/subsystem/overmap.dm index 125adf514288..2a09ae4c6ae7 100644 --- a/code/controllers/subsystem/overmap.dm +++ b/code/controllers/subsystem/overmap.dm @@ -436,13 +436,10 @@ SUBSYSTEM_DEF(overmap) return ship_count /datum/controller/subsystem/overmap/Recover() - if(istype(SSovermap.overmap_objects)) - overmap_objects = SSovermap.overmap_objects - if(istype(SSovermap.controlled_ships)) - controlled_ships = SSovermap.controlled_ships - if(istype(SSovermap.outposts)) - outposts = SSovermap.outposts - if(istype(SSovermap.events)) - events = SSovermap.events - if(istype(SSovermap.radius_positions)) - radius_positions = SSovermap.radius_positions + overmap_objects = SSovermap.overmap_objects + controlled_ships = SSovermap.controlled_ships + events = SSovermap.events + outposts = SSovermap.outposts + radius_positions = SSovermap.radius_positions + overmap_vlevel = SSovermap.overmap_vlevel + overmap_container = SSovermap.overmap_container diff --git a/code/controllers/subsystem/shuttle.dm b/code/controllers/subsystem/shuttle.dm index cbc553fb0f21..e306da3ee4c2 100644 --- a/code/controllers/subsystem/shuttle.dm +++ b/code/controllers/subsystem/shuttle.dm @@ -182,6 +182,7 @@ SUBSYSTEM_DEF(shuttle) return new_transit_dock /datum/controller/subsystem/shuttle/Recover() + initialized = SSshuttle.initialized if (istype(SSshuttle.mobile)) mobile = SSshuttle.mobile if (istype(SSshuttle.stationary)) @@ -192,6 +193,8 @@ SUBSYSTEM_DEF(shuttle) transit_requesters = SSshuttle.transit_requesters if (istype(SSshuttle.transit_request_failures)) transit_request_failures = SSshuttle.transit_request_failures + if (istype(SSshuttle.supply_packs)) + supply_packs = SSshuttle.supply_packs ordernum = SSshuttle.ordernum lockdown = SSshuttle.lockdown diff --git a/code/controllers/subsystem/ticker.dm b/code/controllers/subsystem/ticker.dm index 5fd2805507b7..86c76e653f51 100644 --- a/code/controllers/subsystem/ticker.dm +++ b/code/controllers/subsystem/ticker.dm @@ -11,7 +11,7 @@ SUBSYSTEM_DEF(ticker) var/current_state = GAME_STATE_STARTUP //state of current round (used by process()) Use the defines GAME_STATE_* ! var/force_ending = 0 //Round was ended by admin intervention // If true, there is no lobby phase, the game starts immediately. - var/start_immediately = FALSE + var/start_immediately = TRUE var/setup_done = FALSE //All game setup done including mode post setup and var/hide_mode = 0 @@ -429,13 +429,14 @@ SUBSYSTEM_DEF(ticker) queue_delay = SSticker.queue_delay queued_players = SSticker.queued_players - switch (current_state) - if(GAME_STATE_SETTING_UP) - Master.SetRunLevel(RUNLEVEL_SETUP) - if(GAME_STATE_PLAYING) - Master.SetRunLevel(RUNLEVEL_GAME) - if(GAME_STATE_FINISHED) - Master.SetRunLevel(RUNLEVEL_POSTGAME) + if (Master) //Set Masters run level if it exists + switch (current_state) + if(GAME_STATE_SETTING_UP) + Master.SetRunLevel(RUNLEVEL_SETUP) + if(GAME_STATE_PLAYING) + Master.SetRunLevel(RUNLEVEL_GAME) + if(GAME_STATE_FINISHED) + Master.SetRunLevel(RUNLEVEL_POSTGAME) /datum/controller/subsystem/ticker/proc/send_news_report() var/news_message diff --git a/code/controllers/subsystem/timer.dm b/code/controllers/subsystem/timer.dm index cec14d1ef219..5e499069e71d 100644 --- a/code/controllers/subsystem/timer.dm +++ b/code/controllers/subsystem/timer.dm @@ -342,7 +342,7 @@ SUBSYSTEM_DEF(timer) /datum/controller/subsystem/timer/Recover() - // Find the current timer sub-subsystem in global and recover its buckets etc + //Find the current timer sub-subsystem in global and recover its buckets etc var/datum/controller/subsystem/timer/timerSS = null for(var/global_var in global.vars) if (istype(global.vars[global_var],src.type)) diff --git a/code/game/world.dm b/code/game/world.dm index effed0cb63a3..68cfb89213ff 100644 --- a/code/game/world.dm +++ b/code/game/world.dm @@ -32,8 +32,6 @@ GLOBAL_VAR(restart_counter) //Keep the auxtools stuff at the top AUXTOOLS_CHECK(AUXMOS) - enable_debugger() - log_world("World loaded at [time_stamp()]!") SSmetrics.world_init_time = REALTIMEOFDAY // Important diff --git a/code/modules/events/fugitive_spawning.dm b/code/modules/events/fugitive_spawning.dm index 30ca398014f5..8cf295310282 100644 --- a/code/modules/events/fugitive_spawning.dm +++ b/code/modules/events/fugitive_spawning.dm @@ -99,17 +99,14 @@ //security team gets called in after 10 minutes of prep to find the refugees /datum/round_event/ghost_role/fugitives/proc/spawn_hunters() var/backstory = pick( "russian", "bounty hunter") - var/datum/map_template/shuttle/ship + var/datum/map_template/shuttle/template if (backstory == "russian") - ship = new /datum/map_template/shuttle/hunter/russian + template = new /datum/map_template/shuttle/hunter/russian else - ship = new /datum/map_template/shuttle/hunter/bounty - var/x = rand(TRANSITIONEDGE,world.maxx - TRANSITIONEDGE - ship.width) - var/y = rand(TRANSITIONEDGE,world.maxy - TRANSITIONEDGE - ship.height) - var/z = SSmapping.empty_space.z_value - var/turf/T = locate(x,y,z) - if(!T) - CRASH("Fugitive Hunters (Created from fugitive event) found no turf to load in") - if(!ship.load(T)) + template = new /datum/map_template/shuttle/hunter/bounty + + var/datum/overmap/ship/controlled/ship = new(SSovermap.get_unused_overmap_square(), template) + + if(!ship) CRASH("Loading [backstory] ship failed!") priority_announce("Unidentified ship detected near the station.") diff --git a/code/modules/events/pirates.dm b/code/modules/events/pirates.dm index 691785c5670a..f5e71a3c7c84 100644 --- a/code/modules/events/pirates.dm +++ b/code/modules/events/pirates.dm @@ -7,12 +7,6 @@ earliest_start = 30 MINUTES gamemode_blacklist = list("nuclear") -/datum/round_event_control/pirates/preRunEvent() - if (!SSmapping.empty_space) - return EVENT_CANT_RUN - - return ..() - /datum/round_event/pirates startWhen = 60 //2 minutes to answer var/datum/comm_message/threat @@ -67,18 +61,13 @@ var/list/candidates = pollGhostCandidates("Do you wish to be considered for pirate crew?", ROLE_TRAITOR) shuffle_inplace(candidates) - var/datum/map_template/shuttle/pirate/default/ship = new - var/x = rand(TRANSITIONEDGE,world.maxx - TRANSITIONEDGE - ship.width) - var/y = rand(TRANSITIONEDGE,world.maxy - TRANSITIONEDGE - ship.height) - var/z = SSmapping.empty_space.z_value - var/turf/T = locate(x,y,z) - if(!T) - CRASH("Pirate event found no turf to load in") + var/datum/map_template/shuttle/pirate/default/template = new + var/datum/overmap/ship/controlled/ship = new(SSovermap.get_unused_overmap_square(), template) - if(!ship.load(T)) + if(!ship) CRASH("Loading pirate ship failed!") - for(var/turf/A in ship.get_affected_turfs(T)) + for(var/turf/A in ship.shuttle_port.return_turfs()) for(var/obj/effect/mob_spawn/human/pirate/spawner in A) if(candidates.len > 0) var/mob/M = candidates[1] diff --git a/shiptest.dme b/shiptest.dme index 456902e5ab13..f1f6f0ce8b8e 100644 --- a/shiptest.dme +++ b/shiptest.dme @@ -16,6 +16,7 @@ #include "_maps\_basemap.dm" #include "code\__byond_version_compat.dm" #include "code\_compile_options.dm" +#include "code\_debugger.dm" #include "code\world.dm" #include "code\__DEFINES\_click.dm" #include "code\__DEFINES\_globals.dm" From 0db12871c2a4218fead4d6c2ae8f239bf340c124 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 21 Feb 2023 18:49:16 -0500 Subject: [PATCH 02/13] Update some TGS stuff (#73414) - Make names version independent - Version .yml file (Will I write the code to ever use it, who tf knows?) - Add WatchdogLaunch.sh to .yml - Remove defunct PreSynchronize script. - Cargo isn't needed in WatchdogLaunch - Why are we running apt outside of the if? - grep was only needed for the LinuxOneShot (old tool) - Bring common code into one file TODO: - [x] Test this shit - Added a test app, ran locally, verified the scripts work, added it to CI --------- Co-authored-by: John Willard <53777086+JohnFulpWillard@users.noreply.github.com> Co-authored-by: san7890 --- .gitignore | 10 +- .tgs.yml | 13 + .tgs4.yml | 8 - code/controllers/failsafe.dm | 6 +- code/controllers/master.dm | 4 +- tools/tgs4_scripts/PreSynchronize.sh | 37 -- .../InstallDeps.sh} | 30 +- .../PreCompile.bat | 2 +- .../PreCompile.sh | 2 +- .../PreSynchronize.bat | 0 .../PreSynchronize.ps1 | 0 tools/tgs_scripts/WatchdogLaunch.sh | 6 + tools/tgs_test/Program.cs | 334 ++++++++++++++++++ tools/tgs_test/README.md | 11 + tools/tgs_test/StaticFile.cs | 5 + tools/tgs_test/TgsYml.cs | 15 + tools/tgs_test/Tgstation.TgsTest.csproj | 17 + tools/tgs_test/Tgstation.TgsTest.sln | 25 ++ 18 files changed, 455 insertions(+), 70 deletions(-) create mode 100644 .tgs.yml delete mode 100644 .tgs4.yml delete mode 100755 tools/tgs4_scripts/PreSynchronize.sh rename tools/{tgs4_scripts/WatchdogLaunch.sh => tgs_scripts/InstallDeps.sh} (50%) mode change 100644 => 100755 rename tools/{tgs4_scripts => tgs_scripts}/PreCompile.bat (81%) rename tools/{tgs4_scripts => tgs_scripts}/PreCompile.sh (96%) rename tools/{tgs4_scripts => tgs_scripts}/PreSynchronize.bat (100%) rename tools/{tgs4_scripts => tgs_scripts}/PreSynchronize.ps1 (100%) create mode 100755 tools/tgs_scripts/WatchdogLaunch.sh create mode 100644 tools/tgs_test/Program.cs create mode 100644 tools/tgs_test/README.md create mode 100644 tools/tgs_test/StaticFile.cs create mode 100644 tools/tgs_test/TgsYml.cs create mode 100644 tools/tgs_test/Tgstation.TgsTest.csproj create mode 100644 tools/tgs_test/Tgstation.TgsTest.sln diff --git a/.gitignore b/.gitignore index 35df6d730a28..94713bc82e1c 100644 --- a/.gitignore +++ b/.gitignore @@ -189,13 +189,9 @@ Temporary Items !/config/title_screens/images/exclude #Linux docker -/tools/LinuxOneShot/SetupProgram/obj/* -/tools/LinuxOneShot/SetupProgram/bin/* -/tools/LinuxOneShot/SetupProgram/.vs -/tools/LinuxOneShot/Database -/tools/LinuxOneShot/TGS_Config -/tools/LinuxOneShot/TGS_Instances -/tools/LinuxOneShot/TGS_Logs +/tools/tgs_test/.vs/* +/tools/tgs_test/bin/* +/tools/tgs_test/obj/* # JavaScript tools **/node_modules diff --git a/.tgs.yml b/.tgs.yml new file mode 100644 index 000000000000..aa8d52acedea --- /dev/null +++ b/.tgs.yml @@ -0,0 +1,13 @@ +version: 1 +byond: 514.1588 +static_files: + - name: config + populate: true + - name: data +linux_scripts: + PreCompile.sh: tools/tgs_scripts/PreCompile.sh + WatchdogLaunch.sh: tools/tgs_scripts/WatchdogLaunch.sh + InstallDeps.sh: tools/tgs_scripts/InstallDeps.sh +windows_scripts: + PreCompile.bat: tools/tgs_scripts/PreCompile.bat +security: Trusted diff --git a/.tgs4.yml b/.tgs4.yml deleted file mode 100644 index 932a3a6672ff..000000000000 --- a/.tgs4.yml +++ /dev/null @@ -1,8 +0,0 @@ -static_files: - - name: config - populate: true - - name: data -linux_scripts: - PreCompile.sh: tools/tgs4_scripts/PreCompile.sh -windows_scripts: - PreCompile.bat: tools/tgs4_scripts/PreCompile.bat diff --git a/code/controllers/failsafe.dm b/code/controllers/failsafe.dm index df49e15c76e2..9119697b064f 100644 --- a/code/controllers/failsafe.dm +++ b/code/controllers/failsafe.dm @@ -138,7 +138,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) if (. == 1) //We were able to create a new master master_iteration = 0 SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set - Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this + Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this to_chat(GLOB.admins, span_adminnotice("Failsafe recovered MC while in emergency state [defcon_pretty()]")) else log_game("FailSafe: Failsafe in emergency state and was unable to recreate MC while in defcon state [defcon_pretty()].") @@ -154,7 +154,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) . = Recreate_MC() if (. == 1) //We were able to create a new master SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set - Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this + Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after recovering all subsystems!")) else message_admins(span_boldannounce("Failed to create new MC!")) @@ -168,7 +168,7 @@ GLOBAL_REAL(Failsafe, /datum/controller/failsafe) . = Recreate_MC() if (. == 1) //We were able to create a new master SSticker.Recover(); //Recover the ticket system so the Masters runlevel gets set - Master.Initialize(10, FALSE, TRUE) //Need to manually start the MC, normally world.new would do this + Master.Initialize(10, FALSE, FALSE) //Need to manually start the MC, normally world.new would do this to_chat(GLOB.admins, span_adminnotice("MC successfully recreated after deleting and recreating all subsystems!")) else message_admins(span_boldannounce("Failed to create new MC!")) diff --git a/code/controllers/master.dm b/code/controllers/master.dm index ef833467a63a..6f55532aed39 100644 --- a/code/controllers/master.dm +++ b/code/controllers/master.dm @@ -191,8 +191,8 @@ GLOBAL_REAL(Master, /datum/controller/master) = new current_runlevel = Master.current_runlevel StartProcessing(10) else - to_chat(world, "The Master Controller is having some issues, we will need to re-initialize EVERYTHING") - Initialize(20, TRUE) + to_chat(world, span_boldannounce("The Master Controller is having some issues, we will need to re-initialize EVERYTHING")) + Initialize(20, TRUE, FALSE) // Please don't stuff random bullshit here, diff --git a/tools/tgs4_scripts/PreSynchronize.sh b/tools/tgs4_scripts/PreSynchronize.sh deleted file mode 100755 index 63091bf4b30b..000000000000 --- a/tools/tgs4_scripts/PreSynchronize.sh +++ /dev/null @@ -1,37 +0,0 @@ -#!/bin/sh - -has_python="$(command -v python3)" -has_git="$(command -v git)" -has_sudo="$(command -v sudo)" -has_pip="$(command -v pip3)" - -set -e - -if ! { [ -x "$has_python" ] && [ -x "$has_pip" ] && [ -x "$has_git" ]; }; then - echo "Installing apt dependencies..." - if ! [ -x "$has_sudo" ]; then - apt update - apt install -y python3 python3-pip git - rm -rf /var/lib/apt/lists/* - else - sudo apt update - sudo apt install -y python3 python3-pip git - sudo rm -rf /var/lib/apt/lists/* - fi -fi - -echo "Installing pip dependencies..." -pip3 install PyYaml beautifulsoup4 - -cd $1 - -echo "Running changelog script..." -python3 tools/ss13_genchangelog.py html/changelogs - -echo "Committing changes..." -git add html - -#we now don't care about failures -set +e -git commit -m "Automatic changelog compile, [ci skip]" -exit 0 diff --git a/tools/tgs4_scripts/WatchdogLaunch.sh b/tools/tgs_scripts/InstallDeps.sh old mode 100644 new mode 100755 similarity index 50% rename from tools/tgs4_scripts/WatchdogLaunch.sh rename to tools/tgs_scripts/InstallDeps.sh index 7e184a6ce86d..6069e28ad9c7 --- a/tools/tgs4_scripts/WatchdogLaunch.sh +++ b/tools/tgs_scripts/InstallDeps.sh @@ -1,19 +1,14 @@ #!/bin/bash -# Special file to ensure all dependencies still exist between server lanuches. -# Mainly for use by people who abuse docker by modifying the container's system. -set -e -set -x - #find out what we have (+e is important for this) set +e has_git="$(command -v git)" has_cargo="$(command -v ~/.cargo/bin/cargo)" has_sudo="$(command -v sudo)" -has_grep="$(command -v grep)" has_youtubedl="$(command -v youtube-dl)" has_pip3="$(command -v pip3)" set -e +set -x # install cargo if needed if ! [ -x "$has_cargo" ]; then @@ -23,19 +18,32 @@ if ! [ -x "$has_cargo" ]; then fi # apt packages, libssl needed by rust-g but not included in TGS barebones install -if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then - dpkg --add-architecture i386 - apt-get update - apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev libssl1.1:i386 +if ! ( [ -x "$has_git" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then + echo "Installing apt dependencies..." + if ! [ -x "$has_sudo" ]; then + dpkg --add-architecture i386 + apt-get update + apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 + else + sudo dpkg --add-architecture i386 + sudo apt-get update + sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 + fi fi -# install youtube-dl when not present +# install or update youtube-dl when not present, or if it is present with pip3, +# which we assume was used to install it if ! [ -x "$has_youtubedl" ]; then echo "Installing youtube-dl with pip3..." if ! [ -x "$has_sudo" ]; then + apt-get update apt-get install -y python3 python3-pip else + sudo apt-get update sudo apt-get install -y python3 python3-pip fi pip3 install youtube-dl +elif [ -x "$has_pip3" ]; then + echo "Ensuring youtube-dl is up-to-date with pip3..." + pip3 install youtube-dl -U fi diff --git a/tools/tgs4_scripts/PreCompile.bat b/tools/tgs_scripts/PreCompile.bat similarity index 81% rename from tools/tgs4_scripts/PreCompile.bat rename to tools/tgs_scripts/PreCompile.bat index ccf0b027789e..679aaaad460a 100644 --- a/tools/tgs4_scripts/PreCompile.bat +++ b/tools/tgs_scripts/PreCompile.bat @@ -2,7 +2,7 @@ cd /D "%~dp0" set TG_BOOTSTRAP_CACHE=%cd% IF NOT %1 == "" ( - rem TGS4: we are passed the game directory on the command line + rem TGS4+: we are passed the game directory on the command line cd %1 ) ELSE IF EXIST "..\Game\B\shiptest.dmb" ( rem TGS3: Game/B/shiptest.dmb exists, so build in Game/A diff --git a/tools/tgs4_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh similarity index 96% rename from tools/tgs4_scripts/PreCompile.sh rename to tools/tgs_scripts/PreCompile.sh index d94c88c5e3b8..799e817486b8 100755 --- a/tools/tgs4_scripts/PreCompile.sh +++ b/tools/tgs_scripts/PreCompile.sh @@ -1,6 +1,6 @@ #!/bin/bash -# REPO MAINTAINERS: KEEP CHANGES TO THIS IN SYNC WITH /tools/LinuxOneShot/SetupProgram/PreCompile.sh +./InstallDeps.sh set -e set -x diff --git a/tools/tgs4_scripts/PreSynchronize.bat b/tools/tgs_scripts/PreSynchronize.bat similarity index 100% rename from tools/tgs4_scripts/PreSynchronize.bat rename to tools/tgs_scripts/PreSynchronize.bat diff --git a/tools/tgs4_scripts/PreSynchronize.ps1 b/tools/tgs_scripts/PreSynchronize.ps1 similarity index 100% rename from tools/tgs4_scripts/PreSynchronize.ps1 rename to tools/tgs_scripts/PreSynchronize.ps1 diff --git a/tools/tgs_scripts/WatchdogLaunch.sh b/tools/tgs_scripts/WatchdogLaunch.sh new file mode 100755 index 000000000000..cd400cbb969b --- /dev/null +++ b/tools/tgs_scripts/WatchdogLaunch.sh @@ -0,0 +1,6 @@ +#!/bin/bash + +# Special file to ensure all dependencies still exist between server launches. +# Mainly for use by people who abuse docker by modifying the container's system. + +./InstallDeps.sh diff --git a/tools/tgs_test/Program.cs b/tools/tgs_test/Program.cs new file mode 100644 index 000000000000..e111e19cbfb1 --- /dev/null +++ b/tools/tgs_test/Program.cs @@ -0,0 +1,334 @@ +// Simple app meant to test tgstation's TGS integration given a fresh TGS install with the default account +// +// Args: Repository Owner/Name, TGS instance path, TGS API port, Pushed commit hash (For .tgs.yml access), GitHub Token + +using System.Reflection; +using System.Text; + +using Octokit; +using Tgstation.Server.Api; +using Tgstation.Server.Api.Models.Request; +using Tgstation.Server.Api.Models; +using Tgstation.Server.Api.Models.Response; +using Tgstation.Server.Client; +using YamlDotNet.Serialization.NamingConventions; +using YamlDotNet.Serialization; + +Console.WriteLine("Parsing args..."); + +const int ExpectedArgs = 5; +if (args.Length != ExpectedArgs) +{ + Console.WriteLine($"Incorrect number of args: {args.Length}. Expected {ExpectedArgs}"); + return 1; +} + +var repoSlug = args[0]; +var instancePath = args[1]; +var tgsApiPortString = args[2]; +var pushedCommitHash = args[3]; +var gitHubToken = args[4]; + +var repoSlugSplits = repoSlug.Split('/', StringSplitOptions.RemoveEmptyEntries); +if(repoSlugSplits.Length != 2) +{ + Console.WriteLine($"Invalid repo slug: {repoSlug}"); + return 2; +} + +var repoOwner = repoSlugSplits[0]; +var repoName = repoSlugSplits[1]; + +if (!ushort.TryParse(tgsApiPortString, out var tgsApiPort)) +{ + Console.WriteLine($"Invalid port: {tgsApiPortString}"); + return 3; +} + +try +{ + Console.WriteLine($"Retrieving .tgs.yml (@{pushedCommitHash})..."); + var assemblyName = Assembly.GetExecutingAssembly().GetName(); + var gitHubClient = new GitHubClient( + new ProductHeaderValue( + assemblyName.Name, + assemblyName.Version!.Semver().ToString())) + { + Credentials = new Credentials(gitHubToken) + }; + + var tgsYmlContent = await gitHubClient.Repository.Content.GetRawContentByRef(repoOwner, repoName, ".tgs.yml", pushedCommitHash); + var tgsYmlString = Encoding.UTF8.GetString(tgsYmlContent); + + var deserializer = new DeserializerBuilder() + .WithNamingConvention(new UnderscoredNamingConvention()) + .Build(); + + var tgsYml = deserializer.Deserialize(tgsYmlString); + + const int SupportedTgsYmlVersion = 1; + if (tgsYml.Version != SupportedTgsYmlVersion) + { + Console.WriteLine($"Unsupported .tgs.yml version: {tgsYml.Version}. Expected {SupportedTgsYmlVersion}"); + return 4; + } + + var targetByondVersion = Version.Parse(tgsYml.Byond); + + Console.WriteLine($".tgs.yml Security level: {tgsYml.Security}"); + + Console.WriteLine("Downloading and checking BYOND version in dependencies.sh..."); + var dependenciesShContent = await gitHubClient.Repository.Content.GetRawContentByRef(repoOwner, repoName, "dependencies.sh", pushedCommitHash); + var dependenciesSh = Encoding.UTF8.GetString(dependenciesShContent); + var dependenciesShLines = dependenciesSh.Split(new char[] { '\r', '\n' }, StringSplitOptions.RemoveEmptyEntries); + + int dependenciesShByondMajor = 0; + int dependenciesShByondMinor = 0; + foreach(var dependenciesShLine in dependenciesShLines) + { + var trimmedLine = dependenciesShLine.Trim(); + var lineSplit = trimmedLine.Split('=', StringSplitOptions.RemoveEmptyEntries); + if (lineSplit.Length != 2) + continue; + + if (lineSplit[0].EndsWith("BYOND_MAJOR")) + dependenciesShByondMajor = Int32.Parse(lineSplit[1]); + else if (lineSplit[0].EndsWith("BYOND_MINOR")) + dependenciesShByondMinor = Int32.Parse(lineSplit[1]); + } + + var dependenciesByondVersion = new Version(dependenciesShByondMajor, dependenciesShByondMinor); + if(dependenciesByondVersion != targetByondVersion) + { + Console.WriteLine($".tgs.yml BYOND version does not match dependencies.sh! Expected {dependenciesByondVersion} got {targetByondVersion}!"); + return 5; + } + + // Connect to TGS + var clientFactory = new ServerClientFactory( + new System.Net.Http.Headers.ProductHeaderValue( + assemblyName.Name!, + assemblyName.Version!.Semver().ToString())); + + var tgsApiUrl = new Uri($"http://127.0.0.1:{tgsApiPort}"); + var giveUpAt = DateTimeOffset.UtcNow.AddMinutes(2); + IServerClient client; + for (var I = 1; ; ++I) + { + try + { + Console.WriteLine($"TGS Connection Attempt {I}..."); + client = await clientFactory.CreateFromLogin( + tgsApiUrl, + DefaultCredentials.AdminUserName, + DefaultCredentials.DefaultAdminUserPassword); + break; + } + catch (HttpRequestException) + { + //migrating, to be expected + if (DateTimeOffset.UtcNow > giveUpAt) + throw; + await Task.Delay(TimeSpan.FromSeconds(1)); + } + catch (ServiceUnavailableException) + { + // migrating, to be expected + if (DateTimeOffset.UtcNow > giveUpAt) + throw; + await Task.Delay(TimeSpan.FromSeconds(1)); + } + } + + + Console.WriteLine("Getting TGS information..."); + + var tgsInfo = await client.ServerInformation(default); + + var scriptDictionaryToUse = tgsInfo.WindowsHost ? tgsYml.WindowsScripts : tgsYml.LinuxScripts; + Console.WriteLine($"Downloading {scriptDictionaryToUse.Count} EventScripts..."); + + var scriptDownloadTasks = new Dictionary>(); + foreach (var scriptKvp in scriptDictionaryToUse) + { + scriptDownloadTasks.Add( + scriptKvp.Key, + gitHubClient.Repository.Content.GetRawContentByRef(repoOwner, repoName, scriptKvp.Value, pushedCommitHash)); + } + + await Task.WhenAll(scriptDownloadTasks.Values); + + Console.WriteLine("Setting up TGS instance..."); + + var instance = await client.Instances.CreateOrAttach( + new InstanceCreateRequest + { + ConfigurationType = ConfigurationType.HostWrite, + Name = "tgstation", + Path = instancePath + }, + default); + + instance = await client.Instances.Update( + new InstanceUpdateRequest + { + Id = instance.Id, + Online = true + }, + default); + + var instanceClient = client.Instances.CreateClient(instance); + + Console.WriteLine("Cloning main branch of repo..."); + var repoCloneJob = await instanceClient.Repository.Clone( + new RepositoryCreateRequest + { + Origin = new Uri($"http://github.com/{repoSlug}"), + UpdateSubmodules = true, + AccessUser = "Testing", + AccessToken = gitHubToken + }, + default); + + Console.WriteLine("Installing BYOND..."); + var byondInstallJob = await instanceClient.Byond.SetActiveVersion( + new ByondVersionRequest + { + Version = targetByondVersion + }, + null, + default); + + Console.WriteLine("Updating server/compiler settings..."); + await instanceClient.DreamMaker.Update( + new DreamMakerRequest + { + ApiValidationSecurityLevel = tgsYml.Security + }, + default); + + await instanceClient.DreamDaemon.Update( + new DreamDaemonRequest + { + SecurityLevel = tgsYml.Security, + Visibility = DreamDaemonVisibility.Invisible + }, + default); + + Console.WriteLine("Uploading EventScripts..."); + var configurationUploadTasks = new List>(); + foreach (var scriptDownloadKvp in scriptDownloadTasks) + { + var scriptContent = await scriptDownloadKvp.Value; + + var memoryStream = new MemoryStream(scriptContent); + configurationUploadTasks.Add( + instanceClient.Configuration.Write(new ConfigurationFileRequest + { + Path = $"EventScripts/{scriptDownloadKvp.Key}" + }, + memoryStream, + default)); + } + + await Task.WhenAll(configurationUploadTasks); + + Console.WriteLine("Creating GameStaticFiles structure..."); + var staticFileDownloadTasks = new Dictionary>>(); + foreach (var staticFile in tgsYml.StaticFiles) + { + if (!staticFile.Populate) + { + Console.WriteLine($"Creating empty directory GameStaticFiles/{staticFile.Name}..."); + await instanceClient.Configuration.CreateDirectory(new ConfigurationFileRequest + { + Path = $"GameStaticFiles/{staticFile.Name}" + }, + default); + } + else + { + // not by ref here as we are relying on master being not broken + Console.WriteLine($"Enumerating repo path {staticFile.Name}..."); + var repositoryFilesToUpload = new Queue(await gitHubClient.Repository.Content.GetAllContents(repoOwner, repoName, staticFile.Name)); + while (repositoryFilesToUpload.Count != 0) + { + var repositoryFileToUpload = repositoryFilesToUpload.Dequeue(); + if (repositoryFileToUpload.Type == ContentType.File) + { + // serial because easier to track errors + Console.WriteLine($"Transferring {repositoryFileToUpload.Path}..."); + var fileContent = await gitHubClient.Repository.Content.GetRawContent(repoOwner, repoName, repositoryFileToUpload.Path); + using var memoryStream = new MemoryStream(fileContent); + await instanceClient.Configuration.Write(new ConfigurationFileRequest + { + Path = $"GameStaticFiles/{repositoryFileToUpload.Path}" + }, + memoryStream, + default); + } + else + { + Console.WriteLine($"Enumerating repo path {repositoryFileToUpload.Path}..."); + var additionalFiles = await gitHubClient.Repository.Content.GetAllContents(repoOwner, repoName, repositoryFileToUpload.Path); + foreach (var additionalFile in additionalFiles) + repositoryFilesToUpload.Enqueue(additionalFile); + } + } + } + } + + async Task WaitForJob(JobResponse originalJob, int timeout) + { + Console.WriteLine($"Waiting for job \"{originalJob.Description}\"..."); + var job = originalJob; + var previousProgress = job.Progress; + do + { + if (job.Progress != previousProgress) + Console.WriteLine($"Progress: {previousProgress = job.Progress}"); + + await Task.Delay(TimeSpan.FromSeconds(1)); + job = await instanceClient!.Jobs.GetId(job, default); + --timeout; + } + while (!job.StoppedAt.HasValue && timeout > 0); + + if (!job.StoppedAt.HasValue) + { + await instanceClient!.Jobs.Cancel(job, default); + Console.WriteLine($"Timed out!"); + return false; + } + else if (job.ExceptionDetails != null) + { + Console.WriteLine($"Error: {job.ExceptionDetails}"); + return false; + } + + return true; + } + + if (!await WaitForJob(byondInstallJob.InstallJob!, 120)) + return 6; + + if (!await WaitForJob(repoCloneJob.ActiveJob!, 600)) + return 7; + + Console.WriteLine("Deploying..."); + var deploymentJob = await instanceClient.DreamMaker.Compile(default); + if (!await WaitForJob(deploymentJob, 1800)) + return 8; + + Console.WriteLine("Launching..."); + var launchJob = await instanceClient.DreamDaemon.Start(default); + if (!await WaitForJob(launchJob, 300)) + return 9; + + return 0; +} +catch (Exception ex) +{ + Console.WriteLine(ex); + return 4; +} diff --git a/tools/tgs_test/README.md b/tools/tgs_test/README.md new file mode 100644 index 000000000000..0f2b54458f5d --- /dev/null +++ b/tools/tgs_test/README.md @@ -0,0 +1,11 @@ +# TGS Test Script + +This is a simple app that does a few things + +- Downloads .tgs.yml information from a specific commit of a given repository. +- Checks that the BYOND version in the .tgs.yml file matches the dependencies.sh version. +- Connects to a TGS instance via command line parameters. +- Uses the .tgs.yml information to automatically set up a TGS instance. +- Runs a TGS deploy/launch and validates that they succeeded. + + Look for its invocation in the GitHub workflows diff --git a/tools/tgs_test/StaticFile.cs b/tools/tgs_test/StaticFile.cs new file mode 100644 index 000000000000..135f159ad6e5 --- /dev/null +++ b/tools/tgs_test/StaticFile.cs @@ -0,0 +1,5 @@ +sealed class StaticFile +{ + public string Name { get; set; } = String.Empty; + public bool Populate { get; set; } +} diff --git a/tools/tgs_test/TgsYml.cs b/tools/tgs_test/TgsYml.cs new file mode 100644 index 000000000000..c738ac4fdefd --- /dev/null +++ b/tools/tgs_test/TgsYml.cs @@ -0,0 +1,15 @@ +using Tgstation.Server.Api.Models; + +sealed class TgsYml +{ + public int Version { get; set; } + + public string Byond { get; set; } = String.Empty; + + public List StaticFiles { get; set; } = new List(); + + public Dictionary WindowsScripts { get; set; } = new Dictionary(); + public Dictionary LinuxScripts { get; set; } = new Dictionary(); + + public DreamDaemonSecurity Security { get; set; } +} diff --git a/tools/tgs_test/Tgstation.TgsTest.csproj b/tools/tgs_test/Tgstation.TgsTest.csproj new file mode 100644 index 000000000000..0a641c269ab2 --- /dev/null +++ b/tools/tgs_test/Tgstation.TgsTest.csproj @@ -0,0 +1,17 @@ + + + + 1.0.0 + Exe + net7.0 + enable + enable + + + + + + + + + diff --git a/tools/tgs_test/Tgstation.TgsTest.sln b/tools/tgs_test/Tgstation.TgsTest.sln new file mode 100644 index 000000000000..37a7a119a88c --- /dev/null +++ b/tools/tgs_test/Tgstation.TgsTest.sln @@ -0,0 +1,25 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio Version 17 +VisualStudioVersion = 17.4.33213.308 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tgstation.TgsTest", "Tgstation.TgsTest.csproj", "{3146D745-AAE5-4205-8FF2-0CE471B47B4E}" +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Any CPU = Debug|Any CPU + Release|Any CPU = Release|Any CPU + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Debug|Any CPU.ActiveCfg = Debug|Any CPU + {3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Debug|Any CPU.Build.0 = Debug|Any CPU + {3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Release|Any CPU.ActiveCfg = Release|Any CPU + {3146D745-AAE5-4205-8FF2-0CE471B47B4E}.Release|Any CPU.Build.0 = Release|Any CPU + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection + GlobalSection(ExtensibilityGlobals) = postSolution + SolutionGuid = {001721B4-7740-419D-837E-26CE9DABCAB8} + EndGlobalSection +EndGlobal From b5267bf40b2b14c463dddae5494fc70b2456d6c5 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Mon, 27 Feb 2023 19:58:19 -0500 Subject: [PATCH 03/13] Fix .tgs.yml BYOND version being parsed as a float in JS (#73694) --- .tgs.yml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/.tgs.yml b/.tgs.yml index aa8d52acedea..ce510b60156e 100644 --- a/.tgs.yml +++ b/.tgs.yml @@ -1,5 +1,5 @@ version: 1 -byond: 514.1588 +byond: "514.1588" static_files: - name: config populate: true From 180106c718bdf2f19abec27ed419e3e447088e8e Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Sat, 4 Mar 2023 13:25:53 -0500 Subject: [PATCH 04/13] Conditionally run TGS tests (#73704) Also add test merge support for pull requests --- .github/workflows/tgs_test.yml | 66 ++++++++++++++++++++++++++++++++++ .tgs.yml | 12 +++++++ tools/tgs_test/Program.cs | 38 +++++++++++++++++--- 3 files changed, 112 insertions(+), 4 deletions(-) create mode 100644 .github/workflows/tgs_test.yml diff --git a/.github/workflows/tgs_test.yml b/.github/workflows/tgs_test.yml new file mode 100644 index 000000000000..f0ec6080d3a3 --- /dev/null +++ b/.github/workflows/tgs_test.yml @@ -0,0 +1,66 @@ +name: TGS Test Suite +on: + push: + branches: + - master + - 'project/**' + - 'gh-readonly-queue/master/**' + - 'gh-readonly-queue/project/**' + paths: + - '.tgs.yml' + - 'dependencies.sh' + - 'code/__DEFINES/tgs.config.dm' + - 'code/__DEFINES/tgs.dm' + - 'code/game/world.dm' + - 'code/modules/tgs/**' + - 'tools/tgs_scripts/**' + - 'tools/tgs_test/**' + pull_request: + branches: + - master + - 'project/**' + paths: + - '.tgs.yml' + - 'dependencies.sh' + - 'code/__DEFINES/tgs.config.dm' + - 'code/__DEFINES/tgs.dm' + - 'code/game/world.dm' + - 'code/modules/tgs/**' + - 'tools/tgs_scripts/**' + - 'tools/tgs_test/**' + merge_group: + branches: + - master +env: + TGS_API_PORT: 5000 + PR_NUMBER: ${{ github.event.number }} +jobs: + test_tgs_docker: + if: "!contains(github.event.head_commit.message, '[ci skip]')" + name: Test TGS Docker + runs-on: ubuntu-22.04 + concurrency: + group: test_tgs_docker-${{ github.head_ref || github.run_id }} + cancel-in-progress: true + services: + tgs: + image: tgstation/server + env: + Database__DatabaseType: Sqlite + Database__ConnectionString: Data Source=TGS_TGTest.sqlite3;Mode=ReadWriteCreate + General__ConfigVersion: 4.1.0 + General__ApiPort: ${{ env.TGS_API_PORT }} + General__SetupWizardMode: Never + ports: + - 5000:5000 #Can't use env here for some reason + steps: + - name: Setup dotnet + uses: actions/setup-dotnet@v2 + with: + dotnet-version: 7.0.x + + - name: Checkout Repository + uses: actions/checkout@v3 + + - name: Test TGS Integration + run: dotnet run -c Release --project tools/tgs_test ${{ github.repository }} /tgs_instances/tgstation ${{ env.TGS_API_PORT }} ${{ github.event.head_commit.sha || github.event.pull_request.head.sha }} ${{ secrets.GITHUB_TOKEN }} ${{ env.PR_NUMBER }} diff --git a/.tgs.yml b/.tgs.yml index ce510b60156e..b012bdffe231 100644 --- a/.tgs.yml +++ b/.tgs.yml @@ -1,13 +1,25 @@ +# This file is used by TGS (https://github.com/tgstation/tgstation-server) clients to quickly initialize a server instance for the codebase +# The format isn't documented anywhere but hopefully we never have to change it. If there are questions, contact the TGS maintainer Cyberboss/@Dominion#0444 version: 1 +# The BYOND version to use (kept in sync with dependencies.sh by the "TGS Test Suite" CI job) +# Must be interpreted as a string, keep quoted byond: "514.1588" +# Folders to create in "/Configuration/GameStaticFiles/" static_files: + # Config directory should be static - name: config + # This implies the folder should be pre-populated with contents from the repo populate: true + # Data directory must be static - name: data +# String dictionary. The value is the location of the file in the repo to upload to TGS. The key is the name of the file to upload to "/Configuration/EventScripts/" +# This one is for Linux hosted servers linux_scripts: PreCompile.sh: tools/tgs_scripts/PreCompile.sh WatchdogLaunch.sh: tools/tgs_scripts/WatchdogLaunch.sh InstallDeps.sh: tools/tgs_scripts/InstallDeps.sh +# Same as above for Windows hosted servers windows_scripts: PreCompile.bat: tools/tgs_scripts/PreCompile.bat +# The security level the game should be run at security: Trusted diff --git a/tools/tgs_test/Program.cs b/tools/tgs_test/Program.cs index e111e19cbfb1..f132e206a791 100644 --- a/tools/tgs_test/Program.cs +++ b/tools/tgs_test/Program.cs @@ -1,6 +1,6 @@ // Simple app meant to test tgstation's TGS integration given a fresh TGS install with the default account // -// Args: Repository Owner/Name, TGS instance path, TGS API port, Pushed commit hash (For .tgs.yml access), GitHub Token +// Args: Repository Owner/Name, TGS instance path, TGS API port, Pushed commit hash (For .tgs.yml access), GitHub Token, (OPTIONAL) PR Number using System.Reflection; using System.Text; @@ -16,10 +16,9 @@ Console.WriteLine("Parsing args..."); -const int ExpectedArgs = 5; -if (args.Length != ExpectedArgs) +if (args.Length < 5 || args.Length > 6) { - Console.WriteLine($"Incorrect number of args: {args.Length}. Expected {ExpectedArgs}"); + Console.WriteLine($"Incorrect number of args: {args.Length}. Expected 5-6"); return 1; } @@ -29,6 +28,18 @@ var pushedCommitHash = args[3]; var gitHubToken = args[4]; +int? pullRequest = default; +if(args.Length == 6) +{ + if (!Int32.TryParse(args[5], out int prNumber)) + { + Console.WriteLine($"Invalid repo slug: {repoSlug}"); + return 10; + } + + pullRequest = prNumber; +} + var repoSlugSplits = repoSlug.Split('/', StringSplitOptions.RemoveEmptyEntries); if(repoSlugSplits.Length != 2) { @@ -315,6 +326,25 @@ async Task WaitForJob(JobResponse originalJob, int timeout) if (!await WaitForJob(repoCloneJob.ActiveJob!, 600)) return 7; + if (pullRequest.HasValue) + { + Console.WriteLine($"Applying test merge #{pullRequest}..."); + var testMergeJob = await instanceClient.Repository.Update(new RepositoryUpdateRequest + { + NewTestMerges = new List + { + new TestMergeParameters + { + Comment = "Active Pull Request", + Number = pullRequest.Value, + TargetCommitSha = pushedCommitHash + } + } + }, default); + if (!await WaitForJob(testMergeJob.ActiveJob!, 60)) + return 11; + } + Console.WriteLine("Deploying..."); var deploymentJob = await instanceClient.DreamMaker.Compile(default); if (!await WaitForJob(deploymentJob, 1800)) From 61fd30923eba232db5968d2d2513bd82853f7b08 Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Thu, 20 Jul 2023 16:39:05 -0500 Subject: [PATCH 05/13] adjustment --- .github/workflows/tgs_test.yml | 3 --- 1 file changed, 3 deletions(-) diff --git a/.github/workflows/tgs_test.yml b/.github/workflows/tgs_test.yml index f0ec6080d3a3..e1eea012e61b 100644 --- a/.github/workflows/tgs_test.yml +++ b/.github/workflows/tgs_test.yml @@ -3,9 +3,7 @@ on: push: branches: - master - - 'project/**' - 'gh-readonly-queue/master/**' - - 'gh-readonly-queue/project/**' paths: - '.tgs.yml' - 'dependencies.sh' @@ -18,7 +16,6 @@ on: pull_request: branches: - master - - 'project/**' paths: - '.tgs.yml' - 'dependencies.sh' From a11e43a5c3656d5393e4b7bc3b9fbc3dde2164a9 Mon Sep 17 00:00:00 2001 From: Jordan Dominion Date: Tue, 18 Jul 2023 14:14:07 -0400 Subject: [PATCH 06/13] Fix raciness in TGS test (#76929) Recent update added a 409 response if two or more configuration accesses were attempted simultaneously. --- tools/tgs_test/Program.cs | 9 +++------ 1 file changed, 3 insertions(+), 6 deletions(-) diff --git a/tools/tgs_test/Program.cs b/tools/tgs_test/Program.cs index f132e206a791..b8967dbc156d 100644 --- a/tools/tgs_test/Program.cs +++ b/tools/tgs_test/Program.cs @@ -227,23 +227,20 @@ await instanceClient.DreamDaemon.Update( default); Console.WriteLine("Uploading EventScripts..."); - var configurationUploadTasks = new List>(); foreach (var scriptDownloadKvp in scriptDownloadTasks) { var scriptContent = await scriptDownloadKvp.Value; var memoryStream = new MemoryStream(scriptContent); - configurationUploadTasks.Add( - instanceClient.Configuration.Write(new ConfigurationFileRequest + await instanceClient.Configuration.Write( + new ConfigurationFileRequest { Path = $"EventScripts/{scriptDownloadKvp.Key}" }, memoryStream, - default)); + default); } - await Task.WhenAll(configurationUploadTasks); - Console.WriteLine("Creating GameStaticFiles structure..."); var staticFileDownloadTasks = new Dictionary>>(); foreach (var staticFile in tgsYml.StaticFiles) From 330fcce06fe056cc579b522e7e3757e12a259e0a Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Thu, 20 Jul 2023 17:06:58 -0500 Subject: [PATCH 07/13] fixes, hopefully --- tools/tgs_scripts/InstallDeps.sh | 7 ++++--- tools/tgs_scripts/PreCompile.sh | 4 ++-- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/tools/tgs_scripts/InstallDeps.sh b/tools/tgs_scripts/InstallDeps.sh index 6069e28ad9c7..0a848728e05d 100755 --- a/tools/tgs_scripts/InstallDeps.sh +++ b/tools/tgs_scripts/InstallDeps.sh @@ -3,22 +3,23 @@ #find out what we have (+e is important for this) set +e has_git="$(command -v git)" -has_cargo="$(command -v ~/.cargo/bin/cargo)" +has_rustup="$(command -v ~/.cargo/bin/rustup)" has_sudo="$(command -v sudo)" +has_grep="$(command -v grep)" has_youtubedl="$(command -v youtube-dl)" has_pip3="$(command -v pip3)" set -e set -x # install cargo if needed -if ! [ -x "$has_cargo" ]; then +if ! [ -x "$has_rustup" ]; then echo "Installing rust..." curl https://sh.rustup.rs -sSf | sh -s -- -y . ~/.profile fi # apt packages, libssl needed by rust-g but not included in TGS barebones install -if ! ( [ -x "$has_git" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then +if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then echo "Installing apt dependencies..." if ! [ -x "$has_sudo" ]; then dpkg --add-architecture i386 diff --git a/tools/tgs_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh index 799e817486b8..3fe1f4bc2ee5 100755 --- a/tools/tgs_scripts/PreCompile.sh +++ b/tools/tgs_scripts/PreCompile.sh @@ -15,7 +15,7 @@ cd "$original_dir" #find out what we have (+e is important for this) set +e has_git="$(command -v git)" -has_cargo="$(command -v ~/.cargo/bin/cargo)" +has_rustup="$(command -v ~/.cargo/bin/rustup)" has_sudo="$(command -v sudo)" has_grep="$(command -v grep)" has_youtubedl="$(command -v youtube-dl)" @@ -23,7 +23,7 @@ has_pip3="$(command -v pip3)" set -e # install cargo if needed -if ! [ -x "$has_cargo" ]; then +if ! [ -x "$has_rustup" ]; then echo "Installing rust..." curl https://sh.rustup.rs -sSf | sh -s -- -y . ~/.profile From 3d39e7c31b24cee2b81851f13048a7bfc5dedca7 Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Thu, 20 Jul 2023 17:33:55 -0500 Subject: [PATCH 08/13] please just work --- tools/tgs_scripts/InstallDeps.sh | 11 +++--- tools/tgs_scripts/PreCompile.sh | 55 ---------------------------- tools/tgs_scripts/PreSynchronize.bat | 3 -- tools/tgs_scripts/PreSynchronize.ps1 | 31 ---------------- 4 files changed, 6 insertions(+), 94 deletions(-) delete mode 100644 tools/tgs_scripts/PreSynchronize.bat delete mode 100755 tools/tgs_scripts/PreSynchronize.ps1 diff --git a/tools/tgs_scripts/InstallDeps.sh b/tools/tgs_scripts/InstallDeps.sh index 0a848728e05d..ba370e9c58cc 100755 --- a/tools/tgs_scripts/InstallDeps.sh +++ b/tools/tgs_scripts/InstallDeps.sh @@ -3,8 +3,9 @@ #find out what we have (+e is important for this) set +e has_git="$(command -v git)" -has_rustup="$(command -v ~/.cargo/bin/rustup)" +has_cargo="$(command -v ~/.cargo/bin/cargo)" has_sudo="$(command -v sudo)" +has_curl="$(command -v curl)" has_grep="$(command -v grep)" has_youtubedl="$(command -v youtube-dl)" has_pip3="$(command -v pip3)" @@ -12,23 +13,23 @@ set -e set -x # install cargo if needed -if ! [ -x "$has_rustup" ]; then +if ! [ -x "$has_cargo" ]; then echo "Installing rust..." curl https://sh.rustup.rs -sSf | sh -s -- -y . ~/.profile fi # apt packages, libssl needed by rust-g but not included in TGS barebones install -if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then +if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -x "$has_curl" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then echo "Installing apt dependencies..." if ! [ -x "$has_sudo" ]; then dpkg --add-architecture i386 apt-get update - apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 + apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep else sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 + sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep fi fi diff --git a/tools/tgs_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh index 3fe1f4bc2ee5..30facc976f86 100755 --- a/tools/tgs_scripts/PreCompile.sh +++ b/tools/tgs_scripts/PreCompile.sh @@ -5,46 +5,6 @@ set -e set -x -#load dep exports -#need to switch to game dir for Dockerfile weirdness -original_dir=$PWD -cd "$1" -. dependencies.sh -cd "$original_dir" - -#find out what we have (+e is important for this) -set +e -has_git="$(command -v git)" -has_rustup="$(command -v ~/.cargo/bin/rustup)" -has_sudo="$(command -v sudo)" -has_grep="$(command -v grep)" -has_youtubedl="$(command -v youtube-dl)" -has_pip3="$(command -v pip3)" -set -e - -# install cargo if needed -if ! [ -x "$has_rustup" ]; then - echo "Installing rust..." - curl https://sh.rustup.rs -sSf | sh -s -- -y - . ~/.profile -fi - -# apt packages, libssl needed by rust-g but not included in TGS barebones install -if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then - echo "Installing apt dependencies..." - if ! [ -x "$has_sudo" ]; then - dpkg --add-architecture i386 - apt-get update - apt-get install -y git lib32z1 pkg-config libssl-dev:i386 libssl-dev libssl1.1:i386 - rm -rf /var/lib/apt/lists/* - else - sudo dpkg --add-architecture i386 - sudo apt-get update - sudo apt-get install -y git lib32z1 pkg-config libssl-dev:i386 libssl-dev libssl1.1:i386 - sudo rm -rf /var/lib/apt/lists/* - fi -fi - # update rust-g if [ ! -d "rust-g" ]; then echo "Cloning rust-g..." @@ -90,21 +50,6 @@ env PKG_CONFIG_ALLOW_CROSS=1 RUSTFLAGS="-C target-cpu=native" ~/.cargo/bin/cargo mv target/i686-unknown-linux-gnu/release/libauxmos.so "$1/libauxmos.so" cd .. -# install or update youtube-dl when not present, or if it is present with pip3, -# which we assume was used to install it -if ! [ -x "$has_youtubedl" ]; then - echo "Installing youtube-dl with pip3..." - if ! [ -x "$has_sudo" ]; then - apt-get install -y python3 python3-pip - else - sudo apt-get install -y python3 python3-pip - fi - pip3 install youtube-dl -elif [ -x "$has_pip3" ]; then - echo "Ensuring youtube-dl is up-to-date with pip3..." - pip3 install youtube-dl -U -fi - # compile tgui echo "Compiling tgui..." cd "$1" diff --git a/tools/tgs_scripts/PreSynchronize.bat b/tools/tgs_scripts/PreSynchronize.bat deleted file mode 100644 index d2016e21ae2d..000000000000 --- a/tools/tgs_scripts/PreSynchronize.bat +++ /dev/null @@ -1,3 +0,0 @@ -@echo off - -powershell -NoProfile -ExecutionPolicy Bypass -File PreSynchronize.ps1 -game_path %1 diff --git a/tools/tgs_scripts/PreSynchronize.ps1 b/tools/tgs_scripts/PreSynchronize.ps1 deleted file mode 100755 index db8f0a304305..000000000000 --- a/tools/tgs_scripts/PreSynchronize.ps1 +++ /dev/null @@ -1,31 +0,0 @@ -param( - $game_path -) - -cd $game_path - -Write-Host "Installing pip dependencies..." -pip3 install PyYaml beautifulsoup4 -if(!$?){ - Write-Host "pip3 returned non-zero!" - exit $LASTEXITCODE -} - -Write-Host "Running changelog script..." -python3 tools/ss13_genchangelog.py html/changelogs -if(!$?){ - Write-Host "python3 returned non-zero!" - exit $LASTEXITCODE -} - -Write-Host "Committing changes..." -git add html - -if(!$?){ - Write-Host "`git add` returned non-zero!" - exit $LASTEXITCODE -} - -#we now don't care about failures -git commit -m "Automatic changelog compile, [ci skip]" -exit 0 From 06c1036c4830bf2bb5da23f896783199a83b0f9c Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Thu, 20 Jul 2023 17:44:54 -0500 Subject: [PATCH 09/13] I'm going to scream --- tools/tgs_scripts/InstallDeps.sh | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/tools/tgs_scripts/InstallDeps.sh b/tools/tgs_scripts/InstallDeps.sh index ba370e9c58cc..c1704df9f4b3 100755 --- a/tools/tgs_scripts/InstallDeps.sh +++ b/tools/tgs_scripts/InstallDeps.sh @@ -12,13 +12,6 @@ has_pip3="$(command -v pip3)" set -e set -x -# install cargo if needed -if ! [ -x "$has_cargo" ]; then - echo "Installing rust..." - curl https://sh.rustup.rs -sSf | sh -s -- -y - . ~/.profile -fi - # apt packages, libssl needed by rust-g but not included in TGS barebones install if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -x "$has_curl" ] && [ -f "/usr/lib/i386-linux-gnu/libssl.so" ] ); then echo "Installing apt dependencies..." @@ -33,6 +26,13 @@ if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -x "$has_curl" ] && [ -f "/ fi fi +# install cargo if needed +if ! [ -x "$has_cargo" ]; then + echo "Installing rust..." + curl https://sh.rustup.rs -sSf | sh -s -- -y + . ~/.profile +fi + # install or update youtube-dl when not present, or if it is present with pip3, # which we assume was used to install it if ! [ -x "$has_youtubedl" ]; then From 786c937f15dde7708b7a65e6a6e4e434be9178f0 Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Thu, 20 Jul 2023 17:52:48 -0500 Subject: [PATCH 10/13] please --- tools/tgs_scripts/PreCompile.sh | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/tools/tgs_scripts/PreCompile.sh b/tools/tgs_scripts/PreCompile.sh index 30facc976f86..2cc52be12741 100755 --- a/tools/tgs_scripts/PreCompile.sh +++ b/tools/tgs_scripts/PreCompile.sh @@ -5,6 +5,13 @@ set -e set -x +#load dep exports +#need to switch to game dir for Dockerfile weirdness +original_dir=$PWD +cd "$1" +. dependencies.sh +cd "$original_dir" + # update rust-g if [ ! -d "rust-g" ]; then echo "Cloning rust-g..." From d72d4ee6ba078270431f7a83882ad2646c82622b Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Mon, 24 Jul 2023 18:56:23 -0500 Subject: [PATCH 11/13] sigh --- tools/tgs_scripts/InstallDeps.sh | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/tools/tgs_scripts/InstallDeps.sh b/tools/tgs_scripts/InstallDeps.sh index c1704df9f4b3..140c1485c7ae 100755 --- a/tools/tgs_scripts/InstallDeps.sh +++ b/tools/tgs_scripts/InstallDeps.sh @@ -18,11 +18,11 @@ if ! ( [ -x "$has_git" ] && [ -x "$has_grep" ] && [ -x "$has_curl" ] && [ -f "/ if ! [ -x "$has_sudo" ]; then dpkg --add-architecture i386 apt-get update - apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep + apt-get install -y build-essential g++-multilib libc6-i386 libstdc++6:i386 lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep else sudo dpkg --add-architecture i386 sudo apt-get update - sudo apt-get install -y lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep + sudo apt-get install -y build-essential g++-multilib libc6-i386 libstdc++6:i386 lib32z1 git pkg-config libssl-dev:i386 libssl-dev zlib1g-dev:i386 curl grep fi fi From 2d6aeac34e829018f7d35ccaeda99a7d68aa66ba Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Fri, 28 Jul 2023 20:20:04 -0500 Subject: [PATCH 12/13] eeee --- code/modules/shuttle/on_move.dm | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 413b59dd1a62..1d6b4b4c1b1c 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -141,7 +141,8 @@ All ShuttleMove procs go here /atom/movable/proc/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) SHOULD_CALL_PARENT(TRUE) var/turf/newT = get_turf(src) - if (newT.z != oldT.z) + //TODO: Find out what causes the items to not have a new turf + if (newT?.z != oldT.z) onTransitZ(oldT.z, newT.z) if(light) From 3fd03a523532b78309fd97cc7a9c664a5888ab83 Mon Sep 17 00:00:00 2001 From: Mark Suckerberg Date: Fri, 28 Jul 2023 20:22:56 -0500 Subject: [PATCH 13/13] Revert "eeee" This reverts commit 2d6aeac34e829018f7d35ccaeda99a7d68aa66ba. --- code/modules/shuttle/on_move.dm | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/code/modules/shuttle/on_move.dm b/code/modules/shuttle/on_move.dm index 1d6b4b4c1b1c..413b59dd1a62 100644 --- a/code/modules/shuttle/on_move.dm +++ b/code/modules/shuttle/on_move.dm @@ -141,8 +141,7 @@ All ShuttleMove procs go here /atom/movable/proc/afterShuttleMove(turf/oldT, list/movement_force, shuttle_dir, shuttle_preferred_direction, move_dir, rotation) SHOULD_CALL_PARENT(TRUE) var/turf/newT = get_turf(src) - //TODO: Find out what causes the items to not have a new turf - if (newT?.z != oldT.z) + if (newT.z != oldT.z) onTransitZ(oldT.z, newT.z) if(light)