-----------------‐--------------------------------------------------------------------------------- -- Advanced Vehicles II API by Andrey01 -----‐--------------------------------------------------------------------------------------------- --GLOBAL TABLE vehicles = {} --------------------------------------------------------------------------- -- Constants --------------------------------------------------------------------------- vehicles.gravity = -9.8 -- gravity constant vehicles.air_rfac = 0.3 -- air resistance factor --------------------------------------------------------------------------- -- Dynamic Tables --------------------------------------------------------------------------- vehicles.showed_fspecs = {} -- pair: ["playername"] and {self, formname, [invname, invlist]} vehicles.ngroups_friction_coefs = { -- friction coefficients of some groups of nodes. ["sand"] = 1.5, ["soil"] = 0.6, ["snowy"] = 0.9, ["slippery"] = 0.1, ["default"] = 0.8 } -----‐--------------------------------------------------------------------- -- API functions --------------------------------------------------------------------------- vehicles.set_gravity = function(self) local obj = self.object local acc = obj:get_acceleration() local vel = obj:get_velocity() local m = minetest.registered_entities[self.name].mass obj:set_acceleration({x=acc.x, y=vehicles.gravity, z=acc.z}) end --[[ Registers new vehicle (base and wheel) base_props and wheel_props should contain def props for entity ('obj') and its item ('item') ]] vehicles.register_vehicle = function(name, base_props, wheel_props) minetest.register_entity(MOD_NAME .. ":" .. name .. "_base", { vehicle_type = base_props.obj.vehicle_type, physical = true, mass = base_props.obj.mass or 2000, -- in kgs collide_with_objects = true, collisionbox = base_props.obj.bounding_box or {-0.5, 0.0, -0.5, 0.5, 1.0, 0.5}, selectionbox = base_props.obj.bounding_box or {-0.5, 0.0, -0.5, 0.5, 1.0, 0.5}, visual = base_props.obj.visual, visual_size = base_props.obj.visual_size or {x=1, y=1, z=1}, mesh = (base_props.obj.visual == "mesh" and base_props.obj.mesh), textures = base_props.obj.textures or {""}, use_texture_alpha = base_props.obj.use_texture_alpha, seats = base_props.obj.seats, -- table fields: {["is_busy"] = playername, [dplayer_obj] = ObjectRef, ["pos"] = position, ["rot"] = rotation, ["getout_coords"] = coords from seat, ["type"] = ("driver" or "passenger"), ["model"] = } --ctrl_vals = base_props.ctrl_vals, -- table fields: {["move"] = float (acc_len), ["turn"] = float (degs)} traction_force = base_props.obj.traction_force or 5000, -- in Neutons trunk_inv = base_props.obj.trunk_inv wheels = base_props.obj.wheels, -- table fields: {["type"] = ("front" or "rear"), ["pos"] = position, ["rot"] = rotation, ["radius"] = wheel radius} max_speed = base_props.obj.max_speed or 25000, -- in m/s compartments_edge = base_props.obj.compartments_edge -- rough edge between the base body and the trunk along local Z-axis (num) stepheight = base_props.obj.stepheight or 0.5, on_activate = function(self, staticdata, dtime_s) self.seats = table.copy(base_props.obj.seats) local vehpos = self.object:get_pos() for i, seat in ipairs(self.seats) do seat.rot = seat.rot or {x=0, y=0, z=0} seat.radius = seat.radius or 0.5 end self.wheels = {} self.move_dir = 0 -- specifies direction of the vehicle movement (1 is forward, -1 is backward) self.tracf = 0 -- specifies direction of the traction force and contains its value (> 0 is forward, < 0 is backward, =0 is stay) -- Create detached inventory of the vehicle trunk if base_props.obj.trunk_inv then local tr_inv = base_props.obj.trunk_inv self.trunk_inv = #self.trunk_inv > 0 and self.trunk_inv or {} minetest.create_detached_inventory(tr_inv.name, { allow_move = function(inv, from_list, from_index, to_list, to_index, count, player) return count end, allow_put = function(inv, listname, index, stack, player) return stack:get_count() end, allow_take = function(inv, listname, index, stack, player) return stack:get_count() end }) local inv = minetest.get_inventory({type="detached", name=tr_inv.name}) inv:set_size(tr_inv.listname, tr_inv.listsize.w*tr_inv.listsize.h) inv:set_list(tr_inv.listname, self.trunk_inv) end local vehrot = self.object:get_rotation() for i, whl in ipairs(base_props.obj.wheels) do local whl_obj = minetest.add_entity({x=vehpos.x+whl.pos.x, y=vehpos.y+whl.pos.y, z=vehpos.z+whl.pos.z}, MOD_NAME .. ":" .. name .. "_wheel") whl_obj:set_attach(self.object, "", whl.pos, whl.rot or {0, 0, 0}) self.wheels[i] = {object=whl_obj, type=whl.type, pos=whl.pos, rot=whl.rot or {0, 0, 0}, radius=whl.radius} end vehicles.set_gravity(self) end, on_step = function(self, dtime) local drv_name = self.seats[vehicles.get_driver_i(self)].is_busy if drv_name then local player = minetest.get_player_by_name(drv_name) local ctrls = player:get_player_control() if ctrls.up then minetest.debug("Going forward...") self.move_dir = 1 self.tracf = 1 end if ctrls.down then minetest.debug("Going backward...") self.move_dir = -1 self.tracf = -1 end if not ctrls.up and not ctrls.down then minetest.debug("Stopping...") self.tracf = 0 end end local v3d_v = self.object:get_velocity() local v2d_v = {x=v3d_v.x, y=0, z=v3d_v.z} --minetest.debug("yaw: " .. self.object:get_yaw()) --minetest.debug("velocity: " .. dump(v3d_v)) local v2d_vl = vehicles.v2d_length(v2d_v) if v2d_vl < 0.4 and v2d_vl > 0 and self.tracf == 0 then minetest.debug("Stopped!") self.move_dir = 0 end local yaw = self.object:get_yaw() local entity_def = minetest.registered_entities[self.name] local tdir_v = vehicles.v2d_coords(self.tracf*entity_def.traction_force, yaw) tdir_v.y = 0 local max_fcoef = vehicles.max_fric_coef(self) local unit_v2d_v = vector.normalize(v2d_v) unit_v2d_v = vehicles.check_for_nan(unit_v2d_v) local sf_fforce = (math.abs(vehicles.gravity)*entity_def.mass)*max_fcoef*(-self.move_dir) -- surface friction force local sf_fforce_v = vector.multiply(unit_v2d_v, sf_fforce) sf_fforce_v = vehicles.check_for_nan(sf_fforce_v) local air_rforce = v2d_vl^2 * vehicles.air_rfac * (-self.move_dir) -- air resistance force local air_rforce_v = vector.multiply(unit_v2d_v, air_rforce) air_rforce_v = vehicles.check_for_nan(air_rforce_v) if self.move_dir == 0 then minetest.debug("tdir_v: " .. dump(tdir_v)) minetest.debug("sf_fforce_v: " .. dump(sf_fforce_v)) minetest.debug("air_rforce_v: " .. dump(air_rforce_v)) end --[[if self.tracf_dir ~= 0 then minetest.debug("self.tracf_dir: " .. self.tracf_dir) minetest.debug("sf_fforce: " .. sf_fforce) minetest.debug("air_rforce: " .. air_rforce) end]] --[[minetest.debug("tdir_v: " .. dump(tdir_v)) minetest.debug("sf_fforce: " .. sf_fforce) minetest.debug("sf_fforce_v: " .. dump(sf_fforce_v)) minetest.debug("air_rforce: " .. dump(air_rforce)) minetest.debug("air_rforce_v: " .. dump(air_rforce_v)) minetest.debug("tdir_v+sf_fforce_v: " .. dump(vector.add(tdir_v, sf_fforce_v))) minetest.debug("(tdir_v+sf_fforce_v)+air_rforce_v: " .. dump(vector.add(vector.add(tdir_v, sf_fforce_v), air_rforce_v))) minetest.debug("((tdir_v+sf_fforce_v)+air_rforce_v)/edef.mass: " .. dump(vector.divide(vector.add(vector.add(tdir_v, sf_fforce_v), air_rforce_v), edef.mass)))]] local acc = vector.divide(vector.add(vector.add(tdir_v, sf_fforce_v), air_rforce_v), entity_def.mass) acc.y = vehicles.gravity self.object:set_acceleration(acc}) for i, d in ipairs(self.wheels) do d.object:set_rotation({x=vehicles.calc_angle_vel(vehicles.v2d_length(self.object:get_velocity()), d.radius)*dtime, y=0, z=0}) --minetest.debug("wheels rotation: " .. dump(d.object:get_rotation())) end end, on_death = function(self, killer) for pn, f in pairs(self.showed_fspecs) do vehicles.close_compartments_menu(self, pn) end for i, sdata in ipairs(self.seats) do if sdata.is_busy then vehicles.get_out(self, sdata.dplayer_obj:get_luaentity(), i) end end for i, whl in ipairs(self.wheels) do whl.object:remove() end end, on_rightclick = function(self, clicker) local vel = self.object:get_velocity() if vector.length(vel) ~= 0 then minetest.chat_send_player(clicker:get_player_name(), "The vehicle needs to be stopped at first!") return end local is_player_sit = vehicles.is_player_sit(clicker) if is_player_sit then vehicles.show_cabin_formspec(self, clicker:get_player_name()) else vehicles.show_compartments_menu(self, clicker:get_player_name()) end --[[local pos = self.object:get_pos() local range = minetest.registered_items[""].range local ray_vec = vector.new(0, 0, range) ray_vec = vector.rotate(ray_vec, {x=clicker:get_look_vertical(), y=clicker:get_look_horizontal(), z=0}) local ray = minetest.raycast(pos, vehicles.convert_pos_to_absolute(pos, ray_vec), true) for pointed_thing in ray do if pointed_thing.ref == self.object then local compart_edge = minetest.registered_entities[self.name].compartments_edge vehicles.show_seats_formspec(self, MOD_NAME .. ":vehicle_seats", clicker:get_player_name())]] end }) minetest.register_craftitem(MOD_NAME .. ":" .. name .. "_base", { description = base_props.item.description or "", inventory_image = base_props.item.inv_image or "", on_place = function(itemstack, placer, pointed_thing) if pointed_thing.type =="node" and pointed_thing.above.y >= pointed_thing.under.y then minetest.add_entity(pointed_thing.above, itemstack:get_name()) end end }) minetest.register_entity(MOD_NAME .. ":" .. name .. "_wheel", { visual_size = wheel_props.obj.visual_size or {x=1, y=1, z=1}, pointable = false, visual = wheel_props.obj.visual, mesh = (wheel_props.obj.visual == "mesh" and wheel_props.obj.mesh), textures = wheel_props.obj.textures or {""}, use_texture_alpha = wheel_props.obj.use_texture_alpha }) minetest.register_craftitem(MOD_NAME .. ":" .. name .. "_wheel", { description = wheel_props.item.description or "", inventory_image = wheel_props.item.inventory_image or "" }) if base_props.obj.player_mdefs then if base_props.obj.player_mdefs.driver then player_api.register_model(base_props.obj.player_mdefs.driver.model_name, base_props.obj.player_mdefs.driver.def) elseif base_props.obj.player_mdefs.passenger then player_api.register_model(base_props.obj.player_mdefs.passenger.model_name, base_props.obj.player_mdefs.passenger.def) end end end vehicles.show_compartments_menu = function(self, playername) local formspec = "formspec_version[3]size[6,7.5]label[2.5,0.5;Open:]button[1,1.5;4,2;seats_cabin;Seats Cabin]" local trunk = minetest.registered_entities[self.name].trunk_inv if trunk then formspec = formspec .. "button[1,4.5;4,2;trunk;Trunk]" end vehicles.showed_fspecs[playername] = {self=self, formname=MOD_NAME .. ":compartments_menu"} minetest.show_formspec(playername, MOD_NAME .. ":compartments_menu", formspec) end vehicles.show_cabin_formspec = function(self, playername) local seats_n = #self.seats local sbut_size = {x=4, y=1.5} local pad = 0.5 local visible_cbuts_n = (seats_n <= 4 and seats_n or 4) local scontainer_size = {x=2*0.3 + sbut_size.x, y=visible_cbuts_n*sbut_size.y + (visible_cbuts_n+1)*0.3} local wsize_x = pad*2 + scontainer_size.x local is_player_sit = vehicles.is_player_sit(minetest.get_player_by_name(playername)) local wsize_y = 2 + scontainer_size.y + (is_player_sit and 2.5 or pad) -- + 2.5 units for 'Get Up' button placement local formspec = "formspec_version[3]size[" .. wsize_x .. ", " .. wsize_y .. "]" .. "label[" .. pad + 0.2 .. "," .. pad + 0.5 .. ";" .. minetest.formspec_escape("Select a seat to sit down or press to get up:") .. "]" .. "box[" .. pad .. ",2;" .. scontainer_size.x .. "," .. scontainer_size.y .. ";#000]" .. "scrollbaroptions[thumbsize=1000]" .. "scrollbar[" .. scontainer_size.x + pad .. ",2;0.3," .. scontainer_size.y .. ";vertical;vseats_scrollbar;0]" .. "scroll_container[" .. pad .. ",2;" .. scontainer_size.x .. "," .. scontainer_size.y .. ";vseats_scrollbar;vertical;]" local butpos_y = 0.3 for i, sdata in ipairs(self.seats) do local i_busy = sdata.is_busy formspec = formspec .. (i_busy and "style[seat_" .. i .. ";bgcolor=#FF0000]" or "") .. "button[0.3," .. butpos_y .. ";" .. sbut_size.x .. "," .. sbut_size.y .. ";seat_" .. i .. ";" .. minetest.formspec_escape("#" .. i .. ((i_busy and "\n(busy by " .. playername .. ")") or "")) .. "]" butpos_y = butpos_y + sbut_size.y + 0.3 end formspec = formspec .. "scroll_container_end[]" .. (is_player_sit and "button[" .. wsize_x/2 - sbut_size.x/2 .. "," .. (wsize_y - (2.5/4*3)) .. ";4,1.5;get_up;" .. minetest.formspec_escape("Get up") .. "]" or "") vehicles.showed_fspecs[playername] = {self=self, formname=MOD_NAME .. ":seats_cabin"} minetest.show_formspec(playername, MOD_NAME .. ":seats_cabin", formspec) end vehicles.show_trunk_formspec = function(self, playername, invname, listname, inv_size) local pad = 0.5 local slots_sp = 0.3 local wsize_x = pad*2 + slots_sp*(inv_size.w-1) + inv_size.w local wsize_y = pad*2 + slots_sp*(inv_size.h-1) + inv_size.h + 0.7 + 4 + 3*slots_sp local formspec = "formspec_version[3]size[" .. wsize_x .. "," .. wsize_y .. "]" .. "list[detached:" .. listname .. ";" .. pad .. "," .. pad .. ";" .. inv_size.w .. "," .. inv_size.h .. "]" .. "list[current_player;main;" .. pad .. "," .. (wsize_y - (4+3+slots_sp+pad)) .. ";8,4]" vehicles.showed_fspecs[playername] = {self=self, formname=MOD_NAME .. ":trunk", invname=invname, listname=listname} minetest.show_formspec(playername, MOD_NAME .. ":trunk", formspec) end vehicles.close_compartments_menu = function(self, playername, cabin_action) local fd = vehicles.showed_fspecs[playername] if fd.formname == MOD_NAME .. ":seats_cabin" then vehicles.close_seats_formspec(self, playername, fd.formname, cabin_action, vehicles.is_player_sit(minetest.get_player_by_name(playername))) elseif fd.formname == MOD_NAME .. ":trunk" then vehicles.close_trunk_formspec(self, playername, fd.formname, fd.invname, fd.listname) end minetest.close_formspec(playername, MOD_NAME .. ":compartments_menu") vehicles.showed_fspecs[playername] = nil end -- 'seat_id' is optional -- 'action' is supposed what to do with the player after closing (sit or go out off the vehicle) [optional] vehicles.close_seats_formspec = function(self, playername, formname, action, seat_id) local player = minetest.get_player_by_name(playername) if action == "sit" then minetest.debug("close_seats_formspec") local is_busy = self.seats[seat_id].is_busy if is_busy then return end vehicles.sit(self, player, seat_id) elseif action == "get_up" then minetest.debug(dump(self.seats[seat_id].dplayer_obj)) vehicles.get_out(self, self.seats[seat_id].dplayer_obj:get_luaentity(), seat_id) local getout_coords = self.seats[seat_id].getout_coords local yaw = self.object:get_yaw() local pos = self.object:get_pos() local player = minetest.get_player_by_name(playername) local rel_getout_pos = vector.rotate(vector.add(self.seats[seat_id].pos, getout_coords), {x=0, y=self.object:get_yaw(), z=0}) minetest.debug(dump(pos)) minetest.debug(dump(rel_getout_pos)) player:set_pos(vehicles.convert_pos_to_absolute(pos, rel_getout_pos)) local rand_look = {-90, 90} player:set_look_horizontal(yaw+rand_look[math.random(1, 2)]) end minetest.close_formspec(playername, formname) vehicles.showed_fspecs[playername] = nil end vehicles.close_trunk_formspec = function(self, playername, formname, inv_name, list_name) local self = self.object:get_luaentity() if self then local inv = minetest.get_inventory(type="detached", name=inv_name) self.trunk_inv = inv:get_list(list_name) end minetest.close_formspec(playername, formname) vehicles.showed_fspecs[playername] = nil end vehicles.sit = function(self, player, seat_id) -- seat_id is an id of a seat table of 'self.seats' local sel_seat = self.seats[seat_id] local plname = player:get_player_name() if type(sel_seat.is_busy) == "string" and sel_seat.is_busy ~= plname then minetest.chat_send_player(plname, "Seat #" .. seat_id .. " is busy by " .. sel_seat.is_busy .. "!") return end local cur_seat_i = vehicles.is_player_sit(player) if cur_seat_i then vehicles.get_out(self, self.seats[cur_seat_i].dplayer_obj:get_luaentity(), cur_seat_i) end sel_seat.is_busy = player:get_player_name() local dummy_player if sel_seat.type == "driver" then minetest.debug("adding_dummy_driver...") dummy_player = minetest.add_entity(vehicles.convert_pos_to_absolute(self.object:get_pos(), sel_seat.pos), MOD_NAME .. ":dummy_driver") minetest.debug("added_dummy_driver!") elseif sel_seat.type == "passenger" then dummy_player = minetest.add_entity(vehicles.convert_pos_to_absolute(self.object:get_pos(), sel_seat.pos), MOD_NAME .. ":dummy_passenger") end sel_seat.dplayer_obj = dummy_player dummy_player:set_attach(self.object, "", sel_seat.pos, {x=0, y=180, z=0}) minetest.debug("attaching_dummy_player...") player:set_attach(dummy_player, "", {x=0, y=0, z=0}, {x=0, y=0, z=0}) minetest.debug("dummy_player_attached!") local dplayer_self = dummy_player:get_luaentity() dplayer_self.attached_player = player dplayer_self.last_visual_size = player:get_properties().visual_size player:set_properties({visual_size = vector.new(0, 0, 0)}) player:set_look_horizontal(self.object:get_yaw()+180) end vehicles.get_out = function(self, dplayer, seat_id) if not dplayer.object or not dplayer.attached_player or not self.object:get_luaentity() then return end dplayer.object:set_detach() dplayer.attached_player:set_detach() dplayer.attached_player:set_properties({visual_size = dplayer.last_visual_size}) dplayer.object:remove() self.seats[seat_id].is_busy = nil self.seats[seat_id].dplayer_obj = nil end vehicles.on_formspec_event = function(player, formname, fields) local plname = player:get_player_name() local self = vehicles.showed_fspecs[player:get_player_name()].self if formname == MOD_NAME .. ":context_menu" then if fields.quit then vehicles.close_compartments_menu(self, plname) elseif fields. if formname ~= MOD_NAME .. ":vehicle_seats" or formname ~= MOD_NAME .. ":vehicle_trunk" then return end local plname = player:get_player_name() local obj = vehicles.showed_vehicle_fspecs[plname] local self = obj:get_luaentity() if self then for i, sdata in ipairs(self.seats) do local but_name = "seat_" .. i if fields[but_name] then vehicles.close_seats_formspec(self, plname, formname, "sit", i) return true end if fields["get_up"] then vehicles.close_seats_formspec(self, plname, formname, "get_up", i) return true end end if fields.quit then if formname == MOD_NAME .. ":vehicle_seats" then vehicles.close_seats_formspec(self, plname, formname) return true elseif formname == MOD_NAME .. ":vehicle_trunk" then local edef = minetest.registered_entities[self.name] vehicles.close_trunk_formspec(self, plname, formname, edef.trunk.name, edef.trunk.listname) return true end end else -- supposed that vehicle is died while the player is viewing the formspec if formname == MOD_NAME .. ":vehicle_seats" then vehicles.close_seats_formspec(self, plname, formname) elseif formname == MOD_NAME .. ":vehicle_trunk" then vehicles.close_trunk_formspec(self, plname, formname) end end end -------‐--------------------------------------------------------------------- -- Helper functions ----------------------------------------------------------------------------- -- Derives the elements from range 'i1' up to 'i2' of 't' table into new one -- i1 and i2 can be only positive -- NOTE: table keys can be not only integral table.derive_elems = function(t, i1, i2) local new_t = {} local elem_c = 0 for k, v in pairs(t) do elem_c = elem_c + 1 if elem_c > i2 then return new_t end new_t[k] = v end return new_t end -- Checks whether t[v] is nan and if yes, replaces to zero. Returns changed table vehicles.check_for_nan = function(t) for k, v in pairs(t) do if v ~= v then t[k] = 0 end end return t end vehicles.is_player_sit = function(player) local obj = player:get_attach() if not obj then return false end local self = obj:get_attach():get_luaentity() for i, sdata in pairs(self.seats) do if sdata.is_busy == player:get_player_name() then return i end end return false end -- Returns index in seats table where driver data is. vehicles.get_driver_i = function(self) if not self then return end for i, sdata in ipairs(self.seats) do if sdata.type == "driver" then return i end end return end -- Get sign of 'n' value vehicles.get_sign = function(n) if n == 0 then return 0 end return n/math.abs(n) end -- Calculates an angle speed (in rads) of the wheel vehicles.calc_angle_vel = function(vel_l, radius) return vel_l end -- Calculates new (relative) coords of the acceleration vector vehicles.v2d_coords = function(a_len, yaw) local x = -a_len * math.sin(yaw) local z = a_len * math.cos(yaw) return {x=x, z=z} end vehicles.v2d_length = function(v2d) return math.sqrt(v2d.x^2 + v2d.z^2) end -- Find out max friction coefficient of nodes locating beneath the entity vehicles.max_fric_coef = function(self) local max_friction_coef = 0 local vehpos = self.object:get_pos() for i, whl in ipairs(self.wheels) do local pos = whl.object:get_pos() pos = vehicles.convert_pos_to_absolute(vehpos, pos) local undernode = minetest.get_node({x=pos.x, y=pos.y-whl.radius-0.1, z=pos.z}) local group = vehicles.get_node_groupname(undernode.name) if max_friction_coef < vehicles.ngroups_friction_coefs[group] then max_friction_coef = vehicles.ngroups_friction_coefs[group] end end return max_friction_coef end -- Calculates a modulo of a friction force of the surface under the vehicle vehicles.surface_fric_force = function(fric_coef, mass) return fric_coef*mass*-vehicles.gravity end -- Convert the relative pos coords to absolute vehicles.convert_pos_to_absolute = function(origin, pos) return {x=origin.x+pos.x, y=origin.y+pos.y, z=origin.z+pos.z} end -- Convert the absolute pos coords to relative (relatively to 'origin') vehicles.convert_pos_to_relative = function(origin, pos) return {x=pos.x-origin.x, y=pos.y-origin.y, z=pos.z-origin.z} end -- Returns a node group that associated with its certain type (e.g. sand/desert sand are "sand" group, snow block/snow with grass are "snowy" group) vehicles.get_node_groupname = function(name) local groups = minetest.registered_nodes[name].groups --minetest.debug("nodename:" .. name) --minetest.debug("nodegroups:" .. dump(groups)) for group, coef in pairs(vehicles.ngroups_friction_coefs) do if groups[group] then return group end end return "default" end -- Calculates a modulo of an air resistance force (only along horizontal plane currently) vehicles.air_resist_force = function(v_l) return vehicles.air_rfac * math.abs(v_l)^2 end ----------------------------------------------------------------------------- -- Callback Registrations ----------------------------------------------------------------------------- minetest.register_on_player_receive_fields(vehicles.on_formspec_event) minetest.register_on_leaveplayer(function(obj, timed_out) local is_player_sit = vehicles.is_player_sit(obj:get_luaentity()) if is_player_sit then local self = obj:get_attach():get_attach():get_luaentity() vehicles.get_out(self, self.dplayer_obj:get_luaentity(), is_player_sit) end end)