Version 2.2

This commit is contained in:
stossy11 2024-10-23 08:34:08 +11:00
parent 7fd2de0389
commit 62e396dc32
49 changed files with 848 additions and 287 deletions

View File

@ -17,7 +17,6 @@
3841946C2C4E4D2B00396613 /* ControllerView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384194612C4E4D2B00396613 /* ControllerView.swift */; };
3841946D2C4E4D2B00396613 /* SudachiEmulationView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 384194672C4E4D2B00396613 /* SudachiEmulationView.swift */; };
384194702C4E540500396613 /* SudachiEmulationHandler.swift in Sources */ = {isa = PBXBuildFile; fileRef = 3841946F2C4E53FD00396613 /* SudachiEmulationHandler.swift */; };
3841947F2C4E5D2E00396613 /* SwiftUIIntrospect in Frameworks */ = {isa = PBXBuildFile; productRef = 3841947E2C4E5D2E00396613 /* SwiftUIIntrospect */; };
384F18922C1DCB520073375C /* Assets.xcassets in Resources */ = {isa = PBXBuildFile; fileRef = 384F18912C1DCB520073375C /* Assets.xcassets */; };
386F6EE52C42E0B900C62EBE /* GameButtonView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386F6EDE2C42E0B900C62EBE /* GameButtonView.swift */; };
386F6EE62C42E0B900C62EBE /* ContentView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 386F6ED92C42E0B900C62EBE /* ContentView.swift */; };
@ -41,8 +40,6 @@
38C50D0A2C1DCF3E0007A953 /* libswresample.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B12C1DCE8900331706 /* libswresample.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
38C50D0B2C1DCF420007A953 /* libswscale.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B22C1DCE8900331706 /* libswscale.xcframework */; };
38C50D0C2C1DCF420007A953 /* libswscale.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B22C1DCE8900331706 /* libswscale.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
38C50D102C1DCF5F0007A953 /* SwiftSyntax in Frameworks */ = {isa = PBXBuildFile; productRef = 38C50D0F2C1DCF5F0007A953 /* SwiftSyntax */; };
38C50D122C1DCF690007A953 /* SwiftSyntaxMacros in Frameworks */ = {isa = PBXBuildFile; productRef = 38C50D112C1DCF690007A953 /* SwiftSyntaxMacros */; };
38C50D152C1DD4570007A953 /* GameController.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C50D142C1DD4570007A953 /* GameController.framework */; };
38C50D172C1DD45F0007A953 /* CoreBluetooth.framework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C50D162C1DD45F0007A953 /* CoreBluetooth.framework */; };
38C50D182C1DD5370007A953 /* boost_context.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846B62C1DCE8900331706 /* boost_context.xcframework */; };
@ -70,6 +67,8 @@
499A5E0F2C74A22D00EC0925 /* GameButtonListView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 499A5E0E2C74A22D00EC0925 /* GameButtonListView.swift */; };
4E0E35EA2C7AB5CB001D24EE /* libSPIRV.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846C72C1DCE8900331706 /* libSPIRV.xcframework */; };
4E0E35EB2C7AB5CB001D24EE /* libSPIRV.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846C72C1DCE8900331706 /* libSPIRV.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
4E1687CE2CC7A27000485EDB /* SudachiMetalView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1687CD2CC7A27000485EDB /* SudachiMetalView.swift */; };
4E1687D02CC83C9100485EDB /* AppIconView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E1687CF2CC83C8E00485EDB /* AppIconView.swift */; };
4E4AF11B2C919C0F00BBF2DE /* Haptics.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4E4AF11A2C919C0F00BBF2DE /* Haptics.swift */; };
4E4AF1272C9243B500BBF2DE /* MoltenVK.xcframework in Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846AC2C1DCE8900331706 /* MoltenVK.xcframework */; };
4E4AF1282C9243B500BBF2DE /* MoltenVK.xcframework in Embed Frameworks */ = {isa = PBXBuildFile; fileRef = 38C846AC2C1DCE8900331706 /* MoltenVK.xcframework */; settings = {ATTRIBUTES = (CodeSignOnCopy, RemoveHeadersOnCopy, ); }; };
@ -91,6 +90,7 @@
4EE462C62CB5770700BF268E /* TopBarView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE462C52CB5770700BF268E /* TopBarView.swift */; };
4EE462C92CB5774900BF268E /* GameGridView.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE462C82CB5774900BF268E /* GameGridView.swift */; };
4EE593FF2C5FA1D1000939C4 /* AppIconProvider.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE593FE2C5FA1D1000939C4 /* AppIconProvider.swift */; };
4EE9B1EC2CC47025008FA07B /* LaunchGameIntentDef.swift in Sources */ = {isa = PBXBuildFile; fileRef = 4EE9B1EB2CC47025008FA07B /* LaunchGameIntentDef.swift */; };
4EEA0CFA2CA376AB0029A55D /* Zip in Frameworks */ = {isa = PBXBuildFile; productRef = 4EEA0CF92CA376AB0029A55D /* Zip */; };
/* End PBXBuildFile section */
@ -186,6 +186,8 @@
38F284CB2C2683A000994A77 /* Makefile */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.make; path = Makefile; sourceTree = "<group>"; };
499A5E0B2C74A1B200EC0925 /* GameListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameListView.swift; sourceTree = "<group>"; };
499A5E0E2C74A22D00EC0925 /* GameButtonListView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameButtonListView.swift; sourceTree = "<group>"; };
4E1687CD2CC7A27000485EDB /* SudachiMetalView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = SudachiMetalView.swift; sourceTree = "<group>"; };
4E1687CF2CC83C8E00485EDB /* AppIconView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconView.swift; sourceTree = "<group>"; };
4E4AF11A2C919C0F00BBF2DE /* Haptics.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = Haptics.swift; sourceTree = "<group>"; };
4E4AF12C2C926BBD00BBF2DE /* FolderMonitor.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = FolderMonitor.swift; sourceTree = "<group>"; };
4E5855E22CB6770F00047C2A /* AskForJIT.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AskForJIT.swift; sourceTree = "<group>"; };
@ -203,6 +205,7 @@
4EE462C52CB5770700BF268E /* TopBarView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = TopBarView.swift; sourceTree = "<group>"; };
4EE462C82CB5774900BF268E /* GameGridView.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = GameGridView.swift; sourceTree = "<group>"; };
4EE593FE2C5FA1D1000939C4 /* AppIconProvider.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = AppIconProvider.swift; sourceTree = "<group>"; };
4EE9B1EB2CC47025008FA07B /* LaunchGameIntentDef.swift */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.swift; path = LaunchGameIntentDef.swift; sourceTree = "<group>"; };
/* End PBXFileReference section */
/* Begin PBXFrameworksBuildPhase section */
@ -224,7 +227,6 @@
38C50D2A2C1DD5530007A953 /* libGenericCodeGen.xcframework in Frameworks */,
4E0E35EA2C7AB5CB001D24EE /* libSPIRV.xcframework in Frameworks */,
4EEA0CFA2CA376AB0029A55D /* Zip in Frameworks */,
38C50D122C1DCF690007A953 /* SwiftSyntaxMacros in Frameworks */,
38C50D092C1DCF3E0007A953 /* libswresample.xcframework in Frameworks */,
38C50D0B2C1DCF420007A953 /* libswscale.xcframework in Frameworks */,
4E4AF12E2C927E8E00BBF2DE /* libdynarmic.xcframework in Frameworks */,
@ -239,12 +241,10 @@
38C50D072C1DCF1E0007A953 /* libavfilter.xcframework in Frameworks */,
38C50D2E2C1DD5650007A953 /* libmbedcrypto.xcframework in Frameworks */,
38C50D1C2C1DD53C0007A953 /* boost_program_options.xcframework in Frameworks */,
3841947F2C4E5D2E00396613 /* SwiftUIIntrospect in Frameworks */,
38C50D152C1DD4570007A953 /* GameController.framework in Frameworks */,
38C50D1A2C1DD5390007A953 /* boost_iostreams.xcframework in Frameworks */,
38C50D052C1DCF1B0007A953 /* libavutil.xcframework in Frameworks */,
38C50D012C1DCF150007A953 /* libavcodec.xcframework in Frameworks */,
38C50D102C1DCF5F0007A953 /* SwiftSyntax in Frameworks */,
38C846592C1DCC8400331706 /* OpenSSL in Frameworks */,
38C50D282C1DD5510007A953 /* libfmt.xcframework in Frameworks */,
38C50D322C1DD56B0007A953 /* libmbedx509.xcframework in Frameworks */,
@ -336,6 +336,7 @@
384194692C4E4D2B00396613 /* Emulation */ = {
isa = PBXGroup;
children = (
4E1687CB2CC7A24000485EDB /* MetalViewHandler */,
38B7FDFB2C760CF600D274FB /* AirPlay */,
3841946E2C4E53F100396613 /* EmulationHandlers */,
384194622C4E4D2B00396613 /* ControllerView */,
@ -377,6 +378,7 @@
384F188C2C1DCB4F0073375C /* Pomelo */ = {
isa = PBXGroup;
children = (
4EE9B1EA2CC4700F008FA07B /* Intents */,
4EE462B62CB54F0400BF268E /* ScreenshotManager */,
4EE462B32CB548D800BF268E /* Extentions */,
384194692C4E4D2B00396613 /* Emulation */,
@ -535,6 +537,14 @@
path = Dependencies;
sourceTree = "<group>";
};
4E1687CB2CC7A24000485EDB /* MetalViewHandler */ = {
isa = PBXGroup;
children = (
4E1687CD2CC7A27000485EDB /* SudachiMetalView.swift */,
);
path = MetalViewHandler;
sourceTree = "<group>";
};
4E2E693A2C97F7F900BCFFCC /* Dynamic Libraries */ = {
isa = PBXGroup;
children = (
@ -619,11 +629,20 @@
4EE593FD2C5FA1C4000939C4 /* AppIcon */ = {
isa = PBXGroup;
children = (
4E1687CF2CC83C8E00485EDB /* AppIconView.swift */,
4EE593FE2C5FA1D1000939C4 /* AppIconProvider.swift */,
);
path = AppIcon;
sourceTree = "<group>";
};
4EE9B1EA2CC4700F008FA07B /* Intents */ = {
isa = PBXGroup;
children = (
4EE9B1EB2CC47025008FA07B /* LaunchGameIntentDef.swift */,
);
path = Intents;
sourceTree = "<group>";
};
/* End PBXGroup section */
/* Begin PBXNativeTarget section */
@ -644,9 +663,6 @@
packageProductDependencies = (
38C846542C1DCC7200331706 /* SDL */,
38C846582C1DCC8400331706 /* OpenSSL */,
38C50D0F2C1DCF5F0007A953 /* SwiftSyntax */,
38C50D112C1DCF690007A953 /* SwiftSyntaxMacros */,
3841947E2C4E5D2E00396613 /* SwiftUIIntrospect */,
4EEA0CF92CA376AB0029A55D /* Zip */,
4EC662AF2CAA1229000DBC5F /* SwiftUIJoystick */,
);
@ -682,8 +698,6 @@
packageReferences = (
38C846532C1DCC7200331706 /* XCRemoteSwiftPackageReference "SwiftSDL2" */,
38C846572C1DCC8400331706 /* XCRemoteSwiftPackageReference "OpenSSL" */,
38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */,
3841947D2C4E5D2E00396613 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */,
4EEA0CF82CA376AB0029A55D /* XCRemoteSwiftPackageReference "Zip" */,
4EC662AE2CAA1229000DBC5F /* XCRemoteSwiftPackageReference "SwiftUIJoystick" */,
);
@ -730,12 +744,14 @@
files = (
4EE593FF2C5FA1D1000939C4 /* AppIconProvider.swift in Sources */,
386F6EEC2C42E0C800C62EBE /* PomeloApp.swift in Sources */,
4E1687CE2CC7A27000485EDB /* SudachiMetalView.swift in Sources */,
4E5855E32CB6770F00047C2A /* AskForJIT.swift in Sources */,
384194702C4E540500396613 /* SudachiEmulationHandler.swift in Sources */,
38020F562C43A02100029E9A /* BootOSView.swift in Sources */,
38020F302C43568500029E9A /* AdvancedSettingsView.swift in Sources */,
386F6EE52C42E0B900C62EBE /* GameButtonView.swift in Sources */,
386F6F302C42E64000C62EBE /* SettingsView.swift in Sources */,
4EE9B1EC2CC47025008FA07B /* LaunchGameIntentDef.swift in Sources */,
4EC662B42CAA1257000DBC5F /* JoystickView.swift in Sources */,
386F6EE62C42E0B900C62EBE /* ContentView.swift in Sources */,
4EE462B52CB548E800BF268E /* MTLViewExtentions.swift in Sources */,
@ -743,6 +759,7 @@
4E4AF11B2C919C0F00BBF2DE /* Haptics.swift in Sources */,
386F6EE82C42E0B900C62EBE /* LibraryView.swift in Sources */,
386F6EE92C42E0B900C62EBE /* FileManager.swift in Sources */,
4E1687D02CC83C9100485EDB /* AppIconView.swift in Sources */,
4E5855E62CB6776C00047C2A /* utils.m in Sources */,
386F6F342C42E98700C62EBE /* InfoView.swift in Sources */,
3841946A2C4E4D2B00396613 /* MetalView.swift in Sources */,
@ -921,7 +938,7 @@
INFOPLIST_KEY_UIStatusBarHidden = NO;
INFOPLIST_KEY_UIStatusBarStyle = "";
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -934,7 +951,7 @@
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
);
MARKETING_VERSION = 2.0;
MARKETING_VERSION = 2.2;
OTHER_LDFLAGS = "-lSudachi";
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.Pomelo;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -987,7 +1004,7 @@
INFOPLIST_KEY_UIStatusBarHidden = NO;
INFOPLIST_KEY_UIStatusBarStyle = "";
INFOPLIST_KEY_UISupportedInterfaceOrientations = "UIInterfaceOrientationLandscapeLeft UIInterfaceOrientationLandscapeRight";
IPHONEOS_DEPLOYMENT_TARGET = 16.0;
IPHONEOS_DEPLOYMENT_TARGET = 15.0;
LD_RUNPATH_SEARCH_PATHS = (
"$(inherited)",
"@executable_path/Frameworks",
@ -1000,7 +1017,7 @@
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
"$(PROJECT_DIR)/Pomelo/Dependencies/Dynamic\\ Libraries",
);
MARKETING_VERSION = 2.0;
MARKETING_VERSION = 2.2;
OTHER_LDFLAGS = "-lSudachi";
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.Pomelo;
PRODUCT_NAME = "$(TARGET_NAME)";
@ -1044,14 +1061,6 @@
/* End XCConfigurationList section */
/* Begin XCRemoteSwiftPackageReference section */
3841947D2C4E5D2E00396613 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/siteline/SwiftUI-Introspect";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 1.3.0;
};
};
38C846532C1DCC7200331706 /* XCRemoteSwiftPackageReference "SwiftSDL2" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/ctreffs/SwiftSDL2";
@ -1068,14 +1077,6 @@
minimumVersion = 3.1.5004;
};
};
38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/apple/swift-syntax.git";
requirement = {
kind = upToNextMajorVersion;
minimumVersion = 510.0.2;
};
};
4EC662AE2CAA1229000DBC5F /* XCRemoteSwiftPackageReference "SwiftUIJoystick" */ = {
isa = XCRemoteSwiftPackageReference;
repositoryURL = "https://github.com/michael94ellis/SwiftUIJoystick";
@ -1095,21 +1096,6 @@
/* End XCRemoteSwiftPackageReference section */
/* Begin XCSwiftPackageProductDependency section */
3841947E2C4E5D2E00396613 /* SwiftUIIntrospect */ = {
isa = XCSwiftPackageProductDependency;
package = 3841947D2C4E5D2E00396613 /* XCRemoteSwiftPackageReference "SwiftUI-Introspect" */;
productName = SwiftUIIntrospect;
};
38C50D0F2C1DCF5F0007A953 /* SwiftSyntax */ = {
isa = XCSwiftPackageProductDependency;
package = 38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */;
productName = SwiftSyntax;
};
38C50D112C1DCF690007A953 /* SwiftSyntaxMacros */ = {
isa = XCSwiftPackageProductDependency;
package = 38C8465A2C1DCCA100331706 /* XCRemoteSwiftPackageReference "swift-syntax" */;
productName = SwiftSyntaxMacros;
};
38C846542C1DCC7200331706 /* SDL */ = {
isa = XCSwiftPackageProductDependency;
package = 38C846532C1DCC7200331706 /* XCRemoteSwiftPackageReference "SwiftSDL2" */;

Binary file not shown.

Before

Width:  |  Height:  |  Size: 202 KiB

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -0,0 +1,36 @@
{
"images" : [
{
"filename" : "fun 1.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "fun 1.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 202 KiB

View File

@ -0,0 +1,36 @@
{
"images" : [
{
"filename" : "favicon.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "favicon.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 568 KiB

View File

@ -0,0 +1,36 @@
{
"images" : [
{
"filename" : "fun 1.png",
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "dark"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
},
{
"appearances" : [
{
"appearance" : "luminosity",
"value" : "tinted"
}
],
"idiom" : "universal",
"platform" : "ios",
"size" : "1024x1024"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -0,0 +1,21 @@
{
"images" : [
{
"filename" : "fun 1.png",
"idiom" : "universal",
"scale" : "1x"
},
{
"idiom" : "universal",
"scale" : "2x"
},
{
"idiom" : "universal",
"scale" : "3x"
}
],
"info" : {
"author" : "xcode",
"version" : 1
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 154 KiB

View File

@ -12,12 +12,24 @@ import UIKit
struct ContentView: View {
@State var urlgame: PomeloGame? = nil
@AppStorage("icloudsaves") var icloudsaves: Bool = false
@AppStorage("useTrollStore") var useTrollStore: Bool = false
@State var core = Core(games: [], root: FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0])
var body: some View {
//NavView(core: $core) // pain and suffering
LibraryView(core: core)
LibraryView(urlgame: $urlgame, core: core)
.onOpenURL(perform: { url in
if let components = URLComponents(url: url, resolvingAgainstBaseURL: true),
components.host == "game",
let text = components.queryItems?.first(where: { $0.name == "id" })?.value {
print(text)
let isJIT = UserDefaults.standard.bool(forKey: "JIT-ENABLED")
urlgame = core.games.map(\.self).first(where: { String(describing: $0.programid) == text })
print(urlgame)
}
})
.onAppear() {
Air.play(AnyView(
Text("Select Game")

View File

@ -16,6 +16,7 @@ class SudachiEmulationViewModel: ObservableObject {
var device: MTLDevice?
@State var mtkView: MTKView = MTKView()
var CaLayer: CAMetalLayer?
@State var isPaused: Bool = false
private var sudachiGame: PomeloGame?
private let sudachi = Sudachi.shared
private var thread: Thread!
@ -39,11 +40,13 @@ class SudachiEmulationViewModel: ObservableObject {
DispatchQueue.global(qos: .userInitiated).async { [self] in
if let sudachiGame = self.sudachiGame {
if sudachiGame.fileURL == URL(string: "BootMii") {
self.sudachi.bootMii()
} else {
self.sudachi.insert(game: sudachiGame.fileURL)
}
} else {
self.sudachi.bootOS()
}
@ -58,7 +61,12 @@ class SudachiEmulationViewModel: ObservableObject {
private func step() {
while true {
sudachi.step()
if !isPaused {
sudachi.step()
} else {
print("pased")
}
}
}

View File

@ -10,7 +10,6 @@ import Sudachi
import Foundation
import GameController
import UIKit
import SwiftUIIntrospect
struct SudachiEmulationView: View {
@ -18,8 +17,7 @@ struct SudachiEmulationView: View {
@State var controllerconnected = false
@State var game: PomeloGame?
@State var sudachi = Sudachi.shared
var device: MTLDevice? = MTLCreateSystemDefaultDevice()
@State var CaLayer: CAMetalLayer?
@State var device: MTLDevice? = MTLCreateSystemDefaultDevice()
@State var ShowPopup: Bool = false
@State var mtkview: MTKView?
@State private var thread: Thread!
@ -40,23 +38,7 @@ struct SudachiEmulationView: View {
ZStack {
if !isairplay {
MetalView(device: device) { view in
DispatchQueue.main.async {
if let metalView = view as? MTKView {
mtkview = metalView
viewModel.configureSudachi(with: metalView)
} else {
print("Error: view is not of type MTKView")
}
}
}
.edgesIgnoringSafeArea(.all)
.persistentSystemOverlays(.hidden)
.onRotate { size in
if !isairplay {
viewModel.handleOrientationChange()
}
}
SudachiMetalView(viewModel: viewModel, mtkview: $mtkview, device: $device)
}
@ -148,21 +130,7 @@ struct SudachiEmulationView: View {
})
if isairplay {
Air.play(AnyView(
MetalView(device: device) { view in
DispatchQueue.main.async {
if let metalView = view as? MTKView {
mtkview = metalView
viewModel.configureSudachi(with: metalView)
} else {
print("Error: view is not of type MTKView")
}
}
}
.edgesIgnoringSafeArea(.all)
)
)
Air.play(AnyView(SudachiMetalView(viewModel: viewModel, mtkview: $mtkview, device: $device)))
}
}
@ -177,10 +145,6 @@ struct SudachiEmulationView: View {
uiTabBarController?.tabBar.isHidden = false
}
.navigationBarBackButtonHidden(true)
.introspect(.tabView, on: .iOS(.v13, .v14, .v15, .v16, .v17)) { (tabBarController) in
tabBarController.tabBar.isHidden = true
uiTabBarController = tabBarController
}
}
private func startPollingFirstFrameShowed() {

View File

@ -0,0 +1,58 @@
//
// SudachiMetalView.swift
// Pomelo
//
// Created by Stossy11 on 22/10/2024.
// Copyright © 2024 Stossy11. All rights reserved.
//
import SwiftUI
import Sudachi
import Foundation
import GameController
import UIKit
struct SudachiMetalView: View {
@StateObject var viewModel: SudachiEmulationViewModel
@Binding var mtkview: MTKView?
@Binding var device: MTLDevice?
@AppStorage("isairplay") private var isairplay: Bool = true
var body: some View {
if #available(iOS 16.0, *) {
MetalView(device: device) { view in
DispatchQueue.main.async {
if let metalView = view as? MTKView {
mtkview = metalView
viewModel.configureSudachi(with: metalView)
} else {
print("Error: view is not of type MTKView")
}
}
}
.edgesIgnoringSafeArea(.all)
.persistentSystemOverlays(.hidden)
.onRotate { size in
if !isairplay {
viewModel.handleOrientationChange()
}
}
} else {
MetalView(device: device) { view in
DispatchQueue.main.async {
if let metalView = view as? MTKView {
mtkview = metalView
viewModel.configureSudachi(with: metalView)
} else {
print("Error: view is not of type MTKView")
}
}
}
.edgesIgnoringSafeArea(.all)
.onRotate { size in
if !isairplay {
viewModel.handleOrientationChange()
}
}
}
}
}

View File

@ -20,9 +20,12 @@ class SudachiScreenView: UIView {
override init(frame: CGRect) {
super.init(frame: frame)
if userDefaults.bool(forKey: "isfullscreen") {
// setupSudachiScreenforcools()
setupSudachiScreen2()
} else if userDefaults.bool(forKey: "isairplay") {
setupSudachiScreen2()
} else if userDefaults.bool(forKey: "169fullscreen") { // this is for the 16/9 aspect ratio full screen
setupSudachiScreenforcools()
} else if UIDevice.current.userInterfaceIdiom == .pad {
setupSudachiScreenforiPad()
} else {
@ -87,6 +90,55 @@ class SudachiScreenView: UIView {
addConstraints(fullscreenconstraints)
}
func setupSudachiScreenforcools() { // oh god this took a long time, im going insane
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
primaryScreen.translatesAutoresizingMaskIntoConstraints = false
primaryScreen.clipsToBounds = true
addSubview(primaryScreen)
primaryScreen.layer.cornerRadius = 5
primaryScreen.layer.masksToBounds = true
NSLayoutConstraint.activate([
primaryScreen.centerXAnchor.constraint(equalTo: centerXAnchor),
primaryScreen.centerYAnchor.constraint(equalTo: centerYAnchor),
primaryScreen.widthAnchor.constraint(lessThanOrEqualTo: widthAnchor),
primaryScreen.heightAnchor.constraint(lessThanOrEqualTo: heightAnchor)
])
let aspectRatio: CGFloat = 16.0/9.0
let aspectRatioConstraint = NSLayoutConstraint(
item: primaryScreen ?? UIView(),
attribute: .width,
relatedBy: .equal,
toItem: primaryScreen,
attribute: .height,
multiplier: aspectRatio,
constant: 0
)
aspectRatioConstraint.priority = .required - 1
primaryScreen.addConstraint(aspectRatioConstraint)
let heightConstraint = primaryScreen.heightAnchor.constraint(equalTo: heightAnchor)
heightConstraint.priority = .defaultHigh
let widthConstraint = primaryScreen.widthAnchor.constraint(equalTo: widthAnchor)
widthConstraint.priority = .defaultHigh
NSLayoutConstraint.activate([heightConstraint, widthConstraint])
// Make primaryScreen fill container
fullscreenconstraints = [
primaryScreen.topAnchor.constraint(equalTo: primaryScreen.topAnchor),
primaryScreen.bottomAnchor.constraint(equalTo: primaryScreen.bottomAnchor),
primaryScreen.leadingAnchor.constraint(equalTo: primaryScreen.leadingAnchor),
primaryScreen.trailingAnchor.constraint(equalTo: primaryScreen.trailingAnchor)
]
NSLayoutConstraint.activate(fullscreenconstraints)
}
func setupSudachiScreenforiPad() {
primaryScreen = MTKView(frame: .zero, device: MTLCreateSystemDefaultDevice())
primaryScreen.translatesAutoresizingMaskIntoConstraints = false

View File

@ -14,6 +14,7 @@ import Zip
struct Core : Comparable, Hashable {
let supportedFileTypes = ["nca", "nro", "nsp", "nso", "xci"]
let name = "Pomelo"
var games: [PomeloGame]
let root: URL
@ -22,6 +23,16 @@ struct Core : Comparable, Hashable {
lhs.name < rhs.name
}
func refreshcore(core: inout Core) {
print("Getting Roms...")
do {
core = try LibraryManager.shared.library()
} catch {
print("Failed to fetch library: \(error)")
return
}
}
func AddFirmware(at fileURL: URL) {
do {
let fileManager = FileManager.default
@ -137,105 +148,6 @@ class LibraryManager {
}
}
func homebrewroms() -> [PomeloGame] {
var urls: [URL] = []
let sdmc = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0].appendingPathComponent("sdmc", conformingTo: .folder)
let sdfolder = sdmc.appendingPathComponent("switch", conformingTo: .folder)
if FileManager.default.fileExists(atPath: sdfolder.path) {
if let dirContents = FileManager.default.enumerator(at: sdmc, includingPropertiesForKeys: nil, options: []) {
do {
try dirContents.forEach() { files in
if let file = files as? URL {
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
if let isfile = getaboutfile.isRegularFile, isfile {
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
urls.append(file)
}
}
}
}
} catch {
if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) {
do {
try dirContents.forEach() { files in
if let file = files as? URL {
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
if let isfile = getaboutfile.isRegularFile, isfile {
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
urls.append(file)
}
}
}
}
} catch {
print("damn")
if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) {
do {
try dirContents.forEach() { files in
if let file = files as? URL {
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
if let isfile = getaboutfile.isRegularFile, isfile {
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
urls.append(file)
}
}
}
}
} catch {
return []
}
} else {
return []
}
}
}
}
}
}
if let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) {
do {
try dirContents.forEach() { files in
if let file = files as? URL {
let getaboutfile = try file.resourceValues(forKeys: [.isRegularFileKey])
if let isfile = getaboutfile.isRegularFile, isfile {
if ["nso", "nro"].contains(file.pathExtension.lowercased()) {
urls.append(file)
}
}
}
}
} catch {
return []
}
} else {
return []
}
func games(from urls: [URL]) -> [PomeloGame] {
var pomelogames: [PomeloGame] = []
pomelogames = urls.reduce(into: [PomeloGame]()) { partialResult, element in
let iscustom = element.startAccessingSecurityScopedResource()
let information = Sudachi.shared.information(for: element)
let game = PomeloGame(developer: information.developer, fileURL: element,
imageData: information.iconData,
title: information.title)
if iscustom {
element.stopAccessingSecurityScopedResource()
}
partialResult.append(game)
}
return pomelogames
}
return games(from: urls)
}
func library() throws -> Core {
func getromsfromdir() throws -> [URL] {
guard let dirContents = FileManager.default.enumerator(at: documentdir, includingPropertiesForKeys: nil, options: []) else {
@ -283,7 +195,8 @@ class LibraryManager {
let iscustom = element.startAccessingSecurityScopedResource()
let information = Sudachi.shared.information(for: element)
let game = PomeloGame(developer: information.developer, fileURL: element,
let game = PomeloGame(programid: Int(information.programID), ishomebrew: information.isHomebrew, developer: information.developer, fileURL: element,
imageData: information.iconData,
title: information.title)
if iscustom {

View File

@ -11,6 +11,8 @@ import Foundation
struct PomeloGame : Comparable, Hashable, Identifiable {
var id = UUID()
let programid: Int
let ishomebrew: Bool
let developer: String
let fileURL: URL
let imageData: Data

View File

@ -2,8 +2,51 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>CFBundleURLTypes</key>
<array>
<dict>
<key>CFBundleURLName</key>
<string>com.stossy11.Pomelo</string>
<key>CFBundleURLSchemes</key>
<array>
<string>pomelo</string>
</array>
</dict>
</array>
<key>NSUserActivityTypes</key>
<array>
<string>LaunchGameIntent</string>
</array>
<key>UIFileSharingEnabled</key>
<true/>
<key>CFBundleIcons</key>
<dict>
<key>CFBundlePrimaryIcon</key>
<dict>
<key>CFBundleIconName</key>
<string>AppIcon</string>
<key>CFBundleIconFiles</key>
<array>
<string>AppIcon</string>
<string>secondary</string>
<string>old</string>
<string>original</string>
</array>
<key>UIPrerenderedIcon</key>
<false/>
</dict>
<key>UINewsstandIcon</key>
<dict>
<key>CFBundleIconFiles</key>
<array>
<string></string>
</array>
<key>UINewsstandBindingType</key>
<string>UINewsstandBindingTypeMagazine</string>
<key>UINewsstandBindingEdge</key>
<string>UINewsstandBindingEdgeLeft</string>
</dict>
</dict>
<key>UIRequiresPersistentWiFi</key>
<true/>
<key>UTExportedTypeDeclarations</key>

View File

@ -0,0 +1,58 @@
//
// LaunchGameIntent.swift
// Pomelo
//
// Created by Stossy11 on 20/10/2024.
// Copyright © 2024 Stossy11. All rights reserved.
//
import Foundation
import SwiftUI
import Intents
import AppIntents
@available(iOS 16.0, *)
struct LaunchGameIntentDef: AppIntent {
static let title: LocalizedStringResource = "Launch Game"
static var description = IntentDescription("Launches the Selected Game.")
@Parameter(title: "Game Name / Id")
var gameName: String
static var parameterSummary: some ParameterSummary {
Summary("Launch \(\.$gameName)")
}
static var openAppWhenRun: Bool = true
@MainActor
func perform() async throws -> some IntentResult {
let core = try LibraryManager.shared.library()
var currentid: Int?
if let pomeloGame = core.games.first(where: { $0.title == self.gameName }) {
currentid = pomeloGame.programid
}
if let pomeloGame = core.games.first(where: { $0.title.localizedCaseInsensitiveContains(self.gameName) }) {
currentid = pomeloGame.programid
}
if let pomeloGame = core.games.first(where: { String(describing: $0.programid) == self.gameName }) {
currentid = pomeloGame.programid
}
if let currentid {
let urlString = "pomelo://game?id=\(currentid)"
if let url = URL(string: urlString) {
UIApplication.shared.open(url, options: [:], completionHandler: nil)
}
}
return .result()
}
}

View File

@ -27,7 +27,7 @@ struct GameIconView: View {
NavigationLink(
destination: SudachiEmulationView(game: game).toolbar(.hidden, for: .tabBar),
destination: SudachiEmulationView(game: game),
isActive: $startgame,
label: {
EmptyView() // Keeps the link hidden

View File

@ -29,7 +29,7 @@ struct GameGridView: View {
LazyVGrid(columns: [GridItem(.adaptive(minimum: 200))], spacing: 2) {
ForEach(0..<filteredGames.count, id: \.self) { index in
let game = filteredGames[index] // Use filteredGames here
NavigationLink(destination: SudachiEmulationView(game: game).toolbar(.hidden, for: .tabBar)) {
NavigationLink(destination: SudachiEmulationView(game: game)) {
GameIconView(game: game, selectedGame: $selectedGame)
.frame(maxWidth: 200, minHeight: 250)
}
@ -48,7 +48,7 @@ struct GameGridView: View {
Text("Remove")
}
Button(action: {
if let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appending(path: "roms") {
if let documentsURL = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first?.appendingPathComponent("roms") {
UIApplication.shared.open(documentsURL, options: [:], completionHandler: nil)
}
}) {
@ -58,7 +58,7 @@ struct GameGridView: View {
Text("Open in Files")
}
}
NavigationLink(destination: SudachiEmulationView(game: game).toolbar(.hidden, for: .tabBar)) {
NavigationLink(destination: SudachiEmulationView(game: game)) {
Text("Launch")
}
}

View File

@ -14,7 +14,7 @@ import Sudachi
struct GameListView: View {
// let games: [PomeloGame]
@State var core: Core
@Binding var core: Core
@Binding var selectedGame: PomeloGame?
var body: some View {
@ -22,6 +22,19 @@ struct GameListView: View {
HStack(spacing: 0) {
ForEach(core.games.prefix(12)) { game in
GameIconView(game: game, selectedGame: $selectedGame)
.contextMenu {
Button {
UIPasteboard.general.string = String(describing: game.programid)
} label: {
Text("Game ID: \(String(describing: game.programid))")
}
Button {
saveImageToIconsFolder(gameImageData: game.imageData, imageName: game.title)
} label: {
Text("Save Icon")
}
}
}
if core.games.count > 12 {
@ -47,7 +60,46 @@ struct GameListView: View {
}
}
func saveImageToIconsFolder(gameImageData: Data, imageName: String) {
// Convert Data to UIImage
if let image = UIImage(data: gameImageData) {
// Convert UIImage to PNG data
if let pngData = image.pngData() {
// Access the app's Documents directory
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
// Create the "Icons" folder path
let iconsFolder = documentsDirectory.appendingPathComponent("icons")
// Create the "Icons" folder if it doesn't exist
if !FileManager.default.fileExists(atPath: iconsFolder.path) {
do {
try FileManager.default.createDirectory(at: iconsFolder, withIntermediateDirectories: true, attributes: nil)
} catch {
print("Error creating Icons folder: \(error)")
return
}
}
// Create the file path for the PNG image
let imagePath = iconsFolder.appendingPathComponent("\(imageName).png")
// Save the PNG data to the file
do {
try pngData.write(to: imagePath)
print("Image saved successfully at: \(imagePath)")
} catch {
print("Error saving image: \(error)")
}
}
} else {
print("Failed to convert UIImage to PNG data.")
}
} else {
print("Failed to create UIImage from Data.")
}
}
func doeskeysexist() -> (Bool, Bool) {
var doesprodexist = false

View File

@ -13,22 +13,26 @@ import Sudachi
struct LibraryView: View {
@State private var selectedGame: PomeloGame? = nil
@Binding var urlgame: PomeloGame?
@State var core: Core
init(selectedGame: PomeloGame? = nil, core: Core) {
_core = State(wrappedValue: core)
self.selectedGame = selectedGame
print("Getting Roms...")
do {
_core = State(wrappedValue: try LibraryManager.shared.library())
} catch {
print("Failed to fetch library: \(error)")
}
var binding: Binding<Bool> {
Binding(
get: { urlgame != nil },
set: { newValue in
if !newValue {
urlgame = nil
}
}
)
}
var body: some View {
NavigationStack {
NavigationView {
GeometryReader { geometry in
VStack {
TopBarView()
@ -37,43 +41,43 @@ struct LibraryView: View {
Spacer()
}
GameListView(core: core, selectedGame: $selectedGame)
GameListView(core: $core, selectedGame: $selectedGame)
Spacer()
BottomMenuView(core: core)
BottomMenuView(core: $core)
}
NavigationLink(
destination: SudachiEmulationView(game: urlgame),
isActive: binding,
label: {
EmptyView() // Keeps the link hidden
}
)
.hidden()
}
}
.navigationViewStyle(StackNavigationViewStyle())
.navigationViewStyle(.stack)
.background(Color.gray.opacity(0.1))
.edgesIgnoringSafeArea(.all)
.onAppear {
refreshcore()
core.refreshcore(core: &core)
if let documentsDirectory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask).first {
let romsFolderURL = documentsDirectory.appendingPathComponent("roms")
_ = FolderMonitor(folderURL: romsFolderURL) {
do {
core = Core(games: [], root: documentsDirectory)
core = try LibraryManager.shared.library()
} catch {
print("Error refreshing core: \(error)")
}
do {
core = Core(games: [], root: documentsDirectory)
core = try LibraryManager.shared.library()
} catch {
print("Error refreshing core: \(error)")
}
}
}
}
func refreshcore() {
print("Getting Roms...")
do {
core = try LibraryManager.shared.library()
} catch {
print("Failed to fetch library: \(error)")
return
}
}
}

View File

@ -7,9 +7,11 @@
//
import SwiftUI
import Sudachi
struct BottomMenuView: View {
@State var core: Core
@Binding var core: Core
@State var isImporting: Bool = false
var body: some View {
HStack(spacing: 40) {
@ -48,7 +50,21 @@ struct BottomMenuView: View {
.frame(width: 50, height: 50)
.foregroundColor(Color.init(uiColor: .darkGray))
}
// ScreenshotGridView
Button {
isImporting = true
} label: {
Circle()
.overlay {
Image(systemName: "plus")
.font(.system(size: 30))
.foregroundColor(.white)
}
.frame(width: 50, height: 50)
.foregroundColor(Color.init(uiColor: .darkGray))
}
NavigationLink(destination: SettingsView(core: core)) {
Circle()
.overlay {
@ -73,5 +89,52 @@ struct BottomMenuView: View {
}
}
.padding(.bottom, 20)
.fileImporter(isPresented: $isImporting, allowedContentTypes: [.zip, .item]) { result in
switch result {
case .success(let url):
let directory = FileManager.default.urls(for: .documentDirectory, in: .userDomainMask)[0]
if url.lastPathComponent.hasSuffix(".zip") {
core.AddFirmware(at: url)
}
if core.supportedFileTypes.contains(url.pathExtension.lowercased()) {
let fileManager = FileManager.default
let has = url.startAccessingSecurityScopedResource()
do {
// Move the file
try fileManager.copyItem(at: url, to: directory.appendingPathComponent("roms").appendingPathComponent(url.lastPathComponent))
} catch {
print("Error moving file: \(error.localizedDescription)")
}
if has {
url.stopAccessingSecurityScopedResource()
}
}
if url.lastPathComponent.hasSuffix(".keys") {
let fileManager = FileManager.default
let has = url.startAccessingSecurityScopedResource()
do {
// Move the file
try fileManager.copyItem(at: url, to: directory.appendingPathComponent("keys").appendingPathComponent(url.lastPathComponent))
} catch {
print("Error moving file: \(error.localizedDescription)")
}
if has {
url.stopAccessingSecurityScopedResource()
}
let sudachi = Sudachi.shared
sudachi.refreshKeys()
}
core.refreshcore(core: &core)
case .failure(let err):
print(err)
}
}
}
}

View File

@ -27,7 +27,7 @@ struct TopBarView: View {
HStack {
NavigationLink {
SudachiEmulationView(game: PomeloGame(developer: "", fileURL: URL(string: "BootMii")!, imageData: Data(), title: "BootOS"))
SudachiEmulationView(game: PomeloGame(programid: 0, ishomebrew: false, developer: "", fileURL: URL(string: "BootMii")!, imageData: Data(), title: "BootOS"))
} label: {
Image(systemName: "person.crop.circle.fill")
.resizable()

View File

@ -2,20 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.stossy11.Pomelo</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudDocuments</string>
</array>
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.developer.kernel.increased-debugging-memory-limit</key>
<true/>
<key>com.apple.developer.kernel.increased-memory-limit</key>
<true/>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>iCloud.com.stossy11.Pomelo</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>

View File

@ -6,6 +6,7 @@
//
import SwiftUI
import AppIntents
infix operator --: LogicalDisjunctionPrecedence
func --(lhs: Bool, rhs: Bool) -> Bool {
@ -14,10 +15,16 @@ func --(lhs: Bool, rhs: Bool) -> Bool {
@main
struct PomeloApp: App {
var body: some Scene {
WindowGroup {
ContentView() // i dont know if i should change anything
.persistentSystemOverlays(.hidden)
if #available(iOS 16, *) {
ContentView() // i dont know if i should change anything
.persistentSystemOverlays(.hidden)
} else {
ContentView() // i dont know if i should change anything
}
}
}
}
// .appShortcuts([])

View File

@ -2,20 +2,12 @@
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
<key>com.apple.developer.icloud-container-identifiers</key>
<array>
<string>iCloud.com.stossy11.Pomelo</string>
</array>
<key>com.apple.developer.icloud-services</key>
<array>
<string>CloudDocuments</string>
</array>
<key>com.apple.developer.kernel.extended-virtual-addressing</key>
<true/>
<key>com.apple.developer.kernel.increased-debugging-memory-limit</key>
<true/>
<key>com.apple.developer.kernel.increased-memory-limit</key>
<true/>
<key>com.apple.developer.ubiquity-container-identifiers</key>
<array>
<string>iCloud.com.stossy11.Pomelo</string>
</array>
<key>com.apple.security.app-sandbox</key>
<true/>
<key>com.apple.security.files.user-selected.read-only</key>

View File

@ -26,7 +26,9 @@ struct ZoomableModifier: ViewModifier {
if #available(iOS 17.0, *) {
view.gesture(magnificationGesture)
} else {
view.gesture(oldMagnificationGesture)
if #available(iOS 16.0, *) {
view.gesture(oldMagnificationGesture)
}
}
}
.gesture(doubleTapGesture)
@ -64,20 +66,29 @@ struct ZoomableModifier: ViewModifier {
}
private var doubleTapGesture: some Gesture {
SpatialTapGesture(count: 2)
.onEnded { value in
let newTransform: CGAffineTransform =
if #available(iOS 16.0, *) {
SpatialTapGesture(count: 2)
.onEnded { value in
let newTransform: CGAffineTransform =
if transform.isIdentity {
.anchoredScale(scale: doubleTapZoomScale, anchor: value.location)
} else {
.identity
}
withAnimation(.linear(duration: 0.15)) {
transform = newTransform
lastTransform = newTransform
withAnimation(.linear(duration: 0.15)) {
transform = newTransform
lastTransform = newTransform
}
}
}
}
return AnyGesture(
TapGesture()
.onEnded { value in
// Add your fallback behavior here if needed.
}
)
}
private var dragGesture: some Gesture {

View File

@ -12,6 +12,7 @@ import Foundation
struct AdvancedSettingsView: View {
@AppStorage("icloudsaves2") var icloudsaves: Bool = false
@AppStorage("isfullscreen") var isFullScreen: Bool = false
@AppStorage("169fullscreen") var sixteenbynineaspect: Bool = false
@AppStorage("exitgame") var exitgame: Bool = false
@AppStorage("ClearBackingRegion") var kpagetable: Bool = false
@AppStorage("WaitingforJIT") var waitingJIT: Bool = false
@ -28,7 +29,7 @@ struct AdvancedSettingsView: View {
.frame(width: .infinity, height: 50)
.overlay() {
HStack {
Toggle("FullScreen", isOn: $isFullScreen)
Toggle("Fullscreen", isOn: $isFullScreen)
.padding()
}
}
@ -36,6 +37,22 @@ struct AdvancedSettingsView: View {
.padding(.bottom)
.font(.footnote)
.foregroundColor(.gray)
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground))
.cornerRadius(10)
.frame(width: .infinity, height: 50)
.overlay() {
HStack {
Toggle("Fullscreen (16/9)", isOn: $sixteenbynineaspect)
.padding()
}
}
Text("This is unstable and can lead to crashes. Use at your own risk.")
.padding(.bottom)
.font(.footnote)
.foregroundColor(.gray)
/*
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground))
@ -119,6 +136,8 @@ struct AdvancedSettingsView: View {
.font(.footnote)
.foregroundColor(.gray)
}
.navigationViewStyle(StackNavigationViewStyle())
.navigationViewStyle(.stack)
.onAppear() {
// isshowing = true
}

View File

@ -18,6 +18,7 @@ enum AppIconProvider {
let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
let iconFileName = iconFiles.last else {
print("Could not find icons in bundle")
return ""
}

View File

@ -0,0 +1,114 @@
//
// AppIconView.swift
// Pomelo
//
// Created by Stossy11 on 23/10/2024.
// Copyright © 2024 Stossy11. All rights reserved.
//
import SwiftUI
struct AppIcon: Identifiable {
let id = UUID()
let name: String
let iconName: String?
}
struct AppIconSwitcherView: View {
@State private var selectedIcon: String?
let appIcons: [AppIcon] = [
AppIcon(name: "Default", iconName: nil),
AppIcon(name: "Secondary", iconName: "secondary"),
AppIcon(name: "Old", iconName: "old"),
]
var body: some View {
List {
ForEach(appIcons) { icon in
IconRow(icon: icon, isSelected: icon.iconName == selectedIcon)
.onTapGesture {
changeAppIcon(to: icon.iconName)
}
}
}
.navigationTitle("App Icons")
.onAppear {
// Get current app icon
if let iconName = UIApplication.shared.alternateIconName {
selectedIcon = iconName
}
}
}
private func changeAppIcon(to iconName: String?) {
guard UIApplication.shared.supportsAlternateIcons else {
print("App icon changing not supported")
return
}
UIApplication.shared.setAlternateIconName(iconName) { error in
if let error = error {
print("Error changing app icon: \(error.localizedDescription)")
} else {
selectedIcon = iconName
}
}
}
}
struct IconRow: View {
let icon: AppIcon
let isSelected: Bool
var body: some View {
HStack {
if let iconImage = getIconImage(for: icon.iconName) {
Image(uiImage: iconImage)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)
.cornerRadius(12)
} else {
// Fallback to app's primary icon
if let primaryIcon = Bundle.main.icon {
Image(uiImage: primaryIcon)
.resizable()
.aspectRatio(contentMode: .fit)
.frame(width: 60, height: 60)
.cornerRadius(12)
}
}
Text(icon.name)
.padding(.leading, 8)
Spacer()
}
.padding(.vertical, 8)
}
private func getIconImage(for iconName: String?) -> UIImage? {
if let iconName = iconName {
// Try to get alternate icon
return UIImage(named: iconName)
} else {
// Return primary app icon
return Bundle.main.icon
}
}
}
// Extension to get the app's primary icon
extension Bundle {
var icon: UIImage? {
if let icons = infoDictionary?["CFBundleIcons"] as? [String: Any],
let primaryIcon = icons["CFBundlePrimaryIcon"] as? [String: Any],
let iconFiles = primaryIcon["CFBundleIconFiles"] as? [String],
let lastIcon = iconFiles.last {
return UIImage(named: lastIcon)
}
return nil
}
}

View File

@ -12,6 +12,7 @@ struct InfoView: View {
@AppStorage("entitlementNotExists") private var entitlementNotExists: Bool = false
@AppStorage("increaseddebugmem") private var increaseddebugmem: Bool = false
@AppStorage("extended-virtual-addressing") private var extended: Bool = false
@State var gd = false
let infoDictionary = Bundle.main.infoDictionary
var body: some View {
@ -52,8 +53,19 @@ struct InfoView: View {
}
.padding()
Text("Version: \(getAppVersion())")
.foregroundColor(.gray)
HStack {
Text("Version: \(getAppVersion())")
.foregroundColor(.white)
.font(.system(size: 12))
.onTapGesture {
gd.toggle()
}
if getAppVersion() == "2.2", gd {
Text("Geometry Dash????? ;)")
.foregroundStyle(.secondary)
.font(.system(size: 5))
}
}
}
}
func getAppVersion() -> String {

View File

@ -15,7 +15,7 @@ struct SettingsView: View {
@AppStorage("useTrollStore") var useTrollStore: Bool = false
var body: some View {
NavigationStack {
NavigationView {
ScrollView {
VStack(alignment: .center) {
if iconused == 1 {
@ -123,6 +123,23 @@ struct SettingsView: View {
}
.padding()
NavigationLink(destination: AppIconSwitcherView()) {
Rectangle()
.fill(Color(uiColor: UIColor.secondarySystemBackground)) // Set the fill color (optional)
.cornerRadius(10) // Apply rounded corners
.frame(width: .infinity, height: 50) // Set the desired dimensions
.overlay() {
HStack {
Text("App Icon")
.foregroundColor(.primary)
.padding()
Spacer()
}
}
}
.padding()
HStack(alignment: .center) {
Spacer()
@ -131,7 +148,11 @@ struct SettingsView: View {
Spacer()
}
}
.navigationViewStyle(StackNavigationViewStyle())
.navigationViewStyle(.stack)
}
.navigationViewStyle(StackNavigationViewStyle())
.navigationViewStyle(.stack)
.onAppear() {
do {
core = try LibraryManager.shared.library()

View File

@ -255,6 +255,7 @@ public:
static KeyManager instance;
return instance;
}
KeyManager(const KeyManager&) = delete;
KeyManager& operator=(const KeyManager&) = delete;

View File

@ -1138,7 +1138,6 @@ public:
const void* data) const noexcept {
dld->vkCmdPushDescriptorSetWithTemplateKHR(handle, update_template, layout, set, data);
}
void BindPipeline(VkPipelineBindPoint bind_point, VkPipeline pipeline) const noexcept {
dld->vkCmdBindPipeline(handle, bind_point, pipeline);
}

View File

@ -28,17 +28,17 @@ bool isiOS16OrBelow() {
std::string versionString = systemInfo.release;
// Extract major and minor version numbers from the release string
int majorVersion = std::stoi(versionString.substr(0, versionString.find('.')));
// For iOS 16, the major version is 16.x.x
if (majorVersion <= 16) {
return true; // iOS 16 or below
} else {
return false; // iOS 17 or above
// Extract major version number from the release string
size_t dotPos = versionString.find('.');
if (dotPos == std::string::npos) {
return false; // In case the format is unexpected
}
}
int majorVersion = std::stoi(versionString.substr(0, dotPos));
// For iOS 16, the major version is 16.x.x
return majorVersion <= 16;
}
#if defined(ANDROID) && defined(ARCHITECTURE_arm64)
#include <adrenotools/bcenabler.h>
@ -1174,8 +1174,6 @@ void Device::RemoveUnsuitableExtensions() {
// extensions.extended_dynamic_state = features.extended_dynamic_state.extendedDynamicState;
extensions.extended_dynamic_state = false;
extensions.extended_dynamic_state = false;
RemoveExtensionFeatureIfUnsuitable(extensions.extended_dynamic_state,
features.extended_dynamic_state,
VK_EXT_EXTENDED_DYNAMIC_STATE_EXTENSION_NAME);

View File

@ -30,6 +30,10 @@ public struct Sudachi {
sudachiObjC.insert(games: urls)
}
public func refreshKeys() {
sudachiObjC.refreshKeys()
}
public func bootOS() {
sudachiObjC.bootOS()
}
@ -44,7 +48,7 @@ public struct Sudachi {
public func play() {
sudachiObjC.play()
}
public func ispaused() -> Bool {
return sudachiObjC.ispaused()
}

View File

@ -220,7 +220,7 @@ Core::SystemResultStatus EmulationSession::InitializeEmulation(const std::string
nullptr, // Parental Controls
nullptr, // Photo Viewer
nullptr, // Profile Selector
std::move(software_keyboard_applet), // std::move(android_keyboard), // Software Keyboard
nullptr, // std::move(android_keyboard), // Software Keyboard
nullptr, // Web Browser
});
@ -283,22 +283,22 @@ Core::SystemResultStatus EmulationSession::MiiEditor() {
nullptr, // Parental Controls
nullptr, // Photo Viewer
nullptr, // Profile Selector
std::move(software_keyboard_applet), // std::move(android_keyboard), // Software Keyboard
nullptr, // std::move(android_keyboard), // Software Keyboard
nullptr, // Web Browser
});
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::OfflineWeb);
constexpr u64 QLaunchId = static_cast<u64>(Service::AM::AppletProgramId::MiiEdit);
auto bis_system = m_system.GetFileSystemController().GetSystemNANDContents();
auto qlaunch_applet_nca = bis_system->GetEntry(QLaunchId, FileSys::ContentRecordType::Program);
m_system.GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::OfflineWeb);
m_system.GetFrontendAppletHolder().SetCurrentAppletId(Service::AM::AppletId::MiiEdit);
const auto filename = qlaunch_applet_nca->GetFullPath();
auto params = Service::AM::FrontendAppletParameters {
.program_id = QLaunchId,
.applet_id = Service::AM::AppletId::OfflineWeb,
.applet_id = Service::AM::AppletId::MiiEdit,
.applet_type = Service::AM::AppletType::SystemApplet
};
@ -352,7 +352,7 @@ Core::SystemResultStatus EmulationSession::BootOS() {
nullptr, // Parental Controls
nullptr, // Photo Viewer
nullptr, // Profile Selector
std::move(software_keyboard_applet), // std::move(android_keyboard), // Software Keyboard
nullptr, // std::move(android_keyboard), // Software Keyboard
nullptr, // Web Browser
});

View File

@ -23,7 +23,7 @@ void EmulationWindow::OnSurfaceChanged(CA::MetalLayer* surface, CGSize size) {
m_window_height = size.height;
// Ensures that we emulate with the correct aspect ratio.
UpdateCurrentFramebufferLayout(m_window_width, m_window_height);
// UpdateCurrentFramebufferLayout(m_window_width, m_window_height);
window_info.render_surface = reinterpret_cast<void*>(surface);
window_info.render_surface_scale = [[UIScreen mainScreen] nativeScale];

View File

@ -58,6 +58,7 @@ typedef NS_ENUM(NSUInteger, VirtualControllerButtonType) {
-(void) quit;
-(void) insertGame:(NSURL *)url NS_SWIFT_NAME(insert(game:));
-(void) insertGames:(NSArray<NSURL *> *)games NS_SWIFT_NAME(insert(games:));
-(void) refreshKeys;
-(void) step;
-(BOOL) hasfirstfame;

View File

@ -90,7 +90,6 @@
YuzuSettings::values.dump_shaders.SetValue(true);
YuzuSettings::values.use_asynchronous_shaders.SetValue(true);
// YuzuSettings::values.astc_recompression.SetValue(YuzuSettings::AstcRecompression::Bc3);
YuzuSettings::values.shader_backend.SetValue(YuzuSettings::ShaderBackend::SpirV);
// YuzuSettings::values.resolution_setup.SetValue(YuzuSettings::ResolutionSetup::Res1X);
// YuzuSettings::values.scaling_filter.SetValue(YuzuSettings::ScalingFilter::Bilinear);
@ -189,6 +188,10 @@
}
}
- (void) refreshKeys {
Core::Crypto::KeyManager::Instance().ReloadKeys();
}
-(void) step {
void(EmulationSession::GetInstance().System().Run());
}