Daijishou icon indicating copy to clipboard operation
Daijishou copied to clipboard

Sony PlayStation Vita Platform

Open Cp1N3m0 opened this issue 2 years ago • 18 comments
trafficstars

Please add Sony PlayStation Vita as Platform

https://vita3k.org/ https://github.com/Vita3K/Vita3K-Android

Cp1N3m0 avatar Feb 14 '23 15:02 Cp1N3m0

Sure. I have contacted vita3k author. And fortunately, they said they are working on it!

TapiocaFox avatar Feb 21 '23 14:02 TapiocaFox

Thank you

Cp1N3m0 avatar Mar 03 '23 10:03 Cp1N3m0

Vita3k new update has came with support. So, you should add it now

Mente2 avatar Mar 26 '23 14:03 Mente2

Vita3k new update has came with support. So, you should add it now

thanks will test it

Cp1N3m0 avatar Mar 31 '23 10:03 Cp1N3m0

So, I have updated Daijishou and Vita3K

imported the platform, https://github.com/magneticchen/Daijishou/blob/main/platforms/SonyPSVita.json.test

and added "Android/data/org.vita3k.emulation/files/vita/ux0/app" as a path but no games are detected, am I doing something wrong

Thanks

Cp1N3m0 avatar Mar 31 '23 11:03 Cp1N3m0

Btw, I changed the parameter flag in V3 from AppRestartParameters to AppStartParameters in case you are wondering why this command does not work anymore. I'm not planning on changing it again.

Macdu avatar Apr 02 '23 10:04 Macdu

Btw, I changed the parameter flag in V3 from AppRestartParameters to AppStartParameters in case you are wondering why this command does not work anymore. I'm not planning on changing it again.

Thanks. I will try this command.

TapiocaFox avatar Apr 02 '23 13:04 TapiocaFox

Sorry for the late update. I've tried AppStartParameters with vita's application id to launch vita game. While it works via adb command from PC. It doesn't work directly in Daijishou, however. It launched Vita3k, but only the home screen menu displayed.

I've carefully checked several times whether I've implement it incorrectly, but nothing quirky afaik. A mention that Dai implements the am start parameter directly from AOSP project. I have no idea what goes wrong preventing it working for now. Not sure if anything missing from my side.

Here is the snippet related.

/*
 * Copyright(c) 2023 Daijishou project, TapiocaFox. All rights reserved.
 * Created by TapiocaFox (magneticchen) on 21/03/2023, 09:36.
 * Last modified 17/03/2023, 06:45.
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *     http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */

package com.magneticchen.daijishou.daijishou_player

import android.content.ComponentName
import android.content.Intent
import android.net.Uri
import android.os.Bundle
import android.util.Log.d
import java.net.URISyntaxException
import java.util.*


/*
 * Copyright (C) 2006 The Android Open Source Project
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 *
 *      http://www.apache.org/licenses/LICENSE-2.0
 *
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */


// See https://github.com/aosp-mirror/platform_frameworks_base/blob/master/core/java/android/content/Intent.java
// parseCommandargumentLinkedList method

internal object AmStartCommandToIntentConverter {
    @Throws(URISyntaxException::class)
    fun createIntentByCommandArgs(arguments: String, tokenReplaceList: List<Pair<String, String>>): Intent {

        val argumentSplitted = arguments.split("[\\n\\s]+".toRegex())
        val argumentsReplacedAndSplit = List(argumentSplitted.size) { i ->
            var string = argumentSplitted[i]
            tokenReplaceList.forEach{
                string = string.replace(it.first, it.second)
            }
            string
        }

        val argumentLinkedList: LinkedList<String> = LinkedList(argumentsReplacedAndSplit)
        var intent = Intent()
        var baseIntent: Intent? = intent
        var hasIntentInfo = false
        var data: Uri? = null
        var type: String? = null
        while (!argumentLinkedList.isEmpty()) {
            when (val opt = argumentLinkedList.pop()) {
                "-a" -> {
                    intent.action = argumentLinkedList.pop()
                    if (intent === baseIntent) hasIntentInfo = true
                }
                "-d" -> {
                    data = Uri.parse(argumentLinkedList.pop())
//                    d("daijishou_debug", "$data")
                    if (intent === baseIntent) hasIntentInfo = true
                }
                "-t" -> {
                    type = argumentLinkedList.pop()
                    if (intent === baseIntent) hasIntentInfo = true
                }
                "-i" -> {
                    intent.identifier = argumentLinkedList.pop()
                    if (intent === baseIntent) hasIntentInfo = true
                }
                "-c" -> {
                    intent.addCategory(argumentLinkedList.pop())
                    if (intent === baseIntent) hasIntentInfo = true
                }
                "-e", "--es" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    intent.putExtra(key, value)
                }
                "--esn" -> {
                    val key = argumentLinkedList.pop()
                    intent.putExtra(key, null as String?)
                }
                "--ei" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    intent.putExtra(key, Integer.decode(value))
                }
                "--eu" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    intent.putExtra(key, Uri.parse(value))
                }
                "--ecn" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    val cn = ComponentName.unflattenFromString(value)
                        ?: throw IllegalArgumentException("Bad component name: $value")
                    intent.putExtra(key, cn)
                }
                "--eia" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    val strings = value.split(",").toTypedArray()
                    val list = IntArray(strings.size)
                    var i = 0
                    while (i < strings.size) {
                        list[i] = Integer.decode(strings[i])
                        i++
                    }
                    intent.putExtra(key, list)
                }
                "--eial" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    val strings = value.split(",").toTypedArray()
                    val list = ArrayList<Int>(strings.size)
                    var i = 0
                    while (i < strings.size) {
                        list.add(Integer.decode(strings[i]))
                        i++
                    }
                    intent.putExtra(key, list)
                }
                "--el" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    intent.putExtra(key, java.lang.Long.valueOf(value))
                }
                "--ela" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    val strings = value.split(",").toTypedArray()
                    val list = LongArray(strings.size)
                    var i = 0
                    while (i < strings.size) {
                        list[i] = java.lang.Long.valueOf(strings[i])
                        i++
                    }
                    intent.putExtra(key, list)
                    hasIntentInfo = true
                }
                "--elal" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    val strings = value.split(",").toTypedArray()
                    val list = ArrayList<Long>(strings.size)
                    var i = 0
                    while (i < strings.size) {
                        list.add(java.lang.Long.valueOf(strings[i]))
                        i++
                    }
                    intent.putExtra(key, list)
                    hasIntentInfo = true
                }
                "--ef" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    intent.putExtra(key, java.lang.Float.valueOf(value))
                    hasIntentInfo = true
                }
                "--efa" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    val strings = value.split(",").toTypedArray()
                    val list = FloatArray(strings.size)
                    var i = 0
                    while (i < strings.size) {
                        list[i] = java.lang.Float.valueOf(strings[i])
                        i++
                    }
                    intent.putExtra(key, list)
                    hasIntentInfo = true
                }
                "--efal" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    val strings = value.split(",").toTypedArray()
                    val list = ArrayList<Float>(strings.size)
                    var i = 0
                    while (i < strings.size) {
                        list.add(java.lang.Float.valueOf(strings[i]))
                        i++
                    }
                    intent.putExtra(key, list)
                    hasIntentInfo = true
                }
                "--esa" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    // Split on commas unless they are preceeded by an escape.
                    // The escape character must be escaped for the string and
                    // again for the regex, thus four escape characters become one.
                    val strings = value.split("(?<!\\\\),").toTypedArray()
                    intent.putExtra(key, strings)
                    hasIntentInfo = true
                }
                "--esal" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop()
                    // Split on commas unless they are preceeded by an escape.
                    // The escape character must be escaped for the string and
                    // again for the regex, thus four escape characters become one.
                    val strings = value.split("(?<!\\\\),").toTypedArray()
                    val list = ArrayList<String>(strings.size)
                    var i = 0
                    while (i < strings.size) {
                        list.add(strings[i])
                        i++
                    }
                    intent.putExtra(key, list)
                    hasIntentInfo = true
                }
                "--ez" -> {
                    val key = argumentLinkedList.pop()
                    val value = argumentLinkedList.pop().lowercase(Locale.getDefault())
                    // Boolean.valueOf() results in false for anything that is not "true", which is
                    // error-prone in shell commands
                    val arg: Boolean = if ("true" == value || "t" == value) {
                        true
                    } else if ("false" == value || "f" == value) {
                        false
                    } else {
                        try {
                            Integer.decode(value) != 0
                        } catch (ex: NumberFormatException) {
                            throw IllegalArgumentException("Invalid boolean value: $value")
                        }
                    }
                    intent.putExtra(key, arg)
                }
                "-n" -> {
                    val str = argumentLinkedList.pop()
                    val cn = ComponentName.unflattenFromString(str)
                        ?: throw IllegalArgumentException("Bad component name: $str")
                    intent.component = cn
                    if (intent === baseIntent) hasIntentInfo = true
                }
                "-p" -> {
                    val str = argumentLinkedList.pop()
                    intent.setPackage(str)
                    if (intent === baseIntent) hasIntentInfo = true
                }
                "-f" -> {
                    val str = argumentLinkedList.pop()
                    intent.flags = Integer.decode(str).toInt()
                }
                "--grant-read-uri-permission" -> intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
                "--grant-write-uri-permission" -> intent.addFlags(Intent.FLAG_GRANT_WRITE_URI_PERMISSION)
                "--grant-persistable-uri-permission" -> intent.addFlags(Intent.FLAG_GRANT_PERSISTABLE_URI_PERMISSION)
                "--grant-prefix-uri-permission" -> intent.addFlags(Intent.FLAG_GRANT_PREFIX_URI_PERMISSION)
                "--exclude-stopped-packages" -> intent.addFlags(Intent.FLAG_EXCLUDE_STOPPED_PACKAGES)
                "--include-stopped-packages" -> intent.addFlags(Intent.FLAG_INCLUDE_STOPPED_PACKAGES)
                "--debug-log-resolution" -> intent.addFlags(Intent.FLAG_DEBUG_LOG_RESOLUTION)
                "--activity-brought-to-front" -> intent.addFlags(Intent.FLAG_ACTIVITY_BROUGHT_TO_FRONT)
                "--activity-clear-top" -> intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP)
                "--activity-clear-when-task-reset" -> intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_WHEN_TASK_RESET)
                "--activity-exclude-from-recents" -> intent.addFlags(Intent.FLAG_ACTIVITY_EXCLUDE_FROM_RECENTS)
                "--activity-launched-from-history" -> intent.addFlags(Intent.FLAG_ACTIVITY_LAUNCHED_FROM_HISTORY)
                "--activity-multiple-task" -> intent.addFlags(Intent.FLAG_ACTIVITY_MULTIPLE_TASK)
                "--activity-no-animation" -> intent.addFlags(Intent.FLAG_ACTIVITY_NO_ANIMATION)
                "--activity-no-history" -> intent.addFlags(Intent.FLAG_ACTIVITY_NO_HISTORY)
                "--activity-no-user-action" -> intent.addFlags(Intent.FLAG_ACTIVITY_NO_USER_ACTION)
                "--activity-previous-is-top" -> intent.addFlags(Intent.FLAG_ACTIVITY_PREVIOUS_IS_TOP)
                "--activity-reorder-to-front" -> intent.addFlags(Intent.FLAG_ACTIVITY_REORDER_TO_FRONT)
                "--activity-reset-task-if-needed" -> intent.addFlags(Intent.FLAG_ACTIVITY_RESET_TASK_IF_NEEDED)
                "--activity-single-top" -> intent.addFlags(Intent.FLAG_ACTIVITY_SINGLE_TOP)
                "--activity-clear-task" -> intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TASK)
                "--activity-task-on-home" -> intent.addFlags(Intent.FLAG_ACTIVITY_TASK_ON_HOME)
                "--activity-match-external" -> intent.addFlags(Intent.FLAG_ACTIVITY_MATCH_EXTERNAL)
                "--receiver-registered-only" -> intent.addFlags(Intent.FLAG_RECEIVER_REGISTERED_ONLY)
                "--receiver-replace-pending" -> intent.addFlags(Intent.FLAG_RECEIVER_REPLACE_PENDING)
                "--receiver-foreground" -> intent.addFlags(Intent.FLAG_RECEIVER_FOREGROUND)
                "--receiver-no-abort" -> intent.addFlags(Intent.FLAG_RECEIVER_NO_ABORT)
                "--selector" -> {
                    intent.setDataAndType(data, type)
                    intent = Intent()
                }

                // Ignore below "am start" arguments key and pop value too.
                "-P", "--user", "--start-profiler", "--sampling", "--attach-agent", "--attach-agent-bind", "-R", "--receiver-permission", "--display", "--windowingMode", "--activityType", "--task" -> {
                    argumentLinkedList.pop()
                }
                // Ignore below singular "am start" arguments key.
                "", "-D", "-N", "-W", "-S", "--streaming", "--track-allocation", "--task-overlay", "--lock-task", "--allow-background-activity-starts" -> {}

                else -> throw IllegalArgumentException("Unknown option: $opt")
            }
        }
        intent.setDataAndType(data, type)
        val hasSelector = intent !== baseIntent
        if (hasSelector) {
            // A selector was specified; fix up.
            baseIntent!!.selector = intent
            intent = baseIntent
        }
        val arg = if (argumentLinkedList.isEmpty()) null else argumentLinkedList.pop()
        baseIntent = null
        if (arg == null) {
            if (hasSelector) {
                // If a selector has been specified, and no arguments
                // have been supplied for the main Intent, then we can
                // assume it is ACTION_MAIN CATEGORY_LAUNCHER; we don't
                // need to have a component name specified yet, the
                // selector will take care of that.
                baseIntent = Intent(Intent.ACTION_MAIN)
                baseIntent.addCategory(Intent.CATEGORY_LAUNCHER)
            }
        } else if (arg.indexOf(':') >= 0) {
            // The argument is a URI.  Fully parse it, and use that result
            // to fill in any data not specified so far.
            baseIntent = Intent.parseUri(
                arg, Intent.URI_INTENT_SCHEME
                        or Intent.URI_ANDROID_APP_SCHEME or Intent.URI_ALLOW_UNSAFE
            )
        } else if (arg.indexOf('/') >= 0) {
            // The argument is a component name.  Build an Intent to launch
            // it.
            baseIntent = Intent(Intent.ACTION_MAIN)
            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER)
            baseIntent.component = ComponentName.unflattenFromString(arg)
        } else {
            // Assume the argument is a package name.
            baseIntent = Intent(Intent.ACTION_MAIN)
            baseIntent.addCategory(Intent.CATEGORY_LAUNCHER)
            baseIntent.setPackage(arg)
        }
        if (baseIntent != null) {
            var extras = intent.extras
            intent.replaceExtras(null as Bundle?)
            val uriExtras = baseIntent.extras
            baseIntent.replaceExtras(null as Bundle?)
            if (intent.action != null && baseIntent.categories != null) {
                val cats = HashSet(baseIntent.categories)
                for (c in cats) {
                    baseIntent.removeCategory(c)
                }
            }
            intent.fillIn(baseIntent, Intent.FILL_IN_COMPONENT or Intent.FILL_IN_SELECTOR)
            if (extras == null) {
                extras = uriExtras
            } else if (uriExtras != null) {
                uriExtras.putAll(extras)
                extras = uriExtras
            }
            intent.replaceExtras(extras)
            hasIntentInfo = true
        }
        require(hasIntentInfo) { "No intent supplied" }
        // Add addition flags for player.
        intent.addFlags(Intent.FLAG_ACTIVITY_NEW_TASK)
        intent.addFlags(Intent.FLAG_GRANT_READ_URI_PERMISSION)
        return intent
    }
}

TapiocaFox avatar Apr 17 '23 17:04 TapiocaFox

Any further thoughts on this one? Working on testing this as well and encountered the same issue

mantis-droid avatar Aug 24 '23 22:08 mantis-droid

Has anyone had any success with this? I am running into the same issue of Daijishou only launching to the home screen. Maybe it's worth taking a look at how ES-DE does it as it works there?

mroemore avatar Mar 15 '24 15:03 mroemore

Seeming to have the same issue, tried putting the actual id of the game in the daijisho parameters as well as changing AppStartParameters to AppRestartParameters but neither seems to work to launch the game

stevenbrookslv avatar Mar 27 '24 08:03 stevenbrookslv

val strings = value.split("(?<!\\\\),").toTypedArray() to val strings = value.split("(?<!\\\\),".toRegex()).toTypedArray()

Otherwise, Kotlin cannot use regex .

It works fine with the following configuration . "amStartArguments": "-n org.vita3k.emulator/org.vita3k.emulator.Emulator\n --esa AppStartParameters -r(?<!\\\\),{tags.game_id}",

@TapiocaFox

EagleFlyInSky avatar Mar 31 '24 06:03 EagleFlyInSky

Thanks again, as noted in #652 I added Vita to the platform list. I will create a section in the wiki on how to create dpt files.

Added in 0588af3

If others can test and report the android version and device they are using that would be great. I confirmed it working on the Retroid Pocket 4 Pro/Android 13

Jetup13 avatar Apr 22 '24 21:04 Jetup13

@Jetup13 Good day! Ayn Odin Lite, Android 11, Vita3k v11 (latest version), all is working great. I guess it's no matter what device are used, except OS version.

smlcr avatar Apr 23 '24 18:04 smlcr

I imported the recent SonyPSVita.json file located at https://github.com/TapiocaFox/Daijishou/blob/main/platforms/SonyPSVita.json The VITA platform appears well in daijishou on my R4PPRO On the other hand, I don't understand how to create a link with VITA3K. Create a DPT? how ? what should you put inside? Thank you for your help.

salamandercc37 avatar Apr 25 '24 06:04 salamandercc37

@salamandercc37 I explained how to add Vita games in the wiki here. Within that link I also pregenerated a few thousand dpt files that anyone can use.

Jetup13 avatar Apr 25 '24 06:04 Jetup13

@salamandercc37 I explained how to add Vita games in the wiki here. Within that link I also pregenerated a few thousand dpt files that anyone can use.

Thank you for your quick reply. I'm going to try this tonight when I get home.

salamandercc37 avatar Apr 25 '24 07:04 salamandercc37

@salamandercc37 I explained how to add Vita games in the wiki here. Within that link I also pregenerated a few thousand dpt files that anyone can use.

Thank you for your help. Everything works perfectly

salamandercc37 avatar Apr 26 '24 09:04 salamandercc37

val strings = value.split("(?<!\\\\),").toTypedArray() to val strings = value.split("(?<!\\\\),".toRegex()).toTypedArray()

Otherwise, Kotlin cannot use regex .

It works fine with the following configuration . "amStartArguments": "-n org.vita3k.emulator/org.vita3k.emulator.Emulator\n --esa AppStartParameters -r(?<!\\\\),{tags.game_id}",

@TapiocaFox

I will update that on 1.4.69.

TapiocaFox avatar Aug 21 '24 14:08 TapiocaFox