105 lines
3.0 KiB
JavaScript
105 lines
3.0 KiB
JavaScript
|
|
import { Instance } from "./Instance.js";
|
||
|
|
import { BO3ScriptSignal } from "../core/BO3ScriptSignal.js";
|
||
|
|
|
||
|
|
export class DebugTextService extends Instance {
|
||
|
|
constructor() {
|
||
|
|
super("DebugTextService");
|
||
|
|
|
||
|
|
this.isClient = true; // Mark client-only
|
||
|
|
this._renderService = null;
|
||
|
|
this._networkService = null;
|
||
|
|
this._lastBytes = 0;
|
||
|
|
this._bps = 0;
|
||
|
|
this._lastMeasure = performance.now();
|
||
|
|
|
||
|
|
// Tracks text lines
|
||
|
|
this._lines = [];
|
||
|
|
|
||
|
|
// Hook into render loop later
|
||
|
|
}
|
||
|
|
|
||
|
|
OnAddedToScene(parent) {
|
||
|
|
const dm = this.GetDataModel();
|
||
|
|
|
||
|
|
// Get references to RenderService and NetworkService
|
||
|
|
this._renderService = dm.GetService("RenderService");
|
||
|
|
this._networkService = dm.GetService("NetworkService");
|
||
|
|
|
||
|
|
if (!this._renderService) {
|
||
|
|
console.warn("[DebugTextService] No RenderService found!");
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
|
||
|
|
// Initialize debug text array
|
||
|
|
this._renderService.debugText = [];
|
||
|
|
|
||
|
|
// Hook into RenderStepped
|
||
|
|
this._renderService.RenderStepped.Connect((dt) => this._onRenderStep(dt));
|
||
|
|
}
|
||
|
|
|
||
|
|
// Called each RenderStepped frame (~60fps)
|
||
|
|
_onRenderStep(dt) {
|
||
|
|
this._lines.length = 0; // clear
|
||
|
|
|
||
|
|
// === Network stats ===
|
||
|
|
if (this._networkService) {
|
||
|
|
const now = performance.now();
|
||
|
|
const bytesNow = this._networkService.totalBytes || 0;
|
||
|
|
const deltaBytes = bytesNow - this._lastBytes;
|
||
|
|
const deltaTime = (now - this._lastMeasure) / 1000;
|
||
|
|
|
||
|
|
if (deltaTime > 0.25) { // smooth every 250ms
|
||
|
|
this._bps = deltaBytes / deltaTime;
|
||
|
|
this._lastBytes = bytesNow;
|
||
|
|
this._lastMeasure = now;
|
||
|
|
}
|
||
|
|
|
||
|
|
this._lines.push(
|
||
|
|
`Net: ${(this._bps / 1024).toFixed(2)} KB/s`
|
||
|
|
);
|
||
|
|
}
|
||
|
|
|
||
|
|
// === Instance tree summary ===
|
||
|
|
const dm = this.GetDataModel();
|
||
|
|
if (dm && dm.Children) {
|
||
|
|
const totalInstances = this._countInstances(dm);
|
||
|
|
this._lines.push(`Instances: ${totalInstances}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
// === Misc stats ===
|
||
|
|
if (this._renderService.physicsWorld) {
|
||
|
|
const bodies = this._renderService.physicsWorld.bodies.length;
|
||
|
|
this._lines.push(`Physics Bodies: ${bodies}`);
|
||
|
|
}
|
||
|
|
|
||
|
|
// === Output ===
|
||
|
|
this._renderService.debugText.length = 0;
|
||
|
|
this._renderService.debugText.push(...this._lines);
|
||
|
|
|
||
|
|
// Generate instance tree (for future use)
|
||
|
|
const instanceTree = this._generateTree(dm);
|
||
|
|
// Push this to text overlay if needed
|
||
|
|
this._renderService.debugText.push(...instanceTree);
|
||
|
|
}
|
||
|
|
|
||
|
|
_countInstances(instance) {
|
||
|
|
let count = 1;
|
||
|
|
if (!instance.Children) return count;
|
||
|
|
for (const child of instance.Children) {
|
||
|
|
count += this._countInstances(child);
|
||
|
|
}
|
||
|
|
return count;
|
||
|
|
}
|
||
|
|
_generateTree(instance, depth = 0) {
|
||
|
|
let lines = [];
|
||
|
|
const indent = " ".repeat(depth);
|
||
|
|
lines.push(`${indent}- ${instance.ClassName} (${instance.Name}) [${instance.InstanceId}]`);
|
||
|
|
if (instance.Children) {
|
||
|
|
for (const child of instance.Children) {
|
||
|
|
lines.push(...this._generateTree(child, depth + 1));
|
||
|
|
}
|
||
|
|
}
|
||
|
|
return lines;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
// Displays debug text overlay on screen with network and instance stats
|