Added server setting toggle for 'surface cucking' and 'exposed ceilings' vanilla bugs

This commit is contained in:
MysterD 2022-05-31 01:29:48 -07:00
parent 91ee4f8a8f
commit 9fd309de56
17 changed files with 107 additions and 17 deletions

View file

@ -1573,6 +1573,7 @@
--- @class ServerSettings
--- @field public bubbleDeath integer
--- @field public enableCheats integer
--- @field public fixCollisionBugs integer
--- @field public headlessServer integer
--- @field public playerInteractions PlayerInteractions
--- @field public playerKnockbackStrength integer

View file

@ -1979,6 +1979,7 @@
| ----- | ---- | ------ |
| bubbleDeath | `integer` | |
| enableCheats | `integer` | |
| fixCollisionBugs | `integer` | |
| headlessServer | `integer` | |
| playerInteractions | [enum PlayerInteractions](constants.md#enum-PlayerInteractions) | |
| playerKnockbackStrength | `integer` | |

View file

@ -10,6 +10,7 @@
#include "math_util.h"
#include "game/game_init.h"
#include "pc/utils/misc.h"
#include "pc/network/network.h"
/**************************************************
* WALLS *
@ -240,6 +241,11 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32
ceil = NULL;
// set pheight to highest value
if (gServerSettings.fixCollisionBugs) {
*pheight = CELL_HEIGHT_LIMIT;
}
// Stay in this loop until out of ceilings.
while (surfaceNode != NULL) {
surf = surfaceNode->surface;
@ -284,29 +290,39 @@ static struct Surface *find_ceil_from_list(struct SurfaceNode *surfaceNode, s32
f32 height;
// If a wall, ignore it. Likely a remnant, should never occur.
if (ny == 0.0f) {
continue;
}
if (ny == 0.0f) { continue; }
// Find the ceil height at the specific point.
height = -(x * nx + nz * z + oo) / ny;
// Reject ceilings below previously found ceiling
if (gServerSettings.fixCollisionBugs && (height > *pheight)) {
continue;
}
// Checks for ceiling interaction with a 78 unit buffer.
//! (Exposed Ceilings) Because any point above a ceiling counts
// as interacting with a ceiling, ceilings far below can cause
// "invisible walls" that are really just exposed ceilings.
if (y - (height - -78.0f) > 0.0f) {
continue;
// <Fixed when gServerSettings.fixCollisionBugs != 0>
if (gServerSettings.fixCollisionBugs) {
if (y > height) { continue; }
} else {
if (y - (height - -78.0f) > 0.0f) { continue; }
}
*pheight = height;
ceil = surf;
break;
if (!gServerSettings.fixCollisionBugs) {
break;
}
}
}
//! (Surface Cucking) Since only the first ceil is returned and not the lowest,
// lower ceilings can be "cucked" by higher ceilings.
// <Fixed when gServerSettings.fixCollisionBugs != 0>
return ceil;
}
@ -428,6 +444,11 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
struct Surface *floor = NULL;
s32 interpolate;
// set pheight to lowest value
if (gServerSettings.fixCollisionBugs) {
*pheight = FLOOR_LOWER_LIMIT;
}
// Iterate through the list of floors until there are no more floors.
while (surfaceNode != NULL) {
surf = surfaceNode->surface;
@ -524,6 +545,12 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
// Find the height of the floor at a given location.
height = -(x * nx + nz * z + oo) / ny;
// Find highest floor
if (gServerSettings.fixCollisionBugs && (height < *pheight)) {
continue;
}
// Checks for floor interaction with a 78 unit buffer.
if (y - (height + -78.0f) < 0.0f) {
continue;
@ -544,11 +571,15 @@ static struct Surface *find_floor_from_list(struct SurfaceNode *surfaceNode, s32
}
floor = surf;
break;
if (!gServerSettings.fixCollisionBugs) {
break;
}
}
//! (Surface Cucking) Since only the first floor is returned and not the highest,
// higher floors can be "cucked" by lower floors.
// <Fixed when gServerSettings.fixCollisionBugs != 0>
return floor;
}

View file

@ -17,6 +17,7 @@
#include "game/game_init.h"
#include "engine/math_util.h"
#include "game/level_update.h"
#include "pc/network/network.h"
s32 unused8038BE90;
@ -151,7 +152,11 @@ static void add_surface_to_cell(s16 dynamic, s16 cellX, s16 cellZ, struct Surfac
// many functions only use the first triangle in surface order that fits,
// missing higher surfaces.
// upperY would be a better sort method.
surfacePriority = surface->vertex1[1] * sortDir;
// <Fixed when gServerSettings.fixCollisionBugs != 0>
surfacePriority = gServerSettings.fixCollisionBugs
? (surface->upperY * sortDir)
: (surface->vertex1[1] * sortDir);
newNode->surface = surface;

View file

@ -623,6 +623,18 @@ f32 vec3f_find_ceil(Vec3f pos, f32 height, struct Surface **ceil) {
return find_ceil(pos[0], height + 80.0f, pos[2], ceil);
}
/**
* Finds the ceiling from a vec3f horizontally and a height (with 80 vertical buffer).
* Prevents exposed ceiling bug
*/
// Prevent exposed ceilings
f32 vec3f_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil) {
if (gServerSettings.fixCollisionBugs) {
height = MAX(height, pos[1]) + 3.0f;
}
return vec3f_find_ceil(pos, height, ceil);
}
/**
* Determines if Mario is facing "downhill."
*/
@ -1434,7 +1446,7 @@ copyPlayerGoto:;
m->floorHeight = find_floor(m->pos[0], m->pos[1], m->pos[2], &m->floor);
}
m->ceilHeight = vec3f_find_ceil(&m->pos[0], m->floorHeight, &m->ceil);
m->ceilHeight = vec3f_mario_ceil(&m->pos[0], m->floorHeight, &m->ceil);
gasLevel = find_poison_gas_level(m->pos[0], m->pos[2]);
m->waterLevel = find_water_level(m->pos[0], m->pos[2]);

View file

@ -34,6 +34,7 @@ s32 mario_get_floor_class(struct MarioState *m);
u32 mario_get_terrain_sound_addend(struct MarioState *m);
struct Surface *resolve_and_return_wall_collisions(Vec3f pos, f32 offset, f32 radius);
f32 vec3f_find_ceil(Vec3f pos, f32 height, struct Surface **ceil);
f32 vec3f_mario_ceil(Vec3f pos, f32 height, struct Surface **ceil);
s32 mario_facing_downhill(struct MarioState *m, s32 turnYaw);
u32 mario_floor_is_slippery(struct MarioState *m);
s32 mario_floor_is_slope(struct MarioState *m);

View file

@ -97,7 +97,7 @@ s32 set_pole_position(struct MarioState *m, f32 offsetY) {
collided = f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 60.0f, 50.0f);
collided |= f32_find_wall_collision(&m->pos[0], &m->pos[1], &m->pos[2], 30.0f, 24.0f);
ceilHeight = vec3f_find_ceil(m->pos, m->pos[1], &ceil);
ceilHeight = vec3f_mario_ceil(m->pos, m->pos[1], &ceil);
if (m->pos[1] > ceilHeight - 160.0f) {
m->pos[1] = ceilHeight - 160.0f;
marioObj->oMarioPolePos = m->pos[1] - m->usedObj->oPosY;
@ -333,7 +333,7 @@ s32 perform_hanging_step(struct MarioState *m, Vec3f nextPos) {
m->wall = resolve_and_return_wall_collisions(nextPos, 50.0f, 50.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
if (floor == NULL) {
return HANG_HIT_CEIL_OR_OOB;

View file

@ -89,7 +89,7 @@ u32 perform_water_full_step(struct MarioState *m, Vec3f nextPos) {
wall = resolve_and_return_wall_collisions(nextPos, 10.0f, 110.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
if (floor == NULL) {
return WATER_STEP_CANCELLED;

View file

@ -270,7 +270,7 @@ static s32 perform_ground_quarter_step(struct MarioState *m, Vec3f nextPos) {
upperWall = resolve_and_return_wall_collisions(nextPos, 60.0f, 50.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
waterLevel = find_water_level(nextPos[0], nextPos[2]);
@ -406,7 +406,7 @@ s32 perform_air_quarter_step(struct MarioState *m, Vec3f intendedPos, u32 stepAr
lowerWall = resolve_and_return_wall_collisions(nextPos, 30.0f, 50.0f);
floorHeight = find_floor(nextPos[0], nextPos[1], nextPos[2], &floor);
ceilHeight = vec3f_find_ceil(nextPos, floorHeight, &ceil);
ceilHeight = vec3f_mario_ceil(nextPos, floorHeight, &ceil);
waterLevel = find_water_level(nextPos[0], nextPos[2]);

View file

@ -116,6 +116,7 @@ bool configSkipIntro = 0;
bool configShareLives = 0;
bool configEnableCheats = 0;
bool configBubbleDeath = true;
bool configFixCollBugs = true;
unsigned int configAmountofPlayers = 16;
bool configHUD = true;
#ifdef DISCORDRPC
@ -204,6 +205,7 @@ static const struct ConfigOption options[] = {
{.name = "frame_limit" , .type = CONFIG_TYPE_UINT , .uintValue = &configFrameLimit},
{.name = "amount_of_players", .type = CONFIG_TYPE_UINT , .uintValue = &configAmountofPlayers},
{.name = "bubble_death", .type = CONFIG_TYPE_BOOL , .boolValue = &configBubbleDeath},
{.name = "fix_collision_bugs", .type = CONFIG_TYPE_BOOL , .boolValue = &configFixCollBugs},
{.name = "coop_draw_distance", .type = CONFIG_TYPE_UINT , .uintValue = &configDrawDistance},
{.name = "coop_host_port", .type = CONFIG_TYPE_UINT , .uintValue = &configHostPort},
{.name = "coop_host_save_slot", .type = CONFIG_TYPE_UINT , .uintValue = &configHostSaveSlot},

View file

@ -72,6 +72,7 @@ extern bool configSkipIntro;
extern bool configShareLives;
extern bool configEnableCheats;
extern bool configBubbleDeath;
extern bool configFixCollBugs;
extern unsigned int configAmountofPlayers;
#ifdef DISCORDRPC
extern bool configDiscordRPC;

View file

@ -43,7 +43,7 @@ static void djui_panel_host_player_text_change(struct DjuiBase* caller) {
}
void djui_panel_host_settings_create(struct DjuiBase* caller) {
f32 bodyHeight = 32 * 8 + 64 * 1 + 16 * 8;
f32 bodyHeight = 32 * 9 + 64 * 1 + 16 * 9;
struct DjuiBase* defaultBase = NULL;
struct DjuiThreePanel* panel = djui_panel_menu_create(bodyHeight, "\\#ff0800\\S\\#1be700\\E\\#00b3ff\\T\\#ffef00\\T\\#ff0800\\I\\#1be700\\N\\#00b3ff\\G\\#ffef00\\S");
@ -83,7 +83,11 @@ void djui_panel_host_settings_create(struct DjuiBase* caller) {
struct DjuiCheckbox* checkbox5 = djui_checkbox_create(&body->base, "Bubble on death", &configBubbleDeath);
djui_base_set_size_type(&checkbox5->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox5->base, 1.0f, 32);
struct DjuiCheckbox* checkbox6 = djui_checkbox_create(&body->base, "Fix collision bugs", &configFixCollBugs);
djui_base_set_size_type(&checkbox6->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&checkbox6->base, 1.0f, 32);
struct DjuiRect* rect1 = djui_rect_create(&body->base);
djui_base_set_size_type(&rect1->base, DJUI_SVT_RELATIVE, DJUI_SVT_ABSOLUTE);
djui_base_set_size(&rect1->base, 1.0f, 32);

View file

@ -1729,10 +1729,11 @@ static struct LuaObjectField sRayIntersectionInfoFields[LUA_RAY_INTERSECTION_INF
{ "surface", LVT_COBJECT_P, offsetof(struct RayIntersectionInfo, surface), false, LOT_SURFACE },
};
#define LUA_SERVER_SETTINGS_FIELD_COUNT 8
#define LUA_SERVER_SETTINGS_FIELD_COUNT 9
static struct LuaObjectField sServerSettingsFields[LUA_SERVER_SETTINGS_FIELD_COUNT] = {
{ "bubbleDeath", LVT_U8, offsetof(struct ServerSettings, bubbleDeath), false, LOT_NONE },
{ "enableCheats", LVT_U8, offsetof(struct ServerSettings, enableCheats), false, LOT_NONE },
{ "fixCollisionBugs", LVT_U8, offsetof(struct ServerSettings, fixCollisionBugs), false, LOT_NONE },
{ "headlessServer", LVT_U8, offsetof(struct ServerSettings, headlessServer), false, LOT_NONE },
{ "playerInteractions", LVT_S32, offsetof(struct ServerSettings, playerInteractions), false, LOT_NONE },
{ "playerKnockbackStrength", LVT_U8, offsetof(struct ServerSettings, playerKnockbackStrength), false, LOT_NONE },

View file

@ -8606,6 +8606,31 @@ int smlua_func_vec3f_find_ceil(lua_State* L) {
return 1;
}
*/
/*
int smlua_func_vec3f_mario_ceil(lua_State* L) {
if(!smlua_functions_valid_param_count(L, 3)) { return 0; }
f32* pos = smlua_get_vec3f_from_buffer();
pos[0] = smlua_get_number_field(1, "x");
pos[1] = smlua_get_number_field(1, "y");
pos[2] = smlua_get_number_field(1, "z");
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 1"); return 0; }
f32 height = smlua_to_number(L, 2);
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 2"); return 0; }
// struct Surface** ceil = (struct Surface**)smlua_to_cobject(L, 3, LOT_???); <--- UNIMPLEMENTED
if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter 3"); return 0; }
lua_pushnumber(L, vec3f_mario_ceil(pos, height, ceil));
smlua_push_number_field(1, "x", pos[0]);
smlua_push_number_field(1, "y", pos[1]);
smlua_push_number_field(1, "z", pos[2]);
return 1;
}
*/
//////////////////////////////
@ -17281,6 +17306,7 @@ void smlua_bind_functions_autogen(void) {
smlua_bind_function(L, "update_mario_pos_for_anim", smlua_func_update_mario_pos_for_anim);
smlua_bind_function(L, "update_mario_sound_and_camera", smlua_func_update_mario_sound_and_camera);
//smlua_bind_function(L, "vec3f_find_ceil", smlua_func_vec3f_find_ceil); <--- UNIMPLEMENTED
//smlua_bind_function(L, "vec3f_mario_ceil", smlua_func_vec3f_mario_ceil); <--- UNIMPLEMENTED
// mario_actions_airborne.c
smlua_bind_function(L, "check_common_airborne_cancels", smlua_func_check_common_airborne_cancels);

View file

@ -56,6 +56,7 @@ struct ServerSettings gServerSettings = {
.enableCheats = 0,
.bubbleDeath = 1,
.headlessServer = 0,
.fixCollisionBugs = 1,
};
void network_set_system(enum NetworkSystemType nsType) {
@ -91,6 +92,7 @@ bool network_init(enum NetworkType inNetworkType) {
gServerSettings.shareLives = configShareLives;
gServerSettings.enableCheats = configEnableCheats;
gServerSettings.bubbleDeath = configBubbleDeath;
gServerSettings.fixCollisionBugs = configFixCollBugs;
#if defined(RAPI_DUMMY) || defined(WAPI_DUMMY)
gServerSettings.headlessServer = (inNetworkType == NT_SERVER);
#else

View file

@ -99,6 +99,7 @@ struct ServerSettings {
u8 enableCheats;
u8 bubbleDeath;
u8 headlessServer;
u8 fixCollisionBugs;
};
// Networking-specific externs

View file

@ -107,6 +107,7 @@ void network_send_join(struct Packet* joinRequestPacket) {
packet_write(&p, &gServerSettings.shareLives, sizeof(u8));
packet_write(&p, &gServerSettings.enableCheats, sizeof(u8));
packet_write(&p, &gServerSettings.bubbleDeath, sizeof(u8));
packet_write(&p, &gServerSettings.fixCollisionBugs, sizeof(u8));
packet_write(&p, &gServerSettings.headlessServer, sizeof(u8));
packet_write(&p, eeprom, sizeof(u8) * 512);
@ -170,6 +171,7 @@ void network_receive_join(struct Packet* p) {
packet_read(p, &gServerSettings.shareLives, sizeof(u8));
packet_read(p, &gServerSettings.enableCheats, sizeof(u8));
packet_read(p, &gServerSettings.bubbleDeath, sizeof(u8));
packet_read(p, &gServerSettings.fixCollisionBugs, sizeof(u8));
packet_read(p, &gServerSettings.headlessServer, sizeof(u8));
packet_read(p, eeprom, sizeof(u8) * 512);
packet_read(p, &modCount, sizeof(u8));