[gnome-games/wip/exalm/n64: 31/31] nintendo-64: Handle controller paks
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/wip/exalm/n64: 31/31] nintendo-64: Handle controller paks
- Date: Mon, 2 Mar 2020 11:18:22 +0000 (UTC)
commit 587103cad923cebc058dfe00cc383cb7287e3a45
Author: Alexander Mikhaylenko <alexm gnome org>
Date: Sun Feb 2 15:42:21 2020 +0500
nintendo-64: Handle controller paks
Store paks in the savestate and add a switcher menu, similarly to
Nintendo DS.
plugins/nintendo-64/data/meson.build | 6 +
plugins/nintendo-64/data/nintendo-64.gresource.xml | 7 ++
.../nintendo-64/data/ui/nintendo-64-pak-player.ui | 39 ++++++
.../data/ui/nintendo-64-pak-switcher.ui | 50 ++++++++
plugins/nintendo-64/src/meson.build | 8 +-
.../nintendo-64/src/nintendo-64-pak-player.vala | 43 +++++++
.../nintendo-64/src/nintendo-64-pak-switcher.vala | 81 +++++++++++++
plugins/nintendo-64/src/nintendo-64-pak.vala | 40 +++++++
plugins/nintendo-64/src/nintendo-64-platform.vala | 11 ++
plugins/nintendo-64/src/nintendo-64-plugin.vala | 4 +-
plugins/nintendo-64/src/nintendo-64-runner.vala | 131 +++++++++++++++++++++
plugins/nintendo-64/src/nintendo-64-savestate.vala | 33 ++++++
12 files changed, 450 insertions(+), 3 deletions(-)
---
diff --git a/plugins/nintendo-64/data/meson.build b/plugins/nintendo-64/data/meson.build
index 0d4b6c49..063fe570 100644
--- a/plugins/nintendo-64/data/meson.build
+++ b/plugins/nintendo-64/data/meson.build
@@ -1 +1,7 @@
install_data (plugin_name + '.plugin', install_dir: plugins_dir)
+
+nintendo_64_resources = gnome.compile_resources (
+ 'nintendo-64',
+ 'nintendo-64.gresource.xml',
+ c_name: 'resources'
+)
diff --git a/plugins/nintendo-64/data/nintendo-64.gresource.xml
b/plugins/nintendo-64/data/nintendo-64.gresource.xml
new file mode 100644
index 00000000..3bc5831d
--- /dev/null
+++ b/plugins/nintendo-64/data/nintendo-64.gresource.xml
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<gresources>
+ <gresource prefix="/org/gnome/Games/plugins/nintendo-64">
+ <file>ui/nintendo-64-pak-player.ui</file>
+ <file>ui/nintendo-64-pak-switcher.ui</file>
+ </gresource>
+</gresources>
diff --git a/plugins/nintendo-64/data/ui/nintendo-64-pak-player.ui
b/plugins/nintendo-64/data/ui/nintendo-64-pak-player.ui
new file mode 100644
index 00000000..c9bea10c
--- /dev/null
+++ b/plugins/nintendo-64/data/ui/nintendo-64-pak-player.ui
@@ -0,0 +1,39 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <template class="GamesNintendo64PakPlayer" parent="GtkBox">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <child>
+ <object class="GtkLabel" id="title">
+ <property name="visible" bind-source="GamesNintendo64PakPlayer" bind-property="show-title"
bind-flags="sync-create|bidirectional"/>
+ <property name="xalign">0</property>
+ <property name="margin">5</property>
+ <attributes>
+ <attribute name="weight" value="bold"/>
+ <attribute name="scale" value="0.8"/>
+ </attributes>
+ <style>
+ <class name="dim-label"/>
+ </style>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton" id="memory_btn">
+ <property name="visible">True</property>
+ <property name="role">radio</property>
+ <property name="text" translatable="true">Controller Pak</property>
+ <signal name="clicked" handler="memory_btn_clicked"/>
+ </object>
+ </child>
+ <child>
+ <object class="GtkModelButton" id="rumble_btn">
+ <property name="visible">True</property>
+ <property name="role">radio</property>
+ <property name="text" translatable="true">Rumble Pak</property>
+ <property name="sensitive" bind-source="GamesNintendo64PakPlayer" bind-property="supports-rumble"
bind-flags="sync-create"/>
+ <signal name="clicked" handler="rumble_btn_clicked"/>
+ </object>
+ </child>
+ </template>
+</interface>
diff --git a/plugins/nintendo-64/data/ui/nintendo-64-pak-switcher.ui
b/plugins/nintendo-64/data/ui/nintendo-64-pak-switcher.ui
new file mode 100644
index 00000000..53a48360
--- /dev/null
+++ b/plugins/nintendo-64/data/ui/nintendo-64-pak-switcher.ui
@@ -0,0 +1,50 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<interface>
+ <requires lib="gtk+" version="3.24"/>
+ <template class="GamesNintendo64PakSwitcher" parent="GtkBin">
+ <property name="visible">True</property>
+ <child>
+ <object class="GtkMenuButton" id="menu_button">
+ <property name="visible">True</property>
+ <property name="can-focus">False</property>
+ <property name="popover">pak_popover</property>
+ <signal name="notify::active" handler="on_menu_state_changed"/>
+ <child internal-child="accessible">
+ <object class="AtkObject" id="a11y-display-discs">
+ <property name="accessible-name" translatable="yes">Controller Expansion</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkBox">
+ <property name="visible">True</property>
+ <property name="spacing">6</property>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon-name">input-gaming-symbolic</property>
+ </object>
+ </child>
+ <child>
+ <object class="GtkImage">
+ <property name="visible">True</property>
+ <property name="icon-name">pan-down-symbolic</property>
+ </object>
+ </child>
+ </object>
+ </child>
+ </object>
+ </child>
+ </template>
+ <object class="GtkPopover" id="pak_popover">
+ <property name="visible">False</property>
+ <signal name="show" handler="update_ui"/>
+ <child>
+ <object class="GtkBox" id="controllers_box">
+ <property name="visible">True</property>
+ <property name="orientation">vertical</property>
+ <property name="margin">12</property>
+ <property name="spacing">6</property>
+ </object>
+ </child>
+ </object>
+</interface>
diff --git a/plugins/nintendo-64/src/meson.build b/plugins/nintendo-64/src/meson.build
index 39b5bd24..d1c90409 100644
--- a/plugins/nintendo-64/src/meson.build
+++ b/plugins/nintendo-64/src/meson.build
@@ -1,5 +1,11 @@
vala_sources = [
+ 'nintendo-64-pak.vala',
+ 'nintendo-64-pak-player.vala',
+ 'nintendo-64-pak-switcher.vala',
+ 'nintendo-64-platform.vala',
'nintendo-64-plugin.vala',
+ 'nintendo-64-runner.vala',
+ 'nintendo-64-savestate.vala',
]
c_args = [
@@ -8,7 +14,7 @@ c_args = [
shared_module (
'games-' + plugin_name + '-plugin',
- vala_sources,
+ vala_sources + nintendo_64_resources,
dependencies: gnome_games_dep,
c_args: c_args,
install: true,
diff --git a/plugins/nintendo-64/src/nintendo-64-pak-player.vala
b/plugins/nintendo-64/src/nintendo-64-pak-player.vala
new file mode 100644
index 00000000..87ebd791
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-pak-player.vala
@@ -0,0 +1,43 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/plugins/nintendo-64/ui/nintendo-64-pak-player.ui")]
+private class Games.Nintendo64PakPlayer : Gtk.Box {
+ [GtkChild]
+ private Gtk.Label title;
+ [GtkChild]
+ private Gtk.ModelButton memory_btn;
+ [GtkChild]
+ private Gtk.ModelButton rumble_btn;
+
+ public uint player { get; construct; }
+ public bool supports_rumble { get; construct; }
+ public bool show_title { get; set; default = true; }
+
+ private Nintendo64Pak _pak;
+ public Nintendo64Pak pak {
+ get { return _pak; }
+ set {
+ _pak = value;
+ memory_btn.active = (pak == Nintendo64Pak.MEMORY);
+ rumble_btn.active = (pak == Nintendo64Pak.RUMBLE);
+ }
+ }
+
+ public Nintendo64PakPlayer (uint player, bool supports_rumble) {
+ Object (player: player, supports_rumble: supports_rumble);
+ }
+
+ construct {
+ title.label = _("Player %u").printf (player);
+ }
+
+ [GtkCallback]
+ public void memory_btn_clicked () {
+ pak = Nintendo64Pak.MEMORY;
+ }
+
+ [GtkCallback]
+ public void rumble_btn_clicked () {
+ pak = Nintendo64Pak.RUMBLE;
+ }
+}
diff --git a/plugins/nintendo-64/src/nintendo-64-pak-switcher.vala
b/plugins/nintendo-64/src/nintendo-64-pak-switcher.vala
new file mode 100644
index 00000000..09230b8d
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-pak-switcher.vala
@@ -0,0 +1,81 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+[GtkTemplate (ui = "/org/gnome/Games/plugins/nintendo-64/ui/nintendo-64-pak-switcher.ui")]
+private class Games.Nintendo64PakSwitcher : Gtk.Bin, HeaderBarWidget {
+ [GtkChild]
+ private Gtk.MenuButton menu_button;
+ [GtkChild]
+ private Gtk.Box controllers_box;
+
+ public Nintendo64Runner runner { get; construct; }
+
+ public Nintendo64Pak pak1 { get; set; }
+ public Nintendo64Pak pak2 { get; set; }
+ public Nintendo64Pak pak3 { get; set; }
+ public Nintendo64Pak pak4 { get; set; }
+
+ private bool is_menu_open;
+ public bool block_autohide {
+ get { return is_menu_open; }
+ }
+
+ public override void constructed () {
+ update_ui ();
+
+ bind_property ("pak1", runner,
+ "pak1", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+ bind_property ("pak2", runner,
+ "pak2", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+ bind_property ("pak3", runner,
+ "pak3", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+ bind_property ("pak4", runner,
+ "pak4", BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+
+ base.constructed ();
+ }
+
+ public Nintendo64PakSwitcher (Nintendo64Runner runner) {
+ Object (runner: runner);
+ }
+
+ [GtkCallback]
+ private void on_menu_state_changed () {
+ is_menu_open = menu_button.active;
+ notify_property ("block-autohide");
+ }
+
+ [GtkCallback]
+ private void update_ui () {
+ foreach (var row in controllers_box.get_children ())
+ controllers_box.remove (row);
+
+ var core = runner.get_core ();
+ var iterator = core.iterate_controllers ();
+
+ Nintendo64PakPlayer first_widget = null;
+ uint total_players = 0;
+
+ uint port;
+ unowned Retro.Controller controller;
+ while (iterator.next (out port, out controller)) {
+ if (total_players > 3)
+ break;
+
+ total_players++;
+
+ bool supports_rumble = controller.get_supports_rumble ();
+ var widget = new Nintendo64PakPlayer (total_players, supports_rumble);
+
+ if (first_widget == null)
+ first_widget = widget;
+
+ bind_property (@"pak$total_players", widget, "pak",
+ BindingFlags.SYNC_CREATE | BindingFlags.BIDIRECTIONAL);
+
+ controllers_box.add (widget);
+ }
+
+ if (total_players == 1)
+ first_widget.show_title = false;
+ }
+}
diff --git a/plugins/nintendo-64/src/nintendo-64-pak.vala b/plugins/nintendo-64/src/nintendo-64-pak.vala
new file mode 100644
index 00000000..fa251341
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-pak.vala
@@ -0,0 +1,40 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+public enum Games.Nintendo64Pak {
+ MEMORY,
+ RUMBLE,
+ NONE;
+
+ public string get_value () {
+ switch (this) {
+ case MEMORY:
+ return "memory";
+
+ case RUMBLE:
+ return "rumble";
+
+ case NONE:
+ return "none";
+
+ default:
+ assert_not_reached ();
+ }
+ }
+
+ public static Nintendo64Pak? from_value (string value) {
+ switch (value) {
+ case "memory":
+ return MEMORY;
+
+ case "rumble":
+ return RUMBLE;
+
+ case "none":
+ return NONE;
+
+ default:
+ warning ("Unknown screen layout: %s\n", value);
+ return null;
+ }
+ }
+}
diff --git a/plugins/nintendo-64/src/nintendo-64-platform.vala
b/plugins/nintendo-64/src/nintendo-64-platform.vala
new file mode 100644
index 00000000..64355fb1
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-platform.vala
@@ -0,0 +1,11 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+public class Games.Nintendo64Platform : RetroPlatform {
+ public Nintendo64Platform (string id, string name, string[] mime_types, string prefix) {
+ base (id, name, mime_types, prefix);
+ }
+
+ public override Type get_savestate_type () {
+ return typeof (Nintendo64Savestate);
+ }
+}
diff --git a/plugins/nintendo-64/src/nintendo-64-plugin.vala b/plugins/nintendo-64/src/nintendo-64-plugin.vala
index a06551c7..5e286acb 100644
--- a/plugins/nintendo-64/src/nintendo-64-plugin.vala
+++ b/plugins/nintendo-64/src/nintendo-64-plugin.vala
@@ -9,7 +9,7 @@ private class Games.Nintendo64Plugin : Object, Plugin {
private static RetroPlatform platform;
static construct {
- platform = new RetroPlatform (PLATFORM_ID, PLATFORM_NAME, { MIME_TYPE }, PLATFORM_UID_PREFIX);
+ platform = new Nintendo64Platform (PLATFORM_ID, PLATFORM_NAME, { MIME_TYPE },
PLATFORM_UID_PREFIX);
}
public Platform[] get_platforms () {
@@ -58,7 +58,7 @@ private class Games.Nintendo64Plugin : Object, Plugin {
builder.uri = game.get_uri ();
builder.uid = game.get_uid ();
builder.title = game.name;
- return builder.to_runner ();
+ return builder.to_runner (typeof (Nintendo64Runner));
}
}
diff --git a/plugins/nintendo-64/src/nintendo-64-runner.vala b/plugins/nintendo-64/src/nintendo-64-runner.vala
new file mode 100644
index 00000000..c20462f4
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-runner.vala
@@ -0,0 +1,131 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+private class Games.Nintendo64Runner : RetroRunner {
+ private const string MUPEN64PLUS_PAK_OPTION = "mupen64plus-pak%u";
+ private const string PARALLEL_N64_PAK_OPTION = "parallel-n64-pak%u";
+
+ private Nintendo64Pak pak[4];
+
+ public Nintendo64Pak pak1 {
+ get { return pak[0]; }
+ set {
+ pak[0] = value;
+ update_paks ();
+ }
+ }
+
+ public Nintendo64Pak pak2 {
+ get { return pak[1]; }
+ set {
+ pak[1] = value;
+ update_paks ();
+ }
+ }
+
+ public Nintendo64Pak pak3 {
+ get { return pak[2]; }
+ set {
+ pak[2] = value;
+ update_paks ();
+ }
+ }
+
+ public Nintendo64Pak pak4 {
+ get { return pak[3]; }
+ set {
+ pak[3] = value;
+ update_paks ();
+ }
+ }
+
+ private bool has_pak_options (string prefix) {
+ var core = get_core ();
+
+ for (int i = 1; i <= 4; i++)
+ if (!core.has_option (prefix.printf (i)))
+ return false;
+
+ return true;
+ }
+
+ private string? get_option_prefix () {
+ if (has_pak_options (MUPEN64PLUS_PAK_OPTION))
+ return MUPEN64PLUS_PAK_OPTION;
+
+ if (has_pak_options (PARALLEL_N64_PAK_OPTION))
+ return PARALLEL_N64_PAK_OPTION;
+
+ return null;
+ }
+
+ public override HeaderBarWidget? get_extra_widget () {
+ if (get_option_prefix () == null)
+ return null;
+
+ return new Nintendo64PakSwitcher (this);
+ }
+
+ private void update_paks () {
+ var prefix = get_option_prefix ();
+
+ if (prefix == null)
+ return;
+
+ var core = get_core ();
+ for (int i = 0; i < 4; i++) {
+ var option = core.get_option (prefix.printf (i + 1));
+
+ try {
+ option.set_value (pak[i].get_value ());
+ }
+ catch (Error e) {
+ critical ("Couldn't set pak %u to %s: %s", i + 1, pak[i].get_value (),
e.message);
+ }
+ }
+ }
+
+ protected override void save_savestate_metadata (Savestate savestate) throws Error {
+ assert (savestate is Nintendo64Savestate);
+
+ var platform_savestate = savestate as Nintendo64Savestate;
+ platform_savestate.pak1 = pak1;
+ platform_savestate.pak2 = pak2;
+ platform_savestate.pak3 = pak3;
+ platform_savestate.pak4 = pak4;
+
+ base.save_savestate_metadata (savestate);
+ }
+
+ protected override void load_savestate_metadata (Savestate savestate) throws Error {
+ base.load_savestate_metadata (savestate);
+
+ assert (savestate is Nintendo64Savestate);
+
+ var platform_savestate = savestate as Nintendo64Savestate;
+ pak1 = platform_savestate.pak1;
+ pak2 = platform_savestate.pak2;
+ pak3 = platform_savestate.pak3;
+ pak4 = platform_savestate.pak4;
+ }
+
+ protected override void reset_metadata (Savestate? last_savestate) throws Error {
+ base.reset_metadata (last_savestate);
+
+ if (last_savestate == null) {
+ pak1 = Nintendo64Pak.MEMORY;
+ pak2 = Nintendo64Pak.MEMORY;
+ pak3 = Nintendo64Pak.MEMORY;
+ pak4 = Nintendo64Pak.MEMORY;
+
+ return;
+ }
+
+ assert (last_savestate is Nintendo64Savestate);
+
+ var platform_savestate = last_savestate as Nintendo64Savestate;
+ pak1 = platform_savestate.pak1;
+ pak2 = platform_savestate.pak2;
+ pak3 = platform_savestate.pak3;
+ pak4 = platform_savestate.pak4;
+ }
+}
diff --git a/plugins/nintendo-64/src/nintendo-64-savestate.vala
b/plugins/nintendo-64/src/nintendo-64-savestate.vala
new file mode 100644
index 00000000..b0ab21a9
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-savestate.vala
@@ -0,0 +1,33 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+public class Games.Nintendo64Savestate : Savestate {
+ public Nintendo64Pak pak1 { get; set; }
+ public Nintendo64Pak pak2 { get; set; }
+ public Nintendo64Pak pak3 { get; set; }
+ public Nintendo64Pak pak4 { get; set; }
+
+ protected override void load_metadata (KeyFile keyfile) throws KeyFileError {
+ base.load_metadata (keyfile);
+
+ var value = keyfile.get_string ("Nintendo 64", "Pak 1");
+ pak1 = Nintendo64Pak.from_value (value);
+
+ value = keyfile.get_string ("Nintendo 64", "Pak 2");
+ pak2 = Nintendo64Pak.from_value (value);
+
+ value = keyfile.get_string ("Nintendo 64", "Pak 3");
+ pak3 = Nintendo64Pak.from_value (value);
+
+ value = keyfile.get_string ("Nintendo 64", "Pak 4");
+ pak4 = Nintendo64Pak.from_value (value);
+ }
+
+ protected override void save_metadata (KeyFile keyfile) {
+ base.save_metadata (keyfile);
+
+ keyfile.set_string ("Nintendo 64", "Pak 1", pak1.get_value ());
+ keyfile.set_string ("Nintendo 64", "Pak 2", pak2.get_value ());
+ keyfile.set_string ("Nintendo 64", "Pak 3", pak3.get_value ());
+ keyfile.set_string ("Nintendo 64", "Pak 4", pak4.get_value ());
+ }
+}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]