Fix teleport to places landing in the wrong spot (2.10.5)
Use the median of a place's parts and the dense group around it instead of the bounds of everything (scattered/disabled children pulled the center into the forest); only take top-level objects as the place root. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1,5 +1,11 @@
|
|||||||
# Changelog
|
# Changelog
|
||||||
|
|
||||||
|
## 2.10.5
|
||||||
|
|
||||||
|
- **Teleport zu Orten** (Admin, Reiter TELEPORT) landet wieder am Ort: vorher zählten alle weit verstreuten Teile
|
||||||
|
eines Ortes mit (Briefkasten, Wege, abgeschaltete Objekte) und man landete irgendwo im Wald; außerdem wurde
|
||||||
|
manchmal ein gleichnamiges Unterobjekt statt des Ortes genommen
|
||||||
|
|
||||||
## 2.10.4
|
## 2.10.4
|
||||||
|
|
||||||
**Admin-Menü neu aufgebaut**
|
**Admin-Menü neu aufgebaut**
|
||||||
|
|||||||
@@ -53,8 +53,10 @@ namespace MSCO
|
|||||||
};
|
};
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Wohin bei einem Teleport-Ziel? Neben das Objekt (Mitte seiner sichtbaren Teile, ein Stück außerhalb, damit man
|
/// Wohin bei einem Teleport-Ziel? Zu einem Ort gehören oft weit verstreute Teile (Briefkasten, Wege, Strecken,
|
||||||
/// nicht im Dach oder in einer Wand landet) und dort auf den Boden.
|
/// abgeschaltete Objekte) - deren gemeinsame Mitte liegt irgendwo im Wald. Deshalb: Median aller Teile (der Ort
|
||||||
|
/// selbst, Ausreißer zählen nicht), darum die dichte Gruppe (60 m), daneben ein Stück außerhalb auf den Boden
|
||||||
|
/// (nicht ins Dach oder in eine Wand).
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public static bool FindPlace(string objectName, out Vector3 position)
|
public static bool FindPlace(string objectName, out Vector3 position)
|
||||||
{
|
{
|
||||||
@@ -62,17 +64,28 @@ namespace MSCO
|
|||||||
GameObject root = FindRoot(objectName);
|
GameObject root = FindRoot(objectName);
|
||||||
if (root == null) return false;
|
if (root == null) return false;
|
||||||
|
|
||||||
Bounds bounds = new Bounds(root.transform.position, Vector3.zero);
|
var centers = new List<Vector3>();
|
||||||
bool any = false;
|
|
||||||
foreach (Renderer r in root.GetComponentsInChildren<Renderer>(true))
|
foreach (Renderer r in root.GetComponentsInChildren<Renderer>(true))
|
||||||
{
|
{
|
||||||
if (r == null || r.bounds.size == Vector3.zero) continue;
|
if (r == null || r is ParticleRenderer || r is ParticleSystemRenderer) continue;
|
||||||
if (!any) { bounds = r.bounds; any = true; }
|
Vector3 size = r.bounds.size;
|
||||||
else bounds.Encapsulate(r.bounds);
|
if (size == Vector3.zero || size.x > 150f || size.z > 150f) continue; // Gelände-/Wasserflächen
|
||||||
|
centers.Add(r.bounds.center);
|
||||||
|
}
|
||||||
|
if (centers.Count == 0)
|
||||||
|
{
|
||||||
|
Vector3 ground0;
|
||||||
|
position = Ground(root.transform.position, root.transform.position.y + 50f, out ground0) ? ground0 : root.transform.position;
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
Vector3 center = bounds.center;
|
Vector3 median = new Vector3(Median(centers, 0), Median(centers, 1), Median(centers, 2));
|
||||||
float ox = Mathf.Min(bounds.extents.x, 25f) + 3f, oz = Mathf.Min(bounds.extents.z, 25f) + 3f;
|
Bounds cluster = new Bounds(median, Vector3.zero);
|
||||||
|
foreach (Vector3 c in centers)
|
||||||
|
if (new Vector2(c.x - median.x, c.z - median.z).sqrMagnitude < 60f * 60f) cluster.Encapsulate(c);
|
||||||
|
|
||||||
|
Vector3 center = cluster.center;
|
||||||
|
float ox = Mathf.Min(cluster.extents.x, 20f) + 4f, oz = Mathf.Min(cluster.extents.z, 20f) + 4f;
|
||||||
Vector3[] candidates =
|
Vector3[] candidates =
|
||||||
{
|
{
|
||||||
center + new Vector3(ox, 0f, 0f), center + new Vector3(-ox, 0f, 0f),
|
center + new Vector3(ox, 0f, 0f), center + new Vector3(-ox, 0f, 0f),
|
||||||
@@ -81,20 +94,32 @@ namespace MSCO
|
|||||||
foreach (Vector3 c in candidates)
|
foreach (Vector3 c in candidates)
|
||||||
{
|
{
|
||||||
Vector3 ground;
|
Vector3 ground;
|
||||||
if (Ground(c, bounds.max.y + 30f, out ground)) { position = ground; return true; }
|
if (Ground(c, cluster.max.y + 30f, out ground)) { position = ground; return true; }
|
||||||
}
|
}
|
||||||
position = center;
|
position = center + Vector3.up * 2f;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static float Median(List<Vector3> points, int axis)
|
||||||
|
{
|
||||||
|
var values = new List<float>(points.Count);
|
||||||
|
foreach (Vector3 p in points) values.Add(p[axis]);
|
||||||
|
values.Sort();
|
||||||
|
return values[values.Count / 2];
|
||||||
|
}
|
||||||
|
|
||||||
|
/// <summary>Wurzelobjekt eines Ortes (nur oberste Ebene - "YARD" o.ä. gibt es auch als Unterobjekt).</summary>
|
||||||
static GameObject FindRoot(string name)
|
static GameObject FindRoot(string name)
|
||||||
{
|
{
|
||||||
GameObject go = GameObject.Find(name);
|
GameObject found = null;
|
||||||
if (go != null) return go;
|
// auch ausgeblendete Objekte (das Spiel schaltet entfernte Orte ab); aktive bevorzugt
|
||||||
// auch ausgeblendete Objekte (das Spiel schaltet entfernte Orte ab)
|
|
||||||
foreach (GameObject candidate in Resources.FindObjectsOfTypeAll<GameObject>())
|
foreach (GameObject candidate in Resources.FindObjectsOfTypeAll<GameObject>())
|
||||||
if (candidate.name == name && candidate.transform.parent == null && candidate.hideFlags == HideFlags.None) return candidate;
|
{
|
||||||
return null;
|
if (candidate.name != name || candidate.transform.parent != null || candidate.hideFlags != HideFlags.None) continue;
|
||||||
|
if (candidate.activeInHierarchy) return candidate;
|
||||||
|
if (found == null) found = candidate;
|
||||||
|
}
|
||||||
|
return found;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>Höchster fester Boden unter einem Punkt (ohne Trigger).</summary>
|
/// <summary>Höchster fester Boden unter einem Punkt (ohne Trigger).</summary>
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ namespace MSCO
|
|||||||
/// Version der Mod. Kleine Updates: nur die dritte Stelle erhöhen (2.9.1, 2.9.2 ...) - sie bleiben mit
|
/// Version der Mod. Kleine Updates: nur die dritte Stelle erhöhen (2.9.1, 2.9.2 ...) - sie bleiben mit
|
||||||
/// Servern und Mitspielern derselben ersten zwei Stellen kompatibel.
|
/// Servern und Mitspielern derselben ersten zwei Stellen kompatibel.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
public const string ModVersion = "2.10.4";
|
public const string ModVersion = "2.10.5";
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Netzwerk-Version (die ersten beiden Stellen). Nur erhöhen, wenn sich das Protokoll inkompatibel ändert - dann
|
/// Netzwerk-Version (die ersten beiden Stellen). Nur erhöhen, wenn sich das Protokoll inkompatibel ändert - dann
|
||||||
/// auch GameServer.ModVersion im Server.
|
/// auch GameServer.ModVersion im Server.
|
||||||
|
|||||||
Reference in New Issue
Block a user