diff --git a/include/al/LiveActor.hpp b/include/al/LiveActor.hpp new file mode 100644 index 0000000..b2883f1 --- /dev/null +++ b/include/al/LiveActor.hpp @@ -0,0 +1,8 @@ +#pragma once + +namespace al +{ + class LiveActor { + + }; +} diff --git a/include/al/Scene.hpp b/include/al/Scene.hpp new file mode 100644 index 0000000..aef5d7f --- /dev/null +++ b/include/al/Scene.hpp @@ -0,0 +1,9 @@ +#pragma once + +namespace al +{ + class Scene + { + + }; +} diff --git a/include/al/util.hpp b/include/al/util.hpp new file mode 100644 index 0000000..5cc71bd --- /dev/null +++ b/include/al/util.hpp @@ -0,0 +1,12 @@ +#pragma once + +namespace al +{ + class LiveActor; +} + +namespace al +{ + bool isPadTriggerLeft(int port); + void setTransY(al::LiveActor *, float); +} diff --git a/include/game/StageScene.hpp b/include/game/StageScene.hpp new file mode 100644 index 0000000..8e00f7d --- /dev/null +++ b/include/game/StageScene.hpp @@ -0,0 +1,8 @@ +#pragma once + +#include "al/Scene.hpp" + +class StageScene : public al::Scene +{ + +}; diff --git a/include/rs/util.hpp b/include/rs/util.hpp new file mode 100644 index 0000000..672f4ad --- /dev/null +++ b/include/rs/util.hpp @@ -0,0 +1,13 @@ +#pragma once + + +namespace al +{ + class LiveActor; + class Scene; +} + +namespace rs +{ + al::LiveActor* getPlayerActor(const al::Scene *); +} diff --git a/source/main.cpp b/source/main.cpp index b5cc420..a94f07c 100644 --- a/source/main.cpp +++ b/source/main.cpp @@ -1,283 +1,55 @@ -#include "main.hpp" +#include "al/LiveActor.hpp" +#include "al/util.hpp" +#include "game/StageScene.hpp" +#include "rs/util.hpp" -// Needed on old versions of rtld that doesn't check for DT_INIT existance. -extern "C" void __custom_init(void) {} +void teleportMarioIfNeeded() { + // We replaced a `MOV X19, X0` instruction with the hook + // that calls this function; manually reimplement the + // now-missing instruction here + __asm ("MOV X19, X0"); -// DT_FINI here for completeness. -extern "C" void __custom_fini(void) {} + // A reference to the current `StageScene` is in the X0 register; + // read it into a local variable. + // + // Note: Because the `StageScene` reference is in X0, we could also + // just accept it as a parameter for this function, since that + // parameter would be expected to be passed in X0. Likewise, + // we could return `stageScene` at the end of this function to + // place it back in X0. + // + // However, that sort of interaction with the hooked code + // isn't semantically what's happening here; plus, the values you + // need might not always be in the argument registers; + // so I'd rather think of this as code that simply reads whatever + // state is necessary and restores registers at the end, rather + // than pretending it's a normal function call. + StageScene *stageScene; + __asm ("MOV %[result], X0" : [result] "=r" (stageScene)); -static __int64 lastInputs = 0x200; -static agl::DrawContext *mDrawContext; -static sead::TextWriter *mTextWriter; -static Lp::Sys::Ctrl *mController; -static Game::Player* mCurrentPlayer; -static int mode; -static bool showMenu; + // Check if Left D-Pad is pressed, using the default + // controller port (specified by `-1`) + if (al::isPadTriggerLeft(-1)) { -void render(agl::DrawContext *drawContext, sead::TextWriter *textWriter) -{ - mDrawContext = drawContext; - mTextWriter = textWriter; + // Get the current player actor. + // + // Note: The teleportation does not appear to affect captures, + // so this presumably always returns a reference to Mario + // rather than the currently-controlled actor. + al::LiveActor *player = rs::getPlayerActor(stageScene); - if(isTriggered(mController, Buttons::Minus1)) - showMenu = !showMenu; - - if(showMenu){ - drawBackground(); - - textWriter->setScaleFromFontHeight(20); - sead::TextWriter::setupGraphics(drawContext); // re-setup context - - textWriter->printf("Welcome to Starlight!\n"); - textWriter->printf("This is a demonstration of C/C++ code running in the context of a Switch game!\n"); - textWriter->printf("Credit to shibboleet, Khangaroo, Thog, Retr0id, and the libnx maintainers!\n"); - - textWriter->printf("Current scene name: %s\n", Lp::Utl::getCurSceneName()); - - if(isTriggered(mController, Buttons::RStick)) - mode++; - if(mode > Modes::END) - mode = 0; - textWriter->printf("Current mode: %s\n", modeToText((Modes)mode)); - - Cmn::StaticMem *staticMem = Cmn::StaticMem::sInstance; - if(staticMem != NULL) - handleStaticMem(staticMem); - - Game::PlayerMgr *playerMgr = Game::PlayerMgr::sInstance; - if(playerMgr != NULL) - handlePlayerMgr(playerMgr); - - Cmn::PlayerCtrl *playerCtrl = Cmn::PlayerCtrl::sInstance; - if(playerCtrl != NULL) - handlePlayerControl(playerCtrl); - else if(mode == Modes::INPUT_VIEWER){ - mTextWriter->printf("Information not available.\n"); - } - - Cmn::MushDataHolder* mushData = Cmn::MushDataHolder::sInstance; - if(mushData != NULL) - handleMushDataHolder(mushData); - - Game::MainMgr* mainMgr = Game::MainMgr::sInstance; - if(mainMgr != NULL){ - handleMainMgr(mainMgr); - } - + // Set the player's vertical translation. + // + // Note: Collision is still a factor here, and this will + // not teleport Mario through walls. + // + // If you see no change, try triggering the teleportation + // during a jump; you may have been seeing no movement on + // the ground because the y=0 plane is below you in the current area. + al::setTransY(player, 0.0); } - lastInputs = mController->data; - //sead::HeapMgr::sInstance->setCurrentHeap_(NULL); + + // Restore original state by placing + // `stageScene` back into the X0 register + __asm ("MOV X0, %[input]" : [input] "=r" (stageScene)); } - -void drawBackground(){ - sead::Vector3 p1; // top left - p1.mX = -1.0; - p1.mY = 1.0; - p1.mZ = 0.0; - sead::Vector3 p2; // top right - p2.mX = 0.0; - p2.mY = 1.0; - p2.mZ = 0.0; - sead::Vector3 p3; // bottom left - p3.mX = -1.0; - p3.mY = -1.0; - p3.mZ = 0.0; - sead::Vector3 p4; // bottom right - p4.mX = 0.0; - p4.mY = -1.0; - p4.mZ = 0.0; - - sead::Color4f c; - c.r = 1.0; - c.g = 1.0; - c.b = 1.0; - c.a = 0.5; - - agl::utl::DevTools::beginDrawImm(mDrawContext, sead::Matrix34::ident, sead::Matrix44::ident); - agl::utl::DevTools::drawTriangleImm(mDrawContext, p1, p2, p3, c); - agl::utl::DevTools::drawTriangleImm(mDrawContext, p3, p4, p2, c); -} - -void handleStaticMem(Cmn::StaticMem *staticMem){ - sead::SafeStringBase *stageName = &staticMem->mMapFileName1; - if(stageName->mCharPtr != NULL){ - mTextWriter->printf("Loaded stage: %s\n", stageName->mCharPtr); - } - - Cmn::PlayerInfoAry *playerInfoAry = staticMem->mPlayerInfoAry; - if(playerInfoAry != NULL){ - mTextWriter->printf("PlayerInfoAry ptr: 0x%x\n", playerInfoAry); - } -} - -void handlePlayerMgr(Game::PlayerMgr* playerMgr){ - Game::Player* player = playerMgr->getControlledPerformer(); - - Cmn::PlayerInfo* info = player->mPlayerInfo; - if(info != NULL){ - mTextWriter->printf("Controlled player team: %x\n", info->mTeam); - mTextWriter->printf(u"Controlled player name: %s\n", info->mPlayerName); - if(info->mPlayerIndex == 0){ - info->setPlayerName(u"Shadów"); - } - } - - Game::PlayerMotion *playerMotion = player->mPlayerMotion; - - if(mode == Modes::EVENT_VIEWER) { - static long scroll = 0; - - if(isTriggered(mController, Buttons::UpDpad)) - scroll++; - if(isTriggered(mController, Buttons::DownDpad)) - scroll--; - - if(isTriggered(mController, Buttons::LeftDpad)) - scroll-=0x10; - if(isTriggered(mController, Buttons::RightDpad)) - scroll+=0x10; - - if(scroll < 0) - scroll = 0; - - mTextWriter->printf("Event ID: 0x%x\n", scroll); - - if(isTriggered(mController, Buttons::LStick)) - playerMotion->startEventAnim((Game::PlayerMotion::AnimID) scroll, 0, 1.0); - - } else if(mode == Modes::PLAYER_SWITCHER){ - - signed int currentPlayer = playerMgr->mCurrentPlayerIndex; - mTextWriter->printf("Current player: %i\n", currentPlayer); - - if(isTriggered(mController, Buttons::UpDpad)) - currentPlayer++; - if(isTriggered(mController, Buttons::DownDpad)) - currentPlayer--; - if(currentPlayer < 0) - currentPlayer = playerMgr->mTotalPlayerArry.mBufferSize; - if(playerMgr->mTotalPlayerArry.mBufferSize <= currentPlayer) - currentPlayer = 0; - - playerMgr->mCurrentPlayerIndex = currentPlayer; - playerMgr->onChangeControlledPlayer(); - } -} - -void handlePlayerControl(Cmn::PlayerCtrl* playerCtrl){ - Game::PlayerGamePadData::FrameInput input; - input.record(); // grab input data - - if(mode == Modes::INPUT_VIEWER){ - mTextWriter->printf("Left stick | x: %f | y: %f\n", input.leftStick.mX, input.leftStick.mY); - mTextWriter->printf("Right stick | x: %f | y: %f\n", input.rightStick.mX, input.rightStick.mY); - mTextWriter->printf("Angle vel | x: %f | y: %f | z: %f\n", input.angleVel.mX, input.angleVel.mY, input.angleVel.mZ); - mTextWriter->printf("Posture x | x: %f | y: %f | z: %f\n", input.postureX.mX, input.postureX.mY, input.postureX.mZ); - mTextWriter->printf("Posture y | x: %f | y: %f | z: %f\n", input.postureY.mX, input.postureY.mY, input.postureY.mZ); - mTextWriter->printf("Posture z | x: %f | y: %f | z: %f\n", input.postureZ.mX, input.postureZ.mY, input.postureZ.mZ); - } - - static bool entered = false; - if(mode == 1 && mCurrentPlayer != NULL){ - static float x, y, z; - sead::Vector3 *playerPos = &mCurrentPlayer->mPosition; - if(!entered){ - x = playerPos->mX; - y = playerPos->mY; - z = playerPos->mZ; - } - - int speed = 10; - - if(mController->data & Buttons::UpDpad) - y+=speed; - if(mController->data & Buttons::DownDpad) - y-=speed; - if(mController->data & Buttons::LeftDpad) - x+=speed; - if(mController->data & Buttons::RightDpad) - x-=speed; - if(mController->data & Buttons::RightRStickOrdinal) - z+=speed; - if(mController->data & Buttons::LeftRStickOrdinal) - z-=speed; - - playerPos->mX = x; - playerPos->mY = y; - playerPos->mZ = z; - entered = true; - } else { - entered = false; - } -} - -void handleMushDataHolder(Cmn::MushDataHolder* mushDataHolder){ - static bool entered = false; - - if(!entered){ - for(int i = 0; i < 29001; i++){ - Cmn::WeaponData* data = mushDataHolder->mMushWeaponInfo->getById(Cmn::Def::WeaponKind::cMain, i); - if(data != NULL){ - data->mPrice = 0; - data->mRank = 0; - data->mSpecialCost = 0; - data->mLockType = Cmn::WeaponData::LockType::None; - } - } - - for(int i = 0; i < 230; i++){ - Cmn::MushMapInfo::Data* mapData = mushDataHolder->mMushMapInfo->getByMushOrder(i); - if(strcmp(mapData->mStr1.mCharPtr, "Fld_Plaza00_Plz") != 0) // plaza crashes when using night mode for whatever reason - if(mapData != NULL){ - mapData->mEnvHour = 2; - } - } - - entered = true; - } -} - -void handleMainMgr(Game::MainMgr* mainMgr) { - Game::GfxMgr* gfxMgr = mainMgr->gfxMgr; - if(gfxMgr != NULL){ - gfxMgr->hour = 2; - } - if(mode == Modes::PAINT_ALL){ - if(isTriggered(mController, Buttons::LStick)){ - unsigned int paintGameFrame = mainMgr->getPaintGameFrame(); - Cmn::Def::Team team = Cmn::Def::Team::Alpha; - if(Cmn::StaticMem::sInstance != NULL) - team = Cmn::StaticMem::sInstance->mTeam; - Game::PaintUtl::requestAllPaintFloor(paintGameFrame, team); - Game::PaintUtl::requestAllPaintWall(paintGameFrame, team); - } - } -} - -bool isTriggered(Lp::Sys::Ctrl *controller, unsigned long id){ - bool buttonHeld = controller->data & id; - return buttonHeld & !(controller->data & lastInputs & id); -} - -char const* modeToText(Modes mode){ - switch(mode){ - case Modes::NONE: - return "None"; - case Modes::FLY: - return "Fly"; - case Modes::EVENT_VIEWER: - return "Event viewer"; - case Modes::INPUT_VIEWER: - return "Gyro/stick input viewer"; - case Modes::PLAYER_SWITCHER: - return "Player switcher"; - case Modes::PAINT_ALL: - return "Paint all"; - default: - return "None"; - } -} - -int main(int arg, char **argv){ - -} \ No newline at end of file