JeremyStarTM
e158173104
- [Console.tscn, src/console.gd, src/console_info.gd, src/console_expressionscript.gd] Add (mostly uncommented) debugging console - [example/test.gd] Optimize example presentation controller - [src/loader.gd, src/pmana.gd] Move click overlay into Loader - [src/pmana.gd] Add check against invalid controller scripts - [src/pmana.gd] Create seperate pmana.shutdown() function to handle shutdowns during presentations - [src/preader.gd] Add checks against empty manifest variable - [src/preader.gd] Fix bug in get_authors() - Change/optimize various other smaller things
173 lines
7.9 KiB
GDScript
173 lines
7.9 KiB
GDScript
##############################################################################
|
|
### 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) + ")")
|
|
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
|