Amazing new vector library, safeties on arbitrary fn calls.

* Vectors have a full set of mathematic operations now.
* Vectors are indexed using 1, 2, 3 instead of xyz.
* Now using a Capital V for shorthand constructor.
* More safety on vector operators.
master
Nicole Collings 2020-03-06 18:07:22 -08:00
parent 7886dc8097
commit 0a41147846
17 changed files with 202 additions and 103 deletions

View File

@ -58,13 +58,13 @@ void LocalWorld::localSetBlock(glm::ivec3 pos, unsigned int block) {
if (block == LocalDefinitionAtlas::AIR) {
auto def = defs.defs.blockFromId(getBlock(pos));
if (def.callbacks.count(Callback::BREAK_CLIENT)) {
def.callbacks[Callback::BREAK_CLIENT](defs.parser.vecToTable(pos));
def.callbacks[Callback::BREAK_CLIENT](defs.parser.luaVec(pos));
}
}
else {
auto def = defs.defs.blockFromId(block);
if (def.callbacks.count(Callback::PLACE_CLIENT)) {
def.callbacks[Callback::PLACE_CLIENT](defs.parser.vecToTable(pos));
def.callbacks[Callback::PLACE_CLIENT](defs.parser.luaVec(pos));
}
}

View File

@ -22,6 +22,10 @@ void LuaParser::update(double delta) {
}
}
sol::table LuaParser::vecToTable(glm::vec3 vec) {
return lua.create_table_with("x", vec.x, "y", vec.y, "z", vec.z);
}
sol::table LuaParser::luaVec(glm::vec3 vec) {
return lua["vector"]["new"](vec.x, vec.y, vec.z);
}
sol::table LuaParser::luaVec(sol::state_view s, glm::vec3 vec) {
return s["vector"]["new"](vec.x, vec.y, vec.z);
}

View File

@ -32,7 +32,8 @@ public:
virtual void update(double delta);
sol::table vecToTable(glm::vec3 vec);
sol::table luaVec(glm::vec3 vec);
static sol::table luaVec(sol::state_view s, glm::vec3 vec);
sol::state lua;
sol::table core;

View File

@ -5,16 +5,16 @@
#include "LocalLuaEntity.h"
void LocalLuaEntity::snap_pos(const sol::table &pos) {
entity->setPos({pos["x"], pos["y"], pos["z"]});
entity->setPos({pos[1], pos[2], pos[3]});
}
void LocalLuaEntity::set_pos(const sol::table &pos) {
entity->interpPos({pos["x"], pos["y"], pos["z"]});
entity->interpPos({pos[1], pos[2], pos[3]});
}
sol::table LocalLuaEntity::get_pos(sol::this_state s) {
glm::vec3 pos = entity->getPos();
return sol::state_view(s).create_table_with("x", pos.x, "y", pos.y, "z", pos.z);
return LuaParser::luaVec(sol::state_view(s), pos);
}
void LocalLuaEntity::snap_visual_offset(const sol::table &vs) {
@ -22,12 +22,12 @@ void LocalLuaEntity::snap_visual_offset(const sol::table &vs) {
}
void LocalLuaEntity::set_visual_offset(const sol::table &pos) {
entity->interpVisualOffset({pos["x"], pos["y"], pos["z"]});
entity->interpVisualOffset({pos[1], pos[2], pos[3]});
}
sol::table LocalLuaEntity::get_visual_offset(sol::this_state s) {
glm::vec3 v = entity->getVisualOffset();
return sol::state_view(s).create_table_with("x", v.x, "y", v.y, "z", v.z);
return LuaParser::luaVec(sol::state_view(s), v);
}
void LocalLuaEntity::snap_pitch(float rot) {

View File

@ -5,26 +5,26 @@
#include "LocalLuaPlayer.h"
void LocalLuaPlayer::set_pos(const sol::table &pos) {
player.setPos({pos["x"], pos["y"], pos["z"]});
player.setPos({pos[1], pos[2], pos[3]});
}
sol::table LocalLuaPlayer::get_pos(sol::this_state s) {
glm::vec3 pos = player.getPos();
return sol::state_view(s).create_table_with("x", pos.x, "y", pos.y, "z", pos.z);
return LuaParser::luaVec(sol::state_view(s), pos);
}
sol::table LocalLuaPlayer::get_block_pos(sol::this_state s) {
glm::vec3 pos = glm::floor(player.getPos());
return sol::state_view(s).create_table_with("x", pos.x, "y", pos.y, "z", pos.z);
return LuaParser::luaVec(sol::state_view(s), pos);
}
void LocalLuaPlayer::set_vel(const sol::table &vel) {
player.setVel({vel["x"], vel["y"], vel["z"]});
player.setVel({vel[1], vel[2], vel[3]});
}
sol::table LocalLuaPlayer::get_vel(sol::this_state s) {
glm::vec3 vel = player.getVel();
return sol::state_view(s).create_table_with("x", vel.x, "y", vel.y, "z", vel.z);
return LuaParser::luaVec(sol::state_view(s), vel);
}
void LocalLuaPlayer::set_look_yaw(float rot) {

View File

@ -5,29 +5,29 @@
#include "ServerLuaEntity.h"
void ServerLuaEntity::snap_pos(const sol::table &pos) {
entity->setPos({pos["x"], pos["y"], pos["z"]});
entity->setPos({pos[1], pos[2], pos[3]});
}
void ServerLuaEntity::set_pos(const sol::table &pos) {
entity->setPos({pos["x"], pos["y"], pos["z"]});
entity->setPos({pos[1], pos[2], pos[3]});
}
sol::table ServerLuaEntity::get_pos(sol::this_state s) {
glm::vec3 pos = entity->getPos();
return sol::state_view(s).create_table_with("x", pos.x, "y", pos.y, "z", pos.z);
return LuaParser::luaVec(sol::state_view(s), pos);
}
void ServerLuaEntity::snap_visual_offset(const sol::table &vs) {
entity->setVisualOffset({vs["x"], vs["y"], vs["z"]});
entity->setVisualOffset({vs[1], vs[2], vs[3]});
}
void ServerLuaEntity::set_visual_offset(const sol::table &pos) {
entity->setVisualOffset({pos["x"], pos["y"], pos["z"]});
entity->setVisualOffset({pos[1], pos[2], pos[3]});
}
sol::table ServerLuaEntity::get_visual_offset(sol::this_state s) {
glm::vec3 v = entity->getVisualOffset();
return sol::state_view(s).create_table_with("x", v.x, "y", v.y, "z", v.z);
return LuaParser::luaVec(sol::state_view(s), v);
}
void ServerLuaEntity::snap_pitch(float rot) {

View File

@ -3,20 +3,22 @@
//
#include "ServerLuaPlayer.h"
#include "../../LuaParser.h"
#include "../../../util/net/NetHandler.h"
void ServerLuaPlayer::set_pos(const sol::table &pos) {
player.assertPos({pos["x"], pos["y"], pos["z"]});
player.assertPos({pos[1], pos[2], pos[3]});
}
sol::table ServerLuaPlayer::get_pos(sol::this_state s) {
glm::vec3 pos = player.getPos();
return sol::state_view(s).create_table_with("x", pos.x, "y", pos.y, "z", pos.z);
return LuaParser::luaVec(sol::state_view(s), pos);
}
sol::table ServerLuaPlayer::get_block_pos(sol::this_state s) {
glm::vec3 pos = glm::floor(player.getPos());
return sol::state_view(s).create_table_with("x", pos.x, "y", pos.y, "z", pos.z);
return LuaParser::luaVec(sol::state_view(s), pos);
}
//void ServerLuaPlayer::set_vel(const sol::table &vel) {

View File

@ -49,10 +49,10 @@ void LocalLuaParser::update(double delta, bool* keys) {
LuaParser::update(delta);
this->delta += delta;
while (this->delta > double(UPDATE_STEP)) {
while (this->delta > static_cast<double>(UPDATE_STEP)) {
manager.triggerKeybinds();
core["__builtin"]["update_entities"](double(UPDATE_STEP));
this->delta -= double(UPDATE_STEP);
safe_function(core["__builtin"]["update_entities"], static_cast<double>(UPDATE_STEP));
this->delta -= static_cast<double>(UPDATE_STEP);
}
manager.update(keys);
@ -69,11 +69,11 @@ void LocalLuaParser::loadApi(ClientGame &defs, LocalWorld &world, Player& player
core["__builtin"] = lua.create_table();
// Types
ClientApi::entity (lua);
ClientApi::animation_manager(lua);
ClientApi::local_player (lua);
ClientApi::inventory (lua);
ClientApi::item_stack (lua);
ClientApi::entity (lua);
ClientApi::animation_manager (lua);
ClientApi::local_player (lua);
ClientApi::inventory (lua);
ClientApi::item_stack (lua);
core["client"] = true;
core["player"] = LocalLuaPlayer(player);
@ -112,7 +112,7 @@ void LocalLuaParser::registerDefs(ClientGame &defs) {
RegisterKeybinds::client(core, manager);
}
sol::protected_function_result LocalLuaParser::errorCallback(lua_State*, sol::protected_function_result errPfr) {
sol::protected_function_result LocalLuaParser::errorCallback(sol::protected_function_result errPfr) {
sol::error err = errPfr;
std::string errString = err.what();
@ -170,7 +170,7 @@ sol::protected_function_result LocalLuaParser::runFileSandboxed(std::string file
env["_MODNAME"] = mod.config.name;
return lua.safe_script(f.file, env, std::bind(&LocalLuaParser::errorCallback, this,
std::placeholders::_1, std::placeholders::_2), "@" + f.path, sol::load_mode::text);
std::placeholders::_2), "@" + f.path, sol::load_mode::text);
}
}

View File

@ -19,11 +19,16 @@ public:
void update(double delta, bool* keys);
LocalModHandler& getHandler();
template<typename... Args> void safe_function(sol::protected_function f, Args... args) {
auto res = f(args...);
if (!res.valid()) errorCallback(res);
}
private:
void loadApi(ClientGame& defs, LocalWorld& world, Player& player);
void registerDefs(ClientGame &defs);
sol::protected_function_result errorCallback(lua_State*, sol::protected_function_result errPfr);
sol::protected_function_result errorCallback(sol::protected_function_result errPfr);
sol::protected_function_result runFileSandboxed(std::string file);
LuaInputManager manager;

View File

@ -57,9 +57,9 @@ void ServerLuaParser::update(double delta) {
LuaParser::update(delta);
this->delta += delta;
while (this->delta > double(UPDATE_STEP)) {
core["__builtin"]["update_entities"](double(UPDATE_STEP));
this->delta -= double(UPDATE_STEP);
while (this->delta > static_cast<double>(UPDATE_STEP)) {
safe_function(core["__builtin"]["update_entities"], static_cast<double>(UPDATE_STEP));
this->delta -= static_cast<double>(UPDATE_STEP);
}
}
@ -76,15 +76,17 @@ void ServerLuaParser::playerConnected(std::shared_ptr<ServerClient> client) {
auto players = core.get<sol::table>("players");
players.add(ServerLuaPlayer(*client));
core["__builtin"]["trigger_event"]("new_player", players[players.size()]);
core["__builtin"]["trigger_event"]("player_join", players[players.size()]);
ServerLuaPlayer& player = players[players.size()];
safe_function(core["__builtin"]["trigger_event"], "new_player", player);
safe_function(core["__builtin"]["trigger_event"], "player_join", player);
}
void ServerLuaParser::playerDisconnected(std::shared_ptr<ServerClient> client) {
for (auto& pair : core.get<sol::table>("players")) {
ServerLuaPlayer& p = pair.second.as<ServerLuaPlayer>();
if (p.cid == client->cid) {
core["__builtin"]["trigger_event"]("player_disconnect", p);
safe_function(core["__builtin"]["trigger_event"], "player_disconnect", p);
p.is_player = false;
core.get<sol::table>("players")[pair.first] = sol::nil;
@ -100,10 +102,10 @@ void ServerLuaParser::loadApi(ServerGame &defs, ServerWorld &world) {
core["__builtin"] = lua.create_table();
// Types
ServerApi::entity (lua);
ServerApi::server_player(lua);
ServerApi::inventory (lua);
ClientApi::item_stack (lua);
ServerApi::entity (lua);
ServerApi::server_player (lua);
ServerApi::inventory (lua);
ClientApi::item_stack (lua);
core["server"] = true;
core["players"] = lua.create_table();
@ -143,7 +145,7 @@ void ServerLuaParser::registerDefs(ServerGame &defs) {
RegisterBiomes::server(core, defs);
}
sol::protected_function_result ServerLuaParser::errorCallback(lua_State*, sol::protected_function_result errPfr) {
sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result errPfr) {
sol::error err = errPfr;
std::string errString = err.what();
@ -200,8 +202,7 @@ sol::protected_function_result ServerLuaParser::runFileSandboxed(const std::stri
env["_FILE"] = f.path;
env["_MODNAME"] = mod.config.name;
return lua.safe_script(f.file, env, std::bind(&ServerLuaParser::errorCallback, this,
std::placeholders::_1, std::placeholders::_2), "@" + f.path);
return lua.safe_script(f.file, env, std::bind(&ServerLuaParser::errorCallback, this, std::placeholders::_2), "@" + f.path);
}
}

View File

@ -20,11 +20,16 @@ public:
void playerConnected(std::shared_ptr<ServerClient> client);
void playerDisconnected(std::shared_ptr<ServerClient> client);
template<typename... Args> void safe_function(sol::protected_function f, Args... args) {
auto res = f(args...);
if (!res.valid()) errorCallback(res);
}
private:
void loadApi(ServerGame& defs, ServerWorld& world);
void registerDefs(ServerGame &defs);
sol::protected_function_result errorCallback(lua_State*, sol::protected_function_result errPfr);
sol::protected_function_result errorCallback(sol::protected_function_result errPfr);
sol::protected_function_result runFileSandboxed(const std::string& file);
ServerModHandler handler;

View File

@ -128,30 +128,26 @@ void Server::handlePlayerPacket(ServerClient &client, Packet& p) {
if (block == DefinitionAtlas::AIR) {
auto def = defs.defs.blockFromId(worldBlock);
if (def.callbacks.count(Callback::BREAK))
def.callbacks[Callback::BREAK](defs.parser.vecToTable(pos), ServerLuaPlayer(client));
defs.parser.core["__builtin"]["trigger_event"]("break", defs.parser.vecToTable(pos), ServerLuaPlayer(client));
if (def.callbacks.count(Callback::BREAK)) def.callbacks[Callback::BREAK](defs.parser.luaVec(pos), ServerLuaPlayer(client));
defs.parser.safe_function(defs.parser.core["__builtin"]["trigger_event"], "break", defs.parser.luaVec(pos), ServerLuaPlayer(client));
}
else {
auto def = defs.defs.blockFromId(block);
if (def.callbacks.count(Callback::PLACE))
def.callbacks[Callback::PLACE](defs.parser.vecToTable(pos), ServerLuaPlayer(client));
defs.parser.core["__builtin"]["trigger_event"]("place", defs.parser.vecToTable(pos), ServerLuaPlayer(client));
if (def.callbacks.count(Callback::PLACE)) def.callbacks[Callback::PLACE](defs.parser.luaVec(pos), ServerLuaPlayer(client));
defs.parser.safe_function(defs.parser.core["__builtin"]["trigger_event"], "place", defs.parser.luaVec(pos), ServerLuaPlayer(client));
}
world.setBlock(pos, block);
if (block == DefinitionAtlas::AIR) {
auto def = defs.defs.blockFromId(worldBlock);
if (def.callbacks.count(Callback::AFTER_BREAK))
def.callbacks[Callback::AFTER_BREAK](defs.parser.vecToTable(pos), ServerLuaPlayer(client));
defs.parser.core["__builtin"]["trigger_event"]("after_break", defs.parser.vecToTable(pos), ServerLuaPlayer(client));
if (def.callbacks.count(Callback::AFTER_BREAK)) def.callbacks[Callback::AFTER_BREAK](defs.parser.luaVec(pos), ServerLuaPlayer(client));
defs.parser.safe_function(defs.parser.core["__builtin"]["trigger_event"], "after_break", defs.parser.luaVec(pos), ServerLuaPlayer(client));
}
else {
auto def = defs.defs.blockFromId(block);
if (def.callbacks.count(Callback::AFTER_PLACE))
def.callbacks[Callback::AFTER_PLACE](defs.parser.vecToTable(pos), ServerLuaPlayer(client));
defs.parser.core["__builtin"]["trigger_event"]("after_place", defs.parser.vecToTable(pos), ServerLuaPlayer(client));
if (def.callbacks.count(Callback::AFTER_PLACE)) def.callbacks[Callback::AFTER_PLACE](defs.parser.luaVec(pos), ServerLuaPlayer(client));
defs.parser.safe_function(defs.parser.core["__builtin"]["trigger_event"], "after_place", defs.parser.luaVec(pos), ServerLuaPlayer(client));
}
break;
}

View File

@ -188,13 +188,13 @@ void ServerWorld::setBlock(glm::ivec3 pos, unsigned int block) {
if (block == DefinitionAtlas::AIR) {
auto def = defs.defs.blockFromId(oldBlock);
if (def.callbacks.count(Callback::DESTRUCT)) {
def.callbacks[Callback::DESTRUCT](defs.parser.vecToTable(pos));
def.callbacks[Callback::DESTRUCT](defs.parser.luaVec(pos));
}
}
else {
auto def = defs.defs.blockFromId(block);
if (def.callbacks.count(Callback::CONSTRUCT)) {
def.callbacks[Callback::CONSTRUCT](defs.parser.vecToTable(pos));
def.callbacks[Callback::CONSTRUCT](defs.parser.luaVec(pos));
}
}
@ -225,13 +225,13 @@ void ServerWorld::setBlock(glm::ivec3 pos, unsigned int block) {
if (block == DefinitionAtlas::AIR) {
auto def = defs.defs.blockFromId(oldBlock);
if (def.callbacks.count(Callback::AFTER_DESTRUCT)) {
def.callbacks[Callback::AFTER_DESTRUCT](defs.parser.vecToTable(pos));
def.callbacks[Callback::AFTER_DESTRUCT](defs.parser.luaVec(pos));
}
}
else {
auto def = defs.defs.blockFromId(block);
if (def.callbacks.count(Callback::AFTER_CONSTRUCT)) {
def.callbacks[Callback::AFTER_CONSTRUCT](defs.parser.vecToTable(pos));
def.callbacks[Callback::AFTER_CONSTRUCT](defs.parser.luaVec(pos));
}
}
}

View File

@ -27,7 +27,7 @@ zepha.register_entity("@aurailus:item_collection:dropped_item", {
local x = math.sin(angle) * amp
local z = math.cos(angle) * amp
self.vel = static.vel or v(x, -85, z)
self.vel = static.vel or V(x, -85, z)
if (not zepha.registered_blocks[self.item]) {
self.object.scale = 1/2
@ -62,15 +62,15 @@ zepha.register_entity("@aurailus:item_collection:dropped_item", {
interval = -1/16
}
self.object.pos = vector.add(self.object.pos, v(0, interval, 0))
self.object.pos += V(0, interval, 0)
iter += 0.25
}
self.object.pos = vector.add(self.object.pos, vector.multiply(v(self.vel.x, 0, self.vel.z), delta))
self.object.pos += V(self.vel.x, 0, self.vel.z) * delta
self.vel.x *= 0.6
self.vel.z *= 0.6
self.object.visual_offset = v(0, math.sin(self.time * 2) / 8, 0)
self.object.visual_offset = V(0, math.sin(self.time * 2) / 8, 0)
if (collides(self.object)) {
self.vel.y = 0
@ -85,7 +85,7 @@ zepha.register_entity("@aurailus:item_collection:dropped_item", {
check_collect = fn(self) {
foreach p in zepha.players {
if (vector.distance(p.pos, self.object.pos) < 2) {
self.object.pos = vector.add(p.pos, v(0, 0.90, 0))
self.object.pos = p.pos + V(0, 0.90, 0)
self.scooping = true
zepha.delay(() => {

View File

@ -5,6 +5,6 @@ if (zepha.server) {
local yields = get_yield(pos)
if (yields == nil) { return }
zepha.add_entity("@aurailus:item_collection:dropped_item", vector.add(pos, v(0.5)), { item = yields });
zepha.add_entity("@aurailus:item_collection:dropped_item", pos + 0.5, { item = yields });
})
}

View File

@ -1,87 +1,172 @@
-- Zepha Vector Library
-- Version 1.0
-- Vector metatable
-- A metatable to be assigned to vectors which applies mathematic operators
local vector_mt = {
__is_vector = true,
__index = function(tbl, key)
if key == "x" then return rawget(tbl, 1) end
if key == "y" then return rawget(tbl, 2) end
if key == "z" then return rawget(tbl, 3) end
local val = rawget(tbl, key)
if val == nil then val = rawget(getmetatable(tbl), key) end
return val
end,
__newindex = function(tbl, key, val)
if key == "x" or key == 0 then rawset(tbl, 1, val)
elseif key == "y" or key == 1 then rawset(tbl, 2, val)
elseif key == "z" or key == 2 then rawset(tbl, 3, val) end
end,
__tostring = function(tbl)
return table.concat({
"{ ",
tostring(tbl[1]), ", ",
tostring(tbl[2]), ", ",
tostring(tbl[3]), " }"
})
end,
__eq = function(tbl, o)
return vector.equal(tbl, o)
end,
__unm = function(tbl)
return vector.negative(tbl)
end,
__add = function(tbl, o)
return vector.add(tbl, o)
end,
__sub = function(tbl, o)
return vector.subtract(tbl, o)
end,
__mul = function(tbl, o)
return vector.multiply(tbl, o)
end,
__pow = function(tbl, power)
local curr = tbl
for i = 1, power - 1 do
curr = curr * tbl
end
return curr
end,
}
-- create_vector
-- Create a new vector, and give it a metatable.
-- x, y, and z must all be numbers.
local function create_vector(x, y, z)
local vector = {x, y, z}
setmetatable(vector, vector_mt)
return vector
end
-- check_vector
-- Checks if a value is a vector.
local function check_vector(v)
if type(v) ~= "table" or not v.__is_vector then return false end
return true
end
_G["vector"] = {}
-- vector.new
-- Constructor function for creating vectors from a table or 2-4 values.
-- Table constructor works with 1-4 values
-- Constructor function for creating vectors from a table or 2-3 values.
-- Table constructor works with 1-3 values
vector.new = function(x, y, z)
if x == nil then return {x = 0, y = 0, z = 0}
-- Blank new constructor, return empty vector
if x == nil then return create_vector(0, 0, 0)
-- Invalid type passed to function, return nil
elseif type(x) ~= "number" and type(x) ~= "table" then return nil
elseif type(x) == "table" then return {x = x[1], y = x[2], z = x[3]}
elseif y == nil then return {x = x, y = x, z = x} end
return {x = x, y = y, z = z}
-- Passed a table as x with at least x and y parameters, z will be set to table value or 0
elseif type(x) == "table" and (x.__is_vector or (type(x[1]) == "number" and type(x[2]) == "number")) then return create_vector(x[1], x[2], x[3] or 0)
-- Only one number was passed, give a vector with all three values set to it
elseif y == nil then return create_vector(x, x, x)
-- Invalid type passed to function, return nil
elseif (type(y) ~= "number" and type(y) ~= "table") or type(z) ~= "number" then return end
-- Create a vector with the values x, y, and z
return create_vector(x, y, z)
end
-- vector.new shorthand
_G["v"] = vector.new
_G["V"] = vector.new
-- vector.add
-- Add two vectors
-- Add two vectors or a vector and number
vector.add = function(v1, v2)
if type(v1) ~= "table" or type(v2) ~= "table" then return nil end
return {x = (v1.x or 0) + (v2.x or 0), y = (v1.y or 0) + (v2.y or 0), z = (v1.z or 0) + (v2.z or 0)}
if not check_vector(v1) then return end
if check_vector(v2) then
return create_vector(rawget(v1, 1) + rawget(v2, 1), rawget(v1, 2) + rawget(v2, 2), rawget(v1, 3) + rawget(v2, 3))
elseif type(v2) == "number" then
return create_vector(rawget(v1, 1) + v2, rawget(v1, 2) + v2, rawget(v1, 3) + v2)
end
end
-- vector.negative
-- Flips a vector's content's signs
vector.negative = function(v)
if type(v) ~= "table" then return nil end
return {x = -(v.x or nil), y = -(v.y or nil), z = -(v.z or nil)}
if not check_vector(v) then return end
return create_vector(-rawget(v, 1), -rawget(v, 2), -rawget(v, 3))
end
-- vector.subtract
-- Subtract v2 from v1
vector.subtract = function(v1, v2)
if type(v1) ~= "table" or type(v2) ~= "table" then return nil end
return vector.add(v1, vector.negative(v2))
end
-- vector.multiply
-- Multiply v1 by a vector or number
vector.multiply = function(v1, m)
if type(v1) ~= "table" then return nil end
if type(m) == "table" then
return {x = (v1.x or 0) * (m.x or 0), y = (v1.y or 0) * (m.y or 0), z = (v1.z or 0) * (m.z or 0)}
if not check_vector(v1) then return end
if check_vector(m) then
return create_vector(rawget(v1, 1) * rawget(m, 1), rawget(v1, 2) * rawget(m, 2), rawget(v1, 3) * rawget(m, 3))
elseif type(m) == "number" then
return {x = (v1.x or 0) * m, y = (v1.y or 0) * m, z = (v1.z or 0) * m}
else return nil end
return create_vector(rawget(v1, 1) * m, rawget(v1, 2) * m, rawget(v1, 3) * m)
end
end
-- vector.equal
-- Return a boolean indicating if v1 == v2
vector.equal = function(v1, v2)
if not check_vector(v1) or not check_vector(v2) then return end
return (rawget(v1, 1) == rawget(v2, 1) and rawget(v1, 2) == rawget(v2, 2) and rawget(v1, 3) == rawget(v2, 3))
end
-- vector.abs
-- Return the absolute value of v
vector.abs = function(v)
if type(v) ~= "table" then return nil end
return {x = math.abs(v.x), y = math.abs(v.y), z = math.abs(v.z)}
if not check_vector(v) then return end
return create_vector(math.abs(rawget(v, 1)), math.abs(rawget(v, 2)), math.abs(rawget(v, 3)))
end
-- vector.round
-- Round each vector value to the nearest integer
vector.round = function(v)
if type(v) ~= "table" then return nil end
return {x = math.round(v.x), y = math.round(v.y), z = math.round(v.z)}
if not check_vector(v) then return end
return create_vector(math.round(rawget(v, 1)), math.round(rawget(v, 2)), math.round(rawget(v, 3)))
end
-- vector.floor
-- Floor each vector value to the lowest integer
vector.floor = function(v)
if type(v) ~= "table" then return nil end
return {x = math.floor(v.x), y = math.floor(v.y), z = math.floor(v.z)}
if not check_vector(v) then return end
return create_vector(math.floor(rawget(v, 1)), math.floor(rawget(v, 2)), math.floor(rawget(v, 3)))
end
-- vector.ceil
-- Ceil each vector value to the highest integer
vector.floor = function(v)
if type(v) ~= "table" then return nil end
return {x = math.ceil(v.x), y = math.ceil(v.y), z = math.ceil(v.z)}
if not check_vector(v) then return end
return create_vector(math.ceil(rawget(v, 1)), math.ceil(rawget(v, 2)), math.ceil(rawget(v, 3)))
end
-- vector.distance_squared
-- Get the square of the distance between two vectors
-- This function is faster if you only need to compare two distances
vector.distance_squared = function(v1, v2)
if type(v1) ~= "table" or type(v2) ~= "table" then return nil end
if not check_vector(v1) or not check_vector(v2) then return end
local diff = vector.abs(vector.subtract(v1, v2))
return diff.x ^ 2 + diff.y ^ 2 + diff.z ^ 2
end
@ -89,5 +174,6 @@ end
-- vector.distance
-- Get the distance between two vectors
vector.distance = function(v1, v2)
if not check_vector(v1) or not check_vector(v2) then return end
return math.sqrt(vector.distance_squared(v1, v2))
end

View File

@ -11,13 +11,12 @@ zepha.register_entity("zeus:default:test", {
## self.object.scale = 1/4
},
on_update = fn(self, delta) {
self.object.pos = vector.add(vector.multiply(v(0.6 * math.sin(math.rad(self.object.yaw)), 0,
0.6 * math.cos(math.rad(self.object.yaw))), delta), self.object.pos)
self.object.pos = self.object.pos +
V(0.6 * math.sin(math.rad(self.object.yaw)), 0, 0.6 * math.cos(math.rad(self.object.yaw))) * delta
self.object.yaw += 50 * delta
}
})
if (zepha.server) {
local entity = zepha.add_entity("zeus:default:test", v(0, 0, 0))
##zepha.delay(() => { zepha.remove_entity(entity) }, 10)
local entity = zepha.add_entity("zeus:default:test", V(0, 0, 0))
}