############################################################################## ### PRESENCODE SOURCE FILE ### ### Copyright (c) 2024 JeremyStarTM & Contributors ### ### Licensed under the GNU General Public License v3 ### ### ### ### This program is free software: you can redistribute it and/or modify ### ### it under the terms of the GNU General Public License as published by ### ### the Free Software Foundation, either version 3 of the License, or ### ### (at your option) any later version. ### ### ### ### This program is distributed in the hope that it will be useful, ### ### but WITHOUT ANY WARRANTY; without even the implied warranty of ### ### MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ### ### GNU General Public License for more details. ### ### ### ### You should have received a copy of the GNU General Public License ### ### along with this program. If not, see . ### ############################################################################## ### src/misc.gd (Miscellaneous) ### ### ### ### This source file contains various small functions that do not fit into ### ### other source files. Shutting Presencode down, getting the center of an ### ### object or checking the manifest consistency are examples of this. ### ############################################################################## extends Node # Enums enum Error { OK, PREADER_NO_PRESENTATION_OPEN, PREADER_NO_MANIFEST, PREADER_MANIFEST_PARSING_FAILED, MANIFEST_INCONSISTENT, MANIFEST_INVALID_VERSION, MANIFEST_INVALID_PROGRAM, MANIFEST_INVALID_RATIO } # Manifest specification const manifest_version: int = 1 const manifest_program: String = "Presencode" # Configuration ## Make window invisible on shutdown ### Hides the main window on shutdown if true ### Displays RenderingServer.get_white_texture() if false instead var config_shutdown_invisible: bool = true # Get call origin from stacktrace func get_origin(n: int = 0) -> Dictionary: var stack: Dictionary = get_stack()[2+n] return {"file": stack["source"].replace("user://", "").replace("res://", ""), "line": stack["line"], "function": stack["function"]} # Shutdown Presencode safely func shutdown(exitcode: int = 0) -> void: logger.info("Shutting down") get_tree().paused = true # Display white texture var npr: NinePatchRect = NinePatchRect.new() npr.name = "OverlayTexture" npr.texture = ImageTexture.create_from_image(RenderingServer.texture_2d_get(RenderingServer.get_white_texture())) npr.size = Vector2(100000, 100000) npr.position = Vector2(-50000, -50000) get_tree().root.add_child(npr) get_tree().root.move_child(npr, get_tree().root.get_child_count(true)) # Window stuff if config_shutdown_invisible: # Make window invisible DisplayServer.window_set_mode(DisplayServer.WINDOW_MODE_WINDOWED) DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_BORDERLESS, true) DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_RESIZE_DISABLED, true) DisplayServer.window_set_flag(DisplayServer.WINDOW_FLAG_NO_FOCUS, true) DisplayServer.window_set_min_size(Vector2i(1, 1)) DisplayServer.window_set_size(Vector2i(1, 1)) DisplayServer.window_set_position(Vector2i(0, 0)) logger.diag("Removing temporary directory") # Remove tempdir DirAccess.remove_absolute(get_temporary_dir()) # Wait for all log messages to be printed to console/log logger.diag("Waiting for log messages") await get_tree().create_timer(0.25, true).timeout print("Exiting!") get_tree().quit(exitcode) # Insanely long timer as Godot executes code further even while it's exiting await get_tree().create_timer(999, true).timeout # Calculate the center of a child inside its parent (Vector2i) func get_center(parent_size: Vector2i, child_size: Vector2i) -> Vector2i: @warning_ignore("integer_division") return Vector2i(parent_size.x/2-child_size.x/2, parent_size.y/2-child_size.y/2) # Calculate the center of a child inside its parent (Vector2) func get_center_float(parent_size: Vector2, child_size: Vector2) -> Vector2: return Vector2(parent_size.x/2-child_size.x/2, parent_size.y/2-child_size.y/2) # Return path to temporary directory ## This function tries to utilize the operating system's temporary directory. ## If all of them can't be used, it falls back to "user://temp" instead. func get_temporary_dir() -> String: match(OS.get_name()): "Linux": # Use "/tmp" or fallback if DirAccess.dir_exists_absolute("/tmp"): return "/tmp/presencode" else: return "user://temp" "Windows": # Use "%USERPROFILE%/AppData/Local/Temp/Presencode" or "C:/Users/%USERNAME%/AppData/Local/Temp/Presencode" or fallback if OS.get_environment("USERPROFILE") != "" and DirAccess.dir_exists_absolute(OS.get_environment("USERPROFILE").replace("\\", "/")): return OS.get_environment("USERPROFILE").replace("\\", "/") + "/AppData/Local/Temp/Presencode" elif OS.get_environment("USERNAME") != "" and DirAccess.dir_exists_absolute("C:/Users/" + OS.get_environment("USERNAME")): return "C:/Users/" + OS.get_environment("USERNAME") + "/AppData/Local/Temp/Presencode" else: return "user://temp" _: # Platform not supported logger.warn("The " + OS.get_name() + " platform is not supported by Presencode. You can add support for that platform to Presencode yourself, if you want.") return "" # Check platform support func check_platform() -> void: match(OS.get_name()): "Linux": pass "Windows": pass _: # Platform not supported logger.error("The \"" + OS.get_name() + "\" operating system is not supported by Presencode. You can add support for that platform to Presencode yourself, if you want.") # Check for manifest consistency func check_manifest_consistency(manifest: Dictionary) -> misc.Error: logger.diag("Checking manifest for consistency") # version match(manifest.get("version")): null: return misc.Error.MANIFEST_INCONSISTENT float(1): pass _: return misc.Error.MANIFEST_INVALID_VERSION logger.diag("Manifest passed \"version\" consistency check") # program match(manifest.get("program")): null: return misc.Error.MANIFEST_INCONSISTENT manifest_program: pass _: return misc.Error.MANIFEST_INVALID_PROGRAM logger.diag("Manifest passed \"program\" consistency check") # topic if manifest.get("topic") == null: return misc.Error.MANIFEST_INCONSISTENT elif typeof(manifest.get("topic")) != TYPE_STRING: return misc.Error.MANIFEST_INCONSISTENT logger.diag("Manifest passed \"topic\" consistency check") # authors if manifest.get("authors") == null: return misc.Error.MANIFEST_INCONSISTENT elif typeof(manifest.get("authors")) != TYPE_ARRAY: return misc.Error.MANIFEST_INCONSISTENT for author in manifest.get("authors"): if typeof(author) != TYPE_STRING: return misc.Error.MANIFEST_INCONSISTENT logger.diag("Manifest passed \"authors\" consistency check") # ratio match(manifest.get("ratio")): null: return misc.Error.MANIFEST_INCONSISTENT "16:9": pass "4:3": pass _: return misc.Error.MANIFEST_INVALID_RATIO logger.diag("Manifest passed \"ratio\" consistency check") # entrypoint if manifest.get("entrypoint") == null: return misc.Error.MANIFEST_INCONSISTENT elif typeof(manifest.get("entrypoint")) != TYPE_STRING: return misc.Error.MANIFEST_INCONSISTENT elif !manifest.get("entrypoint").ends_with(".gd"): return misc.Error.MANIFEST_INCONSISTENT logger.diag("Manifest passed \"entrypoint\" consistency check") logger.diag("Manifest follows the Presencode Manifest Specification") return misc.Error.OK