Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions src/SM/ch/attacktutorial.c
Original file line number Diff line number Diff line change
Expand Up @@ -137,6 +137,8 @@ static bool __chAttackTutorial_areLearnableAbilitiesUnlocked() {
}

// [port] A local tutorial opt-out unlocks every move mid-session; re-arm the spawn latch.
bool func_802E4A08(void); // non-interactive demo/playback modes

void chAttackTutorial_onTutorialSkipped(void) {
Actor *tutorial = actorArray_findActorFromActorId(ACTOR_167_ATTACK_TUTORIAL);
if (tutorial != NULL) {
Expand Down Expand Up @@ -175,8 +177,9 @@ static void __chAttackTutorial_update(Actor *this) {
case CH_ATTACK_TUTORIAL_STATE_1_UNKNOWN:
if (mapSpecificFlags_get(SM_SPECIFIC_FLAG_4))
__chAttackTutorial_setState(this, CH_ATTACK_TUTORIAL_STATE_5_SHOW_LEARN_MOVE_DIALOG);

if (this->movesKnownAtSpawn || volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE))
if (this->movesKnownAtSpawn
|| (func_802E4A08() && __chAttackTutorial_areLearnableAbilitiesUnlocked())
|| volatileFlag_get(VOLATILE_FLAG_C1_IN_FINAL_CHARACTER_PARADE))
__chAttackTutorial_setState(this, CH_ATTACK_TUTORIAL_STATE_4_TUTORIAL_COMPLETED);
break;

Expand Down
8 changes: 1 addition & 7 deletions src/core1/display_list.c
Original file line number Diff line number Diff line change
Expand Up @@ -84,13 +84,7 @@ void setupFramebuffer(Gfx **gfx, void *color_buffer) {
void setupFramebufferForGamemode(Gfx **gdl, s32 framebuffer_idx) {
if(getGameMode() == GAME_MODE_8_BOTTLES_BONUS || getGameMode() == GAME_MODE_A_SNS_PICTURE)
{
// [port] Redirect rendering to GPU-side aux FB via gsSPSetFB.
// On N64, gDPSetColorImage pointed to D_80382450 (CPU buffer).
// gsSPResetFB is emitted in func_802E39D0 after the scene draw.
s32 auxFb = port_getAuxGpuFbId();
if (auxFb >= 0) {
gsSPSetFB((*gdl)++, auxFb);
}
EventSystem_Should(VB_PICTUREBOX_TARGET_FB, true, gdl);
picturebox_setScissorBox();
setupFramebuffer(gdl, picturebox_getColorBuffer());
}
Expand Down
7 changes: 2 additions & 5 deletions src/core1/vimgr.c
Original file line number Diff line number Diff line change
Expand Up @@ -174,13 +174,10 @@ void viMgr_func_8024BFAC(void){

void viMgr_func_8024BFD8(s32 arg0){
// [port] Set D_80280724 to the actual VI count so time_func_8033DDB8() returns
// the correct delta for demo/playback zoomboxes. On N64 this was set from the
// VI wait loop counter which reflected real rendering time (including lag).
// During demo playback, sDemoViCount includes the N64's original rendering lag
// for maps that ran slow, which the zoombox dialog system needs to pace text.
// the correct delta for demo/playback zoomboxes.
s32 demoVi = port_getDemoViCount();
static s32 D_80280E90;
s32 viBudget = (!func_802E4A08() && demoVi > 2) ? demoVi : 2;
s32 viBudget = (demoVi > 2) ? demoVi : 2;

osSetThreadPri(NULL, 0x7f);
defragManager_setPriority(DEFRAGMANAGER_THREAD_PRIORITY_HIGH);
Expand Down
7 changes: 5 additions & 2 deletions src/core2/demo.c
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,11 @@ s32 func_80349EC0(s32 arg0){
}

int demo_readInput(OSContPad* arg0, s32* arg1){
int not_eof = D_803860D8 < D_803860DC;
DemoInput *input_ptr = not_eof ? &D_803860D0[D_803860D8++] : &D_80371EF0;
s32 idx = D_803860D8;
int not_eof = (idx + 1) < D_803860DC;
DemoInput *input_ptr = not_eof ? &D_803860D0[idx] : &D_80371EF0;
if (idx < D_803860DC)
D_803860D8 = idx + 1;
#if 0
DemoInput *input_ptr = &D_803860D0[D_803860D8++];
int not_eof = D_803860D8 < D_803860DC;
Expand Down
19 changes: 0 additions & 19 deletions src/core2/frame/auxbuffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -4,27 +4,11 @@
#include "functions.h"
#include "variables.h"

// [port] GPU-side aux framebuffer for the picture box
int gfx_create_framebuffer(unsigned int width, unsigned int height, unsigned int native_width,
unsigned int native_height, unsigned char resize, bool force_fixed_aspect);

#include "port/Patches/Patches.h"

s32 sAuxGpuFbId = -1;

// [port] Renderer call; runs on the render thread under thread5 mode.
static void __auxbuffer_createGpuFb(void* arg);

#define TILE_SIZE 32
#define TILE_COUNT_X 5
#define TILE_COUNT_Y 4
#define IMAGE_WIDTH (TILE_SIZE * TILE_COUNT_X)
#define IMAGE_HEIGHT (TILE_SIZE * TILE_COUNT_Y)

static void __auxbuffer_createGpuFb(void* arg) {
(void)arg;
sAuxGpuFbId = gfx_create_framebuffer(IMAGE_WIDTH, IMAGE_HEIGHT, IMAGE_WIDTH, IMAGE_HEIGHT, 0, 0);
}
#define SCREEN_WIDTH 292
#define SCREEN_HEIGHT 216
#define HORIZONTAL_MARGIN (((SCREEN_WIDTH) - IMAGE_WIDTH) / 2)
Expand Down Expand Up @@ -72,9 +56,6 @@ void picturebox_init(void) {
sPictureBoxColorBuffer++;
}
}
if (sAuxGpuFbId < 0) {
port_runOnRenderThread(__auxbuffer_createGpuFb, NULL);
}
}

void picturebox_free(void) {
Expand Down
9 changes: 7 additions & 2 deletions src/core2/gameloop.c
Original file line number Diff line number Diff line change
Expand Up @@ -288,6 +288,7 @@ void func_802E3E7C(enum game_mode_e mode){
s32 sp28;
s32 prev_mode;
s32 prev_map;
s32 outgoing_mode = D_8037E8E0.game_mode; // [port] game_setMode below overwrites it

core1_15B30_sendMesg3ToRenderThread();
sp34 = D_8037E8E0.unk18;
Expand All @@ -297,13 +298,16 @@ void func_802E3E7C(enum game_mode_e mode){
prev_mode = D_8037E8E0.unk0;
game_setMode(GAME_MODE_2_UNKNOWN, 0);
if(!volatileFlag_getAndSet(VOLATILE_FLAG_21, 0) || map_getLevel(gsworld_getMap()) == map_getLevel(D_8037E8E0.map)){
if(!volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE))
if(!volatileFlag_get(VOLATILE_FLAG_1F_IN_CHARACTER_PARADE)
&& EventSystem_Should(VB_MAP_SAVESTATE_USE, true, outgoing_mode))
mapSavestate_save(gsworld_getMap());
}
func_802E398C(1);
prev_map = gsworld_getMap();
func_802E38E8(map, sp28, sp34);
mapSavestate_apply(map);
if(EventSystem_Should(VB_MAP_SAVESTATE_USE, true, mode)){
mapSavestate_apply(map);
}
D_8037E8E0.unk0 = prev_mode;
game_setMode(mode, sp30);
jiggylist_map_actors();
Expand Down Expand Up @@ -557,6 +561,7 @@ bool func_802E4424(void) {
return false;

case 7: /* switch 1 */
port_beginDemoAudioHold();
func_8034B8C0(D_8037E8E0.map, D_8037E8E0.exit);
func_802E3E7C(GAME_MODE_8_BOTTLES_BONUS);
return false;
Expand Down
7 changes: 6 additions & 1 deletion src/core2/gamestate.c
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,12 @@ bool func_80347A4C(void);
/* .code */
void func_80345EB0(enum item_e item){
if(func_802FAFE8(item)){
item_adjustByDiffWithHud(item, (s32)(-time_getDelta()*(float)(FRAMERATE) * 1.1));
// [port] Pin the Bottles Bonus hourglass for timer consistency
f32 dt = time_getDelta();
if(item == ITEM_0_HOURGLASS_TIMER && getGameMode() == GAME_MODE_8_BOTTLES_BONUS){
dt = 1.0f / 30.0f;
}
item_adjustByDiffWithHud(item, (s32)(-dt*(float)(FRAMERATE) * 1.1));
}else{
code_73640_printItemCount(item);
}
Expand Down
1 change: 0 additions & 1 deletion src/core2/gc/pictureframe.c
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ Actor *func_802DF160(Gfx **gfx, Mtx **mtx, Vtx **vtx) {
sp38 = picturebox_getColorBuffer();
modelRender_setDepthMode(MODEL_RENDER_DEPTH_FULL);
gDPSetTextureFilter((*gfx)++, G_TF_BILERP);
port_readAuxFbToCpu(gfx);
gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp38));
modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)actor_predrawMethod, (void *)this);
modelRender_setPostDrawCallback((model_render_post_draw_callback_f)actor_postdrawMethod, (void *)D_8037E000);
Expand Down
19 changes: 13 additions & 6 deletions src/core2/gc/zoombox.c
Original file line number Diff line number Diff line change
Expand Up @@ -614,7 +614,9 @@ void func_8031594C(GcZoombox * this, u8 *str, s32 arg2, s32 arg3){
s1 = 0;
f22 = (this->portrait_id == ZOOMBOX_SPRITE_5F_TOOTY_4) ? 0.4 : 0.8;

if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){
// [port] The zoombox draws from the shared gameplay RNG, and these two calls are a
// save/restore of the whole state around that.
if(func_802E4A08()){
sfx_rand_sync_to_rand();
}
for(s2 = arg2; s2 <= arg3; s2++){
Expand Down Expand Up @@ -667,7 +669,7 @@ void func_8031594C(GcZoombox * this, u8 *str, s32 arg2, s32 arg3){
}//L80315B6C
this->unk189 = s1;
this->unk187 = 0;
if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){
if(func_802E4A08()){
rand_sync_to_sfx_rand();
}
}
Expand Down Expand Up @@ -995,7 +997,7 @@ void gczoombox_draw(GcZoombox *this, Gfx **gdl, Mtx ** mptr, void *vptr){
if(!this)
return;

if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE)
if(func_802E4A08())
sfx_rand_sync_to_rand();
//L80316BCC
// [port] Stable scope. The crossfade branch below toggles 1↔2 sprite
Expand Down Expand Up @@ -1046,7 +1048,7 @@ void gczoombox_draw(GcZoombox *this, Gfx **gdl, Mtx ** mptr, void *vptr){
}
}//L80316DD8
FrameInterpolation_RecordCloseChild();
if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){
if(func_802E4A08()){
rand_sync_to_sfx_rand();
}

Expand Down Expand Up @@ -1401,9 +1403,14 @@ void __gczoombox_load_sfx(GcZoombox *this, GcZoomboxSprite portrait_id){
}
//L80317E48
}
// [port] Balanced bracket. Vanilla restores below without a matching save,
// which rewinds the shared stream to whenever the last snapshot was taken;
// taking one here means the restore only undoes this randi2.
if(func_802E4A08()){
sfx_rand_sync_to_rand();
}
this->prev_sfx = randi2(0,this->sfx_count);
// [port] This mode needs a rand sync like many other places
if(getGameMode() == GAME_MODE_9_BANJO_AND_KAZOOIE){
if(func_802E4A08()){
rand_sync_to_sfx_rand();
}
}
Expand Down
1 change: 0 additions & 1 deletion src/core2/mumboshandwithpicture.c
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,6 @@ Actor *chMumbosHandWithPicture_draw(ActorMarker *marker, Gfx **gfx, Mtx **mtx, V
modelRender_draw(gfx, mtx, sp58, NULL, 1.0f, sp4C, D_8037DFE8);
gDPSetColorDither((*gfx)++, G_CD_DISABLE);
depthbuffer_clear(gfx);
port_readAuxFbToCpu(gfx);
gDPSetTextureFilter((*gfx)++, G_TF_BILERP);
gSPSegment((*gfx)++, 0x04, osVirtualToPhysical(sp48));
modelRender_setPreDrawCallback((model_render_pre_draw_callback_f)actor_predrawMethod, (void *)this);
Expand Down
60 changes: 17 additions & 43 deletions src/port/Controller/ControlSchemes.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -31,6 +31,7 @@ extern "C" {
#include "enums.h"
int bs_getState(void);
int bsbtrot_inSet(int state); // nonzero if `state` is one of the Talon Trot states
s32 getGameMode(void);
}

using namespace Ship;
Expand Down Expand Up @@ -130,6 +131,8 @@ void ControlSchemes_Apply(int scheme) {
ClearButtonSDL(controller, BTN_CUP);
BindButton(controller, BTN_CUP, SDL_CONTROLLER_BUTTON_Y);
BindButton(controller, BTN_CDOWN, SDL_CONTROLLER_BUTTON_B);
BindAxisToButton(controller, BTN_CLEFT, SDL_CONTROLLER_AXIS_RIGHTX, -1);
BindAxisToButton(controller, BTN_CRIGHT, SDL_CONTROLLER_AXIS_RIGHTX, 1);

// Recenter camera
ClearButtonSDL(controller, BTN_R);
Expand Down Expand Up @@ -228,50 +231,21 @@ extern "C" void port_shapeControllerInput(void* contPad) {
pad->button &= ~BTN_CDOWN;
}

// Read the raw right stick straight from SDL
int32_t sdlX = 0;
int32_t sdlY = 0;
{
auto ctx = Ship::Context::GetRawInstance();
auto controlDeck = ctx != nullptr ? ctx->GetControlDeck() : nullptr;
auto deviceManager = controlDeck != nullptr ? controlDeck->GetConnectedPhysicalDeviceManager() : nullptr;
if (deviceManager != nullptr) {
for (auto& [instanceId, gamepad] : deviceManager->GetConnectedSDLGamepadsForPort(0)) {
if (gamepad == nullptr) {
continue;
}
int32_t x = SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_RIGHTX);
int32_t y = SDL_GameControllerGetAxis(gamepad, SDL_CONTROLLER_AXIS_RIGHTY);
if ((x < 0 ? -x : x) > (sdlX < 0 ? -sdlX : sdlX)) {
sdlX = x;
}
if ((y < 0 ? -y : y) > (sdlY < 0 ? -sdlY : sdlY)) {
sdlY = y;
}
}
const s32 mode = getGameMode();
const bool picturePuzzle = (mode == GAME_MODE_8_BOTTLES_BONUS || mode == GAME_MODE_A_SNS_PICTURE);
if (!picturePuzzle) {
const uint16_t stickC = pad->button & (BTN_CLEFT | BTN_CRIGHT);
uint16_t allow = 0;

// One action per push, so holding the stick cannot repeat Wonderwing.
static bool sStickArmed = true;
if (stickC == 0) {
sStickArmed = true;
} else if (crouched && (stickC & BTN_CRIGHT) && arx >= ary && sStickArmed) {
allow = BTN_CRIGHT;
sStickArmed = false;
}
}
int32_t asx = (sdlX < 0) ? -sdlX : sdlX;
int32_t asy = (sdlY < 0) ? -sdlY : sdlY;

// Edge press with hysteresis
static bool sStickArmed = true;
const int32_t onThreshold = 12000;
const int32_t offThreshold = 6000;

// Standing, the camera owns the right stick
// Crouched, it yields one action
uint16_t want = 0;
if (crouched && sdlX > onThreshold && asx >= asy) {
want = BTN_CRIGHT; // stick-right -> Wonderwing
}

if (want != 0 && sStickArmed) {
pad->button |= want;
sStickArmed = false;
}
if ((crouched ? asx : asy) < offThreshold) {
sStickArmed = true;
pad->button = (pad->button & ~(BTN_CLEFT | BTN_CRIGHT)) | allow;
}
} else {
uint16_t axisMask = 0;
Expand Down
33 changes: 32 additions & 1 deletion src/port/DevTools/ThreadWatchdog.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -116,6 +116,10 @@ std::atomic<bool> sStalledFlags[WATCHDOG_NUM_THREADS] = {};
std::thread sWatcher;
std::atomic<bool> sWatcherRun{ false };

// Non-zero while a serviced thread is blocked on purpose.
std::atomic<int> sExpectedStallDepth{ 0 };
std::atomic<const char*> sExpectedStallReason{ nullptr };

std::string DescribeUnkFlag1(int32_t f) {
switch (f) {
case 0x04:
Expand Down Expand Up @@ -436,6 +440,7 @@ void Watcher() {
auto lastSample = Clock::now();
auto lastReport = Clock::time_point{};
bool wasStalled = false;
bool wasExpected = false;

while (sWatcherRun.load(std::memory_order_relaxed)) {
std::this_thread::sleep_for(kSampleEvery);
Expand All @@ -445,6 +450,9 @@ void Watcher() {
// this one; a stale "last beat" then isn't a stall. Rebaseline.
const bool suspended = (now - lastSample) > kSampleEvery * 4;
lastSample = now;
const bool expected = sExpectedStallDepth.load(std::memory_order_acquire) > 0;
const bool rebaseline = suspended || expected || wasExpected;
wasExpected = expected;

bool stalled[WATCHDOG_NUM_THREADS] = {};
bool anyStalled = false;
Expand All @@ -457,7 +465,7 @@ void Watcher() {
}
hb.started = true;
}
if (cur != hb.lastCount || suspended) {
if (cur != hb.lastCount || rebaseline) {
hb.lastCount = cur;
hb.lastBeat = now;
continue;
Expand Down Expand Up @@ -547,3 +555,26 @@ extern "C" void ThreadWatchdog_DumpNow(void) {
extern "C" int ThreadWatchdog_IsStalled(WatchdogThread id) {
return sStalledFlags[id].load(std::memory_order_relaxed) ? 1 : 0;
}

extern "C" void ThreadWatchdog_BeginExpectedStall(const char* reason) {
if (sExpectedStallDepth.fetch_add(1, std::memory_order_acq_rel) == 0) {
sExpectedStallReason.store(reason, std::memory_order_relaxed);
SPDLOG_DEBUG("[Watchdog] stall reporting suppressed: {}", reason ? reason : "?");
}
}

extern "C" void ThreadWatchdog_EndExpectedStall(void) {
const int prev = sExpectedStallDepth.fetch_sub(1, std::memory_order_acq_rel);
if (prev <= 0) {
// Unbalanced release would leave the counter negative and suppress
// every future stall, which is worse than the false positive.
sExpectedStallDepth.store(0, std::memory_order_release);
SPDLOG_WARN("[Watchdog] ThreadWatchdog_EndExpectedStall without a matching Begin");
return;
}
if (prev == 1) {
const char* reason = sExpectedStallReason.load(std::memory_order_relaxed);
SPDLOG_DEBUG("[Watchdog] stall reporting resumed: {}", reason ? reason : "?");
sExpectedStallReason.store(nullptr, std::memory_order_relaxed);
}
}
Loading