Since my last blog post the main merge request of my GSoC project has landed and after that I followed up with subsequent bugfixes and also a couple of enhancements to the savestates manager.
I will use this blog post for the final submission as part of my participation in the program. As such this post will be a bit longer than the others but I’ll still keep it visual and populate it with gifs and screenshots 🙂
My main merge request
Merge request (MR) !278 is the largest and most important one that I have submitted for this project. The changes it introduces can be summarized as follows:
Automatic migration from the old directory layout
Backend changes to use the new directory layout and savestates
An initial implementation of the UI to manipulate savestates. This UI was capable of saving, loading and deleting savestates.
The most important change was the refactor of the RetroRunner class which is a class that manages the emulator core used to run games (the core is represented as an instance of a Retro.Core object). An instance of a RetroRunner manages an instance of a Retro.Core for one game and now it also manages the savestates for that game.
Secondary MR 1) Add the savestates renaming feature
!301 introduces a new enhancement to the savestates manager, it allows the user to rename savestates.
Secondary MR 2) Add shortcuts for using savestates
!305 along with !317 introduce quality of life shortcuts for the savestates manager 🙂
The former MR implements the shortcuts themselves, while the latter (not yet merged) MR lists them in the Shortcuts window.
Secondary MR 3) Flash effect when creating savestates
!310 introduces a pretty flash effect which is played every time a new savestate is created. This effect was inspired by the one used by GNOME Screenshot and we attempted to mimic it’s implementation. 🙂
I was very surprised to find out the flash is actually not implemented by GNOME Screenshot but rather by GNOME Shell. This feature was very interesting to work on as I had to check the source code of GNOME Shell to find out what interpolation function and duration it used for the animation. Then, using that information, I had to write code that animated the opacity property of the background widget in order to achieve the same effect. We concluded that the initial version of the flash was too bright and might distract the user from the game. Because of that the Games flash has a reduced opacity compared to the GNOME Shell one and as such appears a bit dimmer.
Secondary MR 4) Use a nicer date format for savestates
As I’m writing this post, !319 still needs a bit of work, but it aims to show the savestates dates similarly to how Nautilus shows the Modified date for files. Note that in the screenshot below the dates are of course fabricated (since there were no savestates back in 2018) in order to simply illustrate the various available formats.
Along with these MRs, there were also several others with bugfixes and small tweaks:
!294 Here an important bug was fixed in which the automatic savestates were not pruned properly and we also changed the way in which new savestate names were generated such that it works similarly to how new file names are generated by the file manager (e.g. If we have savestates “New savestate 1”, “A”, “B” and we create a new savestate it would be called “New savestate 2” rather than “New savestate 4”)
!300 Before this MR the game would unpause before the savestates menu finished it’s animation which would confuse the user
!303 Fix a small UI bug in which the new savestate row (the one denoted by the + sign) could be selected, which is to be avoided
!304 Fix a small issue in which savestates would get saved with a wrong thumbnail
!306 These changes are a fix for bugs discovered in !294
!307 The Nintendo DS core caused crashes because it wasn’t properly de-initialized
!311 When renaming a savestate we iterate through the others to check if there exists one with the same name. This fix ensures that we don’t take the new savestate row into consideration when doing that
!312 Some games don’t support savestates (e.g. Steam games) and we must ignore the savestates shortcuts with these games
!313 UI fix for the edge case in which a savestate name spans multiple lines
!314 If we click the Rename button and the selected row is not visible on the screen then we scroll to it
!315 Allow creating multiple savestates per second. Creating savestates rapidly caused runtime errors because the new directories would have the same name based on time.
!316 Avoid runtime errors when spamming the Delete button
Possible future improvements to the project
Gamepad navigation – Allow the player to use the savestates manager with a gamepad. The difficulty of this task comes from the fact that the number of available buttons that games don’t use is limited.
Undo loading – This is a feature common to many emulators and it helps the users in case they accidentally loaded a savestate and lost the progress of their current session.
Since my last blog post I have kept on working on my GSoC project while also making preparations for attending the GUADEC 2019 conference.
The main Merge Request of my project has been merged into the master branch of Games and then I followed up with a couple more bugfixes for bugs that my mentor has noticed after the merge.
A very mean bug 😦
A very important bug/regression that I’m glad we were able to fix is the NintendoDS crash that was caused by introducing the Savestates Manager. We couldn’t have included this feature in a release as long as this bug was present since it was a major regression as the user wasn’t even able to start a NintendoDS game at all.
The bug was caused by the fact that we used to re-instantiate the emulator core everytime we would start the game or load a new savestate. This didn’t cause any problems with other cores but it seems that the NintendoDS core didn’t like this.
The lucky fix \o/
Initially I had no idea how to approach this issue and I also doubted that re-instantiating is the cause of the problem because it was working perfectly fine with the other cores. Nevertheless I decided to try this out and was very surprised, happy and relieved when I saw that it actually fixed the problem completely and now we are able to play NintendoDS games with savestates. Now when loading a savestate the core is stopped, it’s state is changed and then the core is resumed.
There is still one week left of GSoC and during this time with one final effort I will attempt to implement Savestate renaming before submitting the final version of my project.
My next blog post will be after the GUADEC 2019 Conference at which I will have a lightning talk about my project and hopefully get to meet some of the people reading this post 🙂
All good things come to an end and so does the 2019 Google Summer of Code. With the last coding period having officially started my project is slowly approaching it’s last commit.
Lately I have been working mostly on various issues regarding the looks and the behavior of the Savestates Manager, but there are also two new visible UI changes that can be seen in the following screenshot:
The Save button that used to be present in the header bar has been replaced with a special row which creates a new savestate when it’s selected.
The row labels have also been tweaked and now use different font sizes and colors for the savestates names and their dates. Another small change here is that the creation dates use a different format.
The list of current issues is quite large and sometimes if I fix one issue I manage to introduce another issue or even a bug in the process, but I am slowly making progress towards the end goal.
Next up I will be working on adjusting how the savestates thumbnails are being drawn. Currently they are not scaled or resized which causes the UI to look quite weird with certain platforms. For example with this PlayStation game the savestate name and creation date can’t even be seen because the thumbnail is too wide:
Since my last blog post I have been on a short vacation but I have also managed to make some progress on my GSoC project again with guidance from my mentor.
My latest work concerns the UI used for the Savestates Manager.
The available savestates are listed on the right. Note that every savestate has a thumbnail which is a screenshot of the game taken at the moment when the savestate was created. For me it was very satisfying to reach this milestone 🙂
Every savestate also has a creation date which is displayed in the menu, but that’s certainly not as eye-catching as the screenshots.
There are still many missing features and things that need improving (such as the date formatting) but with every commit I feel that I am getting closer to the finished project.
Next up I will be working on the menu header bar which is going to contain the Load, Delete and Cancel buttons.
Since my last blog post I have kept working on my GSoC project with guidance from my mentor and we finally have some UI to show: a very primitive version of the Savestates Menu.
The current capabilities of this menu are as follows:
List the available savestates (they are currently named according to their creation date)
Load any of the savestates on click
Manually create a savestate of the current game using the “Save” button
Unfortunately along with the progress that was made we also encountered a bug with the NintendoDS core that causes Games to crash if we attempt to load a savestate. We are not yet 100% sure if the bug is caused by my changes or by the NintendoDS core itself.
I hope we are able to fix it by the end of the summer although I am not even sure where to start since savestates are working perfectly fine with other cores. Another confusing matter about this is that the Restart/Resume Dialog works fine with the NintendoDS core and it also uses savestates. This led me to believe that perhaps cores can be used to load savestates only once, but this can’t be the problem since we re-instantiate the core every time we load a savestate.
In the worst case we might just have to make a special case for the NintendoDS core and not use savestates with it, except for the Resume/Restart dialog. This would sadden me deeply since there are plenty of NintendoDS games which could benefit from this feature.
On the flip side of the coin, I have been successfully able to use the new menu in order to get a better high-score at Asteroids by loading to a previous savestate everytime I lost a life 🙂 This was one of the first use-cases I thought about when I decided to work on this project and it makes me very happy to see that our work has made it possible.
While this may not be the way the game was meant to be played initially and some might argue it’s considered “cheating”, it was still a very fun way to spend an evening after a long day of work.
In the end that’s why we play games: to have fun 🙂
Lately I have been spending a lot of time staring at the Resume/Restart dialog of GNOME Games.
Games currently allows the user to resume most retro games from the exact state the game was left in last time it was quit. To do this Games saves several files required to restore the state of the emulator core and resume it’s execution. These files grouped together are called a “savestate”. Currently Games has only one savestate per game which is overwritten everytime the user exits the game.
The purpose of my GSoC project is to allow the user to store and manage more than one savestate. These past days I have been writing code that makes Games create a brand new savestate everytime the user exits the game.
Before my changes the Resume button would simply load the single savestate which existed for that particular game. Now it loads the latest savestate that was created, so from the user’s perspective nothing has changed (with one tiny exception I’ll explain later).
My changes are slowly amounting to 1000 lines of code (insertions + deletions). I admit it does feel a bit uneasy to edit 1000 lines from the app’s code and not see any changes from the user’s point of view. It makes me wonder how often does this also happen with other software that I’m using :S
Unfortunately, there is one minor downgrade that my changes have introduced. As can be seen from the first image in the post, there is a screenshot of the game behind the Dialog. My changes have altered the sequence of operations required to boot the emulator core, which in turn broke the loading of screenshots. Now, when starting the game there is always a black screen behind the Resume/Restart Dialog 😦
In the next days I will finally start working on a primitive UI that is going to display all of the savestates that are available when launching a game. The UI would also allow the user to boot the game from a particular savestate on click.
Between my last blog post and now I have been accepted into the Google Summer of Code programme (or GSoC for short), which is basically an opportunity for students to work on open-sorce software projects throughout the summer and also receive a stipend (money) for it.
The coding period officially began on the 27th of May, but I actually started working on my project before that in order to get a head start.
Throughout the summer I will be implementing a feature for GNOME Games. To be more specific, I will be implementing a “Savestates Manager”. The feature itself has already been designed and the details about how it should work are explained very well in this wiki page: https://wiki.gnome.org/Design/Playground/Games/Snapshots
Currently I’m working on automatically migrating files from the old directory layout to the new one in order to support multiple savestates. This is how the new directory layout is going to look like:
The snapshot file is probably the most important one because it’s used to set the state of the emulator core. The creation date is used to uniquely identify savestates.
I will keep adding blog posts as I continue to make progress and hopefully there will also be some UI to screenshot before the next post.