android: Implement amiibo reading from nfc tag
This commit is contained in:
		| @@ -13,6 +13,7 @@ | ||||
|  | ||||
|     <uses-permission android:name="android.permission.INTERNET" /> | ||||
|     <uses-permission android:name="android.permission.FOREGROUND_SERVICE" /> | ||||
|     <uses-permission android:name="android.permission.NFC" /> | ||||
|  | ||||
|     <application | ||||
|         android:name="org.yuzu.yuzu_emu.YuzuApplication" | ||||
| @@ -48,7 +49,19 @@ | ||||
|             android:name="org.yuzu.yuzu_emu.activities.EmulationActivity" | ||||
|             android:theme="@style/Theme.Yuzu.Main" | ||||
|             android:launchMode="singleTop" | ||||
|             android:screenOrientation="userLandscape" /> | ||||
|             android:screenOrientation="userLandscape" | ||||
|             android:exported="true"> | ||||
|  | ||||
|             <intent-filter> | ||||
|                 <action android:name="android.nfc.action.TECH_DISCOVERED" /> | ||||
|                 <category android:name="android.intent.category.DEFAULT" /> | ||||
|                 <data android:mimeType="application/octet-stream" /> | ||||
|             </intent-filter> | ||||
|  | ||||
|             <meta-data | ||||
|                 android:name="android.nfc.action.TECH_DISCOVERED" | ||||
|                 android:resource="@xml/nfc_tech_filter" /> | ||||
|         </activity> | ||||
|  | ||||
|         <service android:name="org.yuzu.yuzu_emu.utils.ForegroundService"/> | ||||
|  | ||||
|   | ||||
| @@ -123,6 +123,18 @@ public final class NativeLibrary { | ||||
|     public static native boolean onGamePadMotionEvent(int Device, long delta_timestamp, float gyro_x, float gyro_y, | ||||
|                                                       float gyro_z, float accel_x, float accel_y, float accel_z); | ||||
|  | ||||
|     /** | ||||
|      * Signals and load a nfc tag | ||||
|      * | ||||
|      * @param data         Byte array containing all the data from a nfc tag | ||||
|      */ | ||||
|     public static native boolean onReadNfcTag(byte[] data); | ||||
|  | ||||
|     /** | ||||
|      * Removes current loaded nfc tag | ||||
|      */ | ||||
|     public static native boolean onRemoveNfcTag(); | ||||
|  | ||||
|     /** | ||||
|      * Handles touch press events. | ||||
|      * | ||||
|   | ||||
| @@ -24,6 +24,7 @@ import org.yuzu.yuzu_emu.features.settings.model.Settings | ||||
| import org.yuzu.yuzu_emu.fragments.EmulationFragment | ||||
| import org.yuzu.yuzu_emu.model.Game | ||||
| import org.yuzu.yuzu_emu.utils.ControllerMappingHelper | ||||
| import org.yuzu.yuzu_emu.utils.NfcReader | ||||
| import org.yuzu.yuzu_emu.utils.SerializableHelper.parcelable | ||||
| import org.yuzu.yuzu_emu.utils.ThemeHelper | ||||
| import kotlin.math.roundToInt | ||||
| @@ -37,6 +38,7 @@ open class EmulationActivity : AppCompatActivity() { | ||||
|     var isActivityRecreated = false | ||||
|     private var menuVisible = false | ||||
|     private var emulationFragment: EmulationFragment? = null | ||||
|     private lateinit var nfcReader: NfcReader | ||||
|  | ||||
|     private lateinit var game: Game | ||||
|  | ||||
| @@ -76,6 +78,9 @@ open class EmulationActivity : AppCompatActivity() { | ||||
|         } | ||||
|         title = game.title | ||||
|  | ||||
|         nfcReader = NfcReader(this) | ||||
|         nfcReader.initialize() | ||||
|  | ||||
|         // Start a foreground service to prevent the app from getting killed in the background | ||||
|         // TODO(bunnei): Disable notifications until we support app suspension. | ||||
|         //foregroundService = new Intent(EmulationActivity.this, ForegroundService.class); | ||||
| @@ -104,6 +109,21 @@ open class EmulationActivity : AppCompatActivity() { | ||||
|         } | ||||
|         return super.onKeyDown(keyCode, event) | ||||
|     } | ||||
|     override fun onResume() { | ||||
|         super.onResume() | ||||
|         nfcReader.startScanning() | ||||
|     } | ||||
|  | ||||
|     override fun onPause() { | ||||
|         super.onPause() | ||||
|         nfcReader.stopScanning() | ||||
|     } | ||||
|  | ||||
|     override fun onNewIntent(intent: Intent) { | ||||
|         super.onNewIntent(intent) | ||||
|         setIntent(intent) | ||||
|         nfcReader.onNewIntent(intent) | ||||
|     } | ||||
|  | ||||
|     override fun onSaveInstanceState(outState: Bundle) { | ||||
|         outState.putParcelable(EXTRA_SELECTED_GAME, game) | ||||
|   | ||||
| @@ -112,6 +112,7 @@ class MainActivity : AppCompatActivity(), MainView { | ||||
|         when (request) { | ||||
|             MainPresenter.REQUEST_ADD_DIRECTORY -> getGamesDirectory.launch(Intent(Intent.ACTION_OPEN_DOCUMENT_TREE).data) | ||||
|             MainPresenter.REQUEST_INSTALL_KEYS -> getProdKey.launch(arrayOf("*/*")) | ||||
|             MainPresenter.REQUEST_INSTALL_AMIIBO_KEYS -> getAmiiboKey.launch(arrayOf("*/*")) | ||||
|             MainPresenter.REQUEST_SELECT_GPU_DRIVER -> { | ||||
|                 // Get the driver name for the dialog message. | ||||
|                 var driverName = GpuDriverHelper.customDriverName | ||||
| @@ -221,6 +222,37 @@ class MainActivity : AppCompatActivity(), MainView { | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     private val getAmiiboKey = | ||||
|         registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> | ||||
|             if (result == null) | ||||
|                 return@registerForActivityResult | ||||
|  | ||||
|             val takeFlags = | ||||
|                 Intent.FLAG_GRANT_WRITE_URI_PERMISSION or Intent.FLAG_GRANT_READ_URI_PERMISSION | ||||
|             contentResolver.takePersistableUriPermission( | ||||
|                 result, | ||||
|                 takeFlags | ||||
|             ) | ||||
|  | ||||
|             val dstPath = DirectoryInitialization.userDirectory + "/keys/" | ||||
|             if (FileUtil.copyUriToInternalStorage(this, result, dstPath, "key_retail.bin")) { | ||||
|                 if (NativeLibrary.ReloadKeys()) { | ||||
|                     Toast.makeText( | ||||
|                         this, | ||||
|                         R.string.install_keys_success, | ||||
|                         Toast.LENGTH_SHORT | ||||
|                     ).show() | ||||
|                     refreshFragment() | ||||
|                 } else { | ||||
|                     Toast.makeText( | ||||
|                         this, | ||||
|                         R.string.install_amiibo_keys_failure, | ||||
|                         Toast.LENGTH_LONG | ||||
|                     ).show() | ||||
|                 } | ||||
|             } | ||||
|         } | ||||
|  | ||||
|     private val getDriver = | ||||
|         registerForActivityResult(ActivityResultContracts.OpenDocument()) { result -> | ||||
|             if (result == null) | ||||
|   | ||||
| @@ -36,6 +36,10 @@ class MainPresenter(private val view: MainView) { | ||||
|                 launchFileListActivity(REQUEST_INSTALL_KEYS) | ||||
|                 return true | ||||
|             } | ||||
|             R.id.button_install_amiibo_keys -> { | ||||
|                 launchFileListActivity(REQUEST_INSTALL_AMIIBO_KEYS) | ||||
|                 return true | ||||
|             } | ||||
|             R.id.button_select_gpu_driver -> { | ||||
|                 launchFileListActivity(REQUEST_SELECT_GPU_DRIVER) | ||||
|                 return true | ||||
| @@ -64,6 +68,7 @@ class MainPresenter(private val view: MainView) { | ||||
|     companion object { | ||||
|         const val REQUEST_ADD_DIRECTORY = 1 | ||||
|         const val REQUEST_INSTALL_KEYS = 2 | ||||
|         const val REQUEST_SELECT_GPU_DRIVER = 3 | ||||
|         const val REQUEST_INSTALL_AMIIBO_KEYS = 3 | ||||
|         const val REQUEST_SELECT_GPU_DRIVER = 4 | ||||
|     } | ||||
| } | ||||
|   | ||||
| @@ -0,0 +1,165 @@ | ||||
| package org.yuzu.yuzu_emu.utils | ||||
|  | ||||
| import android.app.Activity | ||||
| import android.app.PendingIntent | ||||
| import android.content.Intent | ||||
| import android.content.IntentFilter | ||||
| import android.nfc.NfcAdapter | ||||
| import android.nfc.Tag | ||||
| import android.nfc.tech.NfcA | ||||
| import android.os.Build | ||||
| import android.os.Handler | ||||
| import android.os.Looper | ||||
| import org.yuzu.yuzu_emu.NativeLibrary | ||||
| import java.io.IOException | ||||
|  | ||||
| class NfcReader(private val activity: Activity) { | ||||
|     private var nfcAdapter: NfcAdapter? = null | ||||
|     private var pendingIntent: PendingIntent? = null | ||||
|  | ||||
|     fun initialize() { | ||||
|         nfcAdapter = NfcAdapter.getDefaultAdapter(activity) ?: return | ||||
|  | ||||
|         pendingIntent = PendingIntent.getActivity( | ||||
|             activity, | ||||
|             0, Intent(activity, activity.javaClass), | ||||
|             if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.S) | ||||
|                 PendingIntent.FLAG_UPDATE_CURRENT or PendingIntent.FLAG_MUTABLE | ||||
|             else PendingIntent.FLAG_UPDATE_CURRENT | ||||
|         ) | ||||
|  | ||||
|         val tagDetected = IntentFilter(NfcAdapter.ACTION_TAG_DISCOVERED) | ||||
|         tagDetected.addCategory(Intent.CATEGORY_DEFAULT) | ||||
|     } | ||||
|  | ||||
|     fun startScanning() { | ||||
|         nfcAdapter?.enableForegroundDispatch(activity, pendingIntent, null, null) | ||||
|     } | ||||
|  | ||||
|     fun stopScanning() { | ||||
|         nfcAdapter?.disableForegroundDispatch(activity) | ||||
|     } | ||||
|  | ||||
|     fun onNewIntent(intent: Intent) { | ||||
|         val action = intent.action | ||||
|         if (NfcAdapter.ACTION_TAG_DISCOVERED != action | ||||
|             && NfcAdapter.ACTION_TECH_DISCOVERED != action | ||||
|             && NfcAdapter.ACTION_NDEF_DISCOVERED != action | ||||
|         ) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.TIRAMISU) { | ||||
|             val tag = | ||||
|                 intent.getParcelableExtra(NfcAdapter.EXTRA_TAG, Tag::class.java) ?: return | ||||
|             readTagData(tag) | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         val tag = | ||||
|             intent.getParcelableExtra<Tag>(NfcAdapter.EXTRA_TAG) ?: return | ||||
|         readTagData(tag) | ||||
|     } | ||||
|  | ||||
|     private fun readTagData(tag: Tag) { | ||||
|         if (!tag.techList.contains("android.nfc.tech.NfcA")) { | ||||
|             return | ||||
|         } | ||||
|  | ||||
|         val amiibo = NfcA.get(tag) ?: return | ||||
|         amiibo.connect() | ||||
|  | ||||
|         val tagData = ntag215ReadAll(amiibo) ?: return | ||||
|         NativeLibrary.onReadNfcTag(tagData) | ||||
|  | ||||
|         nfcAdapter?.ignore( | ||||
|             tag, | ||||
|             1000, | ||||
|             { NativeLibrary.onRemoveNfcTag() }, | ||||
|             Handler(Looper.getMainLooper()) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     private fun ntag215ReadAll(amiibo: NfcA): ByteArray? { | ||||
|         val bufferSize = amiibo.maxTransceiveLength; | ||||
|         val tagSize = 0x21C | ||||
|         val pageSize = 4 | ||||
|         val lastPage = tagSize / pageSize - 1 | ||||
|         val tagData = ByteArray(tagSize) | ||||
|  | ||||
|         // We need to read the ntag in steps otherwise we overflow the buffer | ||||
|         for (i in 0..tagSize step bufferSize - 1) { | ||||
|             val dataStart = i / pageSize | ||||
|             var dataEnd = (i + bufferSize) / pageSize | ||||
|  | ||||
|             if (dataEnd > lastPage) { | ||||
|                 dataEnd = lastPage | ||||
|             } | ||||
|  | ||||
|             try { | ||||
|                 val data = ntag215FastRead(amiibo, dataStart, dataEnd - 1) | ||||
|                 System.arraycopy(data, 0, tagData, i, (dataEnd - dataStart) * pageSize) | ||||
|             } catch (e: IOException) { | ||||
|                 return null; | ||||
|             } | ||||
|         } | ||||
|         return tagData | ||||
|     } | ||||
|  | ||||
|     private fun ntag215Read(amiibo: NfcA, page: Int): ByteArray? { | ||||
|         return amiibo.transceive( | ||||
|             byteArrayOf( | ||||
|                 0x30.toByte(), | ||||
|                 (page and 0xFF).toByte() | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     private fun ntag215FastRead(amiibo: NfcA, start: Int, end: Int): ByteArray? { | ||||
|         return amiibo.transceive( | ||||
|             byteArrayOf( | ||||
|                 0x3A.toByte(), | ||||
|                 (start and 0xFF).toByte(), | ||||
|                 (end and 0xFF).toByte() | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     private fun ntag215PWrite( | ||||
|         amiibo: NfcA, | ||||
|         page: Int, | ||||
|         data1: Int, | ||||
|         data2: Int, | ||||
|         data3: Int, | ||||
|         data4: Int | ||||
|     ): ByteArray? { | ||||
|         return amiibo.transceive( | ||||
|             byteArrayOf( | ||||
|                 0xA2.toByte(), | ||||
|                 (page and 0xFF).toByte(), | ||||
|                 (data1 and 0xFF).toByte(), | ||||
|                 (data2 and 0xFF).toByte(), | ||||
|                 (data3 and 0xFF).toByte(), | ||||
|                 (data4 and 0xFF).toByte() | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
|  | ||||
|     private fun ntag215PwdAuth( | ||||
|         amiibo: NfcA, | ||||
|         data1: Int, | ||||
|         data2: Int, | ||||
|         data3: Int, | ||||
|         data4: Int | ||||
|     ): ByteArray? { | ||||
|         return amiibo.transceive( | ||||
|             byteArrayOf( | ||||
|                 0x1B.toByte(), | ||||
|                 (data1 and 0xFF).toByte(), | ||||
|                 (data2 and 0xFF).toByte(), | ||||
|                 (data3 and 0xFF).toByte(), | ||||
|                 (data4 and 0xFF).toByte() | ||||
|             ) | ||||
|         ) | ||||
|     } | ||||
| } | ||||
| @@ -2,6 +2,7 @@ | ||||
|  | ||||
| #include "common/logging/log.h" | ||||
| #include "input_common/drivers/touch_screen.h" | ||||
| #include "input_common/drivers/virtual_amiibo.h" | ||||
| #include "input_common/drivers/virtual_gamepad.h" | ||||
| #include "input_common/main.h" | ||||
| #include "jni/emu_window/emu_window.h" | ||||
| @@ -36,7 +37,15 @@ void EmuWindow_Android::OnGamepadMotionEvent(int player_index, u64 delta_timesta | ||||
|                                              float gyro_y, float gyro_z, float accel_x, | ||||
|                                              float accel_y, float accel_z) { | ||||
|     m_input_subsystem->GetVirtualGamepad()->SetMotionState( | ||||
|         player_index, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); | ||||
|             player_index, delta_timestamp, gyro_x, gyro_y, gyro_z, accel_x, accel_y, accel_z); | ||||
| } | ||||
|  | ||||
| void EmuWindow_Android::OnReadNfcTag(std::span<u8> data) { | ||||
|     m_input_subsystem->GetVirtualAmiibo()->LoadAmiibo(data); | ||||
| } | ||||
|  | ||||
| void EmuWindow_Android::OnRemoveNfcTag() { | ||||
|     m_input_subsystem->GetVirtualAmiibo()->CloseAmiibo(); | ||||
| } | ||||
|  | ||||
| EmuWindow_Android::EmuWindow_Android(InputCommon::InputSubsystem* input_subsystem, | ||||
|   | ||||
| @@ -1,6 +1,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <memory> | ||||
| #include <span> | ||||
|  | ||||
| #include "core/frontend/emu_window.h" | ||||
| #include "core/frontend/graphics_context.h" | ||||
| @@ -39,6 +40,8 @@ public: | ||||
|     void OnGamepadJoystickEvent(int player_index, int stick_id, float x, float y); | ||||
|     void OnGamepadMotionEvent(int player_index, u64 delta_timestamp, float gyro_x, float gyro_y, | ||||
|                               float gyro_z, float accel_x, float accel_y, float accel_z); | ||||
|     void OnReadNfcTag(std::span<u8> data); | ||||
|     void OnRemoveNfcTag(); | ||||
|     void OnFrameDisplayed() override {} | ||||
|  | ||||
|     std::unique_ptr<Core::Frontend::GraphicsContext> CreateSharedContext() const override { | ||||
|   | ||||
| @@ -451,6 +451,26 @@ jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMotionEvent( | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag( | ||||
|         [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz, jbyteArray j_data) { | ||||
|     jboolean isCopy{false}; | ||||
|     std::span<u8> data(reinterpret_cast<u8 *>(env->GetByteArrayElements(j_data, &isCopy)), | ||||
|                        static_cast<size_t>(env->GetArrayLength(j_data))); | ||||
|  | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().Window().OnReadNfcTag(data); | ||||
|     } | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| jboolean Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag( | ||||
|         [[maybe_unused]] JNIEnv* env, [[maybe_unused]] jclass clazz) { | ||||
|     if (EmulationSession::GetInstance().IsRunning()) { | ||||
|         EmulationSession::GetInstance().Window().OnRemoveNfcTag(); | ||||
|     } | ||||
|     return static_cast<jboolean>(true); | ||||
| } | ||||
|  | ||||
| void Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchPressed([[maybe_unused]] JNIEnv* env, | ||||
|                                                           [[maybe_unused]] jclass clazz, jint id, | ||||
|                                                           jfloat x, jfloat y) { | ||||
|   | ||||
| @@ -32,7 +32,13 @@ JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadMoveEv | ||||
|     JNIEnv* env, jclass clazz, jstring j_device, jint axis, jfloat x, jfloat y); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onGamePadAxisEvent( | ||||
|     JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val); | ||||
|         JNIEnv* env, jclass clazz, jstring j_device, jint axis_id, jfloat axis_val); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onReadNfcTag( | ||||
|         JNIEnv* env, jclass clazz, jbyteArray j_data); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onRemoveNfcTag( | ||||
|         JNIEnv* env, jclass clazz); | ||||
|  | ||||
| JNIEXPORT jboolean JNICALL Java_org_yuzu_yuzu_1emu_NativeLibrary_onTouchEvent(JNIEnv* env, | ||||
|                                                                               jclass clazz, | ||||
|   | ||||
| @@ -22,6 +22,12 @@ | ||||
|                 android:title="@string/install_keys" | ||||
|                 app:showAsAction="ifRoom" /> | ||||
|  | ||||
|             <item | ||||
|                 android:id="@+id/button_install_amiibo_keys" | ||||
|                 android:icon="@drawable/ic_install" | ||||
|                 android:title="@string/install_amiibo_keys" | ||||
|                 app:showAsAction="ifRoom" /> | ||||
|  | ||||
|             <item | ||||
|                 android:id="@+id/button_select_gpu_driver" | ||||
|                 android:icon="@drawable/ic_settings" | ||||
|   | ||||
| @@ -52,8 +52,10 @@ | ||||
|     <!-- Add Directory Screen--> | ||||
|     <string name="select_game_folder">Select game folder</string> | ||||
|     <string name="install_keys">Install keys</string> | ||||
|     <string name="install_amiibo_keys">Install amiibo keys</string> | ||||
|     <string name="install_keys_success">Keys successfully installed</string> | ||||
|     <string name="install_keys_failure">Keys file (prod.keys) is invalid</string> | ||||
|     <string name="install_amiibo_keys_failure">Keys file (key_retail.bin) is invalid</string> | ||||
|  | ||||
|     <!-- GPU driver installation --> | ||||
|     <string name="select_gpu_driver">Select GPU driver</string> | ||||
|   | ||||
							
								
								
									
										6
									
								
								src/android/app/src/main/res/xml/nfc_tech_filter.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										6
									
								
								src/android/app/src/main/res/xml/nfc_tech_filter.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,6 @@ | ||||
| <?xml version="1.0" encoding="utf-8"?> | ||||
| <resources xmlns:xliff="urn:oasis:names:tc:xliff:document:1.2"> | ||||
|     <tech-list> | ||||
|         <tech>android.nfc.tech.NfcA</tech> | ||||
|     </tech-list> | ||||
| </resources> | ||||
| @@ -73,10 +73,7 @@ VirtualAmiibo::State VirtualAmiibo::GetCurrentState() const { | ||||
| VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { | ||||
|     const Common::FS::IOFile nfc_file{filename, Common::FS::FileAccessMode::Read, | ||||
|                                       Common::FS::FileType::BinaryFile}; | ||||
|  | ||||
|     if (state != State::WaitingForAmiibo) { | ||||
|         return Info::WrongDeviceState; | ||||
|     } | ||||
|     std::vector<u8> data{}; | ||||
|  | ||||
|     if (!nfc_file.IsOpen()) { | ||||
|         return Info::UnableToLoad; | ||||
| @@ -101,7 +98,28 @@ VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(const std::string& filename) { | ||||
|     } | ||||
|  | ||||
|     file_path = filename; | ||||
|     return LoadAmiibo(data); | ||||
| } | ||||
|  | ||||
| VirtualAmiibo::Info VirtualAmiibo::LoadAmiibo(std::span<u8> data) { | ||||
|     if (state != State::WaitingForAmiibo) { | ||||
|         return Info::WrongDeviceState; | ||||
|     } | ||||
|  | ||||
|     switch (data.size_bytes()) { | ||||
|         case AmiiboSize: | ||||
|         case AmiiboSizeWithoutPassword: | ||||
|             nfc_data.resize(AmiiboSize); | ||||
|             break; | ||||
|         case MifareSize: | ||||
|             nfc_data.resize(MifareSize); | ||||
|             break; | ||||
|         default: | ||||
|             return Info::NotAnAmiibo; | ||||
|     } | ||||
|  | ||||
|     state = State::AmiiboIsOpen; | ||||
|     memcpy(nfc_data.data(),data.data(),data.size_bytes()); | ||||
|     SetNfc(identifier, {Common::Input::NfcState::NewAmiibo, nfc_data}); | ||||
|     return Info::Success; | ||||
| } | ||||
|   | ||||
| @@ -4,6 +4,7 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <array> | ||||
| #include <span> | ||||
| #include <string> | ||||
| #include <vector> | ||||
|  | ||||
| @@ -47,6 +48,7 @@ public: | ||||
|     State GetCurrentState() const; | ||||
|  | ||||
|     Info LoadAmiibo(const std::string& amiibo_file); | ||||
|     Info LoadAmiibo(std::span<u8> data); | ||||
|     Info ReloadAmiibo(); | ||||
|     Info CloseAmiibo(); | ||||
|  | ||||
|   | ||||
		Reference in New Issue
	
	Block a user