Skip to content
Open
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: 7 additions & 0 deletions configs/default-config.txt
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,12 @@
// 4:3. Additionally fixes View Stage stretching and Sand's haze breaking in
// widescreen. Sprites will be fixed in the future.

// fix-spooky-action
//
// Fixes an issue where accumulated floating-point error during collision
// calculations may apply a small undesired positiion/velocity to the ball. This is
// most noticeable on stages with many, fast, or very rotational animations.

// ----------------------------------------------------------------------------

// 'enabled' - Applies the patch
Expand Down Expand Up @@ -197,6 +203,7 @@
four-digit-banana-counter: disabled
fix-minimap-color: disabled
fix-widescreen: disabled
fix-spooky-action: disabled
}

// Toggles which party games are accessible from the party game menu.
Expand Down
2 changes: 1 addition & 1 deletion src/internal/tickable.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ namespace tickable {

// Capacity of the tickable manager vector, increase if needed
// This only stores pointers, so memory impact should be low
constexpr size_t PATCH_CAPACITY = 32;
constexpr size_t PATCH_CAPACITY = 48;

// Represents a patch, or code that ticks every frame
struct Tickable {
Expand Down
4 changes: 2 additions & 2 deletions src/mkb/mkb2.us.lst
Original file line number Diff line number Diff line change
Expand Up @@ -4525,7 +4525,7 @@
802C15A0:stcoli_sub11
802C16DC:g_cone_coli_something
802C16DC:stcoli_sub12
802C19AC:g_something_with_physicsball_restitution
802C19AC:collide_ball_with_plane
802C19AC:stcoli_sub13
802C1CEC:line_intersects_rect
802C1CEC:stcoli_sub14
Expand Down Expand Up @@ -4555,7 +4555,7 @@
802C4968:stcoli_sub30
802C49C0:inv_tf_physicsball_by_mtxa
802C49C0:stcoli_sub31
802C4A18:tf_physball_to_itemgroup_space
802C4A18:tf_physicsball_to_itemgroup_space
802C4A18:stcoli_sub32
802C4C38:FUN_801eea00
802C4C58:g_something_w_ig_and_coli_headers
Expand Down
57 changes: 36 additions & 21 deletions src/mkb/mkb2_ghidra.h
Original file line number Diff line number Diff line change
Expand Up @@ -142,6 +142,14 @@ typedef undefined2 StobjType;

typedef struct Vec Vec, *PVec;

enum {
COLI_FLAG_OCCURRED=1,
COLI_FLAG_UNK1=2
};
typedef undefined4 ColiFlag;

typedef struct ColiPlane ColiPlane, *PColiPlane;

typedef struct GmaModel GmaModel, *PGmaModel;

typedef struct S16Vec S16Vec, *PS16Vec;
Expand Down Expand Up @@ -192,6 +200,21 @@ enum {
};
typedef undefined4 GXTexFmt;

struct Vec {
float x;
float y;
float z;
} __attribute__((__packed__));
static_assert(sizeof(Vec) == 0xc);

struct ColiPlane {
struct Vec point;
struct Vec normal;
u16 g_flags1;
u16 g_flags2;
} __attribute__((__packed__));
static_assert(sizeof(ColiPlane) == 0x1c);

struct S16Vec { /* Often used for rotations */
s16 x;
s16 y;
Expand Down Expand Up @@ -231,27 +254,18 @@ struct GXTexObj {
} __attribute__((__packed__));
static_assert(sizeof(GXTexObj) == 0x20);

struct Vec {
float x;
float y;
float z;
} __attribute__((__packed__));
static_assert(sizeof(Vec) == 0xc);

struct PhysicsBall { /* A representation of a Ball with just the physics/collision-related info */
dword flags;
ColiFlag flags;
struct Vec pos;
struct Vec prev_pos;
struct Vec vel;
float radius;
float acceleration;
float restitution;
dword g_jerk;
undefined field_0x38[0xc];
struct Vec g_some_vec;
undefined field_0x50[0x4];
dword field25_0x54;
float field26_0x58;
dword hardest_coli_speed;
struct ColiPlane hardest_coli_plane;
dword hardest_coli_ig_idx;
float friction;
dword itemgroup_idx; /* The itemgroup that this PhysicsBall is relative to, aka in the local space of */
} __attribute__((__packed__));
static_assert(sizeof(PhysicsBall) == 0x60);
Expand Down Expand Up @@ -2185,7 +2199,7 @@ struct Ball {
int field48_0x108;
struct Vec ape_facedir_point; /* The point of interest that the monkey looks at (goal, banana, etc) */
float something_with_ape_facedir; /* Approaches 1 the closer you are to the point of interest */
struct Vec g_last_collision_normal; /* Maybe inverse of the normal of the last triangle collided with? */
struct Vec g_last_coli_normal; /* Maybe inverse of the normal of the last triangle collided with? */
undefined field_0x128[0x4];
dword g_race_flags;
short g_other_counter;
Expand Down Expand Up @@ -2293,7 +2307,7 @@ typedef struct Itemgroup Itemgroup, *PItemgroup;

struct Itemgroup { /* Contains the current animation-related state of each item group in a stage (each thing corresponding to a collision header in the stagedef) */
dword playback_state; /* Corresponding to the switch playback type which is controlling the item group, see PlaybackState */
dword anim_frame;
s32 anim_frame;
struct Vec position;
struct Vec prev_position;
struct S16Vec rotation;
Expand Down Expand Up @@ -8774,7 +8788,7 @@ extern "C" {
void set_ball_properties(struct Ball * ball, int constants_idx);
void ball_collision_stars(struct Ball * ball);
void init_physicsball_from_ball(struct Ball * ball, struct PhysicsBall * physicsball);
void g_copy_physicsball_to_ball(struct Ball * ball, struct PhysicsBall * physicsball);
void apply_physicsball_to_ball(struct Ball * ball, struct PhysicsBall * physicsball);
void g_ball_ape_rotation(struct Ball * ball);
void spawn_postgoal_ball_sparkle(void);
void g_some_ballfunc(struct Ball * param_1);
Expand All @@ -8796,6 +8810,7 @@ extern "C" {
void g_sphere_coli_something(struct PhysicsBall * param_1, struct StagedefColiSphere * param_2);
void g_cone_coli_something(struct PhysicsBall * param_1, struct StagedefColiCone * param_2);
void g_something_with_physicsball_restitution(struct PhysicsBall * physicsball, struct Vec * param_2);
void collide_ball_with_plane(struct PhysicsBall * physicsball, struct ColiPlane * plane);
BOOL32 line_intersects_rect(struct Vec * lineStart, struct Vec * lineEnd, struct Rect * rect);
void stobj_jamabar_child_coli(struct PhysicsBall * physicsball, struct Stobj * stobj);
void raycast_stage_down(struct Vec * origin, struct RaycastHit * out_hit, struct Vec * out_vel_at_point);
Expand All @@ -8813,17 +8828,17 @@ extern "C" {
void stcoli_sub29(float * param_1, float * param_2, float * param_3, float * param_4, undefined4 param_5, undefined4 param_6, undefined4 param_7, undefined4 param_8);
void tf_physicsball_by_mtxa(struct PhysicsBall * physicsball1, struct PhysicsBall * physicsball2);
void inv_tf_physicsball_by_mtxa(struct PhysicsBall * src_physicsball, struct PhysicsBall * dest_physicsball);
void tf_physball_to_itemgroup_space(struct PhysicsBall * physicsball, int itemgroup_idx);
uint g_something_w_ig_and_coli_headers(struct Itemgroup * ig_list, struct StagedefColiHeader * coli_header_list, undefined4 param_3, struct Vec * physicsball_x);
undefined4 g_something_w_ig_and_coli_headers_2(struct Itemgroup * ig_list, struct StagedefColiHeader * coli_header_list, struct Vec * physicsball_pos);
void tf_physicsball_to_itemgroup_space(struct PhysicsBall * physicsball, int dest_ig_idx);
uint g_is_ball_in_ig_coli_range(struct Itemgroup * ig_list, struct StagedefColiHeader * coli_header_list, undefined4 param_3, struct Vec * physicsball_x);
BOOL32 g_ball_ig_bound_sphere_overlap(struct Itemgroup * ig_anim, struct StagedefColiHeader * ig_def, struct Vec * physicsball_pos);
void event_world_init(void);
void event_world_tick(void);
void event_world_dest(void);
double evaluate_stagedef_keyframe(double g_anim_frame, int count, struct StagedefAnimKeyframe * keyframe);
void event_stage_init(void);
void event_stage_tick(void);
void event_stage_dest(void);
double g_advance_itemgroup_anim_frame(struct Itemgroup * itemgroup, struct StagedefColiHeader * colis_header);
float advance_itemgroup_anim(struct Itemgroup * itemgroup, struct StagedefColiHeader * colis_header);
void g_advance_stage_animation(void);
void g_transform_some_itemgroup_vec(void);
GmaModel * get_GmaBuffer_entry(struct GmaBuffer * buffer, char * name);
Expand Down
64 changes: 64 additions & 0 deletions src/patches/fixes/fix_spooky_action.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
#include "fix_spooky_action.h"

#include "patch.h"
#include "tickable.h"
#include "vecutil.h"
#include <mkb/mkb.h>

namespace {

// Our special collision flag that's reset for each itemgroup
constexpr u32 COLI_FLAG_IG = 1 << 7;

patch::Tramp<decltype(&mkb::init_physicsball_from_ball)> s_init_physicsball_tramp;
patch::Tramp<decltype(&mkb::tf_physicsball_to_itemgroup_space)> s_tf_physicsball_tramp;
patch::Tramp<decltype(&mkb::collide_ball_with_plane)> s_collide_physicsball_tramp;

mkb::PhysicsBall s_clean_physicsball;

void init_physicsball_from_ball(mkb::Ball* ball, mkb::PhysicsBall* physicsball) {
s_init_physicsball_tramp.dest(ball, physicsball);
s_clean_physicsball = *physicsball;
}

void tf_physicsball_to_itemgroup_space(mkb::PhysicsBall* physicsball, int dest_ig_idx) {
if (physicsball->flags & COLI_FLAG_IG) {
physicsball->flags &= ~COLI_FLAG_IG;
s_clean_physicsball = *physicsball;
}
else {
*physicsball = s_clean_physicsball;
}
s_tf_physicsball_tramp.dest(physicsball, dest_ig_idx);
}

void collide_ball_with_plane(mkb::PhysicsBall* physicsball, mkb::ColiPlane* plane) {
Vec prev_pos = physicsball->pos;
Vec prev_vel = physicsball->vel;
s_collide_physicsball_tramp.dest(physicsball, plane);
if (!VEC_EQUAL_EXACT(prev_pos, physicsball->pos) ||
!VEC_EQUAL_EXACT(prev_vel, physicsball->vel)) {
physicsball->flags |= COLI_FLAG_IG;
}
}

}// namespace

namespace fix_spooky_action {

TICKABLE_DEFINITION((
.name = "fix-spooky-action",
.description = "Prevent accumulated floating point error from transforming ball during collision",
.init_main_loop = init_main_loop, ))

void init_main_loop() {

patch::hook_function(s_init_physicsball_tramp, mkb::init_physicsball_from_ball,
init_physicsball_from_ball);
patch::hook_function(s_tf_physicsball_tramp, mkb::tf_physicsball_to_itemgroup_space,
tf_physicsball_to_itemgroup_space);
patch::hook_function(s_collide_physicsball_tramp, mkb::collide_ball_with_plane,
collide_ball_with_plane);
}

}// namespace fix_spooky_action
5 changes: 5 additions & 0 deletions src/patches/fixes/fix_spooky_action.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
#pragma once

namespace fix_spooky_action {
void init_main_loop();
}
1 change: 1 addition & 0 deletions src/utils/vecutil.h
Original file line number Diff line number Diff line change
Expand Up @@ -13,3 +13,4 @@
#define VEC_DOT(v1, v2) ((v1).x * (v2).x + (v1).y * (v2).y + (v1).z * (v2).z)
#define VEC_LEN_SQ(v) (VEC_DOT((v), (v)))
#define VEC_ZERO (Vec3f{0, 0, 0})
#define VEC_EQUAL_EXACT(v1, v2) ((v1.x == v2.x && v1.y == v2.y && v1.z == v2.z))