diff --git a/servers/visual/portals/portal_gameplay_monitor.cpp b/servers/visual/portals/portal_gameplay_monitor.cpp index 75073b78fbd..7a46cc4c85b 100644 --- a/servers/visual/portals/portal_gameplay_monitor.cpp +++ b/servers/visual/portals/portal_gameplay_monitor.cpp @@ -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; diff --git a/servers/visual/portals/portal_gameplay_monitor.h b/servers/visual/portals/portal_gameplay_monitor.h index d9e2811b67d..5f2833fdc9f 100644 --- a/servers/visual/portals/portal_gameplay_monitor.h +++ b/servers/visual/portals/portal_gameplay_monitor.h @@ -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); diff --git a/servers/visual/portals/portal_renderer.cpp b/servers/visual/portals/portal_renderer.cpp index 3b30cc16759..39cd37e5206 100644 --- a/servers/visual/portals/portal_renderer.cpp +++ b/servers/visual/portals/portal_renderer.cpp @@ -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()) { @@ -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(); diff --git a/servers/visual/portals/portal_renderer.h b/servers/visual/portals/portal_renderer.h index 4445193312f..4a705681fce 100644 --- a/servers/visual/portals/portal_renderer.h +++ b/servers/visual/portals/portal_renderer.h @@ -87,6 +87,9 @@ public: 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 diff --git a/servers/visual/portals/portal_types.h b/servers/visual/portals/portal_types.h index 3332992fde0..14b5b0a9060 100644 --- a/servers/visual/portals/portal_types.h +++ b/servers/visual/portals/portal_types.h @@ -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() {