Synchronize block interaction callbacks, wieldlists, etc. Breaking broke

master
Nicole Collings 2020-07-28 14:11:11 -07:00
parent ad029752ef
commit 38b75c212b
39 changed files with 563 additions and 274 deletions

View File

@ -1,4 +1,5 @@
runfile(_PATH .. "models/init") runfile(_PATH .. "models/init")
runfile(_PATH .. "player_interact")
runfile(_PATH .. "inventory") runfile(_PATH .. "inventory")
runfile(_PATH .. "tools") runfile(_PATH .. "tools")

View File

@ -0,0 +1,63 @@
-- 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 = zepha.get_block(target.pos)
local target_def = zepha.registered_blocks[target_block]
local stack_def = zepha.registered_blocks[stack and stack.name or nil]
if target_def and (target_def.on_interact or target_def.on_interact_client) then
-- Trigger an interaction if the targeted block has one.
zepha.block_interact(player, target)
return stack, nil
end
-- Return if stack isn't a block.
if stack == nil or stack_def == nil then return stack, nil end
-- Place a block using the passed in 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 = zepha.get_block(target.pos)
local def = zepha.registered_blocks[block]
local cb = zepha.server and "on_interact" or "on_interact_client"
if type(def[cb]) == "function" then def[cb](target.pos, player) end
zepha.trigger(cb, target.pos, player)
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]
if stack == nil or stack_def == nil then return stack, nil end
zepha.set_block(target.pos_above, stack.name)
stack.count = stack.count - 1
return stack, target.pos_above
end
function zepha.block_hit(player, target)
local block = zepha.get_block(target.pos)
local def = zepha.registered_blocks[block]
-- Don't do anything, return a small timeout to avoid spamming the function.
if not def then return 0, 0.1 end
local damage, timeout = zepha.get_hit_impact(player, block)
zepha.block_damage_add(target.pos, damage)
return damage, timeout
end

View File

@ -1,4 +1,4 @@
set(ZEPHA_SRC add_library(Zepha_Core
def/DefinitionAtlas.cpp def/DefinitionAtlas.cpp
def/DefinitionAtlas.h def/DefinitionAtlas.h
def/gen/BiomeAtlas.cpp def/gen/BiomeAtlas.cpp
@ -200,8 +200,7 @@ set(ZEPHA_SRC
lua/LuaMod.h lua/LuaMod.h
lua/LuaParser.cpp lua/LuaParser.cpp
lua/LuaParser.h lua/LuaParser.h
lua/modules/BaseModule.cpp lua/modules/BaseModule.h
lua/modules/BaseModule.h
lua/modules/Block.cpp lua/modules/Block.cpp
lua/modules/Block.h lua/modules/Block.h
lua/modules/create_structure.h lua/modules/create_structure.h
@ -321,9 +320,7 @@ set(ZEPHA_SRC
world/fs/FileManipulator.h world/fs/FileManipulator.h
world/LocalDimension.cpp world/LocalDimension.cpp
world/LocalDimension.h world/LocalDimension.h
world/PointedThing.h world/Target.h
world/ServerDimension.cpp world/ServerDimension.cpp
world/ServerDimension.h world/ServerDimension.h
) lua/usertype/Target.cpp lua/usertype/Target.h lua/usertype/BaseUsertype.h lua/usertype/SubgameUsertype.h world/Target.cpp)
add_library (Zepha_Core ${ZEPHA_SRC})

View File

@ -58,6 +58,12 @@ void BlockCrackEntity::addDamage(double damage) {
update(); update();
} }
void BlockCrackEntity::setDamage(double damage) {
double diff = damage - (this->damage + damagePending);
std::cout << diff << ", " << this->damage << ", " << damagePending << std::endl;
addDamage(diff);
}
void BlockCrackEntity::addFaces(unsigned int &indOffset, std::vector<EntityVertex> &vertices, std::vector<unsigned int> &indices, std::vector<MeshPart> &meshParts) { void BlockCrackEntity::addFaces(unsigned int &indOffset, std::vector<EntityVertex> &vertices, std::vector<unsigned int> &indices, std::vector<MeshPart> &meshParts) {
for (const MeshPart& mp : meshParts) { for (const MeshPart& mp : meshParts) {
glm::vec4 uv; glm::vec4 uv;
@ -81,4 +87,4 @@ void BlockCrackEntity::addFaces(unsigned int &indOffset, std::vector<EntityVerte
indOffset += mp.vertices.size(); indOffset += mp.vertices.size();
} }
} }

View File

@ -18,6 +18,7 @@ public:
void update(); void update();
void addDamage(double damage); void addDamage(double damage);
void setDamage(double damage);
int maxHealth = 0; int maxHealth = 0;
double damage = 0; double damage = 0;

View File

@ -138,21 +138,19 @@ void DebugGui::update(Player& player, LocalWorld& world, LocalSubgame& game, dou
str << "Texture Slots: " << game.textures.textureSlotsUsed << " / " << game.textures.maxTextureSlots str << "Texture Slots: " << game.textures.textureSlotsUsed << " / " << game.textures.maxTextureSlots
<< " (" << round(game.textures.textureSlotsUsed / static_cast<float>(game.textures.maxTextureSlots) * 100) << "%)" << std::endl << std::endl; << " (" << round(game.textures.textureSlotsUsed / static_cast<float>(game.textures.maxTextureSlots) * 100) << "%)" << std::endl << std::endl;
PointedThing thing = player.getPointedThing(); Target thing = player.getPointedThing();
if (thing.thing == PointedThing::Thing::BLOCK) { if (thing.type == Target::Type::BLOCK) {
EVec faceDir = thing.target.block.face;
std::string face = std::string face =
faceDir == EVec::TOP ? "TOP" : thing.face == EVec::TOP ? "TOP" :
faceDir == EVec::BOTTOM ? "BOTTOM" : thing.face == EVec::BOTTOM ? "BOTTOM" :
faceDir == EVec::LEFT ? "LEFT" : thing.face == EVec::LEFT ? "LEFT" :
faceDir == EVec::RIGHT ? "RIGHT" : thing.face == EVec::RIGHT ? "RIGHT" :
faceDir == EVec::FRONT ? "FRONT" : thing.face == EVec::FRONT ? "FRONT" :
faceDir == EVec::BACK ? "BACK" : thing.face == EVec::BACK ? "BACK" :
"NONE" ; "NONE" ;
str << "Pointing At: " << game.defs->blockFromId(thing.target.block.blockId).identifier << std::endl; str << "Pointing At: " << game.defs->blockFromId(world.getBlock(thing.pos)).identifier << std::endl;
str << "Pointed Position: " << vecToString(thing.target.block.pos) << std::endl; str << "Pointed Position: " << vecToString(thing.pos) << std::endl;
str << "Pointed Face: " << face << std::endl; str << "Pointed Face: " << face << std::endl;
} }
else { else {
@ -163,12 +161,12 @@ void DebugGui::update(Player& player, LocalWorld& world, LocalSubgame& game, dou
} }
{ //Crosshair Text { //Crosshair Text
PointedThing thing = player.getPointedThing(); Target target = player.getPointedThing();
std::ostringstream crossText; std::ostringstream crossText;
if (thing.thing == PointedThing::Thing::BLOCK) { if (target.type == Target::Type::BLOCK) {
crossText << game.defs->blockFromId(thing.target.block.blockId).name crossText << game.defs->blockFromId(world.getBlock(target.pos)).name
<< " (" << game.defs->blockFromId(thing.target.block.blockId).identifier << ")" << std::endl; << " (" << game.defs->blockFromId(world.getBlock(target.pos)).identifier << ")" << std::endl;
} }
get<GuiText>("crosshairText")->setText(crossText.str()); get<GuiText>("crosshairText")->setText(crossText.str());
} }

View File

@ -14,7 +14,7 @@ GameScene::GameScene(ClientState& state) : Scene(state),
game(state.defs), game(state.defs),
world(game, &net), world(game, &net),
net(state.connection, game, player), net(state.connection, game, player),
player(world, game, state.renderer, refs), player(game, world, state.renderer, refs, net),
debugGui(state.renderer.window.getSize(), game) { debugGui(state.renderer.window.getSize(), game) {
namespace ph = std::placeholders; namespace ph = std::placeholders;
@ -23,7 +23,7 @@ GameScene::GameScene(ClientState& state) : Scene(state),
r.sendTo(state.connection.getPeer(), PacketChannel::CONNECT); r.sendTo(state.connection.getPeer(), PacketChannel::CONNECT);
world.init(&player); world.init(&player);
net .init(&world, std::bind(&LocalInventoryRefs::packetReceived, refs, ph::_1)); net .init(&world, Util::bind_this(&refs, &LocalInventoryRefs::packetReceived));
game .init(world, player, state); game .init(world, player, state);
refs .init(); refs .init();

View File

@ -9,23 +9,24 @@
#include "WorldInterpolationStream.h" #include "WorldInterpolationStream.h"
#include "../../../world/chunk/Chunk.h" #include "../../../world/chunk/Chunk.h"
#include "../../../def/item/BlockDef.h" #include "../../../def/item/BlockDef.h"
#include "../../../def/gen/LocalBiomeAtlas.h" #include "../../../lua/usertype/Target.h"
#include "../../../def/LocalDefinitionAtlas.h" #include "../../../lua/usertype/LuaItemStack.h"
#include "../../../lua/LocalLuaParser.h" #include "../../inventory/LocalInventoryList.h"
#include "../../entity/engine/ParticleEntity.h" #include "../../entity/engine/ParticleEntity.h"
#include "../../entity/engine/BlockCrackEntity.h" #include "../../entity/engine/BlockCrackEntity.h"
#include "../../../lua/usertype/LocalLuaPlayer.h" #include "../../../lua/usertype/LocalLuaPlayer.h"
#include "../../../net/client/ClientNetworkInterpreter.h" #include "../../../net/client/ClientNetworkInterpreter.h"
LocalWorld::LocalWorld(LocalSubgame& defs, ClientNetworkInterpreter* server) : LocalWorld::LocalWorld(LocalSubgame& defs, ClientNetworkInterpreter* server) :
defs(defs), World(defs),
net(server), game(defs),
dimension(defs) {} net(server),
dimension(defs) {}
void LocalWorld::init(Player* player) { void LocalWorld::init(Player* player) {
this->player = player; this->player = player;
delete worldGenStream; delete worldGenStream;
worldGenStream = new WorldInterpolationStream(55, defs); worldGenStream = new WorldInterpolationStream(55, game);
} }
void LocalWorld::update(double delta) { void LocalWorld::update(double delta) {
@ -61,61 +62,49 @@ void LocalWorld::setBlock(glm::ivec3 pos, unsigned int block) {
dimension.setBlock(pos, block); dimension.setBlock(pos, block);
} }
void LocalWorld::blockPlace(glm::vec3 pos, unsigned int block) { double LocalWorld::setBlockDamage(glm::ivec3 pos, double damage) {
if (block == LocalDefinitionAtlas::AIR) { double totalDamage = World::setBlockDamage(pos, damage);
auto& def = defs.defs->blockFromId(getBlock(pos));
if (def.callbacks.count(Callback::BREAK_CLIENT))
defs.lua->safe_function(def.callbacks[Callback::BREAK_CLIENT], pos);
}
else {
auto& def = defs.defs->blockFromId(block);
if (def.callbacks.count(Callback::PLACE_CLIENT))
defs.lua->safe_function(def.callbacks[Callback::PLACE_CLIENT], pos);
}
net->blockPlace(pos, block);
dimension.setBlock(pos, block);
}
void LocalWorld::blockBreak(glm::vec3 pos) {
blockPlace(pos, DefinitionAtlas::AIR);
}
void LocalWorld::blockInteract(PointedThing &thing) {
auto& def = defs.defs->blockFromId(getBlock(thing.target.block.pos));
if (def.callbacks.count(Callback::INTERACT_CLIENT))
defs.lua->safe_function(def.callbacks[Callback::INTERACT_CLIENT], thing.target.block.pos);
net->blockInteract(thing.target.block.pos);
}
double LocalWorld::blockHit(PointedThing& thing) {
glm::ivec3 pos = thing.target.block.pos;
auto& blockDef = defs.defs->blockFromId(getBlock(thing.target.block.pos));
double damage = 0, timeout = 0;
sol::tie(damage, timeout) = defs.lua->safe_function(defs.lua->core["get_hit_impact"],
defs.lua->core.get<LocalLuaPlayer>("player"), blockDef.identifier);
if (damage == 0) return timeout;
BlockCrackEntity* block = nullptr; BlockCrackEntity* block = nullptr;
for (auto test : crackedBlocks) if (glm::ivec3(test->getPos()) == pos) { block = test; break; } if (crackEntities.count(pos)) block = crackEntities[pos];
if (block == nullptr) { else block = new BlockCrackEntity(game.defs->blockFromId(getBlock(pos)), game.textures, pos);
block = new BlockCrackEntity(blockDef, defs.textures, pos); block->setDamage(damage);
crackedBlocks.push_back(block);
}
block->addDamage(damage);
block->time = 0; block->time = 0;
// auto def = defs.defs.blockFromId(getBlock(pos)); return totalDamage;
// for (int i = 0; i < 40 * damage; i++) { }
// auto p = new ParticleEntity(pos, def);
// particles.push_back(p); void LocalWorld::blockPlace(Target& target) {
// } std::tuple<sol::optional<LuaItemStack>, sol::optional<glm::vec3>> res = game.lua->safe_function(
game.lua->core["block_place"], LocalLuaPlayer(*player), Api::Usertype::Target(target));
auto stack = std::get<sol::optional<LuaItemStack>>(res);
if (stack) player->getWieldList()->setStack(player->getWieldIndex(), ItemStack(*stack, game.getDefs()));
net->blockPlace(target);
}
void LocalWorld::blockInteract(Target &target) {
game.lua->safe_function(game.lua->core["block_interact"],
LocalLuaPlayer(*player), Api::Usertype::Target(target));
net->blockInteract(target);
}
void LocalWorld::blockPlaceOrInteract(Target &target) {
std::tuple<sol::optional<LuaItemStack>, sol::optional<glm::vec3>> res = game.lua->safe_function(
game.lua->core["block_interact_or_place"], LocalLuaPlayer(*player), Api::Usertype::Target(target));
auto stack = std::get<sol::optional<LuaItemStack>>(res);
if (stack) player->getWieldList()->setStack(player->getWieldIndex(), ItemStack(*stack, game.getDefs()));
net->blockPlaceOrInteract(target);
}
double LocalWorld::blockHit(Target& target) {
double timeout = 0, damage = 0;
sol::tie(damage, timeout) = game.lua->safe_function(game.lua->core["block_hit"],
LocalLuaPlayer(*player), Api::Usertype::Target(target));
// net->blockHit(target);
return timeout; return timeout;
} }
@ -143,24 +132,26 @@ int LocalWorld::renderChunks(Renderer &renderer) {
} }
void LocalWorld::renderEntities(Renderer &renderer) { void LocalWorld::renderEntities(Renderer &renderer) {
for (auto block : crackedBlocks) block->draw(renderer); for (auto& block : crackEntities) block.second->draw(renderer);
for (auto &p : particles) p->draw(renderer); for (auto& particle : particles) particle->draw(renderer);
dimension.renderEntities(renderer); dimension.renderEntities(renderer);
} }
void LocalWorld::updateBlockDamages(double delta) { void LocalWorld::updateBlockDamages(double delta) {
auto it = crackedBlocks.cbegin(); auto it = crackEntities.cbegin();
while (it != crackedBlocks.cend()) { while (it != crackEntities.cend()) {
bool deleteMe = false; bool deleteMe = false;
auto curr = it++; auto curr = it++;
auto block = *curr; auto block = curr->second;
block->time += delta; block->time += delta;
if (block->damage >= block->maxHealth) { if (block->damage >= block->maxHealth) {
blockBreak(block->getPos()); //Todo: Lua callback~
setBlock(block->getPos(), DefinitionAtlas::AIR);
setBlockDamage(block->getPos(), 0);
deleteMe = true; deleteMe = true;
} }
@ -175,8 +166,8 @@ void LocalWorld::updateBlockDamages(double delta) {
} }
if (deleteMe) { if (deleteMe) {
delete *curr; delete block;
it = crackedBlocks.erase(curr); it = crackEntities.erase(curr);
} }
else block->update(); else block->update();
} }

View File

@ -8,14 +8,15 @@
#include "../../../world/LocalDimension.h" #include "../../../world/LocalDimension.h"
class Target;
class Player;
class Renderer;
class ItemStack;
class LocalSubgame;
class ParticleEntity;
class BlockCrackEntity;
class ClientNetworkInterpreter; class ClientNetworkInterpreter;
class WorldInterpolationStream; class WorldInterpolationStream;
class BlockCrackEntity;
class ParticleEntity;
class PointedThing;
class LocalSubgame;
class Renderer;
class Player;
class LocalWorld : public World { class LocalWorld : public World {
public: public:
@ -24,17 +25,20 @@ public:
void init(Player* player); void init(Player* player);
void update(double delta) override; void update(double delta) override;
void createDimension(std::string identifier);
void loadWorldPacket(std::unique_ptr<PacketView> p); void loadWorldPacket(std::unique_ptr<PacketView> p);
void commitChunk(std::shared_ptr<Chunk> chunk); void commitChunk(std::shared_ptr<Chunk> chunk);
unsigned int getBlock(glm::ivec3 pos) override; unsigned int getBlock(glm::ivec3 pos) override;
void setBlock(glm::ivec3 pos, unsigned int block) override; void setBlock(glm::ivec3 pos, unsigned int block) override;
void blockPlace(glm::vec3 pos, unsigned int block); double setBlockDamage(glm::ivec3 pos, double damage) override;
void blockBreak(glm::vec3 pos);
void blockInteract(PointedThing& thing); void blockPlace(Target& target);
double blockHit(PointedThing& thing); void blockPlaceOrInteract(Target& target);
void blockInteract(Target& target);
double blockHit(Target& target);
unsigned short getBiome(glm::vec3 pos); unsigned short getBiome(glm::vec3 pos);
std::shared_ptr<Chunk> getChunk(glm::ivec3 pos); std::shared_ptr<Chunk> getChunk(glm::ivec3 pos);
@ -43,7 +47,7 @@ public:
int renderChunks(Renderer &render); int renderChunks(Renderer &render);
void renderEntities(Renderer &renderer); void renderEntities(Renderer &renderer);
LocalSubgame& defs; LocalSubgame& game;
LocalDimension dimension; LocalDimension dimension;
int mapBlocksInterpolated = 0; int mapBlocksInterpolated = 0;
@ -52,7 +56,7 @@ private:
void finishChunks(); void finishChunks();
void updateBlockDamages(double delta); void updateBlockDamages(double delta);
std::vector<BlockCrackEntity*> crackedBlocks; std::unordered_map<glm::ivec3, BlockCrackEntity*, Vec::ivec3> crackEntities;
std::vector<ParticleEntity*> particles; std::vector<ParticleEntity*> particles;
Player* player = nullptr; Player* player = nullptr;

View File

@ -8,23 +8,23 @@
#include "../../../util/Ray.h" #include "../../../util/Ray.h"
#include "../../graph/Renderer.h" #include "../../graph/Renderer.h"
#include "../../../def/ItemDef.h" #include "../../../def/ItemDef.h"
#include "../../../net/Serializer.h"
#include "../../../net/Deserializer.h" #include "../../../net/Deserializer.h"
#include "../../../def/item/BlockDef.h" #include "../../../def/item/BlockDef.h"
#include "../../../world/chunk/Chunk.h" #include "../../../world/chunk/Chunk.h"
#include "../../inventory/LocalInventory.h" #include "../../inventory/LocalInventory.h"
#include "../../../def/LocalDefinitionAtlas.h"
#include "../../inventory/LocalInventoryList.h" #include "../../inventory/LocalInventoryList.h"
#include "../../../net/client/NetPlayerField.h" #include "../../../net/client/NetPlayerField.h"
#include "../../../net/client/ClientNetworkInterpreter.h"
Player::Player(LocalWorld& world, LocalSubgame& defs, Renderer& renderer, LocalInventoryRefs& refs) : Player::Player(LocalSubgame &game, LocalWorld &world, Renderer &renderer, LocalInventoryRefs &refs, ClientNetworkInterpreter& net) :
Collidable(world, defs, {{-0.3, 0, -0.3}, {0.3, 1.8, 0.3}}), Collidable(world, game, {{-0.3, 0, -0.3}, {0.3, 1.8, 0.3}}),
net(net),
refs(refs), refs(refs),
game(defs), game(game),
renderer(renderer), renderer(renderer),
wireframe({}, 0.01, {1, 1, 1}), wireframe({}, 0.01, {1, 1, 1}),
gameGui(refs, renderer.window.getSize(), defs, renderer) { gameGui(refs, renderer.window.getSize(), game, renderer) {
handItemModel.parent = &handModel; handItemModel.parent = &handModel;
renderer.window.addResizeCallback("player", [&](glm::ivec2 win) { renderer.window.addResizeCallback("player", [&](glm::ivec2 win) {
@ -186,27 +186,25 @@ void Player::findPointedThing(Input &input) {
auto face = sBox.intersects(rayEnd, roundedPos); auto face = sBox.intersects(rayEnd, roundedPos);
if (face != EVec::NONE) { if (face != EVec::NONE) {
pointedThing.thing = PointedThing::Thing::BLOCK; target = Target(roundedPos, face);
pointedThing.target.block = { blockID, roundedPos, face };
return; return;
} }
} }
} }
pointedThing.thing = PointedThing::Thing::NOTHING; target = Target {};
pointedThing.target.nothing = 0;
} }
void Player::updateWireframe() { void Player::updateWireframe() {
if (!gameGui.isVisible()) { if (!gameGui.isVisible()) {
wireframe.setVisible(false); wireframe.setVisible(false);
} }
else if (pointedThing.thing == PointedThing::Thing::BLOCK) { else if (target.type == Target::Type::BLOCK) {
auto& boxes = game.defs->blockFromId(pointedThing.target.block.blockId).sBoxes; auto& boxes = game.defs->blockFromId(world.getBlock(target.pos)).sBoxes;
float distance = glm::distance(pos, glm::vec3(pointedThing.target.block.pos) + glm::vec3(0.5)); float distance = glm::distance(pos, target.pos + glm::vec3(0.5));
wireframe.updateMesh(boxes, 0.002f + distance * 0.0014f); wireframe.updateMesh(boxes, 0.002f + distance * 0.0014f);
wireframe.setPos(pointedThing.target.block.pos); wireframe.setPos(target.pos);
wireframe.setVisible(true); wireframe.setVisible(true);
} }
else { else {
@ -215,23 +213,12 @@ void Player::updateWireframe() {
} }
void Player::interact(Input& input, double delta) { void Player::interact(Input& input, double delta) {
if (pointedThing.thing == PointedThing::Thing::BLOCK) { if (target.type == Target::Type::BLOCK) {
if (input.mouseDown(GLFW_MOUSE_BUTTON_LEFT) && breakTime == 0) { if (input.mouseDown(GLFW_MOUSE_BUTTON_LEFT) && breakTime == 0) {
breakInterval = world.blockHit(pointedThing); breakInterval = world.blockHit(target);
breakTime += delta; breakTime += delta;
} }
else if (input.mousePressed(GLFW_MOUSE_BUTTON_RIGHT)) { else if (input.mousePressed(GLFW_MOUSE_BUTTON_RIGHT)) world.blockPlaceOrInteract(target);
auto& target = game.defs->blockFromId(world.getBlock(pointedThing.target.block.pos));
if (target.hasInteraction()) world.blockInteract(pointedThing);
else if (wieldItem > DefinitionAtlas::AIR && game.defs->fromId(wieldItem).type == ItemDef::Type::BLOCK) {
world.blockPlace(pointedThing.target.block.pos + SelectionBox::faceToOffset(pointedThing.target.block.face), wieldItem);
}
else {
//TODO: Item interactions.
// world.itemUse(pointedThing, activeItem);
}
}
} }
if (breakTime > 0) breakTime += delta; if (breakTime > 0) breakTime += delta;
@ -249,7 +236,7 @@ glm::vec3 Player::getPos() {
void Player::setPos(glm::vec3 pos, bool assert) { void Player::setPos(glm::vec3 pos, bool assert) {
this->pos = pos; this->pos = pos;
this->renderer.camera.setPos({pos.x, pos.y + EYE_HEIGHT, pos.z}); this->renderer.camera.setPos({pos.x, pos.y + EYE_HEIGHT, pos.z});
if (assert) assertField(NetPlayerField::POSITION, pos); if (assert) net.assertPlayerField(NetPlayerField::POSITION, pos);
} }
glm::vec3 Player::getVel() { glm::vec3 Player::getVel() {
@ -258,7 +245,7 @@ glm::vec3 Player::getVel() {
void Player::setVel(glm::vec3 vel, bool assert) { void Player::setVel(glm::vec3 vel, bool assert) {
this->vel = vel; this->vel = vel;
if (assert) assertField(NetPlayerField::VELOCITY, vel); if (assert) net.assertPlayerField(NetPlayerField::VELOCITY, vel);
} }
float Player::getYaw() { float Player::getYaw() {
@ -267,7 +254,7 @@ float Player::getYaw() {
void Player::setYaw(float yaw, bool assert) { void Player::setYaw(float yaw, bool assert) {
this->yaw = yaw; this->yaw = yaw;
if (assert) assertField(NetPlayerField::YAW, yaw); if (assert) net.assertPlayerField(NetPlayerField::YAW, yaw);
} }
float Player::getPitch() { float Player::getPitch() {
@ -276,7 +263,7 @@ float Player::getPitch() {
void Player::setPitch(float pitch, bool assert) { void Player::setPitch(float pitch, bool assert) {
this->pitch = pitch; this->pitch = pitch;
if (assert) assertField(NetPlayerField::PITCH, pitch); if (assert) net.assertPlayerField(NetPlayerField::PITCH, pitch);
} }
bool Player::isFlying() { bool Player::isFlying() {
@ -285,11 +272,11 @@ bool Player::isFlying() {
void Player::setFlying(bool flying, bool assert) { void Player::setFlying(bool flying, bool assert) {
this->flying = flying; this->flying = flying;
if (assert) assertField(NetPlayerField::FLYING, flying); if (assert) net.assertPlayerField(NetPlayerField::FLYING, flying);
} }
PointedThing& Player::getPointedThing() { Target& Player::getPointedThing() {
return pointedThing; return target;
} }
LocalInventory& Player::getInventory() { LocalInventory& Player::getInventory() {
@ -313,7 +300,7 @@ void Player::setWieldList(const std::string& list, bool assert) {
refs.setWieldList(list); refs.setWieldList(list);
setWieldIndex(wieldIndex); setWieldIndex(wieldIndex);
updateWieldAndHandItems(); updateWieldAndHandItems();
if (assert) assertField(NetPlayerField::WIELD_INV, list); if (assert) net.assertPlayerField(NetPlayerField::WIELD_INV, list);
} }
unsigned short Player::getWieldIndex() { unsigned short Player::getWieldIndex() {
@ -324,7 +311,7 @@ void Player::setWieldIndex(unsigned short index, bool assert) {
auto wieldList = refs.getWieldList(); auto wieldList = refs.getWieldList();
wieldIndex = index % std::max((wieldList ? wieldList->getLength() : 1), 1); wieldIndex = index % std::max((wieldList ? wieldList->getLength() : 1), 1);
updateWieldAndHandItems(); updateWieldAndHandItems();
if (assert) assertField(NetPlayerField::WIELD_INV, static_cast<unsigned short>(index)); if (assert) net.assertPlayerField(NetPlayerField::WIELD_INDEX, static_cast<unsigned short>(index));
} }
/* /*
@ -386,13 +373,6 @@ void Player::updateWieldAndHandItems() {
handItemModel.setModel(model); handItemModel.setModel(model);
} }
template <typename T>
void Player::assertField(NetPlayerField field, T data) {
std::cout << "attempt to assert field" << std::endl;
// Serializer().append(static_cast<unsigned int>(field)).append<T>(data)
// .packet(PacketType::THIS_PLAYER_INFO).sendTo(peer, PacketChannel::PLAYER);
}
void Player::handleAssertion(Deserializer &d) { void Player::handleAssertion(Deserializer &d) {
while (!d.atEnd()) { while (!d.atEnd()) {
switch (static_cast<NetPlayerField>(d.read<unsigned int>())) { switch (static_cast<NetPlayerField>(d.read<unsigned int>())) {

View File

@ -8,7 +8,7 @@
#include "../../graph/drawable/Drawable.h" #include "../../graph/drawable/Drawable.h"
#include "../../hud/GameGui.h" #include "../../hud/GameGui.h"
#include "../../../world/PointedThing.h" #include "../../../world/Target.h"
#include "../../entity/engine/WireframeEntity.h" #include "../../entity/engine/WireframeEntity.h"
class Input; class Input;
@ -22,8 +22,8 @@ class Player : Collidable, public Drawable {
public: public:
enum class PlayerControl { enum class PlayerControl {
FORWARD, LEFT, BACKWARD, RIGHT, FORWARD, LEFT, BACKWARD, RIGHT,
JUMP, MOD1, MOD2 JUMP, MOD1, MOD2 };
};
static constexpr float MOUSE_SENSITIVITY = 0.1f; static constexpr float MOUSE_SENSITIVITY = 0.1f;
static constexpr float LOOK_DISTANCE = 6.5f; static constexpr float LOOK_DISTANCE = 6.5f;
static constexpr float LOOK_PRECISION = 0.01f; static constexpr float LOOK_PRECISION = 0.01f;
@ -31,7 +31,7 @@ public:
static constexpr float BASE_MOVE_SPEED = 4.3f; static constexpr float BASE_MOVE_SPEED = 4.3f;
static constexpr float JUMP_VEL = 0.14f; static constexpr float JUMP_VEL = 0.14f;
Player(LocalWorld& world, LocalSubgame& defs, Renderer& renderer, LocalInventoryRefs& refs); Player(LocalSubgame &game, LocalWorld &world, Renderer &renderer, LocalInventoryRefs &refs, ClientNetworkInterpreter& net);
void update(Input &input, double delta, glm::vec2 mouseDelta); void update(Input &input, double delta, glm::vec2 mouseDelta);
~Player(); ~Player();
@ -68,7 +68,7 @@ public:
void setHud(std::shared_ptr<LuaGuiElement> hud); void setHud(std::shared_ptr<LuaGuiElement> hud);
std::shared_ptr<LuaGuiElement> getHud(); std::shared_ptr<LuaGuiElement> getHud();
PointedThing& getPointedThing(); Target& getPointedThing();
void setHudVisible(bool hudVisible); void setHudVisible(bool hudVisible);
void draw(Renderer& renderer) override; void draw(Renderer& renderer) override;
@ -90,9 +90,9 @@ private:
void interact(Input& input, double delta); void interact(Input& input, double delta);
void updateWieldAndHandItems(); void updateWieldAndHandItems();
template <typename T> void assertField(NetPlayerField field, T data);
LocalSubgame& game; LocalSubgame& game;
ClientNetworkInterpreter& net;
Renderer& renderer; Renderer& renderer;
GameGui gameGui; GameGui gameGui;
@ -112,6 +112,6 @@ private:
double breakTime = 0; double breakTime = 0;
double breakInterval = 0; double breakInterval = 0;
PointedThing pointedThing; Target target;
}; };

View File

@ -2,4 +2,30 @@
// Created by aurailus on 2020-01-09. // Created by aurailus on 2020-01-09.
// //
#include "World.h" #include "World.h"
#include "../../../def/Subgame.h"
#include "../../../def/item/BlockDef.h"
#include "../../../def/DefinitionAtlas.h"
World::World(Subgame &game) : game(game) {}
double World::getBlockDamage(glm::ivec3 pos) const {
return blockDamages.count(pos) ? blockDamages.at(pos).curr : 0;
}
double World::setBlockDamage(glm::ivec3 pos, double damage) {
if (blockDamages.count(pos)) blockDamages[pos].curr = damage;
else blockDamages.insert({pos, Damage { damage, static_cast<double>(game.getDefs().blockFromId(getBlock(pos)).health)}});
return getBlockDamage(pos);
}
void World::updateBlockDamages() {
for (auto it = blockDamages.begin(); it != blockDamages.end(); ) {
if (it->second.curr > it->second.max) {
setBlock(it->first, DefinitionAtlas::AIR);
it = blockDamages.erase(it);
}
else it++;
}
}

View File

@ -4,14 +4,37 @@
#pragma once #pragma once
#include <map>
#include <memory>
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include <unordered_map>
#include "../../../util/Vec.h"
class Subgame;
class Dimension;
class World { class World {
public: public:
explicit World() = default; explicit World(Subgame& game);
virtual void update(double delta) = 0; virtual void update(double delta) = 0;
// virtual Dimension& getDimension() = 0;
virtual unsigned int getBlock(glm::ivec3 pos) = 0; virtual unsigned int getBlock(glm::ivec3 pos) = 0;
virtual void setBlock(glm::ivec3 pos, unsigned int block) = 0; virtual void setBlock(glm::ivec3 pos, unsigned int block) = 0;
virtual double getBlockDamage(glm::ivec3 pos) const;
virtual double setBlockDamage(glm::ivec3 pos, double damage);
protected:
void updateBlockDamages();
std::map<std::string, std::shared_ptr<Dimension>> dimensions;
struct Damage { double curr, max; };
std::unordered_map<glm::ivec3, Damage, Vec::ivec3> blockDamages;
Subgame& game;
}; };

View File

@ -19,15 +19,14 @@
#include "usertype/cLuaEntity.h" #include "usertype/cLuaEntity.h"
#include "usertype/cInventoryRef.h" #include "usertype/cInventoryRef.h"
#include "usertype/cAnimationManager.h" #include "usertype/cAnimationManager.h"
#include "usertype/Target.h"
// Modules // Modules
#include "modules/Time.h" #include "modules/Time.h"
#include "modules/Block.h" #include "modules/Block.h"
#include "modules/Entity.h" #include "modules/Entity.h"
#include "modules/Register.h" #include "modules/Register.h"
#include "modules/create_structure.h" #include "modules/create_structure.h"
#include "LuaMod.h"
LocalLuaParser::LocalLuaParser(LocalSubgame& game): LuaParser(game), game(game), keybinds(this) {} LocalLuaParser::LocalLuaParser(LocalSubgame& game): LuaParser(game), game(game), keybinds(this) {}
@ -68,6 +67,8 @@ void LocalLuaParser::loadApi(LocalSubgame &defs, LocalWorld &world, Player& play
ClientApi::item_stack (lua); ClientApi::item_stack (lua);
ClientApi::gui_element (lua); ClientApi::gui_element (lua);
Api::Usertype::Target::bind(Api::State::CLIENT, lua, core);
core["client"] = true; core["client"] = true;
core["player"] = LocalLuaPlayer(player); core["player"] = LocalLuaPlayer(player);

View File

@ -19,6 +19,7 @@
#include "usertype/sLuaEntity.h" #include "usertype/sLuaEntity.h"
#include "usertype/sInventoryRef.h" #include "usertype/sInventoryRef.h"
#include "usertype/cItemStack.h" #include "usertype/cItemStack.h"
#include "usertype/Target.h"
// Modules // Modules
#include "modules/Time.h" #include "modules/Time.h"
@ -98,11 +99,13 @@ void ServerLuaParser::loadApi(ServerSubgame &defs, ServerWorld &world) {
ServerApi::inventory (lua); ServerApi::inventory (lua);
ClientApi::item_stack (lua); ClientApi::item_stack (lua);
Api::Usertype::Target::bind(Api::State::SERVER, lua, core);
core["server"] = true; core["server"] = true;
core["players"] = lua.create_table(); core["players"] = lua.create_table();
// Modules // Modules
modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::CLIENT, lua, core)); modules.emplace_back(std::make_unique<Api::Module::Time>(Api::State::SERVER, lua, core));
modules.emplace_back(std::make_unique<Api::Module::Block>(Api::State::SERVER, core, game, world)); modules.emplace_back(std::make_unique<Api::Module::Block>(Api::State::SERVER, core, game, world));
modules.emplace_back(std::make_unique<Api::Module::Entity>(Api::State::SERVER, core, game, world)); modules.emplace_back(std::make_unique<Api::Module::Entity>(Api::State::SERVER, core, game, world));
modules.emplace_back(std::make_unique<Api::Module::Register>(Api::State::SERVER, core, game, world)); modules.emplace_back(std::make_unique<Api::Module::Register>(Api::State::SERVER, core, game, world));
@ -122,7 +125,7 @@ void ServerLuaParser::registerDefs(ServerSubgame &defs) {
RegisterBiomes::server(core, defs); RegisterBiomes::server(core, defs);
} }
sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result errPfr) { sol::protected_function_result ServerLuaParser::errorCallback(sol::protected_function_result errPfr) const {
sol::error err = errPfr; sol::error err = errPfr;
std::string errString = err.what(); std::string errString = err.what();

View File

@ -26,15 +26,16 @@ public:
void playerConnected(std::shared_ptr<ServerClient> client); void playerConnected(std::shared_ptr<ServerClient> client);
void playerDisconnected(std::shared_ptr<ServerClient> client); void playerDisconnected(std::shared_ptr<ServerClient> client);
template<typename... Args> void safe_function(sol::protected_function f, Args... args) { template<typename... Args> sol::safe_function_result safe_function(sol::protected_function f, Args... args) const {
auto res = f(args...); auto res = f(args...);
if (!res.valid()) errorCallback(res); if (!res.valid()) errorCallback(res);
return res;
} }
private: private:
void loadApi(ServerSubgame& defs, ServerWorld& world); void loadApi(ServerSubgame& defs, ServerWorld& world);
void registerDefs(ServerSubgame &defs); void registerDefs(ServerSubgame &defs);
sol::protected_function_result errorCallback(sol::protected_function_result errPfr); sol::protected_function_result errorCallback(sol::protected_function_result errPfr) const;
sol::protected_function_result runFileSandboxed(const std::string& file); sol::protected_function_result runFileSandboxed(const std::string& file);
ServerSubgame& game; ServerSubgame& game;

View File

@ -1,8 +0,0 @@
//
// Created by aurailus on 2020-07-26.
//
#include "BaseModule.h"
Api::Module::BaseModule::BaseModule(Api::State state, sol::state& lua, sol::table& core) :
state(state), lua(lua), core(core) {}

View File

@ -12,7 +12,9 @@ namespace Api {
namespace Module { namespace Module {
class BaseModule { class BaseModule {
public: public:
BaseModule(State state, sol::state& lua, sol::table& core); BaseModule(State state, sol::state& lua, sol::table& core) :
state(state), lua(lua), core(core) {}
virtual void bind() = 0; virtual void bind() = 0;
protected: protected:

View File

@ -14,6 +14,10 @@ void Api::Module::Block::bind() {
core.set_function("get_block", Util::bind_this(this, &Block::getBlock)); core.set_function("get_block", Util::bind_this(this, &Block::getBlock));
core.set_function("set_block", Util::bind_this(this, &Block::setBlock)); core.set_function("set_block", Util::bind_this(this, &Block::setBlock));
core.set_function("remove_block", [&](glm::ivec3 pos) { setBlock(pos, "air"); }); core.set_function("remove_block", [&](glm::ivec3 pos) { setBlock(pos, "air"); });
core.set_function("block_damage_get", Util::bind_this(this, &Block::damageGet));
core.set_function("block_damage_set", Util::bind_this(this, &Block::damageSet));
core.set_function("block_damage_add", Util::bind_this(this, &Block::damageAdd));
} }
std::string Api::Module::Block::getBlock(glm::ivec3 pos) { std::string Api::Module::Block::getBlock(glm::ivec3 pos) {
@ -23,3 +27,15 @@ std::string Api::Module::Block::getBlock(glm::ivec3 pos) {
void Api::Module::Block::setBlock(glm::ivec3 pos, const std::string &identifier) { void Api::Module::Block::setBlock(glm::ivec3 pos, const std::string &identifier) {
world.setBlock(pos, game.getDefs().fromStr(identifier).index); world.setBlock(pos, game.getDefs().fromStr(identifier).index);
} }
double Api::Module::Block::damageGet(glm::ivec3 pos) {
return world.getBlockDamage(pos);
}
double Api::Module::Block::damageSet(glm::ivec3 pos, double damage) {
return world.setBlockDamage(pos, damage);
}
double Api::Module::Block::damageAdd(glm::ivec3 pos, double damage) {
return world.setBlockDamage(pos, world.getBlockDamage(pos) + damage);
}

View File

@ -17,5 +17,9 @@ namespace Api::Module {
protected: protected:
std::string getBlock(glm::ivec3 pos); std::string getBlock(glm::ivec3 pos);
void setBlock(glm::ivec3 pos, const std::string& identifier); void setBlock(glm::ivec3 pos, const std::string& identifier);
double damageGet(glm::ivec3 pos);
double damageSet(glm::ivec3 pos, double damage);
double damageAdd(glm::ivec3 pos, double damage);
}; };
} }

View File

@ -0,0 +1,19 @@
//
// Created by aurailus on 2020-07-27.
//
#pragma once
#include <sol/forward.hpp>
#include "../modules/BaseModule.h"
namespace Api {
namespace Usertype {
class BaseUsertype {
public:
BaseUsertype() = default;
static void bind(State state, sol::state& lua, sol::table& core) {};
};
}
}

View File

@ -89,9 +89,9 @@ sol::object LocalLuaPlayer::get_wield_list(sol::this_state s) {
} }
void LocalLuaPlayer::set_wield_list(sol::optional<sol::object> list) { void LocalLuaPlayer::set_wield_list(sol::optional<sol::object> list) {
if (!list) player.setWieldList(""); if (!list) player.setWieldList("", true);
else if (list->is<std::string>()) player.setWieldList(list->as<std::string>()); else if (list->is<std::string>()) player.setWieldList(list->as<std::string>(), true);
else if (list->is<LocalLuaInventoryList>()) player.setWieldList(list->as<LocalLuaInventoryList>().get_name()); else if (list->is<LocalLuaInventoryList>()) player.setWieldList(list->as<LocalLuaInventoryList>().get_name(), true);
else throw "Attempted to set wield list to nil."; else throw "Attempted to set wield list to nil.";
} }
@ -100,7 +100,7 @@ unsigned int LocalLuaPlayer::get_wield_index() {
} }
void LocalLuaPlayer::set_wield_index(unsigned int index) { void LocalLuaPlayer::set_wield_index(unsigned int index) {
player.setWieldIndex(index - 1); player.setWieldIndex(index - 1, true);
} }
sol::object LocalLuaPlayer::get_wield_stack(sol::this_state s) { sol::object LocalLuaPlayer::get_wield_stack(sol::this_state s) {
@ -110,7 +110,7 @@ sol::object LocalLuaPlayer::get_wield_stack(sol::this_state s) {
} }
void LocalLuaPlayer::set_flying(bool shouldFly) { void LocalLuaPlayer::set_flying(bool shouldFly) {
player.setFlying(shouldFly); player.setFlying(shouldFly, true);
} }
bool LocalLuaPlayer::get_flying() { bool LocalLuaPlayer::get_flying() {

View File

@ -74,8 +74,8 @@ sol::object ServerLuaPlayer::get_hand_list(sol::this_state s) {
void ServerLuaPlayer::set_hand_list(sol::object list) { void ServerLuaPlayer::set_hand_list(sol::object list) {
if (!list) player.setHandList(nullptr); if (!list) player.setHandList(nullptr);
else if (list.is<std::string>()) player.setHandList((*player.getInventory())[list.as<std::string>()], true); else if (list.is<std::string>()) player.setHandList(list.as<std::string>(), true);
else if (list.is<ServerLuaInventoryList>()) player.setHandList((*player.getInventory())[list.as<ServerLuaInventoryList>().get_name()], true); else if (list.is<ServerLuaInventoryList>()) player.setHandList(list.as<ServerLuaInventoryList>().get_name(), true);
else throw "Attempted to set hand list to nil."; else throw "Attempted to set hand list to nil.";
} }
@ -92,9 +92,9 @@ sol::object ServerLuaPlayer::get_wield_list(sol::this_state s) {
} }
void ServerLuaPlayer::set_wield_list(sol::object list) { void ServerLuaPlayer::set_wield_list(sol::object list) {
if (!list) player.setWieldList(nullptr); if (!list) player.setWieldList(nullptr, true);
else if (list.is<std::string>()) player.setWieldList((*player.getInventory())[list.as<std::string>()], true); else if (list.is<std::string>()) player.setWieldList(list.as<std::string>(), true);
else if (list.is<ServerLuaInventoryList>()) player.setWieldList((*player.getInventory())[list.as<ServerLuaInventoryList>().get_name()], true); else if (list.is<ServerLuaInventoryList>()) player.setWieldList(list.as<ServerLuaInventoryList>().get_name(), true);
else throw "Attempted to set wield list to nil."; else throw "Attempted to set wield list to nil.";
} }

View File

@ -0,0 +1,19 @@
//
// Created by aurailus on 2020-07-27.
//
#pragma once
#include "BaseUsertype.h"
class State;
namespace Api {
namespace Usertype {
class SubgameUsertype : public BaseUsertype {
public:
SubgameUsertype() = default;
static void bind(State state, sol::state& lua, sol::table& core) {};
};
}
}

View File

@ -0,0 +1,27 @@
//
// Created by aurailus on 2020-07-27.
//
#include "Target.h"
#include "../Lua.h"
Api::Usertype::Target::Target(const ::Target &target) :
pos(target.pos),
type(target.type),
pos_above(target.getAbovePos()) {}
std::string Api::Usertype::Target::getType() {
return type == ::Target::Type::BLOCK ? "block" :
type == ::Target::Type::ENTITY ? "entity" :
"nothing";
}
void Api::Usertype::Target::bind(State, sol::state &lua, sol::table &core) {
lua.new_usertype<Target>("Target",
"type", sol::property(&Target::getType),
"pos", sol::readonly(&Target::pos),
"pos_above", sol::readonly(&Target::pos_above)
);
}

26
src/lua/usertype/Target.h Normal file
View File

@ -0,0 +1,26 @@
//
// Created by aurailus on 2020-07-27.
//
#pragma once
#include <glm/vec3.hpp>
#include "SubgameUsertype.h"
#include "../../world/Target.h"
namespace Api::Usertype {
class Target : public SubgameUsertype {
public:
Target(const ::Target& target);
std::string getType();
::Target::Type type;
glm::ivec3 pos;
glm::ivec3 pos_above;
static void bind(State state, sol::state& lua, sol::table& core);
};
}

View File

@ -28,8 +28,11 @@ enum class PacketType {
MAPBLOCK, MAPBLOCK,
// Block // Block
BLOCK_SET, BLOCK_PLACE,
BLOCK_INTERACT, BLOCK_INTERACT,
BLOCK_PLACE_OR_INTERACT,
BLOCK_SET,
// Entity // Entity
ENTITY_INFO, ENTITY_INFO,

View File

@ -11,7 +11,6 @@
#include "../NetHandler.h" #include "../NetHandler.h"
#include "../../util/Log.h" #include "../../util/Log.h"
#include "NetPlayerField.h" #include "NetPlayerField.h"
#include "ServerConnection.h"
#include "../../game/entity/Model.h" #include "../../game/entity/Model.h"
#include "../../game/scene/world/Player.h" #include "../../game/scene/world/Player.h"
#include "../../game/scene/world/LocalWorld.h" #include "../../game/scene/world/LocalWorld.h"
@ -128,14 +127,19 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<PacketView> p) {
} }
} }
void ClientNetworkInterpreter::blockPlace(glm::ivec3 pos, unsigned int block) { void ClientNetworkInterpreter::blockPlace(Target &target) {
Serializer().append(pos).append(block).packet(PacketType::BLOCK_SET) Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.sendTo(connection.getPeer(), PacketChannel::INTERACT); .packet(PacketType::BLOCK_PLACE).sendTo(connection.getPeer(), PacketChannel::INTERACT);
} }
void ClientNetworkInterpreter::blockInteract(glm::ivec3 pos) { void ClientNetworkInterpreter::blockInteract(Target &target) {
Serializer().append(pos).packet(PacketType::BLOCK_INTERACT) Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.sendTo(connection.getPeer(), PacketChannel::INTERACT); .packet(PacketType::BLOCK_INTERACT).sendTo(connection.getPeer(), PacketChannel::INTERACT);
}
void ClientNetworkInterpreter::blockPlaceOrInteract(Target &target) {
Serializer().append<glm::ivec3>(target.pos).append(static_cast<unsigned short>(target.face))
.packet(PacketType::BLOCK_PLACE_OR_INTERACT).sendTo(connection.getPeer(), PacketChannel::INTERACT);
} }
void ClientNetworkInterpreter::invWatch(const std::string& inv, const std::string& list) { void ClientNetworkInterpreter::invWatch(const std::string& inv, const std::string& list) {

View File

@ -8,12 +8,16 @@
#include <functional> #include <functional>
#include <glm/vec3.hpp> #include <glm/vec3.hpp>
#include "../Serializer.h"
#include "ServerConnection.h"
class Model; class Model;
class Player; class Player;
class Target;
class LocalWorld; class LocalWorld;
class LocalSubgame;
class PacketView; class PacketView;
class ServerConnection; class LocalSubgame;
enum class NetPlayerField;
class ClientNetworkInterpreter { class ClientNetworkInterpreter {
public: public:
@ -23,14 +27,20 @@ public:
void init(LocalWorld* world, std::function<void(std::unique_ptr<PacketView>)> invCallback); void init(LocalWorld* world, std::function<void(std::unique_ptr<PacketView>)> invCallback);
void update(); void update();
void blockPlace(glm::ivec3 pos, unsigned int block); void blockPlace(Target& target);
void blockInteract(glm::ivec3 pos); void blockInteract(Target& target);
void blockPlaceOrInteract(Target& target);
void invWatch(const std::string& inv, const std::string& list); void invWatch(const std::string& inv, const std::string& list);
void invUnwatch(const std::string& inv, const std::string& list); void invUnwatch(const std::string& inv, const std::string& list);
void invInteractPrimary(const std::string& inv, const std::string& list, unsigned short ind); void invInteractPrimary(const std::string& inv, const std::string& list, unsigned short ind);
void invInteractSecondary(const std::string& inv, const std::string& list, unsigned short ind); void invInteractSecondary(const std::string& inv, const std::string& list, unsigned short ind);
template <typename T> void assertPlayerField(NetPlayerField field, T data) {
Serializer().append(static_cast<unsigned int>(field)).append<T>(data)
.packet(PacketType::THIS_PLAYER_INFO).sendTo(connection.getPeer(), PacketChannel::INTERACT);
}
int recvPackets = 0; int recvPackets = 0;
int serverSideChunkGens = 0; int serverSideChunkGens = 0;
private: private:

View File

@ -8,13 +8,10 @@
#include "Server.h" #include "Server.h"
#include "../Serializer.h" #include "../Serializer.h"
#include "../PacketView.h"
#include "../../util/Log.h"
#include "../../util/Timer.h" #include "../../util/Timer.h"
#include "../PacketChannel.h" #include "../PacketChannel.h"
#include "../../world/Target.h"
#include "../../def/item/BlockDef.h" #include "../../def/item/BlockDef.h"
#include "../../def/ServerDefinitionAtlas.h"
#include "../../lua/ServerLuaParser.h"
#include "../../lua/usertype/ServerLuaPlayer.h" #include "../../lua/usertype/ServerLuaPlayer.h"
Server::Server(unsigned short port, const std::string& subgame) : Server::Server(unsigned short port, const std::string& subgame) :
@ -114,16 +111,20 @@ void Server::handlePlayerPacket(ServerClient& client, PacketView& p) {
switch (p.type) { switch (p.type) {
default: { default: {
std::cout << Log::err << "Invalid packet type (" << static_cast<int>(p.type) << ") recieved." << Log::endl; std::cout << Log::err << "Invalid packet type (" << static_cast<int>(p.type) << ") recieved." << Log::endl;
break; break; }
}
case PacketType::PLAYER_INFO: { case PacketType::PLAYER_INFO: {
client.setPos(p.d.read<glm::vec3>()); client.setPos(p.d.read<glm::vec3>());
client.setPitch(p.d.read<float>()); client.setPitch(p.d.read<float>());
client.setYaw(p.d.read<float>()); client.setYaw(p.d.read<float>());
playersUpdated.emplace(client.cid); playersUpdated.emplace(client.cid);
break; break; }
}
case PacketType::THIS_PLAYER_INFO: {
client.handleAssertion(p.d);
break; }
case PacketType::BLOCK_SET: { case PacketType::BLOCK_SET: {
glm::ivec3 pos = p.d.read<glm::ivec3>(); glm::ivec3 pos = p.d.read<glm::ivec3>();
unsigned int block = p.d.read<unsigned int>(); unsigned int block = p.d.read<unsigned int>();
@ -155,14 +156,26 @@ void Server::handlePlayerPacket(ServerClient& client, PacketView& p) {
defs.lua->safe_function(def.callbacks[Callback::AFTER_PLACE], pos, ServerLuaPlayer(client)); defs.lua->safe_function(def.callbacks[Callback::AFTER_PLACE], pos, ServerLuaPlayer(client));
defs.lua->safe_function(defs.lua->core["trigger"], "after_place", pos, ServerLuaPlayer(client)); defs.lua->safe_function(defs.lua->core["trigger"], "after_place", pos, ServerLuaPlayer(client));
} }
break; break; }
}
case PacketType::BLOCK_PLACE: {
glm::ivec3 pos = p.d.read<glm::ivec3>();
auto face = static_cast<EVec>(p.d.read<unsigned short>());
world.blockPlace(Target(pos, face), client);
break; }
case PacketType::BLOCK_INTERACT: { case PacketType::BLOCK_INTERACT: {
glm::ivec3 pos = p.d.read<glm::ivec3>(); glm::ivec3 pos = p.d.read<glm::ivec3>();
auto& def = defs.defs->blockFromId(world.getBlock(pos)); auto face = static_cast<EVec>(p.d.read<unsigned short>());
if (def.callbacks.count(Callback::INTERACT)) defs.lua->safe_function(def.callbacks[Callback::INTERACT], pos, ServerLuaPlayer(client)); world.blockInteract(Target(pos, face), client);
break; break; }
}
case PacketType::BLOCK_PLACE_OR_INTERACT: {
glm::ivec3 pos = p.d.read<glm::ivec3>();
auto face = static_cast<EVec>(p.d.read<unsigned short>());
world.blockPlaceOrInteract(Target(pos, face), client);
break; }
case PacketType::INV_WATCH: { case PacketType::INV_WATCH: {
std::string source = p.d.read<std::string>(); std::string source = p.d.read<std::string>();
std::string list = p.d.read<std::string>(); std::string list = p.d.read<std::string>();
@ -173,8 +186,8 @@ void Server::handlePlayerPacket(ServerClient& client, PacketView& p) {
bool exists = refs.addWatcher(source, list, client.cid); bool exists = refs.addWatcher(source, list, client.cid);
if (!exists) Serializer().append(source).append(list) if (!exists) Serializer().append(source).append(list)
.packet(PacketType::INV_INVALID).sendTo(client.peer, PacketChannel::INVENTORY); .packet(PacketType::INV_INVALID).sendTo(client.peer, PacketChannel::INVENTORY);
break; break; }
}
case PacketType::INV_UNWATCH: { case PacketType::INV_UNWATCH: {
std::string source = p.d.read<std::string>(); std::string source = p.d.read<std::string>();
std::string list = p.d.read<std::string>(); std::string list = p.d.read<std::string>();
@ -189,10 +202,9 @@ void Server::handlePlayerPacket(ServerClient& client, PacketView& p) {
break; break;
} }
break; break; }
}
case PacketType::INV_INTERACT: {
case PacketType::INV_INTERACT: {
unsigned short type = p.d.read<unsigned short>(); unsigned short type = p.d.read<unsigned short>();
std::string source = p.d.read<std::string>(); std::string source = p.d.read<std::string>();
@ -205,8 +217,7 @@ void Server::handlePlayerPacket(ServerClient& client, PacketView& p) {
if (type == 0) refs.primaryInteract(source, list, ind, client.cid); if (type == 0) refs.primaryInteract(source, list, ind, client.cid);
else refs.secondaryInteract(source, list, ind, client.cid); else refs.secondaryInteract(source, list, ind, client.cid);
break; break; }
}
} }
} }

View File

@ -8,6 +8,7 @@
#include "../../Packet.h" #include "../../Packet.h"
#include "../../Serializer.h" #include "../../Serializer.h"
#include "../../Deserializer.h"
#include "../../client/NetPlayerField.h" #include "../../client/NetPlayerField.h"
#include "../../../game/inventory/InventoryRefs.h" #include "../../../game/inventory/InventoryRefs.h"
@ -77,21 +78,26 @@ std::shared_ptr<Inventory> ServerClient::getInventory() {
} }
std::shared_ptr<InventoryList> ServerClient::getHandList() { std::shared_ptr<InventoryList> ServerClient::getHandList() {
return handList; return (*inventory)[handList];
} }
void ServerClient::setHandList(std::shared_ptr<InventoryList> list, bool assert) { void ServerClient::setHandList(const std::string& list, bool assert) {
handList = list; if (list.empty() || !(*inventory)[list]) this->handList = "";
if (assert) assertField(NetPlayerField::HAND_INV, handList ? handList->getName() : ""); else this->handList = list;
if (assert) assertField(NetPlayerField::HAND_INV, this->handList);
} }
std::shared_ptr<InventoryList> ServerClient::getWieldList() { std::shared_ptr<InventoryList> ServerClient::getWieldList() {
return wieldList; return (*inventory)[wieldList];
} }
void ServerClient::setWieldList(std::shared_ptr<InventoryList> list, bool assert) { void ServerClient::setWieldList(const std::string& list, bool assert) {
wieldList = list; if (list.empty() || !(*inventory)[list]) this->wieldList = "";
if (assert) assertField(NetPlayerField::WIELD_INV, wieldList ? wieldList->getName() : ""); else this->wieldList = list;
if (assert) assertField(NetPlayerField::WIELD_INV, this->wieldList);
setWieldIndex(wieldIndex, assert);
} }
unsigned short ServerClient::getWieldIndex() { unsigned short ServerClient::getWieldIndex() {
@ -99,10 +105,28 @@ unsigned short ServerClient::getWieldIndex() {
} }
void ServerClient::setWieldIndex(unsigned short index, bool assert) { void ServerClient::setWieldIndex(unsigned short index, bool assert) {
auto wieldList = (*inventory)[this->wieldList];
wieldIndex = index % (wieldList ? wieldList->getLength() : 1); wieldIndex = index % (wieldList ? wieldList->getLength() : 1);
if (assert) assertField(NetPlayerField::WIELD_INDEX, static_cast<unsigned short>(wieldIndex)); if (assert) assertField(NetPlayerField::WIELD_INDEX, static_cast<unsigned short>(wieldIndex));
} }
void ServerClient::handleAssertion(Deserializer &d) {
while (!d.atEnd()) {
switch (static_cast<NetPlayerField>(d.read<unsigned int>())) {
case NetPlayerField::POSITION: setPos(d.read<glm::vec3>()); break;
case NetPlayerField::VELOCITY: setVel(d.read<glm::vec3>()); break;
case NetPlayerField::PITCH: setPitch(d.read<float>()); break;
case NetPlayerField::YAW: setYaw(d.read<float>()); break;
case NetPlayerField::FLYING: setFlying(d.read<bool>()); break;
case NetPlayerField::HAND_INV: setHandList(d.read<std::string>()); break;
case NetPlayerField::WIELD_INV: setWieldList(d.read<std::string>()); break;
case NetPlayerField::WIELD_INDEX: setWieldIndex(d.read<unsigned short>()); break;
}
}
}
//void ServerClient::setMapBlockIntegrity(glm::ivec3 pos, unsigned long long integrity) { //void ServerClient::setMapBlockIntegrity(glm::ivec3 pos, unsigned long long integrity) {
// mapBlockIntegrity[pos] = integrity; // mapBlockIntegrity[pos] = integrity;
//} //}
@ -116,4 +140,4 @@ template <typename T>
void ServerClient::assertField(NetPlayerField field, T data) { void ServerClient::assertField(NetPlayerField field, T data) {
Serializer().append(static_cast<unsigned int>(field)).append<T>(data) Serializer().append(static_cast<unsigned int>(field)).append<T>(data)
.packet(PacketType::THIS_PLAYER_INFO).sendTo(peer, PacketChannel::INTERACT); .packet(PacketType::THIS_PLAYER_INFO).sendTo(peer, PacketChannel::INTERACT);
} }

View File

@ -14,6 +14,7 @@
#include "../../../game/inventory/ServerInventoryList.h" #include "../../../game/inventory/ServerInventoryList.h"
enum class NetPlayerField; enum class NetPlayerField;
class Deserializer;
class InventoryRefs; class InventoryRefs;
class ServerClient { class ServerClient {
@ -42,14 +43,16 @@ public:
std::shared_ptr<Inventory> getInventory(); std::shared_ptr<Inventory> getInventory();
std::shared_ptr<InventoryList> getHandList(); std::shared_ptr<InventoryList> getHandList();
void setHandList(std::shared_ptr<InventoryList> list, bool assert = false); void setHandList(const std::string& list, bool assert = false);
std::shared_ptr<InventoryList> getWieldList(); std::shared_ptr<InventoryList> getWieldList();
void setWieldList(std::shared_ptr<InventoryList> list, bool assert = false); void setWieldList(const std::string& list, bool assert = false);
unsigned short getWieldIndex(); unsigned short getWieldIndex();
void setWieldIndex(unsigned short index, bool assert = false); void setWieldIndex(unsigned short index, bool assert = false);
void handleAssertion(Deserializer& d);
// void setMapBlockIntegrity(glm::ivec3 pos, unsigned long long integrity); // void setMapBlockIntegrity(glm::ivec3 pos, unsigned long long integrity);
// unsigned long long getMapBlockIntegrity(glm::ivec3 pos); // unsigned long long getMapBlockIntegrity(glm::ivec3 pos);
@ -76,8 +79,9 @@ private:
std::shared_ptr<Inventory> inventory; std::shared_ptr<Inventory> inventory;
unsigned int wieldIndex = 0; unsigned int wieldIndex = 0;
std::shared_ptr<InventoryList> handList = nullptr;
std::shared_ptr<InventoryList> wieldList = nullptr; std::string handList = "";
std::string wieldList = "";
unsigned int handItem = DefinitionAtlas::AIR; unsigned int handItem = DefinitionAtlas::AIR;
unsigned int wieldItem = DefinitionAtlas::AIR; unsigned int wieldItem = DefinitionAtlas::AIR;

View File

@ -17,12 +17,15 @@
#include "../../../def/ServerSubgame.h" #include "../../../def/ServerSubgame.h"
#include "../../../def/item/BlockDef.h" #include "../../../def/item/BlockDef.h"
#include "../../../world/chunk/Chunk.h" #include "../../../world/chunk/Chunk.h"
#include "../../../lua/usertype/Target.h"
#include "../../../world/chunk/MapBlock.h" #include "../../../world/chunk/MapBlock.h"
#include "../../../world/fs/FileManipulator.h" #include "../../../world/fs/FileManipulator.h"
#include "../../../def/ServerDefinitionAtlas.h" #include "../../../lua/usertype/LuaItemStack.h"
#include "../../../lua/usertype/ServerLuaEntity.h" #include "../../../lua/usertype/ServerLuaEntity.h"
#include "../../../lua/usertype/ServerLuaPlayer.h"
ServerWorld::ServerWorld(unsigned int seed, ServerSubgame& game, ClientList& clients) : ServerWorld::ServerWorld(unsigned int seed, ServerSubgame& game, ClientList& clients) :
World(game),
clientList(clients), clientList(clients),
dimension(game), dimension(game),
seed(seed), seed(seed),
@ -68,7 +71,7 @@ void ServerWorld::init(const std::string& worldDir) {
generateMapBlock({0, 0, 0}); generateMapBlock({0, 0, 0});
} }
void ServerWorld::update(double delta) { void ServerWorld::update(double) {
dimension.update(clientList.clients, mapBlockGenRange); dimension.update(clientList.clients, mapBlockGenRange);
std::unordered_set<glm::ivec3, Vec::ivec3> updatedChunks {}; std::unordered_set<glm::ivec3, Vec::ivec3> updatedChunks {};
@ -253,6 +256,27 @@ void ServerWorld::setBlock(glm::ivec3 pos, unsigned int block) {
} }
} }
void ServerWorld::blockPlace(const Target &target, ServerClient &client) {
std::tuple<sol::optional<LuaItemStack>, sol::optional<glm::vec3>> res = game.lua->safe_function(
game.lua->core["block_place"], ServerLuaPlayer(client), Api::Usertype::Target(target));
auto stack = std::get<sol::optional<LuaItemStack>>(res);
if (stack) client.getWieldList()->setStack(client.getWieldIndex(), ItemStack(*stack, game.getDefs()));
}
void ServerWorld::blockInteract(const Target &target, ServerClient &client) {
game.lua->safe_function(game.lua->core["block_interact"],
ServerLuaPlayer(client), Api::Usertype::Target(target));
}
void ServerWorld::blockPlaceOrInteract(const Target &target, ServerClient &client) {
std::tuple<sol::optional<LuaItemStack>, sol::optional<glm::vec3>> res = game.lua->safe_function(
game.lua->core["block_interact_or_place"], ServerLuaPlayer(client), Api::Usertype::Target(target));
auto stack = std::get<sol::optional<LuaItemStack>>(res);
if (stack) client.getWieldList()->setStack(client.getWieldIndex(), ItemStack(*stack, game.getDefs()));
}
bool ServerWorld::isInBounds(glm::ivec3 cPos, std::pair<glm::ivec3, glm::ivec3> &bounds) { bool ServerWorld::isInBounds(glm::ivec3 cPos, std::pair<glm::ivec3, glm::ivec3> &bounds) {
return (cPos.x >= bounds.first.x && cPos.x <= bounds.second.x return (cPos.x >= bounds.first.x && cPos.x <= bounds.second.x
&& cPos.y >= bounds.first.y && cPos.y <= bounds.second.y && cPos.y >= bounds.first.y && cPos.y <= bounds.second.y

View File

@ -10,9 +10,11 @@
#include "../../../world/ServerDimension.h" #include "../../../world/ServerDimension.h"
class ServerSubgame; class Target;
class ItemStack;
class ClientList; class ClientList;
class ServerClient; class ServerClient;
class ServerSubgame;
class FileManipulator; class FileManipulator;
class ServerGenStream; class ServerGenStream;
class ServerPacketStream; class ServerPacketStream;
@ -27,6 +29,10 @@ public:
unsigned int getBlock(glm::ivec3 pos) override; unsigned int getBlock(glm::ivec3 pos) override;
void setBlock(glm::ivec3 pos, unsigned int block) override; void setBlock(glm::ivec3 pos, unsigned int block) override;
void blockPlace(const Target& target, ServerClient& client);
void blockPlaceOrInteract(const Target& target, ServerClient& client);
void blockInteract(const Target& target, ServerClient& client);
ServerDimension dimension; ServerDimension dimension;
private: private:
void changedMapBlocks(ServerClient& client); void changedMapBlocks(ServerClient& client);

View File

@ -1,38 +0,0 @@
//
// Created by aurailus on 13/05/19.
//
#pragma once
#include "../util/Vec.h"
class PointedThing {
public:
enum class Thing {
ENTITY,
BLOCK,
NOTHING
};
struct PointedBlock {
unsigned int blockId;
glm::ivec3 pos;
EVec face;
};
struct PointedEntity {
//TODO;
};
typedef union {
PointedBlock block;
PointedEntity entity;
unsigned short nothing;
} PointedThingTarget;
PointedThing() = default;
PointedThing(const PointedThing &o) = default;
Thing thing = PointedThing::Thing::NOTHING;
PointedThingTarget target = PointedThingTarget{0};
};

13
src/world/Target.cpp Normal file
View File

@ -0,0 +1,13 @@
//
// Created by aurailus on 2020-07-27.
//
#include "Target.h"
#include "../def/item/SelectionBox.h"
Target::Target(glm::ivec3 pos, EVec face) : type(Type::BLOCK), pos(pos), face(face) {}
glm::ivec3 Target::getAbovePos() const {
return glm::ivec3(pos) + SelectionBox::faceToOffset(face);
}

24
src/world/Target.h Normal file
View File

@ -0,0 +1,24 @@
//
// Created by aurailus on 13/05/19.
//
#pragma once
#include "../util/Vec.h"
class Target {
public:
enum class Type { ENTITY, BLOCK, NOTHING };
Target() = default;
Target(const Target &o) = default;
Target(glm::ivec3 pos, EVec face);
glm::ivec3 getAbovePos() const;
public:
Type type = Target::Type::NOTHING;
glm::vec3 pos {};
EVec face = EVec::NONE;
};

View File

@ -27,6 +27,7 @@ zepha.register_block("@aurailus:crazyblocks:inventory", {
if zepha.server then if zepha.server then
zepha.bind("new_player", function(player) zepha.bind("new_player", function(player)
player:get_inventory():get_list("hot_wheel_1"):add_stack({"zeus:default:dirt", 32})
player:get_inventory():get_list("hot_wheel_1"):add_stack({"@aurailus:crazyblocks:stacker", 1}) player:get_inventory():get_list("hot_wheel_1"):add_stack({"@aurailus:crazyblocks:stacker", 1})
player:get_inventory():get_list("hot_wheel_1"):add_stack({"@aurailus:crazyblocks:inventory", 1}) player:get_inventory():get_list("hot_wheel_1"):add_stack({"@aurailus:crazyblocks:inventory", 1})
player:get_inventory():get_list("hot_wheel_1"):add_stack({"@aurailus:crazyblocks:box", 1}) player:get_inventory():get_list("hot_wheel_1"):add_stack({"@aurailus:crazyblocks:box", 1})

View File

@ -1,4 +1,7 @@
set(ZEPHA_TEST add_library(Zepha_Test
Main.cpp tests/TestSpace.cpp tests/TestBlockChunk.cpp tests/TestSerializer.cpp tests/TestBlockChunkSerialization.cpp) Main.cpp
tests/TestSpace.cpp
add_library (Zepha_Test ${ZEPHA_TEST}) tests/TestBlockChunk.cpp
tests/TestSerializer.cpp
tests/TestBlockChunkSerialization.cpp
)