Added args and user replication
This commit is contained in:
parent
f98d577b89
commit
c8cafd00f8
9
.vscode/settings.json
vendored
Normal file
9
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
{
|
||||
"cmake.debugConfig": {
|
||||
"args": [
|
||||
"--single",
|
||||
"--port",
|
||||
"8080"
|
||||
]
|
||||
}
|
||||
}
|
||||
@ -1,9 +0,0 @@
|
||||
#include <deerith/network/router.h>
|
||||
#include "network/network_internals.h"
|
||||
|
||||
#include <deerith/packets/sync_world_tick.h>
|
||||
|
||||
void deerith::setup_base_protocols()
|
||||
{
|
||||
router_add_packet_processor<sync_world_tick_packet_t>();
|
||||
}
|
||||
@ -1,27 +1,36 @@
|
||||
#include <deerith/engine.h>
|
||||
#include <deerith/graphics/input.h>
|
||||
#include <deerith/network/router.h>
|
||||
|
||||
#include <deerith/world/character_sync_interface.h>
|
||||
#include <deerith/packets/sync_character_interface.h>
|
||||
#include <deerith/network/packets.h>
|
||||
#include <deerith/world/entity.h>
|
||||
|
||||
#include "world/world_internals.h"
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
extern character_sync_interface_t character_sync_interface;
|
||||
|
||||
}
|
||||
|
||||
void deerith::process_player_input()
|
||||
{
|
||||
if (self_entity == entt::null)
|
||||
return;
|
||||
glm::vec2 movment = get_joystick_axes(0, 0);
|
||||
character_sync_interface.move_input.push_value(movment);
|
||||
entity_sync_client_position_t &entity_sync_position = get_component<entity_sync_client_position_t>(self_entity);
|
||||
|
||||
entity_sync_position.move_input = movment;
|
||||
entity_sync_position.position = entity_sync_position.position.read_value() + movment * 0.1f;
|
||||
}
|
||||
|
||||
void deerith::send_player_input()
|
||||
{
|
||||
sync_character_interface_t sync_character_interface;
|
||||
sync_character_interface.load(character_sync_interface);
|
||||
if (self_entity == entt::null)
|
||||
return;
|
||||
entity_sync_client_position_t &entity_sync_position = get_component<entity_sync_client_position_t>(self_entity);
|
||||
|
||||
router_send_packet<sync_character_interface_t>(sync_character_interface, get_server_client());
|
||||
sync_entity_player_position_packet_t packet{};
|
||||
packet.input_transport.load(entity_sync_position.move_input);
|
||||
packet.position_transport.load(entity_sync_position.position);
|
||||
|
||||
router_send_packet(packet, get_server_client());
|
||||
}
|
||||
@ -5,9 +5,14 @@
|
||||
#include <deerith/world.h>
|
||||
|
||||
#include "world/world_internals.h"
|
||||
#include "network/network_internals.h"
|
||||
|
||||
namespace deerith
|
||||
void deerith::setup_base_protocols()
|
||||
{
|
||||
router_add_packet_processor<sync_world_tick_packet_t>();
|
||||
router_add_packet_processor<create_player_entity_packet_t>();
|
||||
router_add_packet_processor<create_entity_packet_t>();
|
||||
router_add_packet_processor<sync_entities_coordinates_packet_t>();
|
||||
}
|
||||
|
||||
template <>
|
||||
@ -22,4 +27,31 @@ void deerith::process_packet(deerith::create_player_entity_packet_t &packet, cli
|
||||
{
|
||||
self_entity = create_entity();
|
||||
add_component<entity_sync_client_position_t>(self_entity);
|
||||
}
|
||||
|
||||
template <>
|
||||
void deerith::process_packet(deerith::create_entity_packet_t &packet, client_t *client)
|
||||
{
|
||||
deerith_trace("creating entity with network id {}", packet.network_sync_id);
|
||||
|
||||
entity_t entity = create_entity();
|
||||
entity_network_id_t &entity_network_id = add_entity_network_with_id(entity, packet.network_sync_id);
|
||||
|
||||
if (packet.add_entity_sync_coordinates)
|
||||
{
|
||||
deerith_trace("-> adding entity sync coordinates to entity");
|
||||
entity_sync_coordinates_t &sync_coords = add_component<entity_sync_coordinates_t>(entity);
|
||||
}
|
||||
}
|
||||
|
||||
template <>
|
||||
void deerith::process_packet(deerith::sync_entities_coordinates_packet_t &packet, client_t *client)
|
||||
{
|
||||
for (int i = 0; i < packet.entities_ids.size(); i++)
|
||||
{
|
||||
entity_t entity = get_network_entity_with_id(packet.entities_ids[i]);
|
||||
entity_sync_coordinates_t &sync_coords = get_component<entity_sync_coordinates_t>(entity);
|
||||
|
||||
packet.positions_to_update[i].recive(sync_coords.position);
|
||||
}
|
||||
}
|
||||
@ -1,5 +0,0 @@
|
||||
#include <deerith/world.h>
|
||||
|
||||
void deerith::render_world()
|
||||
{
|
||||
}
|
||||
@ -1,5 +1,20 @@
|
||||
#include <deerith/world.h>
|
||||
#include <deerith/world/entity.h>
|
||||
|
||||
#include <deerith/graphics/primitive.h>
|
||||
|
||||
void deerith::render_world()
|
||||
{
|
||||
define_primitive_viewspace(glm::vec2(-10, -10), glm::vec2(10, 10));
|
||||
|
||||
auto entities_view = get_entity_registry().view<entity_sync_coordinates_t>();
|
||||
for (auto [entity, sync_coords] : entities_view.each())
|
||||
{
|
||||
glm::vec2 chords;
|
||||
if (sync_coords.position.read_synced(chords))
|
||||
{
|
||||
define_primitive_color(glm::vec4(1, 1, 1, 1));
|
||||
draw_primitive_rectangle(chords - glm::vec2(0.5f, 0.5f), chords + glm::vec2(0.5f, 0.5f));
|
||||
}
|
||||
}
|
||||
}
|
||||
485
deerith_engine_core/include/args/argh.h
Normal file
485
deerith_engine_core/include/args/argh.h
Normal file
@ -0,0 +1,485 @@
|
||||
#pragma once
|
||||
|
||||
#include <algorithm>
|
||||
#include <sstream>
|
||||
#include <limits>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <set>
|
||||
#include <map>
|
||||
#include <cassert>
|
||||
|
||||
namespace argh
|
||||
{
|
||||
// Terminology:
|
||||
// A command line is composed of 2 types of args:
|
||||
// 1. Positional args, i.e. free standing values
|
||||
// 2. Options: args beginning with '-'. We identify two kinds:
|
||||
// 2.1: Flags: boolean options => (exist ? true : false)
|
||||
// 2.2: Parameters: a name followed by a non-option value
|
||||
|
||||
#if !defined(__GNUC__) || (__GNUC__ >= 5)
|
||||
using string_stream = std::istringstream;
|
||||
#else
|
||||
// Until GCC 5, istringstream did not have a move constructor.
|
||||
// stringstream_proxy is used instead, as a workaround.
|
||||
class stringstream_proxy
|
||||
{
|
||||
public:
|
||||
stringstream_proxy() = default;
|
||||
|
||||
// Construct with a value.
|
||||
stringstream_proxy(std::string const& value) :
|
||||
stream_(value)
|
||||
{}
|
||||
|
||||
// Copy constructor.
|
||||
stringstream_proxy(const stringstream_proxy& other) :
|
||||
stream_(other.stream_.str())
|
||||
{
|
||||
stream_.setstate(other.stream_.rdstate());
|
||||
}
|
||||
|
||||
void setstate(std::ios_base::iostate state) { stream_.setstate(state); }
|
||||
|
||||
// Stream out the value of the parameter.
|
||||
// If the conversion was not possible, the stream will enter the fail state,
|
||||
// and operator bool will return false.
|
||||
template<typename T>
|
||||
stringstream_proxy& operator >> (T& thing)
|
||||
{
|
||||
stream_ >> thing;
|
||||
return *this;
|
||||
}
|
||||
|
||||
|
||||
// Get the string value.
|
||||
std::string str() const { return stream_.str(); }
|
||||
|
||||
std::stringbuf* rdbuf() const { return stream_.rdbuf(); }
|
||||
|
||||
// Check the state of the stream.
|
||||
// False when the most recent stream operation failed
|
||||
explicit operator bool() const { return !!stream_; }
|
||||
|
||||
~stringstream_proxy() = default;
|
||||
private:
|
||||
std::istringstream stream_;
|
||||
};
|
||||
using string_stream = stringstream_proxy;
|
||||
#endif
|
||||
|
||||
class multimap_iteration_wrapper
|
||||
{
|
||||
public:
|
||||
using container_t = std::multimap<std::string, std::string>;
|
||||
using iterator_t = container_t::const_iterator;
|
||||
using difference_t = container_t::difference_type;
|
||||
explicit multimap_iteration_wrapper(const iterator_t& lb, const iterator_t& ub)
|
||||
: lb_(lb)
|
||||
, ub_(ub)
|
||||
{}
|
||||
|
||||
iterator_t begin() const { return lb_; }
|
||||
iterator_t end() const { return ub_; }
|
||||
difference_t size() const { return std::distance(lb_, ub_); }
|
||||
|
||||
private:
|
||||
iterator_t lb_;
|
||||
iterator_t ub_;
|
||||
};
|
||||
|
||||
class parser
|
||||
{
|
||||
public:
|
||||
enum Mode { PREFER_FLAG_FOR_UNREG_OPTION = 1 << 0,
|
||||
PREFER_PARAM_FOR_UNREG_OPTION = 1 << 1,
|
||||
NO_SPLIT_ON_EQUALSIGN = 1 << 2,
|
||||
SINGLE_DASH_IS_MULTIFLAG = 1 << 3,
|
||||
};
|
||||
|
||||
parser() = default;
|
||||
|
||||
parser(std::initializer_list<char const* const> pre_reg_names)
|
||||
{ add_params(pre_reg_names); }
|
||||
|
||||
parser(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argv, mode); }
|
||||
|
||||
parser(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
{ parse(argc, argv, mode); }
|
||||
|
||||
void add_param(std::string const& name);
|
||||
void add_params(std::string const& name);
|
||||
|
||||
void add_param(std::initializer_list<char const* const> init_list);
|
||||
void add_params(std::initializer_list<char const* const> init_list);
|
||||
|
||||
void parse(const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
void parse(int argc, const char* const argv[], int mode = PREFER_FLAG_FOR_UNREG_OPTION);
|
||||
|
||||
std::multiset<std::string> const& flags() const { return flags_; }
|
||||
std::multimap<std::string, std::string> const& params() const { return params_; }
|
||||
multimap_iteration_wrapper params(std::string const& name) const;
|
||||
std::vector<std::string> const& pos_args() const { return pos_args_; }
|
||||
|
||||
// begin() and end() for using range-for over positional args.
|
||||
std::vector<std::string>::const_iterator begin() const { return pos_args_.cbegin(); }
|
||||
std::vector<std::string>::const_iterator end() const { return pos_args_.cend(); }
|
||||
size_t size() const { return pos_args_.size(); }
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
// Accessors
|
||||
|
||||
// flag (boolean) accessors: return true if the flag appeared, otherwise false.
|
||||
bool operator[](std::string const& name) const;
|
||||
|
||||
// multiple flag (boolean) accessors: return true if at least one of the flag appeared, otherwise false.
|
||||
bool operator[](std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// returns positional arg string by order. Like argv[] but without the options
|
||||
std::string const& operator[](size_t ind) const;
|
||||
|
||||
// returns a std::istream that can be used to convert a positional arg to a typed value.
|
||||
string_stream operator()(size_t ind) const;
|
||||
|
||||
// same as above, but with a default value in case the arg is missing (index out of range).
|
||||
template<typename T>
|
||||
string_stream operator()(size_t ind, T&& def_val) const;
|
||||
|
||||
// parameter accessors, give a name get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
string_stream operator()(std::string const& name) const;
|
||||
|
||||
// accessor for a parameter with multiple names, give a list of names, get an std::istream that can be used to convert to a typed value.
|
||||
// call .str() on result to get as string
|
||||
// returns the first value in the list to be found.
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list) const;
|
||||
|
||||
// same as above, but with a default value in case the param was missing.
|
||||
// Non-string def_val types must have an operator<<() (output stream operator)
|
||||
// If T only has an input stream operator, pass the string version of the type as in "3" instead of 3.
|
||||
template<typename T>
|
||||
string_stream operator()(std::string const& name, T&& def_val) const;
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream operator()(std::initializer_list<char const* const> init_list, T&& def_val) const;
|
||||
|
||||
private:
|
||||
string_stream bad_stream() const;
|
||||
std::string trim_leading_dashes(std::string const& name) const;
|
||||
bool is_number(std::string const& arg) const;
|
||||
bool is_option(std::string const& arg) const;
|
||||
bool got_flag(std::string const& name) const;
|
||||
bool is_param(std::string const& name) const;
|
||||
|
||||
private:
|
||||
std::vector<std::string> args_;
|
||||
std::multimap<std::string, std::string> params_;
|
||||
std::vector<std::string> pos_args_;
|
||||
std::multiset<std::string> flags_;
|
||||
std::set<std::string> registeredParams_;
|
||||
std::string empty_;
|
||||
};
|
||||
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(const char * const argv[], int mode)
|
||||
{
|
||||
int argc = 0;
|
||||
for (auto argvp = argv; *argvp; ++argc, ++argvp);
|
||||
parse(argc, argv, mode);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::parse(int argc, const char* const argv[], int mode /*= PREFER_FLAG_FOR_UNREG_OPTION*/)
|
||||
{
|
||||
// clear out possible previous parsing remnants
|
||||
flags_.clear();
|
||||
params_.clear();
|
||||
pos_args_.clear();
|
||||
|
||||
// convert to strings
|
||||
args_.resize(static_cast<decltype(args_)::size_type>(argc));
|
||||
std::transform(argv, argv + argc, args_.begin(), [](const char* const arg) { return arg; });
|
||||
|
||||
// parse line
|
||||
for (auto i = 0u; i < args_.size(); ++i)
|
||||
{
|
||||
if (!is_option(args_[i]))
|
||||
{
|
||||
pos_args_.emplace_back(args_[i]);
|
||||
continue;
|
||||
}
|
||||
|
||||
auto name = trim_leading_dashes(args_[i]);
|
||||
|
||||
if (!(mode & NO_SPLIT_ON_EQUALSIGN))
|
||||
{
|
||||
auto equalPos = name.find('=');
|
||||
if (equalPos != std::string::npos)
|
||||
{
|
||||
params_.insert({ name.substr(0, equalPos), name.substr(equalPos + 1) });
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// if the option is unregistered and should be a multi-flag
|
||||
if (1 == (args_[i].size() - name.size()) && // single dash
|
||||
argh::parser::SINGLE_DASH_IS_MULTIFLAG & mode && // multi-flag mode
|
||||
!is_param(name)) // unregistered
|
||||
{
|
||||
std::string keep_param;
|
||||
|
||||
if (!name.empty() && is_param(std::string(1ul, name.back()))) // last char is param
|
||||
{
|
||||
keep_param += name.back();
|
||||
name.resize(name.size() - 1);
|
||||
}
|
||||
|
||||
for (auto const& c : name)
|
||||
{
|
||||
flags_.emplace(std::string{ c });
|
||||
}
|
||||
|
||||
if (!keep_param.empty())
|
||||
{
|
||||
name = keep_param;
|
||||
}
|
||||
else
|
||||
{
|
||||
continue; // do not consider other options for this arg
|
||||
}
|
||||
}
|
||||
|
||||
// any potential option will get as its value the next arg, unless that arg is an option too
|
||||
// in that case it will be determined a flag.
|
||||
if (i == args_.size() - 1 || is_option(args_[i + 1]))
|
||||
{
|
||||
flags_.emplace(name);
|
||||
continue;
|
||||
}
|
||||
|
||||
// if 'name' is a pre-registered option, then the next arg cannot be a free parameter to it is skipped
|
||||
// otherwise we have 2 modes:
|
||||
// PREFER_FLAG_FOR_UNREG_OPTION: a non-registered 'name' is determined a flag.
|
||||
// The following value (the next arg) will be a free parameter.
|
||||
//
|
||||
// PREFER_PARAM_FOR_UNREG_OPTION: a non-registered 'name' is determined a parameter, the next arg
|
||||
// will be the value of that option.
|
||||
|
||||
assert(!(mode & argh::parser::PREFER_FLAG_FOR_UNREG_OPTION)
|
||||
|| !(mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION));
|
||||
|
||||
bool preferParam = mode & argh::parser::PREFER_PARAM_FOR_UNREG_OPTION;
|
||||
|
||||
if (is_param(name) || preferParam)
|
||||
{
|
||||
params_.insert({ name, args_[i + 1] });
|
||||
++i; // skip next value, it is not a free parameter
|
||||
continue;
|
||||
}
|
||||
else
|
||||
{
|
||||
flags_.emplace(name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::bad_stream() const
|
||||
{
|
||||
string_stream bad;
|
||||
bad.setstate(std::ios_base::failbit);
|
||||
return bad;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_number(std::string const& arg) const
|
||||
{
|
||||
// inefficient but simple way to determine if a string is a number (which can start with a '-')
|
||||
std::istringstream istr(arg);
|
||||
double number;
|
||||
istr >> number;
|
||||
return !(istr.fail() || istr.bad());
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::is_option(std::string const& arg) const
|
||||
{
|
||||
assert(0 != arg.size());
|
||||
if (is_number(arg))
|
||||
return false;
|
||||
return '-' == arg[0];
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string parser::trim_leading_dashes(std::string const& name) const
|
||||
{
|
||||
auto pos = name.find_first_not_of('-');
|
||||
return std::string::npos != pos ? name.substr(pos) : name;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::got_flag(std::string const& name) const
|
||||
{
|
||||
return flags_.end() != flags_.find(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool argh::parser::is_param(std::string const& name) const
|
||||
{
|
||||
return registeredParams_.count(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::string const& name) const
|
||||
{
|
||||
return got_flag(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline bool parser::operator[](std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
return std::any_of(init_list.begin(), init_list.end(), [&](char const* const name) { return got_flag(name); });
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline std::string const& parser::operator[](size_t ind) const
|
||||
{
|
||||
if (ind < pos_args_.size())
|
||||
return pos_args_[ind];
|
||||
return empty_;
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::string const& name) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(std::initializer_list<char const* const> init_list) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
return bad_stream();
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::string const& name, T&& def_val) const
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
// same as above but for a list of names. returns the first value to be found.
|
||||
template<typename T>
|
||||
string_stream parser::operator()(std::initializer_list<char const* const> init_list, T&& def_val) const
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
{
|
||||
auto optIt = params_.find(trim_leading_dashes(name));
|
||||
if (params_.end() != optIt)
|
||||
return string_stream(optIt->second);
|
||||
}
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str()); // use default
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline string_stream parser::operator()(size_t ind) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
return bad_stream();
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template<typename T>
|
||||
string_stream parser::operator()(size_t ind, T&& def_val) const
|
||||
{
|
||||
if (pos_args_.size() <= ind)
|
||||
{
|
||||
std::ostringstream ostr;
|
||||
ostr.precision(std::numeric_limits<long double>::max_digits10);
|
||||
ostr << def_val;
|
||||
return string_stream(ostr.str());
|
||||
}
|
||||
|
||||
return string_stream(pos_args_[ind]);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_param(std::string const& name)
|
||||
{
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_param(std::initializer_list<const char *const> init_list)
|
||||
{
|
||||
parser::add_params(init_list);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_params(std::initializer_list<char const* const> init_list)
|
||||
{
|
||||
for (auto& name : init_list)
|
||||
registeredParams_.insert(trim_leading_dashes(name));
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline void parser::add_params(const std::string &name)
|
||||
{
|
||||
parser::add_param(name);
|
||||
}
|
||||
|
||||
//////////////////////////////////////////////////////////////////////////
|
||||
|
||||
inline multimap_iteration_wrapper parser::params(std::string const& name) const
|
||||
{
|
||||
auto trimmed_name = trim_leading_dashes(name);
|
||||
return multimap_iteration_wrapper(params_.lower_bound(trimmed_name), params_.upper_bound(trimmed_name));
|
||||
}
|
||||
}
|
||||
@ -10,6 +10,8 @@
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
using id_t = uint32_t;
|
||||
|
||||
void init_engine();
|
||||
void shutdown_engine();
|
||||
|
||||
|
||||
@ -1,5 +1,8 @@
|
||||
#pragma once
|
||||
#include <deerith/engine.h>
|
||||
#include <deerith/world/entity.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
@ -22,4 +25,52 @@ namespace deerith
|
||||
static constexpr uint16_t packet_id = 2;
|
||||
static constexpr bool reliable = true;
|
||||
};
|
||||
|
||||
struct sync_entity_player_position_packet_t
|
||||
{
|
||||
static constexpr uint16_t packet_id = 3;
|
||||
static constexpr bool reliable = false;
|
||||
|
||||
sync_variable_transport_t<glm::vec2> position_transport;
|
||||
sync_variable_transport_t<glm::vec2> input_transport;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(position_transport);
|
||||
archive(input_transport);
|
||||
}
|
||||
};
|
||||
|
||||
struct create_entity_packet_t
|
||||
{
|
||||
static constexpr uint16_t packet_id = 4;
|
||||
static constexpr bool reliable = true;
|
||||
|
||||
id_t network_sync_id;
|
||||
bool add_entity_sync_coordinates;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(network_sync_id);
|
||||
archive(add_entity_sync_coordinates);
|
||||
}
|
||||
};
|
||||
|
||||
struct sync_entities_coordinates_packet_t
|
||||
{
|
||||
static constexpr uint16_t packet_id = 5;
|
||||
static constexpr bool reliable = false;
|
||||
|
||||
std::vector<id_t> entities_ids;
|
||||
std::vector<sync_variable_transport_t<glm::vec2>> positions_to_update;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(entities_ids);
|
||||
archive(positions_to_update);
|
||||
}
|
||||
};
|
||||
}
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
#include <cereal/cereal.hpp>
|
||||
#include <cereal/archives/portable_binary.hpp>
|
||||
#include <cereal/types/array.hpp>
|
||||
#include <cereal/types/vector.hpp>
|
||||
|
||||
#include <enet/enet.h>
|
||||
|
||||
|
||||
@ -1,9 +1,11 @@
|
||||
#pragma once
|
||||
#include <deerith/engine.h>
|
||||
#include <deerith/world.h>
|
||||
|
||||
#include <glm/glm.hpp>
|
||||
#include <deerith/engine.h>
|
||||
#include <deerith/world/world_core.h>
|
||||
|
||||
#include <algorithm>
|
||||
#include <array>
|
||||
#include <cstdint>
|
||||
|
||||
#include <cereal/types/array.hpp>
|
||||
#include <deerith/core/serialization_ext.h>
|
||||
@ -13,98 +15,195 @@
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
inline size_t get_sync_variable_index(size_t tick = get_world_tick())
|
||||
{
|
||||
return ((size_t)tick) % BUFFER_SIZE;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct sync_variable_transport_t;
|
||||
|
||||
template <typename T>
|
||||
struct sync_variable_entry_t
|
||||
{
|
||||
T value;
|
||||
int tick_id = 0;
|
||||
T value{};
|
||||
uint32_t tick_id = 0;
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(value);
|
||||
archive(tick_id);
|
||||
}
|
||||
void serialize(Archive &archive);
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
class sync_variable_t
|
||||
{
|
||||
public:
|
||||
T pull_value()
|
||||
{
|
||||
sync_variable_entry_t<T> &entry = buffer[get_sync_variable_index()];
|
||||
if (entry.tick_id != get_world_tick())
|
||||
{
|
||||
return T();
|
||||
}
|
||||
return entry.value;
|
||||
}
|
||||
T read_value() const;
|
||||
operator T() const;
|
||||
|
||||
void push_value(const T &v)
|
||||
{
|
||||
set_value(v, get_world_tick() + NETWORK_DELAY);
|
||||
}
|
||||
bool read_synced(T &value) const;
|
||||
|
||||
void set_value(const T &v, int tick_id = 0)
|
||||
{
|
||||
if (tick_id > get_world_tick() + SYNC_VARIABLE_STORAGE)
|
||||
{
|
||||
deerith_error("set_value error, tick_id > get_world_tick() + SYNC_VARIABLE_STORAGE, tick_id : {}", tick_id);
|
||||
return;
|
||||
}
|
||||
sync_variable_entry_t<T> &entry = buffer[get_sync_variable_index(tick_id)];
|
||||
entry.tick_id = tick_id;
|
||||
entry.value = v;
|
||||
}
|
||||
sync_variable_t &operator=(const T &value);
|
||||
|
||||
private:
|
||||
std::array<sync_variable_entry_t<T>, BUFFER_SIZE> buffer;
|
||||
friend sync_variable_transport_t<T>;
|
||||
protected:
|
||||
void assign_value(const T &value);
|
||||
void receive_entry(const sync_variable_entry_t<T> &entry);
|
||||
void backfill();
|
||||
|
||||
sync_variable_entry_t<T> last_assigned_value{};
|
||||
std::array<sync_variable_entry_t<T>, BUFFER_SIZE> buffer{};
|
||||
|
||||
template <typename U>
|
||||
friend struct sync_variable_transport_t;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
struct sync_variable_transport_t
|
||||
{
|
||||
std::array<sync_variable_entry_t<T>, NETWORK_DELAY> variable_transport_data;
|
||||
std::array<sync_variable_entry_t<T>, NETWORK_DELAY> variable_transport_data{};
|
||||
|
||||
void load(const sync_variable_t<T> &sync_var)
|
||||
{
|
||||
int begin_tick_id = get_world_tick();
|
||||
|
||||
for (int i = 0; i < NETWORK_DELAY; i++)
|
||||
{
|
||||
variable_transport_data[i] =
|
||||
sync_var.buffer[get_sync_variable_index(i + begin_tick_id)];
|
||||
}
|
||||
}
|
||||
|
||||
void dipose(sync_variable_t<T> &sync_var)
|
||||
{
|
||||
int begin_tick_id = get_world_tick();
|
||||
for (int i = 0; i < NETWORK_DELAY; i++)
|
||||
{
|
||||
const sync_variable_entry_t<T> &entry = variable_transport_data[i];
|
||||
if (entry.tick_id < begin_tick_id || entry.tick_id >= begin_tick_id + NETWORK_DELAY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
sync_var.buffer[get_sync_variable_index(entry.tick_id)] = entry;
|
||||
}
|
||||
}
|
||||
void load(const sync_variable_t<T> &sync_var);
|
||||
void recive(sync_variable_t<T> &sync_var);
|
||||
|
||||
template <typename Archive>
|
||||
void serialize(Archive &archive)
|
||||
{
|
||||
archive(variable_transport_data);
|
||||
}
|
||||
void serialize(Archive &archive);
|
||||
};
|
||||
}
|
||||
|
||||
inline size_t get_sync_variable_index(uint32_t tick)
|
||||
{
|
||||
return static_cast<size_t>(tick) % BUFFER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
// ============================================================================
|
||||
// Implementations
|
||||
// ============================================================================
|
||||
|
||||
template <typename T>
|
||||
template <typename Archive>
|
||||
void deerith::sync_variable_entry_t<T>::serialize(Archive &archive)
|
||||
{
|
||||
archive(value, tick_id);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T deerith::sync_variable_t<T>::read_value() const
|
||||
{
|
||||
return static_cast<T>(*this);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
deerith::sync_variable_t<T>::operator T() const
|
||||
{
|
||||
const uint32_t tick = get_world_tick() + NETWORK_DELAY;
|
||||
const auto &entry = buffer[get_sync_variable_index(tick)];
|
||||
|
||||
if (entry.tick_id == tick)
|
||||
{
|
||||
return entry.value;
|
||||
}
|
||||
|
||||
return last_assigned_value.value;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
deerith::sync_variable_t<T> &deerith::sync_variable_t<T>::operator=(const T &value)
|
||||
{
|
||||
this->assign_value(value);
|
||||
return *this;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deerith::sync_variable_t<T>::assign_value(const T &value)
|
||||
{
|
||||
backfill();
|
||||
|
||||
const uint32_t tick = get_world_tick() + NETWORK_DELAY;
|
||||
auto &entry = buffer[get_sync_variable_index(tick)];
|
||||
|
||||
entry.value = value;
|
||||
entry.tick_id = tick;
|
||||
|
||||
last_assigned_value = entry;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deerith::sync_variable_t<T>::receive_entry(const sync_variable_entry_t<T> &entry)
|
||||
{
|
||||
const uint32_t current_tick = get_world_tick();
|
||||
|
||||
if (entry.tick_id < current_tick || entry.tick_id >= current_tick + NETWORK_DELAY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
buffer[get_sync_variable_index(entry.tick_id)] = entry;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deerith::sync_variable_t<T>::backfill()
|
||||
{
|
||||
const uint32_t current_tick = get_world_tick();
|
||||
|
||||
if (last_assigned_value.tick_id == 0 || last_assigned_value.tick_id >= current_tick + NETWORK_DELAY)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
const uint32_t start_tick = std::max(
|
||||
last_assigned_value.tick_id,
|
||||
current_tick > 0 ? current_tick - 1 : 0);
|
||||
|
||||
const T previous_value = last_assigned_value.value;
|
||||
|
||||
for (uint32_t tick = start_tick; tick < current_tick + NETWORK_DELAY; ++tick)
|
||||
{
|
||||
auto &entry = buffer[get_sync_variable_index(tick)];
|
||||
|
||||
entry.value = previous_value;
|
||||
entry.tick_id = tick;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool deerith::sync_variable_t<T>::read_synced(T &value) const
|
||||
{
|
||||
const uint32_t tick = get_world_tick();
|
||||
const auto &entry = buffer[get_sync_variable_index(tick)];
|
||||
|
||||
if (entry.tick_id != tick)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
value = entry.value;
|
||||
return true;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deerith::sync_variable_transport_t<T>::load(const sync_variable_t<T> &sync_var)
|
||||
{
|
||||
const uint32_t begin_tick_id = get_world_tick();
|
||||
|
||||
for (int i = 0; i < NETWORK_DELAY; ++i)
|
||||
{
|
||||
variable_transport_data[i] =
|
||||
sync_var.buffer[get_sync_variable_index(i + begin_tick_id)];
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void deerith::sync_variable_transport_t<T>::recive(sync_variable_t<T> &sync_var)
|
||||
{
|
||||
const uint32_t begin_tick_id = get_world_tick();
|
||||
|
||||
for (int i = 0; i < NETWORK_DELAY; ++i)
|
||||
{
|
||||
const sync_variable_entry_t<T> &entry = variable_transport_data[i];
|
||||
|
||||
if (entry.tick_id < begin_tick_id || entry.tick_id >= begin_tick_id + NETWORK_DELAY)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
sync_var.buffer[get_sync_variable_index(entry.tick_id)] = entry;
|
||||
}
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
template <typename Archive>
|
||||
void deerith::sync_variable_transport_t<T>::serialize(Archive &archive)
|
||||
{
|
||||
archive(variable_transport_data);
|
||||
}
|
||||
|
||||
@ -10,10 +10,20 @@ namespace deerith
|
||||
client_t *client = nullptr;
|
||||
};
|
||||
|
||||
struct entity_network_id_t
|
||||
{
|
||||
id_t network_id;
|
||||
};
|
||||
|
||||
// struct for linking a entity to a client
|
||||
struct entity_sync_client_position_t
|
||||
{
|
||||
sync_variable_t<glm::vec2> move_input;
|
||||
sync_variable_t<glm::vec2> position;
|
||||
};
|
||||
|
||||
struct entity_sync_coordinates_t
|
||||
{
|
||||
sync_variable_t<glm::vec2> position;
|
||||
};
|
||||
}
|
||||
@ -4,6 +4,8 @@
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
struct entity_network_id_t;
|
||||
|
||||
using entity_registry_t = entt::registry;
|
||||
using entity_t = entt::entity;
|
||||
|
||||
@ -12,18 +14,28 @@ namespace deerith
|
||||
|
||||
void set_tick(uint32_t);
|
||||
|
||||
entity_registry_t &get_entity_registry_t();
|
||||
inline entity_t create_entity() { return get_entity_registry_t().create(); }
|
||||
entity_registry_t &get_entity_registry();
|
||||
inline entity_t create_entity() { return get_entity_registry().create(); }
|
||||
|
||||
template <typename T>
|
||||
T &add_component(entity_t ent)
|
||||
{
|
||||
return get_entity_registry_t().emplace<T>(ent);
|
||||
return get_entity_registry().emplace<T>(ent);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
T &get_component(entity_t ent)
|
||||
{
|
||||
return get_entity_registry_t().get<T>(ent);
|
||||
return get_entity_registry().get<T>(ent);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
bool has_component(entity_t ent)
|
||||
{
|
||||
return get_entity_registry().all_of<T>(ent);
|
||||
}
|
||||
|
||||
entity_network_id_t &add_entity_network_id(entity_t ent);
|
||||
entity_network_id_t &add_entity_network_with_id(entity_t ent, id_t id);
|
||||
entity_t get_network_entity_with_id(id_t id);
|
||||
}
|
||||
|
||||
@ -1,11 +1,45 @@
|
||||
#include <deerith/world/world_core.h>
|
||||
#include <deerith/world/entity.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
id_t sequential_network_id = 1;
|
||||
std::unordered_map<uint32_t, entity_t> network_entities;
|
||||
entity_registry_t entity_registry;
|
||||
}
|
||||
|
||||
entt::registry &deerith::get_entity_registry_t()
|
||||
entt::registry &deerith::get_entity_registry()
|
||||
{
|
||||
return entity_registry;
|
||||
}
|
||||
|
||||
deerith::entity_network_id_t &deerith::add_entity_network_id(entity_t ent)
|
||||
{
|
||||
while (network_entities.contains(sequential_network_id))
|
||||
{
|
||||
sequential_network_id++;
|
||||
}
|
||||
|
||||
entity_network_id_t &network_id = add_component<entity_network_id_t>(ent);
|
||||
network_id.network_id = sequential_network_id;
|
||||
network_entities[sequential_network_id] = ent;
|
||||
|
||||
sequential_network_id++;
|
||||
return network_id;
|
||||
}
|
||||
|
||||
deerith::entity_network_id_t &deerith::add_entity_network_with_id(entity_t ent, id_t id)
|
||||
{
|
||||
entity_network_id_t &network_id = add_component<entity_network_id_t>(ent);
|
||||
network_id.network_id = id;
|
||||
network_entities[id] = ent;
|
||||
|
||||
return network_id;
|
||||
}
|
||||
|
||||
deerith::entity_t deerith::get_network_entity_with_id(id_t id)
|
||||
{
|
||||
return network_entities[id];
|
||||
}
|
||||
@ -1,9 +1,9 @@
|
||||
#include "network/network_internals.h"
|
||||
#include <deerith/network/router.h>
|
||||
|
||||
#include <deerith/packets/sync_character_interface.h>
|
||||
#include <deerith/network/packets.h>
|
||||
|
||||
void deerith::load_base_protocols()
|
||||
{
|
||||
router_add_packet_processor<sync_character_interface_t>();
|
||||
router_add_packet_processor<sync_entity_player_position_packet_t>();
|
||||
}
|
||||
@ -1,7 +1,7 @@
|
||||
#include <deerith/core/log.h>
|
||||
#include <deerith/network/client.h>
|
||||
#include <deerith/network/router.h>
|
||||
#include <deerith/packets/sync_world_tick.h>
|
||||
#include <deerith/network/packets.h>
|
||||
|
||||
#include <deerith/world.h>
|
||||
|
||||
|
||||
@ -1,7 +1,12 @@
|
||||
#include <deerith/engine.h>
|
||||
|
||||
#include <deerith/packets/sync_character_interface.h>
|
||||
#include <deerith/world.h>
|
||||
#include <deerith/world/entity.h>
|
||||
#include <deerith/network/packets.h>
|
||||
#include <deerith/network/router.h>
|
||||
#include <deerith/network/client.h>
|
||||
|
||||
#include "network/network_internals.h"
|
||||
#include "world/world_internals.h"
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
@ -9,7 +14,55 @@ namespace deerith
|
||||
}
|
||||
|
||||
template <>
|
||||
void deerith::process_packet(sync_character_interface_t &interface, client_t *client)
|
||||
void deerith::process_packet(sync_entity_player_position_packet_t &packet, client_t *client)
|
||||
{
|
||||
deerith_trace("sync player input {} {}");
|
||||
entity_t entity = client->entity_id;
|
||||
entity_sync_client_position_t &sync_client = get_component<entity_sync_client_position_t>(entity);
|
||||
|
||||
packet.input_transport.recive(sync_client.move_input);
|
||||
packet.position_transport.recive(sync_client.position);
|
||||
}
|
||||
|
||||
void deerith::client_connects(client_t *client)
|
||||
{
|
||||
// sync world tick
|
||||
sync_world_tick_packet_t sync_world_tick;
|
||||
sync_world_tick.tick_id = get_world_tick();
|
||||
router_send_packet(sync_world_tick, client);
|
||||
|
||||
// create entity player entity
|
||||
entity_t entity = create_entity();
|
||||
entity_link_to_client_t &link = add_component<entity_link_to_client_t>(entity);
|
||||
entity_sync_client_position_t &position_sync = add_component<entity_sync_client_position_t>(entity);
|
||||
|
||||
create_player_entity_packet_t create_player_entity;
|
||||
router_send_packet(create_player_entity, client);
|
||||
|
||||
link.client = client;
|
||||
client->entity_id = entity;
|
||||
|
||||
// create the server representation of the entity
|
||||
add_entity_network_id(entity);
|
||||
add_component<entity_sync_coordinates_t>(entity);
|
||||
|
||||
send_create_entity_to_all_clients(entity);
|
||||
}
|
||||
|
||||
void deerith::send_create_entity_to_all_clients(deerith::entity_t ent)
|
||||
{
|
||||
entity_network_id_t &entity_network_id = get_component<entity_network_id_t>(ent);
|
||||
|
||||
create_entity_packet_t create_entity;
|
||||
create_entity.network_sync_id = entity_network_id.network_id;
|
||||
|
||||
if (has_component<entity_link_to_client_t>(ent))
|
||||
{
|
||||
create_entity.add_entity_sync_coordinates = true;
|
||||
}
|
||||
|
||||
auto view = get_entity_registry().view<entity_link_to_client_t>();
|
||||
for (auto [entity, link_to_client] : view.each())
|
||||
{
|
||||
router_send_packet(create_entity, link_to_client.client);
|
||||
}
|
||||
}
|
||||
@ -6,7 +6,7 @@
|
||||
#include "world/world_internals.h"
|
||||
|
||||
#include <deerith/world/entity.h>
|
||||
#include <deerith/packets.h>
|
||||
#include <deerith/network/packets.h>
|
||||
|
||||
#include <csignal>
|
||||
#include <atomic>
|
||||
@ -51,24 +51,12 @@ void deerith::world_simulation()
|
||||
flush_network_events();
|
||||
|
||||
// process movments
|
||||
update_players_characters();
|
||||
|
||||
if (get_world_tick() % 2 == 0)
|
||||
{
|
||||
send_entity_data();
|
||||
}
|
||||
|
||||
wait_till_next_tick();
|
||||
}
|
||||
|
||||
void deerith::client_connects(client_t *client)
|
||||
{
|
||||
sync_world_tick_packet_t sync_world_tick;
|
||||
sync_world_tick.tick_id = get_world_tick();
|
||||
|
||||
create_player_entity_packet_t create_player_entity;
|
||||
|
||||
router_send_packet(sync_world_tick, client);
|
||||
router_send_packet(create_player_entity, client);
|
||||
|
||||
entity_t entity = create_entity();
|
||||
entity_link_to_client_t &link = add_component<entity_link_to_client_t>(entity);
|
||||
entity_sync_client_position_t &position_sync = add_component<entity_sync_client_position_t>(entity);
|
||||
|
||||
link.client = client;
|
||||
client->entity_id = entity;
|
||||
}
|
||||
@ -1,8 +1,13 @@
|
||||
#pragma once
|
||||
#include <deerith/network/client.h>
|
||||
#include <deerith/world/entity.h>
|
||||
|
||||
namespace deerith
|
||||
{
|
||||
void update_players_characters();
|
||||
void client_connects(client_t *client);
|
||||
|
||||
void send_entity_data();
|
||||
|
||||
void send_create_entity_to_all_clients(entity_t ent);
|
||||
}
|
||||
@ -1,5 +1,44 @@
|
||||
#include "world/world_internals.h"
|
||||
|
||||
void update_players_characters()
|
||||
#include <deerith/world.h>
|
||||
#include <deerith/world/entity.h>
|
||||
#include <deerith/network/packets.h>
|
||||
#include <deerith/network/router.h>
|
||||
|
||||
void deerith::update_players_characters()
|
||||
{
|
||||
auto view = get_entity_registry().view<entity_sync_client_position_t, entity_link_to_client_t, entity_sync_coordinates_t>();
|
||||
|
||||
for (auto [entity, position_input, client, sync_coords] : view.each())
|
||||
{
|
||||
glm::vec2 ps{};
|
||||
if (position_input.position.read_synced(ps))
|
||||
{
|
||||
sync_coords.position = ps;
|
||||
}
|
||||
else
|
||||
{
|
||||
sync_coords.position = sync_coords.position;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void deerith::send_entity_data()
|
||||
{
|
||||
sync_entities_coordinates_packet_t sync_entities_coordinates;
|
||||
|
||||
auto coordinates_view = get_entity_registry().view<entity_network_id_t, entity_sync_coordinates_t>();
|
||||
for (auto [entity, network_id, sync_coords] : coordinates_view.each())
|
||||
{
|
||||
sync_entities_coordinates.entities_ids.push_back(network_id.network_id);
|
||||
sync_entities_coordinates.positions_to_update.push_back({});
|
||||
sync_variable_transport_t<glm::vec2> &position_trasport = sync_entities_coordinates.positions_to_update.back();
|
||||
position_trasport.load(sync_coords.position);
|
||||
}
|
||||
|
||||
auto clients_view = get_entity_registry().view<entity_link_to_client_t>();
|
||||
for (auto [entity, client] : clients_view.each())
|
||||
{
|
||||
router_send_packet(sync_entities_coordinates, client.client);
|
||||
}
|
||||
}
|
||||
@ -1,21 +1,25 @@
|
||||
#include <deerith/engine.h>
|
||||
#include <deerith/world.h>
|
||||
#include <thread>
|
||||
#include <args/argh.h>
|
||||
|
||||
#ifdef DEERITH_CLIENT
|
||||
#include <deerith/graphics/window.h>
|
||||
#endif
|
||||
|
||||
int main(int args_count, const char **args)
|
||||
int main(int argc, const char **argv)
|
||||
{
|
||||
deerith::init_engine();
|
||||
auto cmdl = argh::parser(argc, argv);
|
||||
|
||||
int port = 8080;
|
||||
cmdl("port", 8080) >> port;
|
||||
#ifdef DEERITH_SERVER
|
||||
deerith::run_world(8080);
|
||||
#endif
|
||||
|
||||
#ifdef DEERITH_CLIENT
|
||||
if (!deerith::execute_server("./SandboxServer", 8080))
|
||||
if (cmdl[{"-s", "--single"}] && !deerith::execute_server("./SandboxServer", port))
|
||||
{
|
||||
deerith_error("could not start server");
|
||||
deerith::shutdown_engine();
|
||||
@ -24,7 +28,7 @@ int main(int args_count, const char **args)
|
||||
|
||||
std::this_thread::sleep_for(std::chrono::milliseconds(100));
|
||||
|
||||
if (deerith::connect_to_world("127.0.0.1", 8080))
|
||||
if (deerith::connect_to_world("127.0.0.1", port))
|
||||
{
|
||||
deerith_assert(deerith::init_window() == 0, "Failed to init_window");
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user