forked from MeloNX/MeloNX
Edit Settings, Make Loading View hide after game has loaded
This commit is contained in:
parent
71551adf2d
commit
09a757c445
@ -634,6 +634,7 @@
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
);
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@ -806,6 +807,10 @@
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
);
|
||||
MARKETING_VERSION = 0.0.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||
@ -845,6 +850,7 @@
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
);
|
||||
GCC_OPTIMIZATION_LEVEL = fast;
|
||||
GENERATE_INFOPLIST_FILE = YES;
|
||||
@ -1017,6 +1023,10 @@
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
"$(PROJECT_DIR)/MeloNX/Dependencies/Dynamic\\ Libraries",
|
||||
);
|
||||
MARKETING_VERSION = 0.0.8;
|
||||
PRODUCT_BUNDLE_IDENTIFIER = com.stossy11.MeloNX;
|
||||
|
Binary file not shown.
@ -12,12 +12,12 @@
|
||||
<key>Ryujinx.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>1</integer>
|
||||
<integer>2</integer>
|
||||
</dict>
|
||||
<key>com.Stossy11.MeloNX.RyujinxAg.xcscheme_^#shared#^_</key>
|
||||
<dict>
|
||||
<key>orderHint</key>
|
||||
<integer>2</integer>
|
||||
<integer>1</integer>
|
||||
</dict>
|
||||
</dict>
|
||||
<key>SuppressBuildableAutocreation</key>
|
||||
|
@ -152,9 +152,9 @@ class Ryujinx {
|
||||
|
||||
args.append(contentsOf: ["--memory-manager-mode", config.memoryManagerMode])
|
||||
|
||||
// args.append(contentsOf: ["--exclusive-fullscreen", String(config.fullscreen)])
|
||||
// args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"])
|
||||
// args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"])
|
||||
args.append(contentsOf: ["--exclusive-fullscreen", String(true)])
|
||||
args.append(contentsOf: ["--exclusive-fullscreen-width", "\(Int(UIScreen.main.bounds.width))"])
|
||||
args.append(contentsOf: ["--exclusive-fullscreen-height", "\(Int(UIScreen.main.bounds.height))"])
|
||||
// We don't need this. Ryujinx should handle it fine :3
|
||||
|
||||
if config.fullscreen {
|
||||
@ -174,10 +174,11 @@ class Ryujinx {
|
||||
args.append(contentsOf: ["--resolution-scale", String(config.resscale)])
|
||||
}
|
||||
|
||||
if config.disableShaderCache {
|
||||
if !config.disableShaderCache { // same with disableShaderCache
|
||||
args.append("--disable-shader-cache")
|
||||
}
|
||||
if config.disableDockedMode {
|
||||
|
||||
if !config.disableDockedMode { // disableDockedMode is actually enableDockedMode, i just have flipped it around in the settings page to make it easier to understand :3
|
||||
args.append("--disable-docked-mode")
|
||||
}
|
||||
if config.enableTextureRecompression {
|
||||
|
@ -22,7 +22,6 @@ struct MoltenVKSettings: Codable, Hashable {
|
||||
struct ContentView: View {
|
||||
// MARK: - Properties
|
||||
@State private var theWindow: UIWindow?
|
||||
@State private var virtualController: GCVirtualController?
|
||||
@State private var game: Game?
|
||||
@State private var controllersList: [Controller] = []
|
||||
@State private var currentControllers: [Controller] = []
|
||||
@ -37,6 +36,11 @@ struct ContentView: View {
|
||||
@AppStorage("quit") var quit: Bool = false
|
||||
|
||||
@State var quits: Bool = false
|
||||
@State private var clumpOffset: CGFloat = -100
|
||||
private let clumpWidth: CGFloat = 100
|
||||
private let animationDuration: Double = 1.0
|
||||
@State private var isAnimating = false
|
||||
@State var isLoading = true
|
||||
|
||||
// MARK: - Initialization
|
||||
init() {
|
||||
@ -58,18 +62,27 @@ struct ContentView: View {
|
||||
// MARK: - Body
|
||||
var body: some View {
|
||||
if let game, quits == false {
|
||||
emulationView
|
||||
.onAppear() {
|
||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||
timer.invalidate()
|
||||
quits = quit
|
||||
|
||||
if quits {
|
||||
quit = false
|
||||
if isLoading {
|
||||
emulationView
|
||||
.onAppear() {
|
||||
Timer.scheduledTimer(withTimeInterval: 0.1, repeats: true) { timer in
|
||||
timer.invalidate()
|
||||
quits = quit
|
||||
|
||||
if quits {
|
||||
quit = false
|
||||
timer.invalidate()
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
VStack {
|
||||
|
||||
}
|
||||
.onAppear() {
|
||||
isAnimating = false
|
||||
}
|
||||
}
|
||||
} else {
|
||||
mainMenuView
|
||||
.onAppear() {
|
||||
@ -81,13 +94,78 @@ struct ContentView: View {
|
||||
|
||||
// MARK: - View Components
|
||||
private var emulationView: some View {
|
||||
ZStack {
|
||||
GeometryReader { screenGeometry in
|
||||
ZStack {
|
||||
HStack(spacing: screenGeometry.size.width * 0.04) {
|
||||
if let icon = game?.icon {
|
||||
Image(uiImage: icon)
|
||||
.resizable()
|
||||
.frame(
|
||||
width: min(screenGeometry.size.width * 0.25, 250),
|
||||
height: min(screenGeometry.size.width * 0.25, 250)
|
||||
)
|
||||
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
.shadow(color: .black.opacity(0.5), radius: 10, x: 0, y: 5)
|
||||
}
|
||||
|
||||
}
|
||||
.onAppear {
|
||||
VStack(alignment: .leading, spacing: screenGeometry.size.height * 0.015) {
|
||||
Text("Loading \(game?.titleName ?? "Game")")
|
||||
.font(.system(size: min(screenGeometry.size.width * 0.04, 32)))
|
||||
.foregroundColor(.white)
|
||||
|
||||
setupEmulation()
|
||||
GeometryReader { geometry in
|
||||
let containerWidth = min(screenGeometry.size.width * 0.35, 350)
|
||||
|
||||
ZStack(alignment: .leading) {
|
||||
// Background track
|
||||
Rectangle()
|
||||
.cornerRadius(10)
|
||||
.frame(width: containerWidth, height: min(screenGeometry.size.height * 0.015, 12))
|
||||
.foregroundColor(.gray.opacity(0.3))
|
||||
.shadow(color: .black.opacity(0.2), radius: 4, x: 0, y: 2)
|
||||
|
||||
// Animated loading bar
|
||||
Rectangle()
|
||||
.cornerRadius(10)
|
||||
.frame(width: clumpWidth, height: min(screenGeometry.size.height * 0.015, 12))
|
||||
.foregroundColor(.blue)
|
||||
.shadow(color: .blue.opacity(0.5), radius: 4, x: 0, y: 2)
|
||||
.offset(x: isAnimating ? containerWidth : -clumpWidth)
|
||||
.animation(
|
||||
Animation.linear(duration: 1.0)
|
||||
.repeatForever(autoreverses: false),
|
||||
value: isAnimating
|
||||
)
|
||||
}
|
||||
.clipShape(RoundedRectangle(cornerRadius: 16))
|
||||
.onAppear {
|
||||
isAnimating = true
|
||||
|
||||
setupEmulation()
|
||||
|
||||
|
||||
Timer.scheduledTimer(withTimeInterval: 0.5, repeats: true) { timer in
|
||||
if get_current_fps() != 0 {
|
||||
isLoading = false
|
||||
isAnimating = false
|
||||
timer.invalidate()
|
||||
}
|
||||
print(get_current_fps())
|
||||
}
|
||||
}
|
||||
}
|
||||
.frame(height: min(screenGeometry.size.height * 0.015, 12))
|
||||
.frame(width: min(screenGeometry.size.width * 0.35, 350))
|
||||
}
|
||||
}
|
||||
.padding(.horizontal, screenGeometry.size.width * 0.06)
|
||||
.padding(.vertical, screenGeometry.size.height * 0.05)
|
||||
.position(
|
||||
x: screenGeometry.size.width / 2,
|
||||
y: screenGeometry.size.height * 0.5
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private var mainMenuView: some View {
|
||||
@ -116,7 +194,6 @@ struct ContentView: View {
|
||||
}
|
||||
|
||||
private func setupEmulation() {
|
||||
virtualController?.disconnect()
|
||||
patchMakeKeyAndVisible()
|
||||
|
||||
if (currentControllers.first(where: { $0 == onscreencontroller }) != nil) {
|
||||
@ -205,6 +282,8 @@ struct ContentView: View {
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
private func setMoltenVKSettings() {
|
||||
|
||||
settings.forEach { setting in
|
||||
|
@ -140,7 +140,7 @@ struct GameLibraryView: View {
|
||||
|
||||
|
||||
Button {
|
||||
var game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion)
|
||||
let game = Game(containerFolder: URL(string: "none")!, fileType: .item, fileURL: URL(string: "MiiMaker")!, titleName: "Mii Maker", titleId: "0", developer: "Nintendo", version: firmwareversion)
|
||||
|
||||
self.startemu = game
|
||||
} label: {
|
||||
@ -165,7 +165,7 @@ struct GameLibraryView: View {
|
||||
Text("Show MeloNX Folder")
|
||||
}
|
||||
} label: {
|
||||
Image(systemName: "ellipsis")
|
||||
Image(systemName: "ellipsis.circle")
|
||||
.foregroundColor(.blue)
|
||||
}
|
||||
|
||||
@ -349,7 +349,6 @@ struct GameLibraryView: View {
|
||||
}
|
||||
}
|
||||
|
||||
// Make sure your Game model conforms to Codable
|
||||
extension Game: Codable {
|
||||
enum CodingKeys: String, CodingKey {
|
||||
case titleName, titleId, developer, version, fileURL
|
||||
|
@ -52,7 +52,7 @@ struct SettingsView: View {
|
||||
.tint(.blue)
|
||||
|
||||
Toggle(isOn: $config.disableShaderCache) {
|
||||
labelWithIcon("Disable Shader Cache", iconName: "memorychip")
|
||||
labelWithIcon("Shader Cache", iconName: "memorychip")
|
||||
}
|
||||
.tint(.blue)
|
||||
|
||||
@ -62,7 +62,7 @@ struct SettingsView: View {
|
||||
.tint(.blue)
|
||||
|
||||
Toggle(isOn: $config.disableDockedMode) {
|
||||
labelWithIcon("Disable Docked Mode", iconName: "dock.rectangle")
|
||||
labelWithIcon("Docked Mode", iconName: "dock.rectangle")
|
||||
}
|
||||
.tint(.blue)
|
||||
|
||||
|
@ -1306,7 +1306,7 @@ namespace Ryujinx.Headless.SDL2
|
||||
options.IgnoreMissingServices,
|
||||
options.AspectRatio,
|
||||
options.AudioVolume,
|
||||
options.UseHypervisor ?? true,
|
||||
options.UseHypervisor ?? false,
|
||||
options.MultiplayerLanInterfaceId,
|
||||
Common.Configuration.Multiplayer.MultiplayerMode.LdnMitm);
|
||||
|
||||
@ -1499,75 +1499,75 @@ namespace Ryujinx.Headless.SDL2
|
||||
return new FileStream(safeHandle, FileAccess.ReadWrite);
|
||||
}
|
||||
|
||||
public class GameInfo
|
||||
{
|
||||
public double FileSize;
|
||||
public string? TitleName;
|
||||
public string? TitleId;
|
||||
public string? Developer;
|
||||
public string? Version;
|
||||
public byte[]? Icon;
|
||||
}
|
||||
|
||||
public unsafe struct GameInfoNative
|
||||
{
|
||||
public ulong FileSize;
|
||||
public fixed byte TitleName[512];
|
||||
public ulong TitleId;
|
||||
public fixed byte Developer[256];
|
||||
public uint Version;
|
||||
public byte* ImageData; // Changed to pointer
|
||||
public uint ImageSize; // Actual size of image data
|
||||
|
||||
public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version, byte[] imageData)
|
||||
{
|
||||
FileSize = fileSize;
|
||||
TitleId = titleId;
|
||||
Version = version;
|
||||
|
||||
fixed (byte* developerPtr = Developer)
|
||||
fixed (byte* titleNamePtr = TitleName)
|
||||
public class GameInfo
|
||||
{
|
||||
CopyStringToFixedArray(titleName, titleNamePtr, 512);
|
||||
CopyStringToFixedArray(developer, developerPtr, 256);
|
||||
public double FileSize;
|
||||
public string? TitleName;
|
||||
public string? TitleId;
|
||||
public string? Developer;
|
||||
public string? Version;
|
||||
public byte[]? Icon;
|
||||
}
|
||||
|
||||
if (imageData == null || imageData.Length > 4096 * 4096)
|
||||
public unsafe struct GameInfoNative
|
||||
{
|
||||
// throw new ArgumentException("Image data must not exceed 4 MB.");
|
||||
ImageSize = (uint)0;
|
||||
ImageData = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageSize = (uint)imageData.Length;
|
||||
public ulong FileSize;
|
||||
public fixed byte TitleName[512];
|
||||
public ulong TitleId;
|
||||
public fixed byte Developer[256];
|
||||
public uint Version;
|
||||
public byte* ImageData;
|
||||
public uint ImageSize;
|
||||
|
||||
ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length);
|
||||
public GameInfoNative(ulong fileSize, string titleName, ulong titleId, string developer, uint version, byte[] imageData)
|
||||
{
|
||||
FileSize = fileSize;
|
||||
TitleId = titleId;
|
||||
Version = version;
|
||||
|
||||
Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length);
|
||||
}
|
||||
}
|
||||
fixed (byte* developerPtr = Developer)
|
||||
fixed (byte* titleNamePtr = TitleName)
|
||||
{
|
||||
CopyStringToFixedArray(titleName, titleNamePtr, 512);
|
||||
CopyStringToFixedArray(developer, developerPtr, 256);
|
||||
}
|
||||
|
||||
// Don't forget to free the allocated memory
|
||||
public void Dispose()
|
||||
{
|
||||
if (ImageData != null)
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)ImageData);
|
||||
ImageData = null;
|
||||
}
|
||||
}
|
||||
private static void CopyStringToFixedArray(string source, byte* destination, int length)
|
||||
{
|
||||
var span = new Span<byte>(destination, length);
|
||||
Encoding.UTF8.GetBytes(source, span);
|
||||
}
|
||||
if (imageData == null || imageData.Length > 4096 * 4096)
|
||||
{
|
||||
// throw new ArgumentException("Image data must not exceed 4 MB.");
|
||||
ImageSize = (uint)0;
|
||||
ImageData = null;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImageSize = (uint)imageData.Length;
|
||||
|
||||
private static void CopyArrayToFixedArray(byte[] source, byte* destination, int maxLength)
|
||||
{
|
||||
var span = new Span<byte>(destination, maxLength);
|
||||
source.AsSpan().CopyTo(span);
|
||||
ImageData = (byte*)Marshal.AllocHGlobal(imageData.Length);
|
||||
|
||||
Marshal.Copy(imageData, 0, (IntPtr)ImageData, imageData.Length);
|
||||
}
|
||||
}
|
||||
|
||||
// Don't forget to free the allocated memory
|
||||
public void Dispose()
|
||||
{
|
||||
if (ImageData != null)
|
||||
{
|
||||
Marshal.FreeHGlobal((IntPtr)ImageData);
|
||||
ImageData = null;
|
||||
}
|
||||
}
|
||||
private static void CopyStringToFixedArray(string source, byte* destination, int length)
|
||||
{
|
||||
var span = new Span<byte>(destination, length);
|
||||
Encoding.UTF8.GetBytes(source, span);
|
||||
}
|
||||
|
||||
private static void CopyArrayToFixedArray(byte[] source, byte* destination, int maxLength)
|
||||
{
|
||||
var span = new Span<byte>(destination, maxLength);
|
||||
source.AsSpan().CopyTo(span);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user