Server-side inventories can be sent to the client for viewing.

master
Nicole Collings 2020-02-27 17:23:42 -08:00
parent 6b4c866ba7
commit 3093d53ea2
33 changed files with 387 additions and 173 deletions

View File

@ -313,6 +313,6 @@ set(ZEPHA_SRC
lua/api/class/LocalLuaInventory.cpp
lua/api/class/LocalLuaInventory.h
lua/api/class/LocalLuaInventoryList.cpp
lua/api/class/LocalLuaInventoryList.h)
lua/api/class/LocalLuaInventoryList.h game/inventory/InventoryRefs.cpp game/inventory/InventoryRefs.h)
add_library (Zepha_Core ${ZEPHA_SRC})

View File

@ -24,4 +24,5 @@ void ClientGame::init(LocalWorld &world, Player& player) {
void ClientGame::update(double delta, bool* keys) {
parser.update(delta, keys);
textures.update();
}

View File

@ -142,6 +142,11 @@ void GuiInventoryList::rightClick(bool down, glm::ivec2 pos) {
}
void GuiInventoryList::drawContents() {
this->hitbox = glm::ivec2 {
padding.x + list->getWidth() * (innerPadding.x*scale.x),
padding.y + (list->getLength() / list->getWidth()) * (innerPadding.y*scale.y)
};
empty();
auto fontRef = defs->textures["font"];

View File

@ -4,8 +4,17 @@
#include "Inventory.h"
void Inventory::sendDirtyLists() {
for (auto& list : lists) {
if (list.second->dirty) {
list.second->sendAll();
list.second->dirty = false;
}
}
}
void Inventory::createList(std::string name, unsigned short length, unsigned short width) {
lists.emplace(name, std::make_shared<InventoryList>(defs, name, length, width));
lists.emplace(name, std::make_shared<InventoryList>(defs, clients, this->name, name, length, width));
}
std::shared_ptr<InventoryList> Inventory::operator[](std::string name) {
@ -15,4 +24,4 @@ std::shared_ptr<InventoryList> Inventory::operator[](std::string name) {
void Inventory::removeList(std::string name) {
lists.erase(name);
}
}

View File

@ -9,15 +9,21 @@
#include <memory>
#include "InventoryList.h"
class ClientList;
class Inventory {
public:
Inventory(DefinitionAtlas& defs) : defs(defs) {};
Inventory(DefinitionAtlas& defs, ClientList* clients, const std::string& name) : defs(defs), clients(clients), name(name) {};
void sendDirtyLists();
void createList(std::string name, unsigned short length, unsigned short width);
std::shared_ptr<InventoryList> operator[](std::string name);
void removeList(std::string name);
DefinitionAtlas& defs;
std::string name;
private:
ClientList* clients;
std::map<std::string, std::shared_ptr<InventoryList>> lists;
};

View File

@ -4,19 +4,21 @@
#include <iostream>
#include <algorithm>
#include "InventoryList.h"
#include "../../util/net/Packet.h"
#include "../../util/net/Serializer.h"
#include "../../server/conn/ClientList.h"
#include "../../lua/api/class/LuaItemStack.h"
InventoryList::InventoryList(DefinitionAtlas& defs, const std::string& name, unsigned short size, unsigned short width) :
InventoryList::InventoryList(DefinitionAtlas& defs, ClientList* list, const std::string& invName, const std::string& name, unsigned short size, unsigned short width) :
defs(defs),
name(name),
itemstacks(size),
width(width) {}
void InventoryList::setGuiCallback(std::function<void()> cb) {
this->guiCallback = cb;
}
width(width),
clients(list),
invName(invName),
itemstacks(size) {}
void InventoryList::setLuaCallback(InventoryList::Callback type, sol::function cb) {
luaCallbacks[static_cast<size_t>(type)] = cb;
@ -33,7 +35,7 @@ ItemStack InventoryList::getStack(unsigned short i) {
void InventoryList::setStack(unsigned short i, const ItemStack &stack) {
if (stack != getStack(i)) {
itemstacks[i] = stack;
triggerCallback();
setDirty();
}
}
@ -128,7 +130,7 @@ ItemStack InventoryList::addStack(ItemStack stack, bool playerInitiated) {
if (itemstacks[i].count == 0) {
if (stack.count <= maxStack) {
itemstacks[i] = stack;
triggerCallback();
setDirty();
return ItemStack{};
}
else {
@ -141,7 +143,7 @@ ItemStack InventoryList::addStack(ItemStack stack, bool playerInitiated) {
unsigned int fits = maxStack - itemstacks[i].count;
if (fits >= stack.count) {
itemstacks[i].count += stack.count;
triggerCallback();
setDirty();
return ItemStack {};
}
else {
@ -152,7 +154,7 @@ ItemStack InventoryList::addStack(ItemStack stack, bool playerInitiated) {
i++;
}
triggerCallback();
setDirty();
return stack;
}
@ -190,7 +192,7 @@ ItemStack InventoryList::takeStack(ItemStack request, bool playerInitiated) {
unsigned int can_take = itemstacks[i].count;
if (can_take >= to_remove) {
itemstacks[i].count -= to_remove;
triggerCallback();
setDirty();
return request;
}
else {
@ -202,7 +204,7 @@ ItemStack InventoryList::takeStack(ItemStack request, bool playerInitiated) {
}
request.count = (request.count - to_remove);
triggerCallback();
setDirty();
return request;
}
@ -220,8 +222,8 @@ ItemStack InventoryList::removeStack(unsigned short ind, unsigned short count) {
}
}
void InventoryList::triggerCallback() {
if (guiCallback != nullptr) guiCallback();
void InventoryList::setDirty() {
dirty = true;
}
unsigned short InventoryList::getLength() {
@ -234,4 +236,61 @@ unsigned short InventoryList::getWidth() {
std::string InventoryList::getName() {
return name;
}
}
bool InventoryList::addWatcher(unsigned int cid) {
auto& client = clients->getClient(cid);
if (!client) return false;
for (const auto& i : watchers) if (i == cid) return false;
watchers.push_back(cid);
sendTo(client);
}
bool InventoryList::removeWatcher(unsigned int cid) {
for (auto it = watchers.cbegin(); it != watchers.cend();) {
if (*it == cid) {
watchers.erase(it);
return true;
}
it++;
}
return false;
}
Packet InventoryList::createPacket() {
Serializer s{};
s.append<std::string>(invName)
.append<std::string>(name)
.append<unsigned int>(itemstacks.size())
.append<unsigned int>(width);
for (auto& stack : itemstacks) {
s.append<unsigned short>(stack.count);
s.append<unsigned int>(stack.id);
}
return s.packet(PacketType::INVENTORY, false);
}
void InventoryList::sendTo(std::shared_ptr<ServerClient> client) {
if (!client) return;
auto p = createPacket();
p.sendTo(client->peer, PacketChannel::INVENTORY);
}
void InventoryList::sendAll() {
auto p = createPacket();
for (auto it = watchers.cbegin(); it != watchers.cend();) {
auto& client = clients->getClient(*it);
if (!client) {
it = watchers.erase(it);
}
else {
p.sendTo(client->peer, PacketChannel::INVENTORY);
it++;
}
}
}

View File

@ -7,13 +7,19 @@
#include <list>
#include <vector>
#include <functional>
#include "ItemStack.h"
class ClientList;
class ServerClient;
class Packet;
class InventoryList {
public:
enum class Callback { ALLOW_TAKE, ALLOW_PUT, ON_TAKE, ON_PUT };
InventoryList(DefinitionAtlas& defs, const std::string& name, unsigned short size, unsigned short width);
InventoryList(DefinitionAtlas& defs, ClientList* list, const std::string& invName,
const std::string& name, unsigned short size, unsigned short width);
unsigned short getLength();
unsigned short getWidth();
@ -36,19 +42,28 @@ public:
// Removes up to count items from ind, returns the items removed
ItemStack removeStack(unsigned short ind, unsigned short count);
void setGuiCallback(std::function<void()> cb);
bool addWatcher(unsigned int cid);
bool removeWatcher(unsigned int cid);
void sendAll();
void sendTo(std::shared_ptr<ServerClient> client);
void setLuaCallback(Callback type, sol::function cb);
sol::function getLuaCallback(Callback type);
DefinitionAtlas& defs;
bool dirty = false;
private:
void triggerCallback();
void setDirty();
Packet createPacket();
std::vector<ItemStack> itemstacks {};
unsigned short width = 0;
std::string name;
std::string invName;
std::function<void()> guiCallback = nullptr;
std::array<sol::function, 4> luaCallbacks = {};
ClientList* clients;
std::list<unsigned int> watchers;
};

View File

@ -0,0 +1,46 @@
//
// Created by aurailus on 2020-02-26.
//
#include "InventoryRefs.h"
#include "InventoryList.h"
InventoryRefs::InventoryRefs(ServerDefinitionAtlas &defs, ClientList* clients) :
defs(defs), clients(clients) {}
void InventoryRefs::update() {
for (auto& inv : inventories) {
inv.second->sendDirtyLists();
}
}
std::shared_ptr<Inventory> InventoryRefs::createInv(const std::string &inv) {
inventories.emplace(inv, std::make_shared<Inventory>(defs, clients, inv));
return inventories[inv];
}
std::shared_ptr<Inventory> InventoryRefs::getInv(const std::string &inv) {
return inventories[inv];
}
std::shared_ptr<InventoryList> InventoryRefs::getList(const std::string &inv, const std::string &list) {
if (!inventories.count(inv)) return nullptr;
return inventories[inv]->operator[](list);
}
bool InventoryRefs::addWatcher(const std::string &inv, const std::string &list, unsigned int cid) {
if (!inventories.count(inv)) return false;
if (!inventories[inv]->operator[](list)) return false;
inventories[inv]->operator[](list)->addWatcher(cid);
return true;
}
bool InventoryRefs::removeWatcher(const std::string &inv, const std::string &list, unsigned int cid) {
if (!inventories.count(inv)) return false;
if (!inventories[inv]->operator[](list)) return false;
inventories[inv]->operator[](list)->removeWatcher(cid);
return true;
}

View File

@ -0,0 +1,30 @@
//
// Created by aurailus on 2020-02-26.
//
#pragma once
#include "../../def/ServerDefinitionAtlas.h"
#include "Inventory.h"
class InventoryList;
class InventoryRefs {
public:
InventoryRefs(ServerDefinitionAtlas& defs, ClientList* clients);
void update();
std::shared_ptr<Inventory> createInv(const std::string& inv);
std::shared_ptr<Inventory> getInv(const std::string& inv);
std::shared_ptr<InventoryList> getList(const std::string& inv, const std::string& list);
bool addWatcher(const std::string& inv, const std::string& list, unsigned int cid);
bool removeWatcher(const std::string& inv, const std::string& list, unsigned int cid);
private:
std::unordered_map<std::string, std::shared_ptr<Inventory>> inventories {};
ClientList* clients;
ServerDefinitionAtlas& defs;
double time = 0;
};

View File

@ -15,6 +15,11 @@ LocalInventoryList::LocalInventoryList(DefinitionAtlas& defs, const std::string&
itemstacks(size),
width(width) {}
void LocalInventoryList::setData(unsigned int size, unsigned int width, std::vector<ItemStack> stacks) {
this->width = width;
this->itemstacks = stacks;
triggerCallback();
}
void LocalInventoryList::setGuiCallback(std::function<void()> cb) {
this->guiCallback = cb;
@ -236,4 +241,4 @@ unsigned short LocalInventoryList::getWidth() {
std::string LocalInventoryList::getName() {
return name;
}
}

View File

@ -20,6 +20,8 @@ public:
unsigned short getWidth();
std::string getName();
void setData(unsigned int size, unsigned int width, std::vector<ItemStack> stacks);
// Place the stack at i into the existing stack, returning overflow or other stack.
ItemStack placeStack(unsigned short i, const ItemStack& stack, bool playerInitiated = false);
// Split the stack at i and return half of it, rounded up

View File

@ -4,15 +4,20 @@
#include "LocalInventoryRefs.h"
LocalInventoryRefs::LocalInventoryRefs(LocalDefinitionAtlas& defs, ClientNetworkInterpreter& net) :
defs(defs),
net(net) {
#include "../scene/net/ClientNetworkInterpreter.h"
LocalInventoryRefs::LocalInventoryRefs(LocalDefinitionAtlas& defs) :
defs(defs) {
inventories.insert({"current_player", std::make_shared<LocalInventory>(defs, "current_player")});
inventories["current_player"]->createList("hand", 1, 1, true);
}
void LocalInventoryRefs::update(double delta) {
void LocalInventoryRefs::setWatchFunction(std::function<void(std::string, std::string)> watchFn) {
this->watchFn = watchFn;
}
void LocalInventoryRefs::update(double delta, ClientNetworkInterpreter& net) {
time += delta;
for (auto mIt = inventories.begin(); mIt != inventories.end();) {
@ -29,11 +34,36 @@ std::shared_ptr<LocalInventoryList> LocalInventoryRefs::getList(const std::strin
if (!inventories.count(inv)) inventories.insert({inv, {}});
if (inventories[inv]->operator[](list) == nullptr) {
inventories[inv]->createList(list, 1, 1);
net.watchInv(inv, list);
watchFn(inv, list);
}
return inventories[inv]->operator[](list);
}
std::shared_ptr<LocalInventoryList> LocalInventoryRefs::getHand() {
return inventories["current_player"]->operator[]("hand");
}
void LocalInventoryRefs::packetReceived(std::unique_ptr<Packet> p) {
Deserializer d(p->data);
std::string source = d.read<std::string>();
std::string list = d.read<std::string>();
if (strncmp(source.data(), "player:", 7) == 0) source = "current_player";
if (!inventories.count(source)) return;
if (!inventories[source]->operator[](list)) return;
unsigned int size = d.read<unsigned int>();
unsigned int width = d.read<unsigned int>();
std::vector<ItemStack> stacks {};
stacks.reserve(size);
while (!d.atEnd()) {
unsigned short count = d.read<unsigned short>();
unsigned int id = d.read<unsigned int>();
stacks.push_back({id, count});
}
inventories[source]->operator[](list)->setData(size, width, stacks);
}

View File

@ -9,14 +9,16 @@
#include "LocalInventory.h"
#include "LocalInventoryList.h"
#include "../scene/net/ClientNetworkInterpreter.h"
#include "../../def/LocalDefinitionAtlas.h"
class LocalInventoryRefs {
public:
LocalInventoryRefs(LocalDefinitionAtlas& defs, ClientNetworkInterpreter& net);
LocalInventoryRefs(LocalDefinitionAtlas& defs);
void update(double delta);
void setWatchFunction(std::function<void(std::string, std::string)> watchFn);
void update(double delta, ClientNetworkInterpreter& net);
void packetReceived(std::unique_ptr<Packet> p);
std::shared_ptr<LocalInventory> getInv(const std::string& inv);
std::shared_ptr<LocalInventoryList> getList(const std::string& inv, const std::string& list);
@ -24,7 +26,8 @@ public:
private:
std::unordered_map<std::string, std::shared_ptr<LocalInventory>> inventories {};
ClientNetworkInterpreter& net;
std::function<void(std::string, std::string)> watchFn = nullptr;
LocalDefinitionAtlas& defs;
double time = 0;

View File

@ -5,48 +5,43 @@
#include "GameScene.h"
GameScene::GameScene(ClientState& state) : Scene(state),
refs(game.defs),
game(state.defs),
refs(game.defs, net),
world(game, &playerPos, &net),
world(game, &net),
net(state.connection, game, player),
player(world, game, state.renderer, refs),
debugGui(state.renderer.window.getSize(), game) {
state.renderer.setClearColor(148, 194, 240);
state.renderer.window.lockMouse(true);
game.init(world, player);
world.init();
net.init(&world);
namespace ph = std::placeholders;
Packet r(PacketType::CONNECT_DATA_RECVD);
r.sendTo(state.connection.getPeer(), PacketChannel::CONNECT);
state.renderer.window.addResizeCallback("gamescene", [&](glm::ivec2 win) {
debugGui.bufferResized(win);
});
world.init(&player);
net.init(&world, std::bind(&LocalInventoryRefs::packetReceived, refs, ph::_1));
game.init(world, player);
refs.setWatchFunction(std::bind(&ClientNetworkInterpreter::watchInv, &net, ph::_1, ph::_2));
state.renderer.window.addResizeCallback("gamescene", std::bind(&DebugGui::bufferResized, debugGui, ph::_1));
state.renderer.setClearColor(148, 194, 240);
state.renderer.window.lockMouse(true);
}
void GameScene::update() {
game.update(state.delta, state.renderer.window.keys);
game.textures.update();
refs.update(state.delta);
net.update();
Window& window = state.renderer.window;
//Update Player
player.update(window.input, state.delta, window.getDelta());
playerPos = player.getPos();
game .update(state.delta, state.renderer.window.keys);
refs .update(state.delta, net);
net .update();
for (auto entity : entities) entity->update(state.delta);
for (auto &chunkPacket : net.chunkPackets) world.loadChunkPacket(std::move(chunkPacket));
net.chunkPackets.clear();
debugGui.update(player, world, game, state.fps, world.getMeshChunkCount(), drawCalls, net.serverSideChunkGens, net.recvPackets);
net.recvPackets = 0;
world.update(state.delta);
net.serverSideChunkGens = 0;
net.recvPackets = 0;
if (window.input.isKeyPressed(GLFW_KEY_F1)) {
hudVisible = !hudVisible;

View File

@ -20,16 +20,13 @@ public:
public:
ClientGame& game;
ClientNetworkInterpreter net;
LocalInventoryRefs refs;
ClientNetworkInterpreter net;
LocalWorld world;
glm::vec3 playerPos;
Player player;
std::vector<Drawable*> entities;
DebugGui debugGui;
std::vector<Drawable*> entities;
int drawCalls = 0;
bool debugVisible = true;

View File

@ -9,16 +9,15 @@
#include "../../../util/net/NetHandler.h"
ClientNetworkInterpreter::ClientNetworkInterpreter(ServerConnection &connection, ClientGame &defs, Player& player) :
world(nullptr),
player(player),
connection(connection),
playerModel(std::make_shared<Model>()) {
playerModel->fromSerialized(defs.models.models["zeus:default:player"], {defs.textures["zeus:default:player"]});
}
void ClientNetworkInterpreter::init(LocalWorld *world) {
void ClientNetworkInterpreter::init(LocalWorld *world, std::function<void(std::unique_ptr<Packet>)> invCallback) {
this->world = world;
this->onInvPacket = invCallback;
}
void ClientNetworkInterpreter::update() {
@ -76,7 +75,7 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<Packet> p) {
while (!d.atEnd()) {
switch (d.read<unsigned int>()) {
case static_cast<unsigned int>(NetPlayerField::ID): {
id = d.read<unsigned int>();
cid = d.read<unsigned int>();
break;
}
case static_cast<unsigned int>(NetPlayerField::POSITION): {
@ -99,7 +98,7 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<Packet> p) {
case PacketType::PLAYER_INFO: {
unsigned int cid = d.read<unsigned int>();
if (cid == id) break;
if (this->cid == cid) break;
bool found = false;
for (auto& entity : world->dimension.playerEntities) {
@ -133,7 +132,7 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<Packet> p) {
}
case PacketType::CHUNK: {
chunkPackets.push_back(std::move(p));
world->loadChunkPacket(std::move(p));
break;
}
@ -141,6 +140,19 @@ void ClientNetworkInterpreter::receivedPacket(std::unique_ptr<Packet> p) {
serverSideChunkGens = d.read<unsigned int>();
break;
}
case PacketType::INV_INVALID: {
std::string source = d.read<std::string>();
std::string list = d.read<std::string>();
std::cout << Log::err << "Invalid inventory " << source << ":" << list << " was requested by client." << Log::endl;
exit(1);
}
case PacketType::INVENTORY: {
onInvPacket(std::move(p));
break;
}
}
}
@ -157,8 +169,4 @@ void ClientNetworkInterpreter::watchInv(const std::string& inv, const std::strin
void ClientNetworkInterpreter::unwatchInv(const std::string& inv, const std::string& list) {
Serializer().append(inv).append(list)
.packet(PacketType::UNWATCH_INV).sendTo(connection.getPeer(), PacketChannel::INVENTORY);
}
ClientNetworkInterpreter::~ClientNetworkInterpreter() {
connection.disconnect();
}
}

View File

@ -12,27 +12,26 @@ public:
ClientNetworkInterpreter(ServerConnection& connection, ClientGame& defs, Player& player);
ClientNetworkInterpreter(const ClientNetworkInterpreter& other) = default;
void init(LocalWorld* world);
void init(LocalWorld* world, std::function<void(std::unique_ptr<Packet>)> invCallback);
void update();
void receivedPacket(std::unique_ptr<Packet> ePacket);
// Functions to be called by outside of ClientNetworkInterpreter
void setBlock(glm::ivec3 pos, unsigned int block);
void watchInv(const std::string& inv, const std::string& list);
void unwatchInv(const std::string& inv, const std::string& list);
~ClientNetworkInterpreter();
int recvPackets = 0;
int serverSideChunkGens = 0;
std::vector<std::unique_ptr<Packet>> chunkPackets;
private:
void receivedPacket(std::unique_ptr<Packet> ePacket);
int cid = 0;
Player& player;
ServerConnection& connection;
LocalWorld* world = nullptr;
std::shared_ptr<Model> playerModel;
int id = 0;
std::function<void(std::unique_ptr<Packet>)> onInvPacket;
};

View File

@ -4,18 +4,19 @@
#include "LocalWorld.h"
#include "Player.h"
#include "WorldInterpolationStream.h"
#include "../net/ClientNetworkInterpreter.h"
#include "../../entity/engine/BlockCrackEntity.h"
#include "../../entity/engine/ParticleEntity.h"
LocalWorld::LocalWorld(ClientGame& defs, glm::vec3* playerPos, ClientNetworkInterpreter* server) :
dimension(defs),
defs(defs),
server(server),
playerPos(playerPos) {}
LocalWorld::LocalWorld(ClientGame& defs, ClientNetworkInterpreter* server) :
defs(defs),
net(server),
dimension(defs) {}
void LocalWorld::init() {
void LocalWorld::init(Player* player) {
this->player = player;
delete worldGenStream;
worldGenStream = new WorldInterpolationStream(55, defs);
}
@ -23,12 +24,12 @@ void LocalWorld::init() {
void LocalWorld::update(double delta) {
finishChunks();
updateBlockDamages(delta);
dimension.update(delta, *playerPos);
dimension.update(delta, player->getPos());
lastMeshUpdates = dimension.lastMeshUpdates;
auto end = particles.begin();
for (auto i = particles.begin(); i < particles.end(); i++) {
(*i)->update(delta, *playerPos);
(*i)->update(delta, player->getPos());
if ((*i)->time > 1) {
end = i;
delete (*i);
@ -67,7 +68,7 @@ void LocalWorld::localSetBlock(glm::ivec3 pos, unsigned int block) {
}
}
server->setBlock(pos, block);
net->setBlock(pos, block);
dimension.setBlock(pos, block);
}

View File

@ -14,12 +14,13 @@ class WorldInterpolationStream;
class BlockCrackEntity;
class ParticleEntity;
class Renderer;
class Player;
class LocalWorld : public World {
public:
LocalWorld(ClientGame& defs, glm::vec3* playerPos, ClientNetworkInterpreter* server);
LocalWorld(ClientGame& defs, ClientNetworkInterpreter* net);
void init();
void init(Player* player);
void update(double delta) override;
void loadChunkPacket(std::unique_ptr<Packet> p);
@ -47,11 +48,10 @@ private:
void finishChunks();
void updateBlockDamages(double delta);
glm::vec3* playerPos;
std::vector<BlockCrackEntity*> crackedBlocks;
std::vector<ParticleEntity*> particles;
ClientNetworkInterpreter* server = nullptr;
Player* player = nullptr;
ClientNetworkInterpreter* net = nullptr;
WorldInterpolationStream* worldGenStream = nullptr;
};

View File

@ -4,7 +4,6 @@
#pragma once
#include "../../inventory/Inventory.h"
#include "../../hud/GameGui.h"
#include "../../entity/Collidable.h"
#include "../../hud/GameGuiBuilder.h"

View File

@ -4,9 +4,7 @@
#pragma once
#include <memory>
#include <glm/vec3.hpp>
#include "../../../world/Dimension.h"
class World {
public:

View File

@ -65,5 +65,5 @@ std::string ServerLuaPlayer::get_address() {
}
ServerLuaInventory ServerLuaPlayer::get_inventory() {
return ServerLuaInventory(player.getInventory());
return ServerLuaInventory(*player.getInventory());
}

View File

@ -14,6 +14,7 @@ Server::Server(unsigned short port, const std::string& subgame) :
defs(subgame),
clientList(defs),
handler(port, 32),
refs(defs.defs, &clientList),
world(10, defs, clientList) {
defs.init(world);
@ -30,6 +31,7 @@ void Server::update() {
world.update(0);
defs.update(deltaTime, clientList);
refs.update();
ENetEvent event;
while (handler.update(&event) && loop.elapsedNs() < interval_ns) {
@ -40,7 +42,7 @@ void Server::update() {
break;
}
case ENET_EVENT_TYPE_CONNECT: {
clientList.handleConnect(event);
clientList.handleConnect(event, refs);
break;
}
case ENET_EVENT_TYPE_DISCONNECT: {
@ -142,19 +144,37 @@ void Server::handlePlayerPacket(ServerClient &client, Packet& p) {
case PacketType::WATCH_INV: {
Deserializer d(p.data);
// std::string source = d.read<std::string>();
// std::string list = d.read<std::string>();
std::string source = d.read<std::string>();
std::string list = d.read<std::string>();
// TODO: When inventory saving / loading is implemented there will need to be a cross-save identifier.
if (source == "current_player") source = "player:" + std::to_string(client.cid);
bool exists = refs.addWatcher(source, list, client.cid);
if (!exists) {
Serializer().append(source).append(list)
.packet(PacketType::INV_INVALID).sendTo(client.peer, PacketChannel::INVENTORY);
break;
}
// std::cout << "watching " << source << ":" << list << std::endl;
break;
}
case PacketType::UNWATCH_INV: {
Deserializer d(p.data);
// std::string source = d.read<std::string>();
// std::string list = d.read<std::string>();
std::string source = d.read<std::string>();
std::string list = d.read<std::string>();
// TODO: When inventory saving / loading is implemented there will need to be a cross-save identifier.
if (source == "current_player") source = "player:" + std::to_string(client.cid);
bool exists = refs.removeWatcher(source, list, client.cid);
if (!exists) {
Serializer().append(source).append(list)
.packet(PacketType::INV_INVALID).sendTo(client.peer, PacketChannel::INVENTORY);
break;
}
// std::cout << "unwatching " << source << ":" << list << std::endl;
break;
}
}

View File

@ -9,6 +9,7 @@
#include "config/ServerConfig.h"
#include "../def/ServerGame.h"
#include "../util/net/NetHandler.h"
#include "../game/inventory/InventoryRefs.h"
class ServerClient;
class Packet;
@ -31,6 +32,7 @@ private:
NetHandler handler;
ClientList clientList;
ServerConfig config;
InventoryRefs refs;
std::unordered_set<unsigned int> playersUpdated {};

View File

@ -3,20 +3,20 @@
//
#include "ClientList.h"
#include "../../def/ServerGame.h"
#include "../../util/net/Serializer.h"
#include "../../util/net/NetHandler.h"
#include "../../def/ServerGame.h"
#include "../../game/scene/net/NetPlayerField.h"
ClientList::ClientList(ServerGame& defs) :
defs(defs) {}
void ClientList::handleConnect(ENetEvent e) {
void ClientList::handleConnect(ENetEvent e, InventoryRefs& refs) {
ENetPeer* peer = e.peer;
ENetAddress& addr = peer->address;
auto client = std::make_shared<ServerClient>(peer, addr, defs.defs);
auto client = std::make_shared<ServerClient>(peer, addr, defs.defs, refs);
clients.push_back(client);
peer->data = client.get();
@ -42,6 +42,8 @@ void ClientList::createPlayer(std::shared_ptr<ServerClient> c) {
c->hasPlayer = true;
c->setUsername("TEMPORaRY");
c->getInventory()->createList("hand", 1, 1);
defs.parser.playerConnected(c);
Packet p(PacketType::THIS_PLAYER_INFO);

View File

@ -5,6 +5,7 @@
#pragma once
#include <vector>
#include "ServerClient.h"
#include "../../lua/parser/ServerLuaParser.h"
@ -12,7 +13,7 @@ class ClientList {
public:
explicit ClientList(ServerGame& defs);
void handleConnect(ENetEvent e);
void handleConnect(ENetEvent e, InventoryRefs& refs);
void handleDisconnect(ENetEvent e);
void createPlayer(std::shared_ptr<ServerClient> c);

View File

@ -3,17 +3,20 @@
//
#include <iostream>
#include "ServerClient.h"
#include "../../util/net/Packet.h"
#include "../../util/net/Serializer.h"
#include "../../game/inventory/InventoryRefs.h"
#include "../../game/scene/net/NetPlayerField.h"
ServerClient::ServerClient(ENetPeer *peer, ENetAddress address, DefinitionAtlas& defs) :
ServerClient::ServerClient(ENetPeer *peer, ENetAddress address, DefinitionAtlas& defs, InventoryRefs& refs) :
peer(peer),
address(address),
cid(peer->connectID),
hand(defs, "hand", 1, 1),
inventory(defs) {}
inventory(refs.createInv("player:" + std::to_string(cid))) {
}
void ServerClient::setUsername(const std::string &name) {
this->username = name;
@ -92,6 +95,6 @@ unsigned long long ServerClient::getMapBlockIntegrity(glm::ivec3 pos) {
return 0;
}
Inventory &ServerClient::getInventory() {
std::shared_ptr<Inventory> ServerClient::getInventory() {
return inventory;
}

View File

@ -12,11 +12,13 @@
#include "../../game/inventory/InventoryList.h"
#include "../../game/inventory/Inventory.h"
class InventoryRefs;
class ServerClient {
public:
const static int CHUNK_SEND_RANGE = 32;
ServerClient(ENetPeer* peer, ENetAddress address, DefinitionAtlas& defs);
ServerClient(ENetPeer* peer, ENetAddress address, DefinitionAtlas& defs, InventoryRefs& refs);
void setUsername(const std::string& name);
@ -38,11 +40,11 @@ public:
void setMapBlockIntegrity(glm::ivec3 pos, unsigned long long integrity);
unsigned long long getMapBlockIntegrity(glm::ivec3 pos);
Inventory& getInventory();
std::shared_ptr<Inventory> getInventory();
bool hasPlayer = false;
unsigned int cid;
unsigned int cid = 0;
std::string username;
ENetPeer* peer;
@ -58,8 +60,7 @@ private:
bool flying = false;
InventoryList hand;
Inventory inventory;
std::shared_ptr<Inventory> inventory;
std::unordered_map<glm::ivec3, unsigned long long, Vec::ivec3> mapBlockIntegrity {};
};

View File

@ -23,7 +23,11 @@ enum class PacketType {
CHUNK,
BLOCK_SET,
ENTITY_INFO,
// Inventory
WATCH_INV,
UNWATCH_INV
UNWATCH_INV,
INV_INVALID,
INVENTORY
};

View File

@ -17,7 +17,11 @@ zepha.register_block("zeus:default:grass", {
shovel = 1,
pick = 2
},
drop = "zeus:default:dirt"
drop = "zeus:default:dirt",
on_break = fn(pos) {
zepha.add_entity("zeus:default:dropped_item", vector.add(pos, v(0.5)),
{item = zepha.registered_blocks["zeus:default:grass"].drop});
}
})
zepha.register_block("zeus:default:grass_slab", {

View File

@ -79,18 +79,21 @@ zepha.register_entity("zeus:default:dropped_item", {
if (self.tick > 0.15) {
self.tick = 0
if (zepha.client) { self:check_collect() }
self:check_collect()
}
},
check_collect = fn(self) {
if (vector.distance(zepha.player.pos, self.object.pos) < 2) {
self.object.pos = vector.add(zepha.player.pos, v(0, 0.90, 0))
self.scooping = true
foreach p in zepha.players {
if (vector.distance(p.pos, self.object.pos) < 2) {
self.object.pos = vector.add(p.pos, v(0, 0.90, 0))
self.scooping = true
zepha.delay(() => {
zepha.remove_entity(self)
zepha.player:get_inventory():get_list("main"):add_stack({self.item, 1})
}, 2/20)
zepha.delay(() => {
zepha.remove_entity(self)
p:get_inventory():get_list("main"):add_stack({self.item, 1})
}, 2/20)
}
}
},
on_serialize = fn(self) {

View File

@ -33,11 +33,11 @@ zepha.register_keybind("zeus:default:open_chat", {
on_press = () => { print "Opened chat!" }
})
if (zepha.server) {
zepha.delay(() => {
foreach player in zepha.players {
player:get_inventory():get_list("main"):add_stack({"zeus:default:dirt", 1})
}
return true
}, 1/20)
}
##if (zepha.server) {
## zepha.delay(() => {
## foreach player in zepha.players {
## player:get_inventory():get_list("main"):add_stack({"zeus:default:dirt", 1})
## }
## return true
## }, 1/20)
##}

View File

@ -3,40 +3,6 @@ zepha.register_on("player_join", (p) => {
local inv = p:get_inventory()
local main = inv:add_list("main", 44, 11)
local shit_adding = false
zepha.register_keybind("zeus:inventory:add_shit_b", {
description = "Add testing items to inventory",
default = zepha.keys.b,
on_press = () => { shit_adding = 1 },
on_release = () => { shit_adding = 0 }
})
zepha.register_keybind("zeus:inventory:add_shit_i", {
description = "Add testing items to inventory",
default = zepha.keys.n,
on_press = () => { shit_adding = 2 },
on_release = () => { shit_adding = 0 }
})
zepha.delay(() => {
if (shit_adding == 1) {
main:add_stack({"zeus:default:cobblestone", 1})
main:add_stack({"zeus:default:tallgrass_5", 1})
main:add_stack({"zeus:default:leaves", 1})
main:add_stack({"zeus:kinetic:axle_0", 1})
main:add_stack({"zeus:default:wood", 1})
}
if (shit_adding == 2) {
main:add_stack({"zeus:materials:plant_fibre", 1})
main:add_stack({"zeus:materials:plant_twine", 1})
main:add_stack({"zeus:materials:stick", 1})
main:add_stack({"zeus:materials:flint", 1})
}
return true
}, 0)
## Bind crafting
local craft_input = inv:add_list("craft", 4, 2)
@ -44,7 +10,7 @@ zepha.register_on("player_join", (p) => {
crafting.bind(craft_input, craft_output)
## Make hotwheel
## Make hot wheel
local invs = {
inv:add_list("hot_wheel_1", 5, 5),