From 0aedb3430c6ae53fdc7b1458a405894bc72c09c9 Mon Sep 17 00:00:00 2001 From: Tim Allen Date: Sat, 21 Jul 2018 21:49:48 +1000 Subject: [PATCH] Update to v106r51 release. byuu says: Changelog: - added `Emulator::Interface::connected(uint port) -> uint device;` - higan, bsnes: updated emulators to use the new Emulator::Interface::connected() function - hiro: fixed Object::cast finally So, Emulator::Interface::connected() solves two annoying problems at the same time. First, on first run of the emulator when the settings file is blank, it will retrieve the default "sane" device ID, which is usually a gamepad for a controller port, or nothing for an expansion/extension port. Second, if you were to select a multi-port device, like the NES Four Score, the core will set the other port to the Four Score device as well, and the GUIs query connected() right after any call to connect(), so it gets updated without needing a system for the emulation core to send messages alerting the GUI of changes. --- higan/emulator/emulator.hpp | 2 +- higan/emulator/interface.hpp | 1 + higan/fc/interface/interface.cpp | 7 ++ higan/fc/interface/interface.hpp | 7 +- higan/gb/system/system.cpp | 1 + higan/md/interface/interface.cpp | 7 ++ higan/md/interface/interface.hpp | 7 +- higan/ms/interface/interface.hpp | 1 - higan/pce/interface/interface.cpp | 5 + higan/pce/interface/interface.hpp | 3 +- higan/sfc/interface/interface.cpp | 7 ++ higan/sfc/interface/interface.hpp | 7 +- .../presentation/presentation.cpp | 91 ++++++++++++------- .../presentation/presentation.hpp | 2 + higan/target-bsnes/program/game.cpp | 1 - higan/target-bsnes/program/input.cpp | 13 --- higan/target-bsnes/program/program.hpp | 1 - .../presentation/presentation.cpp | 91 +++++++++++++------ .../presentation/presentation.hpp | 3 +- higan/target-higan/program/medium.cpp | 6 +- higan/target-higan/program/program.hpp | 1 - higan/target-higan/program/utility.cpp | 14 --- hiro/core/shared.hpp | 13 ++- 23 files changed, 181 insertions(+), 110 deletions(-) diff --git a/higan/emulator/emulator.hpp b/higan/emulator/emulator.hpp index 7b6083da..7ab0b575 100644 --- a/higan/emulator/emulator.hpp +++ b/higan/emulator/emulator.hpp @@ -13,7 +13,7 @@ using namespace nall; namespace Emulator { static const string Name = "higan"; - static const string Version = "106.50"; + static const string Version = "106.51"; static const string Author = "byuu"; static const string License = "GPLv3"; static const string Website = "https://byuu.org/"; diff --git a/higan/emulator/interface.hpp b/higan/emulator/interface.hpp index c5ef8073..bdde0888 100644 --- a/higan/emulator/interface.hpp +++ b/higan/emulator/interface.hpp @@ -58,6 +58,7 @@ struct Interface { virtual auto unload() -> void {} //system interface + virtual auto connected(uint port) -> uint { return 0; } virtual auto connect(uint port, uint device) -> void {} virtual auto power() -> void {} virtual auto reset() -> void {} diff --git a/higan/fc/interface/interface.cpp b/higan/fc/interface/interface.cpp index 2e49241d..36d9ed0e 100644 --- a/higan/fc/interface/interface.cpp +++ b/higan/fc/interface/interface.cpp @@ -132,6 +132,13 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller1) return settings.controllerPort1; + if(port == ID::Port::Controller2) return settings.controllerPort2; + if(port == ID::Port::Expansion) return settings.expansionPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); diff --git a/higan/fc/interface/interface.hpp b/higan/fc/interface/interface.hpp index 9478783f..a184a8c1 100644 --- a/higan/fc/interface/interface.hpp +++ b/higan/fc/interface/interface.hpp @@ -36,6 +36,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto reset() -> void override; @@ -55,9 +56,9 @@ struct Settings { bool colorEmulation = true; bool scanlineEmulation = true; - uint controllerPort1 = 0; - uint controllerPort2 = 0; - uint expansionPort = 0; + uint controllerPort1 = ID::Device::Gamepad; + uint controllerPort2 = ID::Device::Gamepad; + uint expansionPort = ID::Device::None; }; extern Settings settings; diff --git a/higan/gb/system/system.cpp b/higan/gb/system/system.cpp index 8b0996c2..5a90a522 100644 --- a/higan/gb/system/system.cpp +++ b/higan/gb/system/system.cpp @@ -85,6 +85,7 @@ auto System::power() -> void { Emulator::video.reset(interface); Emulator::video.setPalette(); Emulator::video.setEffect(Emulator::Video::Effect::InterframeBlending, settings.blurEmulation); + Emulator::audio.reset(interface); } diff --git a/higan/md/interface/interface.cpp b/higan/md/interface/interface.cpp index 7e7f74d6..cba5cb22 100644 --- a/higan/md/interface/interface.cpp +++ b/higan/md/interface/interface.cpp @@ -116,6 +116,13 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller1) return settings.controllerPort1; + if(port == ID::Port::Controller2) return settings.controllerPort2; + if(port == ID::Port::Extension) return settings.extensionPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); diff --git a/higan/md/interface/interface.hpp b/higan/md/interface/interface.hpp index 75547e11..46d9679b 100644 --- a/higan/md/interface/interface.hpp +++ b/higan/md/interface/interface.hpp @@ -36,6 +36,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto reset() -> void override; @@ -52,9 +53,9 @@ struct Interface : Emulator::Interface { }; struct Settings { - uint controllerPort1 = 0; - uint controllerPort2 = 0; - uint extensionPort = 0; + uint controllerPort1 = ID::Device::ControlPad; + uint controllerPort2 = ID::Device::ControlPad; + uint extensionPort = ID::Device::None; }; extern Settings settings; diff --git a/higan/ms/interface/interface.hpp b/higan/ms/interface/interface.hpp index 54473267..6e20cc66 100644 --- a/higan/ms/interface/interface.hpp +++ b/higan/ms/interface/interface.hpp @@ -31,7 +31,6 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; - auto connect(uint port, uint device) -> void override {} auto power() -> void override; auto run() -> void override; diff --git a/higan/pce/interface/interface.cpp b/higan/pce/interface/interface.cpp index 092b9dc9..1b72600b 100644 --- a/higan/pce/interface/interface.cpp +++ b/higan/pce/interface/interface.cpp @@ -83,6 +83,11 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller) return settings.controllerPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller) controllerPort.connect(settings.controllerPort = device); } diff --git a/higan/pce/interface/interface.hpp b/higan/pce/interface/interface.hpp index 0e79f304..27e7f999 100644 --- a/higan/pce/interface/interface.hpp +++ b/higan/pce/interface/interface.hpp @@ -32,6 +32,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto run() -> void override; @@ -59,7 +60,7 @@ struct SuperGrafxInterface : Interface { }; struct Settings { - uint controllerPort = 0; + uint controllerPort = ID::Device::Gamepad; }; extern Settings settings; diff --git a/higan/sfc/interface/interface.cpp b/higan/sfc/interface/interface.cpp index 98b5236a..49138dcd 100644 --- a/higan/sfc/interface/interface.cpp +++ b/higan/sfc/interface/interface.cpp @@ -186,6 +186,13 @@ auto Interface::unload() -> void { system.unload(); } +auto Interface::connected(uint port) -> uint { + if(port == ID::Port::Controller1) return settings.controllerPort1; + if(port == ID::Port::Controller2) return settings.controllerPort2; + if(port == ID::Port::Expansion) return settings.expansionPort; + return 0; +} + auto Interface::connect(uint port, uint device) -> void { if(port == ID::Port::Controller1) controllerPort1.connect(settings.controllerPort1 = device); if(port == ID::Port::Controller2) controllerPort2.connect(settings.controllerPort2 = device); diff --git a/higan/sfc/interface/interface.hpp b/higan/sfc/interface/interface.hpp index 6a56921e..6b59e4e7 100644 --- a/higan/sfc/interface/interface.hpp +++ b/higan/sfc/interface/interface.hpp @@ -48,6 +48,7 @@ struct Interface : Emulator::Interface { auto save() -> void override; auto unload() -> void override; + auto connected(uint port) -> uint override; auto connect(uint port, uint device) -> void override; auto power() -> void override; auto reset() -> void override; @@ -76,9 +77,9 @@ struct Settings { bool colorEmulation = true; bool scanlineEmulation = true; - uint controllerPort1 = 0; - uint controllerPort2 = 0; - uint expansionPort = 0; + uint controllerPort1 = ID::Device::Gamepad; + uint controllerPort2 = ID::Device::Gamepad; + uint expansionPort = ID::Device::None; bool random = true; }; diff --git a/higan/target-bsnes/presentation/presentation.cpp b/higan/target-bsnes/presentation/presentation.cpp index 53b8ee6d..5fd8d2f2 100644 --- a/higan/target-bsnes/presentation/presentation.cpp +++ b/higan/target-bsnes/presentation/presentation.cpp @@ -21,38 +21,7 @@ Presentation::Presentation() { controllerPort1.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 1")); controllerPort2.setIcon(Icon::Device::Joypad).setText(tr("Controller Port 2")); expansionPort.setIcon(Icon::Device::Storage).setText(tr("Expansion Port")); - for(auto& port : emulator->ports) { - Menu* menu = nullptr; - if(port.name == "Controller Port 1") menu = &controllerPort1; - if(port.name == "Controller Port 2") menu = &controllerPort2; - if(port.name == "Expansion Port") menu = &expansionPort; - if(!menu) continue; - - Group devices; - for(auto& device : port.devices) { - if(port.name != "Expansion Port" && device.name == "None") continue; - if(port.name == "Expansion Port" && device.name == "21fx") continue; - MenuRadioItem item{menu}; - item.setText(tr(device.name)).onActivate([=] { - auto path = string{"Emulator/", port.name}.replace(" ", ""); - settings(path).setValue(device.name); - emulator->connect(port.id, device.id); - }); - devices.append(item); - } - auto path = string{"Emulator/", port.name}.replace(" ", ""); - auto device = settings(path).text(); - bool found = false; - if(devices.objectCount() > 1) { - for(auto item : devices.objects()) { - if(item.text() == device) item.setChecked(), found = true; - } - } - //select the first device when a new settings file is being created - if(devices.objectCount() && !found) { - devices.objects()(0).doActivate(); - } - } + updateDeviceMenu(); quit.setIcon(Icon::Action::Quit).setText(tr("Quit")).onActivate([&] { program->quit(); }); settingsMenu.setText(tr("Settings")); @@ -372,6 +341,64 @@ auto Presentation::toggleFullscreenMode() -> void { } } +auto Presentation::updateDeviceMenu() -> void { + controllerPort1.reset(); + controllerPort2.reset(); + expansionPort.reset(); + + for(auto& port : emulator->ports) { + Menu* menu = nullptr; + if(port.name == "Controller Port 1") menu = &controllerPort1; + if(port.name == "Controller Port 2") menu = &controllerPort2; + if(port.name == "Expansion Port") menu = &expansionPort; + if(!menu) continue; + + auto path = string{"Emulator/", port.name}.replace(" ", ""); + auto deviceName = settings(path).text(); + auto deviceID = emulator->connected(port.id); + + Group devices; + for(auto& device : port.devices) { + if(port.name == "Expansion Port" && device.name == "21fx") continue; + + MenuRadioItem item{menu}; + item.setProperty("deviceID", device.id); + item.setText(tr(device.name)); + item.onActivate([=] { + settings(path).setValue(device.name); + emulator->connect(port.id, device.id); + updateDeviceSelections(); + }); + devices.append(item); + + if(deviceName == device.name) item.doActivate(); + if(!deviceName && deviceID == device.id) item.doActivate(); + } + } + + updateDeviceSelections(); +} + +auto Presentation::updateDeviceSelections() -> void { + for(auto& port : emulator->ports) { + Menu* menu = nullptr; + if(port.name == "Controller Port 1") menu = &controllerPort1; + if(port.name == "Controller Port 2") menu = &controllerPort2; + if(port.name == "Expansion Port") menu = &expansionPort; + if(!menu) continue; + + auto deviceID = emulator->connected(port.id); + for(auto& action : menu->actions()) { + if(auto item = action.cast()) { + if(item.property("deviceID").natural() == deviceID) { + item.setChecked(); + break; + } + } + } + } +} + //generate a list of size multipliers auto Presentation::updateSizeMenu() -> void { assert(sizeMenu.actions() == 0); //should only be called once diff --git a/higan/target-bsnes/presentation/presentation.hpp b/higan/target-bsnes/presentation/presentation.hpp index a0663923..9f90f924 100644 --- a/higan/target-bsnes/presentation/presentation.hpp +++ b/higan/target-bsnes/presentation/presentation.hpp @@ -33,6 +33,8 @@ struct Presentation : Window { auto resizeWindow() -> void; auto updateStatus() -> void; auto toggleFullscreenMode() -> void; + auto updateDeviceMenu() -> void; + auto updateDeviceSelections() -> void; auto updateSizeMenu() -> void; auto clearRecentGames() -> void; auto updateRecentGames() -> void; diff --git a/higan/target-bsnes/program/game.cpp b/higan/target-bsnes/program/game.cpp index 94ad89a8..68dc4522 100644 --- a/higan/target-bsnes/program/game.cpp +++ b/higan/target-bsnes/program/game.cpp @@ -18,7 +18,6 @@ auto Program::load() -> void { return showMessage("Game loading cancelled"); } } - updateInputDevices(); hackCompatibility(); emulator->power(); if(settingsWindow->advanced.autoLoadStateOnLoad.checked()) { diff --git a/higan/target-bsnes/program/input.cpp b/higan/target-bsnes/program/input.cpp index 78f9c30b..260c011b 100644 --- a/higan/target-bsnes/program/input.cpp +++ b/higan/target-bsnes/program/input.cpp @@ -15,16 +15,3 @@ auto Program::updateInputDriver() -> void { return updateInputDriver(); } } - -auto Program::updateInputDevices() -> void { - for(auto& port : emulator->ports) { - auto path = string{"Emulator/", port.name}.replace(" ", ""); - auto name = settings(path).text(); - for(auto& device : port.devices) { - if(device.name == name) { - emulator->connect(port.id, device.id); - break; - } - } - } -} diff --git a/higan/target-bsnes/program/program.hpp b/higan/target-bsnes/program/program.hpp index 4b6366dd..b31ca758 100644 --- a/higan/target-bsnes/program/program.hpp +++ b/higan/target-bsnes/program/program.hpp @@ -74,7 +74,6 @@ struct Program : Emulator::Platform { //input.cpp auto updateInputDriver() -> void; - auto updateInputDevices() -> void; //utility.cpp auto showMessage(string text) -> void; diff --git a/higan/target-higan/presentation/presentation.cpp b/higan/target-higan/presentation/presentation.cpp index 07daff6f..f15fea51 100644 --- a/higan/target-higan/presentation/presentation.cpp +++ b/higan/target-higan/presentation/presentation.cpp @@ -9,9 +9,6 @@ Presentation::Presentation() { systemsMenu.setText("Systems"); systemMenu.setVisible(false); - resetSystem.setText("Soft Reset").onActivate([&] { program->softReset(); }); - powerSystem.setText("Power Cycle").onActivate([&] { program->powerCycle(); }); - unloadSystem.setText("Unload").onActivate([&] { program->unloadMedium(); }); settingsMenu.setText("Settings"); videoScaleMenu.setText("Video Scale"); @@ -165,44 +162,86 @@ Presentation::Presentation() { #endif } -auto Presentation::updateEmulator() -> void { +auto Presentation::updateEmulatorMenu() -> void { if(!emulator) return; - inputPort1.setVisible(false).reset(); - inputPort2.setVisible(false).reset(); - inputPort3.setVisible(false).reset(); - for(auto n : range(emulator->ports.size())) { - if(n >= 3) break; - auto& port = emulator->ports[n]; - auto& menu = (n == 0 ? inputPort1 : n == 1 ? inputPort2 : inputPort3); + systemMenu.reset(); + for(auto& port : emulator->ports) { + Menu menu{&systemMenu}; + menu.setProperty("portID", port.id); menu.setText(port.name); + if(port.name.beginsWith("Expansion") || port.name.beginsWith("Extension")) { + menu.setIcon(Icon::Device::Storage); + } else { + menu.setIcon(Icon::Device::Joypad); + } + + auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); + auto deviceName = settings(path).text(); + auto deviceID = emulator->connected(port.id); Group devices; for(auto& device : port.devices) { MenuRadioItem item{&menu}; - item.setText(device.name).onActivate([=] { - auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); - settings[path].setValue(device.name); + item.setProperty("deviceID", device.id); + item.setText(device.name); + item.onActivate([=] { + settings(path).setValue(device.name); emulator->connect(port.id, device.id); + updateEmulatorDeviceSelections(); }); devices.append(item); + + if(deviceName == device.name) item.doActivate(); + if(!deviceName && deviceID == device.id) item.doActivate(); } - if(devices.objectCount() > 1) { - auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); - auto device = settings(path).text(); - for(auto item : devices.objects()) { - if(item.text() == device) item.setChecked(); - } - menu.setVisible(); + + if(devices.objectCount() == 0) { + menu.setVisible(false); } } - systemMenuSeparatorPorts.setVisible(inputPort1.visible() || inputPort2.visible() || inputPort3.visible()); - resetSystem.setVisible(emulator->information.resettable); + if(systemMenu.actionCount()) { + systemMenu.append(MenuSeparator()); + } - emulator->set("Blur Emulation", blurEmulation.checked()); - emulator->set("Color Emulation", colorEmulation.checked()); - emulator->set("Scanline Emulation", scanlineEmulation.checked()); + if(emulator->information.resettable) { + systemMenu.append(MenuItem().setText("Soft Reset").setIcon(Icon::Action::Refresh).onActivate([&] { + program->softReset(); + })); + } + + systemMenu.append(MenuItem().setText("Power Cycle").setIcon(Icon::Action::Refresh).onActivate([&] { + program->powerCycle(); + })); + + systemMenu.append(MenuItem().setText("Unload").setIcon(Icon::Media::Eject).onActivate([&] { + program->unloadMedium(); + })); + + updateEmulatorDeviceSelections(); +} + +auto Presentation::updateEmulatorDeviceSelections() -> void { + if(!emulator) return; + + for(auto& port : emulator->ports) { + for(auto& action : systemMenu->actions()) { + auto portID = action.property("portID"); + if(portID && portID.natural() == port.id) { + if(auto menu = action.cast()) { + auto deviceID = emulator->connected(port.id); + for(auto& action : menu.actions()) { + if(auto item = action.cast()) { + if(item.property("deviceID").natural() == deviceID) { + item.setChecked(); + } + } + } + } + } + } + } } auto Presentation::drawIcon(uint32_t* output, uint length, uint width, uint height) -> void { diff --git a/higan/target-higan/presentation/presentation.hpp b/higan/target-higan/presentation/presentation.hpp index 3ec8e710..55cde3e9 100644 --- a/higan/target-higan/presentation/presentation.hpp +++ b/higan/target-higan/presentation/presentation.hpp @@ -10,7 +10,8 @@ struct AboutWindow : Window { struct Presentation : Window { Presentation(); - auto updateEmulator() -> void; + auto updateEmulatorMenu() -> void; + auto updateEmulatorDeviceSelections() -> void; auto drawIcon(uint32_t* output, uint length, uint width, uint height) -> void; auto clearViewport() -> void; auto resizeViewport(bool resizeWindow = true) -> void; diff --git a/higan/target-higan/program/medium.cpp b/higan/target-higan/program/medium.cpp index e30a47b9..efff4d18 100644 --- a/higan/target-higan/program/medium.cpp +++ b/higan/target-higan/program/medium.cpp @@ -20,13 +20,16 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa mediumPaths.append(locate({"systems/", medium.name, ".sys/"})); inputManager->bind(emulator = &interface); + presentation->updateEmulatorMenu(); if(!emulator->load(medium.id)) { emulator = nullptr; mediumPaths.reset(); return; } - connectDevices(); emulator->power(); + emulator->set("Blur Emulation", presentation->blurEmulation.checked()); + emulator->set("Color Emulation", presentation->colorEmulation.checked()); + emulator->set("Scanline Emulation", presentation->scanlineEmulation.checked()); updateAudioDriver(); updateAudioEffects(); @@ -34,7 +37,6 @@ auto Program::loadMedium(Emulator::Interface& interface, const Emulator::Interfa presentation->setTitle(emulator->title()); presentation->systemMenu.setText(medium.name).setVisible(true); presentation->toolsMenu.setVisible(true); - presentation->updateEmulator(); toolsManager->cheatEditor.loadCheats(); toolsManager->stateManager.doRefresh(); toolsManager->manifestViewer.doRefresh(); diff --git a/higan/target-higan/program/program.hpp b/higan/target-higan/program/program.hpp index 84182a49..5a9cecee 100644 --- a/higan/target-higan/program/program.hpp +++ b/higan/target-higan/program/program.hpp @@ -34,7 +34,6 @@ struct Program : Emulator::Platform { auto powerCycle() -> void; auto togglePause() -> void; auto rotateDisplay() -> void; - auto connectDevices() -> void; auto showMessage(const string& text) -> void; auto updateStatusText() -> void; auto updateVideoPalette() -> void; diff --git a/higan/target-higan/program/utility.cpp b/higan/target-higan/program/utility.cpp index ef9990dd..43f7ec91 100644 --- a/higan/target-higan/program/utility.cpp +++ b/higan/target-higan/program/utility.cpp @@ -94,20 +94,6 @@ auto Program::rotateDisplay() -> void { showMessage("Display rotated"); } -auto Program::connectDevices() -> void { - if(!emulator) return; - for(auto& port : emulator->ports) { - auto path = string{emulator->information.name, "/", port.name}.replace(" ", ""); - auto name = settings(path).text(); - for(auto& device : port.devices) { - if(device.name == name) { - emulator->connect(port.id, device.id); - break; - } - } - } -} - auto Program::showMessage(const string& text) -> void { statusTime = time(nullptr); statusMessage = text; diff --git a/hiro/core/shared.hpp b/hiro/core/shared.hpp index 6e3c9dd4..04fc1909 100644 --- a/hiro/core/shared.hpp +++ b/hiro/core/shared.hpp @@ -15,6 +15,12 @@ template Name(T* parent, P&&... p) : Name() { \ if(parent) (*parent)->append(*this, std::forward

(p)...); \ } \ + template auto cast() -> T { \ + if(auto pointer = dynamic_cast(data())) { \ + if(auto shared = pointer->instance.acquire()) return T(shared); \ + } \ + return T(); \ + } \ auto enabled(bool recursive = false) const { return self().enabled(recursive); } \ auto focused() const { return self().focused(); } \ auto font(bool recursive = false) const { return self().font(recursive); } \ @@ -52,13 +58,6 @@ struct Object : sObject { DeclareSharedObject(Object) using internalType = mObject; - - template auto cast() -> T { - if(auto pointer = dynamic_cast(data())) { - if(auto shared = pointer->instance.acquire()) return T(shared); - } - return T(); - } }; #endif