From 04581a5b64eaaa6a02f1d130f0d41b2d757525b2 Mon Sep 17 00:00:00 2001 From: Mirsario Date: Sat, 13 Nov 2021 20:20:32 +0300 Subject: [PATCH] Asset lookup registration rework (#15) * Experiments. * AssetFileEntry, disconnected lookup registration from autoload. * Various fixes. (cherry picked from commit 4f5b280182a4e5f8bbf05caa18e96e9a13284c07) * Removed unused junk. --- Src/IO/Asset.cs | 19 ++- Src/IO/AssetFileEntry.cs | 21 +++ Src/IO/AssetLookup.cs | 48 ++++-- Src/IO/Assets.cs | 142 ++++++++++++------ Src/IO/IAssetReader.cs | 2 +- Src/IO/Readers/Audio/OggReader.cs | 11 +- Src/IO/Readers/Audio/WavReader.cs | 3 +- Src/IO/Readers/BytesReader.cs | 4 +- Src/IO/Readers/Graphics/MaterialReader.cs | 3 +- Src/IO/Readers/Graphics/Models/GltfReader.cs | 5 +- Src/IO/Readers/Graphics/Models/ObjReader.cs | 10 +- Src/IO/Readers/Graphics/ShaderReader.cs | 6 +- Src/IO/Readers/HjsonReader.cs | 6 +- .../Physics/ConvexCollisionMeshManager.cs | 7 +- Src/IO/Readers/TextReader.cs | 3 +- Src/IO/Readers/Textures/PngReader.cs | 4 +- 16 files changed, 203 insertions(+), 91 deletions(-) create mode 100644 Src/IO/AssetFileEntry.cs diff --git a/Src/IO/Asset.cs b/Src/IO/Asset.cs index 167ad7f3..65660e84 100644 --- a/Src/IO/Asset.cs +++ b/Src/IO/Asset.cs @@ -20,8 +20,8 @@ public abstract class Asset /// The state of this asset. public AssetState State { get; internal set; } - /// The source of this asset. Can be null. - public AssetSource Source { get; internal set; } + /// The file source of this asset. Can be null. + public AssetFileEntry? File { get; internal set; } /// Whether or not this asset is currently being loaded. public bool IsLoading => State == AssetState.Loading; @@ -111,7 +111,7 @@ private async Task Load(AssetRequestMode mode) var asyncContext = new ContinuationScheduler(this); string extension = Path.GetExtension(AssetPath); - var readerByExtension = Assets.ReadersByDataType.ReaderByExtension; + var readerByExtension = Assets.AssetTypeData.ReaderByExtension; if (readerByExtension.Count == 0) { throw new InvalidOperationException($"No asset reader found with a return type of '{typeof(T).Name}'."); @@ -125,23 +125,26 @@ private async Task Load(AssetRequestMode mode) await Task.Yield(); // This transfers the method's execution to a worker thread. } - using var stream = Source.OpenStream(AssetPath); - - Value = await assetReader.ReadFromStream(stream, AssetPath, new MainThreadCreationContext(asyncContext)); + Value = await assetReader.ReadAsset(File, new MainThreadCreationContext(asyncContext)); State = AssetState.Loaded; } private void SafelyWaitForLoad(Task loadTask, bool tracked) { - if (State == AssetState.Loaded) + if (State == AssetState.Loaded) { return; + } if (!loadTask.IsCompleted && Assets.IsMainThread) { - while (Continuation == null) { + while (Continuation == null && State != AssetState.Loaded) { Thread.Yield(); } + if (State == AssetState.Loaded) { + return; + } + if (tracked) { lock (Assets.RequestLock) { Continuation(); diff --git a/Src/IO/AssetFileEntry.cs b/Src/IO/AssetFileEntry.cs new file mode 100644 index 00000000..2ab75554 --- /dev/null +++ b/Src/IO/AssetFileEntry.cs @@ -0,0 +1,21 @@ +using System.IO; + +namespace Dissonance.Engine.IO +{ + public class AssetFileEntry + { + public readonly string Path; + public readonly AssetSource Source; + + public AssetFileEntry(string path, AssetSource source) + { + Path = path; + Source = source; + } + + public Stream OpenStream() + { + return Source.OpenStream(Path); + } + } +} diff --git a/Src/IO/AssetLookup.cs b/Src/IO/AssetLookup.cs index 7d26eda5..03d29339 100644 --- a/Src/IO/AssetLookup.cs +++ b/Src/IO/AssetLookup.cs @@ -13,7 +13,7 @@ internal static class AssetLookup internal static class AssetLookup { - private static readonly ConcurrentDictionary> lookup = new(); + private static readonly ConcurrentDictionary asset)> lookup = new(); public static int Count => lookup.Count; @@ -24,21 +24,49 @@ static AssetLookup() }; } - public static void Register(string name, Asset asset) + public static void Register(string name, string path, Asset asset) { - if (lookup.ContainsKey(name)) { - //throw new Exception($"Cannot register two {typeof(T).Name} with the same name: {name}."); + if (lookup.TryGetValue(name, out var existingTuple) && existingTuple.assetPath == path) { + lookup[name] = (null, null); // This marks the registry as ambiguous. + } else { + lookup[name] = (path, asset); + } + } + + public static Asset Get(string fullName, AssetRequestMode mode = AssetRequestMode.DoNotLoad) + { + var tuple = lookup[fullName]; - asset = null; // This marks the registry as ambiguous. + if (tuple.assetPath == null && tuple.asset == null) { + throw new ArgumentException($"Key '{fullName}' is ambiguous."); } - lookup[name] = asset; + if (tuple.asset == null) { + tuple.asset = Assets.Get(tuple.assetPath, mode); + lookup[fullName] = tuple; + } + + return tuple.asset; } - public static Asset Get(string fullName) - => lookup[fullName] ?? throw new ArgumentException($"Key '{fullName}' is ambiguous."); + public static bool TryGet(string fullName, out Asset result, AssetRequestMode mode = AssetRequestMode.DoNotLoad) + { + var tuple = lookup[fullName]; + + if (tuple.assetPath == null && tuple.asset == null) { + result = null; + + return false; + } - public static bool TryGetValue(string fullName, out Asset value) - => lookup.TryGetValue(fullName, out value) && value != null; + if (tuple.asset == null) { + tuple.asset = Assets.Get(tuple.assetPath, mode); + lookup[fullName] = tuple; + } + + result = tuple.asset; + + return true; + } } } diff --git a/Src/IO/Assets.cs b/Src/IO/Assets.cs index 6bba291d..b946632f 100644 --- a/Src/IO/Assets.cs +++ b/Src/IO/Assets.cs @@ -11,10 +11,11 @@ namespace Dissonance.Engine.IO //TODO: Make a ton more threadsafe. public sealed class Assets : EngineModule { - internal static class ReadersByDataType + internal static class AssetTypeData { - internal static readonly HashSet> Readers = new(); - internal static readonly Dictionary> ReaderByExtension = new(); + public static readonly Dictionary> Assets = new(); + public static readonly HashSet> Readers = new(); + public static readonly Dictionary> ReaderByExtension = new(); } internal const string BuiltInAssetsDirectory = "BuiltInAssets"; @@ -24,7 +25,8 @@ internal static class ReadersByDataType internal static readonly ConcurrentQueue AssetTransferQueue = new(); private static readonly HashSet sources = new(); - private static readonly Dictionary assets = new(); + private static readonly Dictionary assetFiles = new(); + //private static readonly Dictionary> assets = new(); internal static bool IsMainThread => Thread.CurrentThread == Game.MainThread; @@ -32,7 +34,7 @@ protected override void Init() { RegisterAssetSources(); RegisterAssetReaders(); - AutoloadAssets(); + PrepareAssets(); } protected override void PreRenderUpdate() @@ -45,22 +47,12 @@ protected override void PreRenderUpdate() } /// - /// Returns whether or not an asset the provided case-sensitive virtual path exists. + /// Returns whether or not an asset of the provided type and case-sensitive virtual path exists. /// /// The path of the asset. This path is virtual and case-sensitive - system paths will not work. - public static bool Exists(string assetPath) + public static bool Exists(string assetPath) { - if (assets.ContainsKey(assetPath)) { - return true; - } - - foreach (var source in sources) { - if (source.HasAsset(assetPath)) { - return true; - } - } - - return false; + return assetFiles.ContainsKey(assetPath); } /// @@ -112,7 +104,7 @@ public static bool TryGet(string assetPath, string basePath, out Asset res assetPath = assetPath.Substring(1); } - return TryGet(assetPath, out result, mode); + return TryGet(assetPath, out result, mode); } /// @@ -126,28 +118,30 @@ public static bool TryGet(string assetPath, string basePath, out Asset res /// A boolean indicating whether the operation succeeded. public static bool TryGet(string assetPath, out Asset result, AssetRequestMode mode = AssetRequestMode.DoNotLoad) { - if (assets.TryGetValue(assetPath, out var cachedAsset) && cachedAsset is Asset cachedAssetResult) { + if (AssetTypeData.Assets.TryGetValue(assetPath, out var cachedAsset) && cachedAsset is Asset cachedAssetResult) { if (mode != AssetRequestMode.DoNotLoad && cachedAssetResult.State == AssetState.NotLoaded) { cachedAssetResult.Request(mode); } result = cachedAssetResult; - if (mode == AssetRequestMode.ImmediateLoad) + if (mode == AssetRequestMode.ImmediateLoad && result.State != AssetState.Loaded) { result.Wait(); + } return true; } - foreach (var source in sources) { - if (!source.HasAsset(assetPath)) { - continue; - } + if (assetFiles.TryGetValue(assetPath, out var assetFile)) { + result = CreateAsset(assetFile); - result = RequestFromSource(source, assetPath, mode); + if (mode != AssetRequestMode.DoNotLoad) { + result.Request(mode); + } - if (mode == AssetRequestMode.ImmediateLoad) + if (mode == AssetRequestMode.ImmediateLoad && result.State != AssetState.Loaded) { result.Wait(); + } return true; } @@ -165,16 +159,16 @@ public static bool TryGet(string assetPath, out Asset result, AssetRequest /// The case-sensitive name of the asset. This is not the same as its path. /// <> - an asset handle. /// No registered asset could be found with the provided name. - public static Asset Find(string assetName) - => AssetLookup.Get(assetName); + public static Asset Find(string assetName, AssetRequestMode mode = AssetRequestMode.DoNotLoad) + => AssetLookup.Get(assetName, mode); /// Safely attempts to find a registered asset using its case-sensitive name instead of a path. /// The type of the asset. /// The case-sensitive name of the asset. This is not the same as its path. /// The resulting <> - an asset handle, if it was found. /// A boolean indicating whether the operation succeeded. - public static bool TryFind(string assetName, out Asset result) - => AssetLookup.TryGetValue(assetName, out result); + public static bool TryFind(string assetName, out Asset result, AssetRequestMode mode = AssetRequestMode.DoNotLoad) + => AssetLookup.TryGet(assetName, out result, mode); /// /// Creates, registers and returns a new pre-loaded asset object with the provided name and value. @@ -188,7 +182,7 @@ public static Asset CreateLoaded(string name, T value) { var asset = CreateUntracked(name, value); - AssetLookup.Register(name, asset); + AssetLookup.Register(name, null, asset); return asset; } @@ -238,30 +232,28 @@ public static void AddAssetSource(AssetSource assetSource) /// public static void AddAssetReader(IAssetReader assetReader) { - if (!ReadersByDataType.Readers.Add(assetReader)) { + if (!AssetTypeData.Readers.Add(assetReader)) { throw new InvalidOperationException($"Asset reader '{assetReader.GetType().Name}' is already registered."); } ReaderAssetTypes.Add(typeof(T)); foreach (string extension in assetReader.Extensions) { - ReadersByDataType.ReaderByExtension.Add(extension, assetReader); + AssetTypeData.ReaderByExtension.Add(extension, assetReader); } } - private static Asset RequestFromSource(AssetSource source, string assetPath, AssetRequestMode mode = AssetRequestMode.AsyncLoad) + private static Asset CreateAsset(AssetFileEntry assetFile) { + string assetPath = assetFile.Path; string assetName = Path.GetFileNameWithoutExtension(assetPath); + var asset = new Asset(assetName) { AssetPath = assetPath, - Source = source + File = assetFile }; - AssetLookup.Register(assetName, asset); - - assets[assetPath] = asset; - - asset.Request(mode); + AssetLookup.Register(assetName, assetFile.Path, asset); return asset; } @@ -310,6 +302,51 @@ private static void RegisterAssetReaders() } } + private static void PrepareAssets() + { + PrepareAssetFileLists(); + PrepareAssetLookup(); + AutoloadAssets(); + } + + private static void PrepareAssetFileLists() + { + assetFiles.Clear(); + + foreach (var source in sources) { + foreach (string assetPath in source.EnumerateAssets()) { + assetFiles[assetPath] = new AssetFileEntry(assetPath, source); + } + } + } + + private static void PrepareAssetLookup() + { + var refreshAssetLookupMethod = typeof(Assets).GetMethod(nameof(RefreshAssetLookupOfType), BindingFlags.Static | BindingFlags.NonPublic); + + foreach (var type in ReaderAssetTypes) { + refreshAssetLookupMethod + .MakeGenericMethod(type) + .Invoke(null, null); + } + } + + private static void RefreshAssetLookupOfType() + { + foreach (var assetFile in assetFiles.Values) { + string assetPath = assetFile.Path; + string assetExtension = Path.GetExtension(assetPath); + + if (!AssetTypeData.ReaderByExtension.TryGetValue(assetExtension, out var assetReader)) { + continue; + } + + string assetName = Path.GetFileNameWithoutExtension(assetPath); + + AssetLookup.Register(assetName, assetPath, null); + } + } + private static void AutoloadAssets() { var autoloadAssetsMethod = typeof(Assets).GetMethod(nameof(AutoloadAssetsGeneric), BindingFlags.Static | BindingFlags.NonPublic); @@ -323,18 +360,27 @@ private static void AutoloadAssets() private static void AutoloadAssetsGeneric() { - foreach (var reader in ReadersByDataType.Readers) { + var loadingAssets = new Queue(); + + foreach (var reader in AssetTypeData.Readers) { if (!reader.AutoloadAssets) { continue; } - foreach (var source in sources) { - foreach (string assetPath in source.EnumerateAssets()) { - string extension = Path.GetExtension(assetPath); + foreach (var assetFile in assetFiles.Values) { + string extension = Path.GetExtension(assetFile.Path); + + if (reader.Extensions.Contains(extension)) { + var asset = CreateAsset(assetFile); + + asset.Request(AssetRequestMode.AsyncLoad); + loadingAssets.Enqueue(asset); + } + } - if (reader.Extensions.Contains(extension)) { - RequestFromSource(source, assetPath, AssetRequestMode.ImmediateLoad); //TODO: Use async load, then wait for all of them to finish. - } + while (loadingAssets.TryDequeue(out var asset)) { + if (asset.State == AssetState.Loading) { + asset.Wait(); } } } diff --git a/Src/IO/IAssetReader.cs b/Src/IO/IAssetReader.cs index 658e816d..6a67b78b 100644 --- a/Src/IO/IAssetReader.cs +++ b/Src/IO/IAssetReader.cs @@ -25,6 +25,6 @@ public interface IAssetReader /// The path of the asset that's currently being loaded. /// Await this to switch execution of the method to the main thread. /// A result of type . - ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread); + ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread); } } diff --git a/Src/IO/Readers/Audio/OggReader.cs b/Src/IO/Readers/Audio/OggReader.cs index 79a04839..a2c75b59 100644 --- a/Src/IO/Readers/Audio/OggReader.cs +++ b/Src/IO/Readers/Audio/OggReader.cs @@ -9,18 +9,19 @@ public class OggReader : IAssetReader { public string[] Extensions { get; } = { ".ogg" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { - using var r = new VorbisReader(stream, true); + using var stream = assetFile.OpenStream(); + using var reader = new VorbisReader(stream, true); - long bufferSize = r.TotalSamples * r.Channels; + long bufferSize = reader.TotalSamples * reader.Channels; float[] data = new float[bufferSize]; - r.ReadSamples(data, 0, (int)bufferSize); + reader.ReadSamples(data, 0, (int)bufferSize); var clip = new AudioClip(); - clip.SetData(data, r.Channels, sizeof(float), r.SampleRate); + clip.SetData(data, reader.Channels, sizeof(float), reader.SampleRate); return clip; } diff --git a/Src/IO/Readers/Audio/WavReader.cs b/Src/IO/Readers/Audio/WavReader.cs index 3cf33f3e..7a202402 100644 --- a/Src/IO/Readers/Audio/WavReader.cs +++ b/Src/IO/Readers/Audio/WavReader.cs @@ -9,8 +9,9 @@ public class WavReader : IAssetReader { public string[] Extensions { get; } = { ".wav" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + using var stream = assetFile.OpenStream(); using var reader = new BinaryReader(stream); // RIFF header diff --git a/Src/IO/Readers/BytesReader.cs b/Src/IO/Readers/BytesReader.cs index 59bc6b2f..52e5657f 100644 --- a/Src/IO/Readers/BytesReader.cs +++ b/Src/IO/Readers/BytesReader.cs @@ -7,8 +7,10 @@ public sealed class BytesReader : IAssetReader { public string[] Extensions { get; } = { ".bytes" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + using var stream = assetFile.OpenStream(); + byte[] bytes = new byte[stream.Length]; stream.Read(bytes, 0, bytes.Length); diff --git a/Src/IO/Readers/Graphics/MaterialReader.cs b/Src/IO/Readers/Graphics/MaterialReader.cs index 02628690..e715ec78 100644 --- a/Src/IO/Readers/Graphics/MaterialReader.cs +++ b/Src/IO/Readers/Graphics/MaterialReader.cs @@ -29,8 +29,9 @@ private class JsonMaterial public string[] Extensions { get; } = { ".material" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + string assetPath = assetFile.Path; string directory = Assets.FilterPath(Path.GetDirectoryName(assetPath)); var jsonMat = Assets.Get(assetPath, AssetRequestMode.ImmediateLoad).Value.ToObject(); diff --git a/Src/IO/Readers/Graphics/Models/GltfReader.cs b/Src/IO/Readers/Graphics/Models/GltfReader.cs index 65349653..2af48bd4 100644 --- a/Src/IO/Readers/Graphics/Models/GltfReader.cs +++ b/Src/IO/Readers/Graphics/Models/GltfReader.cs @@ -45,10 +45,13 @@ public partial class GltfReader : IAssetReader public string[] Extensions { get; } = { ".gltf", ".glb" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + string assetPath = assetFile.Path; var info = new GltfInfo(assetPath); + using var stream = assetFile.OpenStream(); + if (assetPath.EndsWith(".gltf")) { byte[] textBytes = new byte[stream.Length - stream.Position]; diff --git a/Src/IO/Readers/Graphics/Models/ObjReader.cs b/Src/IO/Readers/Graphics/Models/ObjReader.cs index 16d032d5..b0ab8101 100644 --- a/Src/IO/Readers/Graphics/Models/ObjReader.cs +++ b/Src/IO/Readers/Graphics/Models/ObjReader.cs @@ -20,13 +20,13 @@ internal struct MeshInfo public string[] Extensions { get; } = { ".obj" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { - string text; + using var stream = assetFile.OpenStream(); + using var reader = new StreamReader(stream); - using (var reader = new StreamReader(stream)) { - text = reader.ReadToEnd(); - } + string assetPath = assetFile.Path; + string text = reader.ReadToEnd(); float scale = 1f; var meshInfo = CreateOBJInfo(text); diff --git a/Src/IO/Readers/Graphics/ShaderReader.cs b/Src/IO/Readers/Graphics/ShaderReader.cs index f0312ac6..5a270d5f 100644 --- a/Src/IO/Readers/Graphics/ShaderReader.cs +++ b/Src/IO/Readers/Graphics/ShaderReader.cs @@ -2,7 +2,6 @@ using System.IO; using System.Threading.Tasks; using Dissonance.Engine.Graphics; -using Newtonsoft.Json; using Newtonsoft.Json.Linq; namespace Dissonance.Engine.IO @@ -13,9 +12,12 @@ public partial class ShaderReader : IAssetReader[]> public bool AutoloadAssets => !Game.Instance.Flags.HasFlag(GameFlags.NoGraphics); - public async ValueTask[]> ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask[]> ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + string assetPath = assetFile.Path; string directory = Assets.FilterPath(Path.GetDirectoryName(assetPath)); + + using var stream = assetFile.OpenStream(); using var reader = new StreamReader(stream); string jsonText = reader.ReadToEnd(); diff --git a/Src/IO/Readers/HjsonReader.cs b/Src/IO/Readers/HjsonReader.cs index 4be84df4..96748bf2 100644 --- a/Src/IO/Readers/HjsonReader.cs +++ b/Src/IO/Readers/HjsonReader.cs @@ -11,8 +11,9 @@ public class HjsonReader : IAssetReader, IAssetReader public string[] Extensions { get; } = new[] { "*", ".hjson" }; // Newtonsoft.Json - async ValueTask IAssetReader.ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + async ValueTask IAssetReader.ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + string assetPath = assetFile.Path; string hjsonText = Assets.Get(assetPath, AssetRequestMode.ImmediateLoad).Value; using var hjsonReader = new StringReader(hjsonText); @@ -23,8 +24,9 @@ async ValueTask IAssetReader.ReadFromStream(Stream stream, str } // System.Text.Json - async ValueTask IAssetReader.ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + async ValueTask IAssetReader.ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + string assetPath = assetFile.Path; string hjsonText = Assets.Get(assetPath, AssetRequestMode.ImmediateLoad).Value; using var hjsonReader = new StringReader(hjsonText); diff --git a/Src/IO/Readers/Physics/ConvexCollisionMeshManager.cs b/Src/IO/Readers/Physics/ConvexCollisionMeshManager.cs index 3ae1df86..892afdc7 100644 --- a/Src/IO/Readers/Physics/ConvexCollisionMeshManager.cs +++ b/Src/IO/Readers/Physics/ConvexCollisionMeshManager.cs @@ -1,8 +1,6 @@ +using System.Threading.Tasks; using Dissonance.Engine.Graphics; using Dissonance.Engine.Physics; -using System; -using System.IO; -using System.Threading.Tasks; namespace Dissonance.Engine.IO { @@ -10,8 +8,9 @@ public class ConvexCollisionMeshManager : IAssetReader { public string[] Extensions { get; } = { ".obj" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + string assetPath = assetFile.Path; var mesh = Assets.Get(assetPath, AssetRequestMode.ImmediateLoad).Value; var collisionMesh = new ConvexCollisionMesh(); diff --git a/Src/IO/Readers/TextReader.cs b/Src/IO/Readers/TextReader.cs index 25cbb809..52cd5f16 100644 --- a/Src/IO/Readers/TextReader.cs +++ b/Src/IO/Readers/TextReader.cs @@ -7,8 +7,9 @@ public class TextReader : IAssetReader { public string[] Extensions { get; } = { "*", ".txt" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + using var stream = assetFile.OpenStream(); using var reader = new StreamReader(stream); return reader.ReadToEnd(); diff --git a/Src/IO/Readers/Textures/PngReader.cs b/Src/IO/Readers/Textures/PngReader.cs index 491076bd..3fbc451d 100644 --- a/Src/IO/Readers/Textures/PngReader.cs +++ b/Src/IO/Readers/Textures/PngReader.cs @@ -12,8 +12,10 @@ public class PngReader : IAssetReader { public string[] Extensions { get; } = { ".png" }; - public async ValueTask ReadFromStream(Stream stream, string assetPath, MainThreadCreationContext switchToMainThread) + public async ValueTask ReadAsset(AssetFileEntry assetFile, MainThreadCreationContext switchToMainThread) { + using var stream = assetFile.OpenStream(); + var (width, height, pixels) = LoadImageData(stream); await switchToMainThread; // Switches context to the main thread for texture uploading.