Don't sync parts that are attached to a vehicle (they were flung away / car fell apart); softer plaid, calmer colors
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
This commit is contained in:
@@ -1475,7 +1475,7 @@ namespace MSCO
|
||||
Color[] colors =
|
||||
{
|
||||
new Color(0.6f, 0.13f, 0.12f), new Color(0.16f, 0.25f, 0.5f), new Color(0.2f, 0.38f, 0.2f), new Color(0.7f, 0.52f, 0.14f),
|
||||
new Color(0.42f, 0.28f, 0.17f), new Color(0.33f, 0.36f, 0.4f), new Color(0.45f, 0.14f, 0.3f), new Color(0.38f, 0.4f, 0.16f)
|
||||
new Color(0.42f, 0.28f, 0.17f), new Color(0.33f, 0.36f, 0.4f), new Color(0.16f, 0.36f, 0.38f), new Color(0.38f, 0.4f, 0.16f)
|
||||
};
|
||||
return colors[id % colors.Length];
|
||||
}
|
||||
|
||||
+46
-6
@@ -27,6 +27,10 @@ namespace MSCO
|
||||
public float NextPartScan;
|
||||
public float StillTime;
|
||||
public float NoMotionClaimUntil; // kurz nach einer Übergabe nicht wegen Nachfedern/Nachrollen übernehmen
|
||||
// Am Auto angebautes Teil (Gelenk zum Fahrzeug oder unter einem anderen Rigidbody): bewegt sich mit dem Auto,
|
||||
// wird dann NICHT als loses Objekt synchronisiert - sonst reißt das Gelenk und das Teil fliegt weg
|
||||
public bool Attached;
|
||||
public float NextAttachCheck;
|
||||
|
||||
public Vector3 TargetPos;
|
||||
public Quaternion TargetRot;
|
||||
@@ -107,6 +111,7 @@ namespace MSCO
|
||||
SyncedBody b;
|
||||
if (!byId.TryGetValue(id, out b) || b.Rb == null || b.OwnerId != SyncedBody.NoOwner) return false;
|
||||
if (!IsValidPose(pos, rot)) return false;
|
||||
if (IsAttached(b)) return false; // inzwischen angebaut: Position kommt vom Auto
|
||||
if (b.IsVehicle) pos = AboveGround(pos, b.Rb.transform); // gespeicherte Position evtl. knapp im Boden
|
||||
b.Rb.transform.position = pos;
|
||||
b.Rb.transform.rotation = rot;
|
||||
@@ -247,6 +252,7 @@ namespace MSCO
|
||||
{
|
||||
if (b.Rb == null) { removeList.Add(b); continue; } // z.B. Teil wurde montiert
|
||||
if (!b.Rb.gameObject.activeInHierarchy) continue;
|
||||
if (UpdateAttached(b)) continue; // angebaut: bewegt sich mit dem Auto
|
||||
|
||||
bool active = b == held || b == driven;
|
||||
if (!IsRemoteOwned(b)) StopRunaway(b);
|
||||
@@ -292,7 +298,7 @@ namespace MSCO
|
||||
{
|
||||
foreach (SyncedBody b in byId.Values)
|
||||
{
|
||||
if (!IsRemoteOwned(b) || b.Rb == null) continue;
|
||||
if (!IsRemoteOwned(b) || b.Rb == null || b.Attached) continue;
|
||||
if (b.IsVehicle && Time.time >= b.NextPartScan) FreezeParts(b);
|
||||
if (Time.time - b.AvatarHoldTime < 0.2f) continue; // sitzt gerade in der Hand eines Mitspielers
|
||||
if ((b.Rb.position - b.TargetPos).sqrMagnitude > SnapDistance * SnapDistance)
|
||||
@@ -315,7 +321,7 @@ namespace MSCO
|
||||
public void ApplyAvatarHold(int playerId, int bodyId, Vector3 pos, Quaternion rot)
|
||||
{
|
||||
SyncedBody b;
|
||||
if (!byId.TryGetValue(bodyId, out b) || b.Rb == null || b.IsVehicle) return; // ältere Mods melden evtl. ein Auto als "gehalten"
|
||||
if (!byId.TryGetValue(bodyId, out b) || b.Rb == null || b.IsVehicle || b.Attached) return; // ältere Mods melden evtl. ein Auto als "gehalten"
|
||||
if (b.OwnerId != playerId)
|
||||
{
|
||||
if (!Wins(playerId, true, b.OwnerId, b.OwnerActive)) return;
|
||||
@@ -428,7 +434,7 @@ namespace MSCO
|
||||
float now = Time.time;
|
||||
foreach (SyncedBody b in byId.Values)
|
||||
{
|
||||
if (!IsLocal(b) || b.Rb == null) continue;
|
||||
if (!IsLocal(b) || b.Rb == null || b.Attached) continue;
|
||||
bool changed = (b.Rb.position - b.LastSentPos).sqrMagnitude > 0.0001f
|
||||
|| Quaternion.Angle(b.Rb.rotation, b.LastSentRot) > 0.5f;
|
||||
if (!changed && now - b.LastSentTime < KeepAliveInterval) continue;
|
||||
@@ -457,7 +463,7 @@ namespace MSCO
|
||||
int id = r.ReadInt32();
|
||||
bool active = r.ReadBoolean();
|
||||
SyncedBody b;
|
||||
if (!byId.TryGetValue(id, out b) || b.Rb == null) return;
|
||||
if (!byId.TryGetValue(id, out b) || b.Rb == null || IsAttached(b)) return;
|
||||
if (!Wins(from, active, b.OwnerId, b.OwnerActive))
|
||||
{
|
||||
// Wir besitzen es und gewinnen: nochmal melden, damit alle es wissen
|
||||
@@ -476,7 +482,7 @@ namespace MSCO
|
||||
int id; Vector3 pos; Quaternion rot; Vector3 vel;
|
||||
ReadState(r, out id, out pos, out rot, out vel);
|
||||
SyncedBody b;
|
||||
if (!byId.TryGetValue(id, out b) || b.Rb == null || !IsValidPose(pos, rot)) continue;
|
||||
if (!byId.TryGetValue(id, out b) || b.Rb == null || !IsValidPose(pos, rot) || IsAttached(b)) continue;
|
||||
// Nur dem aktuellen Besitzer folgen (oder freie Objekte übernehmen)
|
||||
if (b.OwnerId != from && b.OwnerId != SyncedBody.NoOwner) continue;
|
||||
SetRemote(b, from, b.OwnerId == from && b.OwnerActive);
|
||||
@@ -492,7 +498,7 @@ namespace MSCO
|
||||
ReadState(r, out id, out pos, out rot, out vel);
|
||||
SyncedBody b;
|
||||
if (!byId.TryGetValue(id, out b) || b.Rb == null || b.OwnerId != from) return;
|
||||
if (!IsValidPose(pos, rot)) { SetFree(b); return; }
|
||||
if (!IsValidPose(pos, rot) || IsAttached(b)) { SetFree(b); return; }
|
||||
b.Rb.transform.position = pos;
|
||||
b.Rb.transform.rotation = rot;
|
||||
RestoreKinematic(b);
|
||||
@@ -514,6 +520,7 @@ namespace MSCO
|
||||
/// </summary>
|
||||
void StopRunaway(SyncedBody b)
|
||||
{
|
||||
if (b.Attached) return;
|
||||
Rigidbody rb = b.Rb;
|
||||
if (rb.isKinematic || rb.velocity.sqrMagnitude < RunawaySpeed * RunawaySpeed) return;
|
||||
rb.velocity = Vector3.zero;
|
||||
@@ -527,6 +534,39 @@ namespace MSCO
|
||||
ModConsole.Warning("[MSCO] Stopped " + b.RootName + " - it was flung away by the physics");
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Ist das Objekt gerade an ein Fahrzeug angebaut? Dann Besitz aufgeben und nicht mehr als loses Objekt behandeln.
|
||||
/// Wird es wieder abgebaut, läuft der Sync ganz normal weiter. Gibt true zurück, solange es angebaut ist.
|
||||
/// </summary>
|
||||
bool UpdateAttached(SyncedBody b)
|
||||
{
|
||||
if (Time.time < b.NextAttachCheck) return b.Attached;
|
||||
b.NextAttachCheck = Time.time + 0.5f;
|
||||
bool attached = IsAttached(b);
|
||||
if (attached == b.Attached) return attached;
|
||||
b.Attached = attached;
|
||||
if (attached)
|
||||
{
|
||||
if (IsRemoteOwned(b)) RestoreKinematic(b);
|
||||
b.OwnerId = SyncedBody.NoOwner; // jeder Spieler erkennt das Anbauen selbst (Montage kommt über FsmSync)
|
||||
b.OwnerActive = false;
|
||||
}
|
||||
else b.NoMotionClaimUntil = Time.time + HandoverCooldown; // gerade abgebaut: kurz zur Ruhe kommen lassen
|
||||
return attached;
|
||||
}
|
||||
|
||||
static bool IsAttached(SyncedBody b)
|
||||
{
|
||||
if (b.IsVehicle || b.Rb == null) return false;
|
||||
// Unter einem anderen Rigidbody (z.B. am Auto eingehängt)
|
||||
for (Transform p = b.Rb.transform.parent; p != null; p = p.parent)
|
||||
if (p.GetComponent<Rigidbody>() != null) return true;
|
||||
// Per Gelenk mit etwas verbunden, das nicht der Spieler ist (die Hand hält Items nicht über Gelenke fest)
|
||||
foreach (Joint j in b.Rb.GetComponents<Joint>())
|
||||
if (j != null && j.connectedBody != null && j.connectedBody.transform.root.name != "PLAYER") return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
/// <summary>Position innerhalb der Karte, Drehung gültig (gleiche Regel wie auf dem Server).</summary>
|
||||
static bool IsValidPose(Vector3 p, Quaternion q)
|
||||
{
|
||||
|
||||
+12
-10
@@ -88,8 +88,8 @@ namespace MSCO
|
||||
|
||||
// Körper: Karohemd/Jacke, Jeans, Gürtel, leichter Bauch (wie die Leute in MSC)
|
||||
pelvis = Capsule("Pelvis", r, Jeans);
|
||||
torso = Textured(Capsule("Chest", r, Color.white), plaid, new Vector2(2f, 2f));
|
||||
belly = Textured(Capsule("Belly", r, Color.white), plaid, new Vector2(2f, 1f));
|
||||
torso = Textured(Capsule("Chest", r, Color.white), plaid, new Vector2(4f, 4f));
|
||||
belly = Textured(Capsule("Belly", r, Color.white), plaid, new Vector2(4f, 2f));
|
||||
belt = Box("Belt", r, new Color(0.2f, 0.13f, 0.08f));
|
||||
buckle = Box("Buckle", r, Metal);
|
||||
placket = Box("Buttons", r, jacketDark);
|
||||
@@ -102,8 +102,8 @@ namespace MSCO
|
||||
shin[i] = Capsule("Shin", r, Jeans * 0.92f);
|
||||
boot[i] = Box("Boot", r, Boots);
|
||||
sole[i] = Box("Sole", r, Sole);
|
||||
upperArm[i] = Textured(Capsule("UpperArm", r, Color.white), plaid, new Vector2(1f, 2f));
|
||||
forearm[i] = Textured(Capsule("Forearm", r, Color.white), plaid, new Vector2(1f, 2f));
|
||||
upperArm[i] = Textured(Capsule("UpperArm", r, Color.white), plaid, new Vector2(2f, 3f));
|
||||
forearm[i] = Textured(Capsule("Forearm", r, Color.white), plaid, new Vector2(2f, 3f));
|
||||
cuff[i] = Capsule("Cuff", r, jacketDark);
|
||||
hand[i] = Sphere("Hand", r, Skin, 0.1f);
|
||||
}
|
||||
@@ -159,7 +159,8 @@ namespace MSCO
|
||||
brim.localPosition = new Vector3(0f, 0.07f, 0.15f);
|
||||
brim.localScale = new Vector3(0.2f, 0.014f, 0.1f);
|
||||
brim.localRotation = Quaternion.Euler(8f, 0f, 0f); // Schirm leicht nach unten
|
||||
Transform patch = Box("CapPatch", headPivot, new Color(0.9f, 0.88f, 0.8f));
|
||||
Color patchColor = Color.Lerp(jacketDark, Color.white, 0.35f);
|
||||
Transform patch = Box("CapPatch", headPivot, patchColor);
|
||||
patch.localPosition = new Vector3(0f, 0.115f, 0.118f);
|
||||
patch.localScale = new Vector3(0.06f, 0.035f, 0.01f);
|
||||
patch.localRotation = Quaternion.Euler(-25f, 0f, 0f);
|
||||
@@ -175,20 +176,21 @@ namespace MSCO
|
||||
{
|
||||
const int size = 16;
|
||||
var tex = new Texture2D(size, size, TextureFormat.RGB24, false);
|
||||
Color light = Color.Lerp(baseColor, Color.white, 0.18f);
|
||||
Color dark = baseColor * 0.62f;
|
||||
// Weiches Flanell-Karo: wenig Kontrast, dünne Linien - wirkt aus der Entfernung wie Stoff statt Schachbrett
|
||||
Color light = Color.Lerp(baseColor, Color.white, 0.1f);
|
||||
Color dark = baseColor * 0.78f;
|
||||
for (int y = 0; y < size; y++)
|
||||
{
|
||||
for (int x = 0; x < size; x++)
|
||||
{
|
||||
bool bandX = (x / 4) % 2 == 0, bandY = (y / 4) % 2 == 0;
|
||||
Color c = bandX && bandY ? dark : bandX || bandY ? baseColor : light;
|
||||
if (x % 8 == 1 || y % 8 == 1) c = Color.Lerp(c, Color.black, 0.45f); // dünne dunkle Linien
|
||||
if (x % 8 == 1 || y % 8 == 1) c = Color.Lerp(c, Color.black, 0.25f); // dünne dunkle Linien
|
||||
c.a = 1f;
|
||||
tex.SetPixel(x, y, c);
|
||||
}
|
||||
}
|
||||
tex.filterMode = FilterMode.Point;
|
||||
tex.filterMode = FilterMode.Bilinear;
|
||||
tex.wrapMode = TextureWrapMode.Repeat;
|
||||
tex.Apply();
|
||||
return tex;
|
||||
@@ -375,7 +377,7 @@ namespace MSCO
|
||||
Segment(cuff[i], Vector3.Lerp(elbow, handTarget, 0.82f), Vector3.Lerp(elbow, handTarget, 0.9f), 0.105f, 0.105f);
|
||||
hand[i].localPosition = handTarget;
|
||||
hand[i].localRotation = Quaternion.LookRotation(Vector3.forward, (handTarget - elbow).sqrMagnitude > 0f ? elbow - handTarget : Vector3.up);
|
||||
hand[i].localScale = new Vector3(0.075f, 0.115f, 0.1f);
|
||||
hand[i].localScale = new Vector3(0.085f, 0.125f, 0.11f);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user