Skip to content

Commit 16145c8

Browse files
committed
xrGame/alife_graph_registry.cpp: fix remove() on graph/level desync during teleport (fixes #2058)
1 parent 3526a63 commit 16145c8

1 file changed

Lines changed: 67 additions & 3 deletions

File tree

src/xrGame/alife_graph_registry.cpp

Lines changed: 67 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -176,7 +176,27 @@ void CALifeGraphRegistry::add(CSE_ALifeDynamicObject* object, GameGraph::_GRAPH_
176176
if (!object->m_bOnline && object->used_ai_locations() /**&& object->interactive()**/)
177177
{
178178
VERIFY(ai().game_graph().valid_vertex_id(game_vertex_id));
179-
m_objects[game_vertex_id].objects().add(object->ID, object);
179+
OBJECT_REGISTRY& target = m_objects[game_vertex_id].objects();
180+
const auto& target_map = target.objects();
181+
const auto existing_at_target = target_map.find(object->ID);
182+
const bool already_registered_here =
183+
(existing_at_target != target_map.end() && existing_at_target->second == object);
184+
185+
if (!already_registered_here)
186+
{
187+
const GameGraph::_GRAPH_ID vertex_count = (GameGraph::_GRAPH_ID)m_objects.size();
188+
for (GameGraph::_GRAPH_ID i = 0; i < vertex_count; ++i)
189+
{
190+
if (!ai().game_graph().valid_vertex_id(i))
191+
continue;
192+
OBJECT_REGISTRY& reg = m_objects[i].objects();
193+
const auto& om = reg.objects();
194+
if (om.find(object->ID) == om.end())
195+
continue;
196+
reg.remove(object->ID, true);
197+
}
198+
target.add(object->ID, object);
199+
}
180200
object->m_tGraphID = game_vertex_id;
181201
}
182202
else if (!m_level && update)
@@ -191,6 +211,7 @@ void CALifeGraphRegistry::add(CSE_ALifeDynamicObject* object, GameGraph::_GRAPH_
191211

192212
void CALifeGraphRegistry::remove(CSE_ALifeDynamicObject* object, GameGraph::_GRAPH_ID game_vertex_id, bool update)
193213
{
214+
bool removed_from_graph = false;
194215
if (object->used_ai_locations() /**&& object->interactive()**/)
195216
{
196217
#ifdef DEBUG
@@ -200,8 +221,51 @@ void CALifeGraphRegistry::remove(CSE_ALifeDynamicObject* object, GameGraph::_GRA
200221
game_vertex_id);
201222
}
202223
#endif
203-
m_objects[game_vertex_id].objects().remove(object->ID);
224+
if (ai().game_graph().valid_vertex_id(game_vertex_id))
225+
{
226+
OBJECT_REGISTRY& primary = m_objects[game_vertex_id].objects();
227+
const auto& primary_map = primary.objects();
228+
if (primary_map.find(object->ID) != primary_map.end())
229+
{
230+
primary.remove(object->ID);
231+
removed_from_graph = true;
232+
}
233+
}
234+
if (!removed_from_graph)
235+
{
236+
const GameGraph::_GRAPH_ID vertex_count = (GameGraph::_GRAPH_ID)m_objects.size();
237+
for (GameGraph::_GRAPH_ID i = 0; i < vertex_count; ++i)
238+
{
239+
if (!ai().game_graph().valid_vertex_id(i))
240+
continue;
241+
if (i == game_vertex_id)
242+
continue;
243+
OBJECT_REGISTRY& reg = m_objects[i].objects();
244+
const auto& om = reg.objects();
245+
if (om.find(object->ID) == om.end())
246+
continue;
247+
reg.remove(object->ID);
248+
removed_from_graph = true;
249+
#ifndef MASTER_GOLD
250+
Msg("! [ALife] graph registry: object [%s][%d] was at vertex %u, not at m_tGraphID %u — removed from "
251+
"actual vertex",
252+
object->name_replace(), object->ID, i, game_vertex_id);
253+
#endif
254+
break;
255+
}
256+
}
257+
#ifndef MASTER_GOLD
258+
if (!removed_from_graph)
259+
Msg("! [ALife] graph registry: remove [%s][%d] — not in any vertex map (expected %u), continuing",
260+
object->name_replace(), object->ID, game_vertex_id);
261+
#endif
204262
}
205263
if (update && m_level)
206-
level().remove(object, ai().game_graph().vertex(game_vertex_id)->level_id() != level().level_id());
264+
{
265+
bool level_no_assert =
266+
ai().game_graph().vertex(game_vertex_id)->level_id() != level().level_id();
267+
if (object->used_ai_locations() && !removed_from_graph)
268+
level_no_assert = true;
269+
level().remove(object, level_no_assert);
270+
}
207271
}

0 commit comments

Comments
 (0)