1 local minetest,math,vector,ipairs,tonumber = minetest,math,vector,ipairs,tonumber
3 local movement_class = {} -- controls all data of the movement
4 local player_movement_data = {} -- used to calculate player movement
5 local player_state_channels = {} -- holds every player's channel
6 movement_pointer = {} -- allows other mods to index local data
7 movement_class.input_data = nil
8 movement_class.hunger = nil
9 movement_class.data = nil
10 movement_class.data_list = nil
11 movement_class.count = nil
12 movement_class.name = nil
13 movement_class.env_data = nil
14 movement_class.channel_decyphered = nil
15 movement_class.in_water = nil
16 movement_class.get_group = minetest.get_item_group
17 movement_class.get_connected = minetest.get_connected_players
18 movement_class.ipairs = ipairs
19 movement_class.get_by_name = minetest.get_player_by_name
21 -- creates volitile data for the game to use
22 movement_class.create_movement_variables = function(player)
23 movement_class.name = player:get_player_name()
24 if not player_movement_data[movement_class.name] then
25 player_movement_data[movement_class.name] = {
34 -- sets data for the game to use
35 movement_class.set_data = function(player,data)
36 movement_class.name = player:get_player_name()
37 if player_movement_data[movement_class.name] then
38 for index,i_data in pairs(data) do
39 if player_movement_data[movement_class.name][index] ~= nil then
40 player_movement_data[movement_class.name][index] = i_data
44 movement_class.create_movement_variables(player)
48 -- retrieves data for the game to use
49 movement_class.get_data = function(player)
50 movement_class.name = player:get_player_name()
51 if player_movement_data[movement_class.name] then
53 state = player_movement_data[movement_class.name].state ,
54 old_state = player_movement_data[movement_class.name].old_state ,
55 was_in_water = player_movement_data[movement_class.name].was_in_water,
56 swimming = player_movement_data[movement_class.name].swimming ,
61 -- removes movement data
62 movement_class.terminate = function(player)
63 movement_class.name = player:get_player_name()
64 if player_movement_data[movement_class.name] then
65 player_movement_data[movement_class.name] = nil
69 -- creates specific channels for players
70 minetest.register_on_joinplayer(function(player)
71 movement_class.name = player:get_player_name()
72 player_state_channels[movement_class.name] = minetest.mod_channel_join(movement_class.name..":player_movement_state")
73 player:set_physics_override({
77 movement_class.create_movement_variables(player)
80 -- resets the player's state on death
81 minetest.register_on_respawnplayer(function(player)
82 movement_class.set_data(player,{
86 movement_class.send_running_cancellation(player,false)
90 -- delete data on player leaving
91 minetest.register_on_leaveplayer(function(player)
92 movement_class.terminate(player)
95 -- tells the client to stop sending running/bunnyhop data
96 movement_class.send_running_cancellation = function(player,sneaking)
97 movement_class.name = player:get_player_name()
98 player_state_channels[movement_class.name]:send_all(
106 -- intercept incoming data messages
107 minetest.register_on_modchannel_message(function(channel_name, sender, message)
108 movement_class.channel_decyphered = channel_name:gsub(sender,"")
109 if sender ~= "" and movement_class.channel_decyphered == ":player_movement_state" then
110 movement_class.data = tonumber(message)
111 if type(movement_class.data) == "number" then
112 movement_class.set_data(movement_class.get_by_name(sender),{
113 state = movement_class.data
119 -- allows other mods to set data for the game to use
120 movement_pointer.set_data = function(player,data)
121 movement_class.name = player:get_player_name()
122 if player_movement_data[movement_class.name] then
123 for index,i_data in pairs(data) do
124 if player_movement_data[movement_class.name][index] ~= nil then
125 player_movement_data[movement_class.name][index] = i_data
129 movement_class.create_movement_variables(player)
133 -- allows other mods to retrieve data for the game to use
134 movement_pointer.get_data = function(player,requested_data)
135 movement_class.name = player:get_player_name()
136 if player_movement_data[movement_class.name] then
137 movement_class.data_list = {}
138 movement_class.count = 0
139 for index,i_data in pairs(requested_data) do
140 if player_movement_data[movement_class.name][i_data] ~= nil then
141 movement_class.data_list[i_data] = player_movement_data[movement_class.name][i_data]
142 movement_class.count = movement_class.count + 1
145 if movement_class.count > 0 then
146 return(movement_class.data_list)
155 -- controls player states
156 movement_class.control_state = function(player)
157 movement_class.hunger = hunger_pointer.get_data(player,{"hunger"}).hunger
158 movement_class.data = movement_class.get_data(player)
159 -- water movement data
160 movement_class.env_data = environment_pointer.get_data(player,{"legs","head"})
161 movement_class.in_water = {at_all=false,head=false,legs=false}
162 if movement_class.env_data then
163 movement_class.in_water.legs = movement_class.get_group(movement_class.env_data.legs,"water") > 0
164 movement_class.in_water.head = movement_class.get_group(movement_class.env_data.head,"water") > 0
165 if movement_class.in_water.legs or movement_class.in_water.head then
166 movement_class.in_water.at_all = true
167 movement_class.set_data(player,{swimming=true})
169 movement_class.set_data(player,{swimming=false})
173 if (movement_class.in_water.at_all ~= movement_class.data.was_in_water) or
174 (movement_class.data.state ~= movement_class.data.old_state) or
175 ((movement_class.data.state == 1 or movement_class.data.state == 2) and movement_class.hunger and movement_class.hunger <= 6) then
178 if not movement_class.in_water.at_all and movement_class.data.was_in_water then
179 player:set_physics_override({
182 player_pointer.force_update(player)
183 player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
184 player_pointer.set_data(player,{
185 collisionbox = {-0.3, 0.0, -0.3, 0.3, 1.7, 0.3},
187 elseif movement_class.in_water.at_all and not movement_class.data.was_in_water then
188 player:set_physics_override({
192 player_pointer.force_update(player)
193 player:set_eye_offset({x=0,y=-6,z=0},{x=0,y=-6,z=5.9})
194 player_pointer.set_data(player,{
195 collisionbox = {-0.3, 0.5, -0.3, 0.3, 1.2, 0.3},
199 -- running/swimming fov modifier
200 if movement_class.hunger and movement_class.hunger > 6 and (movement_class.data.state == 1 or movement_class.data.state == 2) then
201 player:set_fov(1.25, true, 0.15)
202 if movement_class.data.state == 2 then
203 player:set_physics_override({speed=1.75})
204 elseif movement_class.data.state == 1 then
205 player:set_physics_override({speed=1.5})
207 elseif (not movement_class.in_water.at_all and movement_class.data.state ~= 1 and movement_class.data.state ~= 2 and
208 (movement_class.data.old_state == 1 or movement_class.data.old_state == 2)) or
209 (movement_class.in_water.at_all and movement_class.data.state ~= 1 and movement_class.data.state ~= 2 and movement_class.data.state ~= 3 and
210 (movement_class.data.old_state == 1 or movement_class.data.old_state == 2 or movement_class.data.old_state == 3))then
212 player:set_fov(1, true,0.15)
213 player:set_physics_override({speed=1})
215 movement_class.send_running_cancellation(player,movement_class.data.state==3) --preserve network data
217 elseif (movement_class.data.state == 1 or movement_class.data.state == 2) and (movement_class.hunger and movement_class.hunger <= 6) then
218 player:set_fov(1, true,0.15)
219 player:set_physics_override({speed=1})
220 movement_class.send_running_cancellation(player,false) --preserve network data
224 if movement_class.data.state == 3 and movement_class.in_water.at_all then
225 movement_class.send_running_cancellation(player,false)
226 elseif not movement_class.in_water.at_all and movement_class.data.state == 3 and movement_class.data.old_state ~= 3 then
227 player:set_eye_offset({x=0,y=-1,z=0},{x=0,y=-1,z=0})
228 elseif not movement_class.in_water.at_all and movement_class.data.old_state == 3 and movement_class.data.state ~= 3 then
229 player:set_eye_offset({x=0,y=0,z=0},{x=0,y=0,z=0})
232 movement_class.set_data(player,{
233 old_state = movement_class.data.state,
234 was_in_water = movement_class.in_water.at_all
238 elseif movement_class.in_water.at_all then
239 if not movement_class.data.was_in_water then
240 player:set_physics_override({
243 player:set_velocity(vector.new(0,0,0))
246 movement_class.set_data(player,{
247 old_state = movement_class.data.state,
248 was_in_water = movement_class.in_water.at_all
253 minetest.register_globalstep(function(dtime)
254 for _,player in movement_class.ipairs(movement_class.get_connected()) do
255 movement_class.control_state(player)