RPG Maker MV Repackaged Games

4.00 star(s) 1 Vote

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
So I was asked to put together a list of games that I've worked on and repackaged for Linux/JoiPlay.
You don't have permission to view the spoiler content. Log in or register now.

You don't have permission to view the spoiler content. Log in or register now.
 
Last edited:

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
So a quick update, I've been able to find and fix some egregious issues in Sword Maiden of the Azure Dragon including the bad spacing every time there's an apostrophe.

I've also been able to extract all the images from their "Encryption" scheme.

There's this nice little comment at the start:
JavaScript:
//Hello, cracker. Welcome to the maze I designed.
//
//If you open the source just because of hobbies, please leave immediately, this is not where you should stay.
//It's not easy to make games, I don't allow you to trample on the achievements of the game designers.
//The key has been disassembled and distributed in a random maze by me. If you think that you can find the key with a simple alert, let's go and see.
Followed by lines and lines of this nonsense:
JavaScript:
Decrypter.code_map_drillup = ['62','06','08','a7','73','ac','13','44','43','2c','64','7e','6c','d8','12','15','4f','0d','da','20','b4','71','35','53','10','12','af','eb','03','96','eb','4f','c5','d7','a9','c9','8b','e6','e0','ec','04','6d','af','22','bc','39','48','17','33','57','8b','53','79','1a','39','ca','d9','de','99','91','af','eb','64','50','8d','a2','22','47','8a','bc','26','22','eb','01','40','d9','d8','13','39','61','7e','40','bc','d9','93','76','b6','60','55','25','1c','c6','f2','12','eb','71','da','d0','c5','d2'];
Decrypter.map_code_dRilLuP = [29,97,10,28,86,24,95,46,2,4,12,89,15,68,71,67,82,57,49,81,70,92,75,37,93,35,52,26,90,9,21,85];
Decrypter.map_code_dRiLlUp = [22,98,0,66,94,50,99,57,18,96,79,97,76,15,32,55,20,95,41,34,35,8,30,62,84,80,58,12,65,7,31,2];
Decrypter.map_code_drilLUp = [58,87,81,54,40,77,89,19,4,97,96,12,78,64,18,83,55,9,45,85,42,82,27,37,44,41,7,2,15,57,65,93];
Well someone thinks he's a clever little monkey doesn't he.

Notice the different cases to make you want to refactor each to find the key. And adding the comment to taunt people.

Well here's the thing, you don't need the key.

Warning the following is a very technical discussion of RPG Maker MV's "encryption" and why it is trivial to break.
You don't have permission to view the spoiler content. Log in or register now.
 

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
Naked story has been released. (It was easy to test, so I felt it was ready.)
 

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
Found a video decoding/encoding issue with Furry Eared Girls Never Betray, I'm working on a fix.
 

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
Just put up Apostle with a new cached file list setup, let me know if it causes troubles.
 
  • Like
Reactions: YadenYu

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
So Furry Eared Girls Never Betray was updated so that video transparency is preserved.
 

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
Minor update to Furry Eared Girls Never Betray (fixes for JoiPlay, Linux pre-computed paths)
 

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
So I'm building the release of Island SAGA right now. That said I wanted to talk about how I was handling paths on Linux to run natively, how I'm doing it now and why.

As I point out in the nerd notes of my changelog, Linux is sensitive to file name case. While there's some tricks you can play with ext4 to make the filesystem sort of case insensitive, based on my limited research the requires an option when creating the filesystem. An option I neglected to add when building my raid array. Given that I really don't want to lose a lot of data (again) that is simply not an option.

Note: There is logic that limits this behavior to Linux only so Windows users won't see this behavior at all.
What I was doing was this:

On game startup, scan the entire game directory. Create a map between the lowercase filename and the case sensitive file name. When a request for a file comes in, check to see if it exists. If it does, great use it. If the file couldn't be found convert the name to lower case and ask the map what the real name should be. If the map didn't know, just pass along the request as it was, (and typically let the game crash.)​
Of course due to how RPG Maker MV encoding works, it couldn't be that simple. I had to look at file extensions and if it was one of the encoded types, switch that to the decoded extension in the map and result. I even made this work such that when not encoded, and the file on disk was a .webp, I would map the .png extension to it so play testing would just work.​

While not super efficient, with SSDs and how Linux file systems work this is pretty reasonable. That was until I started working on Island SAGA.

Island SAGA is a beast of a RPG Maker MV game. Unlike a game like Summer Memories which is pretty small and contains less than 7,000 files, Island SAGA hits you with over 14,000 files and they are not small. In my development environment this balloons to 36,000+ files due to source code control and other things I need. This means the files can be spread out on disk a lot, enough to negate the benefits of a SSD/RAID setup. Initially I didn't see these problems because filesystem caching would resolve thing quickly. But if I worked on other stuff for a while and came back, the first startup would take 2-3 minutes (before the loading screen showed up.)

After thinking about the causes for a while I came to the conclusion that my inefficient scan at startup was the cause. I went back to the drawing board.

Scanning the disk every time had to go, so I needed to have the map already built on startup. Well I could scan the filesystem and build up the map on first startup, but that's not exactly a great user experience. Besides I would have to be careful if I used full paths to look and rebuild the map if the files on disk changed or the user moved where the game was. What if I just built the map to begin with, and kept the paths relative to the game root? It wouldn't handle new files very well, so mods on top of my stuff would probably have trouble but I'm already making a set of breaking changes so unless someone took my stuff and modded that, they would break anyways.

So I took the map as it existed in my development environment and wrote it to disk. Yes it wouldn't work for encoded files, but I figured I'd take it one step at a time.

This first attempt wasn't encouraging. The resulting JSON file was 14 megabytes. That's not awesome. I suppose it is all text and I could use compression. But looking at drops off at about 750,000 bytes. Having a file of 14,000,000+ bytes means the lz-string might actually take longer to load than looking at the filesystem. Well, the author did say for larger items you should use LZMA, so I pulled in the . And using LZMA shrunk that file from 14,299,926 bytes to 908,193 bytes which is about 6% of the original size. Experiments showed I could load this in around 800 milliseconds, (0.8 seconds) but then the result still needed to be parsed.

Looking at my file map I saw that my .git directory was being included, as well as a bunch of stuff for my builds. So I targeted the www directory exclusively. (Yes, this has a problem with the scenario folder in Dieselmine games, but that's something I could fix later.) I also started to use compact output for the JSON. Finally, I limited the map to files that have an uppercase letter in them. Coupled with lzma, this brought down the JSON archive size to 58,126 bytes for development, 23,834 bytes for production use. (The development version still has to map .webp to .png files.)

I finally had my solution. Wrap it up in a python script and you get:
Python:
#!/usr/bin/env python3
import json
import lzma
import os
from pathlib import PurePosixPath

real_path = []
# Set the directory you want to start from
rootDir = 'www'
base = PurePosixPath("/")
for dir_name, _, fileList in os.walk(rootDir):
    for file_name in fileList:
        real_path.append(base.joinpath(dir_name, file_name))

file_map={}
enc_file_map={}
for path in real_path:
    p = PurePosixPath(path)
    inputSuffix = p.suffix
    if(inputSuffix == ".webp"):
        inputSuffix = ".png"
    p_str = str(p.parent.joinpath(str(p.stem)+inputSuffix))
    p_str_lc = p_str.lower()
    if p_str_lc in file_map:
        print("Upper case/lower case collision with %s" % p_str)
        exit(1)
    else:
        if(p_str_lc != p_str):
            enc_file_map[p_str_lc]=p_str
            file_map[p_str_lc] = str(p)
        elif(p.suffix == ".webp"):
            file_map[p_str_lc] = str(p)
my_filters = [
    {"id": lzma.FILTER_LZMA1, "preset": 2}
]

with lzma.open("pathdata.xz", "w",format=lzma.FORMAT_ALONE, filters=my_filters) as f:
    f.write(bytes(json.dumps(file_map, separators=(',', ':')), "utf-8"))

with lzma.open("pathdata.enc.xz", "w",format=lzma.FORMAT_ALONE, filters=my_filters) as f:
    f.write(bytes(json.dumps(enc_file_map, separators=(',', ':')), "utf-8"))
The only issues are:
  1. If someone is using the Turkish language set (or other language that does this) the javascript toLower() function may result in a filename that doesn't match
    • Turns out the letter 'I' doesn't become 'i' in Turkish, instead it becomes ı
  2. Windows won't handle the webp mapping for a playtest
    • The core needs to change to fix this, so it isn't any different than before
There are more changes I want to make to Island SAGA, but I want to make sure that the existing changes are working properly first
 

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
Quick update on Island SAGA, I found a couple of show stopping defects so I'll need to get those fixed.

One is that the menu doesn't scroll on JoiPlay. The other and more severe problem is there are missing images from the base game. I'll need to see how I can get those item fixed.

Edit:
And apparently I was using the v4 patch. They released a v5 patch in September so I'm going to bring that in as well.
 
Last edited:

Bloemkool

Well-Known Member
Aug 13, 2017
1,140
984
Quick update on Island SAGA, I found a couple of show stopping defects so I'll need to get those fixed.

One is that the menu doesn't scroll on JoiPlay. The other and more severe problem is there are missing images from the base game. I'll need to see how I can get those item fixed.

Edit:
And apparently I was using the v4 patch. They released a v5 patch in September so I'm going to bring that in as well.
Man, you working hard on all this huh; good hustle.
 
  • Like
Reactions: Didikchool

wboiko

Newbie
Jul 29, 2017
25
121
I'm not really sure if you'd consider this in-scope for your projects, but I encountered 2 issues with your repack of Meltys Quest of which at least the first is probably applicable to all MV games (unless they fix it themselves, which e.g. Karryn's Prison does).

1. The screen freezes at random times but the game continues running in the background
The cause is probably best described here , but I'm not sure how Linux/Android handles this so may only happen on Windows machines.

You could probably switch to that version of the core script, but I found it easiest to just add this plugin to the game:

2. Game pauses for a long time on the Victory screen before continuing
This only happens on games using Yanfly's YEP_VictoryAftermath plugin. It is also highly dependent on the framerate the game is run at.

There is basically a very long pause before the game displays the EXP gauge so you just sit there waiting.

This is the function responsible for updating the gauge:
JavaScript:
Window_VictoryExp.prototype.updateTicks = function() {
    if (this._tick >= Yanfly.Param.VAGaugeTicks) return;
    if (Graphics.frameCount % 4 !== 0) return;
    if (Input.isPressed('ok') || TouchInput.isPressed()) {
      this._tick = Yanfly.Param.VAGaugeTicks;
    } else {
      this._tick += 1;
    }
    this.drawAllGauges();
};
The problem here lies with the second condition, only continuing when the current framecount is not cleanly divisible by 4. From my testing this can take a very long time when running the game at 120FPS (my refresh rate), which requires me to either wait or try to artificially introduce lag by quickly toggling the window-size via F4.

As far as I can tell the only reason for this line is to introduce some small delay between the screen showing up and the EXP gauge being drawn, so for myself I simply removed that line without any ill effects.


Neither of those issues seems to be affecting too many people, since it's quite hard to find anyone complaining about them (or anyone at all in case of the second issue), but it may be nice to include them just in case someone may be affected who doesn't have the drive to figure this out on their own.
 

kin-kun

Active Member
Modder
Jul 10, 2020
963
2,281
I'm not really sure if you'd consider this in-scope for your projects, but I encountered 2 issues with your repack of Meltys Quest of which at least the first is probably applicable to all MV games (unless they fix it themselves, which e.g. Karryn's Prison does).

1. The screen freezes at random times but the game continues running in the background
The cause is probably best described here , but I'm not sure how Linux/Android handles this so may only happen on Windows machines.

You could probably switch to that version of the core script, but I found it easiest to just add this plugin to the game:

2. Game pauses for a long time on the Victory screen before continuing
This only happens on games using Yanfly's YEP_VictoryAftermath plugin. It is also highly dependent on the framerate the game is run at.

There is basically a very long pause before the game displays the EXP gauge so you just sit there waiting.

This is the function responsible for updating the gauge:
JavaScript:
Window_VictoryExp.prototype.updateTicks = function() {
    if (this._tick >= Yanfly.Param.VAGaugeTicks) return;
    if (Graphics.frameCount % 4 !== 0) return;
    if (Input.isPressed('ok') || TouchInput.isPressed()) {
      this._tick = Yanfly.Param.VAGaugeTicks;
    } else {
      this._tick += 1;
    }
    this.drawAllGauges();
};
The problem here lies with the second condition, only continuing when the current framecount is not cleanly divisible by 4. From my testing this can take a very long time when running the game at 120FPS (my refresh rate), which requires me to either wait or try to artificially introduce lag by quickly toggling the window-size via F4.

As far as I can tell the only reason for this line is to introduce some small delay between the screen showing up and the EXP gauge being drawn, so for myself I simply removed that line without any ill effects.


Neither of those issues seems to be affecting too many people, since it's quite hard to find anyone complaining about them (or anyone at all in case of the second issue), but it may be nice to include them just in case someone may be affected who doesn't have the drive to figure this out on their own.
So thank you. I have spent days tracking down that random jitter step. I will be applying a fix to my core script that I use.

As for Yanfly, you're right, that code is completely brain dead. It is not the worst I've seen from his commercial plugins (he actually sells this garbage code to lots of people) but it is something I'm happy to fix. I will work on that soon, I hope to have another release of Melty's quest for you by the end of this week.
 
  • Like
Reactions: Pelbobo and wboiko
4.00 star(s) 1 Vote