mirror of https://github.com/PCSX2/pcsx2.git
[SAVEVERSION+] Multitap: Make multitaps manage their own states
This commit is contained in:
parent
eb1d93d4e5
commit
2443e06745
|
@ -16,6 +16,7 @@
|
|||
#include "PrecompiledHeader.h"
|
||||
|
||||
#include "Common.h"
|
||||
#include "StateWrapper.h"
|
||||
|
||||
#include "SIO/Multitap/MultitapProtocol.h"
|
||||
|
||||
|
@ -25,8 +26,7 @@
|
|||
#define MT_LOG_ENABLE 0
|
||||
#define MT_LOG if (MT_LOG_ENABLE) DevCon
|
||||
|
||||
MultitapProtocol g_MultitapPort0;
|
||||
MultitapProtocol g_MultitapPort1;
|
||||
std::array<MultitapProtocol, SIO::PORTS> g_MultitapArr;
|
||||
|
||||
void MultitapProtocol::SupportCheck()
|
||||
{
|
||||
|
@ -114,6 +114,16 @@ void MultitapProtocol::FullReset()
|
|||
this->currentMemcardSlot = 0;
|
||||
}
|
||||
|
||||
bool MultitapProtocol::DoState(StateWrapper& sw)
|
||||
{
|
||||
if (!sw.DoMarker("Multitap"))
|
||||
return false;
|
||||
|
||||
sw.Do(¤tPadSlot);
|
||||
sw.Do(¤tMemcardSlot);
|
||||
return true;
|
||||
}
|
||||
|
||||
u8 MultitapProtocol::GetPadSlot()
|
||||
{
|
||||
return this->currentPadSlot;
|
||||
|
|
|
@ -15,6 +15,12 @@
|
|||
|
||||
#pragma once
|
||||
|
||||
#include "SIO/SioTypes.h"
|
||||
|
||||
#include <array>
|
||||
|
||||
class StateWrapper;
|
||||
|
||||
enum class MultitapMode
|
||||
{
|
||||
NOT_SET = 0xff,
|
||||
|
@ -39,6 +45,7 @@ public:
|
|||
|
||||
void SoftReset();
|
||||
void FullReset();
|
||||
bool DoState(StateWrapper& sw);
|
||||
|
||||
u8 GetPadSlot();
|
||||
u8 GetMemcardSlot();
|
||||
|
@ -46,6 +53,5 @@ public:
|
|||
void SendToMultitap();
|
||||
};
|
||||
|
||||
extern MultitapProtocol g_MultitapPort0;
|
||||
extern MultitapProtocol g_MultitapPort1;
|
||||
extern std::array<MultitapProtocol, SIO::PORTS> g_MultitapArr;
|
||||
|
||||
|
|
|
@ -49,8 +49,7 @@ namespace Pad
|
|||
|
||||
static const char* GetControllerTypeName(Pad::ControllerType type);
|
||||
|
||||
static std::unique_ptr<PadBase> CreatePad(u8 unifiedSlot, Pad::ControllerType controllerType);
|
||||
static PadBase* ChangePadType(u8 unifiedSlot, Pad::ControllerType controllerType);
|
||||
static PadBase* CreatePad(u8 unifiedSlot, Pad::ControllerType controllerType, size_t ejectTicks = 0);
|
||||
|
||||
static void LoadMacroButtonConfig(
|
||||
const SettingsInterface& si, u32 pad, const ControllerInfo* ci, const std::string& section);
|
||||
|
@ -91,7 +90,6 @@ void Pad::LoadConfig(const SettingsInterface& si)
|
|||
{
|
||||
s_macro_buttons = {};
|
||||
|
||||
// This is where we would load controller types, if onepad supported them.
|
||||
for (u32 i = 0; i < Pad::NUM_CONTROLLER_PORTS; i++)
|
||||
{
|
||||
const std::string section = GetConfigSection(i);
|
||||
|
@ -99,11 +97,12 @@ void Pad::LoadConfig(const SettingsInterface& si)
|
|||
pxAssert(ci);
|
||||
|
||||
// If a pad is not yet constructed, at minimum place a NotConnected pad in the slot.
|
||||
// Do not abort the for loop - If there pad settings, we want those to be applied to the slot.
|
||||
// Do not abort the for loop - If there are pad settings, we want those to be applied to the slot.
|
||||
PadBase* pad = Pad::GetPad(i);
|
||||
|
||||
if (!pad || pad->GetType() != ci->type)
|
||||
{
|
||||
pad = Pad::ChangePadType(i, ci->type);
|
||||
pad = Pad::CreatePad(i, ci->type);
|
||||
pxAssert(pad);
|
||||
}
|
||||
|
||||
|
@ -471,22 +470,22 @@ std::string Pad::GetConfigSection(u32 pad_index)
|
|||
return fmt::format("Pad{}", pad_index + 1);
|
||||
}
|
||||
|
||||
std::unique_ptr<PadBase> Pad::CreatePad(u8 unifiedSlot, ControllerType controllerType)
|
||||
// Create a new pad instance, update the smart pointer for this pad slot, and return a dumb pointer to the new pad.
|
||||
PadBase* Pad::CreatePad(u8 unifiedSlot, ControllerType controllerType, size_t ejectTicks)
|
||||
{
|
||||
switch (controllerType)
|
||||
{
|
||||
case ControllerType::DualShock2:
|
||||
return std::make_unique<PadDualshock2>(unifiedSlot);
|
||||
s_controllers[unifiedSlot] = std::make_unique<PadDualshock2>(unifiedSlot, ejectTicks);
|
||||
break;
|
||||
case ControllerType::Guitar:
|
||||
return std::make_unique<PadGuitar>(unifiedSlot);
|
||||
s_controllers[unifiedSlot] = std::make_unique<PadGuitar>(unifiedSlot, ejectTicks);
|
||||
break;
|
||||
default:
|
||||
return std::make_unique<PadNotConnected>(unifiedSlot);
|
||||
s_controllers[unifiedSlot] = std::make_unique<PadNotConnected>(unifiedSlot, ejectTicks);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
PadBase* Pad::ChangePadType(u8 unifiedSlot, ControllerType controllerType)
|
||||
{
|
||||
s_controllers[unifiedSlot] = CreatePad(unifiedSlot, controllerType);
|
||||
return s_controllers[unifiedSlot].get();
|
||||
}
|
||||
|
||||
|
@ -532,7 +531,7 @@ bool Pad::Freeze(StateWrapper& sw)
|
|||
if (sw.HasError())
|
||||
return false;
|
||||
|
||||
std::unique_ptr<PadBase> tempPad;
|
||||
PadBase* tempPad;
|
||||
PadBase* pad = GetPad(unifiedSlot);
|
||||
if (!pad || pad->GetType() != type)
|
||||
{
|
||||
|
@ -551,7 +550,7 @@ bool Pad::Freeze(StateWrapper& sw)
|
|||
|
||||
// But we still need to pull the data from the state..
|
||||
tempPad = CreatePad(unifiedSlot, type);
|
||||
pad = tempPad.get();
|
||||
pad = tempPad;
|
||||
}
|
||||
|
||||
if (!pad->Freeze(sw))
|
||||
|
|
|
@ -144,9 +144,7 @@ void Sio2::SetRecv1(u32 value)
|
|||
|
||||
void Sio2::Pad()
|
||||
{
|
||||
MultitapProtocol& mtap = (port ? g_MultitapPort1 : g_MultitapPort0);
|
||||
|
||||
// Send PAD our current port, and get back whatever it says the first response byte should be.
|
||||
MultitapProtocol& mtap = g_MultitapArr.at(port);
|
||||
PadBase* pad = Pad::GetPad(port, mtap.GetPadSlot());
|
||||
|
||||
// Update the third nibble with which ports have been accessed
|
||||
|
@ -177,10 +175,9 @@ void Sio2::Pad()
|
|||
}
|
||||
|
||||
g_Sio2FifoOut.push_back(0xff);
|
||||
|
||||
// Then for every byte in g_Sio2FifoIn, pass to PAD and see what it kicks back to us.
|
||||
pad->SoftReset();
|
||||
|
||||
// Then for every byte in g_Sio2FifoIn, pass to PAD and see what it kicks back to us.
|
||||
while (!g_Sio2FifoIn.empty())
|
||||
{
|
||||
const u8 commandByte = g_Sio2FifoIn.front();
|
||||
|
@ -208,8 +205,8 @@ void Sio2::Multitap()
|
|||
// This bit is always set, whether the pad is present or missing
|
||||
this->recv1 |= Recv1::NO_DEVICES_MISSING;
|
||||
|
||||
// If the currently accessed pad is missing, also tick those bits.
|
||||
// MTAPMAN is special - at least, the variant found in Gauntlet: Dark Legacy.
|
||||
// If the currently accessed multitap is missing, also tick those bits.
|
||||
// MTAPMAN is special though.
|
||||
//
|
||||
// For PADMAN and pads, the bits represented by PORT_1_MISSING and PORT_2_MISSING
|
||||
// are always faithful - suppose your game only opened port 2 for some reason,
|
||||
|
@ -223,18 +220,7 @@ void Sio2::Multitap()
|
|||
this->recv1 |= Recv1::PORT_1_MISSING;
|
||||
}
|
||||
|
||||
switch (this->port)
|
||||
{
|
||||
case 0:
|
||||
g_MultitapPort0.SendToMultitap();
|
||||
break;
|
||||
case 1:
|
||||
g_MultitapPort1.SendToMultitap();
|
||||
break;
|
||||
default:
|
||||
Console.Warning("%s() Port value from SEND3 out of bounds! (%d)", __FUNCTION__, this->port);
|
||||
break;
|
||||
}
|
||||
g_MultitapArr.at(this->port).SendToMultitap();
|
||||
}
|
||||
|
||||
void Sio2::Infrared()
|
||||
|
@ -252,7 +238,7 @@ void Sio2::Infrared()
|
|||
|
||||
void Sio2::Memcard()
|
||||
{
|
||||
MultitapProtocol& mtap = (port ? g_MultitapPort1 : g_MultitapPort0);
|
||||
MultitapProtocol& mtap = g_MultitapArr.at(this->port);
|
||||
|
||||
mcd = &mcds[port][mtap.GetMemcardSlot()];
|
||||
|
||||
|
@ -511,7 +497,6 @@ bool Sio2::DoState(StateWrapper& sw)
|
|||
sw.Do(&unknown2);
|
||||
sw.Do(&iStat);
|
||||
sw.Do(&port);
|
||||
sw.Do(&slot);
|
||||
sw.Do(&send3Read);
|
||||
sw.Do(&send3Position);
|
||||
sw.Do(&commandLength);
|
||||
|
|
|
@ -40,7 +40,6 @@ public:
|
|||
u32 iStat; // 0x1f808280
|
||||
|
||||
u8 port = 0;
|
||||
u8 slot = 0;
|
||||
|
||||
// The current working index of SEND3. The SEND3 register is a 16 position
|
||||
// array of command descriptors. Each descriptor describes the port the command
|
||||
|
|
|
@ -33,6 +33,7 @@
|
|||
#include "R3000A.h"
|
||||
#include "SIO/Sio0.h"
|
||||
#include "SIO/Sio2.h"
|
||||
#include "SIO/Multitap/MultitapProtocol.h"
|
||||
#include "SPU2/spu2.h"
|
||||
#include "SaveState.h"
|
||||
#include "StateWrapper.h"
|
||||
|
@ -259,6 +260,9 @@ bool SaveStateBase::FreezeInternals()
|
|||
|
||||
okay = okay && g_Sio0.DoState(sw);
|
||||
okay = okay && g_Sio2.DoState(sw);
|
||||
okay = okay && g_MultitapArr.at(0).DoState(sw);
|
||||
okay = okay && g_MultitapArr.at(1).DoState(sw);
|
||||
|
||||
if (!okay || !sw.IsGood())
|
||||
return false;
|
||||
|
||||
|
|
|
@ -37,7 +37,7 @@ enum class FreezeAction
|
|||
// [SAVEVERSION+]
|
||||
// This informs the auto updater that the users savestates will be invalidated.
|
||||
|
||||
static const u32 g_SaveVersion = (0x9A48 << 16) | 0x0000;
|
||||
static const u32 g_SaveVersion = (0x9A49 << 16) | 0x0000;
|
||||
|
||||
|
||||
// the freezing data between submodules and core
|
||||
|
|
Loading…
Reference in New Issue