Skip to content

Commit 50a70df

Browse files
committed
added a bunch of systems to help with exceptions and tracking of avatar data
1 parent 3aa3141 commit 50a70df

14 files changed

Lines changed: 5907 additions & 1316 deletions

File tree

Basis/Packages/com.basis.framework/BasisUI/BasisSettingsDefaults.cs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -300,6 +300,12 @@ public static class BasisSettingsDefaults
300300
public static BasisSettingsBinding<bool> AudioDebugShowSilence = new("audiodebugshowsilence", new BasisPlatformDefault<bool>(true));
301301
public static BasisSettingsBinding<bool> AudioDebugShowViseme = new("audiodebugshowviseme", new BasisPlatformDefault<bool>(false));
302302

303+
public static BasisSettingsBinding<bool> AvatarDataDebugEnabled = new("avatardatadebugenabled", new BasisPlatformDefault<bool>(false));
304+
public static BasisSettingsBinding<bool> AvatarDataDebugShowReceive = new("avatardatadebugshowreceive", new BasisPlatformDefault<bool>(true));
305+
public static BasisSettingsBinding<bool> AvatarDataDebugShowStaging = new("avatardatadebugshowstaging", new BasisPlatformDefault<bool>(true));
306+
public static BasisSettingsBinding<bool> AvatarDataDebugShowInterp = new("avatardatadebugshowinterp", new BasisPlatformDefault<bool>(true));
307+
public static BasisSettingsBinding<bool> AvatarDataDebugShowMeta = new("avatardatadebugshowmeta", new BasisPlatformDefault<bool>(false));
308+
303309
public static BasisSettingsBinding<string> MemoryAllocation = new("memoryallocation", new BasisPlatformDefault<string>
304310
{
305311
windows = "Dynamic",
@@ -543,6 +549,8 @@ public static class BasisSettingsDefaults
543549
// ---------------- NOTIFICATIONS ----------------
544550
public static BasisSettingsBinding<bool> JoinNotifications = new("joinnotifications", new BasisPlatformDefault<bool>(false));
545551
public static BasisSettingsBinding<bool> LeaveNotifications = new("leavenotifications", new BasisPlatformDefault<bool>(false));
552+
public static BasisSettingsBinding<bool> ExceptionNotifications = new("exceptionnotifications", new BasisPlatformDefault<bool>(true));
553+
public static BasisSettingsBinding<bool> ErrorNotifications = new("errornotifications", new BasisPlatformDefault<bool>(false));
546554

547555
// ---------------- CHAT ----------------
548556
/// <summary>
@@ -1363,6 +1371,8 @@ public static void LoadAll()
13631371
// Notifications
13641372
JoinNotifications.LoadBindingValue();
13651373
LeaveNotifications.LoadBindingValue();
1374+
ExceptionNotifications.LoadBindingValue();
1375+
ErrorNotifications.LoadBindingValue();
13661376

13671377
// Chat
13681378
ChatDisabled.LoadBindingValue();

Basis/Packages/com.basis.framework/BasisUI/Elements/PanelElementDescriptor.cs

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -194,6 +194,22 @@ public void SetDescription(string value)
194194
DescriptionLabel.SetText(value);
195195
}
196196

197+
/// <summary>
198+
/// Sets the description with rich-text parsing left enabled, for trusted
199+
/// code-built markup (colors, sizes, b/i). Only pass strings assembled in
200+
/// code — never raw user or remote text — and wrap any interpolated payload
201+
/// in &lt;noparse&gt; so its angle brackets aren't read as tags.
202+
/// </summary>
203+
public void SetRichDescription(string value)
204+
{
205+
if (!HasDescription) return;
206+
_description = value;
207+
_descriptionSet = true;
208+
DescriptionLabel.gameObject.SetActive(!string.IsNullOrEmpty(value));
209+
DescriptionLabel.richText = true;
210+
DescriptionLabel.SetText(value);
211+
}
212+
197213
/// <summary>
198214
/// Disables rich-text parsing on Title and Description labels. Use for fields
199215
/// that only display plain strings/numbers — TMP skips tag scanning entirely,

Basis/Packages/com.basis.framework/BasisUI/Localization/Languages/en.json

Lines changed: 5204 additions & 1196 deletions
Large diffs are not rendered by default.

Basis/Packages/com.basis.framework/BasisUI/Menus/Main Menu Providers/IndividualPlayerPanelUpdater.cs

Lines changed: 91 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,15 @@ public class IndividualPlayerPanelUpdater : MonoBehaviour
2727
public PanelElementDescriptor SilenceField;
2828
public PanelElementDescriptor VisemeField;
2929

30+
// Avatar data chain debug fields
31+
public PanelElementDescriptor AvatarReceiveField;
32+
public PanelElementDescriptor AvatarStagingField;
33+
public PanelElementDescriptor AvatarInterpField;
34+
public PanelElementDescriptor AvatarMetaField;
35+
36+
private byte _lastHighestSequence;
37+
private bool _lastHighestSeqValid;
38+
3039
private float _updateTimer;
3140
private const float UpdateInterval = 0.2f;
3241

@@ -51,6 +60,10 @@ private void DisableRichTextOnce()
5160
EncodedBufferField?.DisableRichText();
5261
SilenceField?.DisableRichText();
5362
VisemeField?.DisableRichText();
63+
AvatarReceiveField?.DisableRichText();
64+
AvatarStagingField?.DisableRichText();
65+
AvatarInterpField?.DisableRichText();
66+
AvatarMetaField?.DisableRichText();
5467
}
5568

5669
private void FreezeLayoutOnce()
@@ -73,6 +86,10 @@ private void FreezeLayoutOnce()
7386
EncodedBufferField?.FreezeLayoutSize(140f);
7487
SilenceField?.FreezeLayoutSize(90f);
7588
VisemeField?.FreezeLayoutSize(90f);
89+
AvatarReceiveField?.FreezeLayoutSize(120f);
90+
AvatarStagingField?.FreezeLayoutSize(140f);
91+
AvatarInterpField?.FreezeLayoutSize(140f);
92+
AvatarMetaField?.FreezeLayoutSize(170f);
7693
}
7794

7895
private void Update()
@@ -127,6 +144,7 @@ private void Update()
127144
if (RangesField != null) RangesField.SetDescription("No data");
128145
UpdateBufferField();
129146
UpdateAudioDebugFields();
147+
UpdateAvatarDataDebugFields();
130148
return;
131149
}
132150

@@ -138,6 +156,7 @@ private void Update()
138156
if (RangesField != null) RangesField.SetDescription("Player not found");
139157
UpdateBufferField();
140158
UpdateAudioDebugFields();
159+
UpdateAvatarDataDebugFields();
141160
return;
142161
}
143162

@@ -162,6 +181,7 @@ private void Update()
162181
if (RangesField != null) RangesField.SetDescription("Not in snapshot");
163182
UpdateBufferField();
164183
UpdateAudioDebugFields();
184+
UpdateAvatarDataDebugFields();
165185
return;
166186
}
167187

@@ -219,6 +239,7 @@ private void Update()
219239

220240
UpdateBufferField();
221241
UpdateAudioDebugFields();
242+
UpdateAvatarDataDebugFields();
222243

223244
// Only count ticks that reached the full-data path — early-returns
224245
// above set fields to "N/A"/"No data" which would lock at a too-small
@@ -404,6 +425,75 @@ private void SetAudioDebugAll(string message)
404425
if (VisemeField != null) VisemeField.SetDescription(message);
405426
}
406427

428+
private void UpdateAvatarDataDebugFields()
429+
{
430+
if (RemotePlayer == null || RemotePlayer.NetworkReceiver == null)
431+
{
432+
SetAvatarDataDebugAll("No receiver");
433+
return;
434+
}
435+
436+
var receiver = RemotePlayer.NetworkReceiver;
437+
438+
if (AvatarReceiveField != null && BasisSettingsDefaults.AvatarDataDebugShowReceive.RawValue)
439+
{
440+
byte highest = receiver.HighestSequence;
441+
int seen = receiver.SeenPackets;
442+
int queued = receiver.PayloadQueue.Count;
443+
int newThisTick = _lastHighestSeqValid ? unchecked((byte)(highest - _lastHighestSequence)) : 0;
444+
_lastHighestSequence = highest;
445+
_lastHighestSeqValid = true;
446+
string state = seen == 0 ? "None" : seen == 1 ? "Initial" : "Streaming";
447+
448+
AvatarReceiveField.SetDescription(
449+
$"State: {state} | Queued: {queued}\n" +
450+
$"Highest Seq: {highest} | New this tick: +{newThisTick}");
451+
}
452+
453+
if (AvatarStagingField != null && BasisSettingsDefaults.AvatarDataDebugShowStaging.RawValue)
454+
{
455+
var cur = receiver.Current;
456+
var nxt = receiver.Next;
457+
bool hasCur = receiver.HasCurrentBuffer && cur != null;
458+
bool hasNxt = receiver.HasNextBuffer && nxt != null;
459+
double windowMs = (hasCur && hasNxt) ? (nxt.ServerTimeSeconds - cur.ServerTimeSeconds) * 1000.0 : 0.0;
460+
461+
AvatarStagingField.SetDescription(
462+
$"Staged: {receiver.StagedCount} | Data Ready: {(receiver.IsDataReady ? "Yes" : "No")}\n" +
463+
$"Cur Seq: {(hasCur ? cur.Sequence.ToString() : "-")} | Next Seq: {(hasNxt ? nxt.Sequence.ToString() : "-")}\n" +
464+
$"Window: {windowMs:F1}ms");
465+
}
466+
467+
if (AvatarInterpField != null && BasisSettingsDefaults.AvatarDataDebugShowInterp.RawValue)
468+
{
469+
AvatarInterpField.SetDescription(
470+
$"t: {receiver.InterpolationTimeDebug:F3} | Rate: {receiver.LastPlaybackRate:F3}x (0.85-1.35)\n" +
471+
$"Jitter Depth: {receiver.DynamicJitterDepth:F2} (min {BasisNetworkReceiver.MinJitterDepth} / max {BasisNetworkReceiver.MaxJitterDepth})\n" +
472+
$"Buffer Holds: {(receiver.HasBufferHolds ? "Yes" : "No")}");
473+
}
474+
475+
if (AvatarMetaField != null && BasisSettingsDefaults.AvatarDataDebugShowMeta.RawValue)
476+
{
477+
receiver.GetLatestNetworkPose(out var pos, out _, out var scale);
478+
float[] eom = receiver.EyesAndMouth;
479+
float mouth = eom != null && eom.Length > 4 ? eom[4] : 0f;
480+
481+
AvatarMetaField.SetDescription(
482+
$"Scale: {receiver.ApplyingScale.x:F2} | Human: {receiver.CachedHumanScaleDebug:F2} | Net: {scale.x:F2}\n" +
483+
$"Hips: ({pos.x:F1}, {pos.y:F1}, {pos.z:F1})\n" +
484+
$"LOD: {RemotePlayer.CurrentLodLevel} | PoseSkip: {RemotePlayer.PoseSkipCounter}\n" +
485+
$"InAvatar: {(RemotePlayer.InAvatarRange ? "Y" : "N")} | OutOfRange: {(RemotePlayer.OutOfRangeFromLocal ? "Y" : "N")} | Mouth: {mouth:F2}");
486+
}
487+
}
488+
489+
private void SetAvatarDataDebugAll(string message)
490+
{
491+
if (AvatarReceiveField != null) AvatarReceiveField.SetDescription(message);
492+
if (AvatarStagingField != null) AvatarStagingField.SetDescription(message);
493+
if (AvatarInterpField != null) AvatarInterpField.SetDescription(message);
494+
if (AvatarMetaField != null) AvatarMetaField.SetDescription(message);
495+
}
496+
407497
private void SetAll(string message)
408498
{
409499
if (DebugField != null) DebugField.SetDescription(message);
@@ -412,6 +502,7 @@ private void SetAll(string message)
412502
if (RangesField != null) RangesField.SetDescription(message);
413503
if (BufferField != null) BufferField.SetDescription(message);
414504
SetAudioDebugAll(message);
505+
SetAvatarDataDebugAll(message);
415506
}
416507
}
417508
}

Basis/Packages/com.basis.framework/BasisUI/Menus/Main Menu Providers/IndividualPlayerProvider.cs

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1289,6 +1289,80 @@ void CreateAudioDebugFields()
12891289
updater.VisemeField = visemeField;
12901290
};
12911291

1292+
// ---- Avatar Data Debug Section ----
1293+
var avatarDataDebugGroup = PanelElementDescriptor.CreateNew(PanelElementDescriptor.ElementStyles.Group, root);
1294+
avatarDataDebugGroup.SetTitle(BasisLocalization.Get("menu.individualPlayer.avatarDataDebug"));
1295+
avatarDataDebugGroup.SetDescription(BasisLocalization.Get("menu.individualPlayer.avatarDataDebug.description"));
1296+
1297+
PanelToggle avatarDataDebugToggle = PanelToggle.CreateNewEntry(avatarDataDebugGroup.ContentParent);
1298+
avatarDataDebugToggle.Descriptor.SetTitle(BasisLocalization.Get("menu.individualPlayer.showAvatarDataDebug"));
1299+
avatarDataDebugToggle.Descriptor.SetDescription(BasisLocalization.Get("menu.individualPlayer.showAvatarDataDebug.description"));
1300+
avatarDataDebugToggle.AssignBinding(BasisSettingsDefaults.AvatarDataDebugEnabled);
1301+
1302+
PanelElementDescriptor avatarReceiveField = null;
1303+
PanelElementDescriptor avatarStagingField = null;
1304+
PanelElementDescriptor avatarInterpField = null;
1305+
PanelElementDescriptor avatarMetaField = null;
1306+
1307+
void CreateAvatarDataDebugFields()
1308+
{
1309+
if (BasisSettingsDefaults.AvatarDataDebugShowReceive.RawValue)
1310+
{
1311+
avatarReceiveField = PanelElementDescriptor.CreateNew(PanelElementDescriptor.ElementStyles.Group, avatarDataDebugGroup.ContentParent);
1312+
avatarReceiveField.SetTitle(BasisLocalization.Get("menu.individualPlayer.avatarDataDebug.receive"));
1313+
avatarReceiveField.SetDescription("...");
1314+
}
1315+
1316+
if (BasisSettingsDefaults.AvatarDataDebugShowStaging.RawValue)
1317+
{
1318+
avatarStagingField = PanelElementDescriptor.CreateNew(PanelElementDescriptor.ElementStyles.Group, avatarDataDebugGroup.ContentParent);
1319+
avatarStagingField.SetTitle(BasisLocalization.Get("menu.individualPlayer.avatarDataDebug.staging"));
1320+
avatarStagingField.SetDescription("...");
1321+
}
1322+
1323+
if (BasisSettingsDefaults.AvatarDataDebugShowInterp.RawValue)
1324+
{
1325+
avatarInterpField = PanelElementDescriptor.CreateNew(PanelElementDescriptor.ElementStyles.Group, avatarDataDebugGroup.ContentParent);
1326+
avatarInterpField.SetTitle(BasisLocalization.Get("menu.individualPlayer.avatarDataDebug.interp"));
1327+
avatarInterpField.SetDescription("...");
1328+
}
1329+
1330+
if (BasisSettingsDefaults.AvatarDataDebugShowMeta.RawValue)
1331+
{
1332+
avatarMetaField = PanelElementDescriptor.CreateNew(PanelElementDescriptor.ElementStyles.Group, avatarDataDebugGroup.ContentParent);
1333+
avatarMetaField.SetTitle(BasisLocalization.Get("menu.individualPlayer.avatarDataDebug.meta"));
1334+
avatarMetaField.SetDescription("...");
1335+
}
1336+
}
1337+
1338+
if (BasisSettingsDefaults.AvatarDataDebugEnabled.RawValue)
1339+
{
1340+
CreateAvatarDataDebugFields();
1341+
}
1342+
1343+
updater.AvatarReceiveField = avatarReceiveField;
1344+
updater.AvatarStagingField = avatarStagingField;
1345+
updater.AvatarInterpField = avatarInterpField;
1346+
updater.AvatarMetaField = avatarMetaField;
1347+
1348+
avatarDataDebugToggle.OnValueChanged += enabled =>
1349+
{
1350+
if (avatarReceiveField != null) { UnityEngine.Object.Destroy(avatarReceiveField.gameObject); avatarReceiveField = null; }
1351+
if (avatarStagingField != null) { UnityEngine.Object.Destroy(avatarStagingField.gameObject); avatarStagingField = null; }
1352+
if (avatarInterpField != null) { UnityEngine.Object.Destroy(avatarInterpField.gameObject); avatarInterpField = null; }
1353+
if (avatarMetaField != null) { UnityEngine.Object.Destroy(avatarMetaField.gameObject); avatarMetaField = null; }
1354+
1355+
if (enabled)
1356+
{
1357+
CreateAvatarDataDebugFields();
1358+
}
1359+
1360+
updater.AvatarReceiveField = avatarReceiveField;
1361+
updater.AvatarStagingField = avatarStagingField;
1362+
updater.AvatarInterpField = avatarInterpField;
1363+
updater.AvatarMetaField = avatarMetaField;
1364+
};
1365+
12921366
var uuidField = PanelTextField.CreateNewEntry(root);
12931367
uuidField.Descriptor.SetTitle("UUID");
12941368
uuidField.SetValueWithoutNotify(remotePlayer.UUID);

0 commit comments

Comments
 (0)