From 88757cf007bcfbf8ffd422ae8fc983df85c1b51f Mon Sep 17 00:00:00 2001 From: Pyral Date: Tue, 3 Dec 2024 13:43:48 -0500 Subject: [PATCH] Fixed stuff --- LICENSE | 21 +++++++++++++++++++++ create_vfs.gd | 25 ++++++++++++++++++------- vfs.gd | 37 +++++++++++++++++++++++++++++++------ vfs_loaders.gd | 29 +++++++++++++++++++++++++++-- 4 files changed, 97 insertions(+), 15 deletions(-) create mode 100644 LICENSE diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..40af2e0 --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2024 Dinoleaf LLC + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. diff --git a/create_vfs.gd b/create_vfs.gd index 5dd8b91..d27cdc2 100644 --- a/create_vfs.gd +++ b/create_vfs.gd @@ -1,5 +1,8 @@ # Not unlike factory pattern. +# This code's been directly written in due to time and lazy, but +# will be thrown into submodules eventually to clean readability up. + ## Recursively creates virtual file systems. static func create_meta_accessor(file_accessors:Array[VFileAccess])->VFileAccess: var vfiler := VFileAccess.new() @@ -39,8 +42,11 @@ static func create_meta_accessor(file_accessors:Array[VFileAccess])->VFileAccess ## A basic file accessor. -static func create_file_access(root:String = "./")->VFileAccess: - var vfiler := VFileAccess.new(root) +static func create_file_access( + root:String = "./", + support_files:Dictionary[String,Callable] = VFileAccess.IMPORTS.DEFAULT_SUPPORTED_FILES + )->VFileAccess: + var vfiler := VFileAccess.new(root, support_files) vfiler._get_buffer = FileAccess.get_file_as_bytes # thanks for being static @@ -68,7 +74,7 @@ static func create_file_access(root:String = "./")->VFileAccess: static func create_writeonly_zip_access( zip_path:String, - append := ZIPPacker.ZipAppend.APPEND_CREATE + append := ZIPPacker.ZipAppend.APPEND_CREATE, )->VFileAccess: var vfiler := VFileAccess.new() if not is_instance_valid(vfiler): return null @@ -106,18 +112,23 @@ static func create_writeonly_zip_access( ## A single zip file accessor, but with write functions disabled. ## TODO option to keep zips open, for OS to flag files as in-use. -static func create_readonly_zip_access(zip_path:String)->VFileAccess: - var vfiler := create_bulk_readonly_zip_access([zip_path]) +static func create_readonly_zip_access( + zip_path:String, keep_open:bool = false, + support_files:Dictionary[String,Callable] = VFileAccess.IMPORTS.DEFAULT_SUPPORTED_FILES + )->VFileAccess: + var vfiler := create_bulk_readonly_zip_access([zip_path], keep_open, support_files) vfiler._get_stuff = func()->Variant: return vfiler.get_stuff()[0] return vfiler ## A multi-zip readonly accessor. Allows for multiple zips to load with overrides. ## TODO option to keep zips open, for OS to flag files as in-use. +## [param if_missing_zip(String)] executes if a requested file is not found. static func create_bulk_readonly_zip_access( zip_paths:Array[String], keep_open:bool = false, - if_missing_zip := func _ignore(_zip_path:String)->bool: return false + support_files:Dictionary[String,Callable] = VFileAccess.IMPORTS.DEFAULT_SUPPORTED_FILES, + if_missing_zip := func _ignore(_zip_path:String)->bool: return false, )->VFileAccess: - var vfiler := VFileAccess.new("") + var vfiler := VFileAccess.new("", support_files) var readers:Array[ZIPReader] = [] readers.assign(zip_paths.map( diff --git a/vfs.gd b/vfs.gd index 4639b97..571b66c 100644 --- a/vfs.gd +++ b/vfs.gd @@ -2,6 +2,8 @@ ## ## File access across different methods sucks. ## Here's something to abstract that away and suck a little less. +## +## Written for Godot 4.4 class_name VFileAccess extends RefCounted @@ -14,24 +16,40 @@ const IMPORTS:GDScript = preload("vfs_loaders.gd") var root:String = "" ## Callable(bytes:PackedByteArray, [...])->Variant -var supported_files:Dictionary[String,Callable] = IMPORTS.DEFAULT_SUPPORTED_FILES +var supported_files:Dictionary[String,Callable] = {} ## Get any stuff we might be using in our closures. var _get_stuff:Callable = func()->Variant: return null ## How can we write to a file? -var _write_file:Callable = func(_abs_path:String, data:Variant)->Error: return ERR_CANT_OPEN +var _write_file:Callable = func(_abs_path:String, data:Variant)->Error: + return ERR_CANT_OPEN ## How do we get bytes from this? -var _get_buffer:Callable = func(_abs_path:String)->PackedByteArray: return PackedByteArray() +var _get_buffer:Callable = func(_abs_path:String)->PackedByteArray: + return PackedByteArray() ## What determines if a file exists? -var _file_exists:Callable = func(_abs_path:String)->bool: return false +var _file_exists:Callable = func(_abs_path:String)->bool: + return false ## How do we get files at a subdirectory? -var _get_files_at:Callable = func(_abs_path:String)->Array[String]: return [] +var _get_files_at:Callable = func(_abs_path:String)->Array[String]: + return [] ## Shutdown code here. var _close:Callable = func()->void: pass ## Default -func _init(root_dir:String = "./")->void: +func _init( + root_dir:String = "./", + support_files = IMPORTS.DEFAULT_SUPPORTED_FILES + )->void: self.root = root_dir + self.supported_files = support_files.duplicate(true) + +#region Static ops + +static func copy_file(from:VFileAccess, to:VFileAccess)->bool: + push_warning("Copy file unimplemented") + return false + +#endregion ## I never won awards for naming things correctly. func get_stuff()->Variant: @@ -54,6 +72,13 @@ func get_supported_files()->Array[String]: return supported_files.keys() +func load_supported_bulk( + paths:Array[String], + ext_override:String = "" + )->Array[Variant]: + return paths.map(load_supported.bind(ext_override)) + + ## Load a supported file. If [param path]'s extension matches a supported file, ## it will use that loader and return whatever it's supposed to. ## [param ext_override] allows for selecting a specific loader by key. diff --git a/vfs_loaders.gd b/vfs_loaders.gd index 7b161d4..4ef3f6f 100644 --- a/vfs_loaders.gd +++ b/vfs_loaders.gd @@ -14,10 +14,15 @@ static func validate_loader(loader:Callable)->bool: static func load_bin(buffer:PackedByteArray)->PackedByteArray: return buffer static func load_png(buffer:PackedByteArray)->Image: - var img:Image + var img := Image.new() img.load_png_from_buffer(buffer) return img +static func load_jpg(buffer:PackedByteArray)->Image: + var img := Image.new() + img.load_jpg_from_buffer(buffer) + return img + static func load_mp3(buffer:PackedByteArray)->AudioStreamMP3: var sfx := AudioStreamMP3.new() sfx.data = buffer @@ -32,19 +37,39 @@ static func load_txt(buffer:PackedByteArray)->String: var txt:String = buffer.get_string_from_utf8() return txt +static func load_wav(buffer:PackedByteArray)->AudioStreamWAV: + var sfx := AudioStreamWAV.new() + push_warning(""" + Cannot automatically parse wav because dynamic Godot parsing wav is currently manual and awful. + Despite this, somehow Godot's editor importer seems to handle parsing wav just fine.""") + return sfx + # can't use CONST since Callables are technically instanced dynamically static var DEFAULT_SUPPORTED_FILES:Dictionary[String,Callable] = { "bin": load_bin, + "txt": load_txt, "png": load_png, + "jpg": load_jpg, + "jpeg": load_jpg, "mp3": load_mp3, "ogg": load_ogg, + "wav": load_wav, +} + +static var DATA_FILES:Dictionary[String,Callable] = { + "bin": load_bin, "txt": load_txt, } - +static var IMAGE_FILES:Dictionary[String,Callable] = { + "png": load_png, + "jpg": load_jpg, + "jpeg": load_jpg, +} static var AUDIO_FILES:Dictionary[String,Callable] = { "mp3": load_mp3, "ogg": load_ogg, + "wav": load_wav, }