Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -158,33 +158,42 @@ namespace Framework::Integrations::Scripting {
}

void Entity::SetVisible(bool visible) const {
const auto st = _ent.get_mut<Framework::World::Modules::Base::Streamable>();
st->isVisible = visible;
if (visible) {
_ent.remove<Framework::World::Modules::Base::Hidden>();
} else {
_ent.add<Framework::World::Modules::Base::Hidden>();
}
}

void Entity::SetAlwaysVisible(bool visible) const {
const auto st = _ent.get_mut<Framework::World::Modules::Base::Streamable>();
st->alwaysVisible = visible;
if (visible) {
_ent.add<Framework::World::Modules::Base::AlwaysVisible>();
} else {
_ent.remove<Framework::World::Modules::Base::AlwaysVisible>();
}
}

bool Entity::IsVisible() const {
const auto st = _ent.get<Framework::World::Modules::Base::Streamable>();
return st->isVisible;
return !_ent.has<Framework::World::Modules::Base::Hidden>();
}

bool Entity::IsAlwaysVisible() const {
const auto st = _ent.get<Framework::World::Modules::Base::Streamable>();
return st->alwaysVisible;
return _ent.has<Framework::World::Modules::Base::AlwaysVisible>();
}

void Entity::SetVirtualWorld(int virtualWorld) const {
const auto st = _ent.get_mut<Framework::World::Modules::Base::Streamable>();
st->virtualWorld = virtualWorld;
auto engine = Framework::CoreModules::GetWorldEngine();
if (engine) {
engine->SetEntityVirtualWorld(_ent, virtualWorld);
}
}

int Entity::GetVirtualWorld() const {
const auto st = _ent.get<Framework::World::Modules::Base::Streamable>();
return st->virtualWorld;
auto engine = Framework::CoreModules::GetWorldEngine();
if (engine) {
return engine->GetEntityVirtualWorld(_ent);
}
return 0;
}

void Entity::SetUpdateInterval(double interval) const {
Expand Down
51 changes: 35 additions & 16 deletions code/framework/src/world/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@

#include "game_rpc/set_frame.h"
#include "game_rpc/set_transform.h"
#include "networking/messages/game_sync/entity_messages.h"

namespace Framework::World {
EngineError ClientEngine::Init() {
Expand All @@ -21,6 +22,19 @@ namespace Framework::World {

_queryGetEntityByServerID = _world->query_builder<Modules::Base::ServerID>().build();

// Observer to maintain ServerID cache
_world->observer<Modules::Base::ServerID>("ServerIDCacheUpdate")
.event(flecs::OnSet)
.each([this](flecs::entity e, Modules::Base::ServerID& sid) {
_serverIdCache[sid.id] = e;
});

_world->observer<Modules::Base::ServerID>("ServerIDCacheRemove")
.event(flecs::OnRemove)
.each([this](flecs::entity e, Modules::Base::ServerID& sid) {
_serverIdCache.erase(sid.id);
});

return EngineError::ENGINE_NONE;
}

Expand All @@ -33,14 +47,11 @@ namespace Framework::World {
}

flecs::entity ClientEngine::GetEntityByServerID(flecs::entity_t id) const {
flecs::entity ent = {};
_queryGetEntityByServerID.each([&ent, id](flecs::entity e, Modules::Base::ServerID& rhs) {
if (id == rhs.id) {
ent = e;
return;
}
});
return ent;
auto it = _serverIdCache.find(id);
if (it != _serverIdCache.end() && it->second.is_alive()) {
return it->second;
}
return flecs::entity::null();
}

flecs::entity_t ClientEngine::GetServerID(flecs::entity entity) {
Expand All @@ -58,6 +69,7 @@ namespace Framework::World {

auto &sid = e.ensure<Modules::Base::ServerID>();
sid.id = serverID;
e.modified<Modules::Base::ServerID>();
return e;
}

Expand All @@ -72,10 +84,17 @@ namespace Framework::World {
const auto rs = it.field<Modules::Base::Streamable>(1);

for (auto i : it) {
const auto &es = &rs[i];

if (es->GetBaseEvents().updateProc && es->performTickUpdates && Framework::World::Engine::IsEntityOwner(it.entity(i), myGUID.g)) {
es->GetBaseEvents().updateProc(_networkPeer, (SLNet::UNASSIGNED_RAKNET_GUID).g, it.entity(i));
const auto e = it.entity(i);

// Send updates for entities we own
if (!e.has<Modules::Base::NoTickUpdates>() && Framework::World::Engine::IsEntityOwner(e, myGUID.g)) {
const auto sid = e.get<Modules::Base::ServerID>();
if (sid) {
Framework::Networking::Messages::GameSyncEntityUpdate entityUpdate;
entityUpdate.FromParameters(tr[i], 0);
entityUpdate.SetServerID(sid->id);
_networkPeer->Send(entityUpdate, (SLNet::UNASSIGNED_RAKNET_GUID).g);
}
}
}
}
Expand All @@ -98,8 +117,8 @@ namespace Framework::World {
}
}

if (str.modEvents.disconnectProc) {
str.modEvents.disconnectProc(e);
if (str.disconnectProc) {
str.disconnectProc(e);
}

e.destruct();
Expand Down Expand Up @@ -142,8 +161,8 @@ namespace Framework::World {
*tr = rhs;

const auto str = entity.get_mut<Modules::Base::Streamable>();
if (str->modEvents.updateTransformProc) {
str->modEvents.updateTransformProc(entity);
if (str && str->updateTransformProc) {
str->updateTransformProc(entity);
}
}
} // namespace Framework::World
3 changes: 3 additions & 0 deletions code/framework/src/world/client.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,9 @@ namespace Framework::World {
flecs::query<Modules::Base::ServerID> _queryGetEntityByServerID;
OnEntityDestroyCallback _onEntityDestroyCallback;

// Cache for O(1) ServerID lookups
std::unordered_map<flecs::entity_t, flecs::entity> _serverIdCache;

private:
void InitRPCs(Networking::NetworkPeer *peer) const;

Expand Down
98 changes: 88 additions & 10 deletions code/framework/src/world/engine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,19 @@ namespace Framework::World {
_allStreamableEntities = _world->query_builder<Modules::Base::Transform, Modules::Base::Streamable>().build();
_findAllStreamerEntities = _world->query_builder<Modules::Base::Streamer>().build();

// Observer to maintain GUID cache
_world->observer<Modules::Base::Streamer>("GUIDCacheUpdate")
.event(flecs::OnSet)
.each([this](flecs::entity e, Modules::Base::Streamer& s) {
_guidCache[s.guid] = e;
});

_world->observer<Modules::Base::Streamer>("GUIDCacheRemove")
.event(flecs::OnRemove)
.each([this](flecs::entity e, Modules::Base::Streamer& s) {
_guidCache.erase(s.guid);
});

return EngineError::ENGINE_NONE;
}

Expand Down Expand Up @@ -53,13 +66,11 @@ namespace Framework::World {
}

flecs::entity Engine::GetEntityByGUID(uint64_t guid) const {
flecs::entity ourEntity = {};
_findAllStreamerEntities.each([&ourEntity, guid](flecs::entity e, Modules::Base::Streamer &s) {
if (ourEntity == flecs::entity::null() && s.guid == guid) {
ourEntity = e;
}
});
return ourEntity;
auto it = _guidCache.find(guid);
if (it != _guidCache.end() && it->second.is_alive()) {
return it->second;
}
return flecs::entity::null();
}

flecs::entity Engine::WrapEntity(flecs::entity_t serverID) const {
Expand All @@ -68,10 +79,77 @@ namespace Framework::World {

void Engine::PurgeAllResourceEntities() const {
_world->defer_begin();
_findAllResourceEntities.each([this](flecs::entity e, Modules::Base::RemovedOnResourceReload &rhs) {
if (e.is_alive())
e.add<Modules::Base::PendingRemoval>();
_findAllResourceEntities.run([this](flecs::iter& it) {
while (it.next()) {
for (auto i : it) {
auto e = it.entity(i);
if (e.is_alive())
e.add<Modules::Base::PendingRemoval>();
}
}
});
_world->defer_end();
}

flecs::entity Engine::GetOrCreateVirtualWorld(int worldId) {
auto it = _virtualWorldCache.find(worldId);
if (it != _virtualWorldCache.end() && it->second.is_alive()) {
return it->second;
}

// Create a new virtual world entity
std::string name = "VirtualWorld_" + std::to_string(worldId);
auto worldEntity = _world->entity(name.c_str());
worldEntity.set<Modules::Base::VirtualWorld>({worldId});
_virtualWorldCache[worldId] = worldEntity;
return worldEntity;
}

void Engine::SetEntityVirtualWorld(flecs::entity e, int worldId) {
if (!e.is_valid() || !e.is_alive())
return;

// Remove from any existing virtual world
e.remove<Modules::Base::InVirtualWorld>(flecs::Wildcard);

// Add to new virtual world (world ID 0 means no world / default)
if (worldId != 0) {
auto worldEntity = GetOrCreateVirtualWorld(worldId);
e.add<Modules::Base::InVirtualWorld>(worldEntity);
}

// Also update the legacy field for backward compatibility
auto streamable = e.get_mut<Modules::Base::Streamable>();
if (streamable) {
streamable->virtualWorld = worldId;
}
}

int Engine::GetEntityVirtualWorld(flecs::entity e) const {
if (!e.is_valid() || !e.is_alive())
return 0;

// Try to get from relation first
int worldId = 0;
e.each<Modules::Base::InVirtualWorld>([&worldId](flecs::entity worldEntity) {
auto vw = worldEntity.get<Modules::Base::VirtualWorld>();
if (vw) {
worldId = vw->id;
}
});

// Fallback to legacy field if no relation
if (worldId == 0) {
auto streamable = e.get<Modules::Base::Streamable>();
if (streamable) {
worldId = streamable->virtualWorld;
}
}

return worldId;
}

bool Engine::AreInSameVirtualWorld(flecs::entity a, flecs::entity b) const {
return GetEntityVirtualWorld(a) == GetEntityVirtualWorld(b);
}
} // namespace Framework::World
13 changes: 13 additions & 0 deletions code/framework/src/world/engine.h
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@

#include <flecs/flecs.h>
#include <memory>
#include <unordered_map>

#include "core_modules.h"

Expand Down Expand Up @@ -57,6 +58,12 @@ namespace Framework::World {
flecs::query<Modules::Base::RemovedOnResourceReload> _findAllResourceEntities;
Networking::NetworkPeer *_networkPeer = nullptr;

// Cache for O(1) GUID lookups
std::unordered_map<uint64_t, flecs::entity> _guidCache;

// Cache for virtual world entities (by ID)
std::unordered_map<int, flecs::entity> _virtualWorldCache;

public:
EngineError Init(Networking::NetworkPeer *networkPeer);

Expand All @@ -72,5 +79,11 @@ namespace Framework::World {
flecs::world *GetWorld() const {
return _world.get();
}

// Virtual world management
flecs::entity GetOrCreateVirtualWorld(int worldId);
void SetEntityVirtualWorld(flecs::entity e, int worldId);
int GetEntityVirtualWorld(flecs::entity e) const;
bool AreInSameVirtualWorld(flecs::entity a, flecs::entity b) const;
};
} // namespace Framework::World
Loading
Loading