[gnome-games/wip/exalm/n64: 21/21] nintendo-64: Handle controller paks
- From: Alexander Mikhaylenko <alexm src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gnome-games/wip/exalm/n64: 21/21] nintendo-64: Handle controller paks
- Date: Thu, 26 Mar 2020 18:51:52 +0000 (UTC)
commit 5a9dbce738aa71cc4bd6dd78b056255be203d2f8
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 | 49 ++++++++
plugins/nintendo-64/src/meson.build | 8 +-
.../nintendo-64/src/nintendo-64-pak-player.vala | 43 +++++++
.../nintendo-64/src/nintendo-64-pak-switcher.vala | 82 +++++++++++++
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 | 135 +++++++++++++++++++++
plugins/nintendo-64/src/nintendo-64-snapshot.vala | 33 +++++
12 files changed, 454 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..355da19b
--- /dev/null
+++ b/plugins/nintendo-64/data/ui/nintendo-64-pak-switcher.ui
@@ -0,0 +1,49 @@
+<?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>
+ <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..c627268b 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-snapshot.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..8640bca4
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-pak-switcher.vala
@@ -0,0 +1,82 @@
+// 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 ();
+
+ runner.controllers_changed.connect (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");
+ }
+
+ 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..9ca1f6ff
--- /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_snapshot_type () {
+ return typeof (Nintendo64Snapshot);
+ }
+}
diff --git a/plugins/nintendo-64/src/nintendo-64-plugin.vala b/plugins/nintendo-64/src/nintendo-64-plugin.vala
index c55a7fdf..da9eecc5 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 () {
@@ -53,7 +53,7 @@ private class Games.Nintendo64Plugin : Object, Plugin {
private static Runner? create_runner (Game game) throws Error {
var core_source = new RetroCoreSource (platform);
- return new RetroRunner (game, core_source);
+ return new Nintendo64Runner (game, core_source);
}
}
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..3ecd922b
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-runner.vala
@@ -0,0 +1,135 @@
+// 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 ();
+ }
+ }
+
+ public Nintendo64Runner (Game game, RetroCoreSource source) {
+ base.from_source (game, source);
+ }
+
+ 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_to_snapshot (Snapshot snapshot) throws Error {
+ base.save_to_snapshot (snapshot);
+
+ assert (snapshot is Nintendo64Snapshot);
+
+ var n64_snapshot = snapshot as Nintendo64Snapshot;
+ n64_snapshot.pak1 = pak1;
+ n64_snapshot.pak2 = pak2;
+ n64_snapshot.pak3 = pak3;
+ n64_snapshot.pak4 = pak4;
+ }
+
+ protected override void load_from_snapshot (Snapshot snapshot) throws Error {
+ base.load_from_snapshot (snapshot);
+
+ assert (snapshot is Nintendo64Snapshot);
+
+ var n64_snapshot = snapshot as Nintendo64Snapshot;
+ pak1 = n64_snapshot.pak1;
+ pak2 = n64_snapshot.pak2;
+ pak3 = n64_snapshot.pak3;
+ pak4 = n64_snapshot.pak4;
+ }
+
+ protected override void reset_with_snapshot (Snapshot? last_snapshot) throws Error {
+ base.reset_with_snapshot (last_snapshot);
+
+ if (last_snapshot == null) {
+ pak1 = Nintendo64Pak.MEMORY;
+ pak2 = Nintendo64Pak.MEMORY;
+ pak3 = Nintendo64Pak.MEMORY;
+ pak4 = Nintendo64Pak.MEMORY;
+
+ return;
+ }
+
+ assert (last_snapshot is Nintendo64Snapshot);
+
+ var n64_snapshot = last_snapshot as Nintendo64Snapshot;
+ pak1 = n64_snapshot.pak1;
+ pak2 = n64_snapshot.pak2;
+ pak3 = n64_snapshot.pak3;
+ pak4 = n64_snapshot.pak4;
+ }
+}
diff --git a/plugins/nintendo-64/src/nintendo-64-snapshot.vala
b/plugins/nintendo-64/src/nintendo-64-snapshot.vala
new file mode 100644
index 00000000..755e8f5d
--- /dev/null
+++ b/plugins/nintendo-64/src/nintendo-64-snapshot.vala
@@ -0,0 +1,33 @@
+// This file is part of GNOME Games. License: GPL-3.0+.
+
+public class Games.Nintendo64Snapshot : Snapshot {
+ 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]