diff --git a/game.gd b/game.gd index bce77d2..b407a9d 100644 --- a/game.gd +++ b/game.gd @@ -2,7 +2,6 @@ extends Node var tmp_prefix = _tmp_prefix() var global_shell -var debug_file_io = false var fake_editor var _file = "user://savegame.json" @@ -38,41 +37,16 @@ func load_state() -> bool: state[key] = new_state[key] savegame.close() return true - func copy_file_to_game_env(filename): - # Copy fake-editor to tmp directory (because the original might be in a .pck file). var file_outside = tmp_prefix + filename var file_inside = "/tmp/"+filename - var content = game.read_file("res://scripts/"+filename, "") - if content.empty(): - push_error(filename + " could not be read.") - write_file(file_outside, content) + var content = helpers.read_file("res://scripts/"+filename) + helpers.write_file(file_outside, content) global_shell.run("chmod u+x " + file_inside) return file_inside -func read_file(path, fallback_string): - if debug_file_io: - print("reading " + path) - var file = File.new() - var open_status = file.open(path, File.READ) - if open_status == OK: - var content = file.get_as_text() - file.close() - return content - else: - return fallback_string - -func write_file(path, content): - if debug_file_io: - print("writing " + path) - var file = File.new() - file.open(path, File.WRITE) - file.store_string(content) - file.close() - return true - func _tmp_prefix(): var os = OS.get_name() if os == "X11": @@ -80,26 +54,6 @@ func _tmp_prefix(): elif os == "Windows": # For some reason, this command outputs a space in the end? We remove it. # Also, Godot's default is to use forward slashes for everything. - return exec("echo", ["%TEMP%"]).replacen("\\", "/").replace(" \n", "/") + return helpers.exec("echo", ["%TEMP%"]).replacen("\\", "/").replace(" \n", "/") else: - push_error("Unsupported OS") - get_tree().quit() - -# Run a simple command with arguments, blocking, using OS.execute. -func exec(command, args=[]): - var debug = false - - if debug: - print("exec: %s [%s]" % [command, PoolStringArray(args).join(", ")]) - - var output = [] - var exit_code = OS.execute(command, args, true, output, true) - output = output[0] - - if exit_code != 0: - push_error("OS.execute failed: %s [%s] Output: %s" % [command, PoolStringArray(args).join(", "), output]) - - if debug: - print(output) - - return output + helpers.crash("Unsupported OS: %s" % os) diff --git a/helpers.gd b/helpers.gd new file mode 100644 index 0000000..9f54496 --- /dev/null +++ b/helpers.gd @@ -0,0 +1,54 @@ +extends Node + +var debug_file_io = false + +# Crash the game and display the error message. +func crash(message): + push_error(message) + print("Fatal error: " + message) + get_tree().quit() + +# Run a simple command with arguments, blocking, using OS.execute. +func exec(command, args=[], crash_on_fail=true): + var debug = false + + if debug: + print("exec: %s [%s]" % [command, PoolStringArray(args).join(", ")]) + + var output = [] + var exit_code = OS.execute(command, args, true, output, true) + output = output[0] + + if exit_code != 0 and crash_on_fail: + helpers.crash("OS.execute failed: %s [%s] Output: %s" % [command, PoolStringArray(args).join(", "), output]) + + if debug: + print(output) + + return output + +# Return the contents of a file. If no fallback_string is provided, crash when +# the file doesn't exist. +func read_file(path, fallback_string=null): + if debug_file_io: + print("reading " + path) + var file = File.new() + var open_status = file.open(path, File.READ) + if open_status == OK: + var content = file.get_as_text() + file.close() + return content + else: + if fallback_string != null: + return fallback_string + else: + helpers.crash("File %s could not be read, and has no fallback" % path) + +func write_file(path, content): + if debug_file_io: + print("writing " + path) + var file = File.new() + file.open(path, File.WRITE) + file.store_string(content) + file.close() + return true diff --git a/main.gd b/main.gd index 7cb5805..7f2ba2e 100644 --- a/main.gd +++ b/main.gd @@ -67,13 +67,13 @@ func list_levels(): var final_level_sequence = [] - var level_sequence = Array(game.read_file("res://levels/%s/sequence" % chapter, "").split("\n")) + var level_sequence = Array(helpers.read_file("res://levels/%s/sequence" % chapter, "").split("\n")) for level in level_sequence: if level == "": continue if not levels.has(level): - push_error("Level '%s' is specified in the sequence, but could not be found" % level) + helpers.crash("Level '%s' is specified in the sequence, but could not be found" % level) levels.erase(level) final_level_sequence.push_back(level) @@ -105,7 +105,7 @@ func load_level(id): var active_script = level_prefix+level+"/start" var description_file = level_prefix+level+"/description" - var description = game.read_file(description_file, "no description") + var description = helpers.read_file(description_file, "(no description)") # Surround all lines indented with four spaces with [code] tags. var monospace_regex = RegEx.new() @@ -114,7 +114,7 @@ func load_level(id): level_description.bbcode_text = description var congrats_file = level_prefix+level+"/congrats" - var congrats = game.read_file(congrats_file, "Good job, you solved the level!\n\nFeel free to try a few more things or click 'Next Level'.") + var congrats = helpers.read_file(congrats_file, "Good job, you solved the level!\n\nFeel free to try a few more things or click 'Next Level'.") level_congrats.bbcode_text = congrats level_name.text = level @@ -123,18 +123,16 @@ func load_level(id): # Make sure that active_repository is in a temporary directory. var expected_prefix = "/tmp" if active_repository_path.substr(0,4) != expected_prefix: - push_error("Refusing to delete a directory that does not start with %s" % expected_prefix) - get_tree().quit() + helpers.crash("Refusing to delete directory %s that does not start with %s" % [active_repository_path, expected_prefix]) if goal_repository_path.substr(0,4) != expected_prefix: - push_error("Refusing to delete a directory that does not start with %s" % expected_prefix) - get_tree().quit() + helpers.crash("Refusing to delete directory %s that does not start with %s" % [goal_repository_path, expected_prefix]) # Danger zone! game.global_shell.run("rm -rf '%s'" % active_repository_path) game.global_shell.run("rm -rf '%s'" % goal_repository_path) - var goal_script_content = game.read_file(goal_script, "") - var active_script_content = game.read_file(active_script, "") + var goal_script_content = helpers.read_file(goal_script, "") + var active_script_content = helpers.read_file(active_script, "") construct_repo(active_script_content +"\n"+ goal_script_content, goal_repository_path) construct_repo(active_script_content, active_repository_path) @@ -143,8 +141,8 @@ func load_level(id): var win_script = level_prefix+level+"/win" var win_script_target = game.tmp_prefix+"/win" - var win_script_content = game.read_file(win_script, "exit 1\n") - game.write_file(win_script_target, win_script_content) + var win_script_content = helpers.read_file(win_script, "exit 1\n") + helpers.write_file(win_script_target, win_script_content) terminal.clear() @@ -171,7 +169,7 @@ func construct_repo(script_content, path): var script_path_outside = game.tmp_prefix+"/git-hydra-script" var script_path = "/tmp/git-hydra-script" - game.write_file(script_path_outside, script_content) + helpers.write_file(script_path_outside, script_content) game.global_shell.run("mkdir " + path) game.global_shell.cd(path) diff --git a/project.godot b/project.godot index c99c19a..82bc674 100644 --- a/project.godot +++ b/project.godot @@ -26,6 +26,7 @@ run/main_scene="res://main.tscn" [autoload] game="*res://game.gd" +helpers="*res://helpers.gd" [display] diff --git a/shell.gd b/shell.gd index 578df9b..c354521 100644 --- a/shell.gd +++ b/shell.gd @@ -49,7 +49,7 @@ func run(command): # hacky_command = '"\''+hacky_command.replace("'", "'\"'\"'")+'\'"' - var output = game.exec(_shell_binary(), ["-c", hacky_command]) + var output = helpers.exec(_shell_binary(), ["-c", hacky_command], false) if debug: print(output) @@ -64,8 +64,7 @@ func _shell_binary(): elif os == "Windows": return "dependencies\\windows\\git\\bin\\bash.exe" else: - push_error("Unsupported OS") - get_tree().quit() + helpers.crash("Unsupported OS: %s" % os) var _t func run_async(command): diff --git a/tcp_server.gd b/tcp_server.gd index f59d4f9..896754a 100644 --- a/tcp_server.gd +++ b/tcp_server.gd @@ -18,7 +18,7 @@ func _process(_delta): if _s.is_connection_available(): if _connected: _c.disconnect_from_host() - push_error("Dropping active connection") + helpers.crash("Dropping active connection") _c = _s.take_connection() _connected = true print("connected!") @@ -38,4 +38,4 @@ func send(text): text += "\n" _c.put_data(text.to_utf8()) else: - push_error("Trying to send data on closed connection") + helpers.crash("Trying to send data on closed connection") diff --git a/terminal.gd b/terminal.gd index 3961e31..dd8e1bb 100644 --- a/terminal.gd +++ b/terminal.gd @@ -29,7 +29,7 @@ func _ready(): var error = $TextEditor.connect("hide", self, "editor_closed") if error != OK: - push_error("Could not connect TextEditor's hide signal") + helpers.crash("Could not connect TextEditor's hide signal") input.grab_focus() var all_git_commands = repository.shell.run("git help -a | grep \"^ \\+[a-z-]\\+ \" -o") diff --git a/text_editor.gd b/text_editor.gd index b087bdc..e179ba7 100644 --- a/text_editor.gd +++ b/text_editor.gd @@ -22,10 +22,7 @@ func open(filename): path = filename var fixme_path = game.tmp_prefix+"/active/" - var content = game.read_file(fixme_path+filename, "[ERROR_FAKE_EDITOR]") - if content == "[ERROR_FAKE_EDITOR]": - push_error("Specified file could not be read.") - get_tree().quit() + var content = helpers.read_file(fixme_path+filename) text = content show() @@ -33,7 +30,7 @@ func open(filename): func save(): var fixme_path = game.tmp_prefix+"/active/" - game.write_file(fixme_path+path, text) + helpers.write_file(fixme_path+path, text) close() func close():