RetroPie forum home
    • Recent
    • Tags
    • Popular
    • Home
    • Docs
    • Register
    • Login
    Please do not post a support request without first reading and following the advice in https://retropie.org.uk/forum/topic/3/read-this-first

    Guide: AM2R (Another Metroid 2 Remake) on RPi 4

    Scheduled Pinned Locked Moved Help and Support
    guideam2rscriptmodule
    44 Posts 9 Posters 11.5k Views
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • S
      sleve_mcdichael
      last edited by sleve_mcdichael

      Guide: droidports/gmloader

      GMLoader - play GameMaker Studio games for Android on non-Android operating systems

      Runs AM2R (and potentially other Android APKs) natively on Pi 4 RetroPie/Raspbian, without Android OS, Android emulation, or box86/wine (x86/Windows emulation for ARM Linux).

      Thanks:
      reddit.com/u/TheRealLarkas who wrote the guide I based this on, and
      github.com/JohnnyonFlame who wrote the software that it uses and pushed a fix for me in the middle of the night, and
      @mitu for holding my hand through the scripting process.

      A scriptmodule has been developed. Pi 4 only. No game data is provided. No warranty is provided. The droidports project is still in early alpha. Run the install from the "experimental : ports" section of the setup script after placing your .apk file(s) in ~/RetroPie/roms/ports/droidports. Please test:

      GMLoader-RPi

      wget https://raw.githubusercontent.com/s1eve-mcdichae1/GMLoader-RPi/main/gmloader.sh -P $HOME/RetroPie-Setup/scriptmodules/ports/
      

      To get the APK you need the original AM2R 1.1.zip (from...sources) and the AM2RLauncher from AM2R-Community-Developers on GitHub. The launcher will patch the 1.1 game to the latest Community Updates version (currently 1.5.5) and then you have the option to create an APK from right there in the launcher.

      Note: the original guide suggests increasing the gpu_mem value to 256, or even 512. This goes against the official documentation, and preliminary testing shows it is not strictly necessary. I've got the game running (at least as far as the first save point -- EDIT: I've got about an hour in, killed the first ten or twelve Alphas, all seems well) with the default (unset) memory split (equivalent to gpu_mem=76 on Pi4.) I'm not sure if increasing it would help anything or not; I keep reading that "the 3D component of the GPU has its own memory management unit and does not use memory from the gpu_mem allocation," but this looks like a 2D game so I don't know if the 3D component is relevant or not?

      In any case, the maximum recommended value for gpu_mem on Pi 4, per the documentation, is 256, and setting it any higher than necessary may be detrimental.


      Manual install:

      # install dependencies:
      sudo apt install -y libopenal-dev libfreetype6-dev zlib1g-dev libbz2-dev libpng-dev libzip-dev libsdl2-image-dev cmake git
      
      # clone repo:
      cd
      git clone https://github.com/JohnnyonFlame/droidports --recursive
      cd droidports
      
      # force commit (optional):
      git reset --hard faf3970
      # (omit this step to use latest version)
      
      # build/compile gmloader:
      mkdir build-gmloader
      cd build-gmloader
      cmake CMakeLists.txt -DCMAKE_BUILD_TYPE=Release -DPLATFORM=linux -DPORT=gmloader ..
      make -j$(($(nproc)+1))
      

      This compiles the executable gmloader which we then retain, all other build files can be removed:

      # make a directory for the executable:
      sudo mkdir -p /opt/retropie/ports/gmloader
      
      # retain executable and clean up:
      sudo mv ~/droidports/build-gmloader/gmloader /opt/retropie/ports/gmloader/
      rm -rf ~/droidports/
      

      Make a folder for the .apk. Source the .apk and put it in that folder:

      # make rom dir for apk files:
      mkdir -p ~/RetroPie/roms/ports/droidports
      # put your .apk file(s) here
      

      To run, just call gmloader with the path to the .apk as the only argument, for example:

      # launch AM2R 1.5.5:
      "/opt/retropie/ports/gmloader/gmloader" "~/RetroPie/roms/ports/droidports/am2r_155.apk"
      

      So to integrate this with runcommand.sh I've got the config file at /opt/retropie/configs/ports/droidports/emulators.cfg:

      gmloader = "/opt/retropie/ports/gmloader/gmloader %ROM%"
      default = "gmloader"
      

      And then the launch script for the ES ports menu uses the standard runcommand syntax, for example ~/RetroPie/roms/ports/am2r_155.sh:

      #!/bin/bash
      "/opt/retropie/supplementary/runcommand/runcommand.sh" 0 _PORT_ "droidports" "/home/pi/RetroPie/roms/ports/droidports/am2r_155.apk"
      

      Configs are saved to ~/.config/<apk_name> folder, for example:

      ~/.config/am2r_155/
      

      I moved this to the /opt/retropie/configs/ports/droidports directory and pointed to it with a symlink:

      mv ~/.config/am2r_155 /opt/retropie/configs/ports/droidports
      ln -s /opt/retropie/configs/ports/droidports/am2r_155 ~/.config/am2r_155
      

      If you haven't played the game at least once yet, you can create the directory instead of moving it:

      mkdir -p /opt/retropie/configs/ports/droidports/am2r_155
      ln -s /opt/retropie/configs/ports/droidports/am2r_155 ~/.config/am2r_155
      

      If you've never installed a port before through the setup menu, you will need to manually add the "ports" system. Or just install another port and it will be added automatically. To do it manually:

      EmulationStation checks two places for an es_systems.cfg file, using the first one that it finds:

      ~/.emulationstation/es_systems.cfg

      /etc/emulationstation/es_systems.cfg

      The second one gets written automatically. The first one doesn't exist until you make it. The second one gets overwritten automatically, so any custom edits must be made to the first one, so they are not lost when this happens.

      Copy the systems config file to the custom location if it does not exist:

      # copy default es_systems.cfg if custom file does not exist:
      [[ ! -f ~/.emulationstation/es_systems.cfg ]] && cp /etc/emulationstation/es_systems.cfg ~/.emulationstation/
      
      # edit the custom config file:
      nano ~/.emulationstation/es_systems.cfg
      

      Systems are displayed in the order in which they appear in this file. By default they are sorted alphabetically but I like to put RetroPie, Ports, and Arcade right at the top. Decide where you want the "Ports" system and add the following code either before, after, or in between the existing systems:

        <system>
          <name>ports</name>
          <fullname>Ports</fullname>
          <path>/home/pi/RetroPie/roms/ports</path>
          <extension>.sh .SH</extension>
          <command>bash %ROM%</command>
          <platform>pc</platform>
          <theme>ports</theme>
        </system>
      

      After making the addition, use Ctrl-S to save and Ctrl-X to exit.


      And that should be it. Next up, see if I can make it into a scriptmodule...

      S 1 Reply Last reply Reply Quote 0
      • S
        sleve_mcdichael @sleve_mcdichael
        last edited by sleve_mcdichael

        Can anyone help me turn this into a scriptmodule? Here's what I've got so far, based on reading some of the other modules. I start with the shebang and the standard disclaimers:

        #!/usr/bin/env bash
        
        # This file is part of The RetroPie Project
        # 
        # The RetroPie Project is the legal property of its developers, whose names are
        # too numerous to list here. Please refer to the COPYRIGHT.md file distributed with this source.
        # 
        # See the LICENSE.md file at the top-level directory of this distribution and 
        # at https://raw.githubusercontent.com/RetroPie/RetroPie-Setup/master/LICENSE.md
        #
        

        Next up, the "header" section.

        The droidports project is in early alpha and subject to change, so we want to lock it for now at a commit that we know works (the author was kind enough to push a fix for me the other night, that was causing it to crash at the title screen), I think I can do that by adding [branch] [commit] after the repo URL?

        This works on Pi 4. It is said to also work on 2 and 3 although they need extra steps, and I don't know at all about other platforms. Do I just flag it rpi4, or do I also need !all, or how does this work?

        rp_module_id="gmloader"
        rp_module_desc="GMLoader - play GameMaker Studio games for Android on non-Android operating systems"
        rp_module_help="Copy your APK files to $romdir/ports/droidports"
        rp_module_repo="git https://github.com/JohnnyonFlame/droidports.git master faf3970"
        rp_module_licence="GPL3 https://github.com/JohnnyonFlame/droidports/blob/master/LICENSE.md"
        rp_module_section="exp"
        rp_module_flags="!all rpi4"
        

        Depends: libopenal-dev libfreetype6-dev zlib1g-dev libbz2-dev libpng-dev libzip-dev libsdl2-image-dev cmake git

        Are any of these default and don't need to be explicitly stated? Git, for example. Other modules use it, but don't list in their depends. I can leave it out, right? Can I leave any of the rest of these out?

        function depends_gmloader() {
            getDepends libopenal-dev libfreetype6-dev zlib1g-dev libbz2-dev libpng-dev libzip-dev libsdl2-image-dev cmake
        }
        

        Sources: git clone https://github.com/JohnnyonFlame/droidports --recursive

        Is it as easy as gitPullOrClone? By adding [branch] [commit] to the rp_module_repo URL, this rollback will be automatically handled by the helper function? And it looks like the --recursive flag is already baked-in, too?

        function sources_gmloader() {
            gitPullOrClone
        }
        

        Build:

        cd droidports
        mkdir build-gmloader
        cd build-gmloader

        cmake CMakeLists.txt -DCMAKE_BUILD_TYPE=Release -DPLATFORM=linux -DPORT=gmloader ..

        make -j$(($(nproc)+1))

        It starts with a cd into the repo, then creates and enters a dedicated build directory. It looks like I can do this without faffing about with the build directory, and can even trim a word off of the command. The following gives an identical output file to the longer version above:

        cd droidports
        cmake . -DCMAKE_BUILD_TYPE=Release -DPLATFORM=linux -DPORT=gmloader
        make -j$(($(nproc)+1))

        It seems to work, but I have pretty much no idea what I'm doing here. Is there any reason not to do it like this?

        And it looks like I don't need the initial cd into the repo here, as these commands are performed from within the $md_build folder, is that right?

        So as a function I think that would look like:

        function build_gmloader() {
          cmake . -DCMAKE_BUILD_TYPE=Release -DPLATFORM=linux -DPORT=gmloader
          make -j$(($(nproc)+1))
          md_ret_require="$md_build/gmloader"
        }
        

        Install: retain executable, clean up other files

        With the above changes, the executable builds in the droidports folder. This is equivalent to $md_build, yes?

        That is the only file that needs to be kept. Is this all it takes, and does the file end up at /opt/retropie/ports/gmloader/gmloader when it's all over?

        function install_gmloader() {
            md_ret_files="$md_build/gmloader"
        }
        

        ...and here is where I'm a bit out of my element. I know it needs at least a configure function. We need to make the emulators.cfg file:

        gmloader = "/opt/retropie/ports/gmloader/gmloader %ROM"
        default = "gmloader"
        

        (Or is it ports/droidports/gmloader? Is it based on $md_build or $rp_module_id? Or something else?)

        I think we do this with the addPort function, which also makes the launch script(s)? So we need another function to check the rom folder for .apk files and run an addPort on any/all that we find?

        Ports like lr-prboom or wolf4sdl have shareware versions they can download and run addPort on if they don't find any game files. What do we do here if we don't find an .apk?

        There's also the config dirs to symlink (moveConfigDir?), this is also on a per-apk basis so this would be rolled into our other function that looks for those? Something -- and here's where my scripting skills, or lack thereof, will show themselves -- like:

        function add_games_gmloader() {
            # find apk files
            for apk in $romdir/ports/droidports/*.apk $romdir/ports/droidports/*.APK
        
                # for each:
                do
                    local apk_filename="${apk##*/}"
                    local apk_basename="${apk_filename%.*}"
                    addPort "$md_id" "droidports" "$apk_basename" "$md_inst/gmloader %ROM%" "$apk"
                    moveConfigDir "$home/.config/$apk_basename" "$md_conf_root/droidports/$apk_basename"
        
                done
        }
        
        function configure_gmloader() {
            mkRomDir "ports/droidports"
            add_games_gmloader
        }
        

        I say something like that, but not that exactly, because even if it did work, I'm sure it would do weird stuff when there are no files in the apk folder. Can anyone help me with the finishing touches on this?

        1 Reply Last reply Reply Quote 0
        • mituM
          mitu Global Moderator
          last edited by

          For the most part the module is ok.

          Are any of these default and don't need to be explicitly stated? Git, for example

          You can omit git, since it's used by RetroPie-Setup internally, so it's a hard dependency. The other dependencies are ok.

          Is it as easy as gitPullOrClone?

          Yes, gitPullOrClone is enough, as long as you've listed the necessary repo/branch/commit in md_module_repo. It uses --recursive when cloning the repository, so any submodules are cloned also.

          With the above changes, the executable builds in the droidports folder. This is equivalent to $md_build, yes?

          Yes. The build part looks ok, though best practice is for cmake to build out of tree and the folder where CMakeLists.txt is located should be the last parameter. The RetroPie-Setup script sets MAKEFLAGS accordingly (looking at the # of CPUs and the memory) so you don't have to add -j.

          mkdir build && cd build
          cmake <FLAGS> ..
          make
          md_ret_require="$md_build/build/gmloader`
          

          I think we do this with the addPort function, which also makes the launch script(s)? So we need another function to check the rom folder for .apk files and run an addPort on any/all that we find?

          You can do the addPort in the configure function. If you don't find an apk, then no port will be added - that's ok since you can't add something that doesn't exist.

          You don't need any moveConfigDirunless the configuration folder exists/will be created by gmloader when running the game. It's usually needed if you want to expose some config file/folder in /opt/retropie/configs, so they're available as file shares for users to inspect/copy/modify files.

          S 1 Reply Last reply Reply Quote 1
          • S
            sleve_mcdichael @mitu
            last edited by

            @mitu said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

            mkdir build && cd build
            [...]
            md_ret_require="$md_build/build/gmloader"
            

            With this, will the retained file save to $md_inst/ or does it keep the path structure $md_inst/build/? Maybe I'll use bin if it keeps the folder structure; I've seen that one used before.

            You don't need any moveConfigDirunless the configuration folder exists/will be created by gmloader when running the game. It's usually needed if you want to expose some config file/folder in /opt/retropie/configs, so they're available as file shares for users to inspect/copy/modify files.

            The configuration folder is created by gmloader and config.ini and save1 files were created there. I do want to expose these in opt/retropie/configs so they're available as file shares for backup/etc.

            You can do the addPort in the configure function. If you don't find an apk, then no port will be added - that's ok since you can't add something that doesn't exist.

            What if the user doesn't have the apk files yet, but we still want to set up the emulators.cfg so they can add their own apks and launch scripts in the future? Or do we assume that if they know how to do that, they can make their own emulators.cfg too, and we only focus on the fully-automated method?

            In that case, I suppose we check for the files and if there are none, we display a message that tells the user to add their file(s) and re-run the installer?

            I think I still need some help with the actual function that adds the ports, too. The one I wrote is more of a workflow outline, but I don't think it's going to work as written. That's because if I just do:

            for apk in /path/*.apk
            

            ...and there are .apk files, it works fine, but if there are none, then it still returns a single entry as /path/*.apk, which then gets passed to:

            addPort "gmloader" "droidports" "*" "/opt/retropie/ports/gmloader/bin/gmloader %ROM%" "/path/*.apk"
            

            ...which I imagine isn't parsed as anything useful with those wildcards in there.

            I could test for files and then just do the "for" if they exist. Would that look something like this?

            function add_files_gmloader() {
                local files=()
                    [[ -f "$romdir/ports/droidports/*.apk" ]] && files+=("$romdir/ports/droidports/*.apk")
                    [[ -f "$romdir/ports/droidports/*.APK" ]] && files+=("$romdir/ports/droidports/*.APK")
            
                if [[ -n "$files" ]]; then
                    for apk in $files; do
                        local apk_filename="${apk##*/}"
                        local apk_basename="${apk_filename%.*}"
                        addPort "$md_id" "droidports" "$apk_basename" "$md_inst/gmloader %ROM%" "$apk"
                        moveConfigDir "$home/.config/$apk_basename" "$md_conf_root/droidports/$apk_basename"
                    done
                else
                    echo "No APK(s) found. Please place your APK file(s) in $romdir/ports/droidports and re-run this installer."
                fi
            }
            
            function configure_gmloader() {
                mkRomDir "ports/droidports"
                add_files_gmloader
            }
            

            Again, something like that, but not quite exactly that. I don't think my [[ ]] test syntax is right. Or something isn't right, because I've run this slightly-modified version on my system, and while the ls shows the APK files do exist at the path, the script is still reporting "No APK(s) found" instead of echoing the addPort commands:

            pi@retropie:~ $ cat temp/foobar/test.sh 
            function add_files_gmloader() {
                local home="/home/pi"
                local romdir="$home/RetroPie/roms"
                local md_conf_root="/opt/retropie/configs/ports"
                local md_id="gmloader"
            
                local files=()
                    [[ -f "$romdir/ports/droidports/*.apk" ]] && files+=("$romdir/ports/droidports/*.apk")
                    [[ -f "$romdir/ports/droidports/*.APK" ]] && files+=("$romdir/ports/droidports/*.APK")
            
                ls "$romdir/ports/droidports"
            
                if [[ -n "$files" ]]; then
                    for apk in $files; do
                        local apk_filename="${apk##*/}"
                        local apk_basename="${apk_filename%.*}"
                        echo addPort "$md_id" "droidports" "$apk_basename" "$md_inst/gmloader %ROM%" "$apk"
                        echo moveConfigDir "$home/.config/$apk_basename" "$md_conf_root/droidports/$apk_basename"
                    done
                else
                    echo "No APK(s) found. Please place your APK file(s) in $romdir/ports/droidports and re-run this installer."
                fi
            }
            
            function configure_gmloader() {
                echo mkRomDir "ports/droidports"
                add_files_gmloader
            }
            
            configure_gmloader
            pi@retropie:~ $ bash temp/foobar/test.sh 
            mkRomDir ports/droidports
            am2r_155.apk  am2r_155_hq.apk  FooBar.APK
            No APK(s) found. Please place your APK file(s) in /home/pi/RetroPie/roms/ports/droidports and re-run this installer.
            pi@retropie:~ $ 
            

            Thoughts?

            mituM 1 Reply Last reply Reply Quote 0
            • mituM
              mitu Global Moderator @sleve_mcdichael
              last edited by

              mkdir build && cd build
              [...]
              md_ret_require="$md_build/build/gmloader"
              

              With this, will the retained file save to $md_inst/ or does it keep the path structure $md_inst/build/? Maybe I'll use bin if it keeps the folder structure; I've seen that one used before.

              The filestructure is not copied, just the file(s), they'll end up in $md_inst (/opt/retropie/ports/gmloader).

              The configuration folder is created by gmloader and config.ini and save1 files were created there. I do want to expose these in opt/retropie/configs so they're available as file shares for backup/etc.

              Ok, but in this case you only need to run it once (in configure) and not for each apk file.

              What if the user doesn't have the apk files yet, but we still want to set up the emulators.cfg so they can add their own apks and launch scripts in the future? Or do we assume that if they know how to do that, they can make their own emulators.cfg too, and we only focus on the fully-automated method?

              I usually don't assume any post-configuration is needed and just copying the games and installing an emulator should be enough so that I can start the games - i.e. no fiddling necessary.

              In that case, I suppose we check for the files and if there are none, we display a message that tells the user to add their file(s) and re-run the installer?

              Yes, you can add a status message after configuration to show what ports have been added (based on the .apk files detected).

              I think I still need some help with the actual function that adds the ports, too. The one I wrote is more of a workflow outline, but I don't think it's going to work as written. That's because if I just do:
              [...]

              Look at how configedit enumerates .cfg files and do something similar:

                 while read config; do
                      config=${config//$path\//}
                      configs+=("$config")
                      options+=("$i" "$config")
                      ((i++))
                  done < <(find "$path" -type f -regex "$include" ! -regex "$exclude" ! -regex ".*/downloaded_images/.*" | sort)
              

              (from here).

              S 1 Reply Last reply Reply Quote 0
              • S
                sleve_mcdichael @mitu
                last edited by

                @mitu said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

                The configuration folder is created by gmloader and config.ini and save1 files were created there. I do want to expose these in opt/retropie/configs so they're available as file shares for backup/etc.

                Ok, but in this case you only need to run it once (in configure) and not for each apk file.

                ...but the config folder is unique to each APK. am2r_155.apk -> ~/.config/am2r_155/; FooBar.APK -> ~/.config/FooBar/, etc. Don't we need to do a moveConfigDir on each of these individually, or am I missing something?

                I usually don't assume any post-configuration is needed and just copying the games and installing an emulator should be enough so that I can start the games - i.e. no fiddling necessary.

                Fair enough. If they really want to fiddle they can do it after installing the first APK automatically, once the emulators.cfg is configured (or they can configure it themselves.)

                Yes, you can add a status message after configuration to show what ports have been added (based on the .apk files detected).

                And of course I'll want to put this in a dialog box with an "Ok" button and not just echoed to the terminal like I have here. But that's a task for later, since I still need to get the function working before I can report on what it did.

                Look at how configedit enumerates .cfg files and do something similar:

                   while read config; do
                        config=${config//$path\//}
                        configs+=("$config")
                        options+=("$i" "$config")
                        ((i++))
                    done < <(find "$path" -type f -regex "$include" ! -regex "$exclude" ! -regex ".*/downloaded_images/.*" | sort)
                

                (from here).

                I'm gonna have to teach myself some more scripting before that makes any sense to me. I had a feeling while read was gonna be the way to go, but I'm less familiar with its usage, and the rest of that section is over my head.

                Something like:

                local files=()
                local file
                
                while read file; do
                    file="/path/*.apk"
                    files+=("$file")
                done
                
                if [[ -n "$files" ]]; then
                    <function to addPort on "$files">
                else
                    <message to add files and re-install>
                fi
                

                ...or am I way off?

                mituM 1 Reply Last reply Reply Quote 0
                • mituM
                  mitu Global Moderator @sleve_mcdichael
                  last edited by

                  The configuration folder is created by gmloader and config.ini and save1 files were created there. I do want to expose these in opt/retropie/configs so they're available as file shares for backup/etc.

                  Ok, but in this case you only need to run it once (in configure) and not for each apk file.

                  ...but the config folder is unique to each APK. am2r_155.apk -> ~/.config/am2r_155/; FooBar.APK -> ~/.config/FooBar/, etc. Don't we need to do a moveConfigDir on each of these individually, or am I missing something?

                  If each game gets its own folder, then yes, it makes sense to symlink each one, though it's not ideal. It would be better if each game would have its own config folder under $HOME/.config/gmloader.

                  And of course I'll want to put this in a dialog box with an "Ok" button and not just echoed to the terminal like I have here. But that's a task for later, since I still need to get the function working before I can report on what it did.

                  You want to avoid dialogs which require user interaction, since the installer can run non-interactively (i.e. on upgrades).

                  [..]
                  I'm gonna have to teach myself some more scripting before that makes any sense to me. I had a feeling while read was gonna be the way to go, but I'm less familiar with its usage, and the rest of that section is over my head.

                  Something like:

                  local files=()
                  local file
                  
                  while read file; do
                      file="/path/*.apk"
                      files+=("$file")
                  done
                  
                  if [[ -n "$files" ]]; then
                      <function to addPort on "$files">
                  else
                      <message to add files and re-install>
                  fi
                  

                  No, -n is used for single value vars, not for arrays.
                  Use the while, the whole 'magic' is in the command that lists the values which is run after done:

                  while read file; do
                  # do something with the file
                  done < < (# command to list the files you want to loop over)
                  
                  S 1 Reply Last reply Reply Quote 0
                  • S
                    sleve_mcdichael @mitu
                    last edited by sleve_mcdichael

                    @mitu said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

                    It would be better if each game would have its own config folder under $HOME/.config/gmloader.

                    I agree but I didn't write the software. Is this something that we can config?

                    You want to avoid dialogs which require user interaction, since the installer can run non-interactively (i.e. on upgrades).

                    Okay. What, do we write it to a log, then? Would I just use echo then, like I've done above, or what?

                    I was thinking, like, the user installs the module, then it doesn't find any APKs (because they haven't put any there yet, because for example the rom folder hasn't been created yet because they haven't installed it ever before). It needs to tell the user to add the APKs and re-run the installer. It needs to tell them this in a place that they will see it, and it needs to stay there long enough for them to see it.

                    Are there any other ports that function similar that I can check out to base this on?

                    Edit: I guess it's not much different than the shareware games you can provide full versions for. You either install it once or create the folder manually; then you add your game files, then you install it again to import the game files. I guess that's just how it is. So the note in the rp_module_helpto put your APKs in the rom folder is enough, or...? It's okay that after the initial installation, we leave it in a state where the emulators.cfg isn't configured yet?

                    No, -n is used for single value vars, not for arrays.
                    Use the while, the whole 'magic' is in the command that lists the values which is run after done:

                    while read file; do
                    # do something with the file
                    done < < (# command to list the files you want to loop over)
                    

                    Am I getting warmer?

                    function configure_gmloader() {
                        mkRomDir "ports/droidports"
                    
                        while read apk; do
                            local apk_filename="${apk##*/}"
                            local apk_basename="${apk_filename%.*}"
                            addPort "$md_id" "droidports" "$apk_basename" "$md_inst/gmloader %ROM%" "$apk"
                            moveConfigDir "$home/.config/$apk_basename" "$md_conf_root/droidports/$apk_basename"
                        done < < ls "$romdir/ports/droidports/*.apk" "$romdir/ports/droidports/*.APK"
                    }
                    

                    Edit:

                    done < < (find "$romdir/ports/droidports" \( -name "*.apk" -o -name "*.APK" \))
                    

                    ??

                    Edit edit: not there yet. The find command works on its own but not in this test script?

                    pi@retropie:~/temp/foobar $ find "/home/pi/RetroPie/roms/ports/droidports" \( -name "*.apk" -o -name "*.APK" \)
                    /home/pi/RetroPie/roms/ports/droidports/am2r_155_hq.apk
                    /home/pi/RetroPie/roms/ports/droidports/am2r_155.apk
                    /home/pi/RetroPie/roms/ports/droidports/FOOBAR.APK
                    pi@retropie:~/temp/foobar $ cat test.sh 
                    function configure_gmloader() {
                        echo mkRomDir "ports/droidports"
                    
                        local home="/home/pi"
                        local romdir="$home/RetroPie/roms"
                        local md_conf_root="/opt/retropie/configs/ports"
                        local md_id="gmloader"
                    
                        while read apk; do
                            local apk_filename="${apk##*/}"
                            local apk_basename="${apk_filename%.*}"
                                echo addPort "$md_id" "droidports" "$apk_basename" "$md_inst/gmloader %ROM%" "$apk"
                                echo moveConfigDir "$home/.config/$apk_basename" "$md_conf_root/droidports/$apk_basename"
                        done < < (find "$romdir/ports/droidports" \( -name "*.apk" -o -name "*.APK" \))
                    }
                    
                    configure_gmloader
                    pi@retropie:~/temp/foobar $ bash test.sh
                    test.sh: line 14: syntax error near unexpected token `<'
                    test.sh: line 14: `    done < < (find "$romdir/ports/droidports" \( -name "*.apk" -o -name "*.APK" \))'
                    pi@retropie:~/temp/foobar $
                    
                    mituM S 2 Replies Last reply Reply Quote 0
                    • S
                      sleve_mcdichael
                      last edited by sleve_mcdichael

                      So I got my test function working, after I found the problem (I had an extra space that wasn't supposed to be there, after the second <.)

                      Is this ready for prime time? Or at least, do you see anything broken, before I give it a test-drive?

                      #!/usr/bin/env bash
                      
                      # This file is part of The RetroPie Project
                      # 
                      # The RetroPie Project is the legal property of its developers, whose names are
                      # too numerous to list here. Please refer to the COPYRIGHT.md file distributed with this source.
                      # 
                      # See the LICENSE.md file at the top-level directory of this distribution and 
                      # at https://raw.githubusercontent.com/RetroPie/RetroPie-Setup/master/LICENSE.md
                      #
                      
                      rp_module_id="gmloader"
                      rp_module_desc="GMLoader - play GameMaker Studio games for Android on non-Android operating systems"
                      rp_module_help="ROM Extensions: .apk .APK\n\nCopy your APK files to $romdir/ports/droidports and then re-run this installer."
                      rp_module_repo="git https://github.com/JohnnyonFlame/droidports.git master faf3970"
                      rp_module_licence="GPL3 https://github.com/JohnnyonFlame/droidports/blob/master/LICENSE.md"
                      rp_module_section="exp"
                      rp_module_flags="!all rpi4"
                      
                      function depends_gmloader() {
                          getDepends libopenal-dev libfreetype6-dev zlib1g-dev libbz2-dev libpng-dev libzip-dev libsdl2-image-dev cmake
                      }
                      
                      function sources_gmloader() {
                          gitPullOrClone
                      }
                      
                      function build_gmloader() {
                          mkdir build && cd build
                          cmake CMakeLists.txt -DCMAKE_BUILD_TYPE=Release -DPLATFORM=linux -DPORT=gmloader ..
                          make
                          md_ret_require="$md_build/build/gmloader"
                      }
                      
                      function install_gmloader() {
                          md_ret_files="$md_build/build/gmloader"
                      }
                      
                      function configure_gmloader() {
                          mkRomDir "ports/droidports"
                          while read apk; do
                              local apk_filename="${apk##*/}"
                              local apk_basename="${apk_filename%.*}"
                              addPort "$md_id" "droidports" "$apk_basename" "$md_inst/gmloader %ROM%" "$apk"
                              moveConfigDir "$home/.config/$apk_basename" "$md_conf_root/droidports/$apk_basename"
                          done < <(find "$romdir/ports/droidports" \( -name "$*.apk" -o -name "*.APK" \))
                      }
                      

                      EDIT: something still didn't work:

                      pi@retropie:~/RetroPie-Setup/logs $ tail rps_2021-11-29_201831.log 
                      [ 96%] Building C object CMakeFiles/gmloader.dir/platform/linux/so_util_linux.c.o
                      [100%] Linking C executable gmloader
                      [100%] Built target gmloader
                      /home/pi
                      /home/pi/RetroPie-Setup/tmp/build/gmloader /home/pi
                      Could not successfully install GMLoader - play GameMaker Studio games for Android on non-Android operating systems (/home/pi/RetroPie-Setup/tmp/build/gmloader//home/pi/RetroPie-Setup/tmp/build/gmloader/build/gmloader not found).
                      /home/pi
                      
                      Log ended at: Mon 29 Nov 2021 08:19:28 PM PST
                      Total running time: 0 hours, 0 mins, 57 secs
                      pi@retropie:~/RetroPie-Setup/logs $
                      

                      Looking through the other modules, it seems no one is using md_ret_files like I am. I changed it to just md_ret_files="build/gmloader" (no $md_build/ path), and it did complete.

                      Now, two issues:

                      The executable from the installation differs from the one I built manually. I can't test if it works or not until tomorrow, probably. But why aren't they identical?

                      Only one of my APK files was configured with a ~/.config folder and launch script. The droidports folder has am2r_155.apk am2r_155_hq.apk FOOBAR.APK; only the dummy apk FOOBAR was configured when I ran the install. When I bash my test function, it returns all three:

                      pi@retropie:~ $ bash temp/foobar/test.sh 
                      mkRomDir ports/droidports
                      addPort gmloader droidports FOOBAR /opt/retropie/ports/gmloader/gmloader %ROM% /home/pi/RetroPie/roms/ports/droidports/FOOBAR.APK
                      moveConfigDir /home/pi/.config/FOOBAR /opt/retropie/configs/ports/droidports/FOOBAR
                      addPort gmloader droidports am2r_155_hq /opt/retropie/ports/gmloader/gmloader %ROM% /home/pi/RetroPie/roms/ports/droidports/am2r_155_hq.apk
                      moveConfigDir /home/pi/.config/am2r_155_hq /opt/retropie/configs/ports/droidports/am2r_155_hq
                      addPort gmloader droidports am2r_155 /opt/retropie/ports/gmloader/gmloader %ROM% /home/pi/RetroPie/roms/ports/droidports/am2r_155.apk
                      moveConfigDir /home/pi/.config/am2r_155 /opt/retropie/configs/ports/droidports/am2r_155
                      pi@retropie:~ $
                      
                      1 Reply Last reply Reply Quote 0
                      • mituM
                        mitu Global Moderator @sleve_mcdichael
                        last edited by

                        @sleve_mcdichael said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

                        Are there any other ports that function similar that I can check out to base this on?

                        Yes, Quake2 or Wolfenstein work similarly - if the games are detected during install, then the corresponding port entries are added. For printing messages, I think there's a printMsgs helper function you can use.

                        The executable from the installation differs from the one I built manually. I can't test if it works or not until tomorrow, probably. But why aren't they identical?

                        Compilation flags may be different, the setup script tries to optimize the build by adding platform specific tweaks.

                        S 1 Reply Last reply Reply Quote 0
                        • S
                          sleve_mcdichael
                          last edited by

                          Only one of my APK files was configured with a ~/.config folder and launch script.

                          Found the typo!

                          ExarKunIvE 1 Reply Last reply Reply Quote 0
                          • ExarKunIvE
                            ExarKunIv @sleve_mcdichael
                            last edited by

                            @sleve_mcdichael i would like to include your script in my Port list I have going here once its all done of course

                            and have it posted on my Github for easy download and install.
                            Of course you get full credit

                            cant wait to give it a try

                            RPi3B+ / 200GB/ RetroPie v4.5.14, RPi4 Model B 4gb / 256gb / RetroPie 4.8.2
                            RPi5 4gb / 512gb / RetroPie 4.8.9 -Basic
                            Maintainer of RetroPie-Extra .

                            1 Reply Last reply Reply Quote 1
                            • S
                              sleve_mcdichael @mitu
                              last edited by sleve_mcdichael

                              @mitu said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

                              Compilation flags may be different, the setup script tries to optimize the build by adding platform specific tweaks.

                              The installed version still runs the game and loads my save.

                              Why does it say "update is available", immediately after installation?

                              I found the typo that broke the configure function.

                              I think this is almost ready.

                              It doesn't log very much. There's a "-debug" version we can build that is more verbose. Should we build & install them both at the same time so the -debug version is available from the start, or split it up into two separate modules so the initial installation is more streamlined, but users can still install the debug version only if they need it?

                              Pro-combined:
                              Only clone into the repo once
                              Both executables in the same /opt/retropie/ports/gmloader directory
                              Cons:
                              Takes longer since it has to build both (but, it's only like a minute for each one.)
                              Extra file (but only 1.5MB) that they may not even need.

                              Pro-split:
                              Faster installation (each) since it only builds the one you need.
                              Cons:
                              Have to clone into the repo two times if you want to install both versions.
                              Executables in separate gmloader and gmloader-debug dirs.

                              mituM 1 Reply Last reply Reply Quote 0
                              • mituM
                                mitu Global Moderator @sleve_mcdichael
                                last edited by

                                @sleve_mcdichael said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

                                Why does it say "update is available", immediately after installation?

                                Probably because your script is not commited to the git repo and the setup script doesn't know the date of its last modification.

                                Should we build & install them both at the same time so the -debug version is available from the start, or split it up into two separate modules so the initial installation is more streamlined, but users can still install the debug version only if they need it?

                                I don't think it's needed.

                                S 1 Reply Last reply Reply Quote 0
                                • S
                                  sleve_mcdichael @mitu
                                  last edited by sleve_mcdichael

                                  @mitu said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

                                  @sleve_mcdichael said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:
                                  I don't think it's needed.

                                  Sure, less is more, right? I think it's ready to go live, then. Please test:

                                  GMLoader-RPi

                                  wget https://raw.githubusercontent.com/s1eve-mcdichae1/GMLoader-RPi/main/gmloader.sh -P $HOME/RetroPie-Setup/scriptmodules/ports/
                                  

                                  If for some reason the debug module is desired, then just edit the file, find the "build" function and change -DCMAKE_BUILD_TYPE=Release to -DCMAKE_BUILD_TYPE=Debug, then re-install. This will log verbose output to runcommand.log.

                                  ExarKunIvE 1 Reply Last reply Reply Quote 0
                                  • ExarKunIvE
                                    ExarKunIv @sleve_mcdichael
                                    last edited by

                                    @sleve_mcdichael works great.
                                    I will be linking your script on my post. if you dont mind.

                                    Now we need a list of the games that will work. lol

                                    RPi3B+ / 200GB/ RetroPie v4.5.14, RPi4 Model B 4gb / 256gb / RetroPie 4.8.2
                                    RPi5 4gb / 512gb / RetroPie 4.8.9 -Basic
                                    Maintainer of RetroPie-Extra .

                                    S 1 Reply Last reply Reply Quote 0
                                    • S
                                      sleve_mcdichael @ExarKunIv
                                      last edited by sleve_mcdichael

                                      @exarkuniv said in Guide: AM2R (Another Metroid 2 Remake) on Pi 4:

                                      Now we need a list of the games that will work. lol

                                      I don't know how to get any of the rest of these or how to get them in APK format, but there's a partial list here:

                                      www.reddit.com/r/AM2R/comments/pgp2x7/am2r_raspberry_pi_take_4/hbh8vgr

                                      • Minit (Android, linux w/ wrapper)
                                      • Downwell (linux w/ wrapper, game crashes on death, still haven't investigated why)
                                      • Maldita Castilla (ouya)
                                      • Retro Highway (Android)
                                      • Underswap Demo (Android)
                                      • Nuclear Throne (Linux build converted to gms1.4.1804 + wrapper)
                                      • AM2R 1.5.2 and 1.5.5 (Android)
                                      • Psycron Demo (Windows w/ Wrapper)
                                      • Unworthy (Windows w/ Wrapper, runs too slow to be usable even on pi4)

                                      Someone also mentioned Gato Roboto, which looks cool as heck.

                                      ExarKunIvE 1 Reply Last reply Reply Quote 0
                                      • ExarKunIvE
                                        ExarKunIv @sleve_mcdichael
                                        last edited by

                                        @sleve_mcdichael its better then nothing.

                                        still very cool

                                        RPi3B+ / 200GB/ RetroPie v4.5.14, RPi4 Model B 4gb / 256gb / RetroPie 4.8.2
                                        RPi5 4gb / 512gb / RetroPie 4.8.9 -Basic
                                        Maintainer of RetroPie-Extra .

                                        1 Reply Last reply Reply Quote 0
                                        • S
                                          sleve_mcdichael
                                          last edited by sleve_mcdichael

                                          Update: refined the "find" command that configured the games. Now uses:

                                          done < <(find "$romdir/ports/droidports" -maxdepth 1 -type f \( -name "*.apk" -o -name "*.APK" \))
                                          

                                          1: -type f - we don't want to return directories even if they're called *.apk. This forces it to only return files.

                                          2: -maxdepth 1 - nothing inherently wrong with using subdirs and normally it would work just fine, but if a user has two files with the same name in different dirs (for example, both FooBar.apk and subdir/FooBar.apk) then their launch scripts and config dirs will conflict. Setting -maxdepth 1 forces it to only return files in the main droidports directory so there can be no filename conflicts. (Edit: FooBar.apk and FooBar.APK would still conflict. Don't do that, I guess. Anyone know a way to safeguard against this that's simple and easy enough for a noob like me to understand?)

                                          mituM 1 Reply Last reply Reply Quote 0
                                          • mituM
                                            mitu Global Moderator @sleve_mcdichael
                                            last edited by

                                            @sleve_mcdichael find knows about -iname, the command can be shortened to

                                            find "$romdir/ports/droidports" -maxdepth 1 -type f -iname \*.apk
                                            
                                            S 1 Reply Last reply Reply Quote 1
                                            • First post
                                              Last post

                                            Contributions to the project are always appreciated, so if you would like to support us with a donation you can do so here.

                                            Hosting provided by Mythic-Beasts. See the Hosting Information page for more information.