Presencode/src/misc.gd

174 lines
7.9 KiB
GDScript3
Raw Normal View History

2024-01-14 05:58:43 +01:00
##############################################################################
### 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 <https://www.gnu.org/licenses/>. ###
##############################################################################
### 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 (code " + str(exitcode) + ")")
2024-01-14 05:58:43 +01:00
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