| 552 | } |
| 553 | |
| 554 | bool Pad::Freeze(StateWrapper& sw) |
| 555 | { |
| 556 | if (sw.IsReading()) |
| 557 | { |
| 558 | if (!sw.DoMarker("PAD")) |
| 559 | { |
| 560 | Console.Error("PAD state is invalid! Leaving the current state in place."); |
| 561 | return false; |
| 562 | } |
| 563 | |
| 564 | for (u32 unifiedSlot = 0; unifiedSlot < NUM_CONTROLLER_PORTS; unifiedSlot++) |
| 565 | { |
| 566 | PadBase* currentPad = GetPad(unifiedSlot); |
| 567 | ControllerType statePadType; |
| 568 | |
| 569 | sw.Do(&statePadType); |
| 570 | |
| 571 | if (sw.HasError()) |
| 572 | return false; |
| 573 | |
| 574 | if (!currentPad) |
| 575 | { |
| 576 | pxAssertMsg(false, fmt::format("Pad::Freeze (on read) Existing Pad {0} was nullptr", unifiedSlot).c_str()); |
| 577 | } |
| 578 | // If the currently configured pad is of a different type than the pad which was used during the savestate... |
| 579 | else if (currentPad->GetType() != statePadType) |
| 580 | { |
| 581 | const ControllerType currentPadType = currentPad->GetType(); |
| 582 | |
| 583 | const auto& [port, slot] = sioConvertPadToPortAndSlot(unifiedSlot); |
| 584 | Host::AddIconOSDMessage(fmt::format("UnfreezePad{}Changed", unifiedSlot), ICON_FA_GAMEPAD, |
| 585 | //: {0} and {1} are the port and multitap slot, {2} and {3} are controller types (e.g. "DualShock 2", "Jogcon") |
| 586 | fmt::format(TRANSLATE_FS("Pad", |
| 587 | "Controller port {0}, slot {1} has a {2} connected, but the save state has a " |
| 588 | "{3}.\nEjecting {2} and replacing it with {3}."), |
| 589 | port, slot, |
| 590 | GetControllerTypeName(currentPad ? currentPad->GetType() : Pad::ControllerType::NotConnected), |
| 591 | GetControllerTypeName(statePadType))); |
| 592 | |
| 593 | // Run the freeze, using a new pad instance of the old type just so we make sure all those attributes |
| 594 | // from the state are read out and we aren't going to run into some sort of consistency problem. |
| 595 | currentPad = CreatePad(unifiedSlot, statePadType); |
| 596 | |
| 597 | if (currentPad) |
| 598 | { |
| 599 | currentPad->Freeze(sw); |
| 600 | |
| 601 | // Now immediately discard whatever malformed pad state we just created, and replace it with a fresh pad loaded |
| 602 | // using whatever the current user settings are. Savestates are, by definition, never going to occur in the middle |
| 603 | // of a transfer between SIO2 and the peripheral, since they aren't captured until the VM is at a point where everything |
| 604 | // is "stoppable". For all intents and purposes, by the time a savestate is captured, the IOP is "done" and there is no |
| 605 | // "pending work" left hanging in SIO2 or the pads. So there is nothing actually lost from just throwing the pad away and making a new one here. |
| 606 | currentPad = CreatePad(unifiedSlot, currentPadType, Pad::DEFAULT_EJECT_TICKS); |
| 607 | } |
| 608 | else |
| 609 | { |
| 610 | pxAssertMsg(false, fmt::format("Pad::Freeze (on read) State Pad {0} was nullptr", unifiedSlot).c_str()); |
| 611 | } |