mirror of
https://github.com/OgelGames/fakelib.git
synced 2025-01-04 23:30:35 +01:00
working version
This commit is contained in:
parent
3725d31125
commit
a5ad426c8a
47
init.lua
Normal file
47
init.lua
Normal file
@ -0,0 +1,47 @@
|
||||
|
||||
fakelib = {}
|
||||
|
||||
local function check(n, v, a, b)
|
||||
local t = type(v)
|
||||
if t == a or t == b then
|
||||
return v
|
||||
end
|
||||
local info = debug.getinfo(2, "n")
|
||||
local f = info.name or "?"
|
||||
if info.namewhat ~= "method" then
|
||||
-- Offset argument number when called using '.' instead of ':'
|
||||
n = n + 1
|
||||
end
|
||||
error(string.format("bad argument #%i to '%s' (%s expected, got %s)", n, f, a, t), 3)
|
||||
end
|
||||
|
||||
local function secure_table(t, index, id)
|
||||
setmetatable(t, {
|
||||
__index = index,
|
||||
__newindex = {},
|
||||
__metatable = id,
|
||||
})
|
||||
return t
|
||||
end
|
||||
|
||||
local path = minetest.get_modpath("fakelib")
|
||||
|
||||
for _,file in pairs({"metadata", "inventory", "player"}) do
|
||||
loadfile(path.."/"..file..".lua")(check, secure_table)
|
||||
end
|
||||
|
||||
if minetest.is_singleplayer() then
|
||||
minetest.register_chatcommand("fakelib_test", {
|
||||
description = "Test fakelib's API.",
|
||||
params = "[<run error tests>]",
|
||||
func = function(_, param)
|
||||
local start_time = minetest.get_us_time()
|
||||
local success = loadfile(path.."/tests.lua")(param == "true")
|
||||
local end_time = minetest.get_us_time()
|
||||
if success then
|
||||
return true, string.format("Testing completed in %i us", end_time - start_time)
|
||||
end
|
||||
return true, "Testing failed. See console for errors."
|
||||
end,
|
||||
})
|
||||
end
|
310
inventory.lua
Normal file
310
inventory.lua
Normal file
@ -0,0 +1,310 @@
|
||||
|
||||
local fake_inventory = {}
|
||||
local identifier = "fakelib:inventory"
|
||||
local check, secure_table = ...
|
||||
|
||||
-- API functions
|
||||
----------------------------------------
|
||||
|
||||
function fakelib.is_inventory(x)
|
||||
if type(x) == "userdata" and x.get_lists then
|
||||
return true
|
||||
elseif type(x) == "table" and getmetatable(x) == identifier then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function fakelib.create_inventory(inv)
|
||||
local lists = {}
|
||||
if inv and fakelib.is_inventory(inv) then
|
||||
lists = inv:get_lists()
|
||||
for listname in pairs(lists) do
|
||||
local width = inv:get_width(listname)
|
||||
if width > 0 then
|
||||
lists[listname].width = width
|
||||
end
|
||||
end
|
||||
elseif type(inv) == "table" then
|
||||
for listname, size in pairs(inv) do
|
||||
if type(listname) == "string" and type(size) == "number" then
|
||||
local list = {}
|
||||
for i=1, size do
|
||||
list[i] = ItemStack()
|
||||
end
|
||||
lists[listname] = list
|
||||
end
|
||||
end
|
||||
end
|
||||
return secure_table({lists = lists}, fake_inventory, identifier)
|
||||
end
|
||||
|
||||
-- Helper functions
|
||||
----------------------------------------
|
||||
|
||||
local function copy_list(list)
|
||||
local copy = {}
|
||||
for i=1, #list do
|
||||
copy[i] = ItemStack(list[i])
|
||||
end
|
||||
return copy
|
||||
end
|
||||
|
||||
local function stack_matches(a, b, match_meta)
|
||||
if a:get_name() ~= b:get_name() then
|
||||
return false
|
||||
end
|
||||
if match_meta then
|
||||
if a:get_wear() ~= b:get_wear() then
|
||||
return false
|
||||
end
|
||||
return a:get_meta():equals(b:get_meta())
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
-- Inventory functions
|
||||
----------------------------------------
|
||||
|
||||
function fake_inventory:is_empty(listname)
|
||||
check(1, listname, "string", "number")
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or #list == 0 then
|
||||
return true
|
||||
end
|
||||
for _,stack in ipairs(list) do
|
||||
if not stack:is_empty() then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function fake_inventory:get_size(listname)
|
||||
check(1, listname, "string", "number")
|
||||
local list = self.lists[tostring(listname)]
|
||||
return list and #list or 0
|
||||
end
|
||||
|
||||
function fake_inventory:set_size(listname, size)
|
||||
check(1, listname, "string", "number")
|
||||
check(2, size, "number")
|
||||
listname = tostring(listname)
|
||||
if size ~= size or size < 0 then
|
||||
return false
|
||||
end
|
||||
size = math.floor(size)
|
||||
if size == 0 then
|
||||
self.lists[listname] = nil
|
||||
return true
|
||||
end
|
||||
local list = self.lists[listname] or {}
|
||||
if #list < size then
|
||||
for i=#list+1, size do
|
||||
list[i] = ItemStack()
|
||||
end
|
||||
elseif #list > size then
|
||||
for i=size+1, #list do
|
||||
list[i] = nil
|
||||
end
|
||||
end
|
||||
self.lists[listname] = list
|
||||
return true
|
||||
end
|
||||
|
||||
function fake_inventory:get_width(listname)
|
||||
check(1, listname, "string", "number")
|
||||
local list = self.lists[tostring(listname)]
|
||||
return list and list.width or 0
|
||||
end
|
||||
|
||||
function fake_inventory:set_width(listname, width)
|
||||
check(1, listname, "string", "number")
|
||||
check(2, width, "number")
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or width ~= width or width < 0 then
|
||||
return false
|
||||
end
|
||||
width = math.floor(width)
|
||||
list.width = width > 0 and width or nil
|
||||
return true
|
||||
end
|
||||
|
||||
function fake_inventory:get_stack(listname, i)
|
||||
check(1, listname, "string", "number")
|
||||
check(2, i, "number")
|
||||
i = math.floor(i)
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or not list[i] then
|
||||
return ItemStack()
|
||||
end
|
||||
return ItemStack(list[i])
|
||||
end
|
||||
|
||||
function fake_inventory:set_stack(listname, i, stack)
|
||||
check(1, listname, "string", "number")
|
||||
check(2, i, "number")
|
||||
stack = ItemStack(stack)
|
||||
i = math.floor(i)
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or not list[i] or stack:is_empty() then
|
||||
return false
|
||||
end
|
||||
list[i] = stack
|
||||
return true
|
||||
end
|
||||
|
||||
function fake_inventory:get_list(listname)
|
||||
check(1, listname, "string", "number")
|
||||
local list = self.lists[tostring(listname)]
|
||||
return list and copy_list(list) or nil
|
||||
end
|
||||
|
||||
function fake_inventory:set_list(listname, list)
|
||||
check(1, listname, "string", "number")
|
||||
listname = tostring(listname)
|
||||
if list == nil then
|
||||
self.lists[listname] = nil
|
||||
return
|
||||
end
|
||||
check(2, list, "table")
|
||||
local new_list, size = {}, 0
|
||||
for i,s in pairs(list) do
|
||||
check(4, i, "number")
|
||||
if i > size then
|
||||
size = i
|
||||
end
|
||||
new_list[i] = ItemStack(s)
|
||||
end
|
||||
for i=1, size do
|
||||
if not new_list[i] then
|
||||
new_list[i] = ItemStack()
|
||||
end
|
||||
end
|
||||
self.lists[listname] = new_list
|
||||
end
|
||||
|
||||
function fake_inventory:get_lists()
|
||||
local lists = {}
|
||||
for listname, list in pairs(self.lists) do
|
||||
lists[listname] = copy_list(list)
|
||||
end
|
||||
return lists
|
||||
end
|
||||
|
||||
function fake_inventory:set_lists(lists)
|
||||
check(1, lists, "table")
|
||||
local new_lists = {}
|
||||
for listname, list in pairs(lists) do
|
||||
check(3, listname, "string", "number")
|
||||
check(3, list, "table")
|
||||
listname = tostring(listname)
|
||||
local new_list, size = {}, 0
|
||||
for i,s in pairs(list) do
|
||||
check(5, i, "number")
|
||||
if i > size then
|
||||
size = i
|
||||
end
|
||||
new_list[i] = ItemStack(s)
|
||||
end
|
||||
for i=1, size do
|
||||
if not new_list[i] then
|
||||
new_list[i] = ItemStack()
|
||||
end
|
||||
end
|
||||
new_lists[listname] = new_list
|
||||
end
|
||||
self.lists = new_lists
|
||||
end
|
||||
|
||||
function fake_inventory:add_item(listname, stack)
|
||||
check(1, listname, "string", "number")
|
||||
stack = ItemStack(stack)
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or #list == 0 or stack:is_empty() then
|
||||
return stack
|
||||
end
|
||||
local empty = {}
|
||||
for _,s in ipairs(list) do
|
||||
if s:is_empty() then
|
||||
table.insert(empty, s)
|
||||
else
|
||||
stack = s:add_item(stack)
|
||||
if stack:is_empty() then
|
||||
return stack
|
||||
end
|
||||
end
|
||||
end
|
||||
for _,s in ipairs(empty) do
|
||||
stack = s:add_item(stack)
|
||||
if stack:is_empty() then
|
||||
return stack
|
||||
end
|
||||
end
|
||||
return stack
|
||||
end
|
||||
|
||||
function fake_inventory:room_for_item(listname, stack)
|
||||
check(1, listname, "string", "number")
|
||||
stack = ItemStack(stack)
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or #list == 0 or stack:is_empty() then
|
||||
return false
|
||||
end
|
||||
for _,s in ipairs(copy_list(list)) do
|
||||
stack = s:add_item(stack)
|
||||
if stack:is_empty() then
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function fake_inventory:contains_item(listname, stack, match_meta)
|
||||
check(1, listname, "string", "number")
|
||||
stack = ItemStack(stack)
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or stack:is_empty() or stack:is_empty() then
|
||||
return false
|
||||
end
|
||||
local count = stack:get_count()
|
||||
for _,s in ipairs(list) do
|
||||
if stack_matches(stack, s, match_meta) then
|
||||
count = count - s:get_count()
|
||||
if count <= 0 then
|
||||
return true
|
||||
end
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function fake_inventory:remove_item(listname, stack)
|
||||
check(1, listname, "string", "number")
|
||||
stack = ItemStack(stack)
|
||||
local list = self.lists[tostring(listname)]
|
||||
if not list or #list == 0 or stack:is_empty() then
|
||||
return ItemStack()
|
||||
end
|
||||
local name, remaining, removed = stack:get_name(), stack:get_count()
|
||||
for i=#list, 1, -1 do
|
||||
local s = list[i]
|
||||
if s:get_name() == name then
|
||||
s = s:take_item(remaining)
|
||||
remaining = remaining - s:get_count()
|
||||
if not removed then
|
||||
removed = s
|
||||
else
|
||||
removed:set_count(removed:get_count() + s:get_count())
|
||||
end
|
||||
if remaining == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
end
|
||||
return removed or ItemStack()
|
||||
end
|
||||
|
||||
function fake_inventory.get_location()
|
||||
return {type = "undefined"}
|
||||
end
|
130
metadata.lua
Normal file
130
metadata.lua
Normal file
@ -0,0 +1,130 @@
|
||||
|
||||
local fake_metadata = {}
|
||||
local identifier = "fakelib:metadata"
|
||||
local check, secure_table = ...
|
||||
|
||||
-- API functions
|
||||
----------------------------------------
|
||||
|
||||
function fakelib.is_metadata(x)
|
||||
if type(x) == "userdata" and x.get_keys then
|
||||
return true
|
||||
elseif type(x) == "table" and getmetatable(x) == identifier then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function fakelib.create_metadata(meta)
|
||||
local fields = {}
|
||||
if meta and fakelib.is_metadata(meta) then
|
||||
fields = meta:to_table().fields
|
||||
end
|
||||
return secure_table({fields = fields}, fake_metadata, identifier)
|
||||
end
|
||||
|
||||
-- Metadata functions
|
||||
----------------------------------------
|
||||
|
||||
function fake_metadata:contains(key)
|
||||
check(1, key, "string", "number")
|
||||
key = tostring(key)
|
||||
return self.fields[key] ~= nil
|
||||
end
|
||||
|
||||
function fake_metadata:get(key)
|
||||
check(1, key, "string", "number")
|
||||
key = tostring(key)
|
||||
return self.fields[key]
|
||||
end
|
||||
|
||||
function fake_metadata:set_string(key, value)
|
||||
check(1, key, "string", "number")
|
||||
check(2, value, "string", "number")
|
||||
key = tostring(key)
|
||||
value = tostring(value)
|
||||
if value == "" then
|
||||
self.fields[key] = nil
|
||||
end
|
||||
self.fields[key] = value
|
||||
end
|
||||
|
||||
function fake_metadata:get_string(key)
|
||||
check(1, key, "string", "number")
|
||||
key = tostring(key)
|
||||
return self.fields[key] or ""
|
||||
end
|
||||
|
||||
function fake_metadata:set_int(key, value)
|
||||
check(1, key, "string", "number")
|
||||
check(2, value, "number")
|
||||
key = tostring(key)
|
||||
if value >= 2^31 then
|
||||
value = 0
|
||||
end
|
||||
self.fields[key] = string.format("%i", value)
|
||||
end
|
||||
|
||||
function fake_metadata:get_int(key)
|
||||
check(1, key, "string", "number")
|
||||
key = tostring(key)
|
||||
return tonumber(self.fields[key]) or 0
|
||||
end
|
||||
|
||||
function fake_metadata:set_float(key, value)
|
||||
check(1, key, "string", "number")
|
||||
check(2, value, "number")
|
||||
key = tostring(key)
|
||||
self.fields[key] = string.format("%s", value)
|
||||
end
|
||||
|
||||
function fake_metadata:get_float(key)
|
||||
check(1, key, "string", "number")
|
||||
key = tostring(key)
|
||||
return tonumber(self.fields[key]) or 0
|
||||
end
|
||||
|
||||
function fake_metadata:get_keys()
|
||||
local keys = {}
|
||||
for key in pairs(self.fields) do
|
||||
table.insert(keys, key)
|
||||
end
|
||||
return keys
|
||||
end
|
||||
|
||||
function fake_metadata:to_table()
|
||||
return {fields = table.copy(self.fields)}
|
||||
end
|
||||
|
||||
function fake_metadata:from_table(data)
|
||||
if type(data) ~= "table" or type(data.fields) ~= "table" then
|
||||
self.fields = {}
|
||||
return true
|
||||
end
|
||||
local fields = {}
|
||||
for k,v in pairs(data.fields) do
|
||||
check(4, k, "string")
|
||||
check(5, v, "string", "number")
|
||||
fields[k] = tostring(v)
|
||||
end
|
||||
self.fields = fields
|
||||
return true
|
||||
end
|
||||
|
||||
function fake_metadata:equals(other)
|
||||
if not fakelib.is_metadata(other) then
|
||||
check(1, other, "MetaDataRef")
|
||||
end
|
||||
local fields = other:to_table().fields
|
||||
for k,v in pairs(self.fields) do
|
||||
if fields[k] == v then
|
||||
fields[k] = nil
|
||||
elseif fields[k] ~= nil then
|
||||
return false
|
||||
end
|
||||
end
|
||||
if next(fields) == nil then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
494
player.lua
Normal file
494
player.lua
Normal file
@ -0,0 +1,494 @@
|
||||
|
||||
local fake_player = {is_fake_player = true}
|
||||
local identifier = "fakelib:player"
|
||||
local check, secure_table = ...
|
||||
|
||||
local player_controls = {
|
||||
up = 1, down = 2, left = 4, right = 8, jump = 16,
|
||||
aux1 = 32, sneak = 64, dig = 128, place = 256, zoom = 512,
|
||||
}
|
||||
|
||||
-- API functions
|
||||
----------------------------------------
|
||||
|
||||
function fakelib.is_player(x)
|
||||
if type(x) == "userdata" and x.get_player_name then
|
||||
return true
|
||||
elseif type(x) == "table" and getmetatable(x) == identifier then
|
||||
return true
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function fakelib.create_player(player)
|
||||
local data = {}
|
||||
if type(player) == "string" then
|
||||
data.name = player
|
||||
elseif fakelib.is_player(player) then
|
||||
data.name = player:get_player_name()
|
||||
elseif type(player) == "table" then
|
||||
if type(player.name) == "string" then
|
||||
data.name = player.name
|
||||
end
|
||||
if type(player.position) == "table" then
|
||||
data.position = vector.copy(player.position)
|
||||
end
|
||||
if type(player.direction) == "table" then
|
||||
local dir = vector.normalize(player.direction)
|
||||
data.pitch = -math.asin(dir.y)
|
||||
data.yaw = math.atan2(-dir.x, dir.z) % (math.pi * 2)
|
||||
end
|
||||
if type(player.controls) == "table" then
|
||||
data.controls = {}
|
||||
player.controls.dig = player.controls.dig or player.controls.LMB
|
||||
player.controls.place = player.controls.place or player.controls.RMB
|
||||
for name in pairs(player_controls) do
|
||||
data.controls[name] = player.controls[name] == true
|
||||
end
|
||||
end
|
||||
if fakelib.is_metadata(player.metadata) then
|
||||
data.metadata = fakelib.create_metadata(player.metadata)
|
||||
end
|
||||
if fakelib.is_inventory(player.inventory) then
|
||||
data.inventory = fakelib.create_inventory(player.inventory)
|
||||
end
|
||||
local size = 32
|
||||
if data.inventory and type(player.wield_list) == "string" then
|
||||
size = data.inventory:get_size(player.wield_list)
|
||||
if size > 0 then
|
||||
data.wield_list = player.wield_list
|
||||
end
|
||||
end
|
||||
if type(player.wield_index) == "number" then
|
||||
if player.wield_index > 0 and player.wield_index <= size then
|
||||
data.wield_index = player.wield_index
|
||||
end
|
||||
end
|
||||
end
|
||||
return secure_table({data = data}, fake_player, identifier)
|
||||
end
|
||||
|
||||
-- Helper functions
|
||||
----------------------------------------
|
||||
|
||||
local function check_vector(v)
|
||||
local t = type(v)
|
||||
if t ~= "table" then
|
||||
error(string.format("\"Invalid vector (expected table got %s).\"", t), 3)
|
||||
end
|
||||
for _,c in ipairs({"x", "y", "z"}) do
|
||||
t = type(v[c])
|
||||
if t ~= "number" then
|
||||
error(string.format("\"Invalid vector coordinate %s (expected number got %s).\"", c, t), 3)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Dynamic get/set functions
|
||||
----------------------------------------
|
||||
|
||||
function fake_player:get_player_name()
|
||||
return self.data.name or ""
|
||||
end
|
||||
|
||||
function fake_player:get_inventory()
|
||||
if not self.data.inventory then
|
||||
self.data.inventory = fakelib.create_inventory({
|
||||
main = 32, craft = 9, craftpreview = 1, craftresult = 1
|
||||
})
|
||||
end
|
||||
return self.data.inventory
|
||||
end
|
||||
|
||||
function fake_player:get_meta()
|
||||
if not self.data.metadata then
|
||||
self.data.metadata = fakelib:create_metadata()
|
||||
end
|
||||
return self.data.metadata
|
||||
end
|
||||
|
||||
function fake_player:get_look_dir()
|
||||
local p, y = self.data.pitch or 0, self.data.yaw or 0
|
||||
return vector.new(math.sin(-y) * math.cos(p), math.sin(-p), math.cos(y) * math.cos(p))
|
||||
end
|
||||
|
||||
function fake_player:get_look_horizontal()
|
||||
return self.data.yaw or 0
|
||||
end
|
||||
|
||||
function fake_player:set_look_horizontal(value)
|
||||
check(1, value, "number")
|
||||
self.data.yaw = value % (math.pi * 2)
|
||||
end
|
||||
|
||||
function fake_player:get_look_vertical()
|
||||
return self.data.pitch or 0
|
||||
end
|
||||
|
||||
function fake_player:set_look_vertical(value)
|
||||
check(1, value, "number")
|
||||
self.data.pitch = math.max(-math.pi / 2, math.min(value, math.pi / 2))
|
||||
end
|
||||
|
||||
function fake_player:get_player_control()
|
||||
local controls = {}
|
||||
if self.data.controls then
|
||||
for name in pairs(player_controls) do
|
||||
controls[name] = self.data.controls[name]
|
||||
end
|
||||
else
|
||||
for name in pairs(player_controls) do
|
||||
controls[name] = false
|
||||
end
|
||||
end
|
||||
controls.LMB = controls.dig
|
||||
controls.RMB = controls.place
|
||||
return controls
|
||||
end
|
||||
|
||||
function fake_player:get_player_control_bits()
|
||||
if not self.data.controls then
|
||||
return 0
|
||||
end
|
||||
local total = 0
|
||||
for name, value in pairs(player_controls) do
|
||||
total = total + self.data.controls[name] and value or 0
|
||||
end
|
||||
return total
|
||||
end
|
||||
|
||||
function fake_player:get_pos()
|
||||
if self.data.position then
|
||||
return vector.copy(self.data.position)
|
||||
end
|
||||
return vector.zero()
|
||||
end
|
||||
|
||||
function fake_player:set_pos(pos)
|
||||
check_vector(pos)
|
||||
self.data.position = vector.copy(pos)
|
||||
end
|
||||
fake_player.move_to = fake_player.set_pos
|
||||
|
||||
function fake_player:add_pos(pos)
|
||||
check_vector(pos)
|
||||
if self.data.position then
|
||||
self.data.position = vector.add(self.data.position, pos)
|
||||
else
|
||||
self.data.position = vector.copy(pos)
|
||||
end
|
||||
end
|
||||
|
||||
function fake_player:get_wield_index()
|
||||
return self.data.wield_index or 1
|
||||
end
|
||||
|
||||
function fake_player:get_wield_list()
|
||||
return self.data.wield_list or "main"
|
||||
end
|
||||
|
||||
function fake_player:get_wielded_item()
|
||||
if self.data.inventory then
|
||||
return self.data.inventory:get_stack(self:get_wield_list(), self:get_wield_index())
|
||||
end
|
||||
return ItemStack()
|
||||
end
|
||||
|
||||
function fake_player:set_wielded_item(stack)
|
||||
stack = ItemStack(stack)
|
||||
if not self.data.inventory and stack:is_empty() then
|
||||
return true
|
||||
end
|
||||
self:get_inventory():set_stack(self:get_wield_list(), self:get_wield_index(), stack)
|
||||
return true
|
||||
end
|
||||
|
||||
-- Static get functions
|
||||
----------------------------------------
|
||||
|
||||
function fake_player.is_player()
|
||||
return true
|
||||
end
|
||||
|
||||
function fake_player.get_animation()
|
||||
return {x = 1, y = 1}, 15, 0, true
|
||||
end
|
||||
|
||||
function fake_player.get_armor_groups()
|
||||
return {immortal = 1}
|
||||
end
|
||||
|
||||
function fake_player.get_bone_override()
|
||||
return {
|
||||
position = {absolute = false, vec = vector.zero(), interpolation = 0},
|
||||
rotation = {absolute = false, vec = vector.zero(), interpolation = 0},
|
||||
scale = {absolute = false, vec = vector.new(1, 1, 1), interpolation = 0},
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_bone_overrides()
|
||||
return {}
|
||||
end
|
||||
|
||||
function fake_player.get_bone_position()
|
||||
return vector.zero(), vector.zero()
|
||||
end
|
||||
|
||||
function fake_player.get_breath()
|
||||
return 10
|
||||
end
|
||||
|
||||
function fake_player.get_children()
|
||||
return {}
|
||||
end
|
||||
|
||||
function fake_player.get_clouds()
|
||||
return {
|
||||
ambient = {r = 0, g = 0, b = 0, a = 255},
|
||||
color = {r = 240, g = 240, b = 255, a = 229},
|
||||
density = 0.4,
|
||||
height = 120,
|
||||
speed = {x = 0, y = -2},
|
||||
thickness = 16,
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_eye_offset()
|
||||
return vector.zero(), vector.zero(), vector.zero()
|
||||
end
|
||||
|
||||
function fake_player.get_formspec_prepend()
|
||||
return ""
|
||||
end
|
||||
|
||||
function fake_player.get_fov()
|
||||
return 0, false, 0
|
||||
end
|
||||
|
||||
function fake_player.get_hp()
|
||||
return 20
|
||||
end
|
||||
|
||||
function fake_player.get_inventory_formspec()
|
||||
return ""
|
||||
end
|
||||
|
||||
function fake_player.get_lighting()
|
||||
return {
|
||||
exposure = {
|
||||
speed_bright_dark = 1000,
|
||||
center_weight_power = 1,
|
||||
luminance_min = -3,
|
||||
luminance_max = -3,
|
||||
exposure_correction = 0,
|
||||
speed_dark_bright = 1000
|
||||
},
|
||||
saturation = 1,
|
||||
shadows = {intensity = 0},
|
||||
volumetric_light = {strength = 0},
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_local_animation()
|
||||
return {x = 0, y = 0}, {x = 0, y = 0}, {x = 0, y = 0}, {x = 0, y = 0}, 0
|
||||
end
|
||||
|
||||
function fake_player.get_moon()
|
||||
return {
|
||||
scale = 1,
|
||||
texture = "moon.png",
|
||||
tonemap = "moon_tonemap.png",
|
||||
visible = true,
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_nametag_attributes()
|
||||
return {
|
||||
bgcolor = false,
|
||||
color = {r = 255, g = 255, b = 255, a = 255},
|
||||
text = "",
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_physics_override()
|
||||
return {
|
||||
acceleration_air = 1, acceleration_default = 1, acceleration_fast = 1,
|
||||
gravity = 1, jump = 1, speed = 1,
|
||||
liquid_fluidity = 1, liquid_fluidity_smooth = 1, liquid_sink = 1,
|
||||
speed_climb = 1, speed_crouch = 1, speed_fast = 1, speed_walk = 1,
|
||||
new_move = true, sneak = true, sneak_glitch = false,
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_properties()
|
||||
return {
|
||||
automatic_face_movement_dir = false,
|
||||
automatic_face_movement_max_rotation_per_sec = -1,
|
||||
automatic_rotate = 0,
|
||||
backface_culling = false,
|
||||
breath_max = 10,
|
||||
collide_with_objects = true,
|
||||
collisionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5},
|
||||
colors = {{r = 255, g = 255, b = 255, a = 255}},
|
||||
damage_texture_modifier = "^[brighten",
|
||||
eye_height = 0,
|
||||
glow = 0,
|
||||
hp_max = 20,
|
||||
infotext = "",
|
||||
initial_sprite_basepos = {x = 0, y = 0},
|
||||
is_visible = true,
|
||||
makes_footstep_sound = true,
|
||||
mesh = "",
|
||||
nametag = "",
|
||||
nametag_bgcolor = false,
|
||||
nametag_color = {r = 255, g = 255, b = 255, a = 255},
|
||||
physical = false,
|
||||
pointable = true,
|
||||
selectionbox = {-0.5, -0.5, -0.5, 0.5, 0.5, 0.5, rotate = false},
|
||||
shaded = true,
|
||||
show_on_minimap = true,
|
||||
spritediv = {x = 1, y = 1},
|
||||
static_save = true,
|
||||
stepheight = 0.6,
|
||||
textures = {"blank.png"},
|
||||
use_texture_alpha = false,
|
||||
visual = "cube",
|
||||
visual_size = vector.new(1, 1, 1),
|
||||
wield_item = "",
|
||||
zoom_fov = 15,
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_sky_color()
|
||||
return fake_player.get_sky(true).sky_color
|
||||
end
|
||||
|
||||
function fake_player.get_sky(as_table)
|
||||
if as_table then
|
||||
return {
|
||||
base_color = {r = 255, g = 255, b = 255, a = 255},
|
||||
clouds = true,
|
||||
fog = {fog_distance = -1, fog_start = -1},
|
||||
sky_color = {
|
||||
day_sky = {r = 97, g = 181, b = 245, a = 255},
|
||||
day_horizon = {r = 144, g = 211, b = 246, a = 255},
|
||||
dawn_sky = {r = 180, g = 186, b = 250, a = 255},
|
||||
dawn_horizon = {r = 186, g = 193, b = 240, a = 255},
|
||||
night_sky = {r = 0, g = 107, b = 255, a = 255},
|
||||
night_horizon = {r = 64, g = 144, b = 255, a = 255},
|
||||
indoors = {r = 100, g = 100, b = 100, a = 255},
|
||||
fog_sun_tint = {r = 244, g = 125, b = 29, a = 255},
|
||||
fog_moon_tint = {r = 128, g = 153, b = 204, a = 255},
|
||||
fog_tint_type = "default",
|
||||
},
|
||||
textures = {},
|
||||
type = "regular",
|
||||
}
|
||||
end
|
||||
return {r = 255, g = 255, b = 255, a = 255}, "regular", {}, true
|
||||
end
|
||||
|
||||
function fake_player.get_stars()
|
||||
return {
|
||||
count = 1000,
|
||||
day_opacity = 0,
|
||||
scale = 1,
|
||||
star_color = {r = 235, g = 235, b = 255, a = 105},
|
||||
visible = true,
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_sun()
|
||||
return {
|
||||
scale = 1,
|
||||
sunrise = "sunrisebg.png",
|
||||
sunrise_visible = true,
|
||||
texture = "sun.png",
|
||||
tonemap = "sun_tonemap.png",
|
||||
visible = true,
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.get_velocity()
|
||||
return vector.zero()
|
||||
end
|
||||
|
||||
function fake_player.hud_get_all()
|
||||
return {}
|
||||
end
|
||||
|
||||
function fake_player.hud_get_flags()
|
||||
return {
|
||||
basic_debug = false,
|
||||
breathbar = false,
|
||||
chat = false,
|
||||
crosshair = false,
|
||||
healthbar = false,
|
||||
hotbar = false,
|
||||
minimap = false,
|
||||
minimap_radar = false,
|
||||
wielditem = false,
|
||||
}
|
||||
end
|
||||
|
||||
function fake_player.hud_get_hotbar_image()
|
||||
return ""
|
||||
end
|
||||
|
||||
function fake_player.hud_get_hotbar_itemcount()
|
||||
return 8
|
||||
end
|
||||
|
||||
function fake_player.hud_get_hotbar_selected_image()
|
||||
return ""
|
||||
end
|
||||
|
||||
-- No-op functions
|
||||
----------------------------------------
|
||||
do
|
||||
local functions = {
|
||||
-- Lua entity only (no-op for players)
|
||||
"get_acceleration", "get_entity_name", "get_luaentity", "get_rotation",
|
||||
"get_texture_mod", "get_yaw", "getacceleration", "getyaw", "remove",
|
||||
"set_acceleration", "set_rotation", "set_sprite", "set_texture_mod",
|
||||
"set_velocity", "set_yaw", "setacceleration", "setsprite",
|
||||
"settexturemod", "setvelocity", "setyaw",
|
||||
-- Non-functional get/set functions
|
||||
"add_velocity", "get_attach", "get_attribute", "get_day_night_ratio",
|
||||
"hud_add", "hud_change", "hud_get", "hud_remove", "hud_set_flags",
|
||||
"hud_set_hotbar_image", "hud_set_hotbar_itemcount",
|
||||
"hud_set_hotbar_selected_image", "override_day_night_ratio",
|
||||
"set_animation", "set_animation_frame_speed", "set_armor_groups",
|
||||
"set_attach", "set_attribute", "set_bone_override", "set_bone_position",
|
||||
"set_breath", "set_clouds", "set_detach", "set_eye_offset",
|
||||
"set_formspec_prepend", "set_fov", "set_hp", "set_inventory_formspec",
|
||||
"set_lighting", "set_local_animation", "set_minimap_modes", "set_moon",
|
||||
"set_nametag_attributes", "set_physics_override",
|
||||
"set_properties", "set_sky", "set_stars", "set_sun",
|
||||
-- Other functions that do nothing
|
||||
"punch", "respawn", "right_click", "send_mapblock",
|
||||
}
|
||||
for _,func in ipairs(functions) do
|
||||
fake_player[func] = function() end
|
||||
end
|
||||
end
|
||||
|
||||
-- Deprecated functions
|
||||
----------------------------------------
|
||||
|
||||
function fake_player:get_look_pitch()
|
||||
return self:get_look_vertical() * -1
|
||||
end
|
||||
|
||||
function fake_player:get_look_yaw()
|
||||
return self:get_look_horizontal() + math.pi / 2
|
||||
end
|
||||
|
||||
fake_player.set_look_pitch = fake_player.set_look_vertical
|
||||
fake_player.set_look_yaw = fake_player.set_look_horizontal
|
||||
fake_player.getpos = fake_player.get_pos
|
||||
fake_player.setpos = fake_player.set_pos
|
||||
fake_player.moveto = fake_player.set_pos
|
||||
fake_player.getvelocity = fake_player.get_velocity
|
||||
fake_player.add_player_velocity = fake_player.add_velocity
|
||||
fake_player.get_player_velocity = fake_player.get_velocity
|
251
tests.lua
Normal file
251
tests.lua
Normal file
@ -0,0 +1,251 @@
|
||||
|
||||
local error_tests = ...
|
||||
local success = true
|
||||
|
||||
-- Helper functions
|
||||
------------------------------
|
||||
|
||||
local function round(x)
|
||||
if x >= 0 then
|
||||
return math.floor(x + 0.5)
|
||||
end
|
||||
return math.ceil(x - 0.5)
|
||||
end
|
||||
|
||||
local function is_equal(a, b)
|
||||
local ta, tb = type(a), type(b)
|
||||
-- Compare table values recursively
|
||||
if ta == "table" and tb == "table" then
|
||||
if next(a) == nil and next(b) == nil then
|
||||
return true
|
||||
end
|
||||
local keys = {}
|
||||
for k in pairs(a) do
|
||||
keys[k] = true
|
||||
end
|
||||
for k in pairs(b) do
|
||||
keys[k] = true
|
||||
end
|
||||
for k in pairs(keys) do
|
||||
if not is_equal(a[k], b[k]) then
|
||||
return false
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
-- Get rid of floating point errors
|
||||
if ta == "number" and tb == "number" then
|
||||
a = round(a * 1000) / 1000
|
||||
b = round(b * 1000) / 1000
|
||||
end
|
||||
return a == b
|
||||
end
|
||||
|
||||
local function test(real, fake, func, ...)
|
||||
local rvals_real = {pcall(real[func], real, ...)}
|
||||
local rvals_fake = {pcall(fake[func], fake, ...)}
|
||||
local i = 1
|
||||
while true do
|
||||
if rvals_real[i] == nil and rvals_fake[i] == nil then
|
||||
break
|
||||
end
|
||||
if not is_equal(rvals_real[i], rvals_fake[i]) then
|
||||
success = false
|
||||
print(string.format("[fakelib] Test failed with function '%s' and return value #%i", func, i-1))
|
||||
if #{...} > 0 then
|
||||
print(" > Function arguments: ", ...)
|
||||
end
|
||||
local a = type(rvals_real[i]) == "table" and dump(rvals_real[i]) or tostring(rvals_real[i])
|
||||
print(string.format(" > Real return value: %s", a))
|
||||
local b = type(rvals_fake[i]) == "table" and dump(rvals_fake[i]) or tostring(rvals_fake[i])
|
||||
print(string.format(" > Fake return value: %s", b))
|
||||
end
|
||||
i = i + 1
|
||||
end
|
||||
end
|
||||
|
||||
local test_values = {"abc", "", 0, -1, {}, {true}, true, function() end, 0/0, nil}
|
||||
|
||||
local function iter_values()
|
||||
local i = 0
|
||||
return function ()
|
||||
i = i + 1
|
||||
if i <= 1 then return test_values[i] end
|
||||
end
|
||||
end
|
||||
|
||||
-- Player tests
|
||||
------------------------------
|
||||
|
||||
local real_player = minetest.get_player_by_name("singleplayer")
|
||||
local fake_player = fakelib.create_player("singleplayer")
|
||||
|
||||
-- Function check
|
||||
for func in pairs(getmetatable(real_player)) do
|
||||
if not fake_player[func] then
|
||||
success = false
|
||||
print(string.format("[fakelib] Missing function '%s'", func))
|
||||
end
|
||||
end
|
||||
|
||||
-- Functional tests
|
||||
test(real_player, fake_player, "get_player_name")
|
||||
test(real_player, fake_player, "get_player_control")
|
||||
test(real_player, fake_player, "get_player_control_bits")
|
||||
test(real_player, fake_player, "set_pos", vector.zero())
|
||||
test(real_player, fake_player, "add_pos", vector.new(1, 1, 1))
|
||||
test(real_player, fake_player, "get_pos")
|
||||
test(real_player, fake_player, "set_look_horizontal", 0.6)
|
||||
test(real_player, fake_player, "set_look_vertical", 0.3)
|
||||
test(real_player, fake_player, "get_look_dir")
|
||||
test(real_player, fake_player, "get_look_horizontal")
|
||||
test(real_player, fake_player, "get_look_pitch")
|
||||
test(real_player, fake_player, "get_look_yaw")
|
||||
test(real_player, fake_player, "set_wielded_item", ItemStack("air 99"))
|
||||
test(real_player, fake_player, "get_wielded_item")
|
||||
|
||||
-- Error tests
|
||||
if error_tests then
|
||||
for value in iter_values() do
|
||||
-- Only test dynamic functions, no-op functions don't check arguments
|
||||
test(real_player, fake_player, "set_pos", value)
|
||||
test(real_player, fake_player, "add_pos", value)
|
||||
test(real_player, fake_player, "set_look_horizontal", value)
|
||||
test(real_player, fake_player, "set_look_vertical", value)
|
||||
test(real_player, fake_player, "set_wielded_item", value)
|
||||
end
|
||||
end
|
||||
|
||||
-- Inventory tests
|
||||
------------------------------
|
||||
|
||||
local real_inv = real_player:get_inventory()
|
||||
local fake_inv = fakelib.create_inventory()
|
||||
|
||||
-- Function check
|
||||
for func in pairs(getmetatable(real_inv)) do
|
||||
if not fake_inv[func] then
|
||||
success = false
|
||||
print(string.format("[fakelib] Missing function '%s'", func))
|
||||
end
|
||||
end
|
||||
|
||||
-- Save and clear
|
||||
local old_inv = real_inv:get_lists()
|
||||
real_inv:set_lists({})
|
||||
|
||||
local test_item = ItemStack({name = "air", meta = {test = "abc"}})
|
||||
local test_list = {"", "air 50", test_item, "", "air 50", test_item}
|
||||
|
||||
-- Functional tests
|
||||
test(real_inv, fake_inv, "set_list", "test", test_list)
|
||||
test(real_inv, fake_inv, "is_empty", "test")
|
||||
test(real_inv, fake_inv, "set_lists", {test = test_list})
|
||||
test(real_inv, fake_inv, "set_size", "test", 10)
|
||||
test(real_inv, fake_inv, "get_size", "test")
|
||||
test(real_inv, fake_inv, "set_width", "test", 3)
|
||||
test(real_inv, fake_inv, "get_width", "test")
|
||||
test(real_inv, fake_inv, "set_stack", "test", 1.5, "air")
|
||||
test(real_inv, fake_inv, "get_stack", "test", 1)
|
||||
test(real_inv, fake_inv, "get_list", "test")
|
||||
test(real_inv, fake_inv, "add_item", "test", "air")
|
||||
test(real_inv, fake_inv, "room_for_item", "test", "air 99")
|
||||
test(real_inv, fake_inv, "contains_item", "test", "air 99")
|
||||
test(real_inv, fake_inv, "contains_item", "test", test_item, true)
|
||||
test(real_inv, fake_inv, "remove_item", "test", "air 99")
|
||||
test(real_inv, fake_inv, "get_lists")
|
||||
|
||||
-- Error tests
|
||||
if error_tests then
|
||||
for value in iter_values() do
|
||||
test(real_inv, fake_inv, "set_list", value, {})
|
||||
test(real_inv, fake_inv, "set_list", "test", value)
|
||||
test(real_inv, fake_inv, "is_empty", value)
|
||||
test(real_inv, fake_inv, "set_lists", value)
|
||||
test(real_inv, fake_inv, "set_size", value, 1)
|
||||
test(real_inv, fake_inv, "set_size", "test", value)
|
||||
test(real_inv, fake_inv, "get_size", value)
|
||||
test(real_inv, fake_inv, "set_width", value, 1)
|
||||
test(real_inv, fake_inv, "set_width", "test", value)
|
||||
test(real_inv, fake_inv, "get_width", value)
|
||||
test(real_inv, fake_inv, "set_stack", value, 1, "test")
|
||||
test(real_inv, fake_inv, "set_stack", "test", value, "test")
|
||||
test(real_inv, fake_inv, "set_stack", "test", 1, value)
|
||||
test(real_inv, fake_inv, "get_stack", value, 1)
|
||||
test(real_inv, fake_inv, "get_stack", "test", value)
|
||||
test(real_inv, fake_inv, "get_list", value)
|
||||
test(real_inv, fake_inv, "add_item", value, "test")
|
||||
test(real_inv, fake_inv, "add_item", "test", value)
|
||||
test(real_inv, fake_inv, "room_for_item", value, "test")
|
||||
test(real_inv, fake_inv, "room_for_item", "test", value)
|
||||
test(real_inv, fake_inv, "contains_item", value, "test")
|
||||
test(real_inv, fake_inv, "contains_item", "test", value)
|
||||
test(real_inv, fake_inv, "contains_item", "test", "test", value)
|
||||
test(real_inv, fake_inv, "remove_item", value, "test")
|
||||
test(real_inv, fake_inv, "remove_item", "test", value)
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset
|
||||
real_inv:set_lists(old_inv)
|
||||
|
||||
|
||||
-- Metadata tests
|
||||
------------------------------
|
||||
|
||||
local real_meta = real_player:get_meta()
|
||||
local fake_meta = fakelib.create_metadata()
|
||||
|
||||
-- Function check
|
||||
for func in pairs(getmetatable(real_meta)) do
|
||||
if not fake_meta[func] then
|
||||
success = false
|
||||
print(string.format("[fakelib] Missing function '%s'", func))
|
||||
end
|
||||
end
|
||||
|
||||
-- Save and clear
|
||||
local old_meta = real_meta:to_table()
|
||||
real_meta:from_table({})
|
||||
|
||||
local test_data = {fields = {test = "abc"}}
|
||||
|
||||
-- Functional tests
|
||||
test(real_meta, fake_meta, "from_table", test_data)
|
||||
test(real_meta, fake_meta, "contains", "test")
|
||||
test(real_meta, fake_meta, "get", "test")
|
||||
test(real_meta, fake_meta, "set_string", "test", "xyz")
|
||||
test(real_meta, fake_meta, "get_string", "test")
|
||||
test(real_meta, fake_meta, "set_int", "test", 123)
|
||||
test(real_meta, fake_meta, "get_int", "test")
|
||||
test(real_meta, fake_meta, "set_float", "test", 123.456789)
|
||||
test(real_meta, fake_meta, "get_float", "test")
|
||||
test(real_meta, fake_meta, "get_keys")
|
||||
test(real_meta, fake_meta, "to_table")
|
||||
test(real_meta, fake_meta, "equals", real_meta)
|
||||
|
||||
-- Error tests
|
||||
if error_tests then
|
||||
for value in iter_values() do
|
||||
test(real_meta, fake_meta, "from_table", value)
|
||||
test(real_meta, fake_meta, "contains", value)
|
||||
test(real_meta, fake_meta, "get", value)
|
||||
test(real_meta, fake_meta, "set_string", value, "test")
|
||||
test(real_meta, fake_meta, "set_string", "test", value)
|
||||
test(real_meta, fake_meta, "get_string", value)
|
||||
test(real_meta, fake_meta, "set_int", value, 0)
|
||||
test(real_meta, fake_meta, "set_int", "test", value)
|
||||
test(real_meta, fake_meta, "get_int", value)
|
||||
test(real_meta, fake_meta, "set_float", value, 0)
|
||||
test(real_meta, fake_meta, "set_float", "test", value)
|
||||
test(real_meta, fake_meta, "get_float", value)
|
||||
test(real_meta, fake_meta, "equals", value)
|
||||
end
|
||||
end
|
||||
|
||||
-- Reset
|
||||
real_meta:from_table(old_meta)
|
||||
|
||||
------------------------------
|
||||
|
||||
return success
|
Loading…
Reference in New Issue
Block a user