Fix formatting
parent
c231ee4e3e
commit
da27d7f64c
|
@ -35,7 +35,7 @@ Inverse of `get_rotation`.
|
|||
|
||||
```lua
|
||||
moblib.register_entity(name, {
|
||||
initial_properties = {...},
|
||||
initial_properties = {...},
|
||||
lua_properties = {
|
||||
moveresult = {
|
||||
collisions = nil,
|
||||
|
|
492
main.lua
492
main.lua
|
@ -1,327 +1,327 @@
|
|||
storage = minetest.get_mod_storage()
|
||||
entities_by_id = setmetatable({}, {__mode = "v"})
|
||||
objects_by_id = setmetatable({}, {
|
||||
__index = function(_, id)
|
||||
local entity = entities_by_id[id]
|
||||
return entity and entity.object
|
||||
end,
|
||||
__newindex = function(self, id, object)
|
||||
local luaentity = object:get_luaentity()
|
||||
if luaentity then
|
||||
entities_by_id[id] = luaentity
|
||||
else
|
||||
self[id] = object
|
||||
end
|
||||
end,
|
||||
__index = function(_, id)
|
||||
local entity = entities_by_id[id]
|
||||
return entity and entity.object
|
||||
end,
|
||||
__newindex = function(self, id, object)
|
||||
local luaentity = object:get_luaentity()
|
||||
if luaentity then
|
||||
entities_by_id[id] = luaentity
|
||||
else
|
||||
self[id] = object
|
||||
end
|
||||
end,
|
||||
__mode = "v"
|
||||
})
|
||||
|
||||
local highest_id = storage:get_int("highest_id")
|
||||
|
||||
minetest.register_on_joinplayer(function(player)
|
||||
-- INFO no need to check whether it's an entity
|
||||
rawset(objects_by_id, player:get_player_name(), player)
|
||||
-- INFO no need to check whether it's an entity
|
||||
rawset(objects_by_id, player:get_player_name(), player)
|
||||
end)
|
||||
|
||||
minetest.register_on_leaveplayer(function(player)
|
||||
objects_by_id[player:get_player_name()] = nil
|
||||
objects_by_id[player:get_player_name()] = nil
|
||||
end)
|
||||
|
||||
function get_id(object)
|
||||
if object:is_player() then
|
||||
return object:get_player_name()
|
||||
end
|
||||
local luaentity = object:get_luaentity()
|
||||
if luaentity and luaentity._ then
|
||||
return luaentity._.id
|
||||
end
|
||||
if object:is_player() then
|
||||
return object:get_player_name()
|
||||
end
|
||||
local luaentity = object:get_luaentity()
|
||||
if luaentity and luaentity._ then
|
||||
return luaentity._.id
|
||||
end
|
||||
end
|
||||
|
||||
function get_object(id)
|
||||
return objects_by_id[id]
|
||||
return objects_by_id[id]
|
||||
end
|
||||
|
||||
function get_entity(id)
|
||||
return entities_by_id[id]
|
||||
return entities_by_id[id]
|
||||
end
|
||||
|
||||
-- x/z-rotation
|
||||
local function horizontal_rotation(direction)
|
||||
return math.atan2(direction.y, math.sqrt(direction.x*direction.x + direction.z*direction.z))
|
||||
return math.atan2(direction.y, math.sqrt(direction.x*direction.x + direction.z*direction.z))
|
||||
end
|
||||
|
||||
-- y-rotation
|
||||
local function vertical_rotation(direction)
|
||||
return -math.atan2(direction.x, direction.z)
|
||||
return -math.atan2(direction.x, direction.z)
|
||||
end
|
||||
|
||||
-- gets rotation in radians for a z-facing object
|
||||
function get_rotation(direction)
|
||||
return {
|
||||
x = horizontal_rotation(direction),
|
||||
y = vertical_rotation(direction),
|
||||
z = 0
|
||||
}
|
||||
return {
|
||||
x = horizontal_rotation(direction),
|
||||
y = vertical_rotation(direction),
|
||||
z = 0
|
||||
}
|
||||
end
|
||||
|
||||
-- converts a rotation from -pi to pi to 2pi to 0
|
||||
function convert_rotation(rotation)
|
||||
return vector.apply(rotation, function(c)
|
||||
if c < 0 then
|
||||
return 2*math.pi + c
|
||||
end
|
||||
return c
|
||||
end)
|
||||
return vector.apply(rotation, function(c)
|
||||
if c < 0 then
|
||||
return 2*math.pi + c
|
||||
end
|
||||
return c
|
||||
end)
|
||||
end
|
||||
|
||||
-- shorthand
|
||||
function get_converted_rotation(direction)
|
||||
return convert_rotation(get_rotation(direction))
|
||||
return convert_rotation(get_rotation(direction))
|
||||
end
|
||||
|
||||
-- normalizes a rotation
|
||||
function normalize_rotation(rotation)
|
||||
return vector.apply(rotation, function(c)
|
||||
local nc = c % (2*math.pi)
|
||||
if c < 0 then
|
||||
return 2*math.pi + nc
|
||||
end
|
||||
return nc
|
||||
end)
|
||||
return vector.apply(rotation, function(c)
|
||||
local nc = c % (2*math.pi)
|
||||
if c < 0 then
|
||||
return 2*math.pi + nc
|
||||
end
|
||||
return nc
|
||||
end)
|
||||
end
|
||||
|
||||
function get_minimum_converted_rotation_difference(rotation, other_rotation)
|
||||
return vector.apply(vector.subtract(rotation, other_rotation), function(c)
|
||||
if c > math.pi then
|
||||
return -2*math.pi + c
|
||||
end
|
||||
if c < -math.pi then
|
||||
return 2*math.pi + c
|
||||
end
|
||||
return c
|
||||
end)
|
||||
return vector.apply(vector.subtract(rotation, other_rotation), function(c)
|
||||
if c > math.pi then
|
||||
return -2*math.pi + c
|
||||
end
|
||||
if c < -math.pi then
|
||||
return 2*math.pi + c
|
||||
end
|
||||
return c
|
||||
end)
|
||||
end
|
||||
|
||||
-- gets rotation in radians for a wielditem (such as a sword)
|
||||
function get_wield_rotation(direction)
|
||||
return {
|
||||
x = 0,
|
||||
y = 1.5*math.pi+vertical_rotation(direction),
|
||||
z = 1.25*math.pi+horizontal_rotation(direction)
|
||||
}
|
||||
return {
|
||||
x = 0,
|
||||
y = 1.5*math.pi+vertical_rotation(direction),
|
||||
z = 1.25*math.pi+horizontal_rotation(direction)
|
||||
}
|
||||
end
|
||||
|
||||
-- gets the direction for a rotated vector (0, 0, 1), inverse of get_rotation
|
||||
function get_direction(rotation)
|
||||
local rx, ry = rotation.x, rotation.y
|
||||
local direction = {}
|
||||
-- x rotation
|
||||
direction.y = math.sin(rx)
|
||||
local z = math.cos(rx)
|
||||
-- y rotation
|
||||
direction.x = -(z * math.sin(ry))
|
||||
direction.z = z * math.cos(ry)
|
||||
return direction
|
||||
local rx, ry = rotation.x, rotation.y
|
||||
local direction = {}
|
||||
-- x rotation
|
||||
direction.y = math.sin(rx)
|
||||
local z = math.cos(rx)
|
||||
-- y rotation
|
||||
direction.x = -(z * math.sin(ry))
|
||||
direction.z = z * math.cos(ry)
|
||||
return direction
|
||||
end
|
||||
|
||||
function set_look_dir(player, direction)
|
||||
local rotation = get_rotation(direction)
|
||||
player:set_look_vertical(-rotation.x)
|
||||
player:set_look_horizontal(rotation.y)
|
||||
local rotation = get_rotation(direction)
|
||||
player:set_look_vertical(-rotation.x)
|
||||
player:set_look_horizontal(rotation.y)
|
||||
end
|
||||
|
||||
function get_eye_pos(object)
|
||||
local eye_pos = object:get_pos()
|
||||
if object:is_player() then
|
||||
eye_pos.y = eye_pos.y + object:get_properties().eye_height
|
||||
end
|
||||
return eye_pos
|
||||
local eye_pos = object:get_pos()
|
||||
if object:is_player() then
|
||||
eye_pos.y = eye_pos.y + object:get_properties().eye_height
|
||||
end
|
||||
return eye_pos
|
||||
end
|
||||
|
||||
function get_center(object)
|
||||
local collisionbox = object:get_properties().collisionbox
|
||||
return vector.add(object:get_pos(), vector.divide(vector.add(vector.new(collisionbox[1], collisionbox[2], collisionbox[3]), vector.new(unpack(collisionbox, 4))), 2))
|
||||
local collisionbox = object:get_properties().collisionbox
|
||||
return vector.add(object:get_pos(), vector.divide(vector.add(vector.new(collisionbox[1], collisionbox[2], collisionbox[3]), vector.new(unpack(collisionbox, 4))), 2))
|
||||
end
|
||||
|
||||
function get_mass(object)
|
||||
local entity = object:get_luaentity()
|
||||
if entity and entity._mass then
|
||||
return entity._mass
|
||||
end
|
||||
local collisionbox = object:get_properties().collisionbox
|
||||
local mass = (collisionbox[4] - collisionbox[1]) * (collisionbox[5] - collisionbox[2]) * (collisionbox[6] - collisionbox[3])
|
||||
assert(mass > 0)
|
||||
return mass
|
||||
local entity = object:get_luaentity()
|
||||
if entity and entity._mass then
|
||||
return entity._mass
|
||||
end
|
||||
local collisionbox = object:get_properties().collisionbox
|
||||
local mass = (collisionbox[4] - collisionbox[1]) * (collisionbox[5] - collisionbox[2]) * (collisionbox[6] - collisionbox[3])
|
||||
assert(mass > 0)
|
||||
return mass
|
||||
end
|
||||
|
||||
function calculate_damage(object, time_since_last_punch, caps)
|
||||
local damage = 0
|
||||
local armor_groups = assert(object:get_armor_groups()) -- object has to be alive
|
||||
for group, group_damage in pairs(caps.damage_groups) do
|
||||
damage = damage + group_damage * (armor_groups[group] or 0) / 100
|
||||
end
|
||||
return damage * math.min(1, math.max(0, time_since_last_punch / caps.full_punch_interval))
|
||||
local damage = 0
|
||||
local armor_groups = assert(object:get_armor_groups()) -- object has to be alive
|
||||
for group, group_damage in pairs(caps.damage_groups) do
|
||||
damage = damage + group_damage * (armor_groups[group] or 0) / 100
|
||||
end
|
||||
return damage * math.min(1, math.max(0, time_since_last_punch / caps.full_punch_interval))
|
||||
end
|
||||
|
||||
-- TODO implement physics such as air resistance
|
||||
local engine_has_moveresult = minetest.has_feature("object_step_has_moveresult")
|
||||
local sensitivity = 0.01
|
||||
function register_entity(name, def)
|
||||
local props = def.lua_properties
|
||||
def.lua_properties = nil
|
||||
local on_activate = def.on_activate or function() end
|
||||
local on_step = def.on_step or function() end
|
||||
local terminal_speed = props.terminal_speed
|
||||
if terminal_speed then
|
||||
local old_on_step = on_step
|
||||
function on_step(self, dtime, ...)
|
||||
old_on_step(self, dtime, ...)
|
||||
local obj = self.object
|
||||
local vel = obj:get_velocity()
|
||||
if not vel then return end -- object has been deleted
|
||||
local len = vector.length(obj:get_velocity())
|
||||
if len > terminal_speed then
|
||||
obj:set_velocity(vector.multiply(vector.divide(vel, len)))
|
||||
end
|
||||
end
|
||||
end
|
||||
local props = def.lua_properties
|
||||
def.lua_properties = nil
|
||||
local on_activate = def.on_activate or function() end
|
||||
local on_step = def.on_step or function() end
|
||||
local terminal_speed = props.terminal_speed
|
||||
if terminal_speed then
|
||||
local old_on_step = on_step
|
||||
function on_step(self, dtime, ...)
|
||||
old_on_step(self, dtime, ...)
|
||||
local obj = self.object
|
||||
local vel = obj:get_velocity()
|
||||
if not vel then return end -- object has been deleted
|
||||
local len = vector.length(obj:get_velocity())
|
||||
if len > terminal_speed then
|
||||
obj:set_velocity(vector.multiply(vector.divide(vel, len)))
|
||||
end
|
||||
end
|
||||
end
|
||||
local props_staticdata = props.staticdata
|
||||
if props_staticdata then
|
||||
local implementation
|
||||
if type(props_staticdata) == "table" then
|
||||
implementation = props_staticdata
|
||||
else
|
||||
implementation = ({
|
||||
json = {
|
||||
serializer = minetest.write_json,
|
||||
deserializer = minetest.parse_json
|
||||
},
|
||||
lua = {
|
||||
serializer = minetest.serialize,
|
||||
deserializer = minetest.deserialize
|
||||
}
|
||||
})[props_staticdata]
|
||||
end
|
||||
local serializer = implementation.serializer
|
||||
local deserializer = implementation.deserializer
|
||||
local old_on_activate = on_activate
|
||||
function on_activate(self, staticdata, dtime)
|
||||
self._ = (staticdata ~= "" and deserializer(staticdata)) or {}
|
||||
old_on_activate(self, staticdata, dtime)
|
||||
end
|
||||
function def.get_staticdata(self)
|
||||
return serializer(self._)
|
||||
end
|
||||
end
|
||||
if props.id then
|
||||
assert(props_staticdata)
|
||||
local old_on_activate = on_activate
|
||||
function on_activate(self, staticdata, dtime)
|
||||
if not self._.id then
|
||||
highest_id = highest_id + 1
|
||||
self._.id = highest_id
|
||||
storage:set_int("highest_id", highest_id)
|
||||
end
|
||||
entities_by_id[self._.id] = self
|
||||
local implementation
|
||||
if type(props_staticdata) == "table" then
|
||||
implementation = props_staticdata
|
||||
else
|
||||
implementation = ({
|
||||
json = {
|
||||
serializer = minetest.write_json,
|
||||
deserializer = minetest.parse_json
|
||||
},
|
||||
lua = {
|
||||
serializer = minetest.serialize,
|
||||
deserializer = minetest.deserialize
|
||||
}
|
||||
})[props_staticdata]
|
||||
end
|
||||
local serializer = implementation.serializer
|
||||
local deserializer = implementation.deserializer
|
||||
local old_on_activate = on_activate
|
||||
function on_activate(self, staticdata, dtime)
|
||||
self._ = (staticdata ~= "" and deserializer(staticdata)) or {}
|
||||
old_on_activate(self, staticdata, dtime)
|
||||
end
|
||||
end
|
||||
-- TODO consider HACK for #10158
|
||||
if props.moveresult then
|
||||
-- localizing variables for performance reasons
|
||||
local mr = props.moveresult
|
||||
local mr_collisions = mr.collisions
|
||||
local mr_axes = mr.axes
|
||||
local mr_old_velocity = mr.old_velocity
|
||||
local mr_acc_dependent = mr.acceleration_dependent
|
||||
local mr_speed_diff = mr.speed_difference
|
||||
local mr_moblib = mr.moblib
|
||||
local old_on_activate = on_activate
|
||||
function on_activate(self, staticdata, dtime)
|
||||
old_on_activate(self, staticdata, dtime)
|
||||
self._last_velocity = self.object:get_velocity()
|
||||
end
|
||||
local old_on_step = on_step
|
||||
function on_step(self, dtime, moveresult)
|
||||
local obj = self.object
|
||||
if engine_has_moveresult and not mr_acc_dependent and not mr_moblib then
|
||||
if moveresult.collides then
|
||||
if mr_axes then
|
||||
local axes = {}
|
||||
for _, collision in ipairs(moveresult.collisions) do
|
||||
axes[collision.axis] = true
|
||||
end
|
||||
moveresult.axes = axes
|
||||
end
|
||||
if mr_old_velocity then
|
||||
if not moveresult.collisions[1] then
|
||||
moveresult.old_velocity = self._last_velocity
|
||||
else
|
||||
moveresult.old_velocity = moveresult.collisions[1].old_velocity
|
||||
end
|
||||
end
|
||||
if mr_speed_diff then
|
||||
local expected_vel = vector.add(self._last_velocity, vector.multiply(obj:get_acceleration(), dtime))
|
||||
moveresult.speed_difference = vector.length(vector.subtract(expected_vel, obj:get_velocity()))
|
||||
end
|
||||
end
|
||||
else
|
||||
moveresult = {collides = false}
|
||||
if self._last_velocity then
|
||||
local expected_vel = vector.add(self._last_velocity, vector.multiply(obj:get_acceleration(), dtime))
|
||||
local velocity = obj:get_velocity()
|
||||
local diff = vector.subtract(expected_vel, velocity)
|
||||
local speed_difference = vector.length(diff)
|
||||
local collides = speed_difference >= sensitivity
|
||||
moveresult.collides = collides
|
||||
if collides then
|
||||
if mr_speed_diff then
|
||||
moveresult.speed_difference = speed_difference
|
||||
end
|
||||
if mr_collisions then
|
||||
local collisions = {}
|
||||
diff = vector.apply(diff, math.abs)
|
||||
local new_velocity = self._last_velocity
|
||||
for axis, component_diff in pairs(diff) do
|
||||
if component_diff > sensitivity then
|
||||
new_velocity[axis] = velocity[axis]
|
||||
table.insert(collisions, {
|
||||
axis = axis,
|
||||
old_velocity = self._last_velocity,
|
||||
new_velocity = new_velocity
|
||||
})
|
||||
end
|
||||
end
|
||||
moveresult.collisions = collisions
|
||||
end
|
||||
if mr_axes then
|
||||
local axes = {}
|
||||
diff = vector.apply(diff, math.abs)
|
||||
for axis, component_diff in pairs(diff) do
|
||||
if component_diff > sensitivity then
|
||||
axes[axis] = true
|
||||
end
|
||||
end
|
||||
moveresult.axes = axes
|
||||
end
|
||||
if mr_old_velocity then
|
||||
moveresult.old_velocity = self._last_velocity
|
||||
end
|
||||
if mr_acc_dependent then
|
||||
moveresult.acceleration_dependent = vector.length(vector.subtract(self._last_velocity, velocity)) < sensitivity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
old_on_step(self, dtime, moveresult)
|
||||
self._last_velocity = obj:get_velocity()
|
||||
end
|
||||
function def._set_velocity(self, velocity)
|
||||
self.object:set_velocity(velocity)
|
||||
self._last_velocity = velocity
|
||||
end
|
||||
end
|
||||
def.on_activate = on_activate
|
||||
def.on_step = on_step
|
||||
minetest.register_entity(name, def)
|
||||
end
|
||||
function def.get_staticdata(self)
|
||||
return serializer(self._)
|
||||
end
|
||||
end
|
||||
if props.id then
|
||||
assert(props_staticdata)
|
||||
local old_on_activate = on_activate
|
||||
function on_activate(self, staticdata, dtime)
|
||||
if not self._.id then
|
||||
highest_id = highest_id + 1
|
||||
self._.id = highest_id
|
||||
storage:set_int("highest_id", highest_id)
|
||||
end
|
||||
entities_by_id[self._.id] = self
|
||||
old_on_activate(self, staticdata, dtime)
|
||||
end
|
||||
end
|
||||
-- TODO consider HACK for #10158
|
||||
if props.moveresult then
|
||||
-- localizing variables for performance reasons
|
||||
local mr = props.moveresult
|
||||
local mr_collisions = mr.collisions
|
||||
local mr_axes = mr.axes
|
||||
local mr_old_velocity = mr.old_velocity
|
||||
local mr_acc_dependent = mr.acceleration_dependent
|
||||
local mr_speed_diff = mr.speed_difference
|
||||
local mr_moblib = mr.moblib
|
||||
local old_on_activate = on_activate
|
||||
function on_activate(self, staticdata, dtime)
|
||||
old_on_activate(self, staticdata, dtime)
|
||||
self._last_velocity = self.object:get_velocity()
|
||||
end
|
||||
local old_on_step = on_step
|
||||
function on_step(self, dtime, moveresult)
|
||||
local obj = self.object
|
||||
if engine_has_moveresult and not mr_acc_dependent and not mr_moblib then
|
||||
if moveresult.collides then
|
||||
if mr_axes then
|
||||
local axes = {}
|
||||
for _, collision in ipairs(moveresult.collisions) do
|
||||
axes[collision.axis] = true
|
||||
end
|
||||
moveresult.axes = axes
|
||||
end
|
||||
if mr_old_velocity then
|
||||
if not moveresult.collisions[1] then
|
||||
moveresult.old_velocity = self._last_velocity
|
||||
else
|
||||
moveresult.old_velocity = moveresult.collisions[1].old_velocity
|
||||
end
|
||||
end
|
||||
if mr_speed_diff then
|
||||
local expected_vel = vector.add(self._last_velocity, vector.multiply(obj:get_acceleration(), dtime))
|
||||
moveresult.speed_difference = vector.length(vector.subtract(expected_vel, obj:get_velocity()))
|
||||
end
|
||||
end
|
||||
else
|
||||
moveresult = {collides = false}
|
||||
if self._last_velocity then
|
||||
local expected_vel = vector.add(self._last_velocity, vector.multiply(obj:get_acceleration(), dtime))
|
||||
local velocity = obj:get_velocity()
|
||||
local diff = vector.subtract(expected_vel, velocity)
|
||||
local speed_difference = vector.length(diff)
|
||||
local collides = speed_difference >= sensitivity
|
||||
moveresult.collides = collides
|
||||
if collides then
|
||||
if mr_speed_diff then
|
||||
moveresult.speed_difference = speed_difference
|
||||
end
|
||||
if mr_collisions then
|
||||
local collisions = {}
|
||||
diff = vector.apply(diff, math.abs)
|
||||
local new_velocity = self._last_velocity
|
||||
for axis, component_diff in pairs(diff) do
|
||||
if component_diff > sensitivity then
|
||||
new_velocity[axis] = velocity[axis]
|
||||
table.insert(collisions, {
|
||||
axis = axis,
|
||||
old_velocity = self._last_velocity,
|
||||
new_velocity = new_velocity
|
||||
})
|
||||
end
|
||||
end
|
||||
moveresult.collisions = collisions
|
||||
end
|
||||
if mr_axes then
|
||||
local axes = {}
|
||||
diff = vector.apply(diff, math.abs)
|
||||
for axis, component_diff in pairs(diff) do
|
||||
if component_diff > sensitivity then
|
||||
axes[axis] = true
|
||||
end
|
||||
end
|
||||
moveresult.axes = axes
|
||||
end
|
||||
if mr_old_velocity then
|
||||
moveresult.old_velocity = self._last_velocity
|
||||
end
|
||||
if mr_acc_dependent then
|
||||
moveresult.acceleration_dependent = vector.length(vector.subtract(self._last_velocity, velocity)) < sensitivity
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
old_on_step(self, dtime, moveresult)
|
||||
self._last_velocity = obj:get_velocity()
|
||||
end
|
||||
function def._set_velocity(self, velocity)
|
||||
self.object:set_velocity(velocity)
|
||||
self._last_velocity = velocity
|
||||
end
|
||||
end
|
||||
def.on_activate = on_activate
|
||||
def.on_step = on_step
|
||||
minetest.register_entity(name, def)
|
||||
end
|
Loading…
Reference in New Issue