Item use callbacks implemented, spawn keys~
parent
52ae370040
commit
a1896767eb
|
@ -1,6 +1,8 @@
|
|||
|
||||
-- zepha.block_interact_or_place(player: Player , target: Target [, stack: ItemStack]): ItemStack, Vector | nil
|
||||
-- Calls zepha.block_interact if the targeted block can be interacted with, returns the passed in stack or wield stack and nil.
|
||||
-- Otherwise, calls zepha.block_place and returned the function's returned values.
|
||||
|
||||
function zepha.block_interact_or_place(player, target, stack)
|
||||
local stack = stack or player:get_wield_stack()
|
||||
local target_block = target.dim:get_block(target.pos)
|
||||
|
@ -20,9 +22,11 @@ function zepha.block_interact_or_place(player, target, stack)
|
|||
return zepha.block_place(player, target, stack)
|
||||
end
|
||||
|
||||
|
||||
-- zepha.block_interact(player: Player, target: Target): nil
|
||||
-- Interacts with the targeted block. Returns true if the block has an on_interact or
|
||||
-- on_interact_client callback, returns false otherwise.
|
||||
|
||||
function zepha.block_interact(player, target)
|
||||
local block = target.dim:get_block(target.pos)
|
||||
local def = zepha.registered_blocks[block]
|
||||
|
@ -35,10 +39,12 @@ function zepha.block_interact(player, target)
|
|||
return def.on_interact or def.on_interact_client
|
||||
end
|
||||
|
||||
|
||||
-- zepha.block_place(player: Player, target: Target [, stack: ItemStack]): ItemStack, Vector | nil
|
||||
-- Attempts to place `stack` or the wield stack in the world, on success returning the
|
||||
-- wield stack with one count removed, and the placed position, or on failure returning the
|
||||
-- original stack and nil.
|
||||
|
||||
function zepha.block_place(player, target, stack)
|
||||
local stack = stack or player:get_wield_stack()
|
||||
local stack_def = zepha.registered_blocks[stack and stack.name or nil]
|
||||
|
@ -50,9 +56,11 @@ function zepha.block_place(player, target, stack)
|
|||
return stack, target.pos_above
|
||||
end
|
||||
|
||||
|
||||
-- zepha.block_hit(player: Player, target: Target): float, float
|
||||
-- Hits the block at `target` using the player's wielded item.
|
||||
-- Returns the damage done followed by the timeout before the next hit can begin.
|
||||
|
||||
function zepha.block_hit(player, target)
|
||||
local block = player.dim:get_block(target.pos)
|
||||
local def = zepha.registered_blocks[block]
|
||||
|
@ -71,8 +79,10 @@ function zepha.block_hit(player, target)
|
|||
return damage, timeout
|
||||
end
|
||||
|
||||
|
||||
-- zepha.block_break(player: Player, target: Target):
|
||||
-- Breaks the block at `target`.
|
||||
|
||||
function zepha.block_break(player, target)
|
||||
local block = player.dim:get_block(target.pos)
|
||||
local def = zepha.registered_blocks[block] or {}
|
||||
|
@ -88,4 +98,22 @@ function zepha.block_break(player, target)
|
|||
local cb = zepha.server and "after_break" or "after_break_client"
|
||||
if type(def[cb]) == "function" then def[cb](table.unpack(args)) end
|
||||
zepha.trigger(cb, table.unpack(args))
|
||||
end
|
||||
|
||||
|
||||
-- zepha.item_use(player: Player, target: Target [, stack: ItemStack]): ItemStack
|
||||
-- Attempts to use `stack` or the wield stack in,
|
||||
-- returning a modified wieldstack or nil if the stack is unchanged.
|
||||
|
||||
function zepha.item_use(player, target, stack)
|
||||
local stack = stack or player:get_wield_stack()
|
||||
local def = zepha.registered_items[stack and stack.name or nil]
|
||||
|
||||
if stack == nil or def == nil then return stack end
|
||||
|
||||
local args = { stack, target, player }
|
||||
local cb = zepha.server and "on_use" or "on_use_client"
|
||||
|
||||
if type(def[cb]) == "function" then return def[cb](table.unpack(args)) end
|
||||
return nil
|
||||
end
|
|
@ -123,6 +123,10 @@ void ClientNetworkInterpreter::blockPlaceOrInteract(const Target& target) {
|
|||
.packet(Packet::Type::BLOCK_PLACE_OR_INTERACT).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
|
||||
}
|
||||
|
||||
void ClientNetworkInterpreter::wieldItemUse(const Target& target) {
|
||||
Serializer().packet(Packet::Type::WIELD_ITEM_USE).sendTo(connection.getPeer(), Packet::Channel::INTERACT);
|
||||
}
|
||||
|
||||
void ClientNetworkInterpreter::invWatch(const std::string& inv, const std::string& list) {
|
||||
Serializer().append(inv).append(list).packet(Packet::Type::INV_WATCH)
|
||||
.sendTo(connection.getPeer(), Packet::Channel::INTERACT);
|
||||
|
@ -141,4 +145,4 @@ void ClientNetworkInterpreter::invInteract(const std::string& inv, const std::st
|
|||
|
||||
void ClientNetworkInterpreter::sendPacket(const Packet& packet, Packet::Channel channel) {
|
||||
packet.sendTo(connection.getPeer(), channel);
|
||||
}
|
||||
}
|
|
@ -44,6 +44,8 @@ class ClientNetworkInterpreter {
|
|||
|
||||
void blockPlaceOrInteract(const Target& target);
|
||||
|
||||
void wieldItemUse(const Target& target);
|
||||
|
||||
void invWatch(const std::string& inv, const std::string& list);
|
||||
|
||||
void invUnwatch(const std::string& inv, const std::string& list);
|
||||
|
|
|
@ -103,4 +103,8 @@ void CraftItemDef::createModel(TextureAtlas& atlas) {
|
|||
|
||||
mesh->create(vertices, indices);
|
||||
entityModel->fromMesh(std::move(mesh));
|
||||
}
|
||||
}
|
||||
|
||||
bool CraftItemDef::hasUse() {
|
||||
return callbacks.count(CraftItemDef::Callback::USE) || callbacks.count(CraftItemDef::Callback::USE_CLIENT);
|
||||
}
|
||||
|
|
|
@ -31,6 +31,8 @@ public:
|
|||
|
||||
void createModel(TextureAtlas& atlas);
|
||||
|
||||
bool hasUse();
|
||||
|
||||
std::vector<std::string> textures {};
|
||||
std::vector<std::shared_ptr<AtlasRef>> textureRefs {};
|
||||
|
||||
|
|
|
@ -71,7 +71,7 @@ namespace Api::Usertype {
|
|||
};
|
||||
|
||||
class LocalPlayer : public ServerPlayer {
|
||||
public:
|
||||
public:
|
||||
LocalPlayer(PlayerPtr player) : ServerPlayer(player) {}
|
||||
|
||||
bool is_in_menu();
|
||||
|
|
|
@ -6,24 +6,28 @@
|
|||
|
||||
#include "../Lua.h"
|
||||
|
||||
Api::Usertype::Target::Target(const ::Target& target) :
|
||||
pos(target.data.block.pos),
|
||||
type(target.type),
|
||||
dim(Dimension(target.dim)),
|
||||
pos_above(target.getAbovePos()) {}
|
||||
|
||||
std::string Api::Usertype::Target::getType() {
|
||||
return type == ::Target::Type::BLOCK ? "block" :
|
||||
type == ::Target::Type::ENTITY ? "entity" :
|
||||
"nothing";
|
||||
Api::Usertype::Target::Target(const ::Target& target) {
|
||||
if (target.type == ::Target::Type::BLOCK) {
|
||||
type = "block";
|
||||
dim = target.dim;
|
||||
pos = target.data.block.pos;
|
||||
pos_above = target.getAbovePos();
|
||||
}
|
||||
else if (target.type == ::Target::Type::ENTITY) {
|
||||
type = "entity";
|
||||
dim = target.dim;
|
||||
id = target.data.entity.id;
|
||||
}
|
||||
else type = "nothing";
|
||||
}
|
||||
|
||||
void Api::Usertype::Target::bind(State, sol::state& lua, sol::table& core) {
|
||||
lua.new_usertype<Target>("Target",
|
||||
"type", sol::property(&Target::getType),
|
||||
"type", sol::readonly(&Target::type),
|
||||
|
||||
"pos", sol::readonly(&Target::pos),
|
||||
"id", sol::readonly(&Target::id),
|
||||
"dim", sol::readonly(&Target::dim),
|
||||
"pos", sol::readonly(&Target::pos),
|
||||
"pos_above", sol::readonly(&Target::pos_above)
|
||||
);
|
||||
}
|
|
@ -13,16 +13,14 @@
|
|||
|
||||
namespace Api::Usertype {
|
||||
class Target : public SubgameUsertype {
|
||||
public:
|
||||
public:
|
||||
Target(const ::Target& target);
|
||||
|
||||
std::string getType();
|
||||
|
||||
::Target::Type type;
|
||||
|
||||
Dimension dim;
|
||||
glm::ivec3 pos;
|
||||
glm::ivec3 pos_above;
|
||||
std::string type;
|
||||
std::optional<long long> id;
|
||||
std::optional<Dimension> dim;
|
||||
std::optional<glm::ivec3> pos;
|
||||
std::optional<glm::ivec3> pos_above;
|
||||
|
||||
static void bind(State state, sol::state& lua, sol::table& core);
|
||||
};
|
||||
|
|
|
@ -136,6 +136,10 @@ void Server::playerPacketReceived(PacketView& p, PlayerPtr player) {
|
|||
player->getDim()->blockPlaceOrInteract(Target(player->getDim(), pos, face), player);
|
||||
break;
|
||||
|
||||
case Packet::Type::WIELD_ITEM_USE:
|
||||
player->getDim()->wieldItemUse(Target(), player);
|
||||
break;
|
||||
|
||||
case Packet::Type::INV_WATCH:
|
||||
p.d.read<std::string>(source).read<std::string>(list);
|
||||
if (!world->getRefs().s()->addWatcher(source, list, player->getId()))
|
||||
|
|
|
@ -35,6 +35,8 @@ class Packet {
|
|||
// Block
|
||||
BLOCK_HIT, BLOCK_PLACE, BLOCK_INTERACT,
|
||||
BLOCK_PLACE_OR_INTERACT, BLOCK_SET,
|
||||
// Item
|
||||
WIELD_ITEM_USE,
|
||||
// Entity
|
||||
ENTITY_INFO, ENTITY_REMOVED,
|
||||
// Inventory
|
||||
|
|
|
@ -36,6 +36,8 @@ public:
|
|||
|
||||
virtual void blockInteract(const Target& target, PlayerPtr player) = 0;
|
||||
|
||||
virtual void wieldItemUse(const Target& target, PlayerPtr player) = 0;
|
||||
|
||||
virtual long long nextEntityInd() = 0;
|
||||
|
||||
// Calculate light propogation around MapBlock edges,
|
||||
|
|
|
@ -151,6 +151,17 @@ double LocalDimension::blockHit(const Target& target, PlayerPtr player) {
|
|||
return timeout;
|
||||
}
|
||||
|
||||
void LocalDimension::wieldItemUse(const Target& target, PlayerPtr player) {
|
||||
sol::optional<Api::Usertype::ItemStack> stack = game->getParser().safe_function(
|
||||
game->getParser().core["item_use"], Api::Usertype::LocalPlayer(player.l()), Api::Usertype::Target(target));
|
||||
|
||||
static_cast<LocalWorld&>(world).getNet().wieldItemUse(target);
|
||||
|
||||
auto inv = player->getInventory();
|
||||
if (stack && inv->hasList(player->getWieldList()))
|
||||
inv->getList(player->getWieldList())->setStack(player->getWieldIndex(), ItemStack(*stack, game));
|
||||
}
|
||||
|
||||
void LocalDimension::setMeshChunk(std::shared_ptr<MeshChunk> meshChunk) {
|
||||
if (renderRefs.count(meshChunk->getPos())) removeMeshChunk(meshChunk->getPos());
|
||||
renderElems.push_back(std::static_pointer_cast<ChunkRenderElem>(meshChunk));
|
||||
|
|
|
@ -46,6 +46,8 @@ public:
|
|||
|
||||
virtual double blockHit(const Target& target, PlayerPtr player) override;
|
||||
|
||||
virtual void wieldItemUse(const Target& target, PlayerPtr player) override;
|
||||
|
||||
void setMeshChunk(std::shared_ptr<MeshChunk> chunk);
|
||||
|
||||
void removeMeshChunk(const glm::ivec3& pos);
|
||||
|
|
|
@ -85,6 +85,15 @@ void ServerDimension::blockPlaceOrInteract(const Target& target, PlayerPtr playe
|
|||
inv->getList(player->getWieldList())->setStack(player->getWieldIndex(), ItemStack(*stack, game));
|
||||
}
|
||||
|
||||
void ServerDimension::wieldItemUse(const Target& target, PlayerPtr player) {
|
||||
sol::optional<Api::Usertype::ItemStack> stack = game->getParser().safe_function(
|
||||
game->getParser().core["item_use"], Api::Usertype::ServerPlayer(player), Api::Usertype::Target(target));
|
||||
|
||||
auto inv = player->getInventory();
|
||||
if (stack && inv->hasList(player->getWieldList()))
|
||||
inv->getList(player->getWieldList())->setStack(player->getWieldIndex(), ItemStack(*stack, game));
|
||||
}
|
||||
|
||||
void ServerDimension::setChunk(std::shared_ptr<Chunk> chunk) {
|
||||
std::shared_ptr<Chunk> existing = getChunk(chunk->getPos());
|
||||
if (existing) chunk = combineChunks(chunk, existing);
|
||||
|
|
|
@ -33,6 +33,8 @@ class ServerDimension : public Dimension {
|
|||
|
||||
virtual double blockHit(const Target& target, PlayerPtr player) override;
|
||||
|
||||
virtual void wieldItemUse(const Target& target, PlayerPtr player) override;
|
||||
|
||||
virtual long long nextEntityInd() override;
|
||||
|
||||
void addLuaEntity(Api::Usertype::Entity entity);
|
||||
|
|
|
@ -8,9 +8,12 @@
|
|||
#include "world/LocalWorld.h"
|
||||
#include "game/def/BlockDef.h"
|
||||
#include "util/net/NetField.h"
|
||||
#include "lua/usertype/Player.h"
|
||||
#include "lua/usertype/Target.h"
|
||||
#include "client/graph/Renderer.h"
|
||||
#include "world/dim/chunk/Chunk.h"
|
||||
#include "util/net/Deserializer.h"
|
||||
#include "game/def/CraftItemDef.h"
|
||||
#include "world/dim/ent/Collision.h"
|
||||
#include "client/conn/ClientNetworkInterpreter.h"
|
||||
|
||||
|
@ -41,7 +44,7 @@ void LocalPlayer::update(Input& input, double delta, glm::vec2 mouseDelta) {
|
|||
findTarget(input);
|
||||
updateWireframe();
|
||||
|
||||
if (!gameGui.isInMenu()) interact(input, delta);
|
||||
if (!gameGui.isInMenu()) updateInteract(input, delta);
|
||||
}
|
||||
|
||||
void LocalPlayer::setPos(glm::vec3 pos, bool assert) {
|
||||
|
@ -399,20 +402,42 @@ void LocalPlayer::findTarget(Input& input) {
|
|||
target = newTarget;
|
||||
}
|
||||
|
||||
void LocalPlayer::interact(Input& input, double delta) {
|
||||
if (target.type == Target::Type::BLOCK) {
|
||||
if (input.mouseDown(GLFW_MOUSE_BUTTON_LEFT) && breakTime == 0) {
|
||||
void LocalPlayer::updateInteract(Input& input, double delta) {
|
||||
if (breakTime > 0) breakTime += delta;
|
||||
if (breakTime > breakInterval) breakTime = 0;
|
||||
|
||||
if (input.mouseDown(GLFW_MOUSE_BUTTON_LEFT)) {
|
||||
if (target.type == Target::Type::BLOCK && breakTime == 0) {
|
||||
auto& targetedBlock = game->getDefs().blockFromId(dim->getBlock(target.data.block.pos));
|
||||
breakInterval = dim->blockHit(target, static_cast<LocalWorld&>(dim->getWorld()).getPlayer());
|
||||
breakTime += delta;
|
||||
}
|
||||
else if (input.mousePressed(GLFW_MOUSE_BUTTON_RIGHT))
|
||||
dim->blockPlaceOrInteract(target, static_cast<LocalWorld&>(dim->getWorld()).getPlayer());
|
||||
}
|
||||
|
||||
if (breakTime > 0) breakTime += delta;
|
||||
if (breakTime > breakInterval) breakTime = 0;
|
||||
else if (input.mousePressed(GLFW_MOUSE_BUTTON_RIGHT)) {
|
||||
if (target.type == Target::Type::BLOCK) {
|
||||
auto& wieldItem = game->getDefs().fromId(this->wieldItem);
|
||||
auto& targetedBlock = game->getDefs().blockFromId(dim->getBlock(target.data.block.pos));
|
||||
|
||||
if (targetedBlock.hasInteraction())
|
||||
dim->blockInteract(target, static_cast<LocalWorld&>(dim->getWorld()).getPlayer());
|
||||
else if (wieldItem.type == ItemDef::Type::CRAFTITEM && static_cast<CraftItemDef&>(wieldItem).hasUse())
|
||||
dim->wieldItemUse(target, static_cast<LocalWorld&>(dim->getWorld()).getPlayer());
|
||||
else if (wieldItem.type == ItemDef::Type::BLOCK)
|
||||
dim->blockPlace(target, static_cast<LocalWorld&>(dim->getWorld()).getPlayer());
|
||||
}
|
||||
else if (target.type == Target::Type::ENTITY) {
|
||||
auto& wieldItem = game->getDefs().fromId(this->wieldItem);
|
||||
if (wieldItem.type == ItemDef::Type::CRAFTITEM && static_cast<CraftItemDef&>(wieldItem).hasUse())
|
||||
dim->wieldItemUse(target, static_cast<LocalWorld&>(dim->getWorld()).getPlayer());
|
||||
}
|
||||
else {
|
||||
auto& wieldItem = game->getDefs().fromId(this->wieldItem);
|
||||
if (wieldItem.type == ItemDef::Type::CRAFTITEM && static_cast<CraftItemDef&>(wieldItem).hasUse())
|
||||
dim->wieldItemUse(target, static_cast<LocalWorld&>(dim->getWorld()).getPlayer());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
LocalPlayer::~LocalPlayer() {
|
||||
renderer.window.removeResizeCallback("player");
|
||||
}
|
||||
}
|
||||
|
|
|
@ -216,7 +216,7 @@ private:
|
|||
* @param delta - The delta time elapsed in the last frame.
|
||||
*/
|
||||
|
||||
void interact(Input& input, double delta);
|
||||
void updateInteract(Input& input, double delta);
|
||||
|
||||
GameGui gameGui;
|
||||
Renderer& renderer;
|
||||
|
|
|
@ -57,7 +57,7 @@ zepha.register_entity("zeus:default:bee", {
|
|||
}
|
||||
|
||||
local fly = false
|
||||
local def = zepha.registered_blocks[self.object.dim:get_block(self.object.pos - V{ 0, 2, 0 })]
|
||||
local def = zepha.registered_blocks[self.object.dim:get_block(self.object.pos:floor() - V{ 0, 2, 0 })]
|
||||
if def and (def.solid == nil or def.solid ~= false) then fly = true end
|
||||
|
||||
if fly and self.object.vel.y <= 0 then
|
||||
|
@ -68,22 +68,9 @@ zepha.register_entity("zeus:default:bee", {
|
|||
})
|
||||
|
||||
if zepha.server then
|
||||
zepha.bind("message", function(channel, message, player)
|
||||
if channel ~= "zeus:default:spawn" or message ~= "bee" then return end
|
||||
player.dim:add_entity(player.pos + V(0, 1.7, 0), "zeus:default:bee")
|
||||
end)
|
||||
|
||||
zepha.bind("new_player", function(player)
|
||||
for i = 0, 10 do
|
||||
player.dim:add_entity(player.pos + V { math.random(-100, 100), 30, math.random(-100, 100) }, "zeus:default:bee")
|
||||
end
|
||||
end)
|
||||
else
|
||||
zepha.register_keybind("zeus:default:spawn_bee", {
|
||||
description = "Spawn Bee",
|
||||
default = zepha.keys.b,
|
||||
on_press = function()
|
||||
zepha.send_message("zeus:default:spawn", "bee");
|
||||
end
|
||||
})
|
||||
end
|
|
@ -69,22 +69,9 @@ zepha.register_entity("zeus:default:rabbit", {
|
|||
})
|
||||
|
||||
if zepha.server then
|
||||
zepha.bind("message", function(channel, message, player)
|
||||
if channel ~= "zeus:default:spawn" or message ~= "rabbit" then return end
|
||||
player.dim:add_entity(player.pos + V(0, 1.7, 0), "zeus:default:rabbit")
|
||||
end)
|
||||
|
||||
zepha.bind("new_player", function(player)
|
||||
for i = 0, 5 do
|
||||
player.dim:add_entity(player.pos + V { math.random(-100, 100), 30, math.random(-100, 100) }, "zeus:default:rabbit")
|
||||
end
|
||||
end)
|
||||
else
|
||||
zepha.register_keybind("zeus:default:spawn_rabbit", {
|
||||
description = "Spawn Rabbit",
|
||||
default = zepha.keys.v,
|
||||
on_press = function()
|
||||
zepha.send_message("zeus:default:spawn", "rabbit");
|
||||
end
|
||||
})
|
||||
end
|
|
@ -2,6 +2,6 @@
|
|||
"name": "zeus:world",
|
||||
"description": "World and Mapgen definitions for the Zeus subgame.",
|
||||
"version": "0.0.1",
|
||||
"depends": [ "zeus:default", "zeus:flowers" ]
|
||||
"depends": [ "zeus:default", "zeus:flowers", "@auri:hot_wheel" ]
|
||||
}
|
||||
|
||||
|
|
|
@ -1,24 +1,42 @@
|
|||
zepha.register_item(':key_iron', {
|
||||
name = 'Iron Key',
|
||||
textures = { 'zeus:world:key_iron' }
|
||||
textures = { 'zeus:world:key_iron' },
|
||||
|
||||
on_use = function(stack, target, player)
|
||||
player.dim:add_entity(player.pos, "zeus:default:test")
|
||||
stack.count = stack.count - 1
|
||||
return stack
|
||||
end
|
||||
})
|
||||
|
||||
zepha.register_item(':key_silver', {
|
||||
name = 'Silver Key',
|
||||
textures = { 'zeus:world:key_silver' }
|
||||
textures = { 'zeus:world:key_silver' },
|
||||
|
||||
on_use = function(stack, target, player)
|
||||
player.dim:add_entity(player.pos, "zeus:default:rabbit")
|
||||
stack.count = stack.count - 1
|
||||
return stack
|
||||
end
|
||||
})
|
||||
|
||||
zepha.register_item(':key_gold', {
|
||||
name = 'Gold Key',
|
||||
textures = { 'zeus:world:key_gold' }
|
||||
textures = { 'zeus:world:key_gold' },
|
||||
|
||||
on_use = function(stack, target, player)
|
||||
player.dim:add_entity(player.pos, "zeus:default:bee")
|
||||
stack.count = stack.count - 1
|
||||
return stack
|
||||
end
|
||||
})
|
||||
|
||||
if zepha.server then
|
||||
zepha.bind("new_player", function(player)
|
||||
local inv = player:get_inventory():get_list('main')
|
||||
inv:add_stack({'zeus:world:key_iron', 8})
|
||||
inv:add_stack({'zeus:world:key_silver', 4})
|
||||
inv:add_stack({'zeus:world:key_gold', 2})
|
||||
local inv = player:get_inventory():get_list('hot_wheel_2')
|
||||
inv:add_stack({'zeus:world:key_iron', 64})
|
||||
inv:add_stack({'zeus:world:key_silver', 64})
|
||||
inv:add_stack({'zeus:world:key_gold', 64})
|
||||
end)
|
||||
end
|
||||
|
||||
|
|
Loading…
Reference in New Issue