Fehler #1527
geschlossen[Core] Fehler in Objektsichtbarkeit bei verändertem Viewpoint
Beschreibung
Problembeschreibung
Wenn der Viewpoint des Players auf ein anderes Objekt gesetzt ist, werden nur die Objekte angezeigt, die sich vom Spielercharakter aus gesehen (statt vom Viewpoint aus) in Sichtweite befinden. Davon betroffen sind mindestens folgende Klassenfähigkeiten:
- Fernsicht (Schamane), wenn der gewählte Punkt zu weit entfernt ist
- Adlerauge (Jäger), wenn der gewählte Punkt zu weit entfernt ist
- Auge des Wildtiers (Jäger), wenn man sich mit dem Tier zu weit entfernt
Ich habe ein Bild angehängt, in dem die Situtation sichtbar wird. Dort wird Fernsicht auf den kleinen See in Donnerfels gecastet. Wie man sieht, sind weder NPCs noch Spieler noch Objekte wie die Schmiede sichtbar.
Lösungsansatz
Ich konnte das Problem auf einer lokalen Trinity-Installation reproduzieren und lokalisieren. Da die betreffenden Codestellen im Rising Gods-Code vermutlich noch sehr ähnlich aussehen, hoffe ich, dass ich bei der Bugfindung helfen kann.
In Kürze: Das Problem tritt in template<class T> void Player::UpdateVisibilityOf(T* target, UpdateData& data, std::set<Unit*>& visibleNow)
auf (im aktuellen Trinity-Code in der Datei Player.cpp ab Zeile 21334). Dort müssen beide Vorkommen von canSeeOrDetect(target, false, true)
durch m_seer->canSeeOrDetect(target, false, true)
ersetzt werden.
Längere Version: Nachdem der Viewport neu gesetzt wurde (also z.B. nachdem der Cast von Fernsicht beendet ist), wird Player::UpdateVisibilityForPlayer()
aufgerufen, um die sichtbaren Objekte zu aktualisieren. Darin werden mit m_seer->VisitNearbyObject(GetSightRange(), notifier)
alle zu m_seer
nahegelegenen Objekte auf eventuelle Sichtbarkeit getestet. m_seer
ist dabei das WorldObject
, das den aktuellen Sichtpunkt des Spielers darstellt, und zu diesem Zeitpunkt bereits richtig gesetzt (wenn die Viewpoint nicht verändert ist, ist m_seer
einfach this
). In VisitNearbyObject()
wiederum wird mit Map::VisitAll()
über alle Objekte iteriert und Visit()
des Notifiers aufgerufen, in diesem Fall Trinity::VisibleNotifier::Visit()
. Dieses ruft schließlich Player::UpdateVisibilityOf()
zur Überprüfung auf, welches wegen oben beschriebenen Fehlers sämtliche gefundene Objekte verwirft, wenn sie nicht in Sichtweite des Playercharakters sind. Durch die beschriebene Änderung wird stattdessen und korrekterweise getestet, ob m_seer
die Objekte sehen kann.
Leider ist das nur die halbe Miete. Besagtes m_seer->canSeeOrDetect()
vollführt den Distanzcheck leider nicht mit der Sichtweite des Spielers, sondern mit der Sichtweite von m_seer
. Diese wird mit WorldObject::GetSightRange()
ermittelt (konkret in der Zeile if (!corpseCheck && !IsWithinDist(obj, GetSightRange(obj), false)) return false;
). Bei Fernsicht und Adlerauge sind m_seer
einfache DynamicObject
, bei denen GetSightRange()
0 zurückgibt (womit schlussendlich wieder keine Objekte sichtbar sind), bei Auge des Wildtiers hat man immerhin durch das Pet die Standardkreatursichtweite, welche aber in der Regel unter der des Spielers liegt. Ebenso weiß ich nicht, inwiefern Dinge wie Stealth-Detection o.ä. dadurch beeinträchtigt werden, dass die Detektion über m_seer
statt über den Spieler stattfindet (wobei wenn überhaupt nur die Lösung beeinträchtigt wird, der normale Fall ändert sich durch m_seer == this
nicht - ich denke wenn man erstmal überhaupt etwas sieht, wäre sowas vorerst verschmerzbar). Mir fehlt hier der Überblick, um abschätzen zu können, wo man am besten Änderungen vornimmt, um diese Fälle abzudecken.