Skip to content

Commit

Permalink
Portals - fix gameplay monitor unloading
Browse files Browse the repository at this point in the history
The gameplay monitor wasn't being unloaded correctly in between levels. This meant that exit signals were not being sent, and entered signals for the new level were being missed.

This PR sends appropriate exit signals on unloading, and clear the data.
  • Loading branch information
lawnjelly committed Jan 21, 2022
1 parent 08cabf2 commit 6c1e243
Show file tree
Hide file tree
Showing 5 changed files with 107 additions and 0 deletions.
89 changes: 89 additions & 0 deletions servers/visual/portals/portal_gameplay_monitor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,95 @@ bool PortalGameplayMonitor::_source_rooms_changed(const int *p_source_room_ids,
return source_rooms_changed;
}

void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) {
// First : send gameplay exit signals for any objects still in gameplay
////////////////////////////////////////////////////////////////////
// lock output
VisualServerCallbacks *callbacks = VSG::scene->get_callbacks();
callbacks->lock();

// Remove any movings
for (int n = 0; n < _active_moving_pool_ids_prev->size(); n++) {
int pool_id = (*_active_moving_pool_ids_prev)[n];
PortalRenderer::Moving &moving = p_portal_renderer.get_pool_moving(pool_id);
moving.last_gameplay_tick_hit = 0;

VisualServerCallbacks::Message msg;
msg.object_id = VSG::scene->_instance_get_object_ID(moving.instance);
msg.type = _exit_callback_type;
callbacks->push_message(msg);
}

// Remove any roaming ghosts
for (int n = 0; n < _active_rghost_pool_ids_prev->size(); n++) {
int pool_id = (*_active_rghost_pool_ids_prev)[n];
PortalRenderer::RGhost &moving = p_portal_renderer.get_pool_rghost(pool_id);
moving.last_gameplay_tick_hit = 0;

VisualServerCallbacks::Message msg;
msg.object_id = moving.object_id;
msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY;
callbacks->push_message(msg);
}

// Rooms
for (int n = 0; n < _active_room_ids_prev->size(); n++) {
int room_id = (*_active_room_ids_prev)[n];
VSRoom &room = p_portal_renderer.get_room(room_id);
room.last_gameplay_tick_hit = 0;

VisualServerCallbacks::Message msg;
msg.object_id = room._godot_instance_ID;
msg.type = _exit_callback_type;
callbacks->push_message(msg);
}

// RoomGroups
for (int n = 0; n < _active_roomgroup_ids_prev->size(); n++) {
int roomgroup_id = (*_active_roomgroup_ids_prev)[n];
VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id);
roomgroup.last_gameplay_tick_hit = 0;

VisualServerCallbacks::Message msg;
msg.object_id = roomgroup._godot_instance_ID;
msg.type = _exit_callback_type;
callbacks->push_message(msg);
}

// Static Ghosts
for (int n = 0; n < _active_sghost_ids_prev->size(); n++) {
int id = (*_active_sghost_ids_prev)[n];
VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id);
ghost.last_gameplay_tick_hit = 0;

VisualServerCallbacks::Message msg;
msg.object_id = ghost.object_id;
msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY;
callbacks->push_message(msg);
}

// unlock
callbacks->unlock();

// Clear all remaining data
for (int n = 0; n < 2; n++) {
_active_moving_pool_ids[n].clear();
_active_rghost_pool_ids[n].clear();
_active_room_ids[n].clear();
_active_roomgroup_ids[n].clear();
_active_sghost_ids[n].clear();
}

_source_rooms_prev.clear();

// Lets not reset this just in case because it may be possible to have a moving outside the room system
// which is preserved between levels, and has a stored gameplay tick. And with uint32_t this should take
// a *long* time to rollover... (828 days?). And I don't think a rollover would actually cause a problem in practice.
// But can revisit this in the case of e.g. servers running continuously.
// We could alternatively go through all movings (not just active) etc and reset the last_gameplay_tick_hit to 0.
// _gameplay_tick = 1;
}

void PortalGameplayMonitor::set_params(bool p_use_secondary_pvs, bool p_use_signals) {
_use_secondary_pvs = p_use_secondary_pvs;
_use_signals = p_use_signals;
Expand Down
2 changes: 2 additions & 0 deletions servers/visual/portals/portal_gameplay_monitor.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ class PortalGameplayMonitor {
public:
PortalGameplayMonitor();

void unload(PortalRenderer &p_portal_renderer);

// entering and exiting gameplay notifications (requires PVS)
void update_gameplay(PortalRenderer &p_portal_renderer, const int *p_source_room_ids, int p_num_source_rooms);
void set_params(bool p_use_secondary_pvs, bool p_use_signals);
Expand Down
12 changes: 12 additions & 0 deletions servers/visual/portals/portal_renderer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -996,6 +996,7 @@ void PortalRenderer::sprawl_roaming(uint32_t p_mover_pool_id, MovingBase &r_movi
void PortalRenderer::_ensure_unloaded(String p_reason) {
if (_loaded) {
_loaded = false;
_gameplay_monitor.unload(*this);

String str;
if (p_reason != String()) {
Expand All @@ -1014,6 +1015,17 @@ void PortalRenderer::_ensure_unloaded(String p_reason) {

void PortalRenderer::rooms_and_portals_clear() {
_loaded = false;

// N.B. We want to make sure all the tick counters on movings rooms etc to zero,
// so that on loading the next level gameplay entered signals etc will be
// correctly sent and everything is fresh.
// This is mostly done by the gameplay_monitor, but rooms_and_portals_clear()
// will also clear tick counters where possible
// (there is no TrackedList for the RoomGroup pool for example).
// This could be made neater by moving everything to TrackedPooledLists, but this
// may be overkill.
_gameplay_monitor.unload(*this);

_statics.clear();
_static_ghosts.clear();

Expand Down
3 changes: 3 additions & 0 deletions servers/visual/portals/portal_renderer.h
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,9 @@ class PortalRenderer {
void destroy() {
_rooms.clear();
room_id = -1;

last_tick_hit = 0;
last_gameplay_tick_hit = 0;
}

// the expanded aabb allows objects to move on most frames
Expand Down
1 change: 1 addition & 0 deletions servers/visual/portals/portal_types.h
Original file line number Diff line number Diff line change
Expand Up @@ -257,6 +257,7 @@ struct VSRoom {
_secondary_pvs_size = 0;
_priority = 0;
_contains_internal_rooms = false;
last_gameplay_tick_hit = 0;
}

void cleanup_after_conversion() {
Expand Down

0 comments on commit 6c1e243

Please sign in to comment.