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);