diff --git a/engine/network.hpp b/engine/network.hpp
new file mode 100644
index 0000000..8bdeae7
--- /dev/null
+++ b/engine/network.hpp
@@ -0,0 +1,266 @@
+/*
+ * This file is a part of Pixelbox - Infinite 2D sandbox game
+ * Enet wrapper!
+ * Copyright (C) 2023-2024 UtoECat
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#pragma once
+#include
+#include
+#include
+#include
+#include "external/enet.h"
+#include
+
+/**
+ * @description ENet Wrapper
+ */
+namespace pb {
+
+ struct ProtocolInfo {
+ const char* ip;
+ unsigned short port;
+ int nchannels;
+ int nconnections;
+ public:
+ inline ENetAddress getAddress() {
+ ENetAddress addr;
+ addr.port = port;
+
+ if (ip)
+ enet_address_set_host(&addr, ip);
+ else addr.host = ENET_HOST_ANY;
+ return addr;
+ }
+ };
+
+ static void HostDefaultConfig(ENetHost* host) {
+ // TODO Adjust to better values!
+ host->maximumPacketSize = 1024 * 32;
+ host->maximumWaitingData = 1024 * 128;
+ }
+
+ class ENetClient : public Default {
+ ENetHost* host;
+ ENetPeer* server = nullptr;
+ ProtocolInfo pinfo;
+ public:
+
+ ENetClient(ProtocolInfo info) {
+ pinfo = info;
+ auto addr = info.getAddress();
+ host = enet_host_create(NULL, info.nconnections, info.nchannels,
+ 0, 0);
+ if (!host) {
+ throw std::runtime_error("Can't create client!");
+ }
+ HostDefaultConfig(host);
+ }
+
+ void disconnect() {
+ if (server) {
+ enet_peer_reset(server);
+ server = nullptr;
+ }
+ }
+
+ const char* errmsg = nullptr;
+ bool service(ENetEvent& ev, int timeout = 1) {
+ return enet_host_service(host, &ev, timeout) > 0;
+ }
+
+ bool connect() {
+ if (server) disconnect();
+ auto addr = pinfo.getAddress();
+ server = enet_host_connect(host, &addr, pinfo.nchannels, 0);
+
+ if (!server) {
+ errmsg = "can't create peer!";
+ return false;
+ }
+ // process events
+ ENetEvent event;
+ if (enet_host_service(host, &event, 5000) > 0 &&
+ event.type == ENET_EVENT_TYPE_CONNECT) {
+ return true;
+ }
+
+ errmsg = "Can't connect to server!";
+ enet_peer_reset(server);
+ server = nullptr;
+ return false;
+ }
+
+ ~ENetClient() {
+ disconnect();
+ enet_host_destroy(host);
+ }
+
+ /* must be called after event is processeed */
+ bool is_connected() {
+ return server != nullptr;
+ }
+
+ void releaseEvent(ENetEvent& ev) {
+ if (ev.type == ENET_EVENT_TYPE_RECEIVE && ev.packet) {
+ enet_packet_destroy(ev.packet);
+ }
+ }
+
+ /** @warning channel starts FROM ZERO!!!! */
+ void send(uint8_t channel, ENetPacket* data) {
+ if (server)
+ enet_peer_send(server, channel, data);
+ }
+
+ void flush() {
+ enet_host_flush(host);
+ }
+ };
+
+ class ConnectionData {
+ public:
+ virtual ~ConnectionData() {};
+ };
+
+ class ENetConnection {
+ ENetPeer* peer;
+ public:
+ ENetConnection(ENetPeer* p) {
+ peer = p;
+ }
+ ~ENetConnection() {} // nothing
+ public:
+ void disconnect() {
+ enet_peer_disconnect_later(peer, 0);
+ }
+
+ void reset() { // forcefully disconnect
+ release_data();
+ enet_peer_reset(peer);
+ }
+
+ bool send(uint8_t channel, ENetPacket* data) {
+ return enet_peer_send(peer, channel, data) == 0;
+ }
+
+ ConnectionData* data() {
+ return (ConnectionData*)enet_peer_get_data(peer);
+ }
+
+ void set_data(ConnectionData* dat) {
+ return enet_peer_set_data(peer, dat);
+ }
+
+ void release_data() {
+ delete data();
+ set_data(nullptr);
+ }
+ };
+
+ class ENetServer : public Default {
+ ENetHost* host;
+ public:
+
+ ENetServer(ProtocolInfo info) {
+ ENetAddress addr = info.getAddress();
+ host = enet_host_create(&addr, info.nconnections, info.nchannels,
+ 0, 0);
+ if (!host) {
+ throw std::runtime_error("Can't create server!");
+ }
+ HostDefaultConfig(host);
+ }
+
+ bool service(ENetEvent& ev, int timeout = 1) {
+ bool stat = enet_host_service(host, &ev, timeout) > 0;
+ if (stat && ev.type == ENET_EVENT_TYPE_CONNECT) {
+ enet_peer_set_data(ev.peer, nullptr); // we rely on this behaviour!
+ }
+ return stat;
+ }
+
+ ~ENetServer() {
+ enet_host_destroy(host);
+ }
+
+ bool is_valid() {
+ return host != nullptr;
+ }
+
+ void releaseEvent(ENetEvent& ev) {
+ if (ev.type == ENET_EVENT_TYPE_RECEIVE && ev.packet) {
+ enet_packet_destroy(ev.packet);
+ }
+ }
+
+ void broadcast(uint8_t channel, ENetPacket* data) {
+ if (host)
+ enet_host_broadcast(host, channel, data);
+ }
+
+ void foreach(std::function cb) {
+ if (!cb) return;
+ ENetPeer *currentPeer;
+ for (currentPeer = host->peers;
+ currentPeer < &host->peers[host->peerCount]; ++currentPeer) {
+ cb(currentPeer);
+ }
+ }
+
+ void flush() {
+ enet_host_flush(host);
+ }
+
+ /* shutdown sequence. Behaviour after this is not specified! */
+ void shutdown() {
+ // send disconnect
+ foreach([](ENetConnection c) {
+ c.disconnect();
+ });
+ enet_host_flush(host);
+
+ // queue
+ ENetEvent ev;
+ while (service(ev, 200)) {
+ switch (ev.type) {
+ case ENET_EVENT_TYPE_DISCONNECT:
+ case ENET_EVENT_TYPE_DISCONNECT_TIMEOUT: {
+ ENetConnection con(ev.peer);
+ con.release_data();
+ }; break;
+ case ENET_EVENT_TYPE_CONNECT:
+ enet_peer_disconnect_now(ev.peer, 0);
+ break;
+ case ENET_EVENT_TYPE_RECEIVE:
+ enet_packet_destroy(ev.packet);
+ break;
+ default:
+ break;
+ };
+ }
+
+ // force disconnect and free all data
+ foreach([](ENetConnection c) {
+ c.reset();
+ });
+
+ // now we can safely call destructor!
+ }
+ };
+
+};
+
diff --git a/game/main_client.cpp b/game/main_client.cpp
index 877bb60..9de3aac 100644
--- a/game/main_client.cpp
+++ b/game/main_client.cpp
@@ -28,6 +28,7 @@
#include "tools/tools.hpp"
#include "game/world_view.hpp"
+#include "engine/network.hpp"
namespace pb {
diff --git a/game/main_server.cpp b/game/main_server.cpp
index 82b801b..1ab82ca 100644
--- a/game/main_server.cpp
+++ b/game/main_server.cpp
@@ -26,6 +26,7 @@ namespace pb {
// used in main() function only anyway...
void main_server(std::vector argv) {
+
return;
}
};
\ No newline at end of file
diff --git a/game/server.hpp b/game/server.hpp
new file mode 100644
index 0000000..bbdfe5a
--- /dev/null
+++ b/game/server.hpp
@@ -0,0 +1,45 @@
+/*
+ * This file is a part of Pixelbox - Infinite 2D sandbox game
+ * Server setup logic
+ * Copyright (C) 2023-2024 UtoECat
+ *
+ * This program is free software: you can redistribute it and/or modify
+ * it under the terms of the GNU Affero General Public License as published by
+ * the Free Software Foundation, either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU Affero General Public License for more details.
+ *
+ * You should have received a copy of the GNU Affero General Public License
+ * along with this program. If not, see .
+ */
+
+#include
+#include
+#include "engine/network.hpp"
+#include "base.hpp"
+#include "engine/database.hpp"
+
+namespace pb {
+
+ class GamerServerBase {
+ protected:
+ std::unique_ptr server;
+ Database database;
+ public:
+ GamerServerBase(const char* db_file, int port, int max_cli = 1) {
+ // create server
+ server = std::make_unique(ProtocolInfo(NULL, port, 5, max_cli));
+ if (!db_file) {
+ std::cerr << "No file specified - in memory database is used for testing" << std::endl;
+ db_file = ":memory:";
+ }
+ database.open(db_file);
+ db::world_settings(database); // configure PRAGMA's for world storade db
+ }
+ };
+
+};
\ No newline at end of file