From de423d6ec33a20f33652c6b9c8ce703b867b51bd Mon Sep 17 00:00:00 2001
From: Ilari Liusvaara <ilari.liusvaara@elisanet.fi>
Date: Wed, 9 Nov 2011 01:52:08 +0200
Subject: [PATCH 2/8] Save controller state when savestating

When savestating, save the controller state and restore it upon loadstate.
Prevents libsnes from mixing up buttons.
---
 snes/controller/controller.cpp            |  8 +++++++
 snes/controller/controller.hpp            |  2 ++
 snes/controller/gamepad/gamepad.cpp       | 13 +++++++++++
 snes/controller/gamepad/gamepad.hpp       |  2 +-
 snes/controller/justifier/justifier.cpp   | 36 +++++++++++++++++++++++++++++++
 snes/controller/justifier/justifier.hpp   |  1 +
 snes/controller/mouse/mouse.cpp           | 13 +++++++++++
 snes/controller/mouse/mouse.hpp           |  2 +-
 snes/controller/multitap/multitap.cpp     | 16 ++++++++++++++
 snes/controller/multitap/multitap.hpp     |  2 +-
 snes/controller/superscope/superscope.cpp | 31 ++++++++++++++++++++++++++
 snes/controller/superscope/superscope.hpp |  1 +
 snes/system/input.cpp                     | 16 ++++++++++++++
 snes/system/input.hpp                     |  1 +
 snes/system/serialization.cpp             |  1 +
 15 files changed, 142 insertions(+), 3 deletions(-)

diff --git a/snes/controller/controller.cpp b/snes/controller/controller.cpp
index fa8e07d..5f37849 100755
--- a/snes/controller/controller.cpp
+++ b/snes/controller/controller.cpp
@@ -46,8 +46,16 @@ void Controller::iobit(bool data) {
   }
 }
 
+void Controller::serialize(serializer& s) {
+  Processor::serialize(s);
+  //Save a zero block.
+  unsigned char blockzeroes[SaveSize] = {0};
+  s.array(blockzeroes, SaveSize);
+}
+
 Controller::Controller(bool port) : port(port) {
   if(!thread) create(Controller::Enter, 1);
 }
 
+
 }
diff --git a/snes/controller/controller.hpp b/snes/controller/controller.hpp
index dd748a1..46095a8 100755
--- a/snes/controller/controller.hpp
+++ b/snes/controller/controller.hpp
@@ -13,12 +13,14 @@
 
 struct Controller : Processor {
   enum : bool { Port1 = 0, Port2 = 1 };
+  enum { SaveSize = 16 };
   const bool port;
 
   static void Enter();
   virtual void enter();
   void step(unsigned clocks);
   void synchronize_cpu();
+  virtual void serialize(serializer& s);
 
   bool iobit();
   void iobit(bool data);
diff --git a/snes/controller/gamepad/gamepad.cpp b/snes/controller/gamepad/gamepad.cpp
index 594020d..4fa1c99 100755
--- a/snes/controller/gamepad/gamepad.cpp
+++ b/snes/controller/gamepad/gamepad.cpp
@@ -13,6 +13,19 @@ void Gamepad::latch(bool data) {
   counter = 0;
 }
 
+void Gamepad::serialize(serializer& s) {
+  Processor::serialize(s);
+  //Save block.
+  unsigned char block[Controller::SaveSize] = {0};
+  block[0] = latched ? 1 : 0;
+  block[1] = counter;
+  s.array(block, Controller::SaveSize);
+  if(s.mode() == nall::serializer::Load) {
+    latched = (block[0] != 0);
+    counter = block[1];
+  }
+}
+
 Gamepad::Gamepad(bool port) : Controller(port) {
   latched = 0;
   counter = 0;
diff --git a/snes/controller/gamepad/gamepad.hpp b/snes/controller/gamepad/gamepad.hpp
index c5ca69c..a2392d1 100755
--- a/snes/controller/gamepad/gamepad.hpp
+++ b/snes/controller/gamepad/gamepad.hpp
@@ -2,7 +2,7 @@ struct Gamepad : Controller {
   uint2 data();
   void latch(bool data);
   Gamepad(bool port);
-
+  void serialize(serializer& s);
 private:
   bool latched;
   unsigned counter;
diff --git a/snes/controller/justifier/justifier.cpp b/snes/controller/justifier/justifier.cpp
index 6207916..ad13a9b 100755
--- a/snes/controller/justifier/justifier.cpp
+++ b/snes/controller/justifier/justifier.cpp
@@ -100,6 +100,42 @@ void Justifier::latch(bool data) {
   if(latched == 0) active = !active;  //toggle between both controllers, even when unchained
 }
 
+void Justifier::serialize(serializer& s) {
+  Processor::serialize(s);
+  //Save block.
+  unsigned char block[Controller::SaveSize] = {0};
+  block[0] = latched ? 1 : 0;
+  block[1] = counter;
+  block[2] = active ? 1 : 0;
+  block[3] = player1.trigger ? 1 : 0;
+  block[4] = player2.trigger ? 1 : 0;
+  block[5] = player1.start ? 1 : 0;
+  block[6] = player2.start ? 1 : 0;
+  block[7] = (unsigned short)player1.x >> 8;
+  block[8] = (unsigned short)player1.x;
+  block[9] = (unsigned short)player2.x >> 8;
+  block[10] = (unsigned short)player2.x;
+  block[11] = (unsigned short)player1.y >> 8;
+  block[12] = (unsigned short)player1.y;
+  block[13] = (unsigned short)player2.y >> 8;
+  block[14] = (unsigned short)player2.y;
+  s.array(block, Controller::SaveSize);
+  if(s.mode() == nall::serializer::Load) {
+    latched = (block[0] != 0);
+    counter = block[1];
+    active = (block[2] != 0);
+    player1.trigger = (block[3] != 0);
+    player2.trigger = (block[4] != 0);
+    player1.start = (block[5] != 0);
+    player2.start = (block[6] != 0);
+    player1.x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]);
+    player2.x = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]);
+    player1.y = (short)(((unsigned short)block[11] << 8) | (unsigned short)block[12]);
+    player2.y = (short)(((unsigned short)block[13] << 8) | (unsigned short)block[14]);
+  }
+}
+
+
 Justifier::Justifier(bool port, bool chained) : Controller(port), chained(chained) {
   create(Controller::Enter, 21477272);
   latched = 0;
diff --git a/snes/controller/justifier/justifier.hpp b/snes/controller/justifier/justifier.hpp
index f927acf..6b7bba0 100755
--- a/snes/controller/justifier/justifier.hpp
+++ b/snes/controller/justifier/justifier.hpp
@@ -2,6 +2,7 @@ struct Justifier : Controller {
   void enter();
   uint2 data();
   void latch(bool data);
+  void serialize(serializer& s);
   Justifier(bool port, bool chained);
 
 //private:
diff --git a/snes/controller/mouse/mouse.cpp b/snes/controller/mouse/mouse.cpp
index c9f5d16..6b26fae 100755
--- a/snes/controller/mouse/mouse.cpp
+++ b/snes/controller/mouse/mouse.cpp
@@ -61,6 +61,19 @@ void Mouse::latch(bool data) {
   counter = 0;
 }
 
+void Mouse::serialize(serializer& s) {
+  Processor::serialize(s);
+  //Save block.
+  unsigned char block[Controller::SaveSize] = {0};
+  block[0] = latched ? 1 : 0;
+  block[1] = counter;
+  s.array(block, Controller::SaveSize);
+  if(s.mode() == nall::serializer::Load) {
+    latched = (block[0] != 0);
+    counter = block[1];
+  }
+}
+
 Mouse::Mouse(bool port) : Controller(port) {
   latched = 0;
   counter = 0;
diff --git a/snes/controller/mouse/mouse.hpp b/snes/controller/mouse/mouse.hpp
index 95e24b6..b66ea51 100755
--- a/snes/controller/mouse/mouse.hpp
+++ b/snes/controller/mouse/mouse.hpp
@@ -2,7 +2,7 @@ struct Mouse : Controller {
   uint2 data();
   void latch(bool data);
   Mouse(bool port);
-
+  void serialize(serializer& s);
 private:
   bool latched;
   unsigned counter;
diff --git a/snes/controller/multitap/multitap.cpp b/snes/controller/multitap/multitap.cpp
index 3a6eb72..146c41d 100755
--- a/snes/controller/multitap/multitap.cpp
+++ b/snes/controller/multitap/multitap.cpp
@@ -30,6 +30,22 @@ void Multitap::latch(bool data) {
   counter2 = 0;
 }
 
+void Multitap::serialize(serializer& s) {
+  Processor::serialize(s);
+  //Save block.
+  unsigned char block[Controller::SaveSize] = {0};
+  block[0] = latched ? 1 : 0;
+  block[1] = counter1;
+  block[2] = counter2;
+  s.array(block, Controller::SaveSize);
+  if(s.mode() == nall::serializer::Load) {
+    latched = (block[0] != 0);
+    counter1 = block[1];
+    counter2 = block[2];
+  }
+}
+
+
 Multitap::Multitap(bool port) : Controller(port) {
   latched = 0;
   counter1 = 0;
diff --git a/snes/controller/multitap/multitap.hpp b/snes/controller/multitap/multitap.hpp
index 0540af7..e6324ac 100755
--- a/snes/controller/multitap/multitap.hpp
+++ b/snes/controller/multitap/multitap.hpp
@@ -2,7 +2,7 @@ struct Multitap : Controller {
   uint2 data();
   void latch(bool data);
   Multitap(bool port);
-
+  void serialize(serializer& s);
 private:
   bool latched;
   unsigned counter1;
diff --git a/snes/controller/superscope/superscope.cpp b/snes/controller/superscope/superscope.cpp
index 12068f0..1a1dfbf 100755
--- a/snes/controller/superscope/superscope.cpp
+++ b/snes/controller/superscope/superscope.cpp
@@ -100,6 +100,37 @@ void SuperScope::latch(bool data) {
   counter = 0;
 }
 
+void SuperScope::serialize(serializer& s) {
+  Processor::serialize(s);
+  //Save block.
+  unsigned char block[Controller::SaveSize] = {0};
+  block[0] = latched ? 1 : 0;
+  block[1] = counter;
+  block[2] = trigger ? 1 : 0;
+  block[3] = cursor ? 1 : 0;
+  block[4] = turbo ? 1 : 0;
+  block[5] = pause ? 1 : 0;
+  block[6] = offscreen ? 1 : 0;
+  block[7] = (unsigned short)x >> 8;
+  block[8] = (unsigned short)x;
+  block[9] = (unsigned short)y >> 8;
+  block[10] = (unsigned short)y;
+
+  s.array(block, Controller::SaveSize);
+  if(s.mode() == nall::serializer::Load) {
+    latched = (block[0] != 0);
+    counter = block[1];
+    trigger = (block[2] != 0);
+    cursor = (block[3] != 0);
+    turbo = (block[4] != 0);
+    pause = (block[5] != 0);
+    offscreen = (block[6] != 0);
+    x = (short)(((unsigned short)block[7] << 8) | (unsigned short)block[8]);
+    y = (short)(((unsigned short)block[9] << 8) | (unsigned short)block[10]);
+  }
+}
+
+
 SuperScope::SuperScope(bool port) : Controller(port) {
   create(Controller::Enter, 21477272);
   latched = 0;
diff --git a/snes/controller/superscope/superscope.hpp b/snes/controller/superscope/superscope.hpp
index a7a90b7..93509d7 100755
--- a/snes/controller/superscope/superscope.hpp
+++ b/snes/controller/superscope/superscope.hpp
@@ -2,6 +2,7 @@ struct SuperScope : Controller {
   void enter();
   uint2 data();
   void latch(bool data);
+  void serialize(serializer& s);
   SuperScope(bool port);
 
 //private:
diff --git a/snes/system/input.cpp b/snes/system/input.cpp
index 894de0e..4479acc 100755
--- a/snes/system/input.cpp
+++ b/snes/system/input.cpp
@@ -26,6 +26,22 @@ void Input::connect(bool port, Input::Device id) {
   }
 }
 
+void Input::serialize(serializer &s)
+{
+  int p1, p2;
+  p1 = (int)config.controller_port1;
+  p2 = (int)config.controller_port2;
+  s.integer(p1);
+  s.integer(p2);
+  if(s.mode() == nall::serializer::Load) {
+    connect(Controller::Port1, (Device)p1);
+    connect(Controller::Port2, (Device)p2);
+  }
+  port1->serialize(s);
+  port2->serialize(s);
+}
+
+
 Input::Input() : port1(nullptr), port2(nullptr) {
   connect(Controller::Port1, Input::Device::Joypad);
   connect(Controller::Port2, Input::Device::Joypad);
diff --git a/snes/system/input.hpp b/snes/system/input.hpp
index 7a6bd9e..d2f5fef 100755
--- a/snes/system/input.hpp
+++ b/snes/system/input.hpp
@@ -31,6 +31,7 @@ struct Input {
   Controller *port1;
   Controller *port2;
 
+  void serialize(serializer &s);
   void connect(bool port, Input::Device id);
   Input();
   ~Input();
diff --git a/snes/system/serialization.cpp b/snes/system/serialization.cpp
index f746c3a..67e08a2 100755
--- a/snes/system/serialization.cpp
+++ b/snes/system/serialization.cpp
@@ -56,6 +56,7 @@ void System::serialize_all(serializer &s) {
   smp.serialize(s);
   ppu.serialize(s);
   dsp.serialize(s);
+  input.serialize(s);
 
   if(cartridge.mode() == Cartridge::Mode::SufamiTurbo) sufamiturbo.serialize(s);
   #if defined(GAMEBOY)
-- 
1.8.4.4

