Item use callbacks implemented, spawn keys~

master
Auri 2020-12-05 23:10:22 -08:00
parent 52ae370040
commit a1896767eb
21 changed files with 160 additions and 69 deletions

View File

@ -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

View File

@ -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);
}
}

View File

@ -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);

View File

@ -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);
}

View File

@ -31,6 +31,8 @@ public:
void createModel(TextureAtlas& atlas);
bool hasUse();
std::vector<std::string> textures {};
std::vector<std::shared_ptr<AtlasRef>> textureRefs {};

View File

@ -71,7 +71,7 @@ namespace Api::Usertype {
};
class LocalPlayer : public ServerPlayer {
public:
public:
LocalPlayer(PlayerPtr player) : ServerPlayer(player) {}
bool is_in_menu();

View File

@ -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)
);
}

View File

@ -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);
};

View File

@ -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()))

View File

@ -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

View File

@ -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,

View File

@ -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));

View File

@ -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);

View File

@ -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);

View File

@ -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);

View File

@ -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");
}
}

View File

@ -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;

View File

@ -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

View File

@ -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

View File

@ -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" ]
}

View File

@ -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