Merge branch 'dev' of https://github.com/Xertis/VoxelEngine-Cpp into dev
This commit is contained in:
@@ -1,4 +1,5 @@
|
||||
{
|
||||
"texture": "coal_ore",
|
||||
"tags": ["base:ore"],
|
||||
"base:durability": 16.0
|
||||
}
|
||||
|
||||
@@ -7,5 +7,6 @@
|
||||
"obstacle": false,
|
||||
"selectable": false,
|
||||
"replaceable": true,
|
||||
"translucent": true
|
||||
"translucent": true,
|
||||
"tags": ["core:liquid"]
|
||||
}
|
||||
|
||||
@@ -1,6 +1,13 @@
|
||||
{
|
||||
"components": [
|
||||
"base:drop"
|
||||
{
|
||||
"name": "base:drop",
|
||||
"args": {
|
||||
"item": "base:stone.item",
|
||||
"count": 1
|
||||
}
|
||||
}
|
||||
|
||||
],
|
||||
"hitbox": [0.4, 0.25, 0.4],
|
||||
"sensors": [
|
||||
|
||||
@@ -1,5 +1,12 @@
|
||||
{
|
||||
"components": [
|
||||
{
|
||||
"name": "core:mob",
|
||||
"args": {
|
||||
"jump_force": 8.0
|
||||
}
|
||||
},
|
||||
"core:player",
|
||||
"base:player_animator"
|
||||
],
|
||||
"hitbox": [0.6, 1.8, 0.6]
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
{
|
||||
"id": "base",
|
||||
"title": "Base",
|
||||
"version": "0.29",
|
||||
"version": "0.30",
|
||||
"description": "basic content package"
|
||||
}
|
||||
|
||||
@@ -8,6 +8,9 @@ timer = 0.3
|
||||
|
||||
local def_index = entity:def_index()
|
||||
dropitem = ARGS
|
||||
if dropitem.item then
|
||||
dropitem.id = item.index(dropitem.item)
|
||||
end
|
||||
if dropitem then
|
||||
timer = dropitem.pickup_delay or timer
|
||||
end
|
||||
|
||||
@@ -1,11 +1,10 @@
|
||||
local tsf = entity.transform
|
||||
local body = entity.rigidbody
|
||||
local rig = entity.skeleton
|
||||
local mob = entity:require_component("core:mob")
|
||||
|
||||
local itemid = 0
|
||||
local headIndex = rig:index("head")
|
||||
local itemIndex = rig:index("item")
|
||||
local bodyIndex = rig:index("body")
|
||||
|
||||
local function refresh_model(id)
|
||||
itemid = id
|
||||
@@ -18,10 +17,11 @@ function on_render()
|
||||
if pid == -1 then
|
||||
return
|
||||
end
|
||||
|
||||
local rx, ry, rz = player.get_rot(pid, pid ~= hud.get_player())
|
||||
rig:set_matrix(headIndex, mat4.rotate({1, 0, 0}, ry))
|
||||
rig:set_matrix(bodyIndex, mat4.rotate({0, 1, 0}, rx))
|
||||
|
||||
local rx, _, _ = player.get_rot(pid, pid ~= hud.get_player())
|
||||
|
||||
local dir = vec2.rotate({0, -1}, -rx)
|
||||
mob.set_dir({dir[1], 0, dir[2]})
|
||||
|
||||
local invid, slotid = player.get_inventory(pid)
|
||||
local id, _ = inventory.get(invid, slotid)
|
||||
|
||||
@@ -176,18 +176,105 @@ function place_pack(panel, packinfo, callback, position_func)
|
||||
end
|
||||
end
|
||||
|
||||
local Version = {};
|
||||
|
||||
function Version.matches_pattern(version)
|
||||
for _, letter in string.gmatch(version, "%.+") do
|
||||
if type(letter) ~= "number" or letter ~= "." then
|
||||
return false;
|
||||
end
|
||||
|
||||
local t = string.split(version, ".");
|
||||
|
||||
return #t == 2 or #t == 3;
|
||||
end
|
||||
end
|
||||
|
||||
function Version.__equal(ver1, ver2)
|
||||
return ver1[1] == ver2[1] and ver1[2] == ver2[2] and ver1[3] == ver2[3];
|
||||
end
|
||||
|
||||
function Version.__more(ver1, ver2)
|
||||
if ver1[1] ~= ver2[1] then return ver1[1] > ver2[1] end;
|
||||
if ver1[2] ~= ver2[2] then return ver1[2] > ver2[2] end;
|
||||
return ver1[3] > ver2[3];
|
||||
end
|
||||
|
||||
function Version.__less(ver1, ver2)
|
||||
return Version.__more(ver2, ver1);
|
||||
end
|
||||
|
||||
function Version.__more_or_equal(ver1, ver2)
|
||||
return not Version.__less(ver1, ver2);
|
||||
end
|
||||
|
||||
function Version.__less_or_equal(ver1, ver2)
|
||||
return not Version.__more(ver1, ver2);
|
||||
end
|
||||
|
||||
function Version.compare(op, ver1, ver2)
|
||||
ver1 = string.split(ver1, ".");
|
||||
ver2 = string.split(ver2, ".");
|
||||
|
||||
if op == "=" then return Version.__equal(ver1, ver2);
|
||||
elseif op == ">" then return Version.__more(ver1, ver2);
|
||||
elseif op == "<" then return Version.__less(ver1, ver2);
|
||||
elseif op == ">=" then return Version.__more_or_equal(ver1, ver2);
|
||||
elseif op == "<=" then return Version.__less_or_equal(ver1, ver2);
|
||||
else return false; end
|
||||
end
|
||||
|
||||
function Version.parse(version)
|
||||
local op = string.sub(version, 1, 2);
|
||||
if op == ">=" or op == "=>" then
|
||||
return ">=", string.sub(version, #op + 1);
|
||||
elseif op == "<=" or op == "=<" then
|
||||
return "<=", string.sub(version, #op + 1);
|
||||
end
|
||||
|
||||
op = string.sub(version, 1, 1);
|
||||
if op == ">" or op == "<" then
|
||||
return op, string.sub(version, #op + 1);
|
||||
end
|
||||
|
||||
return "=", version;
|
||||
end
|
||||
|
||||
local function compare_version(dependent_version, actual_version)
|
||||
if Version.matches_pattern(dependent_version) and Version.matches_pattern(actual_version) then
|
||||
local op, dep_ver = Version.parse_version(dependent_version);
|
||||
Version.compare(op, dep_ver, actual_version);
|
||||
elseif dependent_version == "*" or dependent_version == actual_version then
|
||||
return true;
|
||||
else
|
||||
return false;
|
||||
end
|
||||
end
|
||||
|
||||
function check_dependencies(packinfo)
|
||||
if packinfo.dependencies == nil then
|
||||
return
|
||||
end
|
||||
for i,dep in ipairs(packinfo.dependencies) do
|
||||
local depid = dep:sub(2,-1)
|
||||
if dep:sub(1,1) == '!' then
|
||||
local depid, depver = unpack(string.split(dep:sub(2,-1), "@"))
|
||||
|
||||
if dep:sub(1,1) == '!' then
|
||||
if not table.has(packs_all, depid) then
|
||||
return string.format(
|
||||
"%s (%s)", gui.str("error.dependency-not-found"), depid
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
local dep_pack = pack.get_info(depid);
|
||||
|
||||
if not compare_version(depver, dep_pack.version) then
|
||||
local op, ver = Version.parse(depver);
|
||||
|
||||
print(string.format("%s: %s !%s %s (%s)", gui.str("error.dependency-version-not-met"), dep_pack.version, op, ver, depid));
|
||||
return string.format("%s: %s != %s (%s)", gui.str("error.dependency-version-not-met"), dep_pack.version, ver, depid);
|
||||
end
|
||||
|
||||
if table.has(packs_installed, packinfo.id) then
|
||||
table.insert(required, depid)
|
||||
end
|
||||
|
||||
@@ -13,9 +13,9 @@ end
|
||||
function refresh()
|
||||
document.list:clear()
|
||||
|
||||
local available = pack.get_available()
|
||||
local infos = pack.get_info(available)
|
||||
for _, name in ipairs(available) do
|
||||
local allpacks = table.merge(pack.get_available(), pack.get_installed())
|
||||
local infos = pack.get_info(allpacks)
|
||||
for _, name in ipairs(allpacks) do
|
||||
local info = infos[name]
|
||||
local scripts_dir = info.path.."/scripts/app"
|
||||
if not file.exists(scripts_dir) then
|
||||
|
||||
@@ -1,5 +1,4 @@
|
||||
<panel size='400' color='0' interval='1' context='menu'>
|
||||
|
||||
<button onclick='menu.page="new_world"'>@New World</button>
|
||||
|
||||
<panel id='worlds' size='390,1' padding='5' color='#FFFFFF11' max-length='400'>
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
local this = {}
|
||||
|
||||
function this.equals(expected, fact)
|
||||
assert(fact == expected, string.format(
|
||||
"(fact == expected) assertion failed\n Expected: %s\n Fact: %s",
|
||||
expected, fact
|
||||
))
|
||||
end
|
||||
|
||||
return this
|
||||
@@ -110,6 +110,21 @@ function vec3.dot(a, b)
|
||||
return a[1] * b[1] + a[2] * b[2] + a[3] * b[3]
|
||||
end
|
||||
|
||||
function vec3.mix(a, b, t, dest)
|
||||
if dest then
|
||||
dest[1] = a[1] * (1.0 - t) + b[1] * t
|
||||
dest[2] = a[2] * (1.0 - t) + b[2] * t
|
||||
dest[3] = a[3] * (1.0 - t) + b[3] * t
|
||||
return dest
|
||||
else
|
||||
return {
|
||||
a[1] * (1.0 - t) + b[1] * t,
|
||||
a[2] * (1.0 - t) + b[2] * t,
|
||||
a[3] * (1.0 - t) + b[3] * t,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
-- =================================================== --
|
||||
-- ====================== vec2 ======================= --
|
||||
-- =================================================== --
|
||||
@@ -210,3 +225,16 @@ end
|
||||
function vec2.dot(a, b)
|
||||
return a[1] * b[1] + a[2] * b[2]
|
||||
end
|
||||
|
||||
function vec2.mix(a, b, t, dest)
|
||||
if dest then
|
||||
dest[1] = a[1] * (1.0 - t) + b[1] * t
|
||||
dest[2] = a[2] * (1.0 - t) + b[2] * t
|
||||
return dest
|
||||
else
|
||||
return {
|
||||
a[1] * (1.0 - t) + b[1] * t,
|
||||
a[2] * (1.0 - t) + b[2] * t,
|
||||
}
|
||||
end
|
||||
end
|
||||
|
||||
@@ -0,0 +1,35 @@
|
||||
local Random = {}
|
||||
|
||||
local M = 2 ^ 31
|
||||
local A = 1103515245
|
||||
local C = 12345
|
||||
|
||||
function Random.randint(self)
|
||||
self._seed = (A * self._seed + C) % M
|
||||
return self._seed
|
||||
end
|
||||
|
||||
function Random.random(self, a, b)
|
||||
local num = self:randint() % M / M
|
||||
if b then
|
||||
return math.floor(num * (b - a + 1) + a)
|
||||
elseif a then
|
||||
return math.floor(num * a + 1)
|
||||
else
|
||||
return num
|
||||
end
|
||||
end
|
||||
|
||||
function Random.seed(self, number)
|
||||
if type(number) ~= "number" then
|
||||
error("number expected")
|
||||
end
|
||||
self._seed = number
|
||||
end
|
||||
|
||||
return function(seed)
|
||||
if seed and type(seed) ~= "number" then
|
||||
error("number expected")
|
||||
end
|
||||
return setmetatable({_seed = seed or random.random(M)}, {__index = Random})
|
||||
end
|
||||
@@ -25,6 +25,7 @@ local Rigidbody = {__index={
|
||||
get_linear_damping=function(self) return __rigidbody.get_linear_damping(self.eid) end,
|
||||
set_linear_damping=function(self, f) return __rigidbody.set_linear_damping(self.eid, f) end,
|
||||
is_vdamping=function(self) return __rigidbody.is_vdamping(self.eid) end,
|
||||
get_vdamping=function(self) return __rigidbody.get_vdamping(self.eid) end,
|
||||
set_vdamping=function(self, b) return __rigidbody.set_vdamping(self.eid, b) end,
|
||||
is_grounded=function(self) return __rigidbody.is_grounded(self.eid) end,
|
||||
is_crouching=function(self) return __rigidbody.is_crouching(self.eid) end,
|
||||
@@ -63,6 +64,13 @@ local Entity = {__index={
|
||||
get_skeleton=function(self) return entities.get_skeleton(self.eid) end,
|
||||
set_skeleton=function(self, s) return entities.set_skeleton(self.eid, s) end,
|
||||
get_component=function(self, name) return self.components[name] end,
|
||||
require_component=function(self, name)
|
||||
local component = self.components[name]
|
||||
if not component then
|
||||
error(("entity has no required component '%s'"):format(name))
|
||||
end
|
||||
return component
|
||||
end,
|
||||
has_component=function(self, name) return self.components[name] ~= nil end,
|
||||
get_uid=function(self) return self.eid end,
|
||||
def_index=function(self) return entities.get_def(self.eid) end,
|
||||
@@ -125,6 +133,19 @@ return {
|
||||
::continue::
|
||||
end
|
||||
end,
|
||||
physics_update = function(delta)
|
||||
for uid, entity in pairs(entities) do
|
||||
for _, component in pairs(entity.components) do
|
||||
local callback = component.on_physics_update
|
||||
if not component.__disabled and callback then
|
||||
local result, err = pcall(callback, delta)
|
||||
if err then
|
||||
debug.error(err)
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end,
|
||||
render = function(delta)
|
||||
for _,entity in pairs(entities) do
|
||||
for _, component in pairs(entity.components) do
|
||||
|
||||
@@ -11,6 +11,9 @@ local Schedule = {
|
||||
self._next_interval = id + 1
|
||||
return id
|
||||
end,
|
||||
set_timeout = function(self, ms, callback)
|
||||
self:set_interval(ms, callback, 1)
|
||||
end,
|
||||
tick = function(self, dt)
|
||||
local timer = self._timer + dt
|
||||
for id, interval in pairs(self._intervals) do
|
||||
|
||||
@@ -23,4 +23,5 @@ function on_menu_setup()
|
||||
menubg = gui.root.menubg
|
||||
controller.resize_menu_bg()
|
||||
menu.page = "main"
|
||||
menu.visible = true
|
||||
end
|
||||
|
||||
@@ -74,6 +74,38 @@ local _tcp_client_callbacks = {}
|
||||
local _udp_server_callbacks = {}
|
||||
local _udp_client_datagram_callbacks = {}
|
||||
local _udp_client_open_callbacks = {}
|
||||
local _http_response_callbacks = {}
|
||||
local _http_error_callbacks = {}
|
||||
|
||||
network.get = function(url, callback, errorCallback, headers)
|
||||
local id = network.__get(url, headers)
|
||||
if callback then
|
||||
_http_response_callbacks[id] = callback
|
||||
end
|
||||
if errorCallback then
|
||||
_http_error_callbacks[id] = errorCallback
|
||||
end
|
||||
end
|
||||
|
||||
network.get_binary = function(url, callback, errorCallback, headers)
|
||||
local id = network.__get_binary(url, headers)
|
||||
if callback then
|
||||
_http_response_callbacks[id] = callback
|
||||
end
|
||||
if errorCallback then
|
||||
_http_error_callbacks[id] = errorCallback
|
||||
end
|
||||
end
|
||||
|
||||
network.post = function(url, data, callback, errorCallback, headers)
|
||||
local id = network.__post(url, data, headers)
|
||||
if callback then
|
||||
_http_response_callbacks[id] = callback
|
||||
end
|
||||
if errorCallback then
|
||||
_http_error_callbacks[id] = errorCallback
|
||||
end
|
||||
end
|
||||
|
||||
network.tcp_open = function (port, handler)
|
||||
local socket = setmetatable({id=network.__open_tcp(port)}, ServerSocket)
|
||||
@@ -131,10 +163,80 @@ local function clean(iterable, checkFun, ...)
|
||||
end
|
||||
end
|
||||
|
||||
local updating_blocks = {}
|
||||
local TYPE_REGISTER = 0
|
||||
local TYPE_UNREGISTER = 1
|
||||
|
||||
block.__perform_ticks = function(delta)
|
||||
for id, entry in pairs(updating_blocks) do
|
||||
entry.timer = entry.timer + delta
|
||||
local steps = math.floor(entry.timer / entry.delta * #entry / 3)
|
||||
if steps == 0 then
|
||||
goto continue
|
||||
end
|
||||
entry.timer = 0.0
|
||||
local event = entry.event
|
||||
local tps = entry.tps
|
||||
for i=1, steps do
|
||||
local x = entry[entry.pointer + 1]
|
||||
local y = entry[entry.pointer + 2]
|
||||
local z = entry[entry.pointer + 3]
|
||||
entry.pointer = (entry.pointer + 3) % #entry
|
||||
events.emit(event, x, y, z, tps)
|
||||
end
|
||||
::continue::
|
||||
end
|
||||
end
|
||||
|
||||
block.__process_register_events = function()
|
||||
local register_events = block.__pull_register_events()
|
||||
if not register_events then
|
||||
return
|
||||
end
|
||||
for i=1, #register_events, 4 do
|
||||
local header = register_events[i]
|
||||
local type = bit.band(header, 0xFFFF)
|
||||
local id = bit.rshift(header, 16)
|
||||
local x = register_events[i + 1]
|
||||
local y = register_events[i + 2]
|
||||
local z = register_events[i + 3]
|
||||
|
||||
local list = updating_blocks[id]
|
||||
if type == TYPE_REGISTER then
|
||||
if not list then
|
||||
list = {}
|
||||
list.event = block.name(id) .. ".blocktick"
|
||||
list.tps = 20 / (block.properties[id]["tick-interval"] or 1)
|
||||
list.delta = 1.0 / list.tps
|
||||
list.timer = 0.0
|
||||
list.pointer = 0
|
||||
updating_blocks[id] = list
|
||||
end
|
||||
table.insert(list, x)
|
||||
table.insert(list, y)
|
||||
table.insert(list, z)
|
||||
elseif type == TYPE_UNREGISTER then
|
||||
if list then
|
||||
for j=1, #list, 3 do
|
||||
if list[j] == x and list[j + 1] == y and list[j + 2] == z then
|
||||
for k=1,3 do
|
||||
table.remove(list, j)
|
||||
end
|
||||
j = j - 3
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
print(type, id, x, y, z)
|
||||
end
|
||||
end
|
||||
|
||||
network.__process_events = function()
|
||||
local CLIENT_CONNECTED = 1
|
||||
local CONNECTED_TO_SERVER = 2
|
||||
local DATAGRAM = 3
|
||||
local RESPONSE = 4
|
||||
|
||||
local ON_SERVER = 1
|
||||
local ON_CLIENT = 2
|
||||
@@ -160,6 +262,22 @@ network.__process_events = function()
|
||||
elseif side == ON_SERVER then
|
||||
_udp_server_callbacks[sid](addr, port, data)
|
||||
end
|
||||
elseif etype == RESPONSE then
|
||||
if event[2] / 100 == 2 then
|
||||
local callback = _http_response_callbacks[event[3]]
|
||||
_http_response_callbacks[event[3]] = nil
|
||||
_http_error_callbacks[event[3]] = nil
|
||||
if callback then
|
||||
callback(event[4])
|
||||
end
|
||||
else
|
||||
local callback = _http_error_callbacks[event[3]]
|
||||
_http_response_callbacks[event[3]] = nil
|
||||
_http_error_callbacks[event[3]] = nil
|
||||
if callback then
|
||||
callback(event[2], event[4])
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- remove dead servers
|
||||
|
||||
@@ -0,0 +1,177 @@
|
||||
local body = entity.rigidbody
|
||||
local tsf = entity.transform
|
||||
local rig = entity.skeleton
|
||||
|
||||
local props = {}
|
||||
|
||||
local function def_prop(name, def_value)
|
||||
props[name] = SAVED_DATA[name] or ARGS[name] or def_value
|
||||
this["get_"..name] = function() return props[name] end
|
||||
this["set_"..name] = function(value)
|
||||
props[name] = value
|
||||
if math.abs(value - def_value) < 1e-7 then
|
||||
SAVED_DATA[name] = nil
|
||||
else
|
||||
SAVED_DATA[name] = value
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
def_prop("jump_force", 0.0)
|
||||
def_prop("air_damping", 1.0)
|
||||
def_prop("ground_damping", 1.0)
|
||||
def_prop("movement_speed", 3.0)
|
||||
def_prop("run_speed_mul", 1.5)
|
||||
def_prop("crouch_speed_mul", 0.35)
|
||||
def_prop("flight_speed_mul", 2.0)
|
||||
def_prop("gravity_scale", 1.0)
|
||||
|
||||
local function normalize_angle(angle)
|
||||
while angle > 180 do
|
||||
angle = angle - 360
|
||||
end
|
||||
while angle <= -180 do
|
||||
angle = angle + 360
|
||||
end
|
||||
return angle
|
||||
end
|
||||
|
||||
local function angle_delta(a, b)
|
||||
return normalize_angle(a - b)
|
||||
end
|
||||
|
||||
local dir = mat4.mul(tsf:get_rot(), {0, 0, -1})
|
||||
local flight = false
|
||||
|
||||
function jump(multiplier)
|
||||
local vel = body:get_vel()
|
||||
body:set_vel(
|
||||
vec3.add(vel, {0, props.jump_force * (multiplier or 1.0), 0}, vel))
|
||||
end
|
||||
|
||||
function move_vertical(speed, vel)
|
||||
vel = vel or body:get_vel()
|
||||
vel[2] = vel[2] * 0.2 + props.movement_speed * speed * 0.8
|
||||
body:set_vel(vel)
|
||||
end
|
||||
|
||||
local function move_horizontal(speed, dir, vel)
|
||||
vel = vel or body:get_vel()
|
||||
if vec2.length(dir) > 0.0 then
|
||||
vec2.normalize(dir, dir)
|
||||
|
||||
local magnitude = vec2.length({vel[1], vel[3]})
|
||||
|
||||
if magnitude <= 1e-4 or (magnitude < speed or vec2.dot(
|
||||
{vel[1] / magnitude, vel[3] / magnitude}, dir) < 0.9)
|
||||
then
|
||||
vel[1] = vel[1] * 0.2 + dir[1] * speed * 0.8
|
||||
vel[3] = vel[3] * 0.2 + dir[2] * speed * 0.8
|
||||
end
|
||||
magnitude = vec3.length({vel[1], 0, vel[3]})
|
||||
if vec2.dot({vel[1] / magnitude, vel[3] / magnitude}, dir) > 0.5 then
|
||||
vel[1] = vel[1] / magnitude * speed
|
||||
vel[3] = vel[3] / magnitude * speed
|
||||
end
|
||||
end
|
||||
body:set_vel(vel)
|
||||
end
|
||||
|
||||
function go(dir, speed_multiplier, sprint, crouch, vel)
|
||||
local speed = props.movement_speed * speed_multiplier
|
||||
if flight then
|
||||
speed = speed * props.flight_speed_mul
|
||||
end
|
||||
if sprint then
|
||||
speed = speed * props.run_speed_mul
|
||||
elseif crouch then
|
||||
speed = speed * props.crouch_speed_mul
|
||||
end
|
||||
move_horizontal(speed, dir, vel)
|
||||
end
|
||||
|
||||
local headIndex = rig:index("head")
|
||||
|
||||
function look_at(point, change_dir)
|
||||
local pos = tsf:get_pos()
|
||||
local viewdir = vec3.normalize(vec3.sub(point, pos))
|
||||
|
||||
local dot = vec3.dot(viewdir, dir)
|
||||
if dot < 0.0 and not change_dir then
|
||||
viewdir = mat4.mul(tsf:get_rot(), {0, 0, -1})
|
||||
else
|
||||
dir[1] = dir[1] * 0.8 + viewdir[1] * 0.13
|
||||
dir[3] = dir[3] * 0.8 + viewdir[3] * 0.13
|
||||
end
|
||||
|
||||
if not headIndex then
|
||||
return
|
||||
end
|
||||
|
||||
local headrot = mat4.idt()
|
||||
local curdir = mat4.mul(mat4.mul(tsf:get_rot(),
|
||||
rig:get_matrix(headIndex)), {0, 0, -1})
|
||||
|
||||
vec3.mix(curdir, viewdir, 0.2, viewdir)
|
||||
|
||||
headrot = mat4.inverse(mat4.look_at({0,0,0}, viewdir, {0, 1, 0}))
|
||||
headrot = mat4.mul(mat4.inverse(tsf:get_rot()), headrot)
|
||||
rig:set_matrix(headIndex, headrot)
|
||||
end
|
||||
|
||||
function follow_waypoints(pathfinding)
|
||||
pathfinding = pathfinding or entity:require_component("core:pathfinding")
|
||||
local pos = tsf:get_pos()
|
||||
local waypoint = pathfinding.next_waypoint()
|
||||
if not waypoint then
|
||||
return
|
||||
end
|
||||
local speed = props.movement_speed
|
||||
local vel = body:get_vel()
|
||||
dir = vec3.sub(
|
||||
vec3.add(waypoint, {0.5, 0, 0.5}),
|
||||
{pos[1], math.floor(pos[2]), pos[3]}
|
||||
)
|
||||
local upper = dir[2] > 0
|
||||
dir[2] = 0.0
|
||||
vec3.normalize(dir, dir)
|
||||
move_horizontal(speed, {dir[1], dir[3]}, vel)
|
||||
if upper and body:is_grounded() then
|
||||
jump(1.0)
|
||||
end
|
||||
end
|
||||
|
||||
function set_dir(new_dir)
|
||||
dir = new_dir
|
||||
end
|
||||
|
||||
function is_flight() return flight end
|
||||
|
||||
function set_flight(flag) flight = flag end
|
||||
|
||||
local prev_angle = (vec2.angle({dir[3], dir[1]})) % 360
|
||||
|
||||
function on_physics_update(delta)
|
||||
local grounded = body:is_grounded()
|
||||
body:set_vdamping(flight)
|
||||
body:set_gravity_scale({0, flight and 0.0 or props.gravity_scale, 0})
|
||||
body:set_linear_damping(
|
||||
(flight or not grounded) and props.air_damping or props.ground_damping
|
||||
)
|
||||
|
||||
local new_angle = (vec2.angle({dir[3], dir[1]})) % 360
|
||||
local angle = prev_angle
|
||||
|
||||
local adelta = angle_delta(
|
||||
normalize_angle(new_angle),
|
||||
normalize_angle(prev_angle)
|
||||
)
|
||||
local rotate_speed = entity:get_player() == -1 and 200 or 400
|
||||
|
||||
if math.abs(adelta) > 5 then
|
||||
angle = angle + delta * rotate_speed * (adelta > 0 and 1 or -1)
|
||||
end
|
||||
|
||||
tsf:set_rot(mat4.rotate({0, 1, 0}, angle + 180))
|
||||
prev_angle = angle
|
||||
end
|
||||
@@ -0,0 +1,71 @@
|
||||
local target
|
||||
local route
|
||||
local started
|
||||
|
||||
local tsf = entity.transform
|
||||
local body = entity.rigidbody
|
||||
|
||||
agent = pathfinding.create_agent()
|
||||
pathfinding.set_max_visited(agent, 1e3)
|
||||
pathfinding.avoid_tag(agent, "core:liquid", 8)
|
||||
|
||||
function set_target(new_target)
|
||||
target = new_target
|
||||
end
|
||||
|
||||
function set_jump_height(height)
|
||||
pathfinding.set_jump_height(agent, height)
|
||||
end
|
||||
|
||||
function get_target()
|
||||
return target
|
||||
end
|
||||
|
||||
function get_route()
|
||||
return route
|
||||
end
|
||||
|
||||
function next_waypoint()
|
||||
if not route or #route == 0 then
|
||||
return
|
||||
end
|
||||
local waypoint = route[#route]
|
||||
local pos = tsf:get_pos()
|
||||
local dst = vec2.length({
|
||||
math.floor(waypoint[1] - math.floor(pos[1])),
|
||||
math.floor(waypoint[3] - math.floor(pos[3]))
|
||||
})
|
||||
if dst < 1.0 then
|
||||
table.remove(route, #route)
|
||||
end
|
||||
return route[#route]
|
||||
end
|
||||
|
||||
local refresh_internal = 100
|
||||
local frameid = math.random(0, refresh_internal)
|
||||
|
||||
function set_refresh_interval(interval)
|
||||
refresh_internal = interval
|
||||
end
|
||||
|
||||
function on_update()
|
||||
if not started then
|
||||
frameid = frameid + 1
|
||||
if body:is_grounded() then
|
||||
if target and (frameid % refresh_internal == 1 or not route) then
|
||||
pathfinding.make_route_async(agent, tsf:get_pos(), target)
|
||||
started = true
|
||||
end
|
||||
end
|
||||
else
|
||||
local new_route = pathfinding.pull_route(agent)
|
||||
if new_route then
|
||||
route = new_route
|
||||
started = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function on_despawn()
|
||||
pathfinding.remove_agent(agent)
|
||||
end
|
||||
@@ -0,0 +1,62 @@
|
||||
local tsf = entity.transform
|
||||
local body = entity.rigidbody
|
||||
local mob = entity:require_component("core:mob")
|
||||
|
||||
local cheat_speed_mul = 10.0
|
||||
|
||||
local function process_player_inputs(pid, delta)
|
||||
if not hud or hud.is_inventory_open() or menu.page ~= "" then
|
||||
return
|
||||
end
|
||||
local cam = cameras.get("core:first-person")
|
||||
local front = cam:get_front()
|
||||
local right = cam:get_right()
|
||||
front[2] = 0.0
|
||||
vec3.normalize(front, front)
|
||||
|
||||
local isjump = input.is_active('movement.jump')
|
||||
local issprint = input.is_active('movement.sprint')
|
||||
local iscrouch = input.is_active('movement.crouch')
|
||||
local isforward = input.is_active('movement.forward')
|
||||
local ischeat = input.is_active('movement.cheat')
|
||||
local isback = input.is_active('movement.back')
|
||||
local isleft = input.is_active('movement.left')
|
||||
local isright = input.is_active('movement.right')
|
||||
mob.set_flight(player.is_flight(pid))
|
||||
body:set_body_type(player.is_noclip(pid) and "kinematic" or "dynamic")
|
||||
body:set_crouching(iscrouch)
|
||||
|
||||
local vel = body:get_vel()
|
||||
local speed = ischeat and cheat_speed_mul or 1.0
|
||||
|
||||
local dir = {0, 0, 0}
|
||||
|
||||
if isforward then vec3.add(dir, front, dir) end
|
||||
if isback then vec3.sub(dir, front, dir) end
|
||||
if isright then vec3.add(dir, right, dir) end
|
||||
if isleft then vec3.sub(dir, right, dir) end
|
||||
|
||||
if vec3.length(dir) > 0.0 then
|
||||
mob.go({dir[1], dir[3]}, speed, issprint, iscrouch, vel)
|
||||
end
|
||||
|
||||
if mob.is_flight() then
|
||||
if isjump then
|
||||
mob.move_vertical(speed * 3)
|
||||
elseif iscrouch then
|
||||
mob.move_vertical(-speed * 3)
|
||||
end
|
||||
elseif body:is_grounded() and isjump then
|
||||
mob.jump()
|
||||
end
|
||||
end
|
||||
|
||||
function on_physics_update(delta)
|
||||
local pid = entity:get_player()
|
||||
if pid ~= -1 then
|
||||
local pos = tsf:get_pos()
|
||||
local cam = cameras.get("core:first-person")
|
||||
process_player_inputs(pid, delta)
|
||||
mob.look_at(vec3.add(pos, cam:get_front()))
|
||||
end
|
||||
end
|
||||
+35
-33
@@ -22,6 +22,39 @@ local function configure_SSAO()
|
||||
-- for test purposes
|
||||
end
|
||||
|
||||
local function update_hand()
|
||||
local skeleton = gfx.skeletons
|
||||
local pid = hud.get_player()
|
||||
local invid, slot = player.get_inventory(pid)
|
||||
local itemid = inventory.get(invid, slot)
|
||||
|
||||
local cam = cameras.get("core:first-person")
|
||||
local bone = skeleton.index("hand", "item")
|
||||
|
||||
local offset = vec3.mul(vec3.sub(cam:get_pos(), {player.get_pos(pid)}), -1)
|
||||
|
||||
local rotation = cam:get_rot()
|
||||
|
||||
local angle = player.get_rot(pid) - 90
|
||||
local cos = math.cos(angle / (180 / math.pi))
|
||||
local sin = math.sin(angle / (180 / math.pi))
|
||||
|
||||
local newX = offset[1] * cos - offset[3] * sin
|
||||
local newZ = offset[1] * sin + offset[3] * cos
|
||||
|
||||
offset[1] = newX
|
||||
offset[3] = newZ
|
||||
|
||||
local mat = mat4.translate(mat4.idt(), {0.06, 0.035, -0.1})
|
||||
mat4.scale(mat, {0.1, 0.1, 0.1}, mat)
|
||||
mat4.mul(rotation, mat, mat)
|
||||
mat4.rotate(mat, {0, 1, 0}, -90, mat)
|
||||
mat4.translate(mat, offset, mat)
|
||||
|
||||
skeleton.set_matrix("hand", bone, mat)
|
||||
skeleton.set_model("hand", bone, item.model_name(itemid))
|
||||
end
|
||||
|
||||
function on_hud_open()
|
||||
input.add_callback("player.pick", function ()
|
||||
if hud.is_paused() or hud.is_inventory_open() then
|
||||
@@ -63,7 +96,7 @@ function on_hud_open()
|
||||
player.set_noclip(pid, true)
|
||||
end
|
||||
end)
|
||||
|
||||
|
||||
input.add_callback("player.flight", function ()
|
||||
if hud.is_paused() or hud.is_inventory_open() then
|
||||
return
|
||||
@@ -81,39 +114,8 @@ function on_hud_open()
|
||||
end)
|
||||
|
||||
configure_SSAO()
|
||||
end
|
||||
|
||||
local function update_hand()
|
||||
local skeleton = gfx.skeletons
|
||||
local pid = hud.get_player()
|
||||
local invid, slot = player.get_inventory(pid)
|
||||
local itemid = inventory.get(invid, slot)
|
||||
|
||||
local cam = cameras.get("core:first-person")
|
||||
local bone = skeleton.index("hand", "item")
|
||||
|
||||
local offset = vec3.mul(vec3.sub(cam:get_pos(), {player.get_pos(pid)}), -1)
|
||||
|
||||
local rotation = cam:get_rot()
|
||||
|
||||
local angle = player.get_rot() - 90
|
||||
local cos = math.cos(angle / (180 / math.pi))
|
||||
local sin = math.sin(angle / (180 / math.pi))
|
||||
|
||||
local newX = offset[1] * cos - offset[3] * sin
|
||||
local newZ = offset[1] * sin + offset[3] * cos
|
||||
|
||||
offset[1] = newX
|
||||
offset[3] = newZ
|
||||
|
||||
local mat = mat4.translate(mat4.idt(), {0.06, 0.035, -0.1})
|
||||
mat4.scale(mat, {0.1, 0.1, 0.1}, mat)
|
||||
mat4.mul(rotation, mat, mat)
|
||||
mat4.rotate(mat, {0, 1, 0}, -90, mat)
|
||||
mat4.translate(mat, offset, mat)
|
||||
|
||||
skeleton.set_matrix("hand", bone, mat)
|
||||
skeleton.set_model("hand", bone, item.model_name(itemid))
|
||||
hud.default_hand_controller = update_hand
|
||||
end
|
||||
|
||||
function on_hud_render()
|
||||
|
||||
@@ -6,28 +6,29 @@ local names = {
|
||||
"shadeless", "ambient-occlusion", "breakable", "selectable", "grounded",
|
||||
"hidden", "draw-group", "picking-item", "surface-replacement", "script-name",
|
||||
"ui-layout", "inventory-size", "tick-interval", "overlay-texture",
|
||||
"translucent", "fields", "particles", "icon-type", "icon", "placing-block",
|
||||
"translucent", "fields", "particles", "icon-type", "icon", "placing-block",
|
||||
"stack-size", "name", "script-file", "culling"
|
||||
}
|
||||
for name, _ in pairs(user_props) do
|
||||
table.insert(names, name)
|
||||
end
|
||||
-- remove undefined properties
|
||||
for id, blockprops in pairs(block.properties) do
|
||||
for propname, value in pairs(blockprops) do
|
||||
if not table.has(names, propname) then
|
||||
blockprops[propname] = nil
|
||||
end
|
||||
end
|
||||
end
|
||||
for id, itemprops in pairs(item.properties) do
|
||||
for propname, value in pairs(itemprops) do
|
||||
if not table.has(names, propname) then
|
||||
itemprops[propname] = nil
|
||||
|
||||
-- remove undefined properties and build tags set
|
||||
local function process_properties(lib)
|
||||
for id, props in pairs(lib.properties) do
|
||||
for propname, _ in pairs(props) do
|
||||
if not table.has(names, propname) then
|
||||
props[propname] = nil
|
||||
end
|
||||
end
|
||||
|
||||
props.tags_set = lib.__get_tags(id)
|
||||
end
|
||||
end
|
||||
|
||||
process_properties(block)
|
||||
process_properties(item)
|
||||
|
||||
local function make_read_only(t)
|
||||
setmetatable(t, {
|
||||
__newindex = function()
|
||||
@@ -57,6 +58,19 @@ local function cache_names(library)
|
||||
function library.index(name)
|
||||
return indices[name]
|
||||
end
|
||||
|
||||
function library.has_tag(id, tag)
|
||||
if id == nil then
|
||||
error("id is nil")
|
||||
end
|
||||
local props = library.properties[id]
|
||||
local tags_set = props.tags_set
|
||||
if tags_set then
|
||||
return tags_set[tag]
|
||||
else
|
||||
return false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
cache_names(block)
|
||||
|
||||
@@ -157,6 +157,16 @@ console.add_command(
|
||||
end
|
||||
)
|
||||
|
||||
|
||||
console.add_command(
|
||||
"entity.spawn name:str x:num~pos.x y:num~pos.y z:num~pos.z",
|
||||
"Spawn entity with default parameters",
|
||||
function(args, kwargs)
|
||||
local eid = entities.spawn(args[1], {args[2], args[3], args[4]})
|
||||
return string.format("spawned %s at %s, %s, %s", unpack(args))
|
||||
end
|
||||
)
|
||||
|
||||
console.add_command(
|
||||
"entity.despawn entity:sel=$entity.selected",
|
||||
"Despawn entity",
|
||||
|
||||
+29
-12
@@ -79,13 +79,20 @@ local function complete_app_lib(app)
|
||||
coroutine.yield()
|
||||
end
|
||||
|
||||
function app.sleep_until(predicate, max_ticks)
|
||||
function app.sleep_until(predicate, max_ticks, max_time)
|
||||
max_ticks = max_ticks or 1e9
|
||||
max_time = max_time or 1e9
|
||||
local ticks = 0
|
||||
while ticks < max_ticks and not predicate() do
|
||||
local start_time = os.clock()
|
||||
while ticks < max_ticks and
|
||||
os.clock() - start_time < max_time
|
||||
and not predicate() do
|
||||
app.tick()
|
||||
ticks = ticks + 1
|
||||
end
|
||||
if os.clock() - start_time >= max_time then
|
||||
error("timeout")
|
||||
end
|
||||
if ticks == max_ticks then
|
||||
error("max ticks exceed")
|
||||
end
|
||||
@@ -174,6 +181,7 @@ if enable_experimental then
|
||||
require "core:internal/maths_inline"
|
||||
end
|
||||
|
||||
asserts = require "core:internal/asserts"
|
||||
events = require "core:internal/events"
|
||||
|
||||
function pack.unload(prefix)
|
||||
@@ -429,6 +437,8 @@ function __vc_on_hud_open()
|
||||
hud.open_permanent("core:ingame_chat")
|
||||
end
|
||||
|
||||
local Schedule = require "core:schedule"
|
||||
|
||||
local ScheduleGroup_mt = {
|
||||
__index = {
|
||||
publish = function(self, schedule)
|
||||
@@ -440,10 +450,11 @@ local ScheduleGroup_mt = {
|
||||
for id, schedule in pairs(self._schedules) do
|
||||
schedule:tick(dt)
|
||||
end
|
||||
self.common:tick(dt)
|
||||
end,
|
||||
remove = function(self, id)
|
||||
self._schedules[id] = nil
|
||||
end
|
||||
end,
|
||||
}
|
||||
}
|
||||
|
||||
@@ -451,6 +462,7 @@ local function ScheduleGroup()
|
||||
return setmetatable({
|
||||
_next_schedule = 1,
|
||||
_schedules = {},
|
||||
common = Schedule()
|
||||
}, ScheduleGroup_mt)
|
||||
end
|
||||
|
||||
@@ -527,15 +539,18 @@ function start_coroutine(chunk, name)
|
||||
local co = coroutine.create(function()
|
||||
local status, error = xpcall(chunk, function(err)
|
||||
local fullmsg = "error: "..string.match(err, ": (.+)").."\n"..debug.traceback()
|
||||
gui.alert(fullmsg, function()
|
||||
if world.is_open() then
|
||||
__vc_app.close_world()
|
||||
else
|
||||
__vc_app.reset_content()
|
||||
menu:reset()
|
||||
menu.page = "main"
|
||||
end
|
||||
end)
|
||||
|
||||
if hud then
|
||||
gui.alert(fullmsg, function()
|
||||
if world.is_open() then
|
||||
__vc_app.close_world()
|
||||
else
|
||||
__vc_app.reset_content()
|
||||
menu:reset()
|
||||
menu.page = "main"
|
||||
end
|
||||
end)
|
||||
end
|
||||
return fullmsg
|
||||
end)
|
||||
if not status then
|
||||
@@ -573,6 +588,8 @@ function __process_post_runnables()
|
||||
end
|
||||
|
||||
network.__process_events()
|
||||
block.__process_register_events()
|
||||
block.__perform_ticks(time.delta())
|
||||
end
|
||||
|
||||
function time.post_runnable(runnable)
|
||||
|
||||
@@ -668,3 +668,5 @@ end
|
||||
|
||||
bit.compile = require "core:bitwise/compiler"
|
||||
bit.execute = require "core:bitwise/executor"
|
||||
|
||||
random.Random = require "core:internal/random_generator"
|
||||
|
||||
@@ -9,7 +9,7 @@
|
||||
|
||||
// lighting
|
||||
#define SKY_LIGHT_MUL 2.9
|
||||
#define SKY_LIGHT_TINT vec3(0.9, 0.8, 1.0)
|
||||
#define SKY_LIGHT_TINT (vec3(1.0, 0.95, 0.9) * 2.0)
|
||||
#define MIN_SKY_LIGHT vec3(0.2, 0.25, 0.33)
|
||||
|
||||
// fog
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
#include <constants>
|
||||
|
||||
vec3 pick_sky_color(samplerCube cubemap) {
|
||||
vec3 skyLightColor = texture(cubemap, vec3(0.4f, 0.0f, 0.4f)).rgb;
|
||||
vec3 skyLightColor = texture(cubemap, vec3(0.8f, 0.01f, 0.4f)).rgb;
|
||||
skyLightColor *= SKY_LIGHT_TINT;
|
||||
skyLightColor = min(vec3(1.0f), skyLightColor * SKY_LIGHT_MUL);
|
||||
skyLightColor = max(MIN_SKY_LIGHT, skyLightColor);
|
||||
|
||||
@@ -25,6 +25,7 @@ Grant %{0} pack modification permission?=Выдаць дазвол на мады
|
||||
Error at line %{0}=Памылка ў радку %{0}
|
||||
Run=Запусціць
|
||||
Filter=Фільтр
|
||||
Are you sure you want to open the link: =Ці вы ўпэўненыя, што хочаце адкрыць спасылку:
|
||||
|
||||
editor.info.tooltip=CTRL+S - Захаваць\nCTRL+R - Запусціць\nCTRL+Z - Скасаваць\nCTRL+Y - Паўтарыць
|
||||
devtools.traceback=Стэк выклікаў (ад апошняга)
|
||||
|
||||
@@ -7,6 +7,7 @@ Back=Zurück
|
||||
Continue=Weitermachen
|
||||
Add=Hinzufügen
|
||||
Converting world...=Weltkonvertierung im Gange...
|
||||
Are you sure you want to open the link: =Sind Sie sicher, dass Sie den Link öffnen möchten:
|
||||
|
||||
error.pack-not-found=Paket konnte nicht gefunden werden
|
||||
error.dependency-not-found=Die verwendete Abhängigkeit wurde nicht gefunden
|
||||
|
||||
@@ -7,6 +7,7 @@ world.convert-block-layouts=Blocks fields have changes! Convert world files?
|
||||
pack.remove-confirm=Do you want to erase all pack(s) content from the world forever?
|
||||
error.pack-not-found=Could not to find pack
|
||||
error.dependency-not-found=Dependency pack is not found
|
||||
error.dependency-version-not-met=Dependency pack version is not met.
|
||||
world.delete-confirm=Do you want to delete world forever?
|
||||
world.generators.default=Default
|
||||
world.generators.flat=Flat
|
||||
|
||||
@@ -19,6 +19,7 @@ Problems=Ongelmia
|
||||
Monitor=Valvonta
|
||||
Debug=Virheenkorjaus
|
||||
File=Tiedosto
|
||||
Are you sure you want to open the link: =Haluatko varmasti avata linkin:
|
||||
|
||||
devtools.traceback=Puhelupino (viimeisestä)
|
||||
error.pack-not-found=Pakettia ei löytynyt!
|
||||
|
||||
@@ -7,6 +7,7 @@ Back=Powrót
|
||||
Continue=Kontynuacja
|
||||
Add=Dodać
|
||||
Converting world...=Konwersja świata w toku...
|
||||
Are you sure you want to open the link: =Czy na pewno chcesz otworzyć link:
|
||||
|
||||
error.pack-not-found=Nie udało się znaleźć pakietu
|
||||
|
||||
|
||||
@@ -25,6 +25,7 @@ Grant %{0} pack modification permission?=Выдать разрешение на
|
||||
Error at line %{0}=Ошибка на строке %{0}
|
||||
Run=Запустить
|
||||
Filter=Фильтр
|
||||
Are you sure you want to open the link: =Вы уверены, что хотите открыть ссылку:
|
||||
|
||||
editor.info.tooltip=CTRL+S - Сохранить\nCTRL+R - Запустить\nCTRL+Z - Отменить\nCTRL+Y - Повторить
|
||||
devtools.traceback=Стек вызовов (от последнего)
|
||||
@@ -32,6 +33,7 @@ devtools.output=Вывод
|
||||
|
||||
error.pack-not-found=Не удалось найти пакет
|
||||
error.dependency-not-found=Используемая зависимость не найдена
|
||||
error.dependency-version-not-met=Версия зависимости не соответствует необходимой
|
||||
pack.remove-confirm=Удалить весь поставляемый паком/паками контент из мира (безвозвратно)?
|
||||
|
||||
# Подсказки
|
||||
|
||||
@@ -23,6 +23,7 @@ devtools.traceback=Стек викликів (від останнього)
|
||||
error.pack-not-found=Не вдалося знайти пакет
|
||||
error.dependency-not-found=Використовувана залежність не знайдена
|
||||
pack.remove-confirm=Видалити весь контент, що постачається паком/паками зі світу (безповоротно)?
|
||||
Are you sure you want to open the link: =Ви впевнені, що хочете відкрити посилання:
|
||||
|
||||
# Меню
|
||||
menu.Apply=Застосувати
|
||||
|
||||
@@ -24,6 +24,7 @@ Save=Saqlash
|
||||
Grant %{0} pack modification permission?=%{0} to‘plamini o‘zgartirish ruxsatini berilsinmi?
|
||||
Error at line %{0}=%{0}-qatorida xatolik
|
||||
Run=Ishga tushirish
|
||||
Are you sure you want to open the link: =Haqiqatan ham havolani ochmoqchimisiz:
|
||||
|
||||
editor.info.tooltip=CTRL+S - Saqlash\nCTRL+R - Ishga tushirish\nCTRL+Z - Bekor qilish\nCTRL+Y - Qayta bajarish
|
||||
devtools.traceback=Chaqiruvlar steki (so`nggisidan boshlab)
|
||||
|
||||
Reference in New Issue
Block a user