diff --git a/src/classes/communication.gd b/src/classes/communication.gd index 0da19ac..9283e97 100644 --- a/src/classes/communication.gd +++ b/src/classes/communication.gd @@ -23,31 +23,30 @@ var logger: CoreLoggerInstance var sms: CoreBaseModule # Presencode infrastructure -var presenloader: Node +var shared: PresencodeSharedCode var clickoverlay: Button = Button.new() # Presentation data -var entrypoint: PresencodeEntrypoint -var manifest: Dictionary var current_slide: int = 0 var slide_switch_in_progress: bool = false # +++ initialization and processing +++ -func _init(core_new: Core, presenloader_new: Node) -> void: +func _init(core_new: Core, shared_new: PresencodeSharedCode) -> void: name = "Communication" core = core_new logger = core.logger.get_instance("src/classes/communication.gd", self) sms = core.sms - presenloader = presenloader_new + shared = shared_new + clickoverlay.name = "Click Overlay" clickoverlay.size = Vector2(100000.0, 100000.0) clickoverlay.position = -Vector2(50000.5, 50000.5) clickoverlay.modulate = Color(1, 1, 1, 0) clickoverlay.connect("pressed", func() -> void: logger.diag("Navigating to next slide") - switch_slide(current_slide + 1) + await switch_slide(current_slide + 1) ) func _ready() -> void: @@ -64,15 +63,10 @@ func _process(_delta: float) -> void: _: DisplayServer.window_set_mode(DisplayServer.WindowMode.WINDOW_MODE_WINDOWED) if Input.is_action_just_pressed("navigate_forwards"): logger.diag("Navigating to next slide") - switch_slide(current_slide + 1) + await switch_slide(current_slide + 1) if Input.is_action_just_pressed("navigate_backwards"): logger.diag("Navigating to previous slide") - switch_slide(current_slide - 1) - -func _update_variables() -> void: - logger.diag("Updating variables") - entrypoint = presenloader.entrypoint_node - manifest = presenloader.manifest + await switch_slide(current_slide - 1) # +++ slide management +++ func switch_slide(new_slide: int) -> PresencodeTypes.PresencodeError: @@ -84,26 +78,27 @@ func switch_slide(new_slide: int) -> PresencodeTypes.PresencodeError: logger.error(core.misc.stringify_variables("Invalid slide %slide%", { "slide": new_slide })) slide_switch_in_progress = false return PresencodeTypes.PresencodeError.INVALID_SLIDE - if new_slide > manifest["slides"]: + if new_slide > shared.manifest["slides"]: logger.error(core.misc.stringify_variables("Invalid slide %slide%", { "slide": new_slide })) slide_switch_in_progress = false return PresencodeTypes.PresencodeError.INVALID_SLIDE logger.info(core.misc.stringify_variables("Switching from slide %old% to %new%", { "old": old_slide, "new": new_slide })) + await get_tree().process_frame # Prevents graphical glitches # Play BEFORE animation - if manifest["animations"]: + if shared.manifest["animations"]: logger.verb("Starting BEFORE animation") - await entrypoint.play_animation(PresencodeTypes.AnimationStage.BEFORE, old_slide, new_slide) + await shared.entrypoint.play_animation(PresencodeTypes.AnimationStage.BEFORE, old_slide, new_slide) - # Call switch_slide() + # Call switch_to_slide() logger.verb("Switching slide") - await entrypoint.switch_to_slide(new_slide) + await shared.entrypoint.switch_to_slide(new_slide) # Play AFTER animation - if manifest["animations"]: + if shared.manifest["animations"]: logger.verb("Starting AFTER animation") - await entrypoint.play_animation(PresencodeTypes.AnimationStage.AFTER, old_slide, new_slide) + await shared.entrypoint.play_animation(PresencodeTypes.AnimationStage.AFTER, old_slide, new_slide) current_slide = new_slide slide_switch_in_progress = false @@ -132,23 +127,23 @@ func load_resource(path: String): var load_path: String - if presenloader.is_file: + if shared.is_file: # Check if file exists - if !presenloader.reader.file_exists(path): + if !shared.reader.file_exists(path): await logger.crash(core.misc.stringify_variables("File path %path% could not be located inside presentation archive", { "path": path })) # Write into temporary file - presenloader.write_temporary_file(presenloader.reader.read_file(path)) + shared.write_temporary_file(shared.reader.read_file(path)) # Update 'load_path' - load_path = presenloader.temporary_file + load_path = shared.temporary_file else: # Check if file exists - if !FileAccess.file_exists(presenloader.path + "/" + path): - await logger.crash(core.misc.stringify_variables("File path %path% could not be located inside presentation directory (full path is %path_full%)", { "path": path, "path_full": presenloader.path + "/" + path })) + if !FileAccess.file_exists(shared.path + "/" + path): + await logger.crash(core.misc.stringify_variables("File path %path% could not be located inside presentation directory (full path is %path_full%)", { "path": path, "path_full": shared.path + "/" + path })) # Update 'load_path' - load_path = presenloader.path + "/" + path + load_path = shared.path + "/" + path # Load resource from temporary file var resource = _load_resource_format_loader(load_path, path) diff --git a/src/classes/shared.gd b/src/classes/shared.gd new file mode 100644 index 0000000..adb10dc --- /dev/null +++ b/src/classes/shared.gd @@ -0,0 +1,63 @@ +# PRESENCODE SOURCE FILE +# Copyright (c) 2024 JeremyStarTM & Contributors +# Licensed under the GNU Affero General Public License v3 +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU Affero 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 Affero General Public License for more details. +# +# You should have received a copy of the GNU Affero General Public License +# along with this program. If not, see . +extends Node +class_name PresencodeSharedCode + +var core: Core +var logger: CoreLoggerInstance + +const temporary_file: String = "user://temporary_file" +var reader: ZIPReader +var diraccess: DirAccess + +var is_file: bool +var path: String + +var entrypoint: Node +var manifest: Dictionary + +# +++ initialization +++ +func _init(core_new: Core, is_file_new: bool, path_new: String, diraccess_new: DirAccess) -> void: + core = core_new + logger = core.logger.get_instance("src/classes/shared.gd", self) + + reader = ZIPReader.new() + diraccess = diraccess_new + + is_file = is_file_new + path = path_new + +func add_presentation_data(entrypoint_new: Node, manifest_new: Dictionary) -> void: + entrypoint = entrypoint_new + manifest = manifest_new + +# +++ etc +++ +func write_temporary_file(bytes: PackedByteArray) -> void: + # Check if exists, if so delete the file + if FileAccess.file_exists(temporary_file): + logger.diag("Removing temporary file") + + # Open + var file: FileAccess = FileAccess.open(temporary_file, FileAccess.WRITE) + if file == null: + await logger.crash(core.misc.stringify_variables("Can't write temporary file: %error_string% (%error%)", { "error": FileAccess.get_open_error(), "error_string": error_string(FileAccess.get_open_error()) })) + + # Write + file.store_buffer(bytes) + + # Close + file.close() diff --git a/src/presenloader.gd b/src/presenloader.gd index 9bdaee7..f552373 100644 --- a/src/presenloader.gd +++ b/src/presenloader.gd @@ -18,33 +18,24 @@ extends Node const version: int = 1 const version_float: float = float(version) -const temporary_file: String = "user://temporary_file" @onready var core: Core = get_node("/root/CORE") @onready var logger: CoreLoggerInstance = core.logger.get_instance("src/presenloader.gd", self) -var path: String = "" -var is_file: bool = true -var manifest: Dictionary = {} +var shared: PresencodeSharedCode +var communication: PresencodeCommunication var entrypoint: Script = null -var entrypoint_node: PresencodeEntrypoint = null -@onready var communication: PresencodeCommunication = PresencodeCommunication.new(core, self) - -var reader: ZIPReader = ZIPReader.new() -var diraccess: DirAccess = null func _ready() -> void: # Register cleanup hook core.register_cleanup_hook(func() -> void: queue_free()) - - # Add 'communication' as a child - add_child(communication) func load_presentation(load_path: String) -> String: logger.info(core.misc.stringify_variables("Loading presentation located at %path%", { "path": load_path })) - path = load_path - is_file = FileAccess.file_exists(path) + var path = load_path + var is_file = FileAccess.file_exists(path) + var diraccess: DirAccess = null # Check if exists logger.verb("Checking if presentation exists") @@ -60,7 +51,7 @@ func load_presentation(load_path: String) -> String: # Open archive logger.verb("Opening archive") - var error: Error = reader.open(path) + var error: Error = shared.reader.open(path) if error != Error.OK: return core.misc.stringify_variables("Can't open ZIP archive: %error_string% (%error%)", { "error": error, "error_string": error_string(error) }, true) else: @@ -70,6 +61,9 @@ func load_presentation(load_path: String) -> String: if diraccess == null: return core.misc.stringify_variables("Can't open directory: %error_string% (%error%)", { "error": DirAccess.get_open_error(), "error_string": error_string(DirAccess.get_open_error()) }, true) + # Update 'shared' + shared = PresencodeSharedCode.new(core, is_file, path, diraccess) + # Check if required files are present var output: String = check_required_files() if output != "": return output @@ -90,12 +84,13 @@ func load_presentation(load_path: String) -> String: output = load_entrypoint() if output != "": return output + # Create 'communication' + communication = PresencodeCommunication.new(core, shared) + add_child(communication) + # Inject entrypoint inject_entrypoint() - # Update 'communication''s variables - communication._update_variables() - return "" func check_required_files() -> String: @@ -105,11 +100,11 @@ func check_required_files() -> String: var files: PackedStringArray = PackedStringArray([]) # Update 'files' appropriately - if is_file: - files = reader.get_files() + if shared.is_file: + files = shared.reader.get_files() else: - files = diraccess.get_files() - for directory in diraccess.get_directories(): + files = shared.diraccess.get_files() + for directory in shared.diraccess.get_directories(): files.append(directory + "/") # Iterate through files and directories @@ -132,9 +127,9 @@ func parse_manifest() -> String: logger.verb("Parsing manifest") var manifest_raw: String = "" - if is_file: manifest_raw = reader.read_file("manifest.json").get_string_from_utf8() + if shared.is_file: manifest_raw = shared.reader.read_file("manifest.json").get_string_from_utf8() else: - var file: FileAccess = FileAccess.open(path + "/manifest.json", FileAccess.READ) + var file: FileAccess = FileAccess.open(shared.path + "/manifest.json", FileAccess.READ) if file == null: return core.misc.stringify_variables("Can't read manifest: %error_string% (%error%)", { "error": FileAccess.get_open_error(), "error_string": error_string(FileAccess.get_open_error()) }) manifest_raw = file.get_as_text() @@ -147,7 +142,7 @@ func parse_manifest() -> String: if typeof(json.data) != Variant.Type.TYPE_DICTIONARY: return core.misc.stringify_variables("Can't parse manifest: Parsed manifest is not of type Dictionary but instead %type%", { "type": type_string(typeof(json.data)) }) - manifest = json.data + shared.manifest = json.data return "" @@ -179,7 +174,7 @@ func check_manifest() -> Array[String]: "slides": core.validation.get_single_schema(self).matches_type([ Variant.Type.TYPE_FLOAT ]).has_minimum_float(1.0), "animations": core.validation.get_single_schema(self).matches_type([ Variant.Type.TYPE_BOOL ]), "display_end_text_after_last_slide": core.validation.get_single_schema(self).matches_type([ Variant.Type.TYPE_BOOL ]) - }, manifest, self) + }, shared.manifest, self) return schema.evaluate() @@ -189,16 +184,16 @@ func validate_entrypoint() -> String: var content: String = "" # Get entrypoint content - if is_file: - if !reader.file_exists("src/" + manifest["entrypoint"]): - return "Specified entrypoint file could not be located at src/" + manifest["entrypoint"] + if shared.is_file: + if !shared.reader.file_exists("src/" + shared.manifest["entrypoint"]): + return "Specified entrypoint file could not be located at src/" + shared.manifest["entrypoint"] - content = reader.read_file("src/" + manifest["entrypoint"]).get_string_from_utf8() + content = shared.reader.read_file("src/" + shared.manifest["entrypoint"]).get_string_from_utf8() else: - if !FileAccess.file_exists(path + "/src/" + manifest["entrypoint"]): - return "Specified entrypoint file could not be located at src/" + manifest["entrypoint"] + if !FileAccess.file_exists(shared.path + "/src/" + shared.manifest["entrypoint"]): + return "Specified entrypoint file could not be located at src/" + shared.manifest["entrypoint"] - var file: FileAccess = FileAccess.open(path + "/src/" + manifest["entrypoint"], FileAccess.READ) + var file: FileAccess = FileAccess.open(shared.path + "/src/" + shared.manifest["entrypoint"], FileAccess.READ) if file == null: return core.misc.stringify_variables("Can't read entrypoint: %error_string% (%error%)", { "error": FileAccess.get_open_error(), "error_string": error_string(FileAccess.get_open_error()) }) content = file.get_as_text() @@ -213,15 +208,15 @@ func validate_entrypoint() -> String: func load_entrypoint() -> String: logger.verb("Loading entrypoint") - if is_file: + if shared.is_file: # Workaround (we can't load resources from buffer. why? idk) # -> Remove temporary file (if exists) - write_temporary_file(reader.read_file("src/" + manifest["entrypoint"])) + shared.write_temporary_file(shared.reader.read_file("src/" + shared.manifest["entrypoint"])) # -> Load temporary file - entrypoint = ResourceLoader.load(temporary_file) + entrypoint = ResourceLoader.load(shared.temporary_file) else: # Load entrypoint - entrypoint = ResourceLoader.load(path + "/src/" + manifest["entrypoint"]) + entrypoint = ResourceLoader.load(shared.path + "/src/" + shared.manifest["entrypoint"]) return "" @@ -229,34 +224,17 @@ func inject_entrypoint() -> void: logger.verb("Injecting entrypoint") # Instantiate new PresencodeEntrypoint - entrypoint_node = PresencodeEntrypoint.new() - entrypoint_node.name = "Entrypoint" - entrypoint_node.set_script(entrypoint) + shared.entrypoint = PresencodeEntrypoint.new() + shared.entrypoint.name = "Entrypoint" + shared.entrypoint.set_script(entrypoint) # Update variables - entrypoint_node.core = core - entrypoint_node.logger = core.logger.get_instance(communication.get_source_path("src/" + manifest["entrypoint"]), entrypoint_node) - entrypoint_node.api = communication + shared.entrypoint.core = core + shared.entrypoint.logger = core.logger.get_instance(communication.get_source_path("src/" + shared.manifest["entrypoint"]), shared.entrypoint) + shared.entrypoint.api = communication # Add to SceneTree - get_tree().root.add_child.call_deferred(entrypoint_node) + get_tree().root.add_child.call_deferred(shared.entrypoint) # Execute initialize() - entrypoint_node.initialize.call_deferred() - -# +++ etc +++ -func write_temporary_file(bytes: PackedByteArray) -> void: - # Check if exists, if so delete the file - if FileAccess.file_exists(temporary_file): - logger.diag("Removing temporary file") - - # Open - var file: FileAccess = FileAccess.open(temporary_file, FileAccess.WRITE) - if file == null: - await logger.crash(core.misc.stringify_variables("Can't write temporary file: %error_string% (%error%)", { "error": FileAccess.get_open_error(), "error_string": error_string(FileAccess.get_open_error()) })) - - # Write - file.store_buffer(bytes) - - # Close - file.close() + shared.entrypoint.initialize.call_deferred()