Пример #1
0
        // inits only to get settings info
        // should only ever be called if no SettingsInfo cache exists statically within the core
        protected void InitForSettingsInfo(string wbxFilename)
        {
            _nyma = PreInit <LibNymaCore>(NymaWaterboxOptions(wbxFilename));

            using (_exe.EnterExit())
            {
                _nyma.PreInit();
                var portData = GetInputPortsData();
                InitAllSettingsInfo(portData);
            }
        }
Пример #2
0
        protected T DoInit <T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension, bool deterministic,
                               IDictionary <string, FirmwareID> firmwares = null)
            where T : LibNymaCore
        {
            _settingsQueryDelegate = SettingsQuery;
            _cdTocCallback         = CDTOCCallback;
            _cdSectorCallback      = CDSectorCallback;

            var filesToRemove = new List <string>();

            var firmwareDelegate = new LibNymaCore.FrontendFirmwareNotify((name) =>
            {
                if (firmwares != null && firmwares.TryGetValue(name, out var id))
                {
                    var data = CoreComm.CoreFileProvider.GetFirmwareOrThrow(id, "Firmware files are usually required and may stop your game from loading");
                    _exe.AddReadonlyFile(data, name);
                    filesToRemove.Add(name);
                }
                else
                {
                    throw new InvalidOperationException($"Core asked for firmware `{name}`, but that was not understood by the system");
                }
            });

            var t = PreInit <T>(new WaterboxOptions
            {
                Filename = wbxFilename,
                // WaterboxHost only saves parts of memory that have changed, so not much to be gained by making these precisely sized
                SbrkHeapSizeKB             = 1024 * 16,
                SealedHeapSizeKB           = 1024 * 48,
                InvisibleHeapSizeKB        = 1024 * 48,
                PlainHeapSizeKB            = 1024 * 48,
                MmapHeapSizeKB             = 1024 * 48,
                SkipCoreConsistencyCheck   = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
                SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
            }, new Delegate[] { _settingsQueryDelegate, _cdTocCallback, _cdSectorCallback, firmwareDelegate });

            _nyma = t;

            using (_exe.EnterExit())
            {
                _nyma.PreInit();
                _nyma.SetFrontendFirmwareNotify(firmwareDelegate);
                var portData = GetInputPortsData();
                InitAllSettingsInfo(portData);
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);

                if (discs?.Length > 0)
                {
                    _disks       = discs;
                    _diskReaders = _disks.Select(d => new DiscSectorReader(d)
                    {
                        Policy = _diskPolicy
                    }).ToArray();
                    _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                    var didInit = _nyma.InitCd(_disks.Length);
                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the CDs!");
                    }
                }
                else
                {
                    var fn = game.FilesystemSafeName();
                    _exe.AddReadonlyFile(rom, fn);

                    var didInit = _nyma.InitRom(new LibNymaCore.InitData
                    {
                        // TODO: Set these as some cores need them
                        FileNameBase = "",
                        FileNameExt  = extension.Trim('.').ToLowerInvariant(),
                        FileNameFull = fn
                    });

                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the rom!");
                    }

                    _exe.RemoveReadonlyFile(fn);
                }

                foreach (var s in filesToRemove)
                {
                    _exe.RemoveReadonlyFile(s);
                }
                // any later attempts to request a firmware will crash
                _nyma.SetFrontendFirmwareNotify(null);

                var info = *_nyma.GetSystemInfo();
                _videoBuffer       = new int[Math.Max(info.MaxWidth * info.MaxHeight, info.LcmWidth * info.LcmHeight)];
                BufferWidth        = info.NominalWidth;
                BufferHeight       = info.NominalHeight;
                _mdfnNominalWidth  = info.NominalWidth;
                _mdfnNominalHeight = info.NominalHeight;
                switch (info.VideoSystem)
                {
                // TODO: There seriously isn't any region besides these?
                case LibNymaCore.VideoSystem.PAL:
                case LibNymaCore.VideoSystem.SECAM:
                    Region = DisplayType.PAL;
                    break;

                case LibNymaCore.VideoSystem.PAL_M:
                    Region = DisplayType.Dendy;                             // sort of...
                    break;

                default:
                    Region = DisplayType.NTSC;
                    break;
                }
                VsyncNumerator   = info.FpsFixed;
                VsyncDenominator = 1 << 24;
                _soundBuffer     = new short[22050 * 2];

                InitControls(portData, discs?.Length > 0, ref info);
                PostInit();
                SettingsInfo.LayerNames = GetLayerData();
                _settings.Normalize(SettingsInfo);
                _syncSettings.Normalize(SettingsInfo);
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
                if (_disks != null)
                {
                    _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                }
                PutSettings(_settings);
                DateTime RtcStart = DateTime.Parse("2010-01-01");
                try
                {
                    RtcStart = DateTime.Parse(SettingsQuery("nyma.rtcinitialtime"));
                }
                catch
                {
                    Console.Error.WriteLine($"Couldn't parse DateTime \"{SettingsQuery("nyma.rtcinitialtime")}\"");
                }
                // Don't optimistically set deterministic, as some cores like faust can change this
                DeterministicEmulation = deterministic;                 // || SettingsQuery("nyma.rtcrealtime") == "0";
                InitializeRtc(RtcStart);
                _frameThreadPtr = _nyma.GetFrameThreadProc();
                if (_frameThreadPtr != IntPtr.Zero)
                {
                    // This will probably be fine, right?  TODO: Revisit
                    // if (deterministic)
                    //  throw new InvalidOperationException("Internal error: Core set a frame thread proc in deterministic mode");
                    Console.WriteLine($"Setting up waterbox thread for {_frameThreadPtr}");
                    _frameThreadStart = CallingConventionAdapters.GetWaterboxUnsafeUnwrapped().GetDelegateForFunctionPointer <Action>(_frameThreadPtr);
                }
            }

            return(t);
        }
Пример #3
0
            public ControllerAdapter(LibNymaCore core, IList <string> config)
            {
                var ret = new ControllerDefinition
                {
                    Name = "Mednafen Controller"
                };

                var finalDevices = new List <string>();

                var numPorts = core.GetNumPorts();

                if (numPorts > MAX_PORTS)
                {
                    throw new InvalidOperationException($"Too many input ports");
                }
                for (uint port = 0, devByteStart = 0; port < numPorts; port++, devByteStart += MAX_PORT_DATA)
                {
                    var portInfo   = *core.GetPort(port);
                    var deviceName = port < config.Count ? config[(int)port] : portInfo.DefaultDeviceShortName;
                    finalDevices.Add(deviceName);

                    var devices = Enumerable.Range(0, (int)portInfo.NumDevices)
                                  .Select(i => new { Index = (uint)i, Device = *core.GetDevice(port, (uint)i) })
                                  .ToList();

                    var device = devices.FirstOrDefault(a => a.Device.ShortName == deviceName);
                    if (device == null)
                    {
                        Console.WriteLine($"Warn: unknown controller device {deviceName}");
                        device = devices.FirstOrDefault(a => a.Device.ShortName == portInfo.DefaultDeviceShortName);
                        if (device == null)
                        {
                            throw new InvalidOperationException($"Fail: unknown controller device {portInfo.DefaultDeviceShortName}");
                        }
                    }

                    var deviceInfo = device.Device;
                    if (deviceInfo.ByteLength > MAX_PORT_DATA)
                    {
                        throw new InvalidOperationException($"Input device {deviceInfo.ShortName} uses more than {MAX_PORT_DATA} bytes");
                    }
                    var category = portInfo.FullName + " - " + deviceInfo.FullName;

                    var inputs = Enumerable.Range(0, (int)deviceInfo.NumInputs)
                                 .Select(i => new { Index = i, Data = *core.GetInput(port, device.Index, (uint)i) })
                                 .OrderBy(a => a.Data.ConfigOrder);

                    foreach (var input in inputs)
                    {
                        var inputInfo = input.Data;
                        var bitSize   = (int)inputInfo.BitSize;
                        var bitOffset = (int)inputInfo.BitOffset;
                        var byteStart = devByteStart + bitOffset / 8;
                        bitOffset %= 8;
                        var name = $"P{port + 1} {inputInfo.Name}";
                        switch (inputInfo.Type)
                        {
                        case LibNymaCore.InputType.PADDING:
                        {
                            break;
                        }

                        case LibNymaCore.InputType.BUTTON:
                        case LibNymaCore.InputType.BUTTON_CAN_RAPID:
                        {
                            // var data = *core.GetButton(port, device.Index, (uint)input.Index);
                            // TODO: Wire up data.ExcludeName
                            ret.BoolButtons.Add(name);
                            _thunks.Add((c, b) =>
                                {
                                    if (c.IsPressed(name))
                                    {
                                        b[byteStart] |= (byte)(1 << bitOffset);
                                    }
                                });
                            break;
                        }

                        case LibNymaCore.InputType.SWITCH:
                        {
                            var data    = *core.GetSwitch(port, device.Index, (uint)input.Index);
                            var zzhacky = (int)data.DefaultPosition;
                            // TODO: Possibly bulebutton for 2 states?
                            ret.AxisControls.Add(name);
                            ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
                                                   0, (int)data.DefaultPosition, (int)data.NumPositions - 1));
                            _thunks.Add((c, b) =>
                                {
                                    // HACK: Silently discard this until bizhawk fixes its shit
                                    // var val = (int)Math.Round(c.AxisValue(name));
                                    var val       = zzhacky;
                                    b[byteStart] |= (byte)(val << bitOffset);
                                });
                            break;
                        }

                        case LibNymaCore.InputType.AXIS:
                        {
                            // var data = core.GetAxis(port, device.Index, (uint)input.Index);
                            ret.AxisControls.Add(name);
                            ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
                                                   0, 0x8000, 0xffff, (inputInfo.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0
                                                   ));
                            _thunks.Add((c, b) =>
                                {
                                    var val          = (ushort)Math.Round(c.AxisValue(name));
                                    b[byteStart]     = (byte)val;
                                    b[byteStart + 1] = (byte)(val >> 8);
                                });
                            break;
                        }

                        case LibNymaCore.InputType.AXIS_REL:
                        {
                            // var data = core.GetAxis(port, device.Index, (uint)input.Index);
                            ret.AxisControls.Add(name);
                            ret.AxisRanges.Add(new ControllerDefinition.AxisRange(
                                                   -0x8000, 0, 0x7fff, (inputInfo.Flags & LibNymaCore.AxisFlags.INVERT_CO) != 0
                                                   ));
                            _thunks.Add((c, b) =>
                                {
                                    var val          = (short)Math.Round(c.AxisValue(name));
                                    b[byteStart]     = (byte)val;
                                    b[byteStart + 1] = (byte)(val >> 8);
                                });
                            break;
                        }

                        case LibNymaCore.InputType.POINTER_X:
                        {
                            throw new Exception("TODO: Axis ranges are ints????");
                            // ret.AxisControls.Add(name);
                            // ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1));
                            // break;
                        }

                        case LibNymaCore.InputType.POINTER_Y:
                        {
                            throw new Exception("TODO: Axis ranges are ints????");
                            // ret.AxisControls.Add(name);
                            // ret.AxisRanges.Add(new ControllerDefinition.AxisRange(0, 0.5, 1, true));
                            // break;
                        }

                        // TODO: wire up statuses to something (not controller, of course)
                        default:
                            throw new NotImplementedException($"Unimplemented button type {inputInfo.Type}");
                        }
                        ret.CategoryLabels[name] = category;
                    }
                }
                Definition = ret;
                finalDevices.Add(null);
                Devices = finalDevices.ToArray();
            }
Пример #4
0
        protected T DoInit <T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension, bool deterministic,
                               ICollection <KeyValuePair <string, byte[]> > firmwares = null)
            where T : LibNymaCore
        {
            var t = PreInit <T>(new WaterboxOptions
            {
                Filename = wbxFilename,
                // MemoryBlock understands reserve vs commit semantics, so nothing to be gained by making these precisely sized
                SbrkHeapSizeKB             = 1024 * 16,
                SealedHeapSizeKB           = 1024 * 48,
                InvisibleHeapSizeKB        = 1024 * 48,
                PlainHeapSizeKB            = 1024 * 48,
                MmapHeapSizeKB             = 1024 * 48,
                SkipCoreConsistencyCheck   = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
                SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
            });

            _nyma = t;
            _settingsQueryDelegate = new LibNymaCore.FrontendSettingQuery(SettingsQuery);

            using (_exe.EnterExit())
            {
                _nyma.PreInit();
                var portData = GetInputPortsData();
                InitSyncSettingsInfo(portData);
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
                if (firmwares != null)
                {
                    foreach (var kvp in firmwares)
                    {
                        _exe.AddReadonlyFile(kvp.Value, kvp.Key);
                    }
                }
                if (discs?.Length > 0)
                {
                    _disks       = discs;
                    _diskReaders = _disks.Select(d => new DiscSectorReader(d)
                    {
                        Policy = _diskPolicy
                    }).ToArray();
                    _cdTocCallback    = CDTOCCallback;
                    _cdSectorCallback = CDSectorCallback;
                    _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                    var didInit = _nyma.InitCd(_disks.Length);
                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the CDs!");
                    }
                }
                else
                {
                    var fn = game.FilesystemSafeName();
                    _exe.AddReadonlyFile(rom, fn);

                    var didInit = _nyma.InitRom(new LibNymaCore.InitData
                    {
                        // TODO: Set these as some cores need them
                        FileNameBase = "",
                        FileNameExt  = extension.Trim('.').ToLowerInvariant(),
                        FileNameFull = fn
                    });

                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the rom!");
                    }

                    _exe.RemoveReadonlyFile(fn);
                }
                if (firmwares != null)
                {
                    foreach (var kvp in firmwares)
                    {
                        _exe.RemoveReadonlyFile(kvp.Key);
                    }
                }

                var info = *_nyma.GetSystemInfo();
                _videoBuffer = new int[info.MaxWidth * info.MaxHeight];
                BufferWidth  = info.NominalWidth;
                BufferHeight = info.NominalHeight;
                switch (info.VideoSystem)
                {
                // TODO: There seriously isn't any region besides these?
                case LibNymaCore.VideoSystem.PAL:
                case LibNymaCore.VideoSystem.SECAM:
                    Region = DisplayType.PAL;
                    break;

                case LibNymaCore.VideoSystem.PAL_M:
                    Region = DisplayType.Dendy;                             // sort of...
                    break;

                default:
                    Region = DisplayType.NTSC;
                    break;
                }
                VsyncNumerator   = info.FpsFixed;
                VsyncDenominator = 1 << 24;
                _soundBuffer     = new short[22050 * 2];

                InitControls(portData);
                _nyma.SetFrontendSettingQuery(null);
                if (_disks != null)
                {
                    _nyma.SetCDCallbacks(null, null);
                }
                PostInit();
                SettingsInfo.LayerNames = GetLayerData();
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
                if (_disks != null)
                {
                    _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                }
                PutSettings(_settings);
                DateTime RtcStart = DateTime.Parse("2010-01-01");
                try
                {
                    RtcStart = DateTime.Parse(SettingsQuery("nyma.rtcinitialtime"));
                }
                catch
                {
                    Console.Error.WriteLine($"Couldn't parse DateTime \"{SettingsQuery("nyma.rtcinitialtime")}\"");
                }
                // Don't optimistically set deterministic, as some cores like faust can change this
                DeterministicEmulation = deterministic;                 // || SettingsQuery("nyma.rtcrealtime") == "0";
                InitializeRtc(RtcStart);
                _frameThreadPtr = _nyma.GetFrameThreadProc();
                if (_frameThreadPtr != IntPtr.Zero)
                {
                    if (deterministic)
                    {
                        throw new InvalidOperationException("Internal error: Core set a frame thread proc in deterministic mode");
                    }
                    Console.WriteLine($"Setting up waterbox thread for {_frameThreadPtr}");
                    _frameThreadStart = CallingConventionAdapters.Waterbox.GetDelegateForFunctionPointer <Action>(_frameThreadPtr);
                }
            }

            return(t);
        }
Пример #5
0
        protected T DoInit <T>(GameInfo game, byte[] rom, Disc[] discs, string wbxFilename, string extension,
                               ICollection <KeyValuePair <string, byte[]> > firmwares = null)
            where T : LibNymaCore
        {
            var t = PreInit <T>(new WaterboxOptions
            {
                // TODO fix these up
                Filename                   = wbxFilename,
                SbrkHeapSizeKB             = 1024 * 16,
                SealedHeapSizeKB           = 1024 * 16,
                InvisibleHeapSizeKB        = 1024 * 16,
                PlainHeapSizeKB            = 1024 * 16,
                MmapHeapSizeKB             = 1024 * 16,
                SkipCoreConsistencyCheck   = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxCoreConsistencyCheck),
                SkipMemoryConsistencyCheck = CoreComm.CorePreferences.HasFlag(CoreComm.CorePreferencesFlags.WaterboxMemoryConsistencyCheck),
            });

            _nyma = t;
            _settingsQueryDelegate = new LibNymaCore.FrontendSettingQuery(SettingsQuery);

            using (_exe.EnterExit())
            {
                _nyma.PreInit();
                InitSyncSettingsInfo();
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
                if (firmwares != null)
                {
                    foreach (var kvp in firmwares)
                    {
                        _exe.AddReadonlyFile(kvp.Value, kvp.Key);
                    }
                }
                if (discs?.Length > 0)
                {
                    _disks       = discs;
                    _diskReaders = _disks.Select(d => new DiscSectorReader(d)
                    {
                        Policy = _diskPolicy
                    }).ToArray();
                    _cdTocCallback    = CDTOCCallback;
                    _cdSectorCallback = CDSectorCallback;
                    _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                    var didInit = _nyma.InitCd(_disks.Length);
                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the CDs!");
                    }
                }
                else
                {
                    var fn = game.FilesystemSafeName();
                    _exe.AddReadonlyFile(rom, fn);

                    var didInit = _nyma.InitRom(new LibNymaCore.InitData
                    {
                        // TODO: Set these as some cores need them
                        FileNameBase = "",
                        FileNameExt  = extension.Trim('.').ToLowerInvariant(),
                        FileNameFull = fn
                    });

                    if (!didInit)
                    {
                        throw new InvalidOperationException("Core rejected the rom!");
                    }

                    _exe.RemoveReadonlyFile(fn);
                }
                if (firmwares != null)
                {
                    foreach (var kvp in firmwares)
                    {
                        _exe.RemoveReadonlyFile(kvp.Key);
                    }
                }

                var info = *_nyma.GetSystemInfo();
                _videoBuffer = new int[info.MaxWidth * info.MaxHeight];
                BufferWidth  = info.NominalWidth;
                BufferHeight = info.NominalHeight;
                switch (info.VideoSystem)
                {
                // TODO: There seriously isn't any region besides these?
                case LibNymaCore.VideoSystem.PAL:
                case LibNymaCore.VideoSystem.SECAM:
                    Region = DisplayType.PAL;
                    break;

                case LibNymaCore.VideoSystem.PAL_M:
                    Region = DisplayType.Dendy;                             // sort of...
                    break;

                default:
                    Region = DisplayType.NTSC;
                    break;
                }
                VsyncNumerator   = info.FpsFixed;
                VsyncDenominator = 1 << 24;
                _soundBuffer     = new short[22050 * 2];

                InitControls();
                _nyma.SetFrontendSettingQuery(null);
                _nyma.SetCDCallbacks(null, null);
                PostInit();
                SettingsInfo.LayerNames = GetLayerData();
                _nyma.SetFrontendSettingQuery(_settingsQueryDelegate);
                _nyma.SetCDCallbacks(_cdTocCallback, _cdSectorCallback);
                PutSettings(_settings);
            }

            return(t);
        }