From fce88728d20c0a8e6208aa9645186a07cc3a0821 Mon Sep 17 00:00:00 2001 From: MysterD Date: Mon, 3 Apr 2023 13:55:03 -0700 Subject: [PATCH] Improve lag compensation --- autogen/convert_functions.py | 1 + autogen/lua_definitions/functions.lua | 27 ++++--- bin/custom_font.c | 2 +- docs/lua/functions-3.md | 100 ++++++++++++++++---------- docs/lua/functions.md | 9 ++- mods/arena/arena-player.lua | 71 +++++++++--------- mods/arena/arena-proj-bobomb.lua | 10 +-- mods/arena/arena-proj-cannon-ball.lua | 12 ++-- src/game/game_init.c | 8 +++ src/game/interaction.c | 34 ++++----- src/pc/lua/smlua_functions_autogen.c | 91 ++++++++++++++--------- src/pc/network/lag_compensation.c | 59 +++++++++++++++ src/pc/network/lag_compensation.h | 8 +++ src/pc/network/network_player.c | 66 +---------------- src/pc/network/network_player.h | 3 - 15 files changed, 282 insertions(+), 219 deletions(-) create mode 100644 src/pc/network/lag_compensation.c create mode 100644 src/pc/network/lag_compensation.h diff --git a/autogen/convert_functions.py b/autogen/convert_functions.py index ed277910..9dad9bcf 100644 --- a/autogen/convert_functions.py +++ b/autogen/convert_functions.py @@ -37,6 +37,7 @@ in_files = [ "src/game/sound_init.h", "src/pc/djui/djui_hud_utils.h", "src/pc/network/network_player.h", + "src/pc/network/lag_compensation.h", "include/behavior_table.h", "src/pc/lua/utils/smlua_obj_utils.h", "src/pc/lua/utils/smlua_misc_utils.h", diff --git a/autogen/lua_definitions/functions.lua b/autogen/lua_definitions/functions.lua index bf1d15bd..da8319cc 100644 --- a/autogen/lua_definitions/functions.lua +++ b/autogen/lua_definitions/functions.lua @@ -4010,6 +4010,22 @@ function take_damage_and_knock_back(m, o) -- ... end +--- @return nil +function lag_compensation_clear() + -- ... +end + +--- @param otherNp NetworkPlayer +--- @return MarioState +function lag_compensation_get_local_state(otherNp) + -- ... +end + +--- @return nil +function lag_compensation_store() + -- ... +end + --- @param courseNum integer --- @param levelNum integer --- @param areaIndex integer @@ -5614,17 +5630,6 @@ function network_player_from_global_index(globalIndex) -- ... end ---- @return nil -function network_player_local_restore_lag_state() - -- ... -end - ---- @param otherNp NetworkPlayer ---- @return nil -function network_player_local_set_lag_state(otherNp) - -- ... -end - --- @param np NetworkPlayer --- @param part PlayerParts --- @param out Color diff --git a/bin/custom_font.c b/bin/custom_font.c index 8748fca3..2db90f13 100644 --- a/bin/custom_font.c +++ b/bin/custom_font.c @@ -21,7 +21,7 @@ const f32 font_normal_widths[] = { /* a b c d e f g h i j k l m n o p q r s t u v w x y z */ 0.3000f, 0.3125f, 0.3125f, 0.3125f, 0.3125f, 0.3000f, 0.3750f, 0.3125f, 0.2200f, 0.3125f, 0.3125f, 0.1700f, 0.4350f, 0.3125f, 0.3000f, 0.3000f, 0.3125f, 0.2700f, 0.3125f, 0.3125f, 0.3125f, 0.2750f, 0.4375f, 0.3750f, 0.3125f, 0.3125f, /* { | } ~ DEL */ - 0.3125f, 0.2500f, 0.3125f, 0.5000f, 0.2000f, + 0.3125f, 0.2500f, 0.3125f, 0.5000f, 0.3125f, }; ////////////////////////////////////////////////////////// diff --git a/docs/lua/functions-3.md b/docs/lua/functions-3.md index d4a98321..1cc88f38 100644 --- a/docs/lua/functions-3.md +++ b/docs/lua/functions-3.md @@ -3299,6 +3299,68 @@
+--- +# functions from lag_compensation.h + +
+ + +## [lag_compensation_clear](#lag_compensation_clear) + +### Lua Example +`lag_compensation_clear()` + +### Parameters +- None + +### Returns +- None + +### C Prototype +`void lag_compensation_clear(void);` + +[:arrow_up_small:](#) + +
+ +## [lag_compensation_get_local_state](#lag_compensation_get_local_state) + +### Lua Example +`local MarioStateValue = lag_compensation_get_local_state(otherNp)` + +### Parameters +| Field | Type | +| ----- | ---- | +| otherNp | [NetworkPlayer](structs.md#NetworkPlayer) | + +### Returns +[MarioState](structs.md#MarioState) + +### C Prototype +`struct MarioState* lag_compensation_get_local_state(struct NetworkPlayer* otherNp);` + +[:arrow_up_small:](#) + +
+ +## [lag_compensation_store](#lag_compensation_store) + +### Lua Example +`lag_compensation_store()` + +### Parameters +- None + +### Returns +- None + +### C Prototype +`void lag_compensation_store(void);` + +[:arrow_up_small:](#) + +
+ --- # functions from level_info.h @@ -8186,44 +8248,6 @@
-## [network_player_local_restore_lag_state](#network_player_local_restore_lag_state) - -### Lua Example -`network_player_local_restore_lag_state()` - -### Parameters -- None - -### Returns -- None - -### C Prototype -`void network_player_local_restore_lag_state(void);` - -[:arrow_up_small:](#) - -
- -## [network_player_local_set_lag_state](#network_player_local_set_lag_state) - -### Lua Example -`network_player_local_set_lag_state(otherNp)` - -### Parameters -| Field | Type | -| ----- | ---- | -| otherNp | [NetworkPlayer](structs.md#NetworkPlayer) | - -### Returns -- None - -### C Prototype -`void network_player_local_set_lag_state(struct NetworkPlayer* otherNp);` - -[:arrow_up_small:](#) - -
- ## [network_player_palette_to_color](#network_player_palette_to_color) ### Lua Example diff --git a/docs/lua/functions.md b/docs/lua/functions.md index 6e32ac9f..c057ee85 100644 --- a/docs/lua/functions.md +++ b/docs/lua/functions.md @@ -792,6 +792,13 @@
+- lag_compensation.h + - [lag_compensation_clear](functions-3.md#lag_compensation_clear) + - [lag_compensation_get_local_state](functions-3.md#lag_compensation_get_local_state) + - [lag_compensation_store](functions-3.md#lag_compensation_store) + +
+ - level_info.h - [get_level_name](functions-3.md#get_level_name) - [get_level_name_ascii](functions-3.md#get_level_name_ascii) @@ -1085,8 +1092,6 @@ - [network_player_color_to_palette](functions-3.md#network_player_color_to_palette) - [network_player_connected_count](functions-3.md#network_player_connected_count) - [network_player_from_global_index](functions-3.md#network_player_from_global_index) - - [network_player_local_restore_lag_state](functions-3.md#network_player_local_restore_lag_state) - - [network_player_local_set_lag_state](functions-3.md#network_player_local_set_lag_state) - [network_player_palette_to_color](functions-3.md#network_player_palette_to_color) - [network_player_set_description](functions-3.md#network_player_set_description) diff --git a/mods/arena/arena-player.lua b/mods/arena/arena-player.lua index b508a323..42ff344b 100644 --- a/mods/arena/arena-player.lua +++ b/mods/arena/arena-player.lua @@ -105,49 +105,46 @@ function mario_local_hammer_check(m) -- check for hammer attacks for i = 1, (MAX_PLAYERS - 1) do - local m2 = gMarioStates[i] - local np2 = gNetworkPlayers[i] - local s2 = gPlayerSyncTable[i] - if passes_pvp_interaction_checks(m2, m) ~= 0 then - network_player_local_set_lag_state(np2) - if s2.item == ITEM_HAMMER and mario_hammer_is_attack(m2.action) and passes_pvp_interaction_checks(m2, m) ~= 0 and global_index_hurts_mario_state(np2.globalIndex, m) then - local pos = mario_hammer_position(m2) - local dist = vec3f_dist(pos, m.pos) - if dist <= 165 then - local yOffset = 100 - if m2.action == ACT_JUMP_KICK then - yOffset = yOffset + 100 - end + local mattacker = gMarioStates[i] + local npattacker = gNetworkPlayers[i] + local sattacker = gPlayerSyncTable[i] + local cmvictim = lag_compensation_get_local_state(npattacker) - local vel = { - x = m.pos.x - m2.pos.x, - y = (m.pos.y + yOffset) - m2.pos.y, - z = m.pos.z - m2.pos.z, - } - vec3f_normalize(vel) - vec3f_mul(vel, 75 + 70 * (1 - mario_health_float(m))) + if sattacker.item == ITEM_HAMMER and mario_hammer_is_attack(mattacker.action) and passes_pvp_interaction_checks(mattacker, cmvictim) ~= 0 and passes_pvp_interaction_checks(mattacker, m) ~= 0 and global_index_hurts_mario_state(npattacker.globalIndex, m) then + local pos = mario_hammer_position(mattacker) + local dist = vec3f_dist(pos, cmvictim.pos) + if dist <= 165 then + local yOffset = 100 + if mattacker.action == ACT_JUMP_KICK then + yOffset = yOffset + 100 + end - network_player_local_restore_lag_state() - set_mario_action(m, ACT_BACKWARD_AIR_KB, 0) - m.invincTimer = 30 - m.knockbackTimer = 10 - m.vel.x = vel.x - m.vel.y = vel.y - m.vel.z = vel.z - m.faceAngle.y = atan2s(vel.z, vel.x) + 0x8000 - s2.ammo = s2.ammo - 1 + local vel = { + x = cmvictim.pos.x - mattacker.pos.x, + y = (cmvictim.pos.y + yOffset) - mattacker.pos.y, + z = cmvictim.pos.z - mattacker.pos.z, + } + vec3f_normalize(vel) + vec3f_mul(vel, 75 + 70 * (1 - mario_health_float(cmvictim))) - send_arena_hammer_hit(np.globalIndex, np2.globalIndex) - e.lastDamagedByGlobal = np2.globalIndex + set_mario_action(m, ACT_BACKWARD_AIR_KB, 0) + m.invincTimer = 30 + m.knockbackTimer = 10 + m.vel.x = vel.x + m.vel.y = vel.y + m.vel.z = vel.z + m.faceAngle.y = atan2s(vel.z, vel.x) + 0x8000 + sattacker.ammo = sattacker.ammo - 1 - if m2.action == ACT_PUNCHING or m2.action == ACT_MOVE_PUNCHING or m2.action == ACT_GROUND_POUND then - m.hurtCounter = 12 - else - m.hurtCounter = 8 - end + send_arena_hammer_hit(np.globalIndex, npattacker.globalIndex) + e.lastDamagedByGlobal = npattacker.globalIndex + + if mattacker.action == ACT_PUNCHING or mattacker.action == ACT_MOVE_PUNCHING or mattacker.action == ACT_GROUND_POUND then + m.hurtCounter = 12 + else + m.hurtCounter = 8 end end - network_player_local_restore_lag_state() end end diff --git a/mods/arena/arena-proj-bobomb.lua b/mods/arena/arena-proj-bobomb.lua index 28a9c24c..0b85601d 100644 --- a/mods/arena/arena-proj-bobomb.lua +++ b/mods/arena/arena-proj-bobomb.lua @@ -17,13 +17,15 @@ end function bhv_arena_bobomb_intersects_player(obj, m, pos, radius) local ownerNp = network_player_from_global_index(obj.oArenaBobombGlobalOwner) - network_player_local_set_lag_state(ownerNp) + local cm = m + if m.playerIndex == 0 then + cm = lag_compensation_get_local_state(ownerNp) + end - local mPos1 = { x = m.pos.x, y = m.pos.y + 50, z = m.pos.z } - local mPos2 = { x = m.pos.x, y = m.pos.y + 150, z = m.pos.z } + local mPos1 = { x = cm.pos.x, y = cm.pos.y + 50, z = cm.pos.z } + local mPos2 = { x = cm.pos.x, y = cm.pos.y + 150, z = cm.pos.z } local ret = (vec3f_dist(pos, mPos1) < radius or vec3f_dist(pos, mPos2) < radius) - network_player_local_restore_lag_state() return ret end diff --git a/mods/arena/arena-proj-cannon-ball.lua b/mods/arena/arena-proj-cannon-ball.lua index 371d838f..8a10be7c 100644 --- a/mods/arena/arena-proj-cannon-ball.lua +++ b/mods/arena/arena-proj-cannon-ball.lua @@ -18,17 +18,17 @@ function bhv_arena_cannon_ball_init(obj) end function bhv_arena_cannon_ball_intersects_local(obj, pos) - local ownerNp = network_player_from_global_index(obj.oArenaBobombGlobalOwner) - network_player_local_set_lag_state(ownerNp) + local cm = gMarioStates[0] + if gMarioStates[0].playerIndex == 0 then + cm = lag_compensation_get_local_state(ownerNp) + end - local m = gMarioStates[0] - local mPos1 = { x = m.pos.x, y = m.pos.y + 50, z = m.pos.z } - local mPos2 = { x = m.pos.x, y = m.pos.y + 150, z = m.pos.z } + local mPos1 = { x = cm.pos.x, y = cm.pos.y + 50, z = cm.pos.z } + local mPos2 = { x = cm.pos.x, y = cm.pos.y + 150, z = cm.pos.z } local radius = clamp(obj.oArenaCannonBallSize * 250, 75, 250) local ret = (vec3f_dist(pos, mPos1) < radius or vec3f_dist(pos, mPos2) < radius) - network_player_local_restore_lag_state() return ret end diff --git a/src/game/game_init.c b/src/game/game_init.c index dbfa334c..09769583 100644 --- a/src/game/game_init.c +++ b/src/game/game_init.c @@ -389,6 +389,14 @@ void adjust_analog_stick(struct Controller *controller) { controller->stickY *= 64 / controller->stickMag; controller->stickMag = 64; } + + /*extern bool gDebugToggle; + if (gDebugToggle) { + controller->stickX = 64; + controller->stickY = 0; + controller->stickMag = 64; + }*/ + } // if a demo sequence exists, this will run the demo diff --git a/src/game/interaction.c b/src/game/interaction.c index 609f7cef..aa861d8f 100644 --- a/src/game/interaction.c +++ b/src/game/interaction.c @@ -29,6 +29,7 @@ #include "pc/configfile.h" #include "pc/network/network.h" +#include "pc/network/lag_compensation.h" #include "pc/lua/smlua_hooks.h" #include "pc/cheats.h" @@ -1412,39 +1413,38 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim) // make sure it passes pvp checks before rollback if (!passes_pvp_interaction_checks(attacker, victim)) { return FALSE; } - // set my local player to the state I was in when they attacked + // grab the lag compensation version of the victim + struct MarioState* cVictim = NULL; if (victim->playerIndex == 0) { - network_player_local_set_lag_state(&gNetworkPlayers[victim->playerIndex]); + cVictim = lag_compensation_get_local_state(&gNetworkPlayers[attacker->playerIndex]); } + if (cVictim == NULL) { cVictim = victim; } // make sure we overlap f32 overlapScale = (attacker->playerIndex == 0) ? 0.6f : 1.0f; - if (!detect_player_hitbox_overlap(attacker, victim, overlapScale)) { - network_player_local_restore_lag_state(); + if (!detect_player_hitbox_overlap(attacker, cVictim, overlapScale)) { return FALSE; } // see if it was an attack - u32 interaction = determine_interaction(attacker, victim->marioObj); - if (!(interaction & INT_ANY_ATTACK) || (interaction & INT_HIT_FROM_ABOVE) || !passes_pvp_interaction_checks(attacker, victim)) { - network_player_local_restore_lag_state(); + u32 interaction = determine_interaction(attacker, cVictim->marioObj); + if (!(interaction & INT_ANY_ATTACK) || (interaction & INT_HIT_FROM_ABOVE) || !passes_pvp_interaction_checks(attacker, cVictim)) { return FALSE; } // call the lua hook bool allow = true; - smlua_call_event_hooks_mario_params_ret_bool(HOOK_ALLOW_PVP_ATTACK, attacker, victim, &allow); + smlua_call_event_hooks_mario_params_ret_bool(HOOK_ALLOW_PVP_ATTACK, attacker, cVictim, &allow); if (!allow) { // Lua blocked the interaction - network_player_local_restore_lag_state(); return FALSE; } // determine if slide attack should be ignored - if ((interaction & INT_ATTACK_SLIDE) || player_is_sliding(victim)) { + if ((interaction & INT_ATTACK_SLIDE) || player_is_sliding(cVictim)) { // determine the difference in velocities Vec3f velDiff; - vec3f_dif(velDiff, attacker->vel, victim->vel); + vec3f_dif(velDiff, attacker->vel, cVictim->vel); if (attacker->action == ACT_SLIDE_KICK_SLIDE || attacker->action == ACT_SLIDE_KICK) { // if the difference vectors are not different enough, do not attack @@ -1455,14 +1455,9 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim) } // if the victim is going faster, do not attack - if (vec3f_length(victim->vel) > vec3f_length(attacker->vel)) { return FALSE; } + if (vec3f_length(cVictim->vel) > vec3f_length(attacker->vel)) { return FALSE; } } - // restore to current state - u32 victimAction = victim->action; - u32 victimFlags = victim->flags; - network_player_local_restore_lag_state(); - // determine if ground pound should be ignored if (attacker->action == ACT_GROUND_POUND) { // not moving down yet? @@ -1473,7 +1468,7 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim) if (victim->playerIndex == 0) { victim->interactObj = attacker->marioObj; if (interaction & INT_KICK) { - if (victimAction == ACT_FIRST_PERSON) { + if (victim->action == ACT_FIRST_PERSON) { // without this branch, the player will be stuck in first person raise_background_noise(2); set_camera_mode(victim->area->camera, -1, 1); @@ -1481,7 +1476,7 @@ u32 interact_player_pvp(struct MarioState* attacker, struct MarioState* victim) } set_mario_action(victim, ACT_FREEFALL, 0); } - if (!(victimFlags & MARIO_METAL_CAP)) { + if (!(victim->flags & MARIO_METAL_CAP)) { attacker->marioObj->oDamageOrCoinValue = determine_player_damage_value(interaction); if (attacker->flags & MARIO_METAL_CAP) { attacker->marioObj->oDamageOrCoinValue *= 2; } } @@ -2250,7 +2245,6 @@ void mario_process_interactions(struct MarioState *m) { if (&gMarioStates[i] == m) { continue; } interact_player_pvp(m, &gMarioStates[i]); } - network_player_local_restore_lag_state(); } if (m->invincTimer > 0 && !sDelayInvincTimer) { diff --git a/src/pc/lua/smlua_functions_autogen.c b/src/pc/lua/smlua_functions_autogen.c index 8a3b549a..4ee608e5 100644 --- a/src/pc/lua/smlua_functions_autogen.c +++ b/src/pc/lua/smlua_functions_autogen.c @@ -20,6 +20,7 @@ #include "src/game/sound_init.h" #include "src/pc/djui/djui_hud_utils.h" #include "src/pc/network/network_player.h" +#include "src/pc/network/lag_compensation.h" #include "include/behavior_table.h" #include "src/pc/lua/utils/smlua_obj_utils.h" #include "src/pc/lua/utils/smlua_misc_utils.h" @@ -12643,6 +12644,57 @@ int smlua_func_take_damage_and_knock_back(lua_State* L) { return 1; } + //////////////////////// + // lag_compensation.h // +//////////////////////// + +int smlua_func_lag_compensation_clear(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "lag_compensation_clear", 0, top); + return 0; + } + + + lag_compensation_clear(); + + return 1; +} + +int smlua_func_lag_compensation_get_local_state(lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 1) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "lag_compensation_get_local_state", 1, top); + return 0; + } + + struct NetworkPlayer* otherNp = (struct NetworkPlayer*)smlua_to_cobject(L, 1, LOT_NETWORKPLAYER); + if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "lag_compensation_get_local_state"); return 0; } + + smlua_push_object(L, LOT_MARIOSTATE, lag_compensation_get_local_state(otherNp)); + + return 1; +} + +int smlua_func_lag_compensation_store(UNUSED lua_State* L) { + if (L == NULL) { return 0; } + + int top = lua_gettop(L); + if (top != 0) { + LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "lag_compensation_store", 0, top); + return 0; + } + + + lag_compensation_store(); + + return 1; +} + ////////////////// // level_info.h // ////////////////// @@ -18659,38 +18711,6 @@ int smlua_func_network_player_from_global_index(lua_State* L) { return 1; } -int smlua_func_network_player_local_restore_lag_state(UNUSED lua_State* L) { - if (L == NULL) { return 0; } - - int top = lua_gettop(L); - if (top != 0) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_player_local_restore_lag_state", 0, top); - return 0; - } - - - network_player_local_restore_lag_state(); - - return 1; -} - -int smlua_func_network_player_local_set_lag_state(lua_State* L) { - if (L == NULL) { return 0; } - - int top = lua_gettop(L); - if (top != 1) { - LOG_LUA_LINE("Improper param count for '%s': Expected %u, Received %u", "network_player_local_set_lag_state", 1, top); - return 0; - } - - struct NetworkPlayer* otherNp = (struct NetworkPlayer*)smlua_to_cobject(L, 1, LOT_NETWORKPLAYER); - if (!gSmLuaConvertSuccess) { LOG_LUA("Failed to convert parameter %u for function '%s'", 1, "network_player_local_set_lag_state"); return 0; } - - network_player_local_set_lag_state(otherNp); - - return 1; -} - int smlua_func_network_player_palette_to_color(lua_State* L) { if (L == NULL) { return 0; } @@ -29910,6 +29930,11 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "passes_pvp_interaction_checks", smlua_func_passes_pvp_interaction_checks); smlua_bind_function(L, "take_damage_and_knock_back", smlua_func_take_damage_and_knock_back); + // lag_compensation.h + smlua_bind_function(L, "lag_compensation_clear", smlua_func_lag_compensation_clear); + smlua_bind_function(L, "lag_compensation_get_local_state", smlua_func_lag_compensation_get_local_state); + smlua_bind_function(L, "lag_compensation_store", smlua_func_lag_compensation_store); + // level_info.h smlua_bind_function(L, "get_level_name", smlua_func_get_level_name); smlua_bind_function(L, "get_level_name_ascii", smlua_func_get_level_name_ascii); @@ -30174,8 +30199,6 @@ void smlua_bind_functions_autogen(void) { smlua_bind_function(L, "network_player_color_to_palette", smlua_func_network_player_color_to_palette); smlua_bind_function(L, "network_player_connected_count", smlua_func_network_player_connected_count); smlua_bind_function(L, "network_player_from_global_index", smlua_func_network_player_from_global_index); - smlua_bind_function(L, "network_player_local_restore_lag_state", smlua_func_network_player_local_restore_lag_state); - smlua_bind_function(L, "network_player_local_set_lag_state", smlua_func_network_player_local_set_lag_state); smlua_bind_function(L, "network_player_palette_to_color", smlua_func_network_player_palette_to_color); smlua_bind_function(L, "network_player_set_description", smlua_func_network_player_set_description); diff --git a/src/pc/network/lag_compensation.c b/src/pc/network/lag_compensation.c new file mode 100644 index 00000000..8c15c2ae --- /dev/null +++ b/src/pc/network/lag_compensation.c @@ -0,0 +1,59 @@ +#include "types.h" +#include "network_player.h" +#include "lag_compensation.h" +#include "pc/debuglog.h" +#include "game/object_helpers.h" +#include "behavior_table.h" +#include "model_ids.h" + +#define MAX_LOCAL_STATE_HISTORY 20 +struct StateHistory { + struct MarioState m; + struct Object marioObj; + struct MarioBodyState bodyState; +}; + +static struct StateHistory sLocalStateHistory[MAX_LOCAL_STATE_HISTORY] = { 0 }; +static bool sLocalStateHistoryReady = false; +static u32 sLocalStateHistoryIndex = 0; + +void lag_compensation_clear(void) { + sLocalStateHistoryReady = false; + sLocalStateHistoryIndex = 0; +} + +void lag_compensation_store(void) { + if (!gMarioStates[0].marioBodyState) { return; } + if (!gMarioStates[0].marioObj) { return; } + + struct StateHistory* sh = &sLocalStateHistory[sLocalStateHistoryIndex]; + memcpy(&sh->m, &gMarioStates[0], sizeof(struct MarioState)); + memcpy(&sh->marioObj, gMarioStates[0].marioObj, sizeof(struct Object)); + memcpy(&sh->bodyState, gMarioStates[0].marioBodyState, sizeof(struct MarioBodyState)); + sh->m.marioObj = &sh->marioObj; + sh->m.marioBodyState = &sh->bodyState; + + if (sLocalStateHistoryIndex + 1 >= MAX_LOCAL_STATE_HISTORY) { + sLocalStateHistoryReady = true; + } + sLocalStateHistoryIndex = (sLocalStateHistoryIndex + 1) % MAX_LOCAL_STATE_HISTORY; +} + +struct MarioState* lag_compensation_get_local_state(struct NetworkPlayer* otherNp) { + if (!otherNp) { return NULL; } + if (gNetworkType == NT_NONE) { return NULL; } + if (!sLocalStateHistoryReady) { return NULL; } + + s32 pingToTicks = (otherNp->ping / 1000.0f) * 30; + if (pingToTicks > (MAX_LOCAL_STATE_HISTORY-1)) { + pingToTicks = (MAX_LOCAL_STATE_HISTORY-1); + } + //LOG_INFO("Ping: %s :: %u :: %d", otherNp->name, otherNp->ping, pingToTicks); + if (pingToTicks == 0) { return NULL; } + + s32 index = (s32)sLocalStateHistoryIndex - pingToTicks; + while (index < 0) { index += MAX_LOCAL_STATE_HISTORY; } + index = index % MAX_LOCAL_STATE_HISTORY; + + return &sLocalStateHistory[index].m; +} diff --git a/src/pc/network/lag_compensation.h b/src/pc/network/lag_compensation.h new file mode 100644 index 00000000..427ed112 --- /dev/null +++ b/src/pc/network/lag_compensation.h @@ -0,0 +1,8 @@ +#ifndef NETWORK_LAG_COMPENSATION_H +#define NETWORK_LAG_COMPENSATION_H + +void lag_compensation_clear(void); +void lag_compensation_store(void); +struct MarioState* lag_compensation_get_local_state(struct NetworkPlayer* otherNp); + +#endif \ No newline at end of file diff --git a/src/pc/network/network_player.c b/src/pc/network/network_player.c index 2b190baf..8bbcdd9a 100644 --- a/src/pc/network/network_player.c +++ b/src/pc/network/network_player.c @@ -10,32 +10,19 @@ #include "game/hardcoded.h" #include "game/object_helpers.h" #include "pc/lua/smlua_hooks.h" +#include "lag_compensation.h" struct NetworkPlayer gNetworkPlayers[MAX_PLAYERS] = { 0 }; struct NetworkPlayer *gNetworkPlayerLocal = NULL; struct NetworkPlayer *gNetworkPlayerServer = NULL; static char sDefaultPlayerName[] = "Player"; -#define MAX_LOCAL_PLAYER_STATES 20 -struct LagState { - struct MarioState m; - struct MarioBodyState bodyState; -}; - -static struct LagState sLocalPlayerStates[MAX_LOCAL_PLAYER_STATES] = { 0 }; -static struct LagState sLocalPlayerTmpState = { 0 }; -static bool sLocalPlayerTmpStateSet = false; -static bool sLocalPlayerStatesReady = false; -static u32 sLocalPlayerStateIndex = 0; - void network_player_init(void) { gNetworkPlayers[0].modelIndex = (configPlayerModel < CT_MAX) ? configPlayerModel : 0; gNetworkPlayers[0].palette = configPlayerPalette; gNetworkPlayers[0].overrideModelIndex = gNetworkPlayers[0].modelIndex; gNetworkPlayers[0].overridePalette = gNetworkPlayers[0].palette; - sLocalPlayerTmpStateSet = false; - sLocalPlayerStatesReady = false; - sLocalPlayerStateIndex = 0; + lag_compensation_clear(); } void network_player_update_model(u8 localIndex) { @@ -160,55 +147,8 @@ void network_player_palette_to_color(struct NetworkPlayer *np, enum PlayerParts out[2] = np->palette.parts[part][2]; } -static void network_player_local_save_state(void) { - if (!gMarioStates[0].marioBodyState) { return; } - - memcpy(&sLocalPlayerStates[sLocalPlayerStateIndex].m, &gMarioStates[0], sizeof(struct MarioState)); - memcpy(&sLocalPlayerStates[sLocalPlayerStateIndex].bodyState, gMarioStates[0].marioBodyState, sizeof(struct MarioBodyState)); - - if (sLocalPlayerStateIndex + 1 >= MAX_LOCAL_PLAYER_STATES) { - sLocalPlayerStatesReady = true; - } - sLocalPlayerStateIndex = (sLocalPlayerStateIndex + 1) % MAX_LOCAL_PLAYER_STATES; -} - -void network_player_local_set_lag_state(struct NetworkPlayer* otherNp) { - if (!otherNp) { return; } - if (gNetworkType == NT_NONE) { return; } - if (!sLocalPlayerStatesReady) { return; } - - s32 pingToTicks = (otherNp->ping / 1000.0f) * 30; - pingToTicks += 2; - if (pingToTicks > (MAX_LOCAL_PLAYER_STATES-1)) { - pingToTicks = (MAX_LOCAL_PLAYER_STATES-1); - } - if (pingToTicks == 0) { return; } - - s32 index = (s32)sLocalPlayerStateIndex - pingToTicks; - while (index < 0) { index += MAX_LOCAL_PLAYER_STATES; } - index = index % MAX_LOCAL_PLAYER_STATES; - - memcpy(&sLocalPlayerTmpState.m, &gMarioStates[0], sizeof(struct MarioState)); - memcpy(&sLocalPlayerTmpState.bodyState, gMarioStates[0].marioBodyState, sizeof(struct MarioBodyState)); - - memcpy(&gMarioStates[0], &sLocalPlayerStates[index].m, sizeof(struct MarioState)); - memcpy(gMarioStates[0].marioBodyState, &sLocalPlayerStates[index].bodyState, sizeof(struct MarioBodyState)); - - sLocalPlayerTmpStateSet = true; -} - -void network_player_local_restore_lag_state(void) { - if (!sLocalPlayerTmpStateSet) { return; } - - memcpy(&gMarioStates[0], &sLocalPlayerTmpState.m, sizeof(struct MarioState)); - memcpy(gMarioStates[0].marioBodyState, &sLocalPlayerTmpState.bodyState, sizeof(struct MarioBodyState)); - - sLocalPlayerTmpStateSet = false; -} - void network_player_update(void) { - network_player_local_save_state(); - network_player_local_restore_lag_state(); + lag_compensation_store(); for (s32 i = 0; i < MAX_PLAYERS; i++) { struct NetworkPlayer *np = &gNetworkPlayers[i]; diff --git a/src/pc/network/network_player.h b/src/pc/network/network_player.h index e8ea12b6..3a365054 100644 --- a/src/pc/network/network_player.h +++ b/src/pc/network/network_player.h @@ -79,9 +79,6 @@ struct NetworkPlayer* get_network_player_smallest_global(void); void network_player_color_to_palette(struct NetworkPlayer *np, enum PlayerParts part, Color color); void network_player_palette_to_color(struct NetworkPlayer *np, enum PlayerParts part, Color out); -void network_player_local_set_lag_state(struct NetworkPlayer* otherNp); -void network_player_local_restore_lag_state(void); - void network_player_update(void); u8 network_player_connected(enum NetworkPlayerType type, u8 globalIndex, u8 modelIndex, const struct PlayerPalette* playerPalette, char* name);