Require complete Mac game bundles and clarify iPhone-only splitting
This commit is contained in:
1 parent
1b5ecaabb5
commit
fd93fdc308
6 files changed
+27
-8
No files matched your search
+2
-2
@@ -26,7 +26,7 @@ Cuando abra la app:
|
||||
|
||||
**Las siguientes veces:** abre **nxnative Easy.app** en la carpeta **Aplicaciones de tu usuario**. La preparación conserva su propia copia del código; puedes borrar el ZIP y la carpeta que descargaste.
|
||||
|
||||
**Mac:** crea una `.app` del juego; pulsa **Abrir juego**. No necesitas Sideloadly ni un iPhone. Las partidas quedan en `~/Library/Application Support/nxnative/<title ID>/`.
|
||||
**Mac:** crea una sola `.app` completa, con todos los datos del juego dentro; pulsa **Abrir juego**. No necesitas copiar una carpeta RomFS aparte. No necesitas Sideloadly ni un iPhone. Las partidas quedan en `~/Library/Application Support/nxnative/<title ID>/`.
|
||||
|
||||
**iPhone / iPad:** crea una IPA ligera sin firmar. Instálala con Sideloadly y copia los datos del juego como te indica la app.
|
||||
|
||||
@@ -40,7 +40,7 @@ Partimos de [seedds/nxnative](https://github.com/seedds/nxnative): el motor, los
|
||||
|
||||
- **App para Mac:** elegir juego, avance, cancelación y acceso a IPA, datos y Sideloadly.
|
||||
- **Controles editables en iPhone:** posición, tamaño y opacidad, guardados por juego y layout.
|
||||
- **IPA ligera automática:** los datos `romfs` van aparte; se conservan salidas y cachés válidas.
|
||||
- **IPA ligera sólo para iPhone/iPad:** los datos `romfs` van aparte; se conservan salidas y cachés válidas.
|
||||
- **Llaves del usuario:** debes seleccionar la carpeta de tus propias `prod.keys`. No incluimos, descargamos ni distribuimos llaves o juegos.
|
||||
- **Preparación local:** sin cuenta Apple, sin certificados de empresa y sin servicio que reciba tus archivos.
|
||||
|
||||
|
||||
@@ -26,7 +26,7 @@ When the app opens:
|
||||
|
||||
**After setup:** open **nxnative Easy.app** in your home **Applications** folder. The setup keeps its source checkout separately, so you can delete the downloaded ZIP and folder.
|
||||
|
||||
**Mac:** creates a game `.app`; click **Open game**. No Sideloadly or iPhone needed. Saves stay in `~/Library/Application Support/nxnative/<title ID>/`.
|
||||
**Mac:** creates one complete game `.app`, with its game data included inside; click **Open game**. No separate RomFS folder to copy. No Sideloadly or iPhone needed. Saves stay in `~/Library/Application Support/nxnative/<title ID>/`.
|
||||
|
||||
**iPhone / iPad:** creates an unsigned lightweight IPA; install it with Sideloadly, then copy the game data as shown in the app.
|
||||
|
||||
@@ -40,7 +40,7 @@ Built on [seedds/nxnative](https://github.com/seedds/nxnative). The original pro
|
||||
|
||||
- **Native Mac app:** game-folder selection, progress, cancellation, and buttons for the IPA, RomFS data and Sideloadly.
|
||||
- **Editable iPhone touch controls:** position, size and opacity, saved per game and 2D/3D layout.
|
||||
- **Automatic lightweight IPA export:** RomFS data live separately; existing outputs and valid caches are preserved.
|
||||
- **Lightweight IPA export for iPhone/iPad only:** RomFS data live separately; existing outputs and valid caches are preserved.
|
||||
- **Your own keys:** explicitly select the external folder containing your `prod.keys`. No games or keys are included, downloaded or distributed.
|
||||
- **Local preparation:** no Apple account or company certificate is used to build the desktop app.
|
||||
|
||||
|
||||
@@ -15,7 +15,8 @@ struct EasyStrings {
|
||||
"¿Dónde quieres jugar?": "Where do you want to play?",
|
||||
"Elige un dispositivo": "Choose a device",
|
||||
"Elige dónde quieres jugar y añade tus archivos.": "Choose where to play, then add your own files.",
|
||||
"Creamos una app para jugar en tu Mac.": "We create an app to play on your Mac.",
|
||||
"Creamos una app completa para jugar en tu Mac.": "We create a complete app to play on your Mac.",
|
||||
"Todo el juego va dentro de la app. No necesitas copiar carpetas.": "The entire game is inside the app. No folders to copy.",
|
||||
"Terminó, pero no encontramos la app.": "Finished, but the app could not be found.",
|
||||
"Tu juego está listo para Mac.": "Your game is ready for Mac.",
|
||||
"Listo. Juega en tu Mac.": "Ready. Play on your Mac.",
|
||||
|
||||
@@ -274,7 +274,7 @@ struct ContentView: View {
|
||||
}
|
||||
VStack(alignment:.leading,spacing:6) {
|
||||
Text(model.text("Prepara tu juego.")).font(.system(size:32,weight:.bold,design:.rounded)).foregroundStyle(ink)
|
||||
Text(model.text(model.isMac ? "Creamos una app para jugar en tu Mac." : "Elige dónde quieres jugar y añade tus archivos."))
|
||||
Text(model.text(model.isMac ? "Creamos una app completa para jugar en tu Mac." : "Elige dónde quieres jugar y añade tus archivos."))
|
||||
.font(.system(size:14)).foregroundStyle(.secondary)
|
||||
}
|
||||
VStack(alignment:.leading,spacing:10) {
|
||||
@@ -352,6 +352,8 @@ struct ContentView: View {
|
||||
.buttonStyle(.borderedProminent).tint(lime).foregroundStyle(.black)
|
||||
Button(model.text("Mostrar app")){model.revealIPA()}
|
||||
}
|
||||
Text(model.text("Todo el juego va dentro de la app. No necesitas copiar carpetas."))
|
||||
.font(.system(size:12)).foregroundStyle(.secondary)
|
||||
Text(model.text("Tus partidas se guardan en este Mac y se conservan al crear otra versión."))
|
||||
.font(.system(size:12)).foregroundStyle(.secondary)
|
||||
} else {
|
||||
|
||||
@@ -36,8 +36,9 @@ def main(argv=None):
|
||||
subprocess.run([sys.executable,'-m','pip','install','nsz'],check=True)
|
||||
code=load_builder().cli(command+['-k',str(keys)])
|
||||
if code: return code
|
||||
if not (output/'Contents/MacOS/dmhost').is_file():
|
||||
raise ValueError('Build finished without a Mac game app.')
|
||||
romfs=output/'Contents/Resources/romfs'
|
||||
if not (output/'Contents/MacOS/dmhost').is_file() or not romfs.is_dir() or romfs.is_symlink():
|
||||
raise ValueError('Build finished without a complete Mac game app (embedded game data required).')
|
||||
record={'schema':1,'app_path':str(output)}
|
||||
state=game/'nxnative-mac.json'
|
||||
temporary=state.with_suffix('.json.tmp')
|
||||
|
||||
@@ -20,6 +20,7 @@ class MacPipeline(unittest.TestCase):
|
||||
calls.append(args)
|
||||
host=Path(args[args.index('-o')+1])/'Contents/MacOS/dmhost'
|
||||
host.parent.mkdir(parents=True);host.write_bytes(b'synthetic')
|
||||
(host.parents[1]/'Resources/romfs').mkdir(parents=True)
|
||||
return 0
|
||||
with patch.object(build_mac,'load_builder',return_value=Builder()),patch.object(build_mac.platform,'machine',return_value='arm64'):
|
||||
self.assertEqual(build_mac.main([temp,'--keys-folder',temp]),0)
|
||||
@@ -37,3 +38,17 @@ class MacPipeline(unittest.TestCase):
|
||||
with patch.object(build_mac,'load_builder',return_value=Builder()),patch.object(build_mac.platform,'machine',return_value='arm64'):
|
||||
self.assertEqual(build_mac.main([temp,'--keys-folder',temp]),1)
|
||||
self.assertEqual((root/'nxnative-mac.json').read_text(),'{"app_path":"old"}')
|
||||
|
||||
def test_incomplete_app_does_not_replace_previous_record(self):
|
||||
with tempfile.TemporaryDirectory() as temp:
|
||||
root=Path(temp);(root/'base.nsp').write_bytes(b'synthetic');(root/'prod.keys').write_bytes(b'synthetic')
|
||||
(root/'nxnative-mac.json').write_text('{"app_path":"old"}')
|
||||
class Builder:
|
||||
def cli(self,args):
|
||||
host=Path(args[args.index('-o')+1])/'Contents/MacOS/dmhost'
|
||||
host.parent.mkdir(parents=True);host.write_bytes(b'synthetic')
|
||||
return 0
|
||||
with patch.object(build_mac,'load_builder',return_value=Builder()),patch.object(build_mac.platform,'machine',return_value='arm64'):
|
||||
with self.assertRaisesRegex(ValueError,'embedded game data required'):
|
||||
build_mac.main([temp,'--keys-folder',temp])
|
||||
self.assertEqual((root/'nxnative-mac.json').read_text(),'{"app_path":"old"}')
|
||||
Reference in new issue
Block a user