mirror of
https://github.com/ovrport/app.git
synced 2026-10-27 03:19:56 -04:00
Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c790854772 | ||
|
|
474f7bf12a | ||
|
|
c50c431a7e |
No files matched your search
@@ -40,7 +40,7 @@ If you have any issues regarding game compatibility, please, enable verbose logg
|
|||||||
|
|
||||||
# About legality
|
# About legality
|
||||||
|
|
||||||
Think of this app like an emulator: you need to legally own the game files to use it.
|
Think of this app like an emulator: you need to legally obtain the game files to use it.
|
||||||
|
|
||||||
Obviously, to get a Quest game running on a different headset, the app has to strip away some entitlement checks.
|
Obviously, to get a Quest game running on a different headset, the app has to strip away some entitlement checks.
|
||||||
However, the game still won't launch on a Quest unless you’ve actually bought it.
|
However, the game still won't launch on a Quest unless you’ve actually bought it.
|
||||||
|
|||||||
@@ -9,7 +9,8 @@ object BitmapIconResizer : IconResizer {
|
|||||||
|
|
||||||
override fun resize(bytes: ByteArray, width: Int, height: Int): ByteArray {
|
override fun resize(bytes: ByteArray, width: Int, height: Int): ByteArray {
|
||||||
val baos = ByteArrayOutputStream()
|
val baos = ByteArrayOutputStream()
|
||||||
BitmapFactory.decodeByteArray(bytes, 0, bytes.size).apply {
|
BitmapFactory.decodeByteArray(bytes, 0, bytes.size)
|
||||||
|
.copy(Bitmap.Config.ARGB_8888, true).apply {
|
||||||
reconfigure(width, height, Bitmap.Config.ARGB_8888)
|
reconfigure(width, height, Bitmap.Config.ARGB_8888)
|
||||||
}.compress(Bitmap.CompressFormat.PNG, 100, baos)
|
}.compress(Bitmap.CompressFormat.PNG, 100, baos)
|
||||||
return baos.toByteArray()
|
return baos.toByteArray()
|
||||||
|
|||||||
@@ -9,9 +9,7 @@
|
|||||||
<string name="progress_cleaning">Cleaning up…</string>
|
<string name="progress_cleaning">Cleaning up…</string>
|
||||||
<string name="patcher_nav_item">Patcher</string>
|
<string name="patcher_nav_item">Patcher</string>
|
||||||
<string name="select_version_title">Select version</string>
|
<string name="select_version_title">Select version</string>
|
||||||
<string name="you_have_no_versions">You have no versions installed and overport release index is not available.
|
<string name="you_have_no_versions">You have no versions installed and overport release index is not available. Check your internet connection.</string>
|
||||||
Check your internet connection.
|
|
||||||
</string>
|
|
||||||
<string name="tag_experimental">experimental</string>
|
<string name="tag_experimental">experimental</string>
|
||||||
<string name="tag_latest">latest</string>
|
<string name="tag_latest">latest</string>
|
||||||
<string name="tag_custom">custom</string>
|
<string name="tag_custom">custom</string>
|
||||||
@@ -28,7 +26,9 @@
|
|||||||
<string name="cant_read_apk">Selected APK file cannot be parsed.</string>
|
<string name="cant_read_apk">Selected APK file cannot be parsed.</string>
|
||||||
<string name="apk_file_exported">APK file has been successfully exported.</string>
|
<string name="apk_file_exported">APK file has been successfully exported.</string>
|
||||||
<string name="cant_update_overport">overport libraries cannot be downloaded.</string>
|
<string name="cant_update_overport">overport libraries cannot be downloaded.</string>
|
||||||
<string name="unknown_error">Unknown error has been occurred.</string>
|
<string name="unknown_error">Unknown error has been occurred</string>
|
||||||
|
<string name="cant_checkout_title">Can't checkout version</string>
|
||||||
|
<string name="cant_checkout_message">Selected overport version is unavailable for download. Please, check your internet connection or choose another version.</string>
|
||||||
<string name="update_available">Update available!</string>
|
<string name="update_available">Update available!</string>
|
||||||
<string name="status_unknown">Unknown</string>
|
<string name="status_unknown">Unknown</string>
|
||||||
<string name="status_playable">Playable</string>
|
<string name="status_playable">Playable</string>
|
||||||
@@ -36,18 +36,18 @@
|
|||||||
<string name="status_not_working">Not working</string>
|
<string name="status_not_working">Not working</string>
|
||||||
<string name="status_loading">Loading…</string>
|
<string name="status_loading">Loading…</string>
|
||||||
<string name="use_at_your_risk">Not recommended, use at your own risk</string>
|
<string name="use_at_your_risk">Not recommended, use at your own risk</string>
|
||||||
<string name="patch_copy_libraries">Copy ovrport libraries</string>
|
<string name="patch_copy_libraries">Copy overport libraries</string>
|
||||||
<string name="patch_copy_ovrplugin_vrapi">Copy OVRPlugin if VrApi is present</string>
|
<string name="patch_copy_ovrplugin_vrapi">Copy OVRPlugin if VrApi is present</string>
|
||||||
<string name="patch_fix_min_android_sdk">Fix minimal Android SDK</string>
|
<string name="patch_fix_min_android_sdk">Fix minimal Android SDK</string>
|
||||||
<string name="patch_generate_config">Generate ovrport config</string>
|
<string name="patch_generate_config">Generate overport config</string>
|
||||||
<string name="patch_remove_localized_names">Remove localized app names</string>
|
<string name="patch_remove_localized_names">Remove localized app names</string>
|
||||||
<string name="patch_clean_up_frida">Clean up Frida leftovers</string>
|
<string name="patch_clean_up_frida">Clean up Frida leftovers in smali</string>
|
||||||
<string name="patch_oculus_unity">Patch Oculus detection for Unity</string>
|
<string name="patch_oculus_unity">Patch Oculus detection for Unity</string>
|
||||||
<string name="patch_oculus_unreal">Patch Oculus detection for Unreal</string>
|
<string name="patch_oculus_unreal">Patch Oculus detection for Unreal</string>
|
||||||
<string name="patch_vr_metadata">Pico/YVR/Quest metadata</string>
|
<string name="patch_vr_metadata">Pico/YVR/Quest metadata</string>
|
||||||
<string name="patch_launcher_entry">Fix launcher icon entry</string>
|
<string name="patch_launcher_entry">Fix launcher icon entry</string>
|
||||||
<string name="patch_remove_uses_library">Remove uses-library</string>
|
<string name="patch_remove_uses_library">Remove uses-library</string>
|
||||||
<string name="patch_fix_unreal_crash">Fix Unreal Engine 4 crash</string>
|
<string name="patch_fix_unreal_crash">Fix UE4 crash with Unity stub</string>
|
||||||
<string name="patch_meta_xr_audio">Patch Meta XR Audio</string>
|
<string name="patch_meta_xr_audio">Patch Meta XR Audio</string>
|
||||||
<string name="patch_mark_as_debuggable">Mark application as debuggable</string>
|
<string name="patch_mark_as_debuggable">Mark application as debuggable</string>
|
||||||
<string name="patch_mark_allow_backup">Mark application to allow backup</string>
|
<string name="patch_mark_allow_backup">Mark application to allow backup</string>
|
||||||
@@ -56,4 +56,5 @@
|
|||||||
<string name="patch_force_passthrough">Force enable passthrough</string>
|
<string name="patch_force_passthrough">Force enable passthrough</string>
|
||||||
<string name="patch_disable_space_warp">Disable application space warp if used</string>
|
<string name="patch_disable_space_warp">Disable application space warp if used</string>
|
||||||
<string name="patch_disable_controller_offset">Disable controller tracking offset</string>
|
<string name="patch_disable_controller_offset">Disable controller tracking offset</string>
|
||||||
|
<string name="patch_remove_vrapi">Remove VrApi library</string>
|
||||||
</resources>
|
</resources>
|
||||||
@@ -46,7 +46,6 @@ fun AppContent(
|
|||||||
}
|
}
|
||||||
|
|
||||||
var versionToUpdate by remember { mutableStateOf<GithubRelease?>(null) }
|
var versionToUpdate by remember { mutableStateOf<GithubRelease?>(null) }
|
||||||
var showAboutDialog by remember { mutableStateOf(false) }
|
|
||||||
val urlHandler = LocalUriHandler.current
|
val urlHandler = LocalUriHandler.current
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
@@ -95,18 +94,5 @@ fun AppContent(
|
|||||||
navigationItems = listOf(patcherNavItem),
|
navigationItems = listOf(patcherNavItem),
|
||||||
itemsEnabled = !viewModel.working && !viewModel.isApkLoaded()
|
itemsEnabled = !viewModel.working && !viewModel.isApkLoaded()
|
||||||
)
|
)
|
||||||
|
|
||||||
if (showAboutDialog) {
|
|
||||||
AlertDialog(
|
|
||||||
onDismissRequest = { showAboutDialog = false },
|
|
||||||
title = { Text("overport") },
|
|
||||||
text = { Text("about overport") }, // TODO
|
|
||||||
confirmButton = {
|
|
||||||
TextButton(onClick = { showAboutDialog = false }) {
|
|
||||||
Text("Close")
|
|
||||||
}
|
|
||||||
},
|
|
||||||
)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
+36
-23
@@ -15,7 +15,6 @@ import androidx.compose.ui.Modifier
|
|||||||
import androidx.compose.ui.graphics.ImageBitmap
|
import androidx.compose.ui.graphics.ImageBitmap
|
||||||
import androidx.compose.ui.unit.dp
|
import androidx.compose.ui.unit.dp
|
||||||
import kotlinx.coroutines.Dispatchers
|
import kotlinx.coroutines.Dispatchers
|
||||||
import kotlinx.coroutines.launch
|
|
||||||
import kotlinx.coroutines.withContext
|
import kotlinx.coroutines.withContext
|
||||||
import moe.crx.overport.app.decodeBitmap
|
import moe.crx.overport.app.decodeBitmap
|
||||||
import moe.crx.overport.app.util.ModifierUtil.rounded
|
import moe.crx.overport.app.util.ModifierUtil.rounded
|
||||||
@@ -25,50 +24,64 @@ import overportapp.composeapp.generated.resources.Res
|
|||||||
import overportapp.composeapp.generated.resources.unknown_package
|
import overportapp.composeapp.generated.resources.unknown_package
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
val iconCache = mutableMapOf<String, ImageBitmap?>()
|
||||||
|
val coverCache = mutableMapOf<String, ImageBitmap?>()
|
||||||
|
|
||||||
@Composable
|
@Composable
|
||||||
fun ApplicationInfo(
|
fun ApplicationInfo(
|
||||||
applicationName: String? = "Application",
|
applicationName: String,
|
||||||
applicationPackage: String? = "com.company.application",
|
applicationPackage: String,
|
||||||
applicationVersion: String? = "1.0.0",
|
applicationVersion: String,
|
||||||
applicationIcon: ImageBitmap? = null,
|
applicationIcon: ImageBitmap? = null,
|
||||||
|
forceLocalInfo: Boolean = false,
|
||||||
|
useCover: Boolean = false,
|
||||||
) {
|
) {
|
||||||
var iconIsLoading by rememberSaveable(applicationPackage) { mutableStateOf(true) }
|
var iconIsLoading by remember(applicationPackage) { mutableStateOf(true) }
|
||||||
var onlineIcon by rememberSaveable(applicationPackage) { mutableStateOf<ImageBitmap?>(null) }
|
var onlineIcon by remember(applicationPackage) { mutableStateOf(iconCache[applicationPackage]) }
|
||||||
|
var onlineCover by remember(applicationPackage) { mutableStateOf(coverCache[applicationPackage]) }
|
||||||
|
|
||||||
var onlineLabel by rememberSaveable(applicationPackage) { mutableStateOf<String?>(null) }
|
var onlineLabel by rememberSaveable(applicationPackage) { mutableStateOf<String?>(null) }
|
||||||
val scope = rememberCoroutineScope()
|
|
||||||
|
|
||||||
LaunchedEffect(applicationPackage) {
|
LaunchedEffect(applicationPackage) {
|
||||||
scope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
runCatching {
|
if (iconCache.containsKey(applicationPackage)) {
|
||||||
val info = applicationPackage?.let { getApplicationInfo(it) }
|
return@withContext
|
||||||
|
}
|
||||||
|
|
||||||
|
val info = getApplicationInfo(applicationPackage)
|
||||||
onlineLabel = info?.displayName
|
onlineLabel = info?.displayName
|
||||||
|
|
||||||
val image = info?.run {
|
val icon = info?.run {
|
||||||
val associated = images.associateBy { it.imageType }
|
val associated = images.associateBy { it.imageType }
|
||||||
associated["APP_IMG_ICON"] ?: associated["APP_IMG_COVER_SQUARE"]
|
associated["APP_IMG_ICON"] ?: associated["APP_IMG_COVER_SQUARE"]
|
||||||
}
|
}
|
||||||
|
|
||||||
onlineIcon = image?.uri?.let { Base64.getDecoder().decode(it) }?.decodeBitmap()
|
val cover = info?.run {
|
||||||
|
val associated = images.associateBy { it.imageType }
|
||||||
|
associated["APP_IMG_COVER_SQUARE"] ?: associated["APP_IMG_ICON"]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
val iconBitmap = icon?.uri?.let { Base64.getDecoder().decode(it) }?.decodeBitmap()
|
||||||
|
val coverBitmap = cover?.uri?.let { Base64.getDecoder().decode(it) }?.decodeBitmap()
|
||||||
|
|
||||||
|
iconCache[applicationPackage] = iconBitmap
|
||||||
|
coverCache[applicationPackage] = coverBitmap
|
||||||
|
|
||||||
|
onlineIcon = iconBitmap
|
||||||
|
onlineCover = coverBitmap
|
||||||
|
|
||||||
iconIsLoading = false
|
iconIsLoading = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
Row(
|
Row(
|
||||||
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
horizontalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
) {
|
) {
|
||||||
Box {
|
Box {
|
||||||
FadeVisibility(!iconIsLoading) {
|
FadeVisibility(!iconIsLoading) {
|
||||||
onlineIcon?.let {
|
AnimatedContent((onlineCover.takeIf { useCover } ?: onlineIcon)
|
||||||
Image(
|
.takeIf { !forceLocalInfo } ?: applicationIcon) {
|
||||||
it,
|
if (it == null) {
|
||||||
contentDescription = null,
|
|
||||||
modifier = Modifier.size(48.dp).rounded(8.dp)
|
|
||||||
)
|
|
||||||
} ?: run {
|
|
||||||
if (applicationIcon == null) {
|
|
||||||
Icon(
|
Icon(
|
||||||
Icons.Default.Widgets,
|
Icons.Default.Widgets,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
@@ -76,7 +89,7 @@ fun ApplicationInfo(
|
|||||||
)
|
)
|
||||||
} else {
|
} else {
|
||||||
Image(
|
Image(
|
||||||
applicationIcon,
|
it,
|
||||||
contentDescription = null,
|
contentDescription = null,
|
||||||
modifier = Modifier.size(48.dp).rounded(8.dp)
|
modifier = Modifier.size(48.dp).rounded(8.dp)
|
||||||
)
|
)
|
||||||
@@ -91,7 +104,7 @@ fun ApplicationInfo(
|
|||||||
modifier = Modifier.height(48.dp),
|
modifier = Modifier.height(48.dp),
|
||||||
verticalArrangement = Arrangement.Center
|
verticalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
AnimatedContent(onlineLabel ?: applicationName) {
|
AnimatedContent(onlineLabel.takeIf { !forceLocalInfo } ?: applicationName) {
|
||||||
Text("$it ($applicationVersion)")
|
Text("$it ($applicationVersion)")
|
||||||
}
|
}
|
||||||
Text(
|
Text(
|
||||||
|
|||||||
+27
-17
@@ -20,31 +20,21 @@ import overportapp.composeapp.generated.resources.*
|
|||||||
@OptIn(ExperimentalLayoutApi::class)
|
@OptIn(ExperimentalLayoutApi::class)
|
||||||
@Composable
|
@Composable
|
||||||
@Preview
|
@Preview
|
||||||
fun ApplicationInfoCard(
|
fun ApplicationInfoContent(
|
||||||
applicationName: String? = "Application",
|
applicationName: String,
|
||||||
applicationPackage: String? = "",
|
applicationPackage: String,
|
||||||
applicationVersion: String? = "1.0.0",
|
applicationVersion: String,
|
||||||
applicationIcon: ImageBitmap? = null,
|
applicationIcon: ImageBitmap? = null,
|
||||||
onCancel: () -> Unit = {},
|
onCancel: () -> Unit = {},
|
||||||
onConfirm: (Map<String, List<String>>) -> Unit = {}
|
onConfirm: (Map<String, List<String>>) -> Unit = {}
|
||||||
) {
|
) {
|
||||||
Column(
|
val enabledPatches = remember(applicationPackage) {
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
) {
|
|
||||||
FlowRow(
|
|
||||||
modifier = Modifier.fillMaxWidth().padding(8.dp),
|
|
||||||
horizontalArrangement = Arrangement.SpaceBetween,
|
|
||||||
verticalArrangement = Arrangement.spacedBy(8.dp),
|
|
||||||
) {
|
|
||||||
ApplicationInfo(applicationName, applicationPackage, applicationVersion, applicationIcon)
|
|
||||||
}
|
|
||||||
|
|
||||||
val enabledPatches = remember {
|
|
||||||
mutableStateMapOf(
|
mutableStateMapOf(
|
||||||
*PatchStore.recommended().map { it.name to listOf<String>() }.toTypedArray()
|
*PatchStore.recommended().map { it.name to listOf<String>() }.toTypedArray()
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
var patchIconArgument by remember {
|
|
||||||
|
var patchIconArgument by remember(applicationPackage) {
|
||||||
mutableStateOf("icon")
|
mutableStateOf("icon")
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -58,6 +48,24 @@ fun ApplicationInfoCard(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Column(
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
FlowRow(
|
||||||
|
modifier = Modifier.fillMaxWidth().padding(8.dp),
|
||||||
|
horizontalArrangement = Arrangement.SpaceBetween,
|
||||||
|
verticalArrangement = Arrangement.spacedBy(8.dp),
|
||||||
|
) {
|
||||||
|
ApplicationInfo(
|
||||||
|
applicationName,
|
||||||
|
applicationPackage,
|
||||||
|
applicationVersion,
|
||||||
|
applicationIcon,
|
||||||
|
!enabledPatches.containsKey(PATCH_REPLACE_ICON_LABEL.name),
|
||||||
|
patchIconArgument != "icon",
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
Box(modifier = Modifier.weight(1f)) {
|
Box(modifier = Modifier.weight(1f)) {
|
||||||
LazyColumn {
|
LazyColumn {
|
||||||
items(PatchStore.all()) {
|
items(PatchStore.all()) {
|
||||||
@@ -129,7 +137,9 @@ fun ApplicationInfoCard(
|
|||||||
Button(
|
Button(
|
||||||
modifier = Modifier.weight(1f),
|
modifier = Modifier.weight(1f),
|
||||||
onClick = {
|
onClick = {
|
||||||
|
if (enabledPatches.containsKey(PATCH_REPLACE_ICON_LABEL.name)) {
|
||||||
enabledPatches[PATCH_REPLACE_ICON_LABEL.name] = listOf(patchIconArgument)
|
enabledPatches[PATCH_REPLACE_ICON_LABEL.name] = listOf(patchIconArgument)
|
||||||
|
}
|
||||||
onConfirm(enabledPatches)
|
onConfirm(enabledPatches)
|
||||||
}
|
}
|
||||||
) {
|
) {
|
||||||
+11
-12
@@ -11,10 +11,9 @@ import androidx.compose.ui.Modifier
|
|||||||
import kotlinx.coroutines.flow.MutableSharedFlow
|
import kotlinx.coroutines.flow.MutableSharedFlow
|
||||||
import kotlinx.coroutines.launch
|
import kotlinx.coroutines.launch
|
||||||
import moe.crx.overport.app.model.MainViewModel
|
import moe.crx.overport.app.model.MainViewModel
|
||||||
|
import moe.crx.overport.utils.CantCheckoutException
|
||||||
import org.jetbrains.compose.resources.getString
|
import org.jetbrains.compose.resources.getString
|
||||||
import overportapp.composeapp.generated.resources.Res
|
import overportapp.composeapp.generated.resources.*
|
||||||
import overportapp.composeapp.generated.resources.apk_file_exported
|
|
||||||
import overportapp.composeapp.generated.resources.unknown_error
|
|
||||||
import java.io.InputStream
|
import java.io.InputStream
|
||||||
import java.io.OutputStream
|
import java.io.OutputStream
|
||||||
|
|
||||||
@@ -36,15 +35,12 @@ fun PatcherScreen(
|
|||||||
val isPatcherVisible = !viewModel.working && viewModel.isApkLoaded()
|
val isPatcherVisible = !viewModel.working && viewModel.isApkLoaded()
|
||||||
|
|
||||||
LaunchedEffect(openFlow) {
|
LaunchedEffect(openFlow) {
|
||||||
scope.launch {
|
|
||||||
openFlow.collect {
|
openFlow.collect {
|
||||||
inputFile = it
|
inputFile = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
LaunchedEffect(saveFlow) {
|
LaunchedEffect(saveFlow) {
|
||||||
scope.launch {
|
|
||||||
saveFlow.collect { stream ->
|
saveFlow.collect { stream ->
|
||||||
val outputStream = stream ?: return@collect
|
val outputStream = stream ?: return@collect
|
||||||
try {
|
try {
|
||||||
@@ -58,8 +54,7 @@ fun PatcherScreen(
|
|||||||
errorMessage = getString(Res.string.unknown_error) to ex.stackTraceToString()
|
errorMessage = getString(Res.string.unknown_error) to ex.stackTraceToString()
|
||||||
} finally {
|
} finally {
|
||||||
viewModel.cancel()
|
viewModel.cancel()
|
||||||
outputStream.close()
|
//outputStream.close()
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -71,10 +66,10 @@ fun PatcherScreen(
|
|||||||
}
|
}
|
||||||
|
|
||||||
FadeVisibility(isPatcherVisible) {
|
FadeVisibility(isPatcherVisible) {
|
||||||
ApplicationInfoCard(
|
ApplicationInfoContent(
|
||||||
viewModel.currentAppName(),
|
viewModel.currentAppName() ?: "",
|
||||||
viewModel.currentAppPackage(),
|
viewModel.currentAppPackage() ?: "",
|
||||||
viewModel.currentAppVersion(),
|
viewModel.currentAppVersion() ?: "",
|
||||||
viewModel.currentAppIcon(),
|
viewModel.currentAppIcon(),
|
||||||
onCancel = {
|
onCancel = {
|
||||||
scope.launch {
|
scope.launch {
|
||||||
@@ -101,6 +96,10 @@ fun PatcherScreen(
|
|||||||
try {
|
try {
|
||||||
viewModel.checkout(it, name)
|
viewModel.checkout(it, name)
|
||||||
viewModel.prepare(stream)
|
viewModel.prepare(stream)
|
||||||
|
} catch (_: CantCheckoutException) {
|
||||||
|
viewModel.cancel()
|
||||||
|
errorMessage =
|
||||||
|
getString(Res.string.cant_checkout_title) to getString(Res.string.cant_checkout_message)
|
||||||
} catch (ex: Throwable) {
|
} catch (ex: Throwable) {
|
||||||
viewModel.cancel()
|
viewModel.cancel()
|
||||||
errorMessage = getString(Res.string.unknown_error) to ex.stackTraceToString()
|
errorMessage = getString(Res.string.unknown_error) to ex.stackTraceToString()
|
||||||
|
|||||||
+1
-4
@@ -27,20 +27,17 @@ fun VersionManagerSheet(viewModel: MainViewModel, onSelected: (String) -> Unit,
|
|||||||
var available by remember { mutableStateOf<List<OverportRelease>?>(null) }
|
var available by remember { mutableStateOf<List<OverportRelease>?>(null) }
|
||||||
|
|
||||||
LaunchedEffect(Unit) {
|
LaunchedEffect(Unit) {
|
||||||
scope.launch {
|
|
||||||
withContext(Dispatchers.IO) {
|
withContext(Dispatchers.IO) {
|
||||||
available = viewModel.versionManager.available()
|
available = viewModel.versionManager.available()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
ModalBottomSheet(
|
ModalBottomSheet(
|
||||||
modifier = Modifier.fillMaxHeight(),
|
|
||||||
onDismissRequest = { onCancel() },
|
onDismissRequest = { onCancel() },
|
||||||
) {
|
) {
|
||||||
if (available == null) {
|
if (available == null) {
|
||||||
Row(
|
Row(
|
||||||
modifier = Modifier.fillMaxSize(),
|
modifier = Modifier.fillMaxWidth().height(240.dp),
|
||||||
verticalAlignment = Alignment.CenterVertically,
|
verticalAlignment = Alignment.CenterVertically,
|
||||||
horizontalArrangement = Arrangement.Center
|
horizontalArrangement = Arrangement.Center
|
||||||
) {
|
) {
|
||||||
|
|||||||
@@ -24,6 +24,7 @@ object PatchLocalizer {
|
|||||||
PATCH_META_XR_AUDIO to Res.string.patch_meta_xr_audio,
|
PATCH_META_XR_AUDIO to Res.string.patch_meta_xr_audio,
|
||||||
PATCH_MARK_AS_DEBUGGABLE to Res.string.patch_mark_as_debuggable,
|
PATCH_MARK_AS_DEBUGGABLE to Res.string.patch_mark_as_debuggable,
|
||||||
PATCH_MARK_ALLOW_BACKUP to Res.string.patch_mark_allow_backup,
|
PATCH_MARK_ALLOW_BACKUP to Res.string.patch_mark_allow_backup,
|
||||||
|
PATCH_REMOVE_VRAPI to Res.string.patch_remove_vrapi,
|
||||||
PATCH_REMOVE_UNREAL_FORCE_QUIT to Res.string.patch_remove_unreal_force_quit,
|
PATCH_REMOVE_UNREAL_FORCE_QUIT to Res.string.patch_remove_unreal_force_quit,
|
||||||
PATCH_FORCE_PASSTHROUGH to Res.string.patch_force_passthrough,
|
PATCH_FORCE_PASSTHROUGH to Res.string.patch_force_passthrough,
|
||||||
PATCH_DISABLE_SPACE_WARP to Res.string.patch_disable_space_warp,
|
PATCH_DISABLE_SPACE_WARP to Res.string.patch_disable_space_warp,
|
||||||
|
|||||||
+1
-4
@@ -1,13 +1,10 @@
|
|||||||
#Kotlin
|
#Kotlin
|
||||||
kotlin.code.style=official
|
kotlin.code.style=official
|
||||||
kotlin.daemon.jvmargs=-Xmx2048M
|
kotlin.daemon.jvmargs=-Xmx2048M
|
||||||
|
|
||||||
#Gradle
|
#Gradle
|
||||||
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
|
org.gradle.jvmargs=-Xmx2048M -Dfile.encoding=UTF-8
|
||||||
|
|
||||||
#Android
|
#Android
|
||||||
android.nonTransitiveRClass=true
|
android.nonTransitiveRClass=true
|
||||||
android.useAndroidX=true
|
android.useAndroidX=true
|
||||||
|
|
||||||
#Application
|
#Application
|
||||||
appVersion=1.2.0
|
appVersion=1.2.3
|
||||||
@@ -8,7 +8,7 @@ plugins {
|
|||||||
}
|
}
|
||||||
|
|
||||||
group = "moe.crx"
|
group = "moe.crx"
|
||||||
version = "1.2.0"
|
version = "1.2.3"
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
implementation(libs.android.tools.build)
|
implementation(libs.android.tools.build)
|
||||||
|
|||||||
Binary file not shown.
@@ -6,16 +6,6 @@ import moe.crx.overport.utils.named
|
|||||||
import moe.crx.overport.utils.takeNodesEach
|
import moe.crx.overport.utils.takeNodesEach
|
||||||
|
|
||||||
val PATCH_CLEAN_UP_FRIDA = Patch("patch_clean_up_frida") {
|
val PATCH_CLEAN_UP_FRIDA = Patch("patch_clean_up_frida") {
|
||||||
selectLibrary("libfrda.so") {
|
|
||||||
file.delete()
|
|
||||||
}
|
|
||||||
selectLibrary("libfrda.config.so") {
|
|
||||||
file.delete()
|
|
||||||
}
|
|
||||||
selectLibrary("libscript.so") {
|
|
||||||
file.delete()
|
|
||||||
}
|
|
||||||
|
|
||||||
selectManifestJson {
|
selectManifestJson {
|
||||||
takeNodesEach({ named("manifest") }) {
|
takeNodesEach({ named("manifest") }) {
|
||||||
takeNodesEach({ named("application") }) {
|
takeNodesEach({ named("application") }) {
|
||||||
|
|||||||
@@ -9,8 +9,8 @@ val PATCH_COPY_OVRPLUGIN_VRAPI = Patch("patch_copy_ovrplugin_vrapi") {
|
|||||||
val arch = getLibraries().resolve("lib/${archDirectory.name}")
|
val arch = getLibraries().resolve("lib/${archDirectory.name}")
|
||||||
|
|
||||||
if (arch.exists()) {
|
if (arch.exists()) {
|
||||||
val hasVrApi = arch.listFiles().find { it.name.lowercase() == "libvrapi.so" } != null
|
val vrApi = archDirectory.listFiles().find { it.name.lowercase() == "libvrapi.so" }
|
||||||
if (hasVrApi) {
|
if (vrApi != null) {
|
||||||
arch.listFiles().filter { it.name == "libOVRPlugin.so" }.forEach { library ->
|
arch.listFiles().filter { it.name == "libOVRPlugin.so" }.forEach { library ->
|
||||||
library.copyTo(File(archDirectory, library.name), true)
|
library.copyTo(File(archDirectory, library.name), true)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -3,18 +3,18 @@ package moe.crx.overport.patches
|
|||||||
import moe.crx.overport.patching.Patch
|
import moe.crx.overport.patching.Patch
|
||||||
|
|
||||||
val PATCH_FIX_UNREAL_CRASH = Patch("patch_fix_unreal_crash") {
|
val PATCH_FIX_UNREAL_CRASH = Patch("patch_fix_unreal_crash") {
|
||||||
createSmali("com/unity3d/player/UnityPlayer") {
|
|
||||||
if (readText().isBlank()) {
|
|
||||||
append(".class public Lcom/unity3d/player/UnityPlayer;")
|
|
||||||
append(".super Ljava/lang/Object;")
|
|
||||||
append(".field public static currentActivity:Landroid/app/Activity;")
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
selectSmali("com/epicgames/ue4/GameActivity") {
|
selectSmali("com/epicgames/ue4/GameActivity") {
|
||||||
replace(
|
replace(
|
||||||
"sput-object (\\w+), Lcom\\/epicgames\\/ue4\\/GameActivity;->\\w+:Lcom\\/epicgames\\/ue4\\/GameActivity;",
|
"sput-object (\\w+), Lcom\\/epicgames\\/ue4\\/GameActivity;->\\w+:Lcom\\/epicgames\\/ue4\\/GameActivity;",
|
||||||
"$0\nsput-object $1, Lcom/unity3d/player/UnityPlayer;->currentActivity:Landroid/app/Activity;"
|
"$0\nsput-object $1, Lcom/unity3d/player/UnityPlayer;->currentActivity:Landroid/app/Activity;"
|
||||||
)
|
)
|
||||||
|
|
||||||
|
createSmali("com/unity3d/player/UnityPlayer") {
|
||||||
|
if (readText().isBlank()) {
|
||||||
|
appendLine(".class public Lcom/unity3d/player/UnityPlayer;")
|
||||||
|
appendLine(".super Ljava/lang/Object;")
|
||||||
|
appendLine(".field public static currentActivity:Landroid/app/Activity;")
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -45,6 +45,7 @@ val PATCH_LAUNCHER_ENTRY = Patch("patch_launcher_entry") {
|
|||||||
.put(createCategory("android.intent.category.LAUNCHER"))
|
.put(createCategory("android.intent.category.LAUNCHER"))
|
||||||
.put(createCategory("com.oculus.intent.category.VR"))
|
.put(createCategory("com.oculus.intent.category.VR"))
|
||||||
.put(createCategory("com.yvr.intent.category.VR"))
|
.put(createCategory("com.yvr.intent.category.VR"))
|
||||||
|
.put(createCategory("org.khronos.openxr.intent.category.IMMERSIVE_HMD"))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,4 +8,15 @@ val PATCH_OCULUS_UNITY = Patch("patch_oculus_unity") {
|
|||||||
"(getIsOnOculusHardware\\(\\)Z.*?)return (\\w+)", "$1\nconst/4 $2, 0x1\nreturn $2"
|
"(getIsOnOculusHardware\\(\\)Z.*?)return (\\w+)", "$1\nconst/4 $2, 0x1\nreturn $2"
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
selectLibrary("libOculusXRPlugin.so") {
|
||||||
|
replaceHex(
|
||||||
|
"1F 1C 00 72 ?? ?? ?? ?? E9 07 9F 1A C0 00 80 52 20 00 A0 72 ?? ?? ?? ??",
|
||||||
|
"1F 1C 00 72 ?? ?? ?? ?? 29 00 80 52 C0 00 80 52 20 00 A0 72 ?? ?? ?? ??"
|
||||||
|
)
|
||||||
|
replaceHex(
|
||||||
|
"00 28 18 BF 01 20 ?? ?? 08 70 06 20 C0 F2 01 00",
|
||||||
|
"01 20 00 BF 00 BF ?? ?? 08 70 06 20 C0 F2 01 00"
|
||||||
|
)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,7 @@
|
|||||||
package moe.crx.overport.patches
|
package moe.crx.overport.patches
|
||||||
|
|
||||||
import moe.crx.overport.patching.Patch
|
import moe.crx.overport.patching.Patch
|
||||||
|
import moe.crx.overport.utils.nameAttribute
|
||||||
import moe.crx.overport.utils.named
|
import moe.crx.overport.utils.named
|
||||||
import moe.crx.overport.utils.takeNodesEach
|
import moe.crx.overport.utils.takeNodesEach
|
||||||
|
|
||||||
@@ -8,8 +9,12 @@ val PATCH_REMOVE_USES_LIBRARY = Patch("patch_remove_uses_library") {
|
|||||||
selectManifestJson {
|
selectManifestJson {
|
||||||
takeNodesEach({ named("manifest") }) {
|
takeNodesEach({ named("manifest") }) {
|
||||||
takeNodesEach({ named("application") }) {
|
takeNodesEach({ named("application") }) {
|
||||||
takeNodesEach({ named("uses-library") }) { null }
|
takeNodesEach({ named("uses-library") }) {
|
||||||
takeNodesEach({ named("uses-native-library") }) { null }
|
if (nameAttribute() != "libopenxr.google.so") null else this
|
||||||
|
}
|
||||||
|
takeNodesEach({ named("uses-native-library") }) {
|
||||||
|
if (nameAttribute() != "libopenxr.google.so") null else this
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,16 @@
|
|||||||
|
package moe.crx.overport.patches
|
||||||
|
|
||||||
|
import moe.crx.overport.patching.Patch
|
||||||
|
|
||||||
|
val PATCH_REMOVE_VRAPI = Patch("patch_remove_vrapi", false) {
|
||||||
|
selectWorkspace {
|
||||||
|
file.resolve("root/lib").listFiles()?.forEach { archDirectory ->
|
||||||
|
val arch = getLibraries().resolve("lib/${archDirectory.name}")
|
||||||
|
|
||||||
|
if (arch.exists()) {
|
||||||
|
val vrApi = archDirectory.listFiles().find { it.name.lowercase() == "libvrapi.so" }
|
||||||
|
vrApi?.delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -55,6 +55,12 @@ val PATCH_REPLACE_ICON_LABEL = Patch("patch_replace_icon_label") { arguments ->
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (!iconDownloaded) {
|
||||||
|
selectFile("root/res/drawable/custom_icon_ovrp.png") {
|
||||||
|
delete()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
if (iconDownloaded) {
|
if (iconDownloaded) {
|
||||||
selectPackageBlock {
|
selectPackageBlock {
|
||||||
getOrCreate("", "drawable", "custom_icon_ovrp").apply {
|
getOrCreate("", "drawable", "custom_icon_ovrp").apply {
|
||||||
|
|||||||
@@ -22,10 +22,99 @@ fun createMetadata(name: String, value: String): JSONObject {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun createMetadataFloat(name: String, value: Float): JSONObject {
|
||||||
|
return JSONObject().put("node_type", "element").put("name", "meta-data").put(
|
||||||
|
"attributes", JSONArray().put(
|
||||||
|
JSONObject().put("name", "name").put("id", 16842755)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "STRING").put("data", name)
|
||||||
|
).put(
|
||||||
|
JSONObject().put("name", "value").put("id", 16842788)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "FLOAT").put("data", value.toRawBits())
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createUsesFeature(name: String, required: Boolean): JSONObject {
|
||||||
|
return JSONObject().put("node_type", "element").put("name", "uses-feature").put(
|
||||||
|
"attributes", JSONArray().put(
|
||||||
|
JSONObject().put("name", "name").put("id", 16842755)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "STRING").put("data", name)
|
||||||
|
).put(
|
||||||
|
JSONObject().put("name", "required").put("id", 16843406)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "BOOLEAN").put("data", required)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createUsesLibrary(name: String, required: Boolean): JSONObject {
|
||||||
|
return JSONObject().put("node_type", "element").put("name", "uses-library").put(
|
||||||
|
"attributes", JSONArray().put(
|
||||||
|
JSONObject().put("name", "name").put("id", 16842755)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "STRING").put("data", name)
|
||||||
|
).put(
|
||||||
|
JSONObject().put("name", "required").put("id", 16843406)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "BOOLEAN").put("data", required)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createUsesPermission(name: String): JSONObject {
|
||||||
|
return JSONObject().put("node_type", "element").put("name", "uses-permission").put(
|
||||||
|
"attributes", JSONArray().put(
|
||||||
|
JSONObject().put("name", "name").put("id", 16842755)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "STRING").put("data", name)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun createProperty(key: String, value: String): JSONObject {
|
||||||
|
return JSONObject().put("node_type", "element").put("name", "property").put(
|
||||||
|
"attributes", JSONArray().put(
|
||||||
|
JSONObject().put("name", "name").put("id", 16842755)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "STRING").put("data", key)
|
||||||
|
).put(
|
||||||
|
JSONObject().put("name", "value").put("id", 16842788)
|
||||||
|
.put("uri", "http://schemas.android.com/apk/res/android").put("prefix", "android")
|
||||||
|
.put("value_type", "STRING").put("data", value)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
val PATCH_VR_METADATA = Patch("patch_vr_metadata") {
|
val PATCH_VR_METADATA = Patch("patch_vr_metadata") {
|
||||||
selectManifestJson {
|
selectManifestJson {
|
||||||
takeNodesEach({ named("manifest") }) {
|
takeNodesEach({ named("manifest") }) {
|
||||||
|
takeNodes {
|
||||||
|
this?.put(createUsesFeature("android.software.xr.api.openxr", true))
|
||||||
|
?.put(createUsesFeature("android.software.xr.api.spatial", true))
|
||||||
|
?.put(createUsesFeature("android.software.xr.input.controller", false))
|
||||||
|
?.put(createUsesPermission("org.khronos.openxr.permission.OPENXR"))
|
||||||
|
?.put(createUsesPermission("org.khronos.openxr.permission.OPENXR_SYSTEM"))
|
||||||
|
?.put(createUsesPermission("com.huawei.android.permission.VR"))
|
||||||
|
}
|
||||||
takeNodesEach({ named("application") }) {
|
takeNodesEach({ named("application") }) {
|
||||||
|
takeNodesEach({ named("activity") }) {
|
||||||
|
takeNodes {
|
||||||
|
this?.put(
|
||||||
|
createProperty(
|
||||||
|
"android.window.PROPERTY_XR_ACTIVITY_START_MODE",
|
||||||
|
"XR_ACTIVITY_START_MODE_FULL_SPACE_UNMANAGED"
|
||||||
|
)
|
||||||
|
)?.put(
|
||||||
|
createProperty(
|
||||||
|
"android.window.PROPERTY_XR_BOUNDARY_TYPE_RECOMMENDED",
|
||||||
|
"XR_BOUNDARY_TYPE_LARGE"
|
||||||
|
)
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
takeNodesEach({ named("meta-data") }) {
|
takeNodesEach({ named("meta-data") }) {
|
||||||
if (nameAttribute() == "com.oculus.supportedDevices") null else this
|
if (nameAttribute() == "com.oculus.supportedDevices") null else this
|
||||||
}
|
}
|
||||||
@@ -33,6 +122,15 @@ val PATCH_VR_METADATA = Patch("patch_vr_metadata") {
|
|||||||
this?.put(createMetadata("pvr.app.type", "vr"))
|
this?.put(createMetadata("pvr.app.type", "vr"))
|
||||||
?.put(createMetadata("com.yvr.intent.category.VR", "vr_only"))
|
?.put(createMetadata("com.yvr.intent.category.VR", "vr_only"))
|
||||||
?.put(createMetadata("com.oculus.supportedDevices", "all"))
|
?.put(createMetadata("com.oculus.supportedDevices", "all"))
|
||||||
|
?.put(createMetadata("com.huawei.android.vr.application.mode", "vr_only"))
|
||||||
|
?.put(createMetadata("com.huawei.android.vr.application.type", "game"))
|
||||||
|
?.put(createMetadata("com.huawei.vr.application.freeDegree", "3dof|6dof"))
|
||||||
|
?.put(createMetadataFloat("android.max_aspect", 2.1f))
|
||||||
|
?.put(createMetadata("minWaveSDKVersion", "1"))
|
||||||
|
?.put(createMetadata("com.htc.vr.content.NumController", "1,2"))
|
||||||
|
?.put(createMetadata("com.htc.vr.content.NumDoFController", "3,6DoF"))
|
||||||
|
?.put(createMetadata("com.htc.vr.content.NumDoFHmd", "3,6DoF"))
|
||||||
|
?.put(createUsesLibrary("libopenxr.google.so", false))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -8,6 +8,10 @@ class FileTransformer(val file: File) {
|
|||||||
file.writeText(Regex(input, RegexOption.DOT_MATCHES_ALL).replace(file.readText(), output))
|
file.writeText(Regex(input, RegexOption.DOT_MATCHES_ALL).replace(file.readText(), output))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun delete(): Boolean {
|
||||||
|
return file.deleteRecursively()
|
||||||
|
}
|
||||||
|
|
||||||
fun readText(): String {
|
fun readText(): String {
|
||||||
return file.readText()
|
return file.readText()
|
||||||
}
|
}
|
||||||
@@ -16,6 +20,11 @@ class FileTransformer(val file: File) {
|
|||||||
file.appendText(line)
|
file.appendText(line)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fun appendLine(line: String) {
|
||||||
|
append(line)
|
||||||
|
append("\n")
|
||||||
|
}
|
||||||
|
|
||||||
fun readJson(): JSONObject? {
|
fun readJson(): JSONObject? {
|
||||||
return runCatching { JSONObject(file.readText()) }.getOrNull()
|
return runCatching { JSONObject(file.readText()) }.getOrNull()
|
||||||
}
|
}
|
||||||
@@ -35,6 +44,10 @@ class FileTransformer(val file: File) {
|
|||||||
fun replaceHex(input: String, output: String) {
|
fun replaceHex(input: String, output: String) {
|
||||||
val bytes = file.readBytes()
|
val bytes = file.readBytes()
|
||||||
val inputBytes = input.split(' ')
|
val inputBytes = input.split(' ')
|
||||||
|
val outputBytes = output.split(' ')
|
||||||
|
var startIndex = -1
|
||||||
|
|
||||||
|
check(inputBytes.size == outputBytes.size)
|
||||||
|
|
||||||
for (i in 0..<bytes.size - inputBytes.size + 1) {
|
for (i in 0..<bytes.size - inputBytes.size + 1) {
|
||||||
var matches = true
|
var matches = true
|
||||||
@@ -52,12 +65,22 @@ class FileTransformer(val file: File) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (matches) {
|
if (matches) {
|
||||||
val replaced = bytes.slice(0..<i) +
|
startIndex = i
|
||||||
output.split(' ').map { it.toUByte(16).toByte() } +
|
}
|
||||||
bytes.slice(i + inputBytes.size..<bytes.size)
|
}
|
||||||
file.writeBytes(replaced.toByteArray())
|
|
||||||
|
if (startIndex == -1) {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (i in 0..<inputBytes.size) {
|
||||||
|
if (outputBytes[i] != "??") {
|
||||||
|
bytes[i + startIndex] = outputBytes[i].toUByte(16).toByte()
|
||||||
|
} else if (inputBytes[i] != "??") {
|
||||||
|
bytes[i + startIndex] = inputBytes[i].toUByte(16).toByte()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
file.writeBytes(bytes)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -42,6 +42,7 @@ object PatchStore {
|
|||||||
register(PATCH_META_XR_AUDIO)
|
register(PATCH_META_XR_AUDIO)
|
||||||
register(PATCH_MARK_AS_DEBUGGABLE)
|
register(PATCH_MARK_AS_DEBUGGABLE)
|
||||||
register(PATCH_MARK_ALLOW_BACKUP)
|
register(PATCH_MARK_ALLOW_BACKUP)
|
||||||
|
register(PATCH_REMOVE_VRAPI)
|
||||||
register(PATCH_REMOVE_UNREAL_FORCE_QUIT)
|
register(PATCH_REMOVE_UNREAL_FORCE_QUIT)
|
||||||
register(PATCH_FORCE_PASSTHROUGH)
|
register(PATCH_FORCE_PASSTHROUGH)
|
||||||
register(PATCH_DISABLE_SPACE_WARP)
|
register(PATCH_DISABLE_SPACE_WARP)
|
||||||
|
|||||||
@@ -6,6 +6,7 @@ import com.reandroid.archive.ArchiveFile
|
|||||||
import com.reandroid.archive.FileInputSource
|
import com.reandroid.archive.FileInputSource
|
||||||
import com.reandroid.archive.io.ZipFileInput
|
import com.reandroid.archive.io.ZipFileInput
|
||||||
import moe.crx.overport.config.OverportPatchedInfo
|
import moe.crx.overport.config.OverportPatchedInfo
|
||||||
|
import moe.crx.overport.utils.CantCheckoutException
|
||||||
import moe.crx.overport.utils.NameFormatter
|
import moe.crx.overport.utils.NameFormatter
|
||||||
import moe.crx.overport.versions.VersionManager
|
import moe.crx.overport.versions.VersionManager
|
||||||
import org.jf.baksmali.Baksmali
|
import org.jf.baksmali.Baksmali
|
||||||
@@ -51,14 +52,8 @@ class PatcherContext(
|
|||||||
}
|
}
|
||||||
|
|
||||||
fun checkout() {
|
fun checkout() {
|
||||||
var successful = VersionManager(patcherDirectory).checkout(overportVersion)
|
overportVersion = VersionManager(patcherDirectory).checkout(overportVersion)
|
||||||
|
?: throw CantCheckoutException("Can't checkout an overport release. Please, check your internet connection or choose another version.")
|
||||||
if (successful == null) {
|
|
||||||
successful = VersionManager(patcherDirectory).checkout("latest")
|
|
||||||
}
|
|
||||||
|
|
||||||
checkNotNull(successful)
|
|
||||||
overportVersion = successful
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fun prepare(stream: InputStream) {
|
fun prepare(stream: InputStream) {
|
||||||
|
|||||||
@@ -0,0 +1,3 @@
|
|||||||
|
package moe.crx.overport.utils
|
||||||
|
|
||||||
|
class CantCheckoutException(message: String) : IllegalStateException(message)
|
||||||
@@ -10,7 +10,7 @@ class VersionManager(val workingDirectory: File) {
|
|||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
val json = Json { ignoreUnknownKeys = true }
|
val json = Json { ignoreUnknownKeys = true }
|
||||||
const val VERSION = "1.2.0"
|
const val VERSION = "1.2.3"
|
||||||
|
|
||||||
private fun isVersionLower(left: String, right: String): Boolean {
|
private fun isVersionLower(left: String, right: String): Boolean {
|
||||||
val (lY, lM, lD) = left.substringBeforeLast('-').split('.').map { it.toInt() }
|
val (lY, lM, lD) = left.substringBeforeLast('-').split('.').map { it.toInt() }
|
||||||
@@ -80,6 +80,7 @@ class VersionManager(val workingDirectory: File) {
|
|||||||
if (installedEntry != null) {
|
if (installedEntry != null) {
|
||||||
val librariesDir = workingDirectory.resolve("libraries/${installedEntry.version}")
|
val librariesDir = workingDirectory.resolve("libraries/${installedEntry.version}")
|
||||||
if (librariesDir.isDirectory) {
|
if (librariesDir.isDirectory) {
|
||||||
|
appendInstalled(installedEntry)
|
||||||
return installedEntry.version
|
return installedEntry.version
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -132,7 +133,7 @@ class VersionManager(val workingDirectory: File) {
|
|||||||
o2.version
|
o2.version
|
||||||
)
|
)
|
||||||
) 1 else -1
|
) 1 else -1
|
||||||
})
|
}).filter { workingDirectory.resolve("libraries/${it.version}").isDirectory }
|
||||||
}
|
}
|
||||||
|
|
||||||
return listOf()
|
return listOf()
|
||||||
|
|||||||
Reference in new issue
Block a user