Docs: reduce over-documentation across gameplay scripts

Trim restated narration, dead commented-out code, and oversized class
headers; keep all why-comments (authority, timing, edge cases), tooltips,
and serialization caveats.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
adminandClaude Fable 5 committed 2026-07-02 10:08:28 +02:00
1 parent 882d30797e
commit 066e308cde
21 files changed
+478 -902

No files matched your search

+35 -66
View File
@@ -8,25 +8,16 @@ using UnityEngine.InputSystem;
using Random = UnityEngine.Random; // System (for Action) also defines Random -> keep the UnityEngine one
/// <summary>
/// Live mesh painting in Play mode: paints the brush onto the mesh textures with the
/// mouse. Three paint maps are driven at once (each can be toggled): albedo color
/// (_BaseMap), an HDRP-style mask map (R = metallic, G = occlusion, A = smoothness; one
/// texture bound to BOTH _MetallicGlossMap and _OcclusionMap) and emission (_EmissionMap).
/// Metallic/smoothness and occlusion share that mask map but stay independently paintable.
/// Two backends (switchable live via <see cref="useGpu"/>):
/// GPU shader painting into RenderTextures (fast, default) and CPU rasterization
/// (slower, identical result). Both paint seamlessly across UV seams because the brush
/// is evaluated in 3D local space around the hit point, capturing triangles on both
/// sides of a seam at once.
/// Live mesh painting in Play mode. Three paint maps are driven at once (each toggleable): albedo
/// (_BaseMap), an HDRP-style mask map (R = metallic, G = occlusion, A = smoothness; one texture bound
/// to BOTH _MetallicGlossMap and _OcclusionMap) and emission (_EmissionMap). Two backends, switchable
/// live via <see cref="useGpu"/>: GPU shader painting into RenderTextures (fast, default) and CPU
/// rasterization (identical result). Both paint seamlessly across UV seams because the brush is
/// evaluated in 3D local space around the hit point, capturing triangles on both sides of a seam.
///
/// The brush is a square stamp in the surface tangent plane whose shape is given by a
/// grayscale mask texture (the mask value = per-texel opacity). A list of masks is
/// assignable in the Inspector; if it is empty a procedural circle mask is used, which
/// reproduces the classic round brush. Attach to the GameObject you want to paint.
///
/// A non-destructive brush preview (size + mask) is shown at the hover point without
/// painting (<see cref="previewMode"/>): either a flat decal quad or a real on-surface
/// overlay that wraps the mesh exactly like the paint would land.
/// The brush is a square stamp in the surface tangent plane shaped by a grayscale mask (mask value =
/// per-texel opacity); an empty mask list falls back to a procedural circle (classic round brush).
/// A non-destructive preview (<see cref="previewMode"/>) shows size + mask at the hover point.
/// </summary>
[DisallowMultipleComponent]
public partial class MeshPainter : MonoBehaviour
@@ -62,13 +53,10 @@ public partial class MeshPainter : MonoBehaviour
public bool IsReady => _setupValid;
/// <summary>
/// Live camouflage knobs on the player's <c>Custom/PlayerCamoLit</c> material instance, surfaced so
/// the paint HUD can tune them at runtime. Backed directly by the material instance, which is the
/// authored source of truth: the getter reads it, the setter writes it. Both are a no-op when the
/// material lacks the property (non-camo shader) or before Start builds the instance, so they never
/// clobber the authored value. Runtime tuning is persisted by the HUD (PaintHud.Persistence saves them
/// to the same JSON as the brush values and carries them across a scene-switch respawn) and replicated
/// to other peers owner-authoritatively by <see cref="PlayerPaintSync"/>, so remotes show the same camo.
/// Live camouflage knobs on the player's <c>Custom/PlayerCamoLit</c> material instance, surfaced for
/// the paint HUD. The material is the source of truth (getter reads, setter writes); both are a
/// no-op when the property is absent or before Start builds the instance, so the authored value is
/// never clobbered. Persisted by PaintHud.Persistence, replicated by <see cref="PlayerPaintSync"/>.
/// </summary>
public float CamoHalfLambert
{
@@ -91,12 +79,9 @@ public partial class MeshPainter : MonoBehaviour
set => SetMatFloat(SpecularDampenId, value);
}
/// <summary>
/// Painted-height look knobs on the same <c>Custom/PlayerCamoLit</c> material instance, surfaced for
/// the HUD like the camo knobs above (material-backed source of truth, no-op before the instance
/// exists). All three persist with the painting (PaintHud.Persistence + the .paint slot) and replicate
/// to peers via <see cref="PlayerPaintSync"/>. Defaults match the shader so the unpainted look is unchanged.
/// </summary>
// Painted-height look knobs on the same material instance, surfaced/guarded/persisted/replicated
// like the camo knobs above. Defaults match the shader so the unpainted look is unchanged.
/// <summary>Painted-height AO darkening depth (shift, 0..1): AO fades from 1 down to (1 - this) at
/// the deepest painted hole. 0 = no darkening (no black spots), 1 = full black at occ=0.</summary>
public float OcclusionThreshold
@@ -120,14 +105,11 @@ public partial class MeshPainter : MonoBehaviour
set => SetMatFloat(ParallaxId, Mathf.Max(0f, value) * ParallaxBase);
}
/// <summary>Drives the see-through-walls X-ray overlay (see <c>PlayerCamoLit</c>): sets the TARGET for
/// the ALPHA of the authored <c>_XRayColor</c>, so the rgb glow colour set on the material is preserved
/// (target 0 = off/no effect, 1 = full glow). The material alpha eases toward this target over
/// <see cref="xrayFadeDuration"/> seconds in <c>Update</c> (a smooth fade instead of a hard pop); set the
/// duration to 0 for an instant toggle. This is a per-avatar runtime reveal, NOT a painted channel: it
/// neither persists with the painting nor round-trips through the HUD. <see cref="NetworkPlayerSetup"/>
/// raises it for the remaining hiders during the resolution phase and for a hider that buries itself
/// too deep in geometry (over the concealment threshold).</summary>
/// <summary>Drives the see-through-walls X-ray overlay: sets the TARGET for the alpha of the authored
/// <c>_XRayColor</c> (the rgb glow colour is preserved); Update eases the material alpha toward it
/// over <see cref="xrayFadeDuration"/> seconds. A per-avatar runtime reveal, NOT a painted channel
/// (neither persists nor round-trips the HUD). <see cref="NetworkPlayerSetup"/> raises it during the
/// resolution phase and for a hider buried too deep in geometry.</summary>
public bool XRayRevealed
{
get => _xrayTarget > 0f;
@@ -505,9 +487,8 @@ public partial class MeshPainter : MonoBehaviour
return;
}
// User mask: cache opacity (luma*alpha) for the CPU backend so it matches the GPU.
// Non-readable textures are read back via the GPU (so even built-ins like
// Default-Particle work on the CPU path, not just the GPU one).
// User mask: cache opacity (luma*alpha) for the CPU backend so it matches the GPU. Non-readable
// textures are read back via the GPU, so even built-ins like Default-Particle work on the CPU path.
var px = ReadMaskPixels(_resolvedMask, out int w, out int h);
_maskW = w;
_maskH = h;
@@ -672,9 +653,8 @@ public partial class MeshPainter : MonoBehaviour
// Spray paints scattered dots, but the preview shows the round footprint (the area
// the dots land in), so the hover ring stays a stable, readable size indicator.
_previewMat.SetTexture(MaskTexId, spray ? _proceduralMask : _resolvedMask);
// Preview stays fully opaque regardless of the brush's albedo alpha; only the
// Preview Opacity property scales it (the hover ring is a size/shape indicator,
// not a paint-strength preview).
// Fully opaque regardless of the brush's albedo alpha; only Preview Opacity scales it
// (a size/shape indicator, not a paint-strength preview).
_previewMat.SetFloat(PreviewOpacityId, Mathf.Max(0f, previewOpacity));
int layer = gameObject.layer;
@@ -688,10 +668,8 @@ public partial class MeshPainter : MonoBehaviour
_previewMat.SetVector(BrushVId, v);
_previewMat.SetVector(BrushNormalId, n);
// Draw the collider mesh again (object transform): the shader clips it to the
// brush box, so only the footprint shows, wrapped onto the real surface. Using
// the collider mesh keeps it in the same local space as the raycast hit and
// valid for both skinned (baked) and static meshes.
// Re-draw the collider mesh; the shader clips it to the brush box. The collider mesh is in
// the same local space as the raycast hit and valid for skinned (baked) and static meshes.
Mesh previewMesh = _collider ? _collider.sharedMesh : null;
if (!previewMesh) return;
Matrix4x4 m = transform.localToWorldMatrix;
@@ -727,7 +705,6 @@ public partial class MeshPainter : MonoBehaviour
RefreshEmissionColor(); // live-tunable emission intensity
TickXRayFade(); // ease the see-through X-ray glow toward its on/off target (runs on every avatar)
// Painting disabled by the game mode (e.g. player-control mode): do nothing.
if (!PaintingEnabled)
{
EndStrokeIfActive(); // finalize an in-progress stroke if the mode was left mid-paint
@@ -761,20 +738,17 @@ public partial class MeshPainter : MonoBehaviour
if (!TryGetMouse(out bool pressed, out Vector2 screenPos))
return;
// Don't paint through the in-game UI: clicking a HUD slider/toggle must not
// also stamp the mesh behind it.
// Don't paint through the in-game UI (a HUD click must not also stamp the mesh behind it).
if (pressed && IsPointerOverUi())
pressed = false;
// Brush preview (size + mask) at the hover point - independent of painting AND of the
// pipette, so you always see the brush footprint: before pressing the button, while the
// momentary pipette holds Shift/Ctrl, and live as Shift/Ctrl+wheel resizes the brush.
// Brush preview at the hover point - independent of painting AND of the pipette, so the
// footprint stays visible before pressing, while the pipette holds, and during wheel resize.
if (previewMode != BrushPreviewMode.Off && _previewMat && paintCamera)
UpdatePreview(screenPos);
// Pipette (eyedropper): a fresh click samples ALL channel values at the hit point and adopts
// them into the brush instead of painting. It takes over the click entirely (no painting),
// but the brush preview above stays visible.
// Pipette: a fresh click samples the channel values at the hit instead of painting. It takes
// over the click entirely; the brush preview above stays visible.
if (pipette)
{
EndStrokeIfActive(); // switching to the eyedropper ends any active stroke
@@ -1020,12 +994,9 @@ public partial class MeshPainter : MonoBehaviour
pLocal = transform.InverseTransformPoint(hit.point);
hitTri = hit.triangleIndex;
// Brush radius (texels) -> constant local 3D radius via the mesh-wide average UV
// density. Deliberately NOT the hit triangle's own density: that varied up to ~7.6x
// across the mesh (spiking at UV seams / stretched islands), so the same brushSize
// painted a visibly larger patch on seam triangles than on evenly-mapped ones. A single
// global scale keeps the brush the same physical size everywhere; the stamp is still a
// 3D box, so seams are bridged as before.
// Brush radius (texels) -> constant local 3D radius via the MESH-WIDE average UV density -
// deliberately not the hit triangle's own (that varied up to ~7.6x at seams/stretched islands,
// painting visibly different sizes). The stamp stays a 3D box, so seams are bridged as before.
radiusLocal = (brushSize / (float)textureSize) * _avgUvToLocal;
if (radiusLocal <= 0f) return false;
@@ -1113,8 +1084,6 @@ public partial class MeshPainter : MonoBehaviour
else if (_pipetteModHeld) pipette = _pipetteBeforeMod;
_pipetteModHeld = mod;
// Shift or Ctrl + wheel resizes the brush (the orbit camera ignores the wheel while either is
// held, so it does not also zoom).
if (!mod) return;
float scroll = InputUtil.ReadScroll();