diff --git a/servers/visual/portals/portal_gameplay_monitor.cpp b/servers/visual/portals/portal_gameplay_monitor.cpp index 7a46cc4c85b5..2f65a8ce9a91 100644 --- a/servers/visual/portals/portal_gameplay_monitor.cpp +++ b/servers/visual/portals/portal_gameplay_monitor.cpp @@ -109,7 +109,7 @@ void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) { 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; + room.last_room_tick_hit = 0; VisualServerCallbacks::Message msg; msg.object_id = room._godot_instance_ID; @@ -121,7 +121,7 @@ void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) { 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; + roomgroup.last_room_tick_hit = 0; VisualServerCallbacks::Message msg; msg.object_id = roomgroup._godot_instance_ID; @@ -133,7 +133,7 @@ void PortalGameplayMonitor::unload(PortalRenderer &p_portal_renderer) { 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; + ghost.last_room_tick_hit = 0; VisualServerCallbacks::Message msg; msg.object_id = ghost.object_id; @@ -185,6 +185,9 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c // if there is no change in the source room IDs, then we can optimize out a lot of the checks // (anything not to do with roamers) bool source_rooms_changed = _source_rooms_changed(p_source_room_ids, p_num_source_rooms); + if (source_rooms_changed) { + _room_tick++; + } // lock output VisualServerCallbacks *callbacks = VSG::scene->get_callbacks(); @@ -249,7 +252,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c const VSRoom &room = p_portal_renderer.get_room(room_id); // gone out of view - if (room.last_gameplay_tick_hit != _gameplay_tick) { + if (room.last_room_tick_hit != _room_tick) { VisualServerCallbacks::Message msg; msg.object_id = room._godot_instance_ID; msg.type = _exit_callback_type; @@ -264,7 +267,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c const VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id); // gone out of view - if (roomgroup.last_gameplay_tick_hit != _gameplay_tick) { + if (roomgroup.last_room_tick_hit != _room_tick) { VisualServerCallbacks::Message msg; msg.object_id = roomgroup._godot_instance_ID; msg.type = _exit_callback_type; @@ -279,7 +282,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id); // gone out of view - if (ghost.last_gameplay_tick_hit != _gameplay_tick) { + if (ghost.last_room_tick_hit != _room_tick) { VisualServerCallbacks::Message msg; msg.object_id = ghost.object_id; msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_EXIT_GAMEPLAY; @@ -293,7 +296,7 @@ void PortalGameplayMonitor::update_gameplay(PortalRenderer &p_portal_renderer, c callbacks->unlock(); // swap the current and previous lists - _swap(); + _swap(source_rooms_changed); } void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_renderer, int p_room_id, bool p_source_rooms_changed) { @@ -367,14 +370,14 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende // later tests only relevant if a room has just come into play bool room_came_into_play = false; - if (room.last_gameplay_tick_hit != _gameplay_tick) { + if (room.last_room_tick_hit != _room_tick) { room_came_into_play = true; // add the room to the active list _active_room_ids_curr->push_back(p_room_id); // if wasn't present in the tick before, add the notification to enter - if (room.last_gameplay_tick_hit != (_gameplay_tick - 1)) { + if (room.last_room_tick_hit != (_room_tick - 1)) { VisualServerCallbacks::Message msg; msg.object_id = room._godot_instance_ID; msg.type = _enter_callback_type; @@ -383,7 +386,7 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende } // mark as done - room.last_gameplay_tick_hit = _gameplay_tick; + room.last_room_tick_hit = _room_tick; } // no need to do later tests @@ -398,12 +401,12 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende VSRoomGroup &roomgroup = p_portal_renderer.get_roomgroup(roomgroup_id); - if (roomgroup.last_gameplay_tick_hit != _gameplay_tick) { + if (roomgroup.last_room_tick_hit != _room_tick) { // add the room to the active list _active_roomgroup_ids_curr->push_back(roomgroup_id); // if wasn't present in the tick before, add the notification to enter - if (roomgroup.last_gameplay_tick_hit != (_gameplay_tick - 1)) { + if (roomgroup.last_room_tick_hit != (_room_tick - 1)) { VisualServerCallbacks::Message msg; msg.object_id = roomgroup._godot_instance_ID; msg.type = _enter_callback_type; @@ -412,7 +415,7 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende } // mark as done - roomgroup.last_gameplay_tick_hit = _gameplay_tick; + roomgroup.last_room_tick_hit = _room_tick; } } // for through roomgroups @@ -425,14 +428,14 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende VSStaticGhost &ghost = p_portal_renderer.get_static_ghost(id); // done already? - if (ghost.last_gameplay_tick_hit == _gameplay_tick) + if (ghost.last_room_tick_hit == _room_tick) continue; // add to the active list _active_sghost_ids_curr->push_back(id); // if wasn't present in the tick before, add the notification to enter - if (ghost.last_gameplay_tick_hit != (_gameplay_tick - 1)) { + if (ghost.last_room_tick_hit != (_room_tick - 1)) { VisualServerCallbacks::Message msg; msg.object_id = ghost.object_id; msg.type = VisualServerCallbacks::CALLBACK_NOTIFICATION_ENTER_GAMEPLAY; @@ -441,11 +444,11 @@ void PortalGameplayMonitor::_update_gameplay_room(PortalRenderer &p_portal_rende } // mark as done - ghost.last_gameplay_tick_hit = _gameplay_tick; + ghost.last_room_tick_hit = _room_tick; } } -void PortalGameplayMonitor::_swap() { +void PortalGameplayMonitor::_swap(bool p_source_rooms_changed) { LocalVector *temp = _active_moving_pool_ids_curr; _active_moving_pool_ids_curr = _active_moving_pool_ids_prev; _active_moving_pool_ids_prev = temp; @@ -456,18 +459,20 @@ void PortalGameplayMonitor::_swap() { _active_rghost_pool_ids_prev = temp; _active_rghost_pool_ids_curr->clear(); - temp = _active_room_ids_curr; - _active_room_ids_curr = _active_room_ids_prev; - _active_room_ids_prev = temp; - _active_room_ids_curr->clear(); - - temp = _active_roomgroup_ids_curr; - _active_roomgroup_ids_curr = _active_roomgroup_ids_prev; - _active_roomgroup_ids_prev = temp; - _active_roomgroup_ids_curr->clear(); - - temp = _active_sghost_ids_curr; - _active_sghost_ids_curr = _active_sghost_ids_prev; - _active_sghost_ids_prev = temp; - _active_sghost_ids_curr->clear(); + if (p_source_rooms_changed) { + temp = _active_room_ids_curr; + _active_room_ids_curr = _active_room_ids_prev; + _active_room_ids_prev = temp; + _active_room_ids_curr->clear(); + + temp = _active_roomgroup_ids_curr; + _active_roomgroup_ids_curr = _active_roomgroup_ids_prev; + _active_roomgroup_ids_prev = temp; + _active_roomgroup_ids_curr->clear(); + + temp = _active_sghost_ids_curr; + _active_sghost_ids_curr = _active_sghost_ids_prev; + _active_sghost_ids_prev = temp; + _active_sghost_ids_curr->clear(); + } } diff --git a/servers/visual/portals/portal_gameplay_monitor.h b/servers/visual/portals/portal_gameplay_monitor.h index 5f2833fdc9ff..00d2c44dc784 100644 --- a/servers/visual/portals/portal_gameplay_monitor.h +++ b/servers/visual/portals/portal_gameplay_monitor.h @@ -52,10 +52,17 @@ class PortalGameplayMonitor { private: void _update_gameplay_room(PortalRenderer &p_portal_renderer, int p_room_id, bool p_source_rooms_changed); bool _source_rooms_changed(const int *p_source_room_ids, int p_num_source_rooms); - void _swap(); + void _swap(bool p_source_rooms_changed); + // gameplay ticks happen every physics tick uint32_t _gameplay_tick = 1; + // Room ticks only happen when the rooms the cameras are within change. + // This is an optimization. This tick needs to be maintained separately from _gameplay_tick + // because testing against the previous tick is used to determine whether to send enter or exit + // gameplay notifications, and this must be synchronized differently for rooms, roomgroups and static ghosts. + uint32_t _room_tick = 1; + // we need two version, current and previous LocalVector _active_moving_pool_ids[2]; LocalVector *_active_moving_pool_ids_curr; diff --git a/servers/visual/portals/portal_renderer.h b/servers/visual/portals/portal_renderer.h index 4a705681fce6..21fd782868a1 100644 --- a/servers/visual/portals/portal_renderer.h +++ b/servers/visual/portals/portal_renderer.h @@ -68,7 +68,7 @@ struct VSStaticGhost { ObjectID object_id; uint32_t last_tick_hit = 0; - uint32_t last_gameplay_tick_hit = 0; + uint32_t last_room_tick_hit = 0; }; class PortalRenderer { diff --git a/servers/visual/portals/portal_types.h b/servers/visual/portals/portal_types.h index 14b5b0a9060b..5944ff04e8b6 100644 --- a/servers/visual/portals/portal_types.h +++ b/servers/visual/portals/portal_types.h @@ -227,7 +227,7 @@ struct VSRoomGroup { } // used for calculating gameplay notifications - uint32_t last_gameplay_tick_hit = 0; + uint32_t last_room_tick_hit = 0; ObjectID _godot_instance_ID = 0; @@ -257,7 +257,7 @@ struct VSRoom { _secondary_pvs_size = 0; _priority = 0; _contains_internal_rooms = false; - last_gameplay_tick_hit = 0; + last_room_tick_hit = 0; } void cleanup_after_conversion() { @@ -354,7 +354,7 @@ struct VSRoom { uint16_t _secondary_pvs_size = 0; // used for calculating gameplay notifications - uint32_t last_gameplay_tick_hit = 0; + uint32_t last_room_tick_hit = 0; // convex hull of the room, either determined by geometry or manual bound LocalVector _planes;