From 4a92e7d4eef7b6940d563b17c8a3d1c8f1fbac09 Mon Sep 17 00:00:00 2001 From: J-rg Date: Fri, 17 Jun 2022 02:43:03 +0200 Subject: [PATCH] Port OECorePlugin to Swift --- OpenEmuKit.xcodeproj/project.pbxproj | 12 +- OpenEmuKit/OpenEmuKit.h | 1 - Source/OECorePlugin.h | 49 ------ Source/OECorePlugin.m | 239 --------------------------- Source/OECorePlugin.swift | 224 +++++++++++++++++++++++++ Source/OpenEmuHelperApp.swift | 2 +- 6 files changed, 229 insertions(+), 298 deletions(-) delete mode 100644 Source/OECorePlugin.h delete mode 100644 Source/OECorePlugin.m create mode 100644 Source/OECorePlugin.swift diff --git a/OpenEmuKit.xcodeproj/project.pbxproj b/OpenEmuKit.xcodeproj/project.pbxproj index 462b68c..582bb34 100644 --- a/OpenEmuKit.xcodeproj/project.pbxproj +++ b/OpenEmuKit.xcodeproj/project.pbxproj @@ -67,9 +67,8 @@ 05E6BA1324CCD56200ACFB35 /* OpenEmuSystem.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 05E6BA1224CCD56200ACFB35 /* OpenEmuSystem.framework */; settings = {ATTRIBUTES = (Weak, ); }; }; 05E6BA1D24CCD71D00ACFB35 /* OESystemPlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05E6BA1724CCD71600ACFB35 /* OESystemPlugin.swift */; }; 05E6BA1E24CCD71D00ACFB35 /* OEPlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E6BA1824CCD71800ACFB35 /* OEPlugin.m */; }; - 05E6BA2024CCD71D00ACFB35 /* OECorePlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 05E6BA1A24CCD71B00ACFB35 /* OECorePlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; 05E6BA2124CCD71D00ACFB35 /* OEPlugin.h in Headers */ = {isa = PBXBuildFile; fileRef = 05E6BA1B24CCD71C00ACFB35 /* OEPlugin.h */; settings = {ATTRIBUTES = (Public, ); }; }; - 05E6BA2224CCD71D00ACFB35 /* OECorePlugin.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E6BA1C24CCD71D00ACFB35 /* OECorePlugin.m */; }; + 05E6BA2224CCD71D00ACFB35 /* OECorePlugin.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05E6BA1C24CCD71D00ACFB35 /* OECorePlugin.swift */; }; 05E6BA3024CCD77600ACFB35 /* OEGameLayerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 05E6BA2D24CCD77300ACFB35 /* OEGameLayerView.swift */; }; 05E6BA3D24CCD79600ACFB35 /* OELogging.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E6BA3724CCD79300ACFB35 /* OELogging.m */; }; 05E6BA3E24CCD79600ACFB35 /* OEThreadProxy.m in Sources */ = {isa = PBXBuildFile; fileRef = 05E6BA3824CCD79500ACFB35 /* OEThreadProxy.m */; }; @@ -178,9 +177,8 @@ 05E6BA1224CCD56200ACFB35 /* OpenEmuSystem.framework */ = {isa = PBXFileReference; explicitFileType = wrapper.framework; path = OpenEmuSystem.framework; sourceTree = BUILT_PRODUCTS_DIR; }; 05E6BA1724CCD71600ACFB35 /* OESystemPlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OESystemPlugin.swift; sourceTree = ""; }; 05E6BA1824CCD71800ACFB35 /* OEPlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OEPlugin.m; sourceTree = ""; }; - 05E6BA1A24CCD71B00ACFB35 /* OECorePlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OECorePlugin.h; sourceTree = ""; }; 05E6BA1B24CCD71C00ACFB35 /* OEPlugin.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OEPlugin.h; sourceTree = ""; }; - 05E6BA1C24CCD71D00ACFB35 /* OECorePlugin.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OECorePlugin.m; sourceTree = ""; }; + 05E6BA1C24CCD71D00ACFB35 /* OECorePlugin.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OECorePlugin.swift; sourceTree = ""; }; 05E6BA2D24CCD77300ACFB35 /* OEGameLayerView.swift */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.swift; path = OEGameLayerView.swift; sourceTree = ""; }; 05E6BA3624CCD79200ACFB35 /* OEThreadProxy.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = OEThreadProxy.h; sourceTree = ""; }; 05E6BA3724CCD79300ACFB35 /* OELogging.m */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.objc; path = OELogging.m; sourceTree = ""; }; @@ -410,8 +408,7 @@ children = ( 05E6BA1B24CCD71C00ACFB35 /* OEPlugin.h */, 05E6BA1824CCD71800ACFB35 /* OEPlugin.m */, - 05E6BA1A24CCD71B00ACFB35 /* OECorePlugin.h */, - 05E6BA1C24CCD71D00ACFB35 /* OECorePlugin.m */, + 05E6BA1C24CCD71D00ACFB35 /* OECorePlugin.swift */, 05E6BA1724CCD71600ACFB35 /* OESystemPlugin.swift */, ); name = Plugins; @@ -506,7 +503,6 @@ 05E6BA3F24CCD79600ACFB35 /* OELogging.h in Headers */, 05E6BA2124CCD71D00ACFB35 /* OEPlugin.h in Headers */, 054A2C0C278CDA6A00A2F241 /* KeyValueScanner+Private.h in Headers */, - 05E6BA2024CCD71D00ACFB35 /* OECorePlugin.h in Headers */, 054A2C0A278CDA5A00A2F241 /* KeyValueScanner.h in Headers */, 05E6958424CA5D4200ACFB35 /* OpenEmuKit.h in Headers */, ); @@ -698,7 +694,7 @@ 05201D6F277D316E0028CBE0 /* UserDefaultsPresetStorage.swift in Sources */, 0572A424287B89CD00AC32F8 /* OEGameStartupInfo.swift in Sources */, 05E6BA1E24CCD71D00ACFB35 /* OEPlugin.m in Sources */, - 05E6BA2224CCD71D00ACFB35 /* OECorePlugin.m in Sources */, + 05E6BA2224CCD71D00ACFB35 /* OECorePlugin.swift in Sources */, 0572A4132878D76C00AC32F8 /* GameRenderer.swift in Sources */, 0553DE2E27B5B83F0085512F /* String+Extensions.swift in Sources */, 054A2C0E278CDA7800A2F241 /* KeyValueScanner.m in Sources */, diff --git a/OpenEmuKit/OpenEmuKit.h b/OpenEmuKit/OpenEmuKit.h index f0e0f0d..04efabb 100644 --- a/OpenEmuKit/OpenEmuKit.h +++ b/OpenEmuKit/OpenEmuKit.h @@ -33,5 +33,4 @@ FOUNDATION_EXPORT const unsigned char OpenEmuKitVersionString[]; // In this header, you should import all the public headers of your framework using statements like #import #import -#import #import diff --git a/Source/OECorePlugin.h b/Source/OECorePlugin.h deleted file mode 100644 index cfe5978..0000000 --- a/Source/OECorePlugin.h +++ /dev/null @@ -1,49 +0,0 @@ -/* - Copyright (c) 2009, OpenEmu Team - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the OpenEmu Team nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -@import Cocoa; -#import - -@class OEGameCoreController; - -@interface OECorePlugin : OEPlugin - -@property(readonly) OEGameCoreController *controller; - -@property(readonly) Class gameCoreClass; -@property(readonly) NSString *bundleIdentifier; -@property(readonly) NSArray *systemIdentifiers; -@property(readonly) NSArray *requiredFiles; -@property(readonly) NSDictionary *coreOptions; - -@property(class, readonly) NSArray *allPlugins; - -+ (OECorePlugin *)corePluginWithBundleAtPath:(NSString *)bundlePath; -+ (OECorePlugin *)corePluginWithBundleIdentifier:(NSString *)identifier; -+ (NSArray *)corePluginsForSystemIdentifier:(NSString *)systemIdentifier; -+ (NSArray *)requiredFiles; - -@end diff --git a/Source/OECorePlugin.m b/Source/OECorePlugin.m deleted file mode 100644 index af6d7e1..0000000 --- a/Source/OECorePlugin.m +++ /dev/null @@ -1,239 +0,0 @@ -/* - Copyright (c) 2009, OpenEmu Team - - Redistribution and use in source and binary forms, with or without - modification, are permitted provided that the following conditions are met: - * Redistributions of source code must retain the above copyright - notice, this list of conditions and the following disclaimer. - * Redistributions in binary form must reproduce the above copyright - notice, this list of conditions and the following disclaimer in the - documentation and/or other materials provided with the distribution. - * Neither the name of the OpenEmu Team nor the - names of its contributors may be used to endorse or promote products - derived from this software without specific prior written permission. - - THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY - EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED - WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE - DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY - DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES - (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; - LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND - ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT - (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS - SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. - */ - -#import "OECorePlugin.h" -#import - -@implementation OECorePlugin -@synthesize controller = _controller, gameCoreClass = _gameCoreClass; - -static NSArray *_cachedRequiredFiles = nil; - -- (OEGameCoreController *)controller -{ - if (_controller == nil) - { - Class principalClass = [[self bundle] principalClass]; - _controller = [self newPluginControllerWithClass:principalClass]; - } - return _controller; -} - -+ (NSArray *)allPlugins -{ - return [OEPlugin pluginsForType:self]; -} - -+ (NSString *)pluginFolder -{ - return @"Cores"; -} - -+ (NSString *)pluginExtension -{ - return @"oecoreplugin"; -} - -+ (OECorePlugin *)corePluginWithBundleAtPath:(NSString *)bundlePath -{ - return [self pluginWithBundleAtPath:bundlePath type:self]; -} - -+ (OECorePlugin *)corePluginWithBundleIdentifier:(NSString *)identifier -{ - NSArray *cores = [OECorePlugin pluginsForType:self]; - for(OECorePlugin *plugin in cores) - if([[plugin bundleIdentifier] caseInsensitiveCompare:identifier] == NSOrderedSame) - return plugin; - - return nil; -} - -+ (NSArray *)corePluginsForSystemIdentifier:(NSString *)systemIdentifier; -{ - NSArray *cores = [self allPlugins]; - NSMutableArray *validCores = [NSMutableArray array]; - - for(OECorePlugin *plugin in cores) - if([[plugin systemIdentifiers] containsObject:systemIdentifier]) - [validCores addObject:plugin]; - - return validCores; -} - -+ (NSArray *)requiredFiles; -{ - if(_cachedRequiredFiles == nil) - { - NSMutableArray *files = [[NSMutableArray alloc] init]; - for(OECorePlugin *plugin in [OEPlugin pluginsForType:self]) - if([plugin requiredFiles] != nil) [files addObjectsFromArray:[plugin requiredFiles]]; - - _cachedRequiredFiles = [files copy]; - } - - return _cachedRequiredFiles; -} - -- (instancetype)initWithBundleAtPath:(NSString *)aPath name:(NSString *)aName error:(NSError *__autoreleasing *)outError -{ - if((self = [super initWithBundleAtPath:aPath name:aName error:outError])) - { - // invalidate global cache - _cachedRequiredFiles = nil; - } - - return self; -} - -- (id)newPluginControllerWithClass:(Class)bundleClass -{ - if(![bundleClass isSubclassOfClass:[OEGameCoreController class]]) return nil; - - return [[bundleClass alloc] initWithBundle:[self bundle]]; -} - -- (NSString *)bundleIdentifier -{ - return [[self infoDictionary] objectForKey:@"CFBundleIdentifier"]; -} - -- (NSArray *)systemIdentifiers; -{ - return [[self infoDictionary] objectForKey:OEGameCoreSystemIdentifiersKey]; -} - -- (NSDictionary *)coreOptions -{ - return [[self infoDictionary] objectForKey:OEGameCoreOptionsKey]; -} - -- (NSArray *)requiredFiles -{ - id options = [self coreOptions]; - NSMutableArray *allRequiredFiles = [NSMutableArray array]; - - for (id key in options) { - id resultDict = [options objectForKey:key]; - if([resultDict objectForKey:OEGameCoreRequiredFilesKey] != nil) - [allRequiredFiles addObjectsFromArray:[resultDict objectForKey:OEGameCoreRequiredFilesKey]]; - } - - if([allRequiredFiles count] > 0) - return [allRequiredFiles copy]; - else - return nil; -} - -- (Class)gameCoreClass -{ - if (_gameCoreClass == Nil) - { - [[self bundle] load]; - _gameCoreClass = NSClassFromString([[self infoDictionary] objectForKey:OEGameCoreClassKey]); - } - - return _gameCoreClass; -} - -- (BOOL)_isMarkedDeprecatedInInfoPlist -{ - if (![self.infoDictionary[OEGameCoreDeprecatedKey] boolValue]) - return NO; - - NSString *minOSXVer = self.infoDictionary[OEGameCoreDeprecatedMinMacOSVersionKey]; - if (!minOSXVer) - return YES; - NSArray *osxVerComponents = [minOSXVer componentsSeparatedByString:@"."]; - if (osxVerComponents.count < 2) - return YES; - NSOperatingSystemVersion minOsxVerParsed = (NSOperatingSystemVersion){ - atoi([osxVerComponents[0] UTF8String]), - atoi([osxVerComponents[1] UTF8String]), - osxVerComponents.count > 2 ? atoi([osxVerComponents[2] UTF8String]) : 0}; - if ([[NSProcessInfo processInfo] isOperatingSystemAtLeastVersion:minOsxVerParsed]) - return YES; - return NO; -} - -- (BOOL)isDeprecated -{ - if (self.isOutOfSupport) - return YES; - return [self _isMarkedDeprecatedInInfoPlist]; -} - -- (BOOL)isOutOfSupport -{ - /* plugins deprecated 2017-11-04 */ - NSString *bundleName = [[[self bundle] bundleURL] lastPathComponent]; - NSArray *deprecatedPlugins = @[ - @"Dolphin-Core.oecoreplugin", - @"NeoPop.oecoreplugin", - @"TwoMbit.oecoreplugin", - @"VisualBoyAdvance.oecoreplugin", - @"Yabause.oecoreplugin"]; - if ([deprecatedPlugins containsObject:bundleName]) - return YES; - - /* beta-era plugins */ - NSString *appcastURL = self.infoDictionary[@"SUFeedURL"]; - if ([appcastURL containsString:@"openemu.org/update"]) - return YES; - - /* plugins marked as deprecated in the Info.plist keys */ - if ([self _isMarkedDeprecatedInInfoPlist]) { - NSDate *deadline = self.infoDictionary[OEGameCoreSupportDeadlineKey]; - if (!deadline) return NO; - if ([[NSDate date] compare:deadline] == NSOrderedDescending) { - // we are past the support deadline; return YES to remove the core - [self _prepareForRemoval]; - return YES; - } - } - - return NO; -} - -- (void)_prepareForRemoval -{ - NSDictionary *replacements = self.infoDictionary[OEGameCoreSuggestedReplacement]; - - NSUserDefaults *ud = [NSUserDefaults standardUserDefaults]; - for (NSString *system in self.systemIdentifiers) { - NSString *replacement = [replacements objectForKey:system]; - NSString *prefKey = [@"defaultCore." stringByAppendingString:system]; - NSString *currentCore = [ud stringForKey:prefKey]; - if (currentCore && [currentCore isEqual:self.bundleIdentifier]) { - if (replacement) - [ud setObject:replacement forKey:prefKey]; - else - [ud removeObjectForKey:prefKey]; - } - } -} - -@end diff --git a/Source/OECorePlugin.swift b/Source/OECorePlugin.swift new file mode 100644 index 0000000..ba97890 --- /dev/null +++ b/Source/OECorePlugin.swift @@ -0,0 +1,224 @@ +// Copyright (c) 2021, OpenEmu Team +// +// Redistribution and use in source and binary forms, with or without +// modification, are permitted provided that the following conditions are met: +// * Redistributions of source code must retain the above copyright +// notice, this list of conditions and the following disclaimer. +// * Redistributions in binary form must reproduce the above copyright +// notice, this list of conditions and the following disclaimer in the +// documentation and/or other materials provided with the distribution. +// * Neither the name of the OpenEmu Team nor the +// names of its contributors may be used to endorse or promote products +// derived from this software without specific prior written permission. +// +// THIS SOFTWARE IS PROVIDED BY OpenEmu Team ''AS IS'' AND ANY +// EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +// WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +// DISCLAIMED. IN NO EVENT SHALL OpenEmu Team BE LIABLE FOR ANY +// DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +// (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +// LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +// ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +// (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +// SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +import Foundation +import OpenEmuBase + +public class OECorePlugin: OEPlugin { + + override public class var pluginExtension: String { + "oecoreplugin" + } + + override public class var pluginFolder: String { + "Cores" + } + + @objc public class var allPlugins: [OECorePlugin] { + return OEPlugin.plugins(forType: Self.self) as? [OECorePlugin] ?? [] + } + + override public required init(bundleAtPath path: String, name: String?) throws { + try super.init(bundleAtPath: path, name: name) + + // invalidate global cache + Self.cachedRequiredFiles = nil + } + + public static func corePlugin(bundleAtPath bundlePath: String) -> OECorePlugin? { + return OEPlugin(bundleAtPath: bundlePath, type: Self.self) as? OECorePlugin + } + + public static func corePlugin(bundleIdentifier identifier: String) -> OECorePlugin? { + return allPlugins.first(where: { + $0.bundleIdentifier.caseInsensitiveCompare(identifier) == .orderedSame + }) + } + + public static func corePlugins(forSystemIdentifier identifier: String) -> [OECorePlugin] { + var validCores: [OECorePlugin] = [] + + for plugin in allPlugins { + if plugin.systemIdentifiers.contains(identifier) { + validCores.append(plugin) + } + } + + return validCores + } + + // MARK: - + + typealias Controller = OEGameCoreController + + private var _controller: Controller? + public var controller: OEGameCoreController! { + if _controller == nil, + let principalClass = bundle.principalClass + { + _controller = newPluginController(with: principalClass) + } + return _controller + } + + private func newPluginController(with bundleClass: AnyClass) -> Controller? { + guard bundleClass.isSubclass(of: Controller.self) else { return nil } + return (bundleClass as! Controller.Type).init(bundle: bundle) + } + + // MARK: - + + private static var cachedRequiredFiles: [[String : Any]]? + public static var requiredFiles: [[String : Any]] { + if cachedRequiredFiles == nil { + var files: [[String : Any]] = [] + for plugin in allPlugins { + files.append(contentsOf: plugin.requiredFiles) + } + + cachedRequiredFiles = files + } + + return cachedRequiredFiles! + } + + public var gameCoreClass: AnyClass? { + return controller?.gameCoreClass + } + + public var bundleIdentifier: String { + return infoDictionary["CFBundleIdentifier"] as! String + } + + public var systemIdentifiers: [String] { + return infoDictionary[OEGameCoreSystemIdentifiersKey] as? [String] ?? [] + } + + public var coreOptions: [String : Any] { + return infoDictionary[OEGameCoreOptionsKey] as? [String : Any] ?? [:] + } + + public var requiredFiles: [[String : Any]] { + var allRequiredFiles: [[String : Any]] = [] + + for value in coreOptions.values { + if let resultDict = value as? [String : Any], + let object = resultDict[OEGameCoreRequiredFilesKey] as? [[String : Any]] + { + allRequiredFiles.append(contentsOf: object) + } + } + + return allRequiredFiles + } + + // MARK: - + + private var isMarkedDeprecatedInInfoPlist: Bool { + if infoDictionary[OEGameCoreDeprecatedKey] as? Bool != true { + return false + } + + func isValidVersionString(_ string: String) -> Bool { + if string.isEmpty { return false } + let validCharacters: Set = [".", "0", "1", "2", "3", "4", "5", "6", "7", "8", "9"] + return Set(string).isSubset(of: validCharacters) + } + + guard let minMacOSVer = self.infoDictionary[OEGameCoreDeprecatedMinMacOSVersionKey] as? String, + isValidVersionString(minMacOSVer) + else { return true } + + let macOSVerComponents = minMacOSVer.components(separatedBy: ".") + if macOSVerComponents.count < 2 { + return true + } + let minMacOSVerParsed = OperatingSystemVersion(majorVersion: Int(macOSVerComponents[0])!, + minorVersion: Int(macOSVerComponents[1])!, + patchVersion: macOSVerComponents.count > 2 ? Int(macOSVerComponents[2])! : 0) + if ProcessInfo.processInfo.isOperatingSystemAtLeast(minMacOSVerParsed) { + return true + } + return false + } + + override public var isDeprecated: Bool { + if isOutOfSupport { + return true + } + return isMarkedDeprecatedInInfoPlist + } + + override public var isOutOfSupport: Bool { + // plugins deprecated 2017-11-04 + let bundleFileName = bundle.bundleURL.lastPathComponent + let deprecatedPlugins = [ + "Dolphin-Core.oecoreplugin", + "NeoPop.oecoreplugin", + "TwoMbit.oecoreplugin", + "VisualBoyAdvance.oecoreplugin", + "Yabause.oecoreplugin", + ] + if deprecatedPlugins.contains(bundleFileName) { + return true + } + + // beta-era plugins + if let appcastURL = infoDictionary["SUFeedURL"] as? String, + appcastURL.contains("openemu.org/update") + { + return true + } + + // plugins marked as deprecated in the Info.plist keys + if isMarkedDeprecatedInInfoPlist, + let deadline = infoDictionary[OEGameCoreSupportDeadlineKey] as? Date, + Date().compare(deadline) == .orderedDescending + { + // we are past the support deadline; return true to remove the core + prepareForRemoval() + return true + } + + return false + } + + private func prepareForRemoval() { + let replacements = infoDictionary[OEGameCoreSuggestedReplacement] as? [String : String] + + let defaults = UserDefaults.standard + for systemIdentifier in systemIdentifiers { + let prefKey = "defaultCore." + systemIdentifier + if let currentCore = defaults.string(forKey: prefKey), + currentCore == bundleIdentifier + { + if let replacement = replacements?[systemIdentifier] { + defaults.set(replacement, forKey: prefKey) + } else { + defaults.removeObject(forKey: prefKey) + } + } + } + } +} diff --git a/Source/OpenEmuHelperApp.swift b/Source/OpenEmuHelperApp.swift index 79b2a2c..4bbb4c1 100644 --- a/Source/OpenEmuHelperApp.swift +++ b/Source/OpenEmuHelperApp.swift @@ -251,7 +251,7 @@ extension OSLog { _systemController = OESystemPlugin.systemPlugin(bundleAtPath: info.systemPluginPath)!.controller _systemResponder = _systemController.newGameSystemResponder() - _gameController = OECorePlugin(bundleAtPath: info.corePluginPath).controller + _gameController = OECorePlugin.corePlugin(bundleAtPath: info.corePluginPath)!.controller gameCore = _gameController.newGameCore() let systemIdentifier = _systemController.systemIdentifier!