diff --git a/PataNext.Export.Desktop/Program.cs b/PataNext.Export.Desktop/Program.cs index 3a61a904..d19c1a46 100644 --- a/PataNext.Export.Desktop/Program.cs +++ b/PataNext.Export.Desktop/Program.cs @@ -72,6 +72,7 @@ static async Task Main(string[] args) gameBootstrap.GameEntity.Set(typeof(PataNext.Simulation.Client.Module)); gameBootstrap.GameEntity.Set(typeof(Feature.RhythmEngineAudio.CustomModule)); gameBootstrap.GameEntity.Set(typeof(PataNext.Game.Module)); + gameBootstrap.GameEntity.Set(typeof(PataNext.Game.Client.Resources.Module)); foreach (var clientData in clientDirectory.GetFiles("*.json", SearchOption.TopDirectoryOnly)) { diff --git a/PataNext.Feature.RhythmEngineAudio/BGM/BgmStore.cs b/PataNext.Feature.RhythmEngineAudio/BGM/BgmStore.cs index 074a0765..eb15c9cf 100644 --- a/PataNext.Feature.RhythmEngineAudio/BGM/BgmStore.cs +++ b/PataNext.Feature.RhythmEngineAudio/BGM/BgmStore.cs @@ -61,11 +61,12 @@ public override async Task> GetFilesAsync(string pattern) { var founds = new List(); - using (var zip = new ZipFile(computedPath)) + using (var stream = new MemoryStream(await Source.GetContentAsync())) + using (var zip = new ZipFile(stream)) { foreach (ZipEntry entry in zip) if (FileSystemName.MatchesSimpleExpression(pattern, entry.Name)) - founds.Add(new ZipEntryFile(computedPath, entry)); + founds.Add(new ZipEntryFile(Source, entry)); } return founds; diff --git a/PataNext.Feature.RhythmEngineAudio/BGM/Directors/BgmDefaultSamplesLoader.cs b/PataNext.Feature.RhythmEngineAudio/BGM/Directors/BgmDefaultSamplesLoader.cs index 57158343..80b39929 100644 --- a/PataNext.Feature.RhythmEngineAudio/BGM/Directors/BgmDefaultSamplesLoader.cs +++ b/PataNext.Feature.RhythmEngineAudio/BGM/Directors/BgmDefaultSamplesLoader.cs @@ -18,6 +18,11 @@ public class BgmDefaultSamplesLoader : BgmSamplesLoaderBase public BgmDefaultSamplesLoader(BgmStore store) : base(store) { + Console.WriteLine(store); + Console.WriteLine(store.CurrentPath); + foreach (var file in store.GetFilesAsync("*.*").Result) + Console.WriteLine(file.FullName); + commandsTaskMap = new TaskMap(async key => { var files = (await Store.GetFilesAsync($"commands/{key}/*.ogg")) @@ -37,6 +42,7 @@ public BgmDefaultSamplesLoader(BgmStore store) : base(store) if (files.Length == 0) throw new InvalidOperationException($"No files found for soundtrack"); + Console.WriteLine(">>> " + files.Length); return new SlicedSoundTrack(files); }); diff --git a/PataNext.Feature.RhythmEngineAudio/SimulationSystems/LoadActiveBgm.cs b/PataNext.Feature.RhythmEngineAudio/SimulationSystems/LoadActiveBgm.cs index 46b200dc..fae33c3a 100644 --- a/PataNext.Feature.RhythmEngineAudio/SimulationSystems/LoadActiveBgm.cs +++ b/PataNext.Feature.RhythmEngineAudio/SimulationSystems/LoadActiveBgm.cs @@ -32,12 +32,14 @@ protected override void OnUpdate() if (currentLoadedBgm.Span.SequenceEqual(LocalInformation.ActiveBgmId.Span) && isBgmLoaded) return; - + + Console.WriteLine(">>>> 0"); currentLoadedBgm = LocalInformation.ActiveBgmId; if (currentLoadedBgm.GetLength() == 0) return; - isBgmLoaded = false; + isBgmLoaded = true; + Console.WriteLine(">>>> 1"); // We use a double scheduler strategy. // - First schedule from the client app (main thread) to get the requested BGM file. @@ -49,11 +51,10 @@ protected override void OnUpdate() where ent.Has() select ent.Get()) .FirstOrDefault(bmgFile => bmgFile.Description.Id.AsSpan().SequenceEqual(currentLoadedBgm.Span)); - + //Console.WriteLine($"File exist for '{currentLoadedBgm}' ? {file != null}"); if (file == null) return; - scheduler.Schedule(LoadBgm, file, default); }, default); } @@ -62,8 +63,7 @@ private void LoadBgm(BgmFile file) { // since the description has been already computed, there is no need to await the result var director = BgmDirector.Create(file).Result; - - var entity = World.Mgr.CreateEntity(); + var entity = World.Mgr.CreateEntity(); entity.Set(director); isBgmLoaded = true; diff --git a/PataNext.Game.Client.Resources/Bgm/ZippedTheme.zip b/PataNext.Game.Client.Resources/Bgm/ZippedTheme.zip new file mode 100644 index 00000000..879a2af2 Binary files /dev/null and b/PataNext.Game.Client.Resources/Bgm/ZippedTheme.zip differ diff --git a/PataNext.Game.Client.Resources/Module.cs b/PataNext.Game.Client.Resources/Module.cs new file mode 100644 index 00000000..af5fd9ea --- /dev/null +++ b/PataNext.Game.Client.Resources/Module.cs @@ -0,0 +1,40 @@ +using System; +using DefaultEcs; +using GameHost.Core.Modules; +using GameHost.Injection; +using GameHost.IO; +using GameHost.Simulation.Application; +using GameHost.Threading; +using GameHost.Worlds; +using PataNext.Game.BGM; +using PataNext.Game.Client.Resources; + +[assembly: RegisterAvailableModule("PataNext.Game.Client.Resources", "guerro", typeof(Module))] + +namespace PataNext.Game.Client.Resources +{ + public class Module : GameHostModule + { + public Module(Entity source, Context ctxParent, GameHostModuleDescription description) : base(source, ctxParent, description) + { + Console.WriteLine("Resources module loaded"); + + var global = new ContextBindingStrategy(ctxParent, true).Resolve(); + Storage.Subscribe((_,exteriorStorage) => + { + var storage = exteriorStorage switch + { + {} => new StorageCollection{exteriorStorage, DllStorage}, + null => new StorageCollection {DllStorage} + }; + + global.Context.BindExisting(new BgmContainerStorage(storage.GetOrCreateDirectoryAsync("Bgm").Result)); + foreach (ref readonly var listener in global.World.Get()) + { + if (listener is SimulationApplication simulationApplication) + simulationApplication.Data.Context.BindExisting(new BgmContainerStorage(storage.GetOrCreateDirectoryAsync("Bgm").Result)); + } + }, true); + } + } +} \ No newline at end of file diff --git a/PataNext.Game/BGM/BgmContainerStorage.cs b/PataNext.Game/BGM/BgmContainerStorage.cs index db500ad8..5546c5d1 100644 --- a/PataNext.Game/BGM/BgmContainerStorage.cs +++ b/PataNext.Game/BGM/BgmContainerStorage.cs @@ -9,7 +9,7 @@ namespace PataNext.Game.BGM /// public class BgmContainerStorage : IStorage { - private IStorage parent; + public readonly IStorage parent; public BgmContainerStorage(IStorage parent) { diff --git a/PataNext.Game/BGM/BgmFile.cs b/PataNext.Game/BGM/BgmFile.cs index 763f8cae..84e808e9 100644 --- a/PataNext.Game/BGM/BgmFile.cs +++ b/PataNext.Game/BGM/BgmFile.cs @@ -42,8 +42,9 @@ public async Task ComputeDescription() private async Task FromZip() { - using var archive = ZipFile.OpenRead(FullName); - var descEntry = archive.GetEntry("description.json"); + await using var memoryStream = new MemoryStream(await GetContentAsync()); + using var archive = new ZipArchive(memoryStream, ZipArchiveMode.Read); + var descEntry = archive.GetEntry("description.json"); // TODO: file errors should be more explicit to the end user if (descEntry == null) diff --git a/PataNext.Game/Module.cs b/PataNext.Game/Module.cs index 5d8a03c7..d2b80000 100644 --- a/PataNext.Game/Module.cs +++ b/PataNext.Game/Module.cs @@ -21,19 +21,6 @@ public Module(Entity source, Context ctxParent, GameHostModuleDescription descri var global = new ContextBindingStrategy(ctxParent, true).Resolve(); var systems = new List(); AppSystemResolver.ResolveFor(GetType().Assembly, systems); - - Storage.Subscribe((_, storage) => - { - if (storage == null) - return; - - global.Context.BindExisting(new BgmContainerStorage(storage.GetOrCreateDirectoryAsync("Bgm").Result)); - foreach (ref readonly var listener in global.World.Get()) - { - if (listener is SimulationApplication simulationApplication) - simulationApplication.Data.Context.BindExisting(new BgmContainerStorage(storage.GetOrCreateDirectoryAsync("Bgm").Result)); - } - }, true); foreach (ref readonly var listener in global.World.Get()) { diff --git a/PataNext.Game/NotifyBgmManager.cs b/PataNext.Game/NotifyBgmManager.cs index 3a6d4519..e0d00bcc 100644 --- a/PataNext.Game/NotifyBgmManager.cs +++ b/PataNext.Game/NotifyBgmManager.cs @@ -2,7 +2,10 @@ using System.Collections.Generic; using System.IO; using GameHost.Core.Ecs; +using GameHost.Core.IO; +using GameHost.IO; using GameHost.Simulation.Application; +using System.Linq; using PataNext.Client.Systems; using PataNext.Game.BGM; @@ -18,24 +21,41 @@ public NotifyBgmManager(WorldCollection collection) : base(collection) DependencyResolver.Add(() => ref bgmStorage); } - private FileSystemWatcher watcher; + private List watchers; protected override void OnDependenciesResolved(IEnumerable dependencies) { base.OnDependenciesResolved(dependencies); - watcher = new FileSystemWatcher(bgmStorage.CurrentPath); - watcher.Filters.Add("*.zip"); - watcher.Filters.Add("*.json"); - watcher.NotifyFilter = NotifyFilters.LastWrite - | NotifyFilters.FileName - | NotifyFilters.CreationTime; - - watcher.Created += onChange; - watcher.Changed += onChange; - watcher.Deleted += onChange; - watcher.Renamed += onChange; - - watcher.EnableRaisingEvents = true; + watchers = new List(); + switch (bgmStorage.parent) + { + case LocalStorage localStorage: + watchers.Add(new FileSystemWatcher(localStorage.CurrentPath)); + break; + case StorageCollection collection: + { + foreach (var storage in collection) + if (storage is LocalStorage local) + watchers.Add(new FileSystemWatcher(local.CurrentPath)); + break; + } + } + + foreach (var watcher in watchers) + { + watcher.Filters.Add("*.zip"); + watcher.Filters.Add("*.json"); + watcher.NotifyFilter = NotifyFilters.LastWrite + | NotifyFilters.FileName + | NotifyFilters.CreationTime; + + watcher.Created += onChange; + watcher.Changed += onChange; + watcher.Deleted += onChange; + watcher.Renamed += onChange; + + watcher.EnableRaisingEvents = true; + } } private void onChange(object source, FileSystemEventArgs e) @@ -49,8 +69,13 @@ public override void Dispose() { base.Dispose(); - watcher.EnableRaisingEvents = false; - watcher.Dispose(); + foreach (var watcher in watchers) + { + watcher.EnableRaisingEvents = false; + watcher.Dispose(); + } + + watchers.Clear(); } } } \ No newline at end of file