Game Data Model
Relevant source files
The following files were used as context for generating this wiki page:
The Game Data Model is a core component of the SOFL application, responsible for representing all data and business logic related to a single game. It employs a decoupled architecture, separating the underlying game data and logic from its graphical representation in the user interface. This separation is achieved through a GameData object, which holds the state, and a Game GTK widget, which displays it.
A key feature of this model is its extensibility, demonstrated by the specialized OnlineFixGameData subclass that provides unique functionality for "Online-Fix" games. A factory pattern (GameFactory) is used to instantiate the correct type of game object based on its source, ensuring that different game types can be handled polymorphically throughout the application.
Core Architecture
The architecture separates data management from UI presentation. The GameData class and its subclasses handle all non-UI logic, such as launching, saving, and managing game properties. The Game class is a GTK widget that observes a GameData instance and updates its appearance in response to data changes, which are communicated via GObject signals.
Sources: [sofl/game.py:32](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game.py#L32), [sofl/game_data.py:30](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_data.py#L30)
Class Diagram
This diagram illustrates the relationship between the data classes (GameData, OnlineFixGameData), the UI widget (Game), and the factory (GameFactory).
Sources: [sofl/game_data.py:30](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_data.py#L30), [sofl/onlinefix_game.py:29](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/onlinefix_game.py#L29), [sofl/game.py:32](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game.py#L32), [sofl/game_factory.py](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_factory.py)
GameData Base Class
The GameData class, inheriting from GObject.Object, is the foundational data model for all games in the application. It stores core attributes and defines base functionality for game interactions. It is designed to be independent of the UI.
Sources: [sofl/game_data.py:30-33](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_data.py#L30-L33)
Attributes
The following table lists the key attributes of the GameData class.
| Attribute | Type | Description |
|---|---|---|
name | str | The display name of the game. |
executable | str | The command or path to the game's executable. |
game_id | str | A unique identifier for the game. |
source | str | The origin of the game (e.g., "steam", "imported", "online-fix"). |
base_source | str | The root source, derived from source (e.g., "online-fix" from "online-fix_1"). |
added | int | The Unix timestamp when the game was added. |
last_played | int | The Unix timestamp of the last time the game was played. |
hidden | bool | If True, the game is hidden from the main view. |
removed | bool | If True, the game is marked for removal. |
developer | Optional[str] | The name of the game's developer. |
Sources: [sofl/game_data.py:37-50](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_data.py#L37-L50)
Communication via Signals
GameData communicates with the UI layer (Game widget) using GObject signals. This allows the data model to remain decoupled from the view.
| Signal | Parameters | Description |
|---|---|---|
update-ready | (object,) | Emitted when the game's UI needs to be refreshed with new data. |
save-ready | (object,) | Emitted to signal that the game's data should be persisted to disk. |
toast | (str,) | Emitted to request that a notification (toast) be shown to the user. |
Sources: [sofl/game_data.py:53-57](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_data.py#L53-L57)
Core Methods
launch(): The standard launch method. It updates thelast_playedtimestamp, saves the state, and then executes the game's command usingrun_executable_with_tracking. It also notifies the main window to track the running process.save(): Emits thesave-readysignal to trigger data persistence.update(): Emits theupdate-readysignal to trigger a UI refresh.toggle_hidden(): Flips the booleanhiddenstate and triggers save/update.remove_game(): Sets theremovedflag toTrueand triggers save/update.
Sources: [sofl/game_data.py:108-144](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_data.py#L108-L144)
OnlineFixGameData Subclass
This class extends GameData to provide specialized handling for games from "online-fix.me". It overrides key methods to manage Wine/Proton environments and launch games through the Steam client.
Sources: [sofl/onlinefix_game.py:29](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/onlinefix_game.py#L29)
Overridden and New Methods
| Method | Description |
|---|---|
get_play_button_label() | Overridden to return "Play with Online-Fix". |
launch() | Overridden with complex logic to launch the game using a specific Proton version, a dedicated Wine prefix, and the Steam client. |
uninstall_game() | A new method to delete the game's files from the disk after confirmation. It includes logic to detect the game's root folder. |
_create_wine_prefix() | A private helper to create the necessary Wine prefix directory structure for the game. |
Sources: [sofl/onlinefix_game.py:32](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/onlinefix_game.py#L32), [sofl/onlinefix_game.py:68](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/onlinefix_game.py#L68), [sofl/onlinefix_game.py:188](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/onlinefix_game.py#L188)
Launch Process for Online-Fix Games
The launch process for an OnlineFixGameData instance is significantly different from the base GameData launch. It involves checking for a running Steam instance, verifying Proton versions, preparing environment variables, and constructing a specific launch command.
This diagram shows the flow of the OnlineFixGameData.launch() method.
Sources: [sofl/onlinefix_game.py:68-175](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/onlinefix_game.py#L68-L175)
Game Widget (Presentation Layer)
The Game class is a Gtk.Box widget that provides the visual representation of a game in the library view. Each Game instance holds a reference to a GameData object. It is responsible for rendering the game's name and cover, and for handling user interactions like clicks.
Sources: [sofl/game.py:32-35](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game.py#L32-L35)
It connects to its GameData object's signals (update-ready, save-ready, toast) to react to changes. For example, when update-ready is emitted, the on_update_ready handler updates the game's title label in the UI. When a user clicks the play button, the main_button_clicked method calls the launch() method on its data object, delegating the actual launch logic.
Sources: [sofl/game.py:68-85](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game.py#L68-L85), [sofl/game.py:104-109](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game.py#L104-L109)
GameFactory
The GameFactory is a simple factory responsible for creating the correct Game object (Game which contains either GameData or OnlineFixGameData) based on the source field in the provided data dictionary. This allows the application to handle different game types without needing to know the specific implementation details at the point of creation.
Sources: [sofl/game_factory.py:27-29](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_factory.py#L27-L29)
Creation Logic
The factory's create_game method inspects the source property of the input data.
- If the
sourcestarts with"online-fix", it instantiatesOnlineFixGameData. - Otherwise, it falls back to the base
GameData.
Finally, it wraps the created data object in aGamewidget and returns it.
# sofl/game_factory.py:31-41
class GameFactory:
@staticmethod
def create_game(data: dict[str, Any]) -> "Game":
"""Factory for creating game objects based on source"""
source = data.get("source", "")
if source.startswith("online-fix"):
game_data = OnlineFixGameData(data)
else:
game_data = GameData(data)
from sofl.game import Game
return Game(data=game_data)
Sources: [sofl/game_factory.py:31-41](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/game_factory.py#L31-L41)
Game Creation and Modification
Games are added and edited through the DetailsDialog.
When adding a new game, the dialog collects the name, executable, and game type ("Online-Fix" or "Regular").
- If the name or executable is empty, an error is shown.
- A new, unique
game_idis generated based on the source (e.g.,online-fix_1,imported_1). - The
GameFactoryis then used to create the newGameobject with the collected data.
Sources: [sofl/details_dialog.py:202-244](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/details_dialog.py#L202-L244)
When editing an existing game, the dialog allows changing the name, developer, executable, and even the game type.
- If the user changes the game type from "Regular" to "Online-Fix" (or vice-versa), the object's
sourceattribute is updated. - The game's entry is moved within the central
shared.store.source_gamesdictionary to reflect the new source category. - The changes are saved by calling the game object's
save()andupdate()methods.
Sources: [sofl/details_dialog.py:262-293](https://github.com/Qeatrix/steam-online-fix-launcher/blob/HEAD/sofl/details_dialog.py#L262-L293)