From d77f31eab895eb274a61f3dfb1dbcf1e43e5d731 Mon Sep 17 00:00:00 2001 From: cora Date: Mon, 13 Sep 2021 23:45:53 +0200 Subject: [PATCH 1/2] Only set/send player properties if necessary Before this patch, Mineclonia set (and therefore sent) player bone positions and player properties in every globalstep. This results in about 30 TOCLIENT_ACTIVE_OBJECT_MESSAGE per second per player. This patch adds conditional functions to set bone positions and properties. The functions set values only when they have changed, reducing traffic. --- mods/PLAYER/mcl_playerplus/init.lua | 89 +++++++++++++++++++++-------- 1 file changed, 66 insertions(+), 23 deletions(-) diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index 73e799a3..ef7a14e9 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -19,8 +19,51 @@ end local pitch, name, node_stand, node_stand_below, node_head, node_feet, pos -minetest.register_globalstep(function(dtime) +local function roundN(n, d) + if type(n) ~= "number" then return n end + local m = 10^d + return math.floor(n * m + 0.5) / m +end +local function close_enough(a,b) + local rt=true + if type(a) == "table" and type(b) == "table" then + for k,v in pairs(a) do + if roundN(v,2) ~= roundN(b[k],2) then + rt=false + break + end + end + else + rt = roundN(a,2) == roundN(b,2) + end + return rt +end + +local function set_properties_conditional(player,props) + local oldprops=player:get_properties() + local changed=true + local p={} + for k,v in pairs(props) do + if not close_enough(v,oldprops[k]) then + p[k]=v + changed=true + end + end + if changed then + player:set_properties(p) + end +end + +local function set_bone_position_conditional(player,b,p,r) --bone,position,rotation + local oldp,oldr=player:get_bone_position(b) + if vector.equals(vector.round(oldp),vector.round(p)) and vector.equals(vector.round(oldr),vector.round(r)) then + return + end + player:set_bone_position(b,p,r) +end + +minetest.register_globalstep(function(dtime) time = time + dtime -- Update jump status immediately since we need this info in real time. @@ -45,55 +88,55 @@ minetest.register_globalstep(function(dtime) -- controls right and left arms pitch when shooting a bow or punching if string.find(player:get_wielded_item():get_name(), "mcl_bows:bow") and controls.RMB and not controls.LMB and not controls.up and not controls.down and not controls.left and not controls.right then - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch+90,-30,pitch * -1 * .35)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3.5,5.785,0), vector.new(pitch+90,43,pitch * .35)) elseif controls.LMB and player:get_attach() == nil then - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(pitch,0,0)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) else - player:set_bone_position("Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) - player:set_bone_position("Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Arm_Left_Pitch_Control", vector.new(3,5.785,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Arm_Right_Pitch_Control", vector.new(-3,5.785,0), vector.new(0,0,0)) end if controls.sneak and player:get_attach() == nil then -- controls head pitch when sneaking - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+36,0,0)) + set_bone_position_conditional(player,"Head", vector.new(0,6.3,0), vector.new(pitch+36,0,0)) -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }}) + set_properties_conditional(player,{collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 0, g = 225 }}) -- sneaking body conrols - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) elseif minetest.get_item_group(mcl_playerinfo[name].node_head, "water") ~= 0 and player:get_attach() == nil and mcl_sprint.is_sprinting(name) == true then -- set head pitch and yaw when swimming - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch+90-degrees(dir_to_pitch(player_velocity)),yaw - player_vel_yaw * -1,0)) + set_bone_position_conditional(player,"Head", vector.new(0,6.3,0), vector.new(pitch+90-degrees(dir_to_pitch(player_velocity)),yaw - player_vel_yaw * -1,0)) -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + set_properties_conditional(player,{collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) -- control body bone when swimming - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,player_vel_yaw * -1 - yaw + 180,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(degrees(dir_to_pitch(player_velocity)) - 90,player_vel_yaw * -1 - yaw + 180,0)) elseif player:get_attach() == nil then -- sets eye height, and nametag color accordingly - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + set_properties_conditional(player,{collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) if player_velocity.x > 0.35 or player_velocity.z > 0.35 or player_velocity.x < -0.35 or player_velocity.z < -0.35 then if player_vel_yaw * -1 - yaw < 90 or player_vel_yaw * -1 - yaw > 270 then -- controls head and Body_Control bones while moving backwards - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,yaw - player_vel_yaw * -1,0)) - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,player_vel_yaw * -1 - yaw,0)) + set_bone_position_conditional(player,"Head", vector.new(0,6.3,0), vector.new(pitch,yaw - player_vel_yaw * -1,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0,player_vel_yaw * -1 - yaw,0)) else -- controls head and Body_Control bones while moving forwards - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,yaw - player_vel_yaw * -1 + 180,0)) - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,player_vel_yaw * -1 - yaw + 180,0)) + set_bone_position_conditional(player,"Head", vector.new(0,6.3,0), vector.new(pitch,yaw - player_vel_yaw * -1 + 180,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0,player_vel_yaw * -1 - yaw + 180,0)) end else - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,0,0)) - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) + set_bone_position_conditional(player,"Head", vector.new(0,6.3,0), vector.new(pitch,0,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) end else local attached = player:get_attach(parent) local attached_yaw = degrees(attached:get_yaw()) - player:set_properties({collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) - player:set_bone_position("Head", vector.new(0,6.3,0), vector.new(pitch,degrees(player:get_look_horizontal()) * -1 + attached_yaw,0)) - player:set_bone_position("Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) + set_properties_conditional(player,{collisionbox = {-0.35,0,-0.35,0.35,1.8,0.35}, eye_height = 1.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }}) + set_bone_position_conditional(player,"Head", vector.new(0,6.3,0), vector.new(pitch,degrees(player:get_look_horizontal()) * -1 + attached_yaw,0)) + set_bone_position_conditional(player,"Body_Control", vector.new(0,6.3,0), vector.new(0,0,0)) end if mcl_playerplus_internal[name].jump_cooldown > 0 then From 5deaabdb47454fa3b198d6a28a891bb87f31e545 Mon Sep 17 00:00:00 2001 From: cora Date: Wed, 8 Dec 2021 22:48:14 +0100 Subject: [PATCH 2/2] Fix player bone positions and properties setting The comparison and setting logic in the previous patch that set player bone positions and properties conditionally incorrectly did not update some values (like player eye level position) when they changed. This patch fixes it and adds asserts to ensure the code works as intended. --- mods/PLAYER/mcl_playerplus/init.lua | 69 +++++++++++++++++++++++++++-- 1 file changed, 66 insertions(+), 3 deletions(-) diff --git a/mods/PLAYER/mcl_playerplus/init.lua b/mods/PLAYER/mcl_playerplus/init.lua index ef7a14e9..a7dba3b0 100644 --- a/mods/PLAYER/mcl_playerplus/init.lua +++ b/mods/PLAYER/mcl_playerplus/init.lua @@ -40,9 +40,10 @@ local function close_enough(a,b) return rt end -local function set_properties_conditional(player,props) - local oldprops=player:get_properties() - local changed=true + + +local function props_changed(props,oldprops) + local changed=false local p={} for k,v in pairs(props) do if not close_enough(v,oldprops[k]) then @@ -50,6 +51,68 @@ local function set_properties_conditional(player,props) changed=true end end + return changed,p +end + +--test if assert works +assert(true) +assert(not false) + +--test data for == and ~= +local test_equal1=42 +local test_equal2=42.0 +local test_equal3=42.1 + +assert(test_equal1==test_equal1) +assert(test_equal1==test_equal2) +assert(test_equal1~=test_equal3) + +--testdata for roundN +local test_round1=15 +local test_round2=15.00199999999 +local test_round3=15.00111111 +local test_round4=15.00999999 + +assert(roundN(test_round1,2)==roundN(test_round1,2)) --test again if basic equality works because wth not +assert(roundN(test_round1,2)==roundN(test_round2,2)) +assert(roundN(test_round1,2)==roundN(test_round3,2)) +assert(roundN(test_round1,2)~=roundN(test_round4,2)) + + +-- tests for close_enough +local test_cb = {-0.35,0,-0.35,0.35,0.8,0.35} --collisionboxes +local test_cb_close = {-0.351213,0,-0.35,0.35,0.8,0.351212} +local test_cb_diff = {-0.35,0,-1.35,0.35,0.8,0.35} + +local test_eh = 1.65 --eye height +local test_eh_close = 1.65123123 +local test_eh_diff = 1.35 + +local test_nt = { r = 225, b = 225, a = 225, g = 225 } --nametag +local test_nt_diff = { r = 225, b = 225, a = 0, g = 225 } + +assert(close_enough(test_cb,test_cb_close)) +assert(not close_enough(test_cb,test_cb_diff)) + +assert(close_enough(test_eh,test_eh_close)) +assert(not close_enough(test_eh,test_eh_diff)) + +assert(not close_enough(test_nt,test_nt_diff)) --no floats involved here + +--tests for props_changed +local test_properties_set1={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 0.65, nametag_color = { r = 225, b = 225, a = 225, g = 225 }} +local test_properties_set2={collisionbox = {-0.35,0,-0.35,0.35,0.8,0.35}, eye_height = 1.35, nametag_color = { r = 225, b = 225, a = 225, g = 225 }} + +local test_p1,p=props_changed(test_properties_set1,test_properties_set1) +local test_p2,p=props_changed(test_properties_set1,test_properties_set2) + +assert(not test_p1) +assert(test_p2) + +-- we still don't really know if lua is lying to us! but at least everything *seems* to be ok + +local function set_properties_conditional(player,props) + local changed,p=props_changed(props,player:get_properties()) if changed then player:set_properties(p) end