Portals - fix gameplay monitor unloading
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.
This commit is contained in:
parent
08cabf2a36
commit
6c1e243fa2
5 changed files with 107 additions and 0 deletions
|
@ -74,6 +74,95 @@ bool PortalGameplayMonitor::_source_rooms_changed(const int *p_source_room_ids,
|
||||||
return source_rooms_changed;
|
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) {
|
void PortalGameplayMonitor::set_params(bool p_use_secondary_pvs, bool p_use_signals) {
|
||||||
_use_secondary_pvs = p_use_secondary_pvs;
|
_use_secondary_pvs = p_use_secondary_pvs;
|
||||||
_use_signals = p_use_signals;
|
_use_signals = p_use_signals;
|
||||||
|
|
|
@ -43,6 +43,8 @@ class PortalGameplayMonitor {
|
||||||
public:
|
public:
|
||||||
PortalGameplayMonitor();
|
PortalGameplayMonitor();
|
||||||
|
|
||||||
|
void unload(PortalRenderer &p_portal_renderer);
|
||||||
|
|
||||||
// entering and exiting gameplay notifications (requires PVS)
|
// 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 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);
|
void set_params(bool p_use_secondary_pvs, bool p_use_signals);
|
||||||
|
|
|
@ -996,6 +996,7 @@ void PortalRenderer::sprawl_roaming(uint32_t p_mover_pool_id, MovingBase &r_movi
|
||||||
void PortalRenderer::_ensure_unloaded(String p_reason) {
|
void PortalRenderer::_ensure_unloaded(String p_reason) {
|
||||||
if (_loaded) {
|
if (_loaded) {
|
||||||
_loaded = false;
|
_loaded = false;
|
||||||
|
_gameplay_monitor.unload(*this);
|
||||||
|
|
||||||
String str;
|
String str;
|
||||||
if (p_reason != String()) {
|
if (p_reason != String()) {
|
||||||
|
@ -1014,6 +1015,17 @@ void PortalRenderer::_ensure_unloaded(String p_reason) {
|
||||||
|
|
||||||
void PortalRenderer::rooms_and_portals_clear() {
|
void PortalRenderer::rooms_and_portals_clear() {
|
||||||
_loaded = false;
|
_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();
|
_statics.clear();
|
||||||
_static_ghosts.clear();
|
_static_ghosts.clear();
|
||||||
|
|
||||||
|
|
|
@ -87,6 +87,9 @@ public:
|
||||||
void destroy() {
|
void destroy() {
|
||||||
_rooms.clear();
|
_rooms.clear();
|
||||||
room_id = -1;
|
room_id = -1;
|
||||||
|
|
||||||
|
last_tick_hit = 0;
|
||||||
|
last_gameplay_tick_hit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// the expanded aabb allows objects to move on most frames
|
// the expanded aabb allows objects to move on most frames
|
||||||
|
|
|
@ -257,6 +257,7 @@ struct VSRoom {
|
||||||
_secondary_pvs_size = 0;
|
_secondary_pvs_size = 0;
|
||||||
_priority = 0;
|
_priority = 0;
|
||||||
_contains_internal_rooms = false;
|
_contains_internal_rooms = false;
|
||||||
|
last_gameplay_tick_hit = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_after_conversion() {
|
void cleanup_after_conversion() {
|
||||||
|
|
Loading…
Reference in a new issue