Skip to content

Commit

Permalink
WIP
Browse files Browse the repository at this point in the history
  • Loading branch information
daid committed Oct 27, 2022
1 parent 0563f42 commit d3cebb2
Show file tree
Hide file tree
Showing 8 changed files with 82 additions and 28 deletions.
23 changes: 22 additions & 1 deletion src/ecs/entity.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@ Entity Entity::create()
} else {
e.index = free_list.back();
free_list.pop_back();
entity_version[e.index] &=~destroyed_flag;
e.version = entity_version[e.index];
}
return e;
Expand All @@ -37,14 +38,34 @@ Entity::operator bool() const
return entity_version[index] == version;
}

bool Entity::operator==(const Entity& other) const {
auto bt = bool(*this);
auto bo = bool(*this);
if (bt != bo)
return false;
if (!bt)
return true;
return index == other.index;
}

bool Entity::operator!=(const Entity& other) const {
auto bt = bool(*this);
auto bo = bool(*this);
if (bt != bo)
return true;
if (!bt)
return false;
return index != other.index;
}

void Entity::destroy()
{
if (!*this)
return;
ComponentStorageBase::destroyAll(index);

// By increasing the version number, everything else will know this entity no longer exists.
entity_version[index] += 1;
entity_version[index] = (entity_version[index] + 1) | destroyed_flag;
free_list.push_back(index);
}

Expand Down
9 changes: 9 additions & 0 deletions src/ecs/entity.h
Original file line number Diff line number Diff line change
Expand Up @@ -42,8 +42,17 @@ class Entity final {
{
return ComponentStorage<T>::storage.sparseset.has(index);
}
template<class T> void removeComponent()
{
ComponentStorage<T>::storage.sparseset.remove(index);
}

bool operator==(const Entity& other) const;
bool operator!=(const Entity& other) const;

uint32_t getIndex() { return index; } // You should never need this, but the multiplayer code does need it.
private:
static constexpr uint32_t destroyed_flag = 1 << 31;

uint32_t index = std::numeric_limits<uint32_t>::max();
uint32_t version = std::numeric_limits<uint32_t>::max();
Expand Down
14 changes: 14 additions & 0 deletions src/multiplayer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,20 @@ template <> bool multiplayerReplicationFunctions<string>::isChanged(void* data,
return false;
}

template <> void multiplayerReplicationFunctions<sp::ecs::Entity>::sendData(void* data, sp::io::DataBuffer& packet)
{
auto e = (sp::ecs::Entity*)data;
if (*e) {
packet << e->getIndex();
} else {
packet << std::numeric_limits<uint32_t>::max();
}
}

template <> void multiplayerReplicationFunctions<sp::ecs::Entity>::receiveData(void* data, sp::io::DataBuffer& packet)
{
}

static bool collisionable_isChanged(void* data, void* prev_data_ptr)
{
CollisionableReplicationData* rep_data = *(CollisionableReplicationData**)prev_data_ptr;
Expand Down
21 changes: 9 additions & 12 deletions src/multiplayer.h
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ bool multiplayerReplicationFunctions<T>::isChanged(void* data, void* prev_data_p

template <> bool multiplayerReplicationFunctions<string>::isChanged(void* data, void* prev_data_ptr);

template <> void multiplayerReplicationFunctions<sp::ecs::Entity>::sendData(void* data, sp::io::DataBuffer& packet);
template <> void multiplayerReplicationFunctions<sp::ecs::Entity>::receiveData(void* data, sp::io::DataBuffer& packet);

//In between class that handles all the nasty synchronization of objects between server and client.
//I'm assuming that it should be a pure virtual class though.
class MultiplayerObject : public virtual PObject
Expand Down Expand Up @@ -226,12 +229,6 @@ class MultiplayerObject : public virtual PObject
registerMemberReplication(&member->z, update_delay);
}

void registerMemberReplication_(F_PARAM sp::ecs::Entity* member, float update_delay = 0.0f)
{
registerMemberReplication(&member->index, update_delay);
registerMemberReplication(&member->version, update_delay);
}

void updateMemberReplicationUpdateDelay(void* data, float update_delay)
{
for(unsigned int n=0; n<memberReplicationInfo.size(); n++)
Expand Down Expand Up @@ -314,8 +311,8 @@ class MultiplayerECSComponentReplicationBase {
}

virtual void update(sp::io::DataBuffer& packet) = 0;
virtual void receive(uint32_t index, sp::io::DataBuffer& packet) = 0;
virtual void remove(uint32_t index) = 0;
virtual void receive(sp::ecs::Entity entity, sp::io::DataBuffer& packet) = 0;
virtual void remove(sp::ecs::Entity entity) = 0;
};
template<typename T> class MultiplayerECSComponentReplication : public MultiplayerECSComponentReplicationBase
{
Expand All @@ -340,15 +337,15 @@ template<typename T> class MultiplayerECSComponentReplication : public Multiplay
}
}

void receive(uint32_t index, sp::io::DataBuffer& packet) override
void receive(sp::ecs::Entity entity, sp::io::DataBuffer& packet) override
{
T data;
packet >> data;
sp::ecs::ComponentStorage<T>::storage.sparseset.set(index, data);
entity.addComponent<T>(data);
}
void remove(uint32_t index) override
void remove(sp::ecs::Entity entity) override
{
sp::ecs::ComponentStorage<T>::storage.sparseset.remove(index);
entity.removeComponent<T>();
}
};

Expand Down
26 changes: 16 additions & 10 deletions src/multiplayer_client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -254,15 +254,21 @@ void GameClient::update(float /*delta*/)
packet >> ecs_cmd;
switch(ecs_cmd)
{
case CMD_ECS_ENTITY_VERSION:
case CMD_ECS_ENTITY_CREATE:
{
uint32_t index, version;
packet >> index >> version;
if (index >= sp::ecs::Entity::entity_version.size()) {
sp::ecs::Entity::entity_version.push_back(version);
} else if (sp::ecs::Entity::entity_version[index] != version) {
sp::ecs::Entity::entity_version[index] = version;
}
uint32_t index;
packet >> index;
if (index >= entity_mapping.size())
entity_mapping.resize(index + 1);
entity_mapping[index] = sp::ecs::Entity::create();
}
break;
case CMD_ECS_ENTITY_DESTROY:
{
uint32_t index;
packet >> index;
if (index < entity_mapping.size())
entity_mapping[index].destroy();
}
break;
case CMD_ECS_SET_COMPONENT:
Expand All @@ -272,7 +278,7 @@ void GameClient::update(float /*delta*/)
packet >> component_index >> index;
for(auto ecsrb = MultiplayerECSComponentReplicationBase::first; ecsrb; ecsrb=ecsrb->next) {
if (ecsrb->component_index == component_index)
ecsrb->receive(index, packet);
ecsrb->receive(entity_mapping[index], packet);
}
}
break;
Expand All @@ -283,7 +289,7 @@ void GameClient::update(float /*delta*/)
packet >> component_index >> index;
for(auto ecsrb = MultiplayerECSComponentReplicationBase::first; ecsrb; ecsrb=ecsrb->next) {
if (ecsrb->component_index == component_index)
ecsrb->remove(index);
ecsrb->remove(entity_mapping[index]);
}
}
break;
Expand Down
3 changes: 3 additions & 0 deletions src/multiplayer_client.h
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "multiplayer_server.h"
#include "networkAudioStream.h"
#include "timer.h"
#include "ecs/entity.h"

#include <stdint.h>
#include <thread>
Expand All @@ -20,6 +21,8 @@ class GameClient : public Updatable
{
constexpr static float no_data_disconnect_time = 20;
public:
std::vector<sp::ecs::Entity> entity_mapping;

enum Status
{
Connecting,
Expand Down
7 changes: 4 additions & 3 deletions src/multiplayer_internal.h
Original file line number Diff line number Diff line change
Expand Up @@ -26,8 +26,9 @@ static const command_t CMD_AUDIO_COMM_DATA = 0x0021;
static const command_t CMD_AUDIO_COMM_STOP = 0x0022;

static constexpr command_t CMD_ECS_UPDATE = 0x0030;
static constexpr uint8_t CMD_ECS_ENTITY_VERSION = 0x00;
static constexpr uint8_t CMD_ECS_SET_COMPONENT = 0x01;
static constexpr uint8_t CMD_ECS_DEL_COMPONENT = 0x02;
static constexpr uint8_t CMD_ECS_ENTITY_CREATE = 0x00;
static constexpr uint8_t CMD_ECS_ENTITY_DESTROY = 0x01;
static constexpr uint8_t CMD_ECS_SET_COMPONENT = 0x02;
static constexpr uint8_t CMD_ECS_DEL_COMPONENT = 0x03;

#endif//MULTIPLAYER_INTERNAL_H
7 changes: 5 additions & 2 deletions src/multiplayer_server.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -147,12 +147,15 @@ void GameServer::update(float /*gameDelta*/)
//Replicate ECS data, we send this as one big packet so ECS state is always consistent on the client.
sp::io::DataBuffer ecs_packet;
ecs_packet << CMD_ECS_UPDATE;
// For each entity, check which version number we last transmitted and if it is changed, transmit the new version number.
// For each entity, check which version number we last transmitted and if it is changed, transmit creation/deletion of entities.
ecs_entity_version.resize(sp::ecs::Entity::entity_version.size(), std::numeric_limits<uint32_t>::max());
for(uint32_t index; index<sp::ecs::Entity::entity_version.size(); index++) {
if (ecs_entity_version[index] != sp::ecs::Entity::entity_version[index]) {
if (ecs_entity_version[index] & sp::ecs::Entity::destroyed_flag)
ecs_packet << CMD_ECS_ENTITY_DESTROY << index;
ecs_entity_version[index] = sp::ecs::Entity::entity_version[index];
ecs_packet << CMD_ECS_ENTITY_VERSION << index << ecs_entity_version[index];
if (!(ecs_entity_version[index] & sp::ecs::Entity::destroyed_flag))
ecs_packet << CMD_ECS_ENTITY_CREATE << index;
}
}
// For each component type, check which components are added/changed/deleted and send that over.
Expand Down

1 comment on commit d3cebb2

@daid-tinyci
Copy link

@daid-tinyci daid-tinyci bot commented on d3cebb2 Dec 11, 2024

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

TinyCI build failure:

[/home/tinyci/builds/daid/SeriousProton/_build_native:make -j 2] returned [2]:


[ 15%] Built target spfreetype2

[ 16%] Built target glad

[ 29%] Built target box2d

[ 37%] Built target lua

[ 43%] Built target basisu-encoder

[ 83%] Built target opus

[ 83%] Building CXX object CMakeFiles/seriousproton_objects.dir/src/multiplayer.cpp.o

[ 84%] Building CXX object CMakeFiles/seriousproton_objects.dir/src/multiplayer_client.cpp.o

[ 84%] Building CXX object CMakeFiles/seriousproton_objects.dir/src/multiplayer_proxy.cpp.o

[ 84%] Building CXX object CMakeFiles/seriousproton_objects.dir/src/multiplayer_server.cpp.o

[ 84%] Building CXX object CMakeFiles/seriousproton_objects.dir/src/networkRecorder.cpp.o

[ 85%] Building CXX object CMakeFiles/seriousproton_objects.dir/src/ecs/entity.cpp.o

In file included from /data/tinyci_builds/daid/SeriousProton/src/ecs/component.h:3,

                 from /data/tinyci_builds/daid/SeriousProton/src/ecs/entity.h:6,

                 from /data/tinyci_builds/daid/SeriousProton/src/ecs/entity.cpp:1:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:60:35: error: ‘size_t’ has not been declared

   60 |         Iterator(SparseSet& _set, size_t _dense_index) : set(_set), dense_index(_dense_index) {}

      |                                   ^~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:70:9: error: ‘size_t’ does not name a type

   70 |         size_t dense_index;

      |         ^~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:5:1: note: ‘size_t’ is defined in header ‘<cstddef>’; did you forget to ‘#include <cstddef>’?

    4 | #include <vector>

  +++ |+#include <cstddef>

    5 | #include <limits>

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h: In constructor ‘sp::SparseSet<T>::Iterator::Iterator(sp::SparseSet<T>&, int)’:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:60:69: error: class ‘sp::SparseSet<T>::Iterator’ does not have any field named ‘dense_index’

   60 |         Iterator(SparseSet& _set, size_t _dense_index) : set(_set), dense_index(_dense_index) {}

      |                                                                     ^~~~~~~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h: In member function ‘bool sp::SparseSet<T>::Iterator::operator!=(const sp::SparseSet<T>::Iterator&) const’:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:62:63: error: ‘dense_index’ was not declared in this scope

   62 |         bool operator!=(const Iterator& other) const { return dense_index != other.dense_index; }

      |                                                               ^~~~~~~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h: In member function ‘void sp::SparseSet<T>::Iterator::operator++()’:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:63:29: error: ‘dense_index’ was not declared in this scope

   63 |         void operator++() { dense_index--; }

      |                             ^~~~~~~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h: In member function ‘std::pair<unsigned int, T&> sp::SparseSet<T>::Iterator::operator*()’:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:64:65: error: ‘dense_index’ was not declared in this scope

   64 |         std::pair<uint32_t, T&> operator*() { return {set.dense[dense_index], set.data[dense_index]}; }

      |                                                                 ^~~~~~~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h: In member function ‘std::pair<unsigned int, const T&> sp::SparseSet<T>::Iterator::operator*() const’:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:65:77: error: ‘dense_index’ was not declared in this scope

   65 |         std::pair<uint32_t, const T&> operator*() const { return {set.dense[dense_index], set.data[dense_index]}; }

      |                                                                             ^~~~~~~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h: In member function ‘bool sp::SparseSet<T>::Iterator::atEnd()’:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:67:31: error: ‘dense_index’ was not declared in this scope

   67 |         bool atEnd() { return dense_index == std::numeric_limits<size_t>::max(); }

      |                               ^~~~~~~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:67:66: error: ‘size_t’ was not declared in this scope; did you mean ‘std::size_t’?

   67 |         bool atEnd() { return dense_index == std::numeric_limits<size_t>::max(); }

      |                                                                  ^~~~~~

      |                                                                  std::size_t

In file included from /usr/include/c++/12/limits:42,

                 from /data/tinyci_builds/daid/SeriousProton/src/ecs/entity.h:4:

/usr/include/x86_64-linux-gnu/c++/12/bits/c++config.h:298:33: note: ‘std::size_t’ declared here

  298 |   typedef __SIZE_TYPE__         size_t;

      |                                 ^~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:67:72: error: template argument 1 is invalid

   67 |         bool atEnd() { return dense_index == std::numeric_limits<size_t>::max(); }

      |                                                                        ^

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h: In member function ‘sp::SparseSet<T>::Iterator sp::SparseSet<T>::end()’:

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:74:65: error: ‘size_t’ was not declared in this scope; did you mean ‘std::size_t’?

   74 |     Iterator end() { return Iterator(*this, std::numeric_limits<size_t>::max()); }

      |                                                                 ^~~~~~

      |                                                                 std::size_t

/usr/include/x86_64-linux-gnu/c++/12/bits/c++config.h:298:33: note: ‘std::size_t’ declared here

  298 |   typedef __SIZE_TYPE__         size_t;

      |                                 ^~~~~~

/data/tinyci_builds/daid/SeriousProton/src/container/sparseset.h:74:71: error: template argument 1 is invalid

   74 |     Iterator end() { return Iterator(*this, std::numeric_limits<size_t>::max()); }

      |                                                                       ^

make[2]: *** [CMakeFiles/seriousproton_objects.dir/build.make:866: CMakeFiles/seriousproton_objects.dir/src/ecs/entity.cpp.o] Error 1

make[2]: *** Waiting for unfinished jobs....

make[1]: *** [CMakeFiles/Makefile2:238: CMakeFiles/seriousproton_objects.dir/all] Error 2

make: *** [Makefile:136: all] Error 2

Please sign in to comment.