diff --git a/BizHawk.Client.Common/CoreFileProvider.cs b/BizHawk.Client.Common/CoreFileProvider.cs index 80911fe4be..0a56502f40 100644 --- a/BizHawk.Client.Common/CoreFileProvider.cs +++ b/BizHawk.Client.Common/CoreFileProvider.cs @@ -32,6 +32,11 @@ namespace BizHawk.Client.Common return PathManager.SaveRamPath(Global.Game); } + public string GetGameBasePath() + { + return PathManager.GetGameBasePath(Global.Game); + } + #region EmuLoadHelper api private void FirmwareWarn(string sysID, string firmwareID, bool required, string msg = null) diff --git a/BizHawk.Client.Common/PathManager.cs b/BizHawk.Client.Common/PathManager.cs index 11d1df49d9..008b4f841c 100644 --- a/BizHawk.Client.Common/PathManager.cs +++ b/BizHawk.Client.Common/PathManager.cs @@ -259,9 +259,6 @@ namespace BizHawk.Client.Common var filesystemSafeName = game.Name.Replace("|", "+"); // zero 06-nov-2015 - regarding the below, i changed my mind. for libretro i want subdirectories here. - //var parts = filesystemSafeName.Split(System.IO.Path.PathSeparator); - //var dirParts = new string[parts.Length - 1]; - //Array.Copy(parts, dirParts, dirParts.Length); var filesystemDir = Path.GetDirectoryName(filesystemSafeName); filesystemSafeName = Path.GetFileName(filesystemSafeName); @@ -295,6 +292,14 @@ namespace BizHawk.Client.Common return Path.Combine(MakeAbsolutePath(pathEntry.Path, game.System), name) + ".SaveRAM"; } + public static string GetGameBasePath(GameInfo game) + { + var name = FilesystemSafeName(game); + + var pathEntry = Global.Config.PathEntries[game.System, "Base"]; + return MakeAbsolutePath(pathEntry.Path, game.System); + } + public static string GetSaveStatePath(GameInfo game) { var pathEntry = Global.Config.PathEntries[game.System, "Savestates"] ?? diff --git a/BizHawk.Client.Common/RomLoader.cs b/BizHawk.Client.Common/RomLoader.cs index 115897c67b..bba8d5402e 100644 --- a/BizHawk.Client.Common/RomLoader.cs +++ b/BizHawk.Client.Common/RomLoader.cs @@ -181,6 +181,35 @@ namespace BizHawk.Client.Common public bool AsLibretro; + bool HandleArchiveBinding(HawkFile file) + { + var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC", "GBA" }; + + // try binding normal rom extensions first + if (!file.IsBound) + { + file.BindSoleItemOf(romExtensions); + } + + // if we have an archive and need to bind something, then pop the dialog + if (file.IsArchive && !file.IsBound) + { + int? result = HandleArchive(file); + if (result.HasValue) + { + file.BindArchiveMember(result.Value); + } + else + { + return false; + } + } + + CanonicalFullPath = file.CanonicalFullPath; + + return true; + } + public bool LoadRom(string path, CoreComm nextComm, bool forceAccurateCore = false, int recursiveCount = 0) // forceAccurateCore is currently just for Quicknes vs Neshawk but could be used for other situations { @@ -199,7 +228,6 @@ namespace BizHawk.Client.Common using (var file = new HawkFile()) { - var romExtensions = new[] { "SMS", "SMC", "SFC", "PCE", "SGX", "GG", "SG", "BIN", "GEN", "MD", "SMD", "GB", "NES", "FDS", "ROM", "INT", "GBC", "UNF", "A78", "CRT", "COL", "XML", "Z64", "V64", "N64", "WS", "WSC", "GBA" }; //only try mounting a file if a filename was given if (!string.IsNullOrEmpty(path)) @@ -213,31 +241,10 @@ namespace BizHawk.Client.Common { return false; } - - // try binding normal rom extensions first - if (!file.IsBound) - { - file.BindSoleItemOf(romExtensions); - } - - // if we have an archive and need to bind something, then pop the dialog - if (file.IsArchive && !file.IsBound) - { - int? result = HandleArchive(file); - if (result.HasValue) - { - file.BindArchiveMember(result.Value); - } - else - { - return false; - } - } - - // set this here so we can see what file we tried to load even if an error occurs - CanonicalFullPath = file.CanonicalFullPath; } + CanonicalFullPath = file.CanonicalFullPath; + IEmulator nextEmulator = null; RomGame rom = null; GameInfo game = null; @@ -291,7 +298,11 @@ namespace BizHawk.Client.Common if (retro.system_info.need_fullpath) ret = retro.LoadPath(file.FullPathWithoutMember); else - ret = retro.LoadData(file.ReadAllBytes()); + { + ret = HandleArchiveBinding(file); + if (ret) + ret = retro.LoadData(file.ReadAllBytes()); + } if (!ret) { @@ -311,8 +322,14 @@ namespace BizHawk.Client.Common } else { - //if not libretro, do extension checknig + //if not libretro: + + //do extension checknig ext = file.Extension.ToLowerInvariant(); + + //do the archive binding we had to skip + if (!HandleArchiveBinding(file)) + return false; } if (string.IsNullOrEmpty(ext)) { } diff --git a/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs b/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs index 6a28a27545..75f2c4074c 100644 --- a/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs +++ b/BizHawk.Emulation.Common/Interfaces/ICoreFileProvider.cs @@ -22,6 +22,8 @@ namespace BizHawk.Emulation.Common /// string GetSaveRAMPath(); + string GetGameBasePath(); + #region EmuLoadHelper api diff --git a/BizHawk.Emulation.Cores/LibRetroEmulator.cs b/BizHawk.Emulation.Cores/LibRetroEmulator.cs index 3698bb21ea..5e4e181787 100644 --- a/BizHawk.Emulation.Cores/LibRetroEmulator.cs +++ b/BizHawk.Emulation.Cores/LibRetroEmulator.cs @@ -92,6 +92,7 @@ namespace BizHawk.Emulation.Cores unsafe bool retro_environment(LibRetro.RETRO_ENVIRONMENT cmd, IntPtr data) { + Console.WriteLine(cmd); switch (cmd) { case LibRetro.RETRO_ENVIRONMENT.SET_ROTATION: @@ -113,6 +114,9 @@ namespace BizHawk.Emulation.Cores case LibRetro.RETRO_ENVIRONMENT.SET_PERFORMANCE_LEVEL: return false; case LibRetro.RETRO_ENVIRONMENT.GET_SYSTEM_DIRECTORY: + //an alternative (alongside where the saverams and such will go?) + //*((IntPtr*)data.ToPointer()) = unmanagedResources.StringToHGlobalAnsi(CoreComm.CoreFileProvider.GetGameBasePath()); + *((IntPtr*)data.ToPointer()) = SystemDirectoryAtom; return false; case LibRetro.RETRO_ENVIRONMENT.SET_PIXEL_FORMAT: { @@ -143,8 +147,28 @@ namespace BizHawk.Emulation.Cores // this can be done in principle, but there's no reason to right now return false; case LibRetro.RETRO_ENVIRONMENT.GET_VARIABLE: + { + void** variables = (void**)data.ToPointer(); + IntPtr pKey = new IntPtr(*variables++); + string key = Marshal.PtrToStringAnsi(pKey); + Console.WriteLine("Requesting variable: {0}", key); + *variables = unmanagedResources.StringToHGlobalAnsi("0").ToPointer(); + } return false; case LibRetro.RETRO_ENVIRONMENT.SET_VARIABLES: + { + void** variables = (void**)data.ToPointer(); + for (; ; ) + { + IntPtr pKey = new IntPtr(*variables++); + IntPtr pValue = new IntPtr(*variables++); + if(pKey == IntPtr.Zero) + break; + string key = Marshal.PtrToStringAnsi(pKey); + string value = Marshal.PtrToStringAnsi(pValue); + Console.WriteLine("Defined variable: {0} = {1}", key, value); + } + } return false; case LibRetro.RETRO_ENVIRONMENT.GET_VARIABLE_UPDATE: return false; @@ -174,6 +198,8 @@ namespace BizHawk.Emulation.Cores //unmanagedResources and CoreFileProvider *((IntPtr*)data.ToPointer()) = IntPtr.Zero; return false; + case LibRetro.RETRO_ENVIRONMENT.SET_CONTROLLER_INFO: + return true; default: Console.WriteLine("Unknkown retro_environment command {0}", (int)cmd); return false; @@ -253,9 +279,16 @@ namespace BizHawk.Emulation.Cores } public RetroEnvironmentInfo EnvironmentInfo = new RetroEnvironmentInfo(); + string CoresDirectory; + string SystemDirectory; + IntPtr SystemDirectoryAtom; public LibRetroEmulator(CoreComm nextComm, string modulename) { + CoresDirectory = Path.GetDirectoryName(new FileInfo(modulename).FullName); + SystemDirectory = Path.Combine(CoresDirectory, "System"); + SystemDirectoryAtom = unmanagedResources.StringToHGlobalAnsi(SystemDirectory); + ServiceProvider = new BasicServiceProvider(this); _SyncSettings = new SyncSettings(); @@ -371,7 +404,6 @@ namespace BizHawk.Emulation.Cores public void FrameAdvance(bool render, bool rendersound = true) { //TODO - consider changing directory and using Libretro subdir of bizhawk as a kind of sandbox, for the duration of the run? - CloneSaveRam(); IsLagFrame = true; Frame++; nsamprecv = 0; @@ -476,11 +508,16 @@ namespace BizHawk.Emulation.Cores public void SaveStateBinary(System.IO.BinaryWriter writer) { - fixed (byte* ptr = &savebuff[0]) + //is this the only way we know of to detect unavailable savestates? + if (savebuff.Length > 0) { - if (!retro.retro_serialize((IntPtr)ptr, (uint)savebuff.Length)) - throw new Exception("retro_serialize() failed"); + fixed (byte* ptr = &savebuff[0]) + { + if (!retro.retro_serialize((IntPtr)ptr, (uint)savebuff.Length)) + throw new Exception("retro_serialize() failed"); + } } + writer.Write(savebuff.Length); writer.Write(savebuff); // other variables @@ -495,10 +532,13 @@ namespace BizHawk.Emulation.Cores if (newlen > savebuff.Length) throw new Exception("Unexpected buffer size"); reader.Read(savebuff, 0, newlen); - fixed (byte* ptr = &savebuff[0]) + if (savebuff.Length > 0) { - if (!retro.retro_unserialize((IntPtr)ptr, (uint)newlen)) - throw new Exception("retro_unserialize() failed"); + fixed (byte* ptr = &savebuff[0]) + { + if (!retro.retro_unserialize((IntPtr)ptr, (uint)newlen)) + throw new Exception("retro_unserialize() failed"); + } } // other variables Frame = reader.ReadInt32(); @@ -699,7 +739,9 @@ namespace BizHawk.Emulation.Cores { get { - if (dar > 1.0f) + if(dar==0) + return BufferWidth; + else if (dar > 1.0f) return (int)(BufferHeight * dar); else return BufferWidth; @@ -709,6 +751,8 @@ namespace BizHawk.Emulation.Cores { get { + if(dar==0) + return BufferHeight; if (dar < 1.0f) return (int)(BufferWidth / dar); else