Skip to main content

Wii Homebrew Browser revival

hbb source code

introduction

Back during the big days of Wii Homebrew a user named teknecal decided to take it upon himself and create the Wii Homebrew Browser (HBB from now on)

for the time it was a fantastic piece of software beloved by many, including me

Then it 2012 it received its last update followed by its eventual death.

Fast forward to 2020 Modern Vintage Game released his Homebrew Wars video about the Xbox and Wii and teknecal finally decides to release the source code of the HBB.

The OpenShopChannel team has since created a backup of the source code in a github repository as well as a fork to keep it up to date with bug fixes and links to their own servers.

spring cleaning

February 2021 I finally dusted off my Wii and set it back up again.

After a bit of cleanup as well as the creation of a new nand backup (you never know) I decided to look at what cool programs there still are and to my surprise there is still some development being done for the Wii.

After looking through some classics like OpenTTD I noticed the text saying "Downloadable via the Homebrew Browser" and installed it having had such a great memory using it, but sadly its time had come

the servers were down (or very disfunctional) and I couldn't even start the program :(

Determined to put the project into a state where it can compile and actually run using the modern devkitPPC toolchain I went looking for the source code and noticed CompuCat, a member of the ForTheUsers group, asking for permission to use the code and create HBB successor, sadly it fell on deaf ears.

Not being one to give up I joined the ForTheUsers Discord and instantly talked to people in the development chat asking if there are any existing efforts to make a new HBB or at least revive it.

Promptly I was informed about the OpenShopChannel (OSC from now on), a project formerly intended to hack the Wii Shop channel and keep it updated but downscaled to keeping HBB running.

The OSC had released a modified version of the original HBB dol file with simple edit to point to their servers something that wasn't enough for me and being told to simply use OSC instead and talk to the team since they apparently got it to compile in their private repository (later I had been told it was made private by accident) I went to make my own out of spite.

I make a lot of things out of spite simply because I am not happy with the state of how things are, so one night I sat down, set up devkitPPC and began working

reviving a dead codebase

the beginning was a nightmare

the source code wasn't even remotely in a condition to compile it

assets were lying around both in source code form as well as converted C code (and some were missing and had to be recreated from the C code)

various source code of dependencies were stored in-tree as well as a static archive of libpng

binaries across the root of the project folder

a mess in every sense

but I continued and started with some simpler things: I readded -fcommon (since the defaule behavior changed with GCC 10), fixed the Makefile and removed loads of inline declarations.

Since connecting to a dead server isn't going to show me if I am actually making progress and I didn't want to set one up myself, I grepped the OSC binary to see where their server is: hbb1.oscwii.org

a quick replacing and everything worked but was far from where I wanted to go

next I replaced in the in-tree version of libpngu with the upstream variant in the GRRLIB repo and made sure I find functions that matched the behavior of the old ones

at this point I grew annoyed at all the object files sitting around and finally added the conversion from binary file to object file so I don't have 2 copies of the same file sitting around

not wanting to rework the code responsible for it yet I simple added a make target to translate all png files to C code

%.c : %.png
    @echo $(notdir $<) 
    @raw2c $<

following that I finally went and started replaced the behemoth that was GRRLIB

HBB used an outdated version with a different API as well as extensions copied from the GRRLIB forum like FreeType support.

two days later I was finally done and everything was working as intended and overall more than 1000 lines had to be changed to ensure everything worked as it used to

along the way some interesting results came up

Afterwards everything was well... except

Something was obviously wrong somewhere

dhtdht, OSC lead, simply truncated the descriptions to 334 characters and it worked again but that isn't a solution I am happy with, the issue must occur somewhere else

The first cause I found was this

char text_description[500];

strcpy(text_description, homebrew_list[current_app].app_description);

for(s = strlen(text_description); s < 400; s++) {
    text_description[s] = text_white[0];
    l = s;
}

looking at where the description comes from it was obvious we had a stack overflow which had caused the actual texture with the text to have some bad data that manifested itself as corruption like visuals.

But that didn't solve all of it

during the launch of the application for some reason applications caused invalid memory reads for reasons not sure

After some digging I found that in total HBB only had a buffer of 2000 bytes for everything it was send

char cmd_line [2000];

the app in the image has a description longer than 2000 characters but that shouldn't be a big deal right? its only a buffer that we copy somewhere else later

but the copying code calculated using the buffer contents, not the max size of the place we will store it in

strncpy(homebrew_list[array_count].app_name, cmd_line, strlen(cmd_line) - hbb_string_len);

we had caused an overflow

a variable was added to check what the max amount of bytes is we can copy over

hbb_null_len = (strlen(cmd_line) - hbb_string_len + 1) > sizeof(homebrew_list[array_count].app_author) ? sizeof(homebrew_list[array_count].app_author) : strlen(cmd_line) - hbb_string_len + 1;  

Some other part of the code had problems if I set an incorrect size to copy over so this had to do

some more cleaning of the code had been done including the replacement of 6 different images showing the ratings 0 to 5 being replaced with code and the gray star being replaced with the image being grayscaled which changed the looks a bit but works way better

Being near the end I finally moved from raw2c to bin2o and made all PNGs into objects and had to replace 500 different references to the previous files with the new ones.

Finally done with my changes I made a PR to OSC and left them to their devices

GameBoy Thumbnails on Linux

Where I started

My introduction to SameBoy came from stacksmashing's "How to reverse engineer & patch a Game Boy ROM" video.

I'm not big on reverse engineering but I do enjoy a good GameBoy game when I see one.

and there it was

this is the type of integration I like to see from projects

but these kinds of features are almost never present on Linux be it because no one bothers or because each major DE supports a different method.

Despite that I was interested in it and started looking through the code

pretty images for pretty games

the code was simple it stored the framebuffer output in a bitmap image and composed that under the image for the cartridge case.

Seems simple

(source code)

            bitmap* pbitmap  = malloc(sizeof(bitmap));
            pbitmap->fileheader.signature[0] = 0x42;
            pbitmap->fileheader.signature[1] = 0x4D;

            pbitmap->fileheader.filesize = sizeof(pixels) + sizeof(bitmap);
            pbitmap->fileheader.fileoffset_to_pixelarray = sizeof(bitmap);
            pbitmap->bitmapinfoheader.dibheadersize = sizeof(bitmapinfoheader);
            pbitmap->bitmapinfoheader.width = 160;
            pbitmap->bitmapinfoheader.height = -144;
            pbitmap->bitmapinfoheader.planes = 1;
            pbitmap->bitmapinfoheader.bitsperpixel = 32;
            pbitmap->bitmapinfoheader.compression = 0;
            pbitmap->bitmapinfoheader.imagesize = sizeof(pixels);
            pbitmap->bitmapinfoheader.ypixelpermeter = 0;
            pbitmap->bitmapinfoheader.xpixelpermeter = 0;
            pbitmap->bitmapinfoheader.numcolorspallette = 0;
            fwrite(pbitmap, 1, sizeof(bitmap),fp);
            fwrite(pixels, 1, sizeof(pixels),fp);
            fclose(fp);
            free(pbitmap);

I actually wanted to see the images in my filemanager though so I went to see how that is done and quickly changed my mind.

The way you creat ThumbCreator plugins for KDE was way too complicated to propose to the repository so I went Freedesktop Thumbnailer standard instead

the biggest requirement was that the output format was a PNG so I started from scratch

writing my own png lib was too big of an undertaking so I simply chose to use lodepng, a free png library under zlib so it was fair to use

a simple conversion to PNG was completed and the resulting binary outputted pngs for any files you wanted

I was happy with this but it was a bit bare and having to specify the bootrom path wasn't very user friendly so I took suggestions from max-m and embedded everything needed in the binary itself

but the image does need to be resized if a differnt resolution was desired

so I implemented a basic scaling function with things like passable sample size

(source code)

static void scale_image(const uint32_t* input, const signed input_width, const signed input_height,
                        uint32_t* output, const double multiplier, const signed samples)
{
    signed output_width = input_width * multiplier;
    uint32_t pixel;

    for (signed h = 0; h < input_height * multiplier; ++h) {
        for (signed w = 0; w < input_width * multiplier; ++w) {
            pixel = 0;

            signed h_input = h/multiplier;
            signed w_input = w/multiplier;

            signed h_input_max = (h+1)/multiplier-1;
            signed w_input_max = (w+1)/multiplier-1;

            signed h_step = h_input_max - h_input + 2;
            signed w_step = w_input_max - w_input + 2;

            for (signed xa = w_input; xa < w_input_max + 2 && xa < input_width; xa += w_step / samples)
                for (signed ya = h_input; ya < h_input_max + 2 && ya < input_width; ya += h_step / samples)
                    pixel = average(pixel, input[(signed)xa + ((signed)ya * input_width)]);

            output[w + (h * output_width)] = pixel;
        }
    }
}

with this I could also create thumbnails of any size that still looked correct

the end result looks great and similar to the MacOS implementation which means I have achived my goal

pull request

Bootstrapping executables

executable hell

a lot of applications these days are distributed in multiple executable files

especially game mods

launching these programs directly is fine and good but for things like mods for steam games that require a third party executable thats where the problems come in, especially on Linux.

My local install of Modern Warfare 2 with IW4x installed has 3 executables

iw4mp.exe  iw4sp.exe  iw4x.exe 

It gets away with this on steam by having 2 different titles for singleplayer and multiplayer

but launching iw4x with the Proton environment is where it gets annoying

I can replace the mp executable but that means I need to deal with moving it when I want to play regular MP

launching it directly without steam can be done in this case but other games may depend on steam running, which wine itself cannot tell if it is

wrapping around binaries

I copied together some boilerplate code from my other projects polecat and OFLauncher to create a simple Qt application.

the logic is quite simple

QDirIterator it(".", {"*" EXE}, QDir::Files);
while (it.hasNext())
{
    it.next(); // we want the filename so lets ignore the output
    QString filename = it.fileName();

    if (!isExe(filename.toStdString().c_str()) || filename.compare(prgm) == 0) continue;

    addButton(filename);

}

we iterate over all files in the current directory and check if they are executable files.

On linux we can simply check the executable bit but on Windows there isn't such a straight forward way so we just check if it ends with .EXE

#define EXE ".exe"

int isExe(const char* path)
{
#ifdef _WIN32
    size_t pathlen = strlen(path);

    return strncmp(path + (pathlen - strlen(EXE)), EXE, strlen(EXE)+1) == 0;
#else
    struct stat sb = getStat(path);

    return (sb.st_mode & S_IXUSR) != 0;
#endif
}

to be cheap we don't store the executable names or paths ourselves

every executable gets a button added with its name

void MainWindow::addButton(const QString name)
{
    QPushButton* button = new QPushButton(this->centralwidget);
    button->setText(name);

    connect(button, &QPushButton::clicked, this, [=]{replaceProcess(name);});

    this->verticalLayout->addWidget(button);
}

that button gets a lambda function hooked up to its clicked event giving us access to the name without having to store it ourselves

void MainWindow::replaceProcess(QString name)
{
    char* exec = new char[strlen(this->argv[0]) - strlen(this->prgm) + name.size()];
    strcpy(exec, this->argv[0]);
    strcpy(exec+(this->prgm-this->argv[0]), name.toStdString().c_str());
    this->argv[0] = exec;

    if (execvp(exec, this->argv) == -1)
        printf("execvp() %s\n", strerror(errno));
}

we keep all but argv[0] the same so we can retain commandline arguments.

argv[0] needs to be modified since many programs expect it to contain its own executable name

the resulting executable is rather simplistic in design but it does its job as advertised

source code

OpenFortress Launcher history

2020

After continuing some work on getting the updated UI ported to Linux I started experimenting with the idea of a launcher

first designs were rather simple and naive in nature

after talking a bit about this in a Discord server I am in a friend of mine decided to create a mockup for a launcher

Implementing it was a bit rough and since I wanted to use OpenFortress assets some things needed to be changed

after that I stopped wanting to work on any of it and concluded any work on OpenFortress

the old source code has been archived on this branch for the sake of archival

2021

After a lot of events (including getting banned from the OpenFortress server due to me being confused with another person) I came back and looked at what was there

A User called VoxelTek had posted a link to their Linux script to install OpenFortress

having seen his script I opened a PR to make it a shell script instead of calling shell commands in python

the response

you might be better off creating your own project.

lead to me doing exactly that

ofman was a shells script inspired by r2mod_cli

from there on I remembered that I the plan to make a launcher in the past so I archived ofman and created OFLauncher

since I can't simply pull together a bunch of binaries to do the heavy lifting

there isn't a lot I can say about most parts except for the SVN code

SVN

when adding support SVN I just used the standard svn library which created simple yet powerful code

int svn_checkout(char* path, char* url)
{
    err = svn_client_checkout(NULL, url, path, &rev, true, ctx, pool);

    return handle_error();
}

int svn_update(char* path)
{
    svn_revnum_t tmp;

    err = svn_client_update(&tmp, path, &rev, true, ctx, pool);

    return handle_error();
}

(source code)

but during development I used

the M cross environment to compile the program for the Windows platform

which didn't build svn with serf to there was no support for fetching over http/https

without support I had to fall back to either loading a svn dll or calling the svn binary

I had no conscistent place to get a free libsvn.dll from so I resorted to calling the svn binary which resulted in interesting code

int svn_checkout(char* path, char* url)
{
    char exec[PATH_MAX] = {0};
    strcpy(exec, "\"");
#ifdef _WIN32
    strcat(exec, "\"");
#endif
    strcat(exec, SVN);
    strcat(exec, "\" " SVN_CHECKOUT " \"");
    strcat(exec, url);
    strcat(exec, "\" \"");
    strcat(exec, path);
    strcat(exec, "\"");
#ifdef _WIN32
    strcat(exec, "\"");
#endif

    return system(exec);
}

You might wonder about the windows preprocessors and I can only link you this SO post https://stackoverflow.com/a/9965141

Qt

Since having a graphical interface was a goal of the original launcher I took the design and asked anyone for feedback on it

I thought I had lost the code for the original so I had recreated a similar design from scratch

with the help of some players I iterated over designs and ended up with this

at this point the launcher was already beyond a simple design and checked your installation to adapt the UI

and with that it was pretty much done

here is a video of version thats a bit older in action

since then the OpenFortress people have created a system that improves the way assets can be downloaded by indexing them into an SQLite database with a program

maybe I'll add that too at some point