Skip to content

Commit 3f77fef

Browse files
committed
Merge remote-tracking branch 'upstream/main' into adb-websocket
2 parents 2ece7ba + 83199de commit 3f77fef

20 files changed

Lines changed: 388 additions & 157 deletions

mbf-agent/build.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ use std::{fs::OpenOptions, path::Path};
33
const LIBMAIN_URL: &str =
44
"https://github.com/sc2ad/LibMainLoader/releases/download/v0.1.0-alpha/libmain.so";
55
const SL2_URL: &str = "https://github.com/sc2ad/Scotland2/releases/latest/download/libsl2.so";
6+
const OVR_URL: &str = "https://github.com/kodenamekrak/JusticeForQuest/raw/refs/heads/master/third_party/libovrplatformloader.so";
67

78
fn download_if_not_exist(url: &str, to: &str) {
89
if Path::new(to).exists() {
@@ -27,4 +28,5 @@ fn main() {
2728
std::fs::create_dir_all("./libs").expect("Failed to create ./libs");
2829
download_if_not_exist(LIBMAIN_URL, "./libs/libmain.so");
2930
download_if_not_exist(SL2_URL, "./libs/libsl2.so");
31+
download_if_not_exist(OVR_URL, "./libs/libovrplatformloader.so");
3032
}

mbf-agent/src/handlers/mod.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,12 +37,14 @@ pub fn handle_request(request: Request) -> Result<Response> {
3737
remodding,
3838
manifest_mod,
3939
allow_no_core_mods,
40+
device_pre_v51,
4041
override_core_mod_url,
4142
vr_splash_path,
4243
} => patching::handle_patch(
4344
downgrade_to,
4445
remodding,
4546
manifest_mod,
47+
device_pre_v51,
4648
allow_no_core_mods,
4749
override_core_mod_url,
4850
vr_splash_path,

mbf-agent/src/handlers/patching.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ pub(super) fn handle_patch(
3232
downgrade_to: Option<String>,
3333
repatch: bool,
3434
manifest_mod: String,
35+
device_pre_v51: bool,
3536
allow_no_core_mods: bool,
3637
override_core_mod_url: Option<String>,
3738
vr_splash_path: Option<String>,
@@ -61,6 +62,7 @@ pub(super) fn handle_patch(
6162
&app_info,
6263
version_diffs,
6364
manifest_mod,
65+
device_pre_v51,
6466
vr_splash_path.as_deref(),
6567
&res_cache,
6668
)
@@ -71,6 +73,7 @@ pub(super) fn handle_patch(
7173
&app_info,
7274
manifest_mod,
7375
repatch,
76+
device_pre_v51,
7477
vr_splash_path.as_deref(),
7578
&res_cache,
7679
)

mbf-agent/src/models/request.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -69,6 +69,8 @@ pub enum Request {
6969
remodding: bool,
7070
// If this is true, patching will not be failed if core mods cannot be found for the version.
7171
allow_no_core_mods: bool,
72+
// If this is true, libovrplatformloader.so will be replaced with the old version to make the game work on quest 1
73+
device_pre_v51: bool,
7274
// If not null, this specifies a core mod JSON to use instead of the default core mods source.
7375
// This is useful for developers testing a core mod update.
7476
override_core_mod_url: Option<String>,

mbf-agent/src/patching.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -24,12 +24,14 @@ use mbf_zip::{signing, FileCompression, ZipFile, ZIP_CRC};
2424
const DEBUG_CERT_PEM: &[u8] = include_bytes!("debug_cert.pem");
2525
const LIB_MAIN: &[u8] = include_bytes!("../libs/libmain.so");
2626
const MODLOADER: &[u8] = include_bytes!("../libs/libsl2.so");
27+
const LEGACY_OVRPLATFORMLOADER: &[u8] = include_bytes!("../libs/libovrplatformloader.so");
2728

2829
const MODLOADER_NAME: &str = "libsl2.so";
2930
const MOD_TAG_PATH: &str = "modded.json";
3031

3132
const LIB_MAIN_PATH: &str = "lib/arm64-v8a/libmain.so";
3233
const LIB_UNITY_PATH: &str = "lib/arm64-v8a/libunity.so";
34+
const LIB_OVR_PATH: &str = "lib/arm64-v8a/libovrplatformloader.so";
3335

3436
// Aligment to use for ZIP entries with the STORE compression method, in bytes.
3537
// 4 is the standard value.
@@ -42,6 +44,7 @@ pub fn mod_current_apk(
4244
app_info: &AppInfo,
4345
manifest_mod: String,
4446
manifest_only: bool,
47+
device_pre_v51: bool,
4548
vr_splash_path: Option<&str>,
4649
res_cache: &ResCache,
4750
) -> Result<()> {
@@ -78,6 +81,7 @@ pub fn mod_current_apk(
7881
obb_backups,
7982
manifest_mod,
8083
manifest_only,
84+
device_pre_v51,
8185
vr_splash_path,
8286
)
8387
.context("Patching and reinstalling APK")?;
@@ -91,6 +95,7 @@ pub fn downgrade_and_mod_apk(
9195
app_info: &AppInfo,
9296
diffs: VersionDiffs,
9397
manifest_mod: String,
98+
device_pre_v51: bool,
9499
vr_splash_path: Option<&str>,
95100
res_cache: &ResCache,
96101
) -> Result<bool> {
@@ -149,6 +154,7 @@ pub fn downgrade_and_mod_apk(
149154
obb_backup_paths,
150155
manifest_mod,
151156
false,
157+
device_pre_v51,
152158
vr_splash_path,
153159
)
154160
.context("Patching and reinstall APK")?;
@@ -182,6 +188,7 @@ fn patch_and_reinstall(
182188
obb_paths: Vec<PathBuf>,
183189
manifest_mod: String,
184190
manifest_only: bool,
191+
device_pre_v51: bool,
185192
vr_splash_path: Option<&str>,
186193
) -> Result<()> {
187194
info!("Patching APK");
@@ -190,6 +197,7 @@ fn patch_and_reinstall(
190197
libunity_path,
191198
manifest_mod,
192199
manifest_only,
200+
device_pre_v51,
193201
vr_splash_path,
194202
)
195203
.context("Patching APK")?;
@@ -209,7 +217,7 @@ fn patch_and_reinstall(
209217
}
210218
}
211219

212-
reinstall_modded_app(&temp_apk_path).context("Reinstalling modded APK")?;
220+
reinstall_modded_app(&temp_apk_path, device_pre_v51).context("Reinstalling modded APK")?;
213221
std::fs::remove_file(temp_apk_path)?;
214222

215223
info!("Restoring OBB files");
@@ -239,7 +247,10 @@ pub fn backup_player_data() -> Result<()> {
239247
Ok(())
240248
}
241249

242-
fn reinstall_modded_app(temp_apk_path: &Path) -> Result<()> {
250+
fn reinstall_modded_app(
251+
temp_apk_path: &Path,
252+
device_pre_v51: bool,
253+
) -> Result<()> {
243254
info!("Reinstalling modded app");
244255
Command::new("pm")
245256
.args(["uninstall", APK_ID])
@@ -256,6 +267,17 @@ fn reinstall_modded_app(temp_apk_path: &Path) -> Result<()> {
256267
.args(["set", "--uid", APK_ID, "MANAGE_EXTERNAL_STORAGE", "allow"])
257268
.output()?;
258269

270+
// Quest 1 specific permissions
271+
if device_pre_v51 {
272+
info!("Granting WRITE_EXTERNAL_STORAGE and READ_EXTERNAL_STORAGE (Quest 1)");
273+
Command::new("pm")
274+
.args(["grant", APK_ID, "android.permission.WRITE_EXTERNAL_STORAGE"])
275+
.output()?;
276+
Command::new("pm")
277+
.args(["grant", APK_ID, "android.permission.READ_EXTERNAL_STORAGE"])
278+
.output()?;
279+
}
280+
259281
Ok(())
260282
}
261283

@@ -431,6 +453,7 @@ fn patch_apk_in_place(
431453
libunity_path: Option<PathBuf>,
432454
manifest_mod: String,
433455
manifest_only: bool,
456+
device_pre_v51: bool,
434457
vr_splash_path: Option<&str>,
435458
) -> Result<()> {
436459
let file = OpenOptions::new()
@@ -474,6 +497,15 @@ fn patch_apk_in_place(
474497
}
475498
None => warn!("No unstripped unity added to the APK! This might cause issues later"),
476499
}
500+
501+
if device_pre_v51 {
502+
info!("Replacing ovrplatformloader");
503+
zip.write_file(
504+
LIB_OVR_PATH,
505+
&mut Cursor::new(LEGACY_OVRPLATFORMLOADER),
506+
FileCompression::Deflate
507+
)?;
508+
}
477509
}
478510

479511
if let Some(splash_path) = vr_splash_path {

mbf-site/src/Agent.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -366,6 +366,7 @@ export async function patchApp(device: Adb,
366366
manifestMod: string,
367367
remodding: boolean,
368368
allow_no_core_mods: boolean,
369+
device_pre_v51: boolean,
369370
splashScreen: File | null): Promise<ModStatus> {
370371
Log.debug("Patching with manifest: " + manifestMod);
371372

@@ -390,6 +391,7 @@ export async function patchApp(device: Adb,
390391
manifest_mod: manifestMod,
391392
allow_no_core_mods: allow_no_core_mods,
392393
override_core_mod_url: CORE_MOD_OVERRIDE_URL,
394+
device_pre_v51: device_pre_v51,
393395
remodding,
394396
vr_splash_path: splashPath
395397
}) as Patched;

mbf-site/src/AndroidManifest.ts

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -111,12 +111,21 @@ export class AndroidManifest {
111111
// - Enable MANAGE_EXTERNAL_STORAGE permission.
112112
// - Make app debuggable
113113
// - Enable hardware acceleration. (useful for any mods that make use of the WebView API)
114-
public applyPatchingManifestMod() {
114+
public applyPatchingManifestMod(devicePreV51: boolean = false) {
115115
const application = this.document.getElementsByTagName("application")[0];
116116
application.setAttributeNS(ANDROID_NS_URI, `${this.androidNsPrefix}:debuggable`, "true");
117117
application.setAttributeNS(ANDROID_NS_URI, `${this.androidNsPrefix}:hardwareAccelerated`, "true");
118-
118+
119119
this.addPermission("android.permission.MANAGE_EXTERNAL_STORAGE");
120+
this.setMetadata("com.oculus.supportedDevices", "quest|quest2");
121+
122+
// Quest 1 specific
123+
if (devicePreV51) {
124+
application.setAttributeNS(ANDROID_NS_URI, `${this.androidNsPrefix}:requestLegacyExternalStorage`, "true");
125+
126+
this.addPermission("android.permission.WRITE_EXTERNAL_STORAGE");
127+
this.addPermission("android.permission.READ_EXTERNAL_STORAGE");
128+
}
120129
}
121130

122131
// Adds a <uses-permission> element for the specified permission underneath the manifest tag.

mbf-site/src/App.tsx

Lines changed: 27 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -20,10 +20,11 @@ import { waitForDisconnect } from "./waitForDisconnect";
2020
import { BridgeManager } from './BridgeManager';
2121
import { AllowAuth, DeviceInUse, NoCompatibleDevices, OculusBrowserMessage, OldOsVersion, QuestOneNotSupported, Title, UnsupportedMessage } from './AppMessages';
2222
import { PagePinger } from './PagePinger';
23+
import { useDeviceStore } from './DeviceStore';
2324

2425
type NoDeviceCause = "NoDeviceSelected" | "DeviceInUse";
2526

26-
const MIN_SUPPORTED_ANDROID_VERSION: number = 11;
27+
const NON_LEGACY_ANDROID_VERSION: number = 11;
2728

2829
/**
2930
* Connects to the ADB server using the given client and device.
@@ -121,17 +122,17 @@ enum ConnectedState {
121122
*/
122123
async function connectDevice(device: Adb, { setDevicePreV51, setAuthing, setChosenDevice }: {
123124
/** State setter for indicating if the device is pre-v51 (unsupported). */
124-
setDevicePreV51: SetStateAction<boolean>
125+
setDevicePreV51: (isPreV51: boolean) => void
125126

126-
/** State setter for authentication status (false when done). */
127+
/** State setter for authentication status. */
127128
setAuthing: SetStateAction<boolean>
128129

129130
/** State setter for the currently selected device. */
130-
setChosenDevice: SetStateAction<Adb | null>
131+
setChosenDevice: (adb: Adb | null) => void
131132
}) {
132133
const androidVersion = await getAndroidVersion(device);
133134
Log.debug("Device android version: " + androidVersion);
134-
setDevicePreV51(androidVersion < MIN_SUPPORTED_ANDROID_VERSION);
135+
setDevicePreV51(androidVersion < NON_LEGACY_ANDROID_VERSION);
135136
setAuthing(false);
136137
setChosenDevice(device);
137138

@@ -153,13 +154,13 @@ async function connectDevice(device: Adb, { setDevicePreV51, setAuthing, setChos
153154
*/
154155
async function connectBridgeDevice(bridgeClient: AdbServerClient, device: AdbServerClient.Device, { setDevicePreV51, setAuthing, setChosenDevice, setConnectError }: {
155156
/** State setter for indicating if the device is pre-v51 (unsupported). */
156-
setDevicePreV51: SetStateAction<boolean>
157+
setDevicePreV51: (isPreV51: boolean) => void
157158

158159
/** State setter for authentication status. */
159160
setAuthing: SetStateAction<boolean>
160161

161162
/** State setter for the currently selected device. */
162-
setChosenDevice: SetStateAction<Adb | null>
163+
setChosenDevice: (adb: Adb | null) => void
163164

164165
/** State setter for connection error messages. */
165166
setConnectError: SetStateAction<string | null>
@@ -196,7 +197,7 @@ async function connectWebUsb({ setAuthing, setDeviceInUse, setChosenDevice, setC
196197
setDeviceInUse: SetStateAction<boolean>
197198

198199
/** State setter for the currently selected device. */
199-
setChosenDevice: SetStateAction<Adb | null>
200+
setChosenDevice: (adb: Adb | null) => void
200201

201202
/** State setter for connection error messages. */
202203
setConnectError: SetStateAction<string | null>
@@ -243,10 +244,13 @@ async function connectWebUsb({ setAuthing, setDeviceInUse, setChosenDevice, setC
243244
*/
244245
function ChooseDevice() {
245246
const [authing, setAuthing] = useState(false);
246-
const [chosenDevice, setChosenDevice] = useState(null as Adb | null);
247247
const [connectError, setConnectError] = useState(null as string | null);
248-
const [devicePreV51, setDevicePreV51] = useState(false);
249248
const [deviceInUse, setDeviceInUse] = useState(false);
249+
const {
250+
devicePreV51, setDevicePreV51,
251+
device: chosenDevice, setDevice: setChosenDevice, usingBridge, setUsingBridge,
252+
androidVersion, setAndroidVersion
253+
} = useDeviceStore();
250254
const [bridgeClient, setBridgeClient] = useState<AdbServerClient | null>(null);
251255
const [adbDevices, setAdbDevices] = useState<AdbServerClient.Device[]>([]);
252256
const stateSetters = {
@@ -258,33 +262,28 @@ function ChooseDevice() {
258262
setBridgeClient,
259263
setAdbDevices
260264
}
261-
265+
262266
useEffect(() => {
263267
// If the user is using a bridge and there is only one device, connect to it automatically.
264268
if (chosenDevice == null && bridgeClient != null && adbDevices.length == 1) {
265269
connectBridgeDevice(bridgeClient, adbDevices[0], stateSetters).catch(err => Log.error("Failed to connect to device: " + err, err));
266270
}
267-
268271
});
269272

270273
if(chosenDevice !== null) {
271274
Log.debug("Device model: " + chosenDevice.banner.model);
272-
if(chosenDevice.banner.model === "Quest") { // "Quest" not "Quest 2/3"
273-
return <QuestOneNotSupported />
274-
} else if(devicePreV51 && chosenDevice.banner.model?.includes("Quest")) {
275-
return <OldOsVersion />
276-
} else {
277-
return <>
278-
{ bridgeClient && <PagePinger url={bridgeData.pingAddress} interval={5000} /> }
279-
<DeviceModder device={chosenDevice} usingBridge={bridgeClient != null} quit={(err) => {
280-
if(err != null) {
281-
setConnectError(String(err));
282-
}
283-
chosenDevice.close().catch(err => Log.error("Failed to close device " + err, err));
284-
setChosenDevice(null);
285-
}} />
286-
</>
287-
}
275+
setUsingBridge(bridgeClient != null);
276+
return <>
277+
{ bridgeClient && <PagePinger url={bridgeData.pingAddress} interval={5000} /> }
278+
<DeviceModder quit={(err) => {
279+
if(err != null) {
280+
setConnectError(String(err));
281+
}
282+
chosenDevice.close().catch(err => Log.error("Failed to close device " + err, err));
283+
setChosenDevice(null);
284+
setUsingBridge(false);
285+
}} />
286+
</>
288287
} else if(authing) {
289288
return <AllowAuth />
290289
} else {

0 commit comments

Comments
 (0)