fix: crashes related to Keyboard in FreezeTagConfigMenu

In some kingdoms (e.g. in Sand, but not in Cascade) it always/sometimes crashed the game when closing the keyboard.

I assume that's because the Keyboard was on the SceneHeap which it shouldn't.
At least moving it to the game mode heap fixed it.

But then there was a memory leak that the game mode heap growed everytime the scene was reloaded.
That was because of some never freed memory in the Keyboard class.
I tried to implement destructors for `StageSceneStateServerConfig` and `FreezeTagConfigMenu` but that also crashed.
So I added new `clean()` methods instead.
This commit is contained in:
Robin C. Ladiges 2024-10-29 02:50:07 +01:00
parent 7fa8c659e1
commit be50d034f8
No known key found for this signature in database
GPG key ID: B494D3DF92661B99
8 changed files with 42 additions and 17 deletions

View file

@ -9,6 +9,7 @@ typedef void (*KeyboardSetup)(nn::swkbd::KeyboardConfig&);
class Keyboard {
public:
Keyboard(ulong strSize);
~Keyboard();
void keyboardThread();
void openKeyboard(const char* initialText, KeyboardSetup setup);

View file

@ -41,6 +41,7 @@ class StageSceneStateServerConfig : public al::HostStateBase<al::Scene>, public
virtual void appear(void) override;
virtual void kill(void) override;
void clean();
void exeMainMenu();
void exeOpenKeyboardIP();
void exeOpenKeyboardPort();

View file

@ -9,6 +9,8 @@ class FreezeTagConfigMenu : public GameModeConfigMenu {
public:
FreezeTagConfigMenu();
void clean() override;
const sead::WFixedSafeString<0x200>* getStringData() override;
GameModeConfigMenu::UpdateAction updateMenu(int selectIndex) override;
@ -17,6 +19,5 @@ class FreezeTagConfigMenu : public GameModeConfigMenu {
private:
static constexpr int mItemCount = 8;
sead::SafeArray<sead::WFixedSafeString<0x200>, mItemCount>* mItems = nullptr;
Keyboard* mScoreKeyboard;
Keyboard* mRoundKeyboard;
Keyboard* mKeyboard;
};

View file

@ -12,6 +12,8 @@ public:
GameModeConfigMenu() = default;
virtual void clean() {}
virtual UpdateAction updateMenu(int selectIndex) { return UpdateAction::NOOP; }
virtual const sead::WFixedSafeString<0x200>* getStringData() { return nullptr; }

View file

@ -20,7 +20,13 @@ Keyboard::Keyboard(ulong strSize) : mResultString(strSize) {
mCustomizeDicSize = 0x400;
mCustomizeDicBuf = (char*)malloc(mCustomizeDicSize);
}
Keyboard::~Keyboard() {
delete mThread;
free(mWorkBuf);
free(mTextCheckBuf);
free(mCustomizeDicBuf);
}
void Keyboard::keyboardThread() {
@ -48,7 +54,6 @@ void Keyboard::keyboardThread() {
}
void Keyboard::openKeyboard(const char* initialText, KeyboardSetup setupFunc) {
mInitialText = initialText;
mSetupFunc = setupFunc;

View file

@ -119,6 +119,7 @@ void initStateHook(
) {
thisPtr->mStateOption = new StageSceneStateOption(stateName, host, initInfo, footer, data, unkBool);
if (sceneStateServerConfig) { sceneStateServerConfig->clean(); }
sceneStateServerConfig = new StageSceneStateServerConfig("ServerConfig", host, initInfo, footer, data, unkBool);
}

View file

@ -1,6 +1,10 @@
#include "server/freeze-tag/FreezeTagConfigMenu.hpp"
#include <cmath>
#include <stdint.h>
#include "sead/basis/seadNew.h"
#include "sead/heap/seadHeap.h"
#include "server/gamemode/GameModeManager.hpp"
#include "nn/util.h"
FreezeTagConfigMenu::FreezeTagConfigMenu() : GameModeConfigMenu() {
@ -14,13 +18,12 @@ FreezeTagConfigMenu::FreezeTagConfigMenu() : GameModeConfigMenu() {
mItems->mBuffer[6].copy(u"Cappy Collision (ON) ");
mItems->mBuffer[7].copy(u"Cappy Bounce (OFF) ");
mScoreKeyboard = new Keyboard(6);
mScoreKeyboard->setHeaderText(u"Set your Freeze Tag score");
mScoreKeyboard->setSubText(u"");
sead::Heap* heap = GameModeManager::instance()->getHeap();
mKeyboard = new (heap) Keyboard(6);
}
mRoundKeyboard = new Keyboard(3);
mRoundKeyboard->setHeaderText(u"Set length of rounds you start in minutes");
mRoundKeyboard->setSubText(u"This will be automatically sent to other players (2-60 minutes)");
void FreezeTagConfigMenu::clean() {
delete mKeyboard;
}
const sead::WFixedSafeString<0x200>* FreezeTagConfigMenu::getStringData() {
@ -92,7 +95,9 @@ GameModeConfigMenu::UpdateAction FreezeTagConfigMenu::updateMenu(int selectIndex
char buf[5];
nn::util::SNPrintf(buf, 5, "%u", oldScore);
mScoreKeyboard->openKeyboard(
mKeyboard->setHeaderText(u"Set your Freeze Tag score");
mKeyboard->setSubText(u"");
mKeyboard->openKeyboard(
buf,
[](nn::swkbd::KeyboardConfig& config) {
config.keyboardMode = nn::swkbd::KeyboardMode::ModeNumeric;
@ -103,12 +108,12 @@ GameModeConfigMenu::UpdateAction FreezeTagConfigMenu::updateMenu(int selectIndex
}
);
while (!mScoreKeyboard->isThreadDone()) {
while (!mKeyboard->isThreadDone()) {
nn::os::YieldThread(); // allow other threads to run
}
if (!mScoreKeyboard->isKeyboardCancelled()) {
newScore = ::atoi(mScoreKeyboard->getResult());
if (!mKeyboard->isKeyboardCancelled()) {
newScore = std::atoi(mKeyboard->getResult());
}
if (newScore != uint16_t(-1)) {
@ -128,7 +133,9 @@ GameModeConfigMenu::UpdateAction FreezeTagConfigMenu::updateMenu(int selectIndex
char buf[3];
nn::util::SNPrintf(buf, 3, "%u", oldTime);
mRoundKeyboard->openKeyboard(
mKeyboard->setHeaderText(u"Set length of rounds you start in minutes");
mKeyboard->setSubText(u"This will be automatically sent to other players (2-60 minutes)");
mKeyboard->openKeyboard(
buf,
[](nn::swkbd::KeyboardConfig& config) {
config.keyboardMode = nn::swkbd::KeyboardMode::ModeNumeric;
@ -139,17 +146,18 @@ GameModeConfigMenu::UpdateAction FreezeTagConfigMenu::updateMenu(int selectIndex
}
);
while (!mRoundKeyboard->isThreadDone()) {
while (!mKeyboard->isThreadDone()) {
nn::os::YieldThread(); // allow other threads to run
}
if (!mRoundKeyboard->isKeyboardCancelled()) {
newTime = ::atoi(mRoundKeyboard->getResult());
if (!mKeyboard->isKeyboardCancelled()) {
newTime = std::atoi(mKeyboard->getResult());
}
if (newTime != uint8_t(-1)) {
FreezeTagInfo::mRoundLength = al::clamp(newTime, u8(2), u8(60));
}
return UpdateAction::NOOP;
}
case 4: {

View file

@ -139,6 +139,12 @@ al::MessageSystem* StageSceneStateServerConfig::getMessageSystem(void) const {
return mMsgSystem;
}
void StageSceneStateServerConfig::clean() {
for (int mode = 0; mode < GameModeFactory::getModeCount() - 1; mode++) {
mGamemodeConfigMenus[mode].mMenu->clean();
}
}
void StageSceneStateServerConfig::exeMainMenu() {
if (al::isFirstStep(this)) {
activateInput();