diff --git a/Directory.Packages.props b/Directory.Packages.props
index 7eb217ce6..2c63988fc 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -49,5 +49,6 @@
+
diff --git a/src/LibRyujinx/AndroidLogTarget.cs b/src/LibRyujinx/AndroidLogTarget.cs
new file mode 100644
index 000000000..937b02bf2
--- /dev/null
+++ b/src/LibRyujinx/AndroidLogTarget.cs
@@ -0,0 +1,51 @@
+using Ryujinx.Common;
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Logging.Formatters;
+using Ryujinx.Common.Logging.Targets;
+using System;
+using System.IO;
+using System.Linq;
+
+namespace LibRyujinx
+{
+ public class AndroidLogTarget : ILogTarget
+ {
+ private readonly string _name;
+ private readonly DefaultLogFormatter _formatter;
+
+ string ILogTarget.Name { get => _name; }
+
+ public AndroidLogTarget( string name)
+ {
+ _name = name;
+ _formatter = new DefaultLogFormatter();
+ }
+
+ public void Log(object sender, LogEventArgs args)
+ {
+ Logcat.AndroidLogPrint(GetLogLevel(args.Level), _name, _formatter.Format(args));
+ }
+
+ private Logcat.LogLevel GetLogLevel(LogLevel logLevel)
+ {
+ return logLevel switch
+ {
+ LogLevel.Debug => Logcat.LogLevel.Debug,
+ LogLevel.Stub => Logcat.LogLevel.Info,
+ LogLevel.Info => Logcat.LogLevel.Info,
+ LogLevel.Warning => Logcat.LogLevel.Warn,
+ LogLevel.Error => Logcat.LogLevel.Error,
+ LogLevel.Guest => Logcat.LogLevel.Info,
+ LogLevel.AccessLog => Logcat.LogLevel.Info,
+ LogLevel.Notice => Logcat.LogLevel.Info,
+ LogLevel.Trace => Logcat.LogLevel.Verbose,
+ _ => throw new NotImplementedException()
+
+ };
+ }
+
+ public void Dispose()
+ {
+ }
+ }
+}
diff --git a/src/LibRyujinx/Audio/Oboe/OboeAudioBuffer.cs b/src/LibRyujinx/Audio/Oboe/OboeAudioBuffer.cs
new file mode 100644
index 000000000..aad74115f
--- /dev/null
+++ b/src/LibRyujinx/Audio/Oboe/OboeAudioBuffer.cs
@@ -0,0 +1,18 @@
+namespace LibRyujinx.Shared.Audio.Oboe
+{
+ internal class OboeAudioBuffer
+ {
+ public readonly ulong DriverIdentifier;
+ public readonly ulong SampleCount;
+ public readonly byte[] Data;
+ public ulong SamplePlayed;
+
+ public OboeAudioBuffer(ulong driverIdentifier, byte[] data, ulong sampleCount)
+ {
+ DriverIdentifier = driverIdentifier;
+ Data = data;
+ SampleCount = sampleCount;
+ SamplePlayed = 0;
+ }
+ }
+}
diff --git a/src/LibRyujinx/Audio/Oboe/OboeHardwareDeviceDriver.cs b/src/LibRyujinx/Audio/Oboe/OboeHardwareDeviceDriver.cs
new file mode 100644
index 000000000..c56d0fe38
--- /dev/null
+++ b/src/LibRyujinx/Audio/Oboe/OboeHardwareDeviceDriver.cs
@@ -0,0 +1,108 @@
+using Ryujinx.Audio;
+using Ryujinx.Audio.Common;
+using Ryujinx.Audio.Integration;
+using Ryujinx.Memory;
+using System;
+using System.Collections.Concurrent;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading;
+using System.Threading.Tasks;
+using static Ryujinx.Audio.Integration.IHardwareDeviceDriver;
+
+namespace LibRyujinx.Shared.Audio.Oboe
+{
+ internal class OboeHardwareDeviceDriver : IHardwareDeviceDriver
+ {
+ private readonly ManualResetEvent _updateRequiredEvent;
+ private readonly ManualResetEvent _pauseEvent;
+ private readonly ConcurrentDictionary _sessions;
+
+ public OboeHardwareDeviceDriver()
+ {
+ _updateRequiredEvent = new ManualResetEvent(false);
+ _pauseEvent = new ManualResetEvent(true);
+ _sessions = new ConcurrentDictionary();
+ }
+
+ public static bool IsSupported => true;
+
+ public ManualResetEvent GetUpdateRequiredEvent()
+ {
+ return _updateRequiredEvent;
+ }
+
+ public ManualResetEvent GetPauseEvent()
+ {
+ return _pauseEvent;
+ }
+
+ public IHardwareDeviceSession OpenDeviceSession(Direction direction, IVirtualMemoryManager memoryManager, SampleFormat sampleFormat, uint sampleRate, uint channelCount, float volume)
+ {
+ if (channelCount == 0)
+ {
+ channelCount = 2;
+ }
+
+ if (sampleRate == 0)
+ {
+ sampleRate = Constants.TargetSampleRate;
+ }
+
+ if (direction != Direction.Output)
+ {
+ throw new NotImplementedException("Input direction is currently not implemented on Oboe backend!");
+ }
+
+ OboeHardwareDeviceSession session = new OboeHardwareDeviceSession(this, memoryManager, sampleFormat, sampleRate, channelCount, volume);
+
+ _sessions.TryAdd(session, 0);
+
+ return session;
+ }
+
+ internal bool Unregister(OboeHardwareDeviceSession session)
+ {
+ return _sessions.TryRemove(session, out _);
+ }
+
+ public void Dispose()
+ {
+ Dispose(true);
+ }
+
+ protected virtual void Dispose(bool disposing)
+ {
+ if (disposing)
+ {
+ foreach (OboeHardwareDeviceSession session in _sessions.Keys)
+ {
+ session.Dispose();
+ }
+
+ _pauseEvent.Dispose();
+ }
+ }
+
+ public bool SupportsSampleRate(uint sampleRate)
+ {
+ return true;
+ }
+
+ public bool SupportsSampleFormat(SampleFormat sampleFormat)
+ {
+ return sampleFormat != SampleFormat.Adpcm;
+ }
+
+ public bool SupportsChannelCount(uint channelCount)
+ {
+ return channelCount == 1 || channelCount == 2 || channelCount == 4 || channelCount == 6;
+ }
+
+ public bool SupportsDirection(Direction direction)
+ {
+ return direction == Direction.Output;
+ }
+ }
+}
\ No newline at end of file
diff --git a/src/LibRyujinx/Audio/Oboe/OboeHardwareDeviceSession.cs b/src/LibRyujinx/Audio/Oboe/OboeHardwareDeviceSession.cs
new file mode 100644
index 000000000..b23426d30
--- /dev/null
+++ b/src/LibRyujinx/Audio/Oboe/OboeHardwareDeviceSession.cs
@@ -0,0 +1,169 @@
+using Ryujinx.Audio.Backends.Common;
+using Ryujinx.Audio.Common;
+using Ryujinx.Memory;
+using System;
+using System.Collections.Generic;
+using System.Threading;
+
+namespace LibRyujinx.Shared.Audio.Oboe
+{
+ internal class OboeHardwareDeviceSession : HardwareDeviceSessionOutputBase
+ {
+ private OboeHardwareDeviceDriver _driver;
+ private bool _isWorkerActive;
+ private Queue _queuedBuffers;
+ private bool _isActive;
+ private ulong _playedSampleCount;
+ private Thread _workerThread;
+ private ManualResetEvent _updateRequiredEvent;
+ private IntPtr _session;
+ private object _queueLock = new object();
+ private object _trackLock = new object();
+
+ public OboeHardwareDeviceSession(OboeHardwareDeviceDriver driver, IVirtualMemoryManager memoryManager, SampleFormat requestedSampleFormat, uint requestedSampleRate, uint requestedChannelCount, float requestedVolume) : base(memoryManager, requestedSampleFormat, requestedSampleRate, requestedChannelCount)
+ {
+ _driver = driver;
+ _isActive = false;
+ _playedSampleCount = 0;
+ _isWorkerActive = true;
+ _queuedBuffers = new Queue();
+ _updateRequiredEvent = driver.GetUpdateRequiredEvent();
+
+ _session = OboeInterop.CreateSession((int)requestedSampleFormat, requestedSampleRate, requestedChannelCount);
+
+ _workerThread = new Thread(Update);
+ _workerThread.Name = $"HardwareDeviceSession.Android.Track";
+ _workerThread.Start();
+
+ SetVolume(requestedVolume);
+ }
+
+ public override void UnregisterBuffer(AudioBuffer buffer) { }
+
+ public unsafe void Update(object ignored)
+ {
+ while (_isWorkerActive)
+ {
+ bool needUpdate = false;
+
+ bool hasBuffer;
+
+ OboeAudioBuffer buffer;
+
+ lock (_queueLock)
+ {
+ hasBuffer = _queuedBuffers.TryPeek(out buffer);
+ }
+
+ while (hasBuffer)
+ {
+ StartIfNotPlaying();
+
+ fixed(byte* ptr = buffer.Data)
+ OboeInterop.WriteToSession(_session, (ulong)ptr, buffer.SampleCount);
+
+ lock (_queueLock)
+ {
+ _playedSampleCount += buffer.SampleCount;
+
+ _queuedBuffers.TryDequeue(out _);
+ }
+
+ needUpdate = true;
+
+ lock (_queueLock)
+ {
+ hasBuffer = _queuedBuffers.TryPeek(out buffer);
+ }
+ }
+
+ if (needUpdate)
+ {
+ _updateRequiredEvent.Set();
+ }
+
+ // No work
+ Thread.Sleep(5);
+ }
+
+ }
+
+ public override void Dispose()
+ {
+ OboeInterop.CloseSession(_session);
+ }
+ public override void PrepareToClose()
+ {
+ _isWorkerActive = false;
+ _workerThread.Join();
+ }
+
+ private void StartIfNotPlaying()
+ {
+ lock (_trackLock)
+ {
+ if (OboeInterop.IsPlaying(_session) == 0)
+ {
+ Start();
+ }
+ }
+ }
+
+ public override void QueueBuffer(AudioBuffer buffer)
+ {
+ lock (_queueLock)
+ {
+ OboeAudioBuffer driverBuffer = new OboeAudioBuffer(buffer.DataPointer, buffer.Data, GetSampleCount(buffer));
+
+ _queuedBuffers.Enqueue(driverBuffer);
+
+ if (_isActive)
+ {
+ StartIfNotPlaying();
+ }
+ }
+ }
+
+ public override float GetVolume()
+ {
+ return OboeInterop.GetSessionVolume(_session);
+ }
+
+ public override ulong GetPlayedSampleCount()
+ {
+ lock (_queueLock)
+ {
+ return _playedSampleCount;
+ }
+ }
+
+ public override void SetVolume(float volume)
+ {
+ volume = 1;
+ OboeInterop.SetSessionVolume(_session, volume);
+ }
+
+ public override void Start()
+ {
+ OboeInterop.StartSession(_session);
+ }
+
+ public override void Stop()
+ {
+ OboeInterop.StopSession(_session);
+ }
+
+ public override bool WasBufferFullyConsumed(AudioBuffer buffer)
+ {
+ lock (_queueLock)
+ {
+ if (!_queuedBuffers.TryPeek(out OboeAudioBuffer driverBuffer))
+ {
+ return true;
+ }
+
+ return driverBuffer.DriverIdentifier != buffer.DataPointer;
+ }
+ }
+ }
+}
diff --git a/src/LibRyujinx/Audio/Oboe/OboeInterop.cs b/src/LibRyujinx/Audio/Oboe/OboeInterop.cs
new file mode 100644
index 000000000..79d9ca43e
--- /dev/null
+++ b/src/LibRyujinx/Audio/Oboe/OboeInterop.cs
@@ -0,0 +1,41 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Runtime.InteropServices;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace LibRyujinx.Shared.Audio.Oboe
+{
+ internal static partial class OboeInterop
+ {
+ private const string InteropLib = "libryujinxjni";
+
+ [LibraryImport(InteropLib, EntryPoint = "create_session")]
+ public static partial IntPtr CreateSession(int sample_format,
+ uint sample_rate,
+ uint channel_count);
+
+
+ [LibraryImport(InteropLib, EntryPoint = "start_session")]
+ public static partial void StartSession(IntPtr session);
+
+ [LibraryImport(InteropLib, EntryPoint = "stop_session")]
+ public static partial void StopSession(IntPtr session);
+
+ [LibraryImport(InteropLib, EntryPoint = "close_session")]
+ public static partial void CloseSession(IntPtr session);
+
+ [LibraryImport(InteropLib, EntryPoint = "set_session_volume")]
+ public static partial void SetSessionVolume(IntPtr session, float volume);
+
+ [LibraryImport(InteropLib, EntryPoint = "get_session_volume")]
+ public static partial float GetSessionVolume(IntPtr session);
+
+ [LibraryImport(InteropLib, EntryPoint = "is_playing")]
+ public static partial int IsPlaying(IntPtr session);
+
+ [LibraryImport(InteropLib, EntryPoint = "write_to_session")]
+ public static partial void WriteToSession(IntPtr session, ulong data, ulong samples);
+ }
+}
diff --git a/src/LibRyujinx/Jni/Delegates.cs b/src/LibRyujinx/Jni/Delegates.cs
new file mode 100644
index 000000000..683109ade
--- /dev/null
+++ b/src/LibRyujinx/Jni/Delegates.cs
@@ -0,0 +1,286 @@
+using LibRyujinx.Jni.Identifiers;
+using LibRyujinx.Jni.Internal.Pointers;
+using LibRyujinx.Jni.Pointers;
+using LibRyujinx.Jni.Primitives;
+using LibRyujinx.Jni.References;
+using LibRyujinx.Jni.Values;
+using System;
+
+namespace LibRyujinx.Jni
+{
+ internal delegate Int32 GetVersionDelegate(JEnvRef env);
+
+ internal delegate JClassLocalRef DefineClassDelegate(JEnvRef env, CCharSequence name, JObjectLocalRef loader, IntPtr binaryData, Int32 len);
+ internal delegate JClassLocalRef FindClassDelegate(JEnvRef env, CCharSequence name);
+
+ internal delegate JMethodId FromReflectedMethodDelegate(JEnvRef env, JObjectLocalRef method);
+ internal delegate JFieldId FromReflectedFieldIdDelegate(JEnvRef env, JObjectLocalRef field);
+
+ internal delegate JObjectLocalRef ToReflectedMethodDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId methodId, Boolean isStatic);
+
+ internal delegate JClassLocalRef GetSuperclassDelegate(JEnvRef env, JClassLocalRef sub);
+ internal delegate Boolean IsAssignableFromDelegate(JEnvRef env, JClassLocalRef sub, JClassLocalRef sup);
+
+ internal delegate JObjectLocalRef ToReflectedFieldIdDelegate(JEnvRef env, JClassLocalRef jClass, JFieldId fieldId, Boolean isStatic);
+
+ internal delegate JResult ThrowDelegate(JEnvRef env, JThrowableLocalRef obj);
+ internal delegate JResult ThrowNewDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence msg);
+ internal delegate JThrowableLocalRef ExceptionOccurredDelegate(JEnvRef env);
+ internal delegate void ExceptionDescribeDelegate(JEnvRef env);
+ internal delegate void ExceptionClearDelegate(JEnvRef env);
+ internal delegate void FatalErrorDelegate(JEnvRef env, CCharSequence msg);
+
+ internal delegate JResult PushLocalFrameDelegate(JEnvRef env, Int32 capacity);
+ internal delegate JObjectLocalRef PopLocalFrameDelegate(JEnvRef env, JObjectLocalRef result);
+
+ internal delegate JGlobalRef NewGlobalRefDelegate(JEnvRef env, JObjectLocalRef lref);
+ internal delegate void DeleteGlobalRefDelegate(JEnvRef env, JGlobalRef gref);
+ internal delegate void DeleteLocalRefDelegate(JEnvRef env, JObjectLocalRef lref);
+ internal delegate Boolean IsSameObjectDelegate(JEnvRef env, JObjectLocalRef obj1, JObjectLocalRef obj2);
+ internal delegate JObjectLocalRef NewLocalRefDelegate(JEnvRef env, JObjectLocalRef objRef);
+ internal delegate JResult EnsureLocalCapacityDelegate(JEnvRef env, Int32 capacity);
+
+ internal delegate JObjectLocalRef AllocObjectDelegate(JEnvRef env, JClassLocalRef jClass);
+ internal delegate JObjectLocalRef NewObjectDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, IntPtr args);
+ internal delegate JObjectLocalRef NewObjectVDelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, ArgIterator args);
+ internal delegate JObjectLocalRef NewObjectADelegate(JEnvRef env, JClassLocalRef jClass, JMethodId jMethod, JValueSequence args);
+
+ internal delegate JClassLocalRef GetObjectClassDelegate(JEnvRef env, JObjectLocalRef obj);
+ internal delegate Boolean IsInstanceOfDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass);
+
+ internal delegate JMethodId GetMethodIdDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence name, CCharSequence signature);
+
+ internal delegate JObjectLocalRef CallObjectMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JObjectLocalRef CallObjectMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JObjectLocalRef CallObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JBoolean CallBooleanMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JBoolean CallBooleanMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JBoolean CallBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JByte CallByteMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JByte CallByteMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JByte CallByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JChar CallCharMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JChar CallCharMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JChar CallCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JShort CallShortMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JShort CallShortMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JShort CallShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JInt CallIntMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JInt CallIntMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JInt CallIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JLong CallLongMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JLong CallLongMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JLong CallLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JFloat CallFloatMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JFloat CallFloatMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JFloat CallFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate JDouble CallDoubleMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate JDouble CallDoubleMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate JDouble CallDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+ internal delegate void CallVoidMethodDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, IntPtr args);
+ internal delegate void CallVoidMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, ArgIterator args);
+ internal delegate void CallVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JMethodId jMethod, JValueSequence args);
+
+ internal delegate JObjectLocalRef CallNonVirtualObjectMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JObjectLocalRef CallNonVirtualObjectMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JObjectLocalRef CallNonVirtualObjectMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JBoolean CallNonVirtualBooleanMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JBoolean CallNonVirtualBooleanMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JBoolean CallNonVirtualBooleanMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JByte CallNonVirtualByteMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JByte CallNonVirtualByteMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JByte CallNonVirtualByteMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JChar CallNonVirtualCharMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JChar CallNonVirtualCharMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JChar CallNonVirtualCharMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JShort CallNonVirtualShortMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JShort CallNonVirtualShortMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JShort CallNonVirtualShortMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JInt CallNonVirtualIntMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JInt CallNonVirtualIntMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JInt CallNonVirtualIntMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JLong CallNonVirtualLongMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JLong CallNonVirtualLongMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JLong CallNonVirtualLongMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JFloat CallNonVirtualFloatMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JFloat CallNonVirtualFloatMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JFloat CallNonVirtualFloatMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JDouble CallNonVirtualDoubleMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JDouble CallNonVirtualDoubleMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JDouble CallNonVirtualDoubleMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate void CallNonVirtualVoidMethodDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate void CallNonVirtualVoidMethodVDelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate void CallNonVirtualVoidMethodADelegate(JEnvRef env, JObjectLocalRef obj, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+
+ internal delegate JFieldId GetFieldIdDelegate(JEnvRef env, JClassLocalRef jclass, CCharSequence name, CCharSequence signature);
+
+ internal delegate JObjectLocalRef GetObjectFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JBoolean GetBooleanFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JByte GetByteFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JChar GetCharFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JShort GetShortFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JInt GetIntFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JLong GetLongFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JFloat GetFloatFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate JDouble GetDoubleFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField);
+ internal delegate void SetObjectFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JObjectLocalRef value);
+ internal delegate void SetBooleanFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JBoolean value);
+ internal delegate void SetByteFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JByte value);
+ internal delegate void SetCharFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JChar value);
+ internal delegate void SetShortFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JShort value);
+ internal delegate void SetIntFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JInt value);
+ internal delegate void SetLongFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JLong value);
+ internal delegate void SetFloatFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JFloat value);
+ internal delegate void SetDoubleFieldDelegate(JEnvRef env, JObjectLocalRef obj, JFieldId jField, JDouble value);
+
+ internal delegate JMethodId GetStaticMethodIdDelegate(JEnvRef env, JClassLocalRef jClass, CCharSequence name, CCharSequence signature);
+
+ internal delegate JObjectLocalRef CallStaticObjectMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JObjectLocalRef CallStaticObjectMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JObjectLocalRef CallStaticObjectMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JBoolean CallStaticBooleanMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JBoolean CallStaticBooleanMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JBoolean CallStaticBooleanMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JByte CallStaticByteMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JByte CallStaticByteMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JByte CallStaticByteMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JChar CallStaticCharMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JChar CallStaticCharMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JChar CallStaticCharMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JShort CallStaticShortMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JShort CallStaticShortMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JShort CallStaticShortMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JInt CallStaticIntMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JInt CallStaticIntMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JInt CallStaticIntMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JLong CallStaticLongMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JLong CallStaticLongMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JLong CallStaticLongMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JFloat CallStaticFloatMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JFloat CallStaticFloatMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JFloat CallStaticFloatMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate JDouble CallStaticDoubleMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate JDouble CallStaticDoubleMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate JDouble CallStaticDoubleMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+ internal delegate void CallStaticVoidMethodDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, IntPtr args);
+ internal delegate void CallStaticVoidMethodVDelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, ArgIterator args);
+ internal delegate void CallStaticVoidMethodADelegate(JEnvRef env, JClassLocalRef jclass, JMethodId jMethod, JValueSequence args);
+
+ internal delegate JFieldId GetStaticFieldIdDelegate(JEnvRef env, JClassLocalRef jclass, CCharSequence name, CCharSequence signature);
+
+ internal delegate JObjectLocalRef GetStaticObjectFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JBoolean GetStaticBooleanFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JByte GetStaticByteFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JChar GetStaticCharFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JShort GetStaticShortFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JInt GetStaticIntFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JLong GetStaticLongFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JFloat GetStaticFloatFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate JDouble GetStaticDoubleFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField);
+ internal delegate void SetStaticObjectFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JObjectLocalRef value);
+ internal delegate void SetStaticBooleanFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JBoolean value);
+ internal delegate void SetStaticByteFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JByte value);
+ internal delegate void SetStaticCharFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JChar value);
+ internal delegate void SetStaticShortFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JShort value);
+ internal delegate void SetStaticIntFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JInt value);
+ internal delegate void SetStaticLongFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JLong value);
+ internal delegate void SetStaticFloatFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JFloat value);
+ internal delegate void SetStaticDoubleFieldDelegate(JEnvRef env, JClassLocalRef jclass, JFieldId jField, JDouble value);
+
+ internal delegate JStringLocalRef NewStringDelegate(JEnvRef env, JCharSequence unicode, Int32 length);
+
+ internal delegate Int32 GetStringLengthDelegate(JEnvRef env, JStringLocalRef jString);
+ internal delegate JCharSequence GetStringCharsDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
+ internal delegate void ReleaseStringCharsDelegate(JEnvRef env, JStringLocalRef jString, JCharSequence chars);
+
+ internal delegate JStringLocalRef NewStringUtfDelegate(JEnvRef env, CCharSequence unicode);
+ internal delegate Int32 GetStringUtfLengthDelegate(JEnvRef env, JStringLocalRef jString);
+ internal delegate CCharSequence GetStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
+ internal delegate void ReleaseStringUtfCharsDelegate(JEnvRef env, JStringLocalRef jString, CCharSequence chars);
+
+ internal delegate Int32 GetArrayLengthDelegate(JEnvRef env, JArrayLocalRef array);
+
+ internal delegate JArrayLocalRef NewObjectArrayDelegate(JEnvRef env, Int32 length, JClassLocalRef jClass, JObjectLocalRef init);
+ internal delegate JObjectLocalRef GetObjectArrayElementDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 index);
+ internal delegate void SetObjectArrayElementDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 index, JObjectLocalRef obj);
+
+ internal delegate JArrayLocalRef NewBooleanArrayDelegate(JEnvRef env, Int32 length);
+ internal delegate JArrayLocalRef NewByteArrayDelegate(JEnvRef env, Int32 length);
+ internal delegate JArrayLocalRef NewCharArrayDelegate(JEnvRef env, Int32 length);
+ internal delegate JArrayLocalRef NewShortArrayDelegate(JEnvRef env, Int32 length);
+ internal delegate JArrayLocalRef NewIntArrayDelegate(JEnvRef env, Int32 length);
+ internal delegate JArrayLocalRef NewLongArrayDelegate(JEnvRef env, Int32 length);
+ internal delegate JArrayLocalRef NewFloatArrayDelegate(JEnvRef env, Int32 length);
+ internal delegate JArrayLocalRef NewDoubleArrayDelegate(JEnvRef env, Int32 length);
+
+ internal delegate IntPtr GetBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate IntPtr GetByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate IntPtr GetCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate IntPtr GetShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate IntPtr GetIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate IntPtr GetLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate IntPtr GetFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate IntPtr GetDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+
+ internal delegate void ReleaseBooleanArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+ internal delegate void ReleaseByteArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+ internal delegate void ReleaseCharArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+ internal delegate void ReleaseShortArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+ internal delegate void ReleaseIntArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+ internal delegate void ReleaseLongArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+ internal delegate void ReleaseFloatArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+ internal delegate void ReleaseDoubleArrayElementsDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+
+ internal delegate void GetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void GetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void GetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void GetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void GetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void GetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void GetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void GetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetBooleanArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetByteArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetCharArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetShortArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetIntArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetLongArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetFloatArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+ internal delegate void SetDoubleArrayRegionDelegate(JEnvRef env, JArrayLocalRef jArray, Int32 startIndex, Int32 length, IntPtr buffer);
+
+ internal delegate JResult RegisterNativesDelegate(JEnvRef env, JClassLocalRef jClass, JNativeMethodSequence methods);
+ internal delegate JResult UnregisterNativesDelegate(JEnvRef env, JClassLocalRef jClass);
+
+ internal delegate JResult MonitorEnterDelegate(JEnvRef env, JObjectLocalRef jClass);
+ internal delegate JResult MonitorExitDelegate(JEnvRef env, JObjectLocalRef jClass);
+
+ internal delegate JResult GetJavaVMDelegate(JEnvRef env, ref JavaVMRef jvm);
+
+ internal delegate void GetStringRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length, JCharSequence buffer);
+ internal delegate void GetStringUtfRegionDelegate(JEnvRef env, JStringLocalRef jString, Int32 startIndex, Int32 length, CCharSequence buffer);
+
+ internal delegate IntPtr GetPrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef jArray, JBooleanRef isCopy);
+ internal delegate void ReleasePrimitiveArrayCriticalDelegate(JEnvRef env, JArrayLocalRef jArray, IntPtr elements, JReleaseMode mode);
+
+ internal delegate JCharSequence GetStringCriticalDelegate(JEnvRef env, JStringLocalRef jString, JBooleanRef isCopy);
+ internal delegate void ReleaseStringCriticalDelegate(JEnvRef env, JStringLocalRef jString, JCharSequence chars);
+
+ internal delegate JWeakRef NewWeakGlobalRefDelegate(JEnvRef env, JObjectLocalRef obj);
+ internal delegate void DeleteWeakGlobalRefDelegate(JEnvRef env, JWeakRef jWeak);
+
+ internal delegate Boolean ExceptionCheckDelegate(JEnvRef env);
+
+ internal delegate JObjectLocalRef NewDirectByteBufferDelegate(JEnvRef env, IntPtr address, Int64 capacity);
+ internal delegate IntPtr GetDirectBufferAddressDelegate(JEnvRef env, JObjectLocalRef buffObj);
+ internal delegate Int64 GetDirectBufferCapacityDelegate(JEnvRef env, JObjectLocalRef buffObj);
+
+ internal delegate JReferenceType GetObjectRefTypeDelegate(JEnvRef env, JObjectLocalRef obj);
+
+ internal delegate JResult DestroyJavaVMDelegate(JavaVMRef vm);
+ internal delegate JResult AttachCurrentThreadDelegate(JavaVMRef vm, ref JEnvRef env, in JavaVMAttachArgs args);
+ internal delegate JResult DetachCurrentThreadDelegate(JavaVMRef vm);
+
+ internal delegate JResult GetEnvDelegate(JavaVMRef vm, ref JEnvRef env, JInt version);
+
+ internal delegate JResult AttachCurrentThreadAsDaemonDelegate(JavaVMRef vm, ref JEnvRef env, in JavaVMAttachArgs args);
+}
\ No newline at end of file
diff --git a/src/LibRyujinx/Jni/Identifiers/JFieldId.cs b/src/LibRyujinx/Jni/Identifiers/JFieldId.cs
new file mode 100644
index 000000000..aa35f9074
--- /dev/null
+++ b/src/LibRyujinx/Jni/Identifiers/JFieldId.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.Identifiers
+{
+ public readonly struct JFieldId : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JFieldId other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JFieldId other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JFieldId a, JFieldId b) => a.Equals(b);
+ public static Boolean operator !=(JFieldId a, JFieldId b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Identifiers/JMethodId.cs b/src/LibRyujinx/Jni/Identifiers/JMethodId.cs
new file mode 100644
index 000000000..b8fee13c3
--- /dev/null
+++ b/src/LibRyujinx/Jni/Identifiers/JMethodId.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.Identifiers
+{
+ public readonly struct JMethodId : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JMethodId other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JMethodId other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JMethodId a, JMethodId b) => a.Equals(b);
+ public static Boolean operator !=(JMethodId a, JMethodId b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/JReferenceType.cs b/src/LibRyujinx/Jni/JReferenceType.cs
new file mode 100644
index 000000000..47c9f2aef
--- /dev/null
+++ b/src/LibRyujinx/Jni/JReferenceType.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace LibRyujinx.Jni
+{
+ public enum JReferenceType : Int32
+ {
+ InvalidRefType = 0,
+ LocalRefType = 1,
+ GlobalRefType = 2,
+ WeakGlobalRefType = 3
+ }
+}
diff --git a/src/LibRyujinx/Jni/JReleaseMode.cs b/src/LibRyujinx/Jni/JReleaseMode.cs
new file mode 100644
index 000000000..4a86b5a0b
--- /dev/null
+++ b/src/LibRyujinx/Jni/JReleaseMode.cs
@@ -0,0 +1,10 @@
+using System;
+namespace LibRyujinx.Jni
+{
+ public enum JReleaseMode : Int32
+ {
+ Free = 0,
+ Commit = 1,
+ Abort = 2,
+ }
+}
diff --git a/src/LibRyujinx/Jni/JResult.cs b/src/LibRyujinx/Jni/JResult.cs
new file mode 100644
index 000000000..d3cdddff9
--- /dev/null
+++ b/src/LibRyujinx/Jni/JResult.cs
@@ -0,0 +1,14 @@
+using System;
+namespace LibRyujinx.Jni
+{
+ public enum JResult : Int32
+ {
+ Ok = 0,
+ Error = -1,
+ DetachedThreadError = -2,
+ VersionError = -3,
+ MemoryError = -4,
+ ExitingVMError = -5,
+ InvalidArgumentsError = -6,
+ }
+}
diff --git a/src/LibRyujinx/Jni/Pointers/CCharSequence.cs b/src/LibRyujinx/Jni/Pointers/CCharSequence.cs
new file mode 100644
index 000000000..d52bcf6f4
--- /dev/null
+++ b/src/LibRyujinx/Jni/Pointers/CCharSequence.cs
@@ -0,0 +1,36 @@
+using System.Runtime.InteropServices;
+using System;
+
+using Rxmxnx.PInvoke;
+
+namespace LibRyujinx.Jni.Pointers
+{
+ public readonly struct CCharSequence : IEquatable
+ {
+ private readonly IntPtr _value;
+
+ private CCharSequence(IntPtr value) => this._value = value;
+
+ #region Operators
+ public static implicit operator CCharSequence(IntPtr value) => new(value);
+ public static implicit operator CCharSequence(Span span) => new(span.GetUnsafeIntPtr());
+ public static implicit operator CCharSequence(ReadOnlySpan readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
+
+ public static CCharSequence operator ++(CCharSequence a) => new(a._value + sizeof(Byte));
+ public static CCharSequence operator --(CCharSequence a) => new(a._value - sizeof(Byte));
+ public static Boolean operator ==(CCharSequence a, CCharSequence b) => a._value.Equals(b._value);
+ public static Boolean operator !=(CCharSequence a, CCharSequence b) => !a._value.Equals(b._value);
+ #endregion
+
+ #region Public Methods
+ public Boolean Equals(CCharSequence other) => this._value.Equals(other._value);
+ public String AsString(Int32 length = 0)
+ => length == 0 ? Marshal.PtrToStringUTF8(_value) : Marshal.PtrToStringUTF8(_value, length);
+ #endregion
+
+ #region Overrided Methods
+ public override Boolean Equals(Object obj) => obj is CCharSequence other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Pointers/JBooleanRef.cs b/src/LibRyujinx/Jni/Pointers/JBooleanRef.cs
new file mode 100644
index 000000000..6ec641f3d
--- /dev/null
+++ b/src/LibRyujinx/Jni/Pointers/JBooleanRef.cs
@@ -0,0 +1,25 @@
+using System.Runtime.CompilerServices;
+using System;
+
+using LibRyujinx.Jni.Primitives;
+
+using Rxmxnx.PInvoke;
+
+namespace LibRyujinx.Jni.Pointers
+{
+ public readonly struct JBooleanRef
+ {
+ private const Int32 JBooleanResultFalse = 0;
+ private const Int32 JBooleanResultTrue = 1;
+
+#pragma warning disable IDE0052
+ private readonly IntPtr _value;
+#pragma warning restore IDE0052
+
+ public JBooleanRef(JBoolean? jBoolean)
+ => this._value = jBoolean.HasValue ? GetJBooleanRef(jBoolean.Value) : IntPtr.Zero;
+
+ private static IntPtr GetJBooleanRef(Boolean value)
+ => value ? Unsafe.AsRef(JBooleanResultTrue).GetUnsafeIntPtr() : Unsafe.AsRef(JBooleanResultFalse).GetUnsafeIntPtr();
+ }
+}
diff --git a/src/LibRyujinx/Jni/Pointers/JCharSequence.cs b/src/LibRyujinx/Jni/Pointers/JCharSequence.cs
new file mode 100644
index 000000000..461944fc5
--- /dev/null
+++ b/src/LibRyujinx/Jni/Pointers/JCharSequence.cs
@@ -0,0 +1,33 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Pointers
+{
+ public readonly struct JCharSequence : IEquatable
+ {
+ private readonly IntPtr _value;
+
+ private JCharSequence(IntPtr value) => this._value = value;
+
+ #region Operators
+ public static implicit operator JCharSequence(IntPtr value) => new(value);
+ public static implicit operator JCharSequence(Span span) => new(span.GetUnsafeIntPtr());
+ public static implicit operator JCharSequence(ReadOnlySpan readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
+
+ public static JCharSequence operator ++(JCharSequence a) => new(a._value + sizeof(Char));
+ public static JCharSequence operator --(JCharSequence a) => new(a._value - sizeof(Char));
+ public static Boolean operator ==(JCharSequence a, JCharSequence b) => a._value.Equals(b._value);
+ public static Boolean operator !=(JCharSequence a, JCharSequence b) => !a._value.Equals(b._value);
+ #endregion
+
+ #region Public Methods
+ public Boolean Equals(JCharSequence other) => this._value.Equals(other._value);
+ public String AsString(Int32 length = 0) => this._value.GetUnsafeString(length);
+ #endregion
+
+ #region Overrided Methods
+ public override Boolean Equals(Object obj) => obj is JCharSequence other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Pointers/JEnvRef.cs b/src/LibRyujinx/Jni/Pointers/JEnvRef.cs
new file mode 100644
index 000000000..f58c25d5e
--- /dev/null
+++ b/src/LibRyujinx/Jni/Pointers/JEnvRef.cs
@@ -0,0 +1,32 @@
+using LibRyujinx.Jni.Values;
+
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Pointers
+{
+ public readonly struct JEnvRef : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Operators
+ public static Boolean operator ==(JEnvRef a, JEnvRef b) => a._value.Equals(b._value);
+ public static Boolean operator !=(JEnvRef a, JEnvRef b) => !a._value.Equals(b._value);
+ #endregion
+
+ #region Public Properties
+ internal readonly ref JEnvValue Environment => ref this._value.GetUnsafeReference();
+ #endregion
+
+ #region Public Methods
+ public Boolean Equals(JEnvRef other) => this._value.Equals(other._value);
+ #endregion
+
+ #region Overrided Methods
+ public override Boolean Equals(Object obj) => obj is JEnvRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Pointers/JNativeMethodSequence.cs b/src/LibRyujinx/Jni/Pointers/JNativeMethodSequence.cs
new file mode 100644
index 000000000..d5508714d
--- /dev/null
+++ b/src/LibRyujinx/Jni/Pointers/JNativeMethodSequence.cs
@@ -0,0 +1,33 @@
+using LibRyujinx.Jni.Values;
+
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Pointers
+{
+ public readonly struct JNativeMethodSequence : IEquatable
+ {
+ private readonly IntPtr _value;
+
+ private JNativeMethodSequence(IntPtr value) => this._value = value;
+
+ #region Operators
+ public static implicit operator JNativeMethodSequence(IntPtr value) => new(value);
+ public static implicit operator JNativeMethodSequence(ReadOnlySpan readonlySpan) => new(readonlySpan.GetUnsafeIntPtr());
+
+ public static JNativeMethodSequence operator ++(JNativeMethodSequence a) => new(a._value + JValue.Size);
+ public static JNativeMethodSequence operator --(JNativeMethodSequence a) => new(a._value - JValue.Size);
+ public static Boolean operator ==(JNativeMethodSequence a, JNativeMethodSequence b) => a._value.Equals(b._value);
+ public static Boolean operator !=(JNativeMethodSequence a, JNativeMethodSequence b) => !a._value.Equals(b._value);
+ #endregion
+
+ #region Public Methods
+ public Boolean Equals(JNativeMethodSequence other) => this._value.Equals(other._value);
+ #endregion
+
+ #region Overrided Methods
+ public override Boolean Equals(Object obj) => obj is JNativeMethodSequence other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Pointers/JValueSequence.cs b/src/LibRyujinx/Jni/Pointers/JValueSequence.cs
new file mode 100644
index 000000000..caa65ac9b
--- /dev/null
+++ b/src/LibRyujinx/Jni/Pointers/JValueSequence.cs
@@ -0,0 +1,33 @@
+using LibRyujinx.Jni.Values;
+
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Internal.Pointers
+{
+ internal readonly struct JValueSequence : IEquatable
+ {
+ private readonly IntPtr _value;
+
+ private JValueSequence(IntPtr value) => this._value = value;
+ internal JValueSequence(ReadOnlySpan readonlySpan) : this(readonlySpan.GetUnsafeIntPtr()) { }
+
+ #region Operators
+ public static implicit operator JValueSequence(IntPtr value) => new(value);
+
+ public static JValueSequence operator ++(JValueSequence a) => new(a._value + JValue.Size);
+ public static JValueSequence operator --(JValueSequence a) => new(a._value - JValue.Size);
+ public static Boolean operator ==(JValueSequence a, JValueSequence b) => a._value.Equals(b._value);
+ public static Boolean operator !=(JValueSequence a, JValueSequence b) => !a._value.Equals(b._value);
+ #endregion
+
+ #region Public Methods
+ public Boolean Equals(JValueSequence other) => this._value.Equals(other._value);
+ #endregion
+
+ #region Overrided Methods
+ public override Boolean Equals(Object obj) => obj is JValueSequence other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Pointers/JavaVMRef.cs b/src/LibRyujinx/Jni/Pointers/JavaVMRef.cs
new file mode 100644
index 000000000..27ba389f1
--- /dev/null
+++ b/src/LibRyujinx/Jni/Pointers/JavaVMRef.cs
@@ -0,0 +1,25 @@
+using System;
+
+namespace LibRyujinx.Jni.Pointers
+{
+ public readonly struct JavaVMRef : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Operators
+ public static Boolean operator ==(JavaVMRef a, JavaVMRef b) => a._value.Equals(b._value);
+ public static Boolean operator !=(JavaVMRef a, JavaVMRef b) => !a._value.Equals(b._value);
+ #endregion
+
+ #region Public Methods
+ public Boolean Equals(JavaVMRef other) => this._value.Equals(other._value);
+ #endregion
+
+ #region Overrided Methods
+ public override Boolean Equals(Object obj) => obj is JavaVMRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JBoolean.cs b/src/LibRyujinx/Jni/Primitives/JBoolean.cs
new file mode 100644
index 000000000..88b4b7dba
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JBoolean.cs
@@ -0,0 +1,67 @@
+using LibRyujinx.Jni.Pointers;
+
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JBoolean : IComparable, IEquatable
+ {
+ internal static readonly Type Type = typeof(JBoolean);
+ private static readonly Byte trueByte = 1;
+ private static readonly Byte falseByte = 2;
+
+ public static readonly CString Signature = (CString)"Z";
+
+ private readonly Byte _value;
+ private Boolean Value => this._value == trueByte;
+
+ private JBoolean(Boolean value) => this._value = value ? trueByte : falseByte;
+
+ #region Operators
+ public static implicit operator JBoolean(Boolean value) => new(value);
+ public static implicit operator Boolean(JBoolean jValue) => jValue._value == 1;
+ public static implicit operator JBooleanRef(JBoolean? jValue) => new(jValue);
+ public static JBoolean operator !(JBoolean a) => new(!a.Value);
+ public static JBoolean operator |(JBoolean a, JBoolean b) => new(a.Value || b.Value);
+ public static JBoolean operator |(Boolean a, JBoolean b) => new(a || b.Value);
+ public static JBoolean operator |(JBoolean a, Boolean b) => new(a.Value || b);
+ public static JBoolean operator &(JBoolean a, JBoolean b) => new(a.Value && b.Value);
+ public static JBoolean operator &(Boolean a, JBoolean b) => new(a && b.Value);
+ public static JBoolean operator &(JBoolean a, Boolean b) => new(a.Value && b);
+ public static Boolean operator ==(JBoolean a, JBoolean b) => a._value.Equals(b._value);
+ public static Boolean operator ==(Boolean a, JBoolean b) => a.Equals(b._value);
+ public static Boolean operator ==(JBoolean a, Boolean b) => a._value.Equals(b);
+ public static Boolean operator !=(JBoolean a, JBoolean b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(Boolean a, JBoolean b) => !a.Equals(b._value);
+ public static Boolean operator !=(JBoolean a, Boolean b) => !a._value.Equals(b);
+ public static Boolean operator >(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(Boolean a, JBoolean b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JBoolean a, Boolean b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(Boolean a, JBoolean b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JBoolean a, Boolean b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(Boolean a, JBoolean b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JBoolean a, Boolean b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JBoolean a, JBoolean b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(Boolean a, JBoolean b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JBoolean a, Boolean b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(Boolean other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JBoolean other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JBoolean jvalue ? this.CompareTo(jvalue) : obj is Boolean value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(Boolean other) => this._value.Equals(other);
+ public Boolean Equals(JBoolean other) => this._value.Equals(other._value);
+ public String ToString(IFormatProvider formatProvider) => this._value.ToString(formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JBoolean jvalue ? this.Equals(jvalue) : obj is Boolean value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JByte.cs b/src/LibRyujinx/Jni/Primitives/JByte.cs
new file mode 100644
index 000000000..a5ed5b0a4
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JByte.cs
@@ -0,0 +1,74 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JByte : IComparable, IEquatable, IFormattable
+ {
+ internal static readonly Type Type = typeof(JByte);
+
+ public static readonly CString Signature = (CString)"B";
+
+ private readonly SByte _value;
+
+ private JByte(SByte value) => this._value = value;
+ private JByte(Int32 value) => this._value = Convert.ToSByte(value);
+
+ #region Operators
+ public static implicit operator JByte(SByte value) => new(value);
+ public static implicit operator SByte(JByte jValue) => jValue._value;
+ public static JByte operator +(JByte a) => a;
+ public static JByte operator ++(JByte a) => new(a._value + 1);
+ public static JByte operator -(JByte a) => new(-a._value);
+ public static JByte operator --(JByte a) => new(a._value - 1);
+ public static JByte operator +(JByte a, JByte b) => new(a._value + b._value);
+ public static JByte operator +(SByte a, JByte b) => new(a + b._value);
+ public static JByte operator +(JByte a, SByte b) => new(a._value + b);
+ public static JByte operator -(JByte a, JByte b) => new(a._value - b._value);
+ public static JByte operator -(SByte a, JByte b) => new(a - b._value);
+ public static JByte operator -(JByte a, SByte b) => new(a._value - b);
+ public static JByte operator *(JByte a, JByte b) => new(a._value * b._value);
+ public static JByte operator *(SByte a, JByte b) => new(a * b._value);
+ public static JByte operator *(JByte a, SByte b) => new(a._value * b);
+ public static JByte operator /(JByte a, JByte b) => new(a._value / b._value);
+ public static JByte operator /(SByte a, JByte b) => new(a / b._value);
+ public static JByte operator /(JByte a, SByte b) => new(a._value / b);
+ public static JByte operator %(JByte a, JByte b) => new(a._value % b._value);
+ public static JByte operator %(SByte a, JByte b) => new(a % b._value);
+ public static JByte operator %(JByte a, SByte b) => new(a._value % b);
+ public static Boolean operator ==(JByte a, JByte b) => a._value.Equals(b._value);
+ public static Boolean operator ==(SByte a, JByte b) => a.Equals(b._value);
+ public static Boolean operator ==(JByte a, SByte b) => a._value.Equals(b);
+ public static Boolean operator !=(JByte a, JByte b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(SByte a, JByte b) => !a.Equals(b._value);
+ public static Boolean operator !=(JByte a, SByte b) => !a._value.Equals(b);
+ public static Boolean operator >(JByte a, JByte b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(SByte a, JByte b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JByte a, SByte b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JByte a, JByte b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(SByte a, JByte b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JByte a, SByte b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JByte a, JByte b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(SByte a, JByte b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JByte a, SByte b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JByte a, JByte b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(SByte a, JByte b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JByte a, SByte b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(SByte other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JByte other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JByte jValue ? this.CompareTo(jValue) : obj is SByte value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(SByte other) => this._value.Equals(other);
+ public Boolean Equals(JByte other) => this._value.Equals(other._value);
+ public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JByte jvalue ? this.Equals(jvalue) : obj is SByte value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JChar.cs b/src/LibRyujinx/Jni/Primitives/JChar.cs
new file mode 100644
index 000000000..b2ba3782d
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JChar.cs
@@ -0,0 +1,56 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JChar : IComparable, IEquatable
+ {
+ internal static readonly Type Type = typeof(JChar);
+
+ public static readonly CString Signature = (CString)"C";
+
+ private readonly Char _value;
+
+ private JChar(Char value) => this._value = value;
+
+ #region Operators
+ public static implicit operator JChar(Char value) => new(value);
+ public static explicit operator JChar(Int16 value) => new((Char)value);
+ public static implicit operator Char(JChar jValue) => jValue._value;
+ public static explicit operator Int16(JChar jValue) => (Int16)jValue._value;
+ public static Boolean operator ==(JChar a, JChar b) => a._value.Equals(b._value);
+ public static Boolean operator ==(Char a, JChar b) => a.Equals(b._value);
+ public static Boolean operator ==(JChar a, Char b) => a._value.Equals(b);
+ public static Boolean operator !=(JChar a, JChar b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(Char a, JChar b) => !a.Equals(b._value);
+ public static Boolean operator !=(JChar a, Char b) => !a._value.Equals(b);
+ public static Boolean operator >(JChar a, JChar b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(Char a, JChar b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JChar a, Char b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JChar a, JChar b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(Char a, JChar b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JChar a, Char b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JChar a, JChar b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(Char a, JChar b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JChar a, Char b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JChar a, JChar b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(Char a, JChar b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JChar a, Char b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(Char other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JChar other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JChar jvalue ? this.CompareTo(jvalue) : obj is Char value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(Char other) => this._value.Equals(other);
+ public Boolean Equals(JChar other) => this._value.Equals(other._value);
+ public String ToString(IFormatProvider formatProvider) => this._value.ToString(formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JChar jvalue ? this.Equals(jvalue) : obj is Char value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JDouble.cs b/src/LibRyujinx/Jni/Primitives/JDouble.cs
new file mode 100644
index 000000000..94f05eb9a
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JDouble.cs
@@ -0,0 +1,70 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JDouble : IComparable, IEquatable, IFormattable
+ {
+ internal static readonly Type Type = typeof(JDouble);
+
+ public static readonly CString Signature = (CString)"D";
+
+ private readonly Double _value;
+
+ private JDouble(Double value) => this._value = value;
+
+ #region Operators
+ public static implicit operator JDouble(Double value) => new(value);
+ public static implicit operator Double(JDouble jValue) => jValue._value;
+ public static JDouble operator +(JDouble a) => a;
+ public static JDouble operator ++(JDouble a) => new(a._value + 1);
+ public static JDouble operator -(JDouble a) => new(-a._value);
+ public static JDouble operator --(JDouble a) => new(a._value - 1);
+ public static JDouble operator +(JDouble a, JDouble b) => new(a._value + b._value);
+ public static JDouble operator +(Double a, JDouble b) => new(a + b._value);
+ public static JDouble operator +(JDouble a, Double b) => new(a._value + b);
+ public static JDouble operator -(JDouble a, JDouble b) => new(a._value - b._value);
+ public static JDouble operator -(Double a, JDouble b) => new(a - b._value);
+ public static JDouble operator -(JDouble a, Double b) => new(a._value - b);
+ public static JDouble operator *(JDouble a, JDouble b) => new(a._value * b._value);
+ public static JDouble operator *(Double a, JDouble b) => new(a * b._value);
+ public static JDouble operator *(JDouble a, Double b) => new(a._value * b);
+ public static JDouble operator /(JDouble a, JDouble b) => new(a._value / b._value);
+ public static JDouble operator /(Double a, JDouble b) => new(a / b._value);
+ public static JDouble operator /(JDouble a, Double b) => new(a._value / b);
+ public static Boolean operator ==(JDouble a, JDouble b) => a._value.Equals(b._value);
+ public static Boolean operator ==(Double a, JDouble b) => a.Equals(b._value);
+ public static Boolean operator ==(JDouble a, Double b) => a._value.Equals(b);
+ public static Boolean operator !=(JDouble a, JDouble b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(Double a, JDouble b) => !a.Equals(b._value);
+ public static Boolean operator !=(JDouble a, Double b) => !a._value.Equals(b);
+ public static Boolean operator >(JDouble a, JDouble b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(Double a, JDouble b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JDouble a, Double b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JDouble a, JDouble b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(Double a, JDouble b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JDouble a, Double b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JDouble a, JDouble b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(Double a, JDouble b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JDouble a, Double b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JDouble a, JDouble b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(Double a, JDouble b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JDouble a, Double b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(Double other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JDouble other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JDouble jvalue ? this.CompareTo(jvalue) : obj is Double value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(Double other) => this._value.Equals(other);
+ public Boolean Equals(JDouble other) => this._value.Equals(other._value);
+ public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JDouble jvalue ? this.Equals(jvalue) : obj is Double value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JFloat.cs b/src/LibRyujinx/Jni/Primitives/JFloat.cs
new file mode 100644
index 000000000..52f833241
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JFloat.cs
@@ -0,0 +1,70 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JFloat : IComparable, IEquatable, IFormattable
+ {
+ internal static readonly Type Type = typeof(JFloat);
+
+ public static readonly CString Signature = (CString)"F";
+
+ private readonly Single _value;
+
+ private JFloat(Single value) => this._value = value;
+
+ #region Operators
+ public static implicit operator JFloat(Single value) => new(value);
+ public static implicit operator Single(JFloat jValue) => jValue._value;
+ public static JFloat operator +(JFloat a) => a;
+ public static JFloat operator ++(JFloat a) => new(a._value + 1);
+ public static JFloat operator -(JFloat a) => new(-a._value);
+ public static JFloat operator --(JFloat a) => new(a._value - 1);
+ public static JFloat operator +(JFloat a, JFloat b) => new(a._value + b._value);
+ public static JFloat operator +(Single a, JFloat b) => new(a + b._value);
+ public static JFloat operator +(JFloat a, Single b) => new(a._value + b);
+ public static JFloat operator -(JFloat a, JFloat b) => new(a._value - b._value);
+ public static JFloat operator -(Single a, JFloat b) => new(a - b._value);
+ public static JFloat operator -(JFloat a, Single b) => new(a._value - b);
+ public static JFloat operator *(JFloat a, JFloat b) => new(a._value * b._value);
+ public static JFloat operator *(Single a, JFloat b) => new(a * b._value);
+ public static JFloat operator *(JFloat a, Single b) => new(a._value * b);
+ public static JFloat operator /(JFloat a, JFloat b) => new(a._value / b._value);
+ public static JFloat operator /(Single a, JFloat b) => new(a / b._value);
+ public static JFloat operator /(JFloat a, Single b) => new(a._value / b);
+ public static Boolean operator ==(JFloat a, JFloat b) => a._value.Equals(b._value);
+ public static Boolean operator ==(Single a, JFloat b) => a.Equals(b._value);
+ public static Boolean operator ==(JFloat a, Single b) => a._value.Equals(b);
+ public static Boolean operator !=(JFloat a, JFloat b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(Single a, JFloat b) => !a.Equals(b._value);
+ public static Boolean operator !=(JFloat a, Single b) => !a._value.Equals(b);
+ public static Boolean operator >(JFloat a, JFloat b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(Single a, JFloat b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JFloat a, Single b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JFloat a, JFloat b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(Single a, JFloat b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JFloat a, Single b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JFloat a, JFloat b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(Single a, JFloat b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JFloat a, Single b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JFloat a, JFloat b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(Single a, JFloat b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JFloat a, Single b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(Single other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JFloat other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JFloat jvalue ? this.CompareTo(jvalue) : obj is Single value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(Single other) => this._value.Equals(other);
+ public Boolean Equals(JFloat other) => this._value.Equals(other._value);
+ public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JFloat jvalue ? this.Equals(jvalue) : obj is Single value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JInt.cs b/src/LibRyujinx/Jni/Primitives/JInt.cs
new file mode 100644
index 000000000..adf86a8d7
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JInt.cs
@@ -0,0 +1,73 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JInt : IComparable, IEquatable, IFormattable
+ {
+ internal static readonly Type Type = typeof(JInt);
+
+ public static readonly CString Signature = (CString)"I";
+
+ private readonly Int32 _value;
+
+ private JInt(Int32 value) => this._value = value;
+
+ #region Operators
+ public static implicit operator JInt(Int32 value) => new(value);
+ public static implicit operator Int32(JInt jValue) => jValue._value;
+ public static JInt operator +(JInt a) => a;
+ public static JInt operator ++(JInt a) => new(a._value + 1);
+ public static JInt operator -(JInt a) => new(-a._value);
+ public static JInt operator --(JInt a) => new(a._value - 1);
+ public static JInt operator +(JInt a, JInt b) => new(a._value + b._value);
+ public static JInt operator +(Int32 a, JInt b) => new(a + b._value);
+ public static JInt operator +(JInt a, Int32 b) => new(a._value + b);
+ public static JInt operator -(JInt a, JInt b) => new(a._value - b._value);
+ public static JInt operator -(Int32 a, JInt b) => new(a - b._value);
+ public static JInt operator -(JInt a, Int32 b) => new(a._value - b);
+ public static JInt operator *(JInt a, JInt b) => new(a._value * b._value);
+ public static JInt operator *(Int32 a, JInt b) => new(a * b._value);
+ public static JInt operator *(JInt a, Int32 b) => new(a._value * b);
+ public static JInt operator /(JInt a, JInt b) => new(a._value / b._value);
+ public static JInt operator /(Int32 a, JInt b) => new(a / b._value);
+ public static JInt operator /(JInt a, Int32 b) => new(a._value / b);
+ public static JInt operator %(JInt a, JInt b) => new(a._value % b._value);
+ public static JInt operator %(Int32 a, JInt b) => new(a % b._value);
+ public static JInt operator %(JInt a, Int32 b) => new(a._value % b);
+ public static Boolean operator ==(JInt a, JInt b) => a._value.Equals(b._value);
+ public static Boolean operator ==(Int32 a, JInt b) => a.Equals(b._value);
+ public static Boolean operator ==(JInt a, Int32 b) => a._value.Equals(b);
+ public static Boolean operator !=(JInt a, JInt b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(Int32 a, JInt b) => !a.Equals(b._value);
+ public static Boolean operator !=(JInt a, Int32 b) => !a._value.Equals(b);
+ public static Boolean operator >(JInt a, JInt b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(Int32 a, JInt b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JInt a, Int32 b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JInt a, JInt b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(Int32 a, JInt b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JInt a, Int32 b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JInt a, JInt b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(Int32 a, JInt b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JInt a, Int32 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JInt a, JInt b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(Int32 a, JInt b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JInt a, Int32 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(Int32 other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JInt other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JInt jValue ? this.CompareTo(jValue) : obj is Int32 value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(Int32 other) => this._value.Equals(other);
+ public Boolean Equals(JInt other) => this._value.Equals(other._value);
+ public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JInt jvalue ? this.Equals(jvalue) : obj is Int32 value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JLong.cs b/src/LibRyujinx/Jni/Primitives/JLong.cs
new file mode 100644
index 000000000..a5bd6613a
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JLong.cs
@@ -0,0 +1,73 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JLong : IComparable, IEquatable, IFormattable
+ {
+ internal static readonly Type Type = typeof(JLong);
+
+ public static readonly CString Signature = (CString)"J";
+
+ private readonly Int64 _value;
+
+ private JLong(Int64 value) => this._value = value;
+
+ #region Operators
+ public static implicit operator JLong(Int64 value) => new(value);
+ public static implicit operator Int64(JLong jValue) => jValue._value;
+ public static JLong operator +(JLong a) => a;
+ public static JLong operator ++(JLong a) => new(a._value + 1);
+ public static JLong operator -(JLong a) => new(-a._value);
+ public static JLong operator --(JLong a) => new(a._value - 1);
+ public static JLong operator +(JLong a, JLong b) => new(a._value + b._value);
+ public static JLong operator +(Int64 a, JLong b) => new(a + b._value);
+ public static JLong operator +(JLong a, Int64 b) => new(a._value + b);
+ public static JLong operator -(JLong a, JLong b) => new(a._value - b._value);
+ public static JLong operator -(Int64 a, JLong b) => new(a - b._value);
+ public static JLong operator -(JLong a, Int64 b) => new(a._value - b);
+ public static JLong operator *(JLong a, JLong b) => new(a._value * b._value);
+ public static JLong operator *(Int64 a, JLong b) => new(a * b._value);
+ public static JLong operator *(JLong a, Int64 b) => new(a._value * b);
+ public static JLong operator /(JLong a, JLong b) => new(a._value / b._value);
+ public static JLong operator /(Int64 a, JLong b) => new(a / b._value);
+ public static JLong operator /(JLong a, Int64 b) => new(a._value / b);
+ public static JLong operator %(JLong a, JLong b) => new(a._value % b._value);
+ public static JLong operator %(Int64 a, JLong b) => new(a % b._value);
+ public static JLong operator %(JLong a, Int64 b) => new(a._value % b);
+ public static Boolean operator ==(JLong a, JLong b) => a._value.Equals(b._value);
+ public static Boolean operator ==(Int64 a, JLong b) => a.Equals(b._value);
+ public static Boolean operator ==(JLong a, Int64 b) => a._value.Equals(b);
+ public static Boolean operator !=(JLong a, JLong b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(Int64 a, JLong b) => !a.Equals(b._value);
+ public static Boolean operator !=(JLong a, Int64 b) => !a._value.Equals(b);
+ public static Boolean operator >(JLong a, JLong b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(Int64 a, JLong b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JLong a, Int64 b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JLong a, JLong b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(Int64 a, JLong b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JLong a, Int64 b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JLong a, JLong b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(Int64 a, JLong b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JLong a, Int64 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JLong a, JLong b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(Int64 a, JLong b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JLong a, Int64 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(Int64 other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JLong other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JLong jvalue ? this.CompareTo(jvalue) : obj is Int64 value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(Int64 other) => this._value.Equals(other);
+ public Boolean Equals(JLong other) => this._value.Equals(other._value);
+ public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JLong jvalue ? this.Equals(jvalue) : obj is Int64 value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Primitives/JShort.cs b/src/LibRyujinx/Jni/Primitives/JShort.cs
new file mode 100644
index 000000000..78650c2fe
--- /dev/null
+++ b/src/LibRyujinx/Jni/Primitives/JShort.cs
@@ -0,0 +1,74 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Primitives
+{
+ public readonly struct JShort : IComparable, IEquatable, IFormattable
+ {
+ internal static readonly Type Type = typeof(JShort);
+
+ public static readonly CString Signature = (CString)"S";
+
+ private readonly Int16 _value;
+
+ private JShort(Int16 value) => this._value = value;
+ private JShort(Int32 value) => this._value = Convert.ToInt16(value);
+
+ #region Operators
+ public static implicit operator JShort(Int16 value) => new(value);
+ public static implicit operator Int16(JShort jValue) => jValue._value;
+ public static JShort operator +(JShort a) => a;
+ public static JShort operator ++(JShort a) => new(a._value + 1);
+ public static JShort operator -(JShort a) => new(-a._value);
+ public static JShort operator --(JShort a) => new(a._value - 1);
+ public static JShort operator +(JShort a, JShort b) => new(a._value + b._value);
+ public static JShort operator +(Int16 a, JShort b) => new(a + b._value);
+ public static JShort operator +(JShort a, Int16 b) => new(a._value + b);
+ public static JShort operator -(JShort a, JShort b) => new(a._value - b._value);
+ public static JShort operator -(Int16 a, JShort b) => new(a - b._value);
+ public static JShort operator -(JShort a, Int16 b) => new(a._value - b);
+ public static JShort operator *(JShort a, JShort b) => new(a._value * b._value);
+ public static JShort operator *(Int16 a, JShort b) => new(a * b._value);
+ public static JShort operator *(JShort a, Int16 b) => new(a._value * b);
+ public static JShort operator /(JShort a, JShort b) => new(a._value / b._value);
+ public static JShort operator /(Int16 a, JShort b) => new(a / b._value);
+ public static JShort operator /(JShort a, Int16 b) => new(a._value / b);
+ public static JShort operator %(JShort a, JShort b) => new(a._value % b._value);
+ public static JShort operator %(Int16 a, JShort b) => new(a % b._value);
+ public static JShort operator %(JShort a, Int16 b) => new(a._value % b);
+ public static Boolean operator ==(JShort a, JShort b) => a._value.Equals(b._value);
+ public static Boolean operator ==(Int16 a, JShort b) => a.Equals(b._value);
+ public static Boolean operator ==(JShort a, Int16 b) => a._value.Equals(b);
+ public static Boolean operator !=(JShort a, JShort b) => !a._value.Equals(b._value);
+ public static Boolean operator !=(Int16 a, JShort b) => !a.Equals(b._value);
+ public static Boolean operator !=(JShort a, Int16 b) => !a._value.Equals(b);
+ public static Boolean operator >(JShort a, JShort b) => a._value.CompareTo(b._value) > 0;
+ public static Boolean operator >(Int16 a, JShort b) => a.CompareTo(b._value) > 0;
+ public static Boolean operator >(JShort a, Int16 b) => a._value.CompareTo(b) > 0;
+ public static Boolean operator <(JShort a, JShort b) => a._value.CompareTo(b._value) < 0;
+ public static Boolean operator <(Int16 a, JShort b) => a.CompareTo(b._value) < 0;
+ public static Boolean operator <(JShort a, Int16 b) => a._value.CompareTo(b) < 0;
+ public static Boolean operator >=(JShort a, JShort b) => a._value.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(Int16 a, JShort b) => a.CompareTo(b._value) > 0 || a.Equals(b._value);
+ public static Boolean operator >=(JShort a, Int16 b) => a._value.CompareTo(b) > 0 || a._value.Equals(b);
+ public static Boolean operator <=(JShort a, JShort b) => a._value.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(Int16 a, JShort b) => a.CompareTo(b._value) < 0 || a.Equals(b._value);
+ public static Boolean operator <=(JShort a, Int16 b) => a._value.CompareTo(b) < 0 || a._value.Equals(b);
+ #endregion
+
+ #region Public Methods
+ public Int32 CompareTo(Int16 other) => this._value.CompareTo(other);
+ public Int32 CompareTo(JShort other) => this._value.CompareTo(other._value);
+ public Int32 CompareTo(Object obj) => obj is JShort jvalue ? this.CompareTo(jvalue) : obj is Int16 value ? this.CompareTo(value) : this._value.CompareTo(obj);
+ public Boolean Equals(Int16 other) => this._value.Equals(other);
+ public Boolean Equals(JShort other) => this._value.Equals(other._value);
+ public String ToString(String format, IFormatProvider formatProvider) => this._value.ToString(format, formatProvider);
+ #endregion
+
+ #region Overrided Methods
+ public override String ToString() => this._value.ToString();
+ public override Boolean Equals(Object obj) => obj is JShort jvalue ? this.Equals(jvalue) : obj is Int16 value ? this.Equals(value) : this._value.Equals(obj);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/References/JArrayLocalRef.cs b/src/LibRyujinx/Jni/References/JArrayLocalRef.cs
new file mode 100644
index 000000000..6501b4360
--- /dev/null
+++ b/src/LibRyujinx/Jni/References/JArrayLocalRef.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.References
+{
+ public readonly struct JArrayLocalRef : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly JObjectLocalRef _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JArrayLocalRef other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JArrayLocalRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JArrayLocalRef a, JArrayLocalRef b) => a.Equals(b);
+ public static Boolean operator !=(JArrayLocalRef a, JArrayLocalRef b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/References/JClassLocalRef.cs b/src/LibRyujinx/Jni/References/JClassLocalRef.cs
new file mode 100644
index 000000000..5880f5ddb
--- /dev/null
+++ b/src/LibRyujinx/Jni/References/JClassLocalRef.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.References
+{
+ public readonly struct JClassLocalRef : IEquatable
+ {
+#pragma warning disable 0649
+ public readonly JObjectLocalRef _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JClassLocalRef other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JClassLocalRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JClassLocalRef a, JClassLocalRef b) => a.Equals(b);
+ public static Boolean operator !=(JClassLocalRef a, JClassLocalRef b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/References/JGlobalRef.cs b/src/LibRyujinx/Jni/References/JGlobalRef.cs
new file mode 100644
index 000000000..1befe7b94
--- /dev/null
+++ b/src/LibRyujinx/Jni/References/JGlobalRef.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.References
+{
+ public readonly struct JGlobalRef : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JGlobalRef other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JGlobalRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JGlobalRef a, JGlobalRef b) => a.Equals(b);
+ public static Boolean operator !=(JGlobalRef a, JGlobalRef b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/References/JObjectLocalRef.cs b/src/LibRyujinx/Jni/References/JObjectLocalRef.cs
new file mode 100644
index 000000000..ff1953137
--- /dev/null
+++ b/src/LibRyujinx/Jni/References/JObjectLocalRef.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.References
+{
+ public readonly struct JObjectLocalRef : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JObjectLocalRef other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JObjectLocalRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JObjectLocalRef a, JObjectLocalRef b) => a.Equals(b);
+ public static Boolean operator !=(JObjectLocalRef a, JObjectLocalRef b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/References/JStringLocalRef.cs b/src/LibRyujinx/Jni/References/JStringLocalRef.cs
new file mode 100644
index 000000000..002fd9942
--- /dev/null
+++ b/src/LibRyujinx/Jni/References/JStringLocalRef.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.References
+{
+ public readonly struct JStringLocalRef : IEquatable
+ {
+#pragma warning disable 0649
+ public readonly JObjectLocalRef _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JStringLocalRef other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JStringLocalRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JStringLocalRef a, JStringLocalRef b) => a.Equals(b);
+ public static Boolean operator !=(JStringLocalRef a, JStringLocalRef b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/References/JThrowableLocalRef.cs b/src/LibRyujinx/Jni/References/JThrowableLocalRef.cs
new file mode 100644
index 000000000..a7e5e3b40
--- /dev/null
+++ b/src/LibRyujinx/Jni/References/JThrowableLocalRef.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.References
+{
+ public readonly struct JThrowableLocalRef : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JThrowableLocalRef other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JThrowableLocalRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JThrowableLocalRef a, JThrowableLocalRef b) => a.Equals(b);
+ public static Boolean operator !=(JThrowableLocalRef a, JThrowableLocalRef b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/References/JWeakRef.cs b/src/LibRyujinx/Jni/References/JWeakRef.cs
new file mode 100644
index 000000000..9572c6035
--- /dev/null
+++ b/src/LibRyujinx/Jni/References/JWeakRef.cs
@@ -0,0 +1,28 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.References
+{
+ public readonly struct JWeakRef : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Public Methods
+ public Boolean Equals(JWeakRef other)
+ => this._value.Equals(other._value);
+ #endregion
+
+ #region Override Methods
+ public override Boolean Equals([NotNullWhen(true)] Object obj)
+ => obj is JWeakRef other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+
+ #region Operators
+ public static Boolean operator ==(JWeakRef a, JWeakRef b) => a.Equals(b);
+ public static Boolean operator !=(JWeakRef a, JWeakRef b) => !a.Equals(b);
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JEnvValue.cs b/src/LibRyujinx/Jni/Values/JEnvValue.cs
new file mode 100644
index 000000000..dc4d8a17b
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JEnvValue.cs
@@ -0,0 +1,30 @@
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ internal readonly struct JEnvValue : IEquatable
+ {
+#pragma warning disable 0649
+ private readonly IntPtr _value;
+#pragma warning restore 0649
+
+ #region Operators
+ public static Boolean operator ==(JEnvValue a, JEnvValue b) => a._value.Equals(b._value);
+ public static Boolean operator !=(JEnvValue a, JEnvValue b) => !a._value.Equals(b._value);
+ #endregion
+
+ #region Public Properties
+ internal readonly ref JNativeInterface Functions => ref this._value.GetUnsafeReference();
+ #endregion
+
+ #region Public Methods
+ public Boolean Equals(JEnvValue other) => this._value.Equals(other._value);
+ #endregion
+
+ #region Overrided Methods
+ public override Boolean Equals(Object obj) => obj is JEnvValue other && this.Equals(other);
+ public override Int32 GetHashCode() => this._value.GetHashCode();
+ #endregion
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JInvokeInterface.cs b/src/LibRyujinx/Jni/Values/JInvokeInterface.cs
new file mode 100644
index 000000000..14473c574
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JInvokeInterface.cs
@@ -0,0 +1,20 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "This struct is created only by binary operations.")]
+ public readonly struct JInvokeInterface
+ {
+#pragma warning disable 0169
+ private readonly IntPtr _reserved0;
+ private readonly IntPtr _reserved1;
+ private readonly IntPtr _reserved2;
+#pragma warning restore 0169
+ internal IntPtr DestroyJavaVMPointer { get; init; }
+ internal IntPtr AttachCurrentThreadPointer { get; init; }
+ internal IntPtr DetachCurrentThreadPointer { get; init; }
+ internal IntPtr GetEnvPointer { get; init; }
+ internal IntPtr AttachCurrentThreadAsDaemonPointer { get; init; }
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JNativeInterface.cs b/src/LibRyujinx/Jni/Values/JNativeInterface.cs
new file mode 100644
index 000000000..b3aa132ec
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JNativeInterface.cs
@@ -0,0 +1,245 @@
+using System.Diagnostics.CodeAnalysis;
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ [SuppressMessage("CodeQuality", "IDE0051:Remove unused private members", Justification = "This struct is created only by binary operations.")]
+ public readonly struct JNativeInterface
+ {
+#pragma warning disable 0169
+ private readonly IntPtr _reserved0;
+ private readonly IntPtr _reserved1;
+ private readonly IntPtr _reserved2;
+ private readonly IntPtr _reserved3;
+#pragma warning restore 0169
+ internal readonly IntPtr GetVersionPointer { get; init; }
+ internal readonly IntPtr DefineClassPointer { get; init; }
+ internal readonly IntPtr FindClassPointer { get; init; }
+ internal readonly IntPtr FromReflectedMethodPointer { get; init; }
+ internal readonly IntPtr FromReflectedFieldPointer { get; init; }
+ internal readonly IntPtr ToReflectedMethodPointer { get; init; }
+ internal readonly IntPtr GetSuperclassPointer { get; init; }
+ internal readonly IntPtr IsAssignableFromPointer { get; init; }
+ internal readonly IntPtr ToReflectedFieldPointer { get; init; }
+ internal readonly IntPtr ThrowPointer { get; init; }
+ internal readonly IntPtr ThrowNewPointer { get; init; }
+ internal readonly IntPtr ExceptionOccurredPointer { get; init; }
+ internal readonly IntPtr ExceptionDescribePointer { get; init; }
+ internal readonly IntPtr ExceptionClearPointer { get; init; }
+ internal readonly IntPtr FatalErrorPointer { get; init; }
+ internal readonly IntPtr PushLocalFramePointer { get; init; }
+ internal readonly IntPtr PopLocalFramePointer { get; init; }
+ internal readonly IntPtr NewGlobalRefPointer { get; init; }
+ internal readonly IntPtr DeleteGlobalRefPointer { get; init; }
+ internal readonly IntPtr DeleteLocalRefPointer { get; init; }
+ internal readonly IntPtr IsSameObjectPointer { get; init; }
+ internal readonly IntPtr NewLocalRefPointer { get; init; }
+ internal readonly IntPtr EnsureLocalCapacityPointer { get; init; }
+ internal readonly IntPtr AllocObjectPointer { get; init; }
+ internal readonly IntPtr NewObjectPointer { get; init; }
+ internal readonly IntPtr NewObjectVPointer { get; init; }
+ internal readonly IntPtr NewObjectAPointer { get; init; }
+ internal readonly IntPtr GetObjectClassPointer { get; init; }
+ internal readonly IntPtr IsInstanceOfPointer { get; init; }
+ internal readonly IntPtr GetMethodIdPointer { get; init; }
+ internal readonly IntPtr CallObjectMethodPointer { get; init; }
+ internal readonly IntPtr CallObjectMethodVPointer { get; init; }
+ internal readonly IntPtr CallObjectMethodAPointer { get; init; }
+ internal readonly IntPtr CallBooleanMethodPointer { get; init; }
+ internal readonly IntPtr CallBooleanMethodVPointer { get; init; }
+ internal readonly IntPtr CallBooleanMethodAPointer { get; init; }
+ internal readonly IntPtr CallByteMethodPointer { get; init; }
+ internal readonly IntPtr CallByteMethodVPointer { get; init; }
+ internal readonly IntPtr CallByteMethodAPointer { get; init; }
+ internal readonly IntPtr CallCharMethodPointer { get; init; }
+ internal readonly IntPtr CallCharMethodVPointer { get; init; }
+ internal readonly IntPtr CallCharMethodAPointer { get; init; }
+ internal readonly IntPtr CallShortMethodPointer { get; init; }
+ internal readonly IntPtr CallShortMethodVPointer { get; init; }
+ internal readonly IntPtr CallShortMethodAPointer { get; init; }
+ internal readonly IntPtr CallIntMethodPointer { get; init; }
+ internal readonly IntPtr CallIntMethodVPointer { get; init; }
+ internal readonly IntPtr CallIntMethodAPointer { get; init; }
+ internal readonly IntPtr CallLongMethodPointer { get; init; }
+ internal readonly IntPtr CallLongMethodVPointer { get; init; }
+ internal readonly IntPtr CallLongMethodAPointer { get; init; }
+ internal readonly IntPtr CallFloatMethodPointer { get; init; }
+ internal readonly IntPtr CallFloatMethodVPointer { get; init; }
+ internal readonly IntPtr CallFloatMethodAPointer { get; init; }
+ internal readonly IntPtr CallDoubleMethodPointer { get; init; }
+ internal readonly IntPtr CallDoubleMethodVPointer { get; init; }
+ internal readonly IntPtr CallDoubleMethodAPointer { get; init; }
+ internal readonly IntPtr CallVoidMethodPointer { get; init; }
+ internal readonly IntPtr CallVoidMethodVPointer { get; init; }
+ internal readonly IntPtr CallVoidMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualObjectMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualObjectMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualObjectMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualBooleanMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualBooleanMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualBooleanMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualByteMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualByteMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualByteMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualCharMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualCharMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualCharMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualShortMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualShortMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualShortMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualIntMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualIntMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualIntMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualLongMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualLongMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualLongMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualFloatMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualFloatMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualFloatMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualDoubleMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualDoubleMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualDoubleMethodAPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualVoidMethodPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualVoidMethodVPointer { get; init; }
+ internal readonly IntPtr CallNonVirtualVoidMethodAPointer { get; init; }
+ internal readonly IntPtr GetFieldIdPointer { get; init; }
+ internal readonly IntPtr GetObjectFieldPointer { get; init; }
+ internal readonly IntPtr GetBooleanFieldPointer { get; init; }
+ internal readonly IntPtr GetByteFieldPointer { get; init; }
+ internal readonly IntPtr GetCharFieldPointer { get; init; }
+ internal readonly IntPtr GetShortFieldPointer { get; init; }
+ internal readonly IntPtr GetIntFieldPointer { get; init; }
+ internal readonly IntPtr GetLongFieldPointer { get; init; }
+ internal readonly IntPtr GetFloatFieldPointer { get; init; }
+ internal readonly IntPtr GetDoubleFieldPointer { get; init; }
+ internal readonly IntPtr SetObjectFieldPointer { get; init; }
+ internal readonly IntPtr SetBooleanFieldPointer { get; init; }
+ internal readonly IntPtr SetByteFieldPointer { get; init; }
+ internal readonly IntPtr SetCharFieldPointer { get; init; }
+ internal readonly IntPtr SetShortFieldPointer { get; init; }
+ internal readonly IntPtr SetIntFieldPointer { get; init; }
+ internal readonly IntPtr SetLongFieldPointer { get; init; }
+ internal readonly IntPtr SetFloatFieldPointer { get; init; }
+ internal readonly IntPtr SetDoubleFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticMethodIdPointer { get; init; }
+ internal readonly IntPtr CallStaticObjectMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticObjectMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticObjectMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticBooleanMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticBooleanMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticBooleanMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticByteMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticByteMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticByteMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticCharMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticCharMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticCharMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticShortMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticShortMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticShortMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticIntMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticIntMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticIntMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticLongMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticLongMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticLongMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticFloatMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticFloatMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticFloatMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticDoubleMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticDoubleMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticDoubleMethodAPointer { get; init; }
+ internal readonly IntPtr CallStaticVoidMethodPointer { get; init; }
+ internal readonly IntPtr CallStaticVoidMethodVPointer { get; init; }
+ internal readonly IntPtr CallStaticVoidMethodAPointer { get; init; }
+ internal readonly IntPtr GetStaticFieldIdPointer { get; init; }
+ internal readonly IntPtr GetStaticObjectFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticBooleanFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticByteFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticCharFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticShortFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticIntFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticLongFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticFloatFieldPointer { get; init; }
+ internal readonly IntPtr GetStaticDoubleFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticObjectFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticBooleanFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticByteFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticCharFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticShortFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticIntFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticLongFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticFloatFieldPointer { get; init; }
+ internal readonly IntPtr SetStaticDoubleFieldPointer { get; init; }
+ internal readonly IntPtr NewStringPointer { get; init; }
+ internal readonly IntPtr GetStringLengthPointer { get; init; }
+ internal readonly IntPtr GetStringCharsPointer { get; init; }
+ internal readonly IntPtr ReleaseStringCharsPointer { get; init; }
+ internal readonly IntPtr NewStringUtfPointer { get; init; }
+ internal readonly IntPtr GetStringUtfLengthPointer { get; init; }
+ internal readonly IntPtr GetStringUtfCharsPointer { get; init; }
+ internal readonly IntPtr ReleaseStringUtfCharsPointer { get; init; }
+ internal readonly IntPtr GetArrayLengthPointer { get; init; }
+ internal readonly IntPtr NewObjectArrayPointer { get; init; }
+ internal readonly IntPtr GetObjectArrayElementPointer { get; init; }
+ internal readonly IntPtr SetObjectArrayElementPointer { get; init; }
+ internal readonly IntPtr NewBooleanArrayPointer { get; init; }
+ internal readonly IntPtr NewByteArrayPointer { get; init; }
+ internal readonly IntPtr NewCharArrayPointer { get; init; }
+ internal readonly IntPtr NewShortArrayPointer { get; init; }
+ internal readonly IntPtr NewIntArrayPointer { get; init; }
+ internal readonly IntPtr NewLongArrayPointer { get; init; }
+ internal readonly IntPtr NewFloatArrayPointer { get; init; }
+ internal readonly IntPtr NewDoubleArrayPointer { get; init; }
+ internal readonly IntPtr GetBooleanArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetByteArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetCharArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetShortArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetIntArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetLongArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetFloatArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetDoubleArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseBooleanArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseByteArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseCharArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseShortArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseIntArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseLongArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseFloatArrayElementsPointer { get; init; }
+ internal readonly IntPtr ReleaseDoubleArrayElementsPointer { get; init; }
+ internal readonly IntPtr GetBooleanArrayRegionPointer { get; init; }
+ internal readonly IntPtr GetByteArrayRegionPointer { get; init; }
+ internal readonly IntPtr GetCharArrayRegionPointer { get; init; }
+ internal readonly IntPtr GetShortArrayRegionPointer { get; init; }
+ internal readonly IntPtr GetIntArrayRegionPointer { get; init; }
+ internal readonly IntPtr GetLongArrayRegionPointer { get; init; }
+ internal readonly IntPtr GetFloatArrayRegionPointer { get; init; }
+ internal readonly IntPtr GetDoubleArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetBooleanArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetByteArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetCharArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetShortArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetIntArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetLongArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetFloatArrayRegionPointer { get; init; }
+ internal readonly IntPtr SetDoubleArrayRegionPointer { get; init; }
+ internal readonly IntPtr RegisterNativesPointer { get; init; }
+ internal readonly IntPtr UnregisterNativesPointer { get; init; }
+ internal readonly IntPtr MonitorEnterPointer { get; init; }
+ internal readonly IntPtr MonitorExitPointer { get; init; }
+ internal readonly IntPtr GetJavaVMPointer { get; init; }
+ internal readonly IntPtr GetStringRegionPointer { get; init; }
+ internal readonly IntPtr GetStringUtfRegionPointer { get; init; }
+ internal readonly IntPtr GetPrimitiveArrayCriticalPointer { get; init; }
+ internal readonly IntPtr ReleasePrimitiveArrayCriticalPointer { get; init; }
+ internal readonly IntPtr GetStringCriticalPointer { get; init; }
+ internal readonly IntPtr ReleaseStringCriticalPointer { get; init; }
+ internal readonly IntPtr NewWeakGlobalRefPointer { get; init; }
+ internal readonly IntPtr DeleteWeakGlobalRefPointer { get; init; }
+ internal readonly IntPtr ExceptionCheckPointer { get; init; }
+ internal readonly IntPtr NewDirectByteBufferPointer { get; init; }
+ internal readonly IntPtr GetDirectBufferAddressPointer { get; init; }
+ internal readonly IntPtr GetDirectBufferCapacityPointer { get; init; }
+ internal readonly IntPtr GetObjectRefTypePointer { get; init; }
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JNativeMethod.cs b/src/LibRyujinx/Jni/Values/JNativeMethod.cs
new file mode 100644
index 000000000..10315071e
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JNativeMethod.cs
@@ -0,0 +1,12 @@
+using LibRyujinx.Jni.Pointers;
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ public readonly struct JNativeMethod
+ {
+ internal CCharSequence Name { get; init; }
+ internal CCharSequence Signature { get; init; }
+ internal IntPtr Pointer { get; init; }
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JValue.cs b/src/LibRyujinx/Jni/Values/JValue.cs
new file mode 100644
index 000000000..c482b85ad
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JValue.cs
@@ -0,0 +1,44 @@
+using System.Runtime.CompilerServices;
+
+using Rxmxnx.PInvoke;
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ internal readonly struct JValue
+ {
+ private delegate Boolean IsDefaultDelegate(in JValue value);
+
+ public static readonly Int32 Size = NativeUtilities.SizeOf();
+
+ private static readonly IsDefaultDelegate isDefault = GetIsDefault();
+
+#pragma warning disable 0649
+#pragma warning disable 0169
+ private readonly Byte _value1;
+ private readonly Byte _value2;
+ private readonly Int16 _value3;
+ private readonly Int32 _value4;
+#pragma warning restore 0169
+#pragma warning restore 0649
+
+ public Boolean IsDefault => isDefault(this);
+
+ public static JValue Create(ReadOnlySpan source)
+ {
+ Byte[] result = new Byte[Size];
+ for (Int32 i = 0; i < source.Length; i++)
+ result[i] = source[i];
+ return result.ToValue();
+ }
+
+ private static IsDefaultDelegate GetIsDefault() => Environment.Is64BitProcess ? DefaultLong : Default;
+
+ private static Boolean Default(in JValue jValue)
+ => (jValue._value1 + jValue._value2 + jValue._value3) == default
+ && jValue._value4 == default;
+
+ private static Boolean DefaultLong(in JValue jValue) =>
+ Unsafe.AsRef(jValue).Transform() == default;
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JavaVMAttachArgs.cs b/src/LibRyujinx/Jni/Values/JavaVMAttachArgs.cs
new file mode 100644
index 000000000..d8b827c4d
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JavaVMAttachArgs.cs
@@ -0,0 +1,13 @@
+using LibRyujinx.Jni.Pointers;
+using LibRyujinx.Jni.References;
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ public readonly struct JavaVMAttachArgs
+ {
+ internal Int32 Version { get; init; }
+ internal CCharSequence Name { get; init; }
+ internal JObjectLocalRef Group { get; init; }
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JavaVMInitArgs.cs b/src/LibRyujinx/Jni/Values/JavaVMInitArgs.cs
new file mode 100644
index 000000000..d9fa6d161
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JavaVMInitArgs.cs
@@ -0,0 +1,12 @@
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ public readonly struct JavaVMInitArgs
+ {
+ internal Int32 Version { get; init; }
+ internal Int32 OptionsLenght { get; init; }
+ internal IntPtr Options { get; init; }
+ internal Boolean IgnoreUnrecognized { get; init; }
+ }
+}
diff --git a/src/LibRyujinx/Jni/Values/JavaVMOption.cs b/src/LibRyujinx/Jni/Values/JavaVMOption.cs
new file mode 100644
index 000000000..153fc64c3
--- /dev/null
+++ b/src/LibRyujinx/Jni/Values/JavaVMOption.cs
@@ -0,0 +1,11 @@
+using LibRyujinx.Jni.Pointers;
+using System;
+
+namespace LibRyujinx.Jni.Values
+{
+ public readonly struct JavaVMOption
+ {
+ internal CCharSequence Name { get; init; }
+ internal IntPtr ExtraInfo { get; init; }
+ }
+}
diff --git a/src/LibRyujinx/JniExportedMethods.cs b/src/LibRyujinx/JniExportedMethods.cs
new file mode 100644
index 000000000..c27e488f1
--- /dev/null
+++ b/src/LibRyujinx/JniExportedMethods.cs
@@ -0,0 +1,404 @@
+using System;
+using System.Runtime.InteropServices;
+using Ryujinx.Common.Configuration;
+using System.Collections.Generic;
+using LibRyujinx.Jni.Pointers;
+using LibRyujinx.Jni.References;
+using LibRyujinx.Jni.Values;
+using LibRyujinx.Jni.Primitives;
+using LibRyujinx.Jni;
+using Rxmxnx.PInvoke;
+using System.Text;
+using LibRyujinx.Jni.Internal.Pointers;
+using Ryujinx.Common.Logging;
+using Ryujinx.Common.Logging.Targets;
+using Silk.NET.Vulkan;
+using Silk.NET.Vulkan.Extensions.KHR;
+using LibRyujinx.Shared.Audio.Oboe;
+using System.Threading;
+using System.IO;
+using Microsoft.Win32.SafeHandles;
+using Newtonsoft.Json.Linq;
+using System.Security.Cryptography;
+
+namespace LibRyujinx
+{
+ public static partial class LibRyujinx
+ {
+ private static ManualResetEvent _surfaceEvent;
+ private static long _surfacePtr;
+
+ [DllImport("libryujinxjni")]
+ private extern static IntPtr getStringPointer(JEnvRef jEnv, JStringLocalRef s);
+
+ public delegate IntPtr JniCreateSurface(IntPtr native_surface, IntPtr instance);
+
+ [UnmanagedCallersOnly(EntryPoint = "JNI_OnLoad")]
+ internal static int LoadLibrary(JavaVMRef vm, IntPtr unknown)
+ {
+ return 0x00010006; //JNI_VERSION_1_6
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_initialize")]
+ public static JBoolean JniInitialize(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef jpath)
+ {
+ var path = GetString(jEnv, jpath);
+
+ Ryujinx.Common.SystemInfo.SystemInfo.IsBionic = true;
+
+ var init = Initialize(path);
+
+ AudioDriver = new OboeHardwareDeviceDriver();
+
+ _surfaceEvent = new ManualResetEvent(false);
+
+ Logger.AddTarget(
+ new AsyncLogTargetWrapper(
+ new AndroidLogTarget("Ryujinx"),
+ 1000,
+ AsyncLogTargetOverflowAction.Block
+ ));
+
+ return init;
+ }
+
+ private static string GetString(JEnvRef jEnv, JStringLocalRef jString)
+ {
+ var stringPtr = getStringPointer(jEnv, jString);
+
+ var s = Marshal.PtrToStringAnsi(stringPtr);
+ Marshal.FreeHGlobal(stringPtr);
+ return s;
+ }
+
+ private static JStringLocalRef CreateString(string str, JEnvRef jEnv)
+ {
+ return str.AsSpan().WithSafeFixed(jEnv, CreateString);
+ }
+
+
+ private static JStringLocalRef CreateString(in IReadOnlyFixedContext ctx, JEnvRef jEnv)
+ {
+ JEnvValue value = jEnv.Environment;
+ ref JNativeInterface jInterface = ref value.Functions;
+
+ IntPtr newStringPtr = jInterface.NewStringPointer;
+ NewStringDelegate newString = newStringPtr.GetUnsafeDelegate();
+
+ return newString(jEnv, ctx.Pointer, ctx.Values.Length);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceInitialize")]
+ public static JBoolean JniInitializeDeviceNative(JEnvRef jEnv, JObjectLocalRef jObj, JBoolean isHostMapped)
+ {
+ return InitializeDevice(isHostMapped);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoad")]
+ public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JStringLocalRef pathPtr)
+ {
+ if (SwitchDevice?.EmulationContext == null)
+ {
+ return false;
+ }
+
+ var path = GetString(jEnv, pathPtr);
+
+ return LoadApplication(path);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceLoadDescriptor")]
+ public static JBoolean JniLoadApplicationNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt descriptor, JBoolean isXci)
+ {
+ if (SwitchDevice?.EmulationContext == null)
+ {
+ return false;
+ }
+
+ var stream = OpenFile(descriptor);
+
+ return LoadApplication(stream, isXci);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsInitialize")]
+ public static JBoolean JniInitializeGraphicsNative(JEnvRef jEnv, JObjectLocalRef jObj, JObjectLocalRef graphicObject)
+ {
+ JEnvValue value = jEnv.Environment;
+ ref JNativeInterface jInterface = ref value.Functions;
+ IntPtr getObjectClassPtr = jInterface.GetObjectClassPointer;
+ IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
+ IntPtr getIntFieldPtr = jInterface.GetIntFieldPointer;
+ IntPtr getLongFieldPtr = jInterface.GetLongFieldPointer;
+ IntPtr getFloatFieldPtr = jInterface.GetFloatFieldPointer;
+ IntPtr getBooleanFieldPtr = jInterface.GetBooleanFieldPointer;
+
+ var getObjectClass = getObjectClassPtr.GetUnsafeDelegate();
+ var getFieldId = getFieldIdPtr.GetUnsafeDelegate();
+ var getLongField = getLongFieldPtr.GetUnsafeDelegate();
+ var getIntField = getIntFieldPtr.GetUnsafeDelegate();
+ var getBooleanField = getBooleanFieldPtr.GetUnsafeDelegate();
+ var getFloatField = getFloatFieldPtr.GetUnsafeDelegate();
+
+ var jobject = getObjectClass(jEnv, graphicObject);
+
+ GraphicsConfiguration graphicsConfiguration = new GraphicsConfiguration()
+ {
+ EnableShaderCache = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableShaderCache"), GetCCharSequence("Z"))),
+ EnableMacroHLE = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableMacroHLE"), GetCCharSequence("Z"))),
+ EnableMacroJit = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableMacroJit"), GetCCharSequence("Z"))),
+ EnableTextureRecompression = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("EnableTextureRecompression"), GetCCharSequence("Z"))),
+ Fast2DCopy = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("Fast2DCopy"), GetCCharSequence("Z"))),
+ FastGpuTime = getBooleanField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("FastGpuTime"), GetCCharSequence("Z"))),
+ ResScale = getFloatField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("ResScale"), GetCCharSequence("F"))),
+ MaxAnisotropy = getFloatField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("MaxAnisotropy"), GetCCharSequence("F"))),
+ BackendThreading = (BackendThreading)(int)getIntField(jEnv, graphicObject, getFieldId(jEnv, jobject, GetCCharSequence("BackendThreading"), GetCCharSequence("I")))
+ };
+ Silk.NET.Core.Loader.SearchPathContainer.Platform = Silk.NET.Core.Loader.UnderlyingPlatform.Android;
+ return InitializeGraphics(graphicsConfiguration);
+ }
+
+ private static CCharSequence GetCCharSequence(string s)
+ {
+ return (CCharSequence)Encoding.UTF8.GetBytes(s).AsSpan();
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsSetSurface")]
+ public unsafe static void JniSetSurface(JEnvRef jEnv, JObjectLocalRef jObj, JLong surfacePtr)
+ {
+ _surfacePtr = surfacePtr;
+
+ _surfaceEvent.Set();
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsInitializeRenderer")]
+ public unsafe static JBoolean JniInitializeGraphicsRendererNative(JEnvRef jEnv, JObjectLocalRef jObj, JArrayLocalRef extensionsArray, JLong surfacePtr)
+ {
+ if (Renderer != null)
+ {
+ return false;
+ }
+
+ JEnvValue value = jEnv.Environment;
+ ref JNativeInterface jInterface = ref value.Functions;
+ IntPtr getObjectClassPtr = jInterface.GetObjectClassPointer;
+ IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
+ IntPtr getLongFieldPtr = jInterface.GetLongFieldPointer;
+ IntPtr getArrayLengthPtr = jInterface.GetArrayLengthPointer;
+ IntPtr getObjectArrayElementPtr = jInterface.GetObjectArrayElementPointer;
+ IntPtr getObjectFieldPtr = jInterface.GetObjectFieldPointer;
+
+ var getObjectClass = getObjectClassPtr.GetUnsafeDelegate();
+ var getFieldId = getFieldIdPtr.GetUnsafeDelegate();
+ var getArrayLength = getArrayLengthPtr.GetUnsafeDelegate();
+ var getObjectArrayElement = getObjectArrayElementPtr.GetUnsafeDelegate();
+ var getLongField = getLongFieldPtr.GetUnsafeDelegate();
+ var getObjectField = getObjectFieldPtr.GetUnsafeDelegate();
+
+ List extensions = new List();
+
+ var count = getArrayLength(jEnv, extensionsArray);
+
+ for(int i = 0; i < count; i++)
+ {
+ var obj = getObjectArrayElement(jEnv, extensionsArray, i);
+ var ext = obj.Transform();
+
+ extensions.Add(GetString(jEnv, ext));
+ }
+
+ _surfaceEvent.Set();
+
+ _surfacePtr = (long)surfacePtr;
+
+ CreateSurface createSurfaceFunc = (IntPtr instance) =>
+ {
+ _surfaceEvent.WaitOne();
+ _surfaceEvent.Reset();
+
+ var api = Vk.GetApi();
+ if (api.TryGetInstanceExtension(new Instance(instance), out KhrAndroidSurface surfaceExtension))
+ {
+ var createInfo = new AndroidSurfaceCreateInfoKHR()
+ {
+ SType = StructureType.AndroidSurfaceCreateInfoKhr,
+ Window = (nint*)_surfacePtr
+ };
+
+ var result = surfaceExtension.CreateAndroidSurface(new Instance(instance), createInfo, null, out var surface);
+
+ return (nint)surface.Handle;
+ }
+
+ return IntPtr.Zero;
+ };
+
+ return InitializeGraphicsRenderer(GraphicsBackend.Vulkan, createSurfaceFunc, extensions.ToArray());
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetSize")]
+ public static void JniSetRendererSizeNative(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
+ {
+ Renderer?.Window?.SetSize(width, height);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererRunLoop")]
+ public static void JniRunLoopNative(JEnvRef jEnv, JObjectLocalRef jObj)
+ {
+ RunLoop();
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_deviceGetGameInfo")]
+ public static JObjectLocalRef JniGetGameInfo(JEnvRef jEnv, JObjectLocalRef jObj, JInt fileDescriptor, JBoolean isXci)
+ {
+ using var stream = OpenFile(fileDescriptor);
+
+ var info = GetGameInfo(stream, isXci) ?? new GameInfo();
+
+ var javaClassName = GetCCharSequence("org/ryujinx/android/viewmodels/GameInfo");
+
+ JEnvValue value = jEnv.Environment;
+ ref JNativeInterface jInterface = ref value.Functions;
+ IntPtr findClassPtr = jInterface.FindClassPointer;
+ IntPtr newGlobalRefPtr = jInterface.NewGlobalRefPointer;
+ IntPtr getFieldIdPtr = jInterface.GetFieldIdPointer;
+ IntPtr getMethodPtr = jInterface.GetMethodIdPointer;
+ IntPtr newObjectPtr = jInterface.NewObjectPointer;
+ IntPtr setObjectFieldPtr = jInterface.SetObjectFieldPointer;
+ IntPtr setDoubleFieldPtr = jInterface.SetDoubleFieldPointer;
+
+
+ var findClass = findClassPtr.GetUnsafeDelegate();
+ var newGlobalRef = newGlobalRefPtr.GetUnsafeDelegate ();
+ var getFieldId = getFieldIdPtr.GetUnsafeDelegate();
+ var getMethod = getMethodPtr.GetUnsafeDelegate();
+ var newObject = newObjectPtr.GetUnsafeDelegate();
+ var setObjectField = setObjectFieldPtr.GetUnsafeDelegate();
+ var setDoubleField = setDoubleFieldPtr.GetUnsafeDelegate();
+
+ var javaClass = findClass(jEnv, javaClassName);
+ var newGlobal = newGlobalRef(jEnv, javaClass._value);
+ var constructor = getMethod(jEnv, javaClass, GetCCharSequence(""), GetCCharSequence("()V"));
+ var newObj = newObject(jEnv, javaClass, constructor, 0);
+
+ using var sha = SHA256.Create();
+
+ var iconCacheByte = sha.ComputeHash(info.Icon ?? new byte[0]);
+ var iconCache = BitConverter.ToString(iconCacheByte).Replace("-", "");
+
+ var cacheDirectory = Path.Combine(AppDataManager.BaseDirPath, "iconCache");
+ Directory.CreateDirectory(cacheDirectory);
+
+ var cachePath = Path.Combine(cacheDirectory, iconCache);
+ if (!File.Exists(cachePath))
+ {
+ File.WriteAllBytes(cachePath, info.Icon ?? new byte[0]);
+ }
+
+ setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleName"), GetCCharSequence("Ljava/lang/String;")), CreateString(info.TitleName, jEnv)._value);
+ setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("TitleId"), GetCCharSequence("Ljava/lang/String;")), CreateString(info.TitleId, jEnv)._value);
+ setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Developer"), GetCCharSequence("Ljava/lang/String;")), CreateString(info.Developer, jEnv)._value);
+ setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("Version"), GetCCharSequence("Ljava/lang/String;")), CreateString(info.Version, jEnv)._value);
+ setObjectField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("IconCache"), GetCCharSequence("Ljava/lang/String;")), CreateString(iconCache, jEnv)._value);
+ setDoubleField(jEnv, newObj, getFieldId(jEnv, javaClass, GetCCharSequence("FileSize"), GetCCharSequence("D")), info.FileSize);
+
+ return newObj;
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetVsync")]
+ public static void JniSetVsyncStateNative(JEnvRef jEnv, JObjectLocalRef jObj, JBoolean enabled)
+ {
+ SetVsyncState(enabled);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_graphicsRendererSetSwapBufferCallback")]
+ public static void JniSetSwapBuffersCallbackNative(JEnvRef jEnv, JObjectLocalRef jObj, IntPtr swapBuffersCallback)
+ {
+ _swapBuffersCallback = Marshal.GetDelegateForFunctionPointer(swapBuffersCallback);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputInitialize")]
+ public static void JniInitializeInput(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
+ {
+ InitializeInput(width, height);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetClientSize")]
+ public static void JniSetClientSize(JEnvRef jEnv, JObjectLocalRef jObj, JInt width, JInt height)
+ {
+ SetClientSize(width, height);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetTouchPoint")]
+ public static void JniSetTouchPoint(JEnvRef jEnv, JObjectLocalRef jObj, JInt x, JInt y)
+ {
+ SetTouchPoint(x, y);
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputReleaseTouchPoint")]
+ public static void JniReleaseTouchPoint(JEnvRef jEnv, JObjectLocalRef jObj)
+ {
+ ReleaseTouchPoint();
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputUpdate")]
+ public static void JniUpdateInput(JEnvRef jEnv, JObjectLocalRef jObj)
+ {
+ UpdateInput();
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonPressed")]
+ public static void JniSetButtonPressed(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JStringLocalRef id)
+ {
+ SetButtonPressed((Ryujinx.Input.GamepadButtonInputId)(int)button, GetString(jEnv, id));
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetButtonReleased")]
+ public static void JniSetButtonReleased(JEnvRef jEnv, JObjectLocalRef jObj, JInt button, JStringLocalRef id)
+ {
+ SetButtonReleased((Ryujinx.Input.GamepadButtonInputId)(int)button, GetString(jEnv, id));
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputSetStickAxis")]
+ public static void JniSetStickAxis(JEnvRef jEnv, JObjectLocalRef jObj, JInt stick, JFloat x, JFloat y, JStringLocalRef id)
+ {
+ SetStickAxis((Ryujinx.Input.StickInputId)(int)stick, new System.Numerics.Vector2(x, y), GetString(jEnv, id));
+ }
+
+ [UnmanagedCallersOnly(EntryPoint = "Java_org_ryujinx_android_RyujinxNative_inputConnectGamepad")]
+ public static JStringLocalRef JniConnectGamepad(JEnvRef jEnv, JObjectLocalRef jObj, JInt index)
+ {
+ var id = ConnectGamepad(index);
+
+ return (id ?? "").AsSpan().WithSafeFixed(jEnv, CreateString);
+ }
+
+ private static Stream OpenFile(int descriptor)
+ {
+ var safeHandle = new SafeFileHandle(descriptor, false);
+
+ return new FileStream(safeHandle, FileAccess.Read);
+ }
+ }
+
+ internal static partial class Logcat
+ {
+ [LibraryImport("liblog", StringMarshalling = StringMarshalling.Utf8)]
+ private static partial void __android_log_print(LogLevel level, string? tag, string format, string args, IntPtr ptr);
+
+ internal static void AndroidLogPrint(LogLevel level, string? tag, string message) =>
+ __android_log_print(level, tag, "%s", message, IntPtr.Zero);
+
+ internal enum LogLevel
+ {
+ Unknown = 0x00,
+ Default = 0x01,
+ Verbose = 0x02,
+ Debug = 0x03,
+ Info = 0x04,
+ Warn = 0x05,
+ Error = 0x06,
+ Fatal = 0x07,
+ Silent = 0x08
+ }
+ }
+}
diff --git a/src/LibRyujinx/rd.xml b/src/LibRyujinx/rd.xml
index b1cecb007..2faf502ad 100644
--- a/src/LibRyujinx/rd.xml
+++ b/src/LibRyujinx/rd.xml
@@ -15,6 +15,8 @@
+
-
+
\ No newline at end of file
diff --git a/src/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs b/src/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs
index b1cffcb56..2ff49526a 100644
--- a/src/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs
+++ b/src/Ryujinx.Common/Logging/Formatters/DefaultLogFormatter.cs
@@ -3,7 +3,7 @@ using System.Text;
namespace Ryujinx.Common.Logging.Formatters
{
- internal class DefaultLogFormatter : ILogFormatter
+ public class DefaultLogFormatter : ILogFormatter
{
private static readonly ObjectPool _stringBuilderPool = SharedPools.Default();