Compare commits
No commits in common. "b5fe707c1aad6437bbf59c960ac51c9619d4857d" and "b0de07fda89a285a75e9bab169665b89ea330411" have entirely different histories.
b5fe707c1a
...
b0de07fda8
21
LICENSE
21
LICENSE
@ -1,21 +0,0 @@
|
|||||||
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.
|
|
@ -1,8 +1,5 @@
|
|||||||
# Not unlike factory pattern.
|
# 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.
|
## Recursively creates virtual file systems.
|
||||||
static func create_meta_accessor(file_accessors:Array[VFileAccess])->VFileAccess:
|
static func create_meta_accessor(file_accessors:Array[VFileAccess])->VFileAccess:
|
||||||
var vfiler := VFileAccess.new()
|
var vfiler := VFileAccess.new()
|
||||||
@ -42,11 +39,8 @@ static func create_meta_accessor(file_accessors:Array[VFileAccess])->VFileAccess
|
|||||||
|
|
||||||
|
|
||||||
## A basic file accessor.
|
## A basic file accessor.
|
||||||
static func create_file_access(
|
static func create_file_access(root:String = "./")->VFileAccess:
|
||||||
root:String = "./",
|
var vfiler := VFileAccess.new(root)
|
||||||
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
|
vfiler._get_buffer = FileAccess.get_file_as_bytes # thanks for being static
|
||||||
|
|
||||||
@ -74,7 +68,7 @@ static func create_file_access(
|
|||||||
|
|
||||||
static func create_writeonly_zip_access(
|
static func create_writeonly_zip_access(
|
||||||
zip_path:String,
|
zip_path:String,
|
||||||
append := ZIPPacker.ZipAppend.APPEND_CREATE,
|
append := ZIPPacker.ZipAppend.APPEND_CREATE
|
||||||
)->VFileAccess:
|
)->VFileAccess:
|
||||||
var vfiler := VFileAccess.new()
|
var vfiler := VFileAccess.new()
|
||||||
if not is_instance_valid(vfiler): return null
|
if not is_instance_valid(vfiler): return null
|
||||||
@ -112,23 +106,18 @@ static func create_writeonly_zip_access(
|
|||||||
|
|
||||||
## A single zip file accessor, but with write functions disabled.
|
## A single zip file accessor, but with write functions disabled.
|
||||||
## TODO option to keep zips open, for OS to flag files as in-use.
|
## TODO option to keep zips open, for OS to flag files as in-use.
|
||||||
static func create_readonly_zip_access(
|
static func create_readonly_zip_access(zip_path:String)->VFileAccess:
|
||||||
zip_path:String, keep_open:bool = false,
|
var vfiler := create_bulk_readonly_zip_access([zip_path])
|
||||||
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]
|
vfiler._get_stuff = func()->Variant: return vfiler.get_stuff()[0]
|
||||||
return vfiler
|
return vfiler
|
||||||
|
|
||||||
## A multi-zip readonly accessor. Allows for multiple zips to load with overrides.
|
## 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.
|
## 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(
|
static func create_bulk_readonly_zip_access(
|
||||||
zip_paths:Array[String], keep_open:bool = false,
|
zip_paths:Array[String], keep_open:bool = false,
|
||||||
support_files:Dictionary[String,Callable] = VFileAccess.IMPORTS.DEFAULT_SUPPORTED_FILES,
|
if_missing_zip := func _ignore(_zip_path:String)->bool: return false
|
||||||
if_missing_zip := func _ignore(_zip_path:String)->bool: return false,
|
|
||||||
)->VFileAccess:
|
)->VFileAccess:
|
||||||
var vfiler := VFileAccess.new("", support_files)
|
var vfiler := VFileAccess.new("")
|
||||||
|
|
||||||
var readers:Array[ZIPReader] = []
|
var readers:Array[ZIPReader] = []
|
||||||
readers.assign(zip_paths.map(
|
readers.assign(zip_paths.map(
|
||||||
|
37
vfs.gd
37
vfs.gd
@ -2,8 +2,6 @@
|
|||||||
##
|
##
|
||||||
## File access across different methods sucks.
|
## File access across different methods sucks.
|
||||||
## Here's something to abstract that away and suck a little less.
|
## Here's something to abstract that away and suck a little less.
|
||||||
##
|
|
||||||
## Written for Godot 4.4
|
|
||||||
|
|
||||||
class_name VFileAccess extends RefCounted
|
class_name VFileAccess extends RefCounted
|
||||||
|
|
||||||
@ -16,40 +14,24 @@ const IMPORTS:GDScript = preload("vfs_loaders.gd")
|
|||||||
var root:String = ""
|
var root:String = ""
|
||||||
|
|
||||||
## Callable(bytes:PackedByteArray, [...])->Variant
|
## Callable(bytes:PackedByteArray, [...])->Variant
|
||||||
var supported_files:Dictionary[String,Callable] = {}
|
var supported_files:Dictionary[String,Callable] = IMPORTS.DEFAULT_SUPPORTED_FILES
|
||||||
|
|
||||||
## Get any stuff we might be using in our closures.
|
## Get any stuff we might be using in our closures.
|
||||||
var _get_stuff:Callable = func()->Variant: return null
|
var _get_stuff:Callable = func()->Variant: return null
|
||||||
## How can we write to a file?
|
## How can we write to a file?
|
||||||
var _write_file:Callable = func(_abs_path:String, data:Variant)->Error:
|
var _write_file:Callable = func(_abs_path:String, data:Variant)->Error: return ERR_CANT_OPEN
|
||||||
return ERR_CANT_OPEN
|
|
||||||
## How do we get bytes from this?
|
## How do we get bytes from this?
|
||||||
var _get_buffer:Callable = func(_abs_path:String)->PackedByteArray:
|
var _get_buffer:Callable = func(_abs_path:String)->PackedByteArray: return PackedByteArray()
|
||||||
return PackedByteArray()
|
|
||||||
## What determines if a file exists?
|
## What determines if a file exists?
|
||||||
var _file_exists:Callable = func(_abs_path:String)->bool:
|
var _file_exists:Callable = func(_abs_path:String)->bool: return false
|
||||||
return false
|
|
||||||
## How do we get files at a subdirectory?
|
## How do we get files at a subdirectory?
|
||||||
var _get_files_at:Callable = func(_abs_path:String)->Array[String]:
|
var _get_files_at:Callable = func(_abs_path:String)->Array[String]: return []
|
||||||
return []
|
|
||||||
## Shutdown code here.
|
## Shutdown code here.
|
||||||
var _close:Callable = func()->void: pass
|
var _close:Callable = func()->void: pass
|
||||||
|
|
||||||
## Default
|
## Default
|
||||||
func _init(
|
func _init(root_dir:String = "./")->void:
|
||||||
root_dir:String = "./",
|
|
||||||
support_files = IMPORTS.DEFAULT_SUPPORTED_FILES
|
|
||||||
)->void:
|
|
||||||
self.root = root_dir
|
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.
|
## I never won awards for naming things correctly.
|
||||||
func get_stuff()->Variant:
|
func get_stuff()->Variant:
|
||||||
@ -72,13 +54,6 @@ func get_supported_files()->Array[String]:
|
|||||||
return supported_files.keys()
|
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,
|
## 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.
|
## it will use that loader and return whatever it's supposed to.
|
||||||
## [param ext_override] allows for selecting a specific loader by key.
|
## [param ext_override] allows for selecting a specific loader by key.
|
||||||
|
@ -14,15 +14,10 @@ static func validate_loader(loader:Callable)->bool:
|
|||||||
static func load_bin(buffer:PackedByteArray)->PackedByteArray: return buffer
|
static func load_bin(buffer:PackedByteArray)->PackedByteArray: return buffer
|
||||||
|
|
||||||
static func load_png(buffer:PackedByteArray)->Image:
|
static func load_png(buffer:PackedByteArray)->Image:
|
||||||
var img := Image.new()
|
var img:Image
|
||||||
img.load_png_from_buffer(buffer)
|
img.load_png_from_buffer(buffer)
|
||||||
return img
|
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:
|
static func load_mp3(buffer:PackedByteArray)->AudioStreamMP3:
|
||||||
var sfx := AudioStreamMP3.new()
|
var sfx := AudioStreamMP3.new()
|
||||||
sfx.data = buffer
|
sfx.data = buffer
|
||||||
@ -37,39 +32,19 @@ static func load_txt(buffer:PackedByteArray)->String:
|
|||||||
var txt:String = buffer.get_string_from_utf8()
|
var txt:String = buffer.get_string_from_utf8()
|
||||||
return txt
|
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
|
# can't use CONST since Callables are technically instanced dynamically
|
||||||
|
|
||||||
static var DEFAULT_SUPPORTED_FILES:Dictionary[String,Callable] = {
|
static var DEFAULT_SUPPORTED_FILES:Dictionary[String,Callable] = {
|
||||||
"bin": load_bin,
|
"bin": load_bin,
|
||||||
"txt": load_txt,
|
|
||||||
"png": load_png,
|
"png": load_png,
|
||||||
"jpg": load_jpg,
|
|
||||||
"jpeg": load_jpg,
|
|
||||||
"mp3": load_mp3,
|
"mp3": load_mp3,
|
||||||
"ogg": load_ogg,
|
"ogg": load_ogg,
|
||||||
"wav": load_wav,
|
|
||||||
}
|
|
||||||
|
|
||||||
static var DATA_FILES:Dictionary[String,Callable] = {
|
|
||||||
"bin": load_bin,
|
|
||||||
"txt": load_txt,
|
"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] = {
|
static var AUDIO_FILES:Dictionary[String,Callable] = {
|
||||||
"mp3": load_mp3,
|
"mp3": load_mp3,
|
||||||
"ogg": load_ogg,
|
"ogg": load_ogg,
|
||||||
"wav": load_wav,
|
|
||||||
}
|
}
|
||||||
|
Loading…
Reference in New Issue
Block a user