initial upload
This commit is contained in:
611
Unity-Master/Assets/Scripts/AvatarSyncComparison.cs
Normal file
611
Unity-Master/Assets/Scripts/AvatarSyncComparison.cs
Normal file
@ -0,0 +1,611 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using Newtonsoft.Json;
|
||||
|
||||
/// <summary>
|
||||
/// Utility script to compare the old JSON system vs new UDP binary system
|
||||
/// Attach this to any GameObject and check the console for size comparisons
|
||||
/// </summary>
|
||||
public class AvatarSyncComparison : MonoBehaviour
|
||||
{
|
||||
[Header("Comparison Settings")]
|
||||
[SerializeField] private bool runComparisonOnStart = true;
|
||||
[SerializeField] private bool showDetailedBreakdown = true;
|
||||
[SerializeField] private bool saveToFile = true;
|
||||
[SerializeField] private string outputFileName = "avatar_sync_comparison.txt";
|
||||
|
||||
[Header("Test Data - Avatar Reference")]
|
||||
[SerializeField] private Transform testAvatar;
|
||||
[SerializeField] private UDPAvatarBroadcaster udpBroadcaster; // Get actual settings
|
||||
[SerializeField] private UDPAvatarReceiver udpReceiver; // Get actual settings
|
||||
|
||||
[Header("System Parameters")]
|
||||
[SerializeField] private float updateRate = 30f; // Hz - configurable refresh rate
|
||||
[SerializeField] private int oldSystemBoneCount = 80; // Calculated from avatar if available
|
||||
[SerializeField] private int oldSystemMeshCount = 4; // Calculated from avatar if available
|
||||
[SerializeField] private int oldSystemBlendShapesPerMesh = 52; // Calculated from avatar if available
|
||||
|
||||
[Header("Code Complexity (Lines of Code)")]
|
||||
[SerializeField] private int oldSystemTotalLines = 2300; // Can be calculated by scanning files
|
||||
[SerializeField] private int newSystemTotalLines = 800; // Can be calculated by scanning files
|
||||
|
||||
void Start()
|
||||
{
|
||||
if (runComparisonOnStart)
|
||||
{
|
||||
// Add 5 second delay to allow UDPAvatarBroadcaster to fully initialize
|
||||
Invoke(nameof(DelayedStart), 5f);
|
||||
}
|
||||
}
|
||||
|
||||
void DelayedStart()
|
||||
{
|
||||
// Auto-calculate values from avatar if available
|
||||
CalculateAvatarParameters();
|
||||
RunComparison();
|
||||
}
|
||||
|
||||
void CalculateAvatarParameters()
|
||||
{
|
||||
// Get UDPAvatarBroadcaster from same GameObject if not assigned
|
||||
if (udpBroadcaster == null)
|
||||
{
|
||||
udpBroadcaster = GetComponent<UDPAvatarBroadcaster>();
|
||||
}
|
||||
|
||||
// Get actual values from UDP broadcaster
|
||||
if (udpBroadcaster != null)
|
||||
{
|
||||
updateRate = GetUDPBroadcasterUpdateRate();
|
||||
Debug.Log($"Got actual update rate from UDPAvatarBroadcaster: {updateRate} Hz");
|
||||
|
||||
// Use the avatar from the broadcaster if not set
|
||||
if (testAvatar == null)
|
||||
{
|
||||
testAvatar = GetUDPBroadcasterAvatarRoot();
|
||||
}
|
||||
}
|
||||
|
||||
if (testAvatar != null)
|
||||
{
|
||||
// Calculate actual bone count from avatar
|
||||
SkinnedMeshRenderer[] meshRenderers = testAvatar.GetComponentsInChildren<SkinnedMeshRenderer>();
|
||||
HashSet<Transform> uniqueBones = new HashSet<Transform>();
|
||||
|
||||
foreach (SkinnedMeshRenderer smr in meshRenderers)
|
||||
{
|
||||
if (smr.bones != null)
|
||||
{
|
||||
foreach (Transform bone in smr.bones)
|
||||
{
|
||||
if (bone != null)
|
||||
{
|
||||
uniqueBones.Add(bone);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (uniqueBones.Count > 0)
|
||||
{
|
||||
oldSystemBoneCount = uniqueBones.Count;
|
||||
}
|
||||
|
||||
// Calculate actual mesh and blend shape counts
|
||||
if (meshRenderers.Length > 0)
|
||||
{
|
||||
oldSystemMeshCount = meshRenderers.Length;
|
||||
|
||||
// Calculate average blend shapes per mesh
|
||||
int totalBlendShapes = 0;
|
||||
int meshesWithBlendShapes = 0;
|
||||
|
||||
foreach (var mesh in meshRenderers)
|
||||
{
|
||||
if (mesh.sharedMesh != null && mesh.sharedMesh.blendShapeCount > 0)
|
||||
{
|
||||
totalBlendShapes += mesh.sharedMesh.blendShapeCount;
|
||||
meshesWithBlendShapes++;
|
||||
}
|
||||
}
|
||||
|
||||
if (meshesWithBlendShapes > 0)
|
||||
{
|
||||
oldSystemBlendShapesPerMesh = totalBlendShapes / meshesWithBlendShapes;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Debug.Log($"Calculated Parameters: {oldSystemBoneCount} bones, {oldSystemMeshCount} meshes, {oldSystemBlendShapesPerMesh} blend shapes/mesh, {updateRate} Hz");
|
||||
}
|
||||
|
||||
float GetUDPBroadcasterUpdateRate()
|
||||
{
|
||||
if (udpBroadcaster == null) return updateRate;
|
||||
|
||||
// Use reflection to get the private updateRate field
|
||||
var field = typeof(UDPAvatarBroadcaster).GetField("updateRate",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
return (float)field.GetValue(udpBroadcaster);
|
||||
}
|
||||
|
||||
return updateRate; // Fallback to current value
|
||||
}
|
||||
|
||||
Transform GetUDPBroadcasterAvatarRoot()
|
||||
{
|
||||
if (udpBroadcaster == null) return null;
|
||||
|
||||
// Use reflection to get the private avatarRoot field
|
||||
var field = typeof(UDPAvatarBroadcaster).GetField("avatarRoot",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
return (Transform)field.GetValue(udpBroadcaster);
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
bool GetUDPBroadcasterFullDataMode()
|
||||
{
|
||||
if (udpBroadcaster == null) return false;
|
||||
|
||||
// Use reflection to get the private fullDataMode field
|
||||
var field = typeof(UDPAvatarBroadcaster).GetField("fullDataMode",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
return (bool)field.GetValue(udpBroadcaster);
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
int GetUDPBroadcasterCurrentBoneCount()
|
||||
{
|
||||
if (udpBroadcaster == null) return 20;
|
||||
|
||||
// Use reflection to get the private currentBoneCount field
|
||||
var field = typeof(UDPAvatarBroadcaster).GetField("currentBoneCount",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
return (int)field.GetValue(udpBroadcaster);
|
||||
}
|
||||
|
||||
return 20; // Default optimized mode
|
||||
}
|
||||
|
||||
int GetUDPBroadcasterCurrentBlendShapeCount()
|
||||
{
|
||||
if (udpBroadcaster == null) return 10;
|
||||
|
||||
// Use reflection to get the private currentBlendShapeCount field
|
||||
var field = typeof(UDPAvatarBroadcaster).GetField("currentBlendShapeCount",
|
||||
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance);
|
||||
|
||||
if (field != null)
|
||||
{
|
||||
return (int)field.GetValue(udpBroadcaster);
|
||||
}
|
||||
|
||||
return 10; // Default optimized mode
|
||||
}
|
||||
|
||||
[ContextMenu("Run Size Comparison")]
|
||||
public void RunComparison()
|
||||
{
|
||||
Debug.Log("=== Avatar Sync System Comparison ===");
|
||||
|
||||
// Simulate old JSON system
|
||||
var jsonSize = CalculateJSONSystemSize();
|
||||
|
||||
// Simulate new UDP binary system
|
||||
var binarySize = CalculateUDPBinarySize();
|
||||
|
||||
// Calculate efficiency gains
|
||||
float compressionRatio = (float)jsonSize / binarySize;
|
||||
float bandwidthReduction = (1f - (float)binarySize / jsonSize) * 100f;
|
||||
|
||||
Debug.Log($"\n📊 SIZE COMPARISON:");
|
||||
Debug.Log($"Old JSON System: {jsonSize:N0} bytes ({jsonSize / 1024f:F1} KB)");
|
||||
Debug.Log($"New UDP Binary: {binarySize:N0} bytes ({binarySize / 1024f:F1} KB)");
|
||||
Debug.Log($"Compression Ratio: {compressionRatio:F1}x smaller");
|
||||
Debug.Log($"Bandwidth Reduction: {bandwidthReduction:F1}%");
|
||||
|
||||
if (showDetailedBreakdown)
|
||||
{
|
||||
ShowDetailedBreakdown();
|
||||
}
|
||||
|
||||
ShowNetworkImpact(jsonSize, binarySize);
|
||||
ShowSystemComplexity();
|
||||
|
||||
if (saveToFile)
|
||||
{
|
||||
SaveComparisonToFile(jsonSize, binarySize);
|
||||
}
|
||||
}
|
||||
|
||||
int CalculateJSONSystemSize()
|
||||
{
|
||||
// Recreate the old AvatarSyncData structure using calculated values
|
||||
var oldSystemData = new
|
||||
{
|
||||
rootTransform = new
|
||||
{
|
||||
worldPosition = new { x = 0f, y = 0f, z = 0f },
|
||||
worldRotation = new { x = 0f, y = 0f, z = 0f, w = 1f },
|
||||
localScale = new { x = 1f, y = 1f, z = 1f }
|
||||
},
|
||||
bones = GenerateOldSystemBones(oldSystemBoneCount),
|
||||
blendShapes = GenerateOldSystemBlendShapes(oldSystemMeshCount, oldSystemBlendShapesPerMesh),
|
||||
timestamp = Time.time
|
||||
};
|
||||
|
||||
string json = JsonConvert.SerializeObject(oldSystemData, Formatting.Indented);
|
||||
int jsonBytes = Encoding.UTF8.GetByteCount(json);
|
||||
|
||||
Debug.Log($"📄 Old System Structure: {oldSystemBoneCount} bones, {oldSystemMeshCount} meshes × {oldSystemBlendShapesPerMesh} blend shapes = {oldSystemMeshCount * oldSystemBlendShapesPerMesh} total blend shapes");
|
||||
Debug.Log($"📄 Sample JSON (first 200 chars):\n{json.Substring(0, Math.Min(200, json.Length))}...");
|
||||
|
||||
return jsonBytes;
|
||||
}
|
||||
|
||||
int CalculateUDPBinarySize()
|
||||
{
|
||||
// Get actual bone and blend shape counts from UDP system
|
||||
int actualBoneCount = GetNewSystemBoneCount();
|
||||
int actualBlendShapeCount = GetNewSystemBlendShapeCount();
|
||||
|
||||
// Calculate new UDP binary system size
|
||||
int headerSize = 1 + 4 + 4 + 1; // playerID + sequenceNumber + timestamp + isFullDataMode
|
||||
int rootTransformSize = (3 + 4 + 3) * 4; // 3 Vector3s + 1 Quaternion * 4 bytes per float
|
||||
int bonesSize = 4 + (actualBoneCount * (3 + 4) * 4); // bone count + bones * (position + rotation) * 4 bytes per float
|
||||
int blendShapesSize = 4 + (actualBlendShapeCount * 4); // blend shape count + weights * 4 bytes per float
|
||||
|
||||
int totalSize = headerSize + rootTransformSize + bonesSize + blendShapesSize;
|
||||
|
||||
Debug.Log($"🔢 New UDP Binary Structure:");
|
||||
Debug.Log($" Header: {headerSize} bytes");
|
||||
Debug.Log($" Root Transform: {rootTransformSize} bytes");
|
||||
Debug.Log($" Bones ({actualBoneCount}): {bonesSize} bytes");
|
||||
Debug.Log($" Blend Shapes ({actualBlendShapeCount}): {blendShapesSize} bytes");
|
||||
Debug.Log($" Total: {totalSize} bytes");
|
||||
|
||||
return totalSize;
|
||||
}
|
||||
|
||||
int GetNewSystemBoneCount()
|
||||
{
|
||||
// Get actual bone count from UDP broadcaster
|
||||
if (udpBroadcaster != null)
|
||||
{
|
||||
int actualBoneCount = GetUDPBroadcasterCurrentBoneCount();
|
||||
bool fullDataMode = GetUDPBroadcasterFullDataMode();
|
||||
|
||||
if (showDetailedBreakdown)
|
||||
{
|
||||
string mode = fullDataMode ? "FULL DATA" : "OPTIMIZED";
|
||||
Debug.Log($"UDP Broadcaster is in {mode} mode with {actualBoneCount} bones");
|
||||
}
|
||||
|
||||
return actualBoneCount;
|
||||
}
|
||||
|
||||
// Default to optimized mode bone count
|
||||
return 20;
|
||||
}
|
||||
|
||||
int GetNewSystemBlendShapeCount()
|
||||
{
|
||||
// Get actual blend shape count from UDP broadcaster
|
||||
if (udpBroadcaster != null)
|
||||
{
|
||||
int actualBlendShapeCount = GetUDPBroadcasterCurrentBlendShapeCount();
|
||||
bool fullDataMode = GetUDPBroadcasterFullDataMode();
|
||||
|
||||
if (showDetailedBreakdown)
|
||||
{
|
||||
string mode = fullDataMode ? "FULL DATA" : "OPTIMIZED";
|
||||
Debug.Log($"UDP Broadcaster is in {mode} mode with {actualBlendShapeCount} blend shapes");
|
||||
}
|
||||
|
||||
return actualBlendShapeCount;
|
||||
}
|
||||
|
||||
// Default to optimized mode blend shape count
|
||||
return 10;
|
||||
}
|
||||
|
||||
object[] GenerateOldSystemBones(int count)
|
||||
{
|
||||
object[] bones = new object[count];
|
||||
string[] boneNames = {
|
||||
"Hips", "Spine", "Spine1", "Spine2", "Neck", "Head", "HeadTop_End",
|
||||
"LeftEye", "RightEye", "LeftShoulder", "LeftArm", "LeftArmTwist",
|
||||
"LeftForeArm", "LeftForeArmTwist", "LeftHand", "LeftHandThumb1",
|
||||
"LeftHandThumb2", "LeftHandThumb3", "LeftHandThumb4", "LeftHandIndex0",
|
||||
"LeftHandIndex1", "LeftHandIndex2", "LeftHandIndex3", "LeftHandIndex4",
|
||||
"LeftHandMiddle0", "LeftHandMiddle1", "LeftHandMiddle2", "LeftHandMiddle3",
|
||||
"LeftHandMiddle4", "LeftHandRing0", "LeftHandRing1", "LeftHandRing2",
|
||||
"LeftHandRing3", "LeftHandRing4", "LeftHandPinky0", "LeftHandPinky1",
|
||||
"LeftHandPinky2", "LeftHandPinky3", "LeftHandPinky4", "LeftPalm",
|
||||
"RightShoulder", "RightArm", "RightArmTwist", "RightForeArm",
|
||||
"RightForeArmTwist", "RightHand", "RightHandThumb1", "RightHandThumb2",
|
||||
"RightHandThumb3", "RightHandThumb4", "RightHandIndex0", "RightHandIndex1",
|
||||
"RightHandIndex2", "RightHandIndex3", "RightHandIndex4", "RightHandMiddle0",
|
||||
"RightHandMiddle1", "RightHandMiddle2", "RightHandMiddle3", "RightHandMiddle4",
|
||||
"RightHandRing0", "RightHandRing1", "RightHandRing2", "RightHandRing3",
|
||||
"RightHandRing4", "RightHandPinky0", "RightHandPinky1", "RightHandPinky2",
|
||||
"RightHandPinky3", "RightHandPinky4", "RightPalm", "LeftUpLeg", "LeftLeg",
|
||||
"LeftFoot", "LeftToeBase", "LeftToe_End", "RightUpLeg", "RightLeg",
|
||||
"RightFoot", "RightToeBase", "RightToe_End"
|
||||
};
|
||||
|
||||
for (int i = 0; i < count; i++)
|
||||
{
|
||||
string boneName = i < boneNames.Length ? boneNames[i] : $"Bone_{i}";
|
||||
bones[i] = new
|
||||
{
|
||||
boneName = boneName,
|
||||
position = new { x = UnityEngine.Random.Range(-1f, 1f), y = UnityEngine.Random.Range(-1f, 1f), z = UnityEngine.Random.Range(-1f, 1f) },
|
||||
rotation = new { x = UnityEngine.Random.Range(-1f, 1f), y = UnityEngine.Random.Range(-1f, 1f), z = UnityEngine.Random.Range(-1f, 1f), w = UnityEngine.Random.Range(-1f, 1f) },
|
||||
scale = new { x = 1f, y = 1f, z = 1f }
|
||||
};
|
||||
}
|
||||
|
||||
return bones;
|
||||
}
|
||||
|
||||
object[] GenerateOldSystemBlendShapes(int meshCount, int weightsPerMesh)
|
||||
{
|
||||
object[] blendShapes = new object[meshCount];
|
||||
string[] meshNames = { "Renderer_Head", "Renderer_EyeLeft", "Renderer_EyeRight", "Renderer_Teeth" };
|
||||
|
||||
for (int i = 0; i < meshCount; i++)
|
||||
{
|
||||
float[] weights = new float[weightsPerMesh];
|
||||
for (int j = 0; j < weightsPerMesh; j++)
|
||||
{
|
||||
weights[j] = UnityEngine.Random.Range(0f, 100f);
|
||||
}
|
||||
|
||||
blendShapes[i] = new
|
||||
{
|
||||
meshName = i < meshNames.Length ? meshNames[i] : $"Mesh_{i}",
|
||||
weights = weights
|
||||
};
|
||||
}
|
||||
|
||||
return blendShapes;
|
||||
}
|
||||
|
||||
void ShowDetailedBreakdown()
|
||||
{
|
||||
int newSystemBones = GetNewSystemBoneCount();
|
||||
int newSystemBlendShapes = GetNewSystemBlendShapeCount();
|
||||
int totalOldBlendShapes = oldSystemMeshCount * oldSystemBlendShapesPerMesh;
|
||||
bool fullDataMode = GetUDPBroadcasterFullDataMode();
|
||||
string currentMode = fullDataMode ? "FULL DATA" : "OPTIMIZED";
|
||||
|
||||
Debug.Log($"\n📋 DETAILED BREAKDOWN:");
|
||||
Debug.Log($"\nCurrent UDP System Configuration:");
|
||||
Debug.Log($" • Mode: {currentMode}");
|
||||
Debug.Log($" • Update Rate: {updateRate} Hz");
|
||||
Debug.Log($" • Bones: {newSystemBones}");
|
||||
Debug.Log($" • Blend Shapes: {newSystemBlendShapes}");
|
||||
|
||||
Debug.Log($"\nOld JSON System Issues:");
|
||||
Debug.Log($" • {oldSystemBoneCount} bones with full transform data");
|
||||
Debug.Log($" • {oldSystemMeshCount} meshes × {oldSystemBlendShapesPerMesh} blend shapes = {totalOldBlendShapes} facial weights");
|
||||
Debug.Log($" • Verbose JSON with field names repeated");
|
||||
Debug.Log($" • UTF-8 string encoding overhead");
|
||||
Debug.Log($" • HTTP headers and protocol overhead");
|
||||
Debug.Log($" • Requires Python server infrastructure");
|
||||
|
||||
Debug.Log($"\nNew UDP Binary Advantages:");
|
||||
if (fullDataMode)
|
||||
{
|
||||
Debug.Log($" • {newSystemBones} bones (FULL avatar data)");
|
||||
Debug.Log($" • {newSystemBlendShapes} facial blend shapes (ALL expressions)");
|
||||
}
|
||||
else
|
||||
{
|
||||
Debug.Log($" • Only {newSystemBones} priority bones (most important)");
|
||||
Debug.Log($" • {newSystemBlendShapes} key facial blend shapes only");
|
||||
}
|
||||
Debug.Log($" • Compact binary format, no field names");
|
||||
Debug.Log($" • Variable-size packets with length prefixes");
|
||||
Debug.Log($" • Direct UDP broadcast, no server needed");
|
||||
Debug.Log($" • Predictable network usage");
|
||||
|
||||
float boneReduction = (1f - (float)newSystemBones / oldSystemBoneCount) * 100f;
|
||||
float blendShapeReduction = (1f - (float)newSystemBlendShapes / totalOldBlendShapes) * 100f;
|
||||
Debug.Log($"\nData Reduction vs Old System:");
|
||||
Debug.Log($" • Bones: {boneReduction:F1}% reduction ({oldSystemBoneCount} → {newSystemBones})");
|
||||
Debug.Log($" • Blend Shapes: {blendShapeReduction:F1}% reduction ({totalOldBlendShapes} → {newSystemBlendShapes})");
|
||||
}
|
||||
|
||||
void ShowNetworkImpact(int jsonSize, int binarySize)
|
||||
{
|
||||
Debug.Log($"\n🌐 NETWORK IMPACT (at {updateRate} Hz):");
|
||||
|
||||
float jsonBandwidthKBps = (jsonSize * updateRate) / 1024f;
|
||||
float binaryBandwidthKBps = (binarySize * updateRate) / 1024f;
|
||||
|
||||
Debug.Log($"Old System: {jsonBandwidthKBps:F1} KB/s per player");
|
||||
Debug.Log($"New System: {binaryBandwidthKBps:F1} KB/s per player");
|
||||
|
||||
// Calculate for 3 player setup
|
||||
int playerCount = 3;
|
||||
Debug.Log($"\n3 Player Setup:");
|
||||
Debug.Log($"Old System: {jsonBandwidthKBps * playerCount:F1} KB/s total");
|
||||
Debug.Log($"New System: {binaryBandwidthKBps * playerCount:F1} KB/s total");
|
||||
|
||||
Debug.Log($"\nData usage per hour (single player):");
|
||||
float oldMBPerHour = (jsonBandwidthKBps * 3600) / 1024;
|
||||
float newMBPerHour = (binaryBandwidthKBps * 3600) / 1024;
|
||||
Debug.Log($"Old System: {oldMBPerHour:F1} MB/hour");
|
||||
Debug.Log($"New System: {newMBPerHour:F1} MB/hour");
|
||||
Debug.Log($"Savings: {oldMBPerHour - newMBPerHour:F1} MB/hour ({((oldMBPerHour - newMBPerHour) / oldMBPerHour) * 100:F1}% reduction)");
|
||||
}
|
||||
|
||||
void ShowSystemComplexity()
|
||||
{
|
||||
float codeReduction = (1f - (float)newSystemTotalLines / oldSystemTotalLines) * 100f;
|
||||
|
||||
Debug.Log($"\n⚙️ SYSTEM COMPLEXITY:");
|
||||
Debug.Log($"\nOld System Components:");
|
||||
Debug.Log($" • avatar_sync_server.py");
|
||||
Debug.Log($" • AvatarSyncClient.cs");
|
||||
Debug.Log($" • AvatarDataUploader.cs");
|
||||
Debug.Log($" • AvatarDataDownloader.cs");
|
||||
Debug.Log($" • AvatarDataWriter.cs");
|
||||
Debug.Log($" • AvatarDataReader.cs");
|
||||
Debug.Log($" • Multiple serialization classes");
|
||||
Debug.Log($" • HTTP client/server infrastructure");
|
||||
Debug.Log($" Total: ~{oldSystemTotalLines:N0} lines of code");
|
||||
|
||||
Debug.Log($"\nNew System Components:");
|
||||
Debug.Log($" • UDPAvatarBroadcaster.cs");
|
||||
Debug.Log($" • UDPAvatarReceiver.cs");
|
||||
Debug.Log($" • Simple binary serialization");
|
||||
Debug.Log($" • No server infrastructure needed");
|
||||
Debug.Log($" Total: ~{newSystemTotalLines:N0} lines of code");
|
||||
|
||||
Debug.Log($"\n✅ New system is {codeReduction:F1}% less code and much simpler!");
|
||||
Debug.Log($"Code reduction: {oldSystemTotalLines:N0} → {newSystemTotalLines:N0} lines ({oldSystemTotalLines - newSystemTotalLines:N0} lines removed)");
|
||||
}
|
||||
|
||||
void SaveComparisonToFile(int jsonSize, int binarySize)
|
||||
{
|
||||
try
|
||||
{
|
||||
// Calculate all metrics using dynamic values
|
||||
float compressionRatio = (float)jsonSize / binarySize;
|
||||
float bandwidthReduction = (1f - (float)binarySize / jsonSize) * 100f;
|
||||
float jsonBandwidthKBps = (jsonSize * updateRate) / 1024f;
|
||||
float binaryBandwidthKBps = (binarySize * updateRate) / 1024f;
|
||||
|
||||
// Get calculated counts
|
||||
int newSystemBones = GetNewSystemBoneCount();
|
||||
int newSystemBlendShapes = GetNewSystemBlendShapeCount();
|
||||
int totalOldBlendShapes = oldSystemMeshCount * oldSystemBlendShapesPerMesh;
|
||||
bool fullDataMode = GetUDPBroadcasterFullDataMode();
|
||||
string currentMode = fullDataMode ? "FULL DATA" : "OPTIMIZED";
|
||||
|
||||
// Create file content with just the data
|
||||
StringBuilder fileContent = new StringBuilder();
|
||||
fileContent.AppendLine("Avatar Sync System Comparison Results");
|
||||
fileContent.AppendLine($"Generated: {DateTime.Now:yyyy-MM-dd HH:mm:ss}");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// Size comparison
|
||||
fileContent.AppendLine("PACKET SIZE COMPARISON:");
|
||||
fileContent.AppendLine($"Old JSON System: {jsonSize:N0} bytes ({jsonSize / 1024f:F2} KB)");
|
||||
fileContent.AppendLine($"New UDP Binary: {binarySize:N0} bytes ({binarySize / 1024f:F2} KB)");
|
||||
fileContent.AppendLine($"Compression Ratio: {compressionRatio:F1}x smaller");
|
||||
fileContent.AppendLine($"Size Reduction: {bandwidthReduction:F1}%");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// Binary structure breakdown using calculated values
|
||||
int headerSize = 1 + 4 + 4 + 1; // playerID + sequenceNumber + timestamp + isFullDataMode
|
||||
int rootTransformSize = (3 + 4 + 3) * 4;
|
||||
int bonesSize = 4 + (newSystemBones * (3 + 4) * 4);
|
||||
int blendShapesSize = 4 + (newSystemBlendShapes * 4);
|
||||
|
||||
fileContent.AppendLine("UDP BINARY STRUCTURE:");
|
||||
fileContent.AppendLine($"Header: {headerSize} bytes");
|
||||
fileContent.AppendLine($"Root Transform: {rootTransformSize} bytes");
|
||||
fileContent.AppendLine($"Bones ({newSystemBones}): {bonesSize} bytes");
|
||||
fileContent.AppendLine($"Blend Shapes ({newSystemBlendShapes}): {blendShapesSize} bytes");
|
||||
fileContent.AppendLine($"Total: {binarySize} bytes");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// Bandwidth impact at configured rate
|
||||
fileContent.AppendLine($"BANDWIDTH USAGE ({updateRate} Hz):");
|
||||
fileContent.AppendLine($"Old System: {jsonBandwidthKBps:F1} KB/s per player");
|
||||
fileContent.AppendLine($"New System: {binaryBandwidthKBps:F1} KB/s per player");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// System details
|
||||
fileContent.AppendLine("SYSTEM DETAILS:");
|
||||
fileContent.AppendLine($"Update Rate: {updateRate} Hz");
|
||||
fileContent.AppendLine($"UDP Mode: {currentMode}");
|
||||
fileContent.AppendLine($"Old System: {oldSystemBoneCount} bones, {totalOldBlendShapes} blend shapes ({oldSystemMeshCount} meshes × {oldSystemBlendShapesPerMesh})");
|
||||
fileContent.AppendLine($"New System: {newSystemBones} bones, {newSystemBlendShapes} blend shapes");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// 3 Player setup bandwidth
|
||||
int players = 3;
|
||||
float oldTotal = jsonBandwidthKBps * players;
|
||||
float newTotal = binaryBandwidthKBps * players;
|
||||
fileContent.AppendLine("3 PLAYER SETUP BANDWIDTH:");
|
||||
fileContent.AppendLine($"Old System: {oldTotal:F1} KB/s total");
|
||||
fileContent.AppendLine($"New System: {newTotal:F1} KB/s total");
|
||||
fileContent.AppendLine($"Bandwidth Savings: {oldTotal - newTotal:F1} KB/s ({((oldTotal - newTotal) / oldTotal) * 100:F1}% reduction)");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// Data usage per hour
|
||||
float oldMBPerHour = (jsonBandwidthKBps * 3600) / 1024;
|
||||
float newMBPerHour = (binaryBandwidthKBps * 3600) / 1024;
|
||||
fileContent.AppendLine("DATA USAGE PER HOUR (single player):");
|
||||
fileContent.AppendLine($"Old System: {oldMBPerHour:F1} MB/hour");
|
||||
fileContent.AppendLine($"New System: {newMBPerHour:F1} MB/hour");
|
||||
fileContent.AppendLine($"Savings: {oldMBPerHour - newMBPerHour:F1} MB/hour ({((oldMBPerHour - newMBPerHour) / oldMBPerHour) * 100:F1}% reduction)");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// Code complexity
|
||||
float codeReduction = (1f - (float)newSystemTotalLines / oldSystemTotalLines) * 100f;
|
||||
fileContent.AppendLine("CODE COMPLEXITY:");
|
||||
fileContent.AppendLine($"Old System: ~{oldSystemTotalLines:N0} lines (6 components + Python server)");
|
||||
fileContent.AppendLine($"New System: ~{newSystemTotalLines:N0} lines (2 components, no server)");
|
||||
fileContent.AppendLine($"Code Reduction: {codeReduction:F1}% ({oldSystemTotalLines - newSystemTotalLines:N0} lines removed)");
|
||||
fileContent.AppendLine();
|
||||
|
||||
// Performance characteristics
|
||||
fileContent.AppendLine("PERFORMANCE CHARACTERISTICS:");
|
||||
fileContent.AppendLine("Old System: HTTP request/response, JSON parsing, server dependency");
|
||||
fileContent.AppendLine("New System: UDP broadcast, binary format, peer-to-peer");
|
||||
fileContent.AppendLine("Latency: Local network UDP (~1-10ms vs HTTP ~10-50ms)");
|
||||
fileContent.AppendLine("Infrastructure: None required (vs Python server)");
|
||||
|
||||
// Write to file
|
||||
string filePath = Path.Combine(Application.dataPath, outputFileName);
|
||||
File.WriteAllText(filePath, fileContent.ToString());
|
||||
|
||||
Debug.Log($"Comparison data saved to: {filePath}");
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError($"Failed to save comparison to file: {e.Message}");
|
||||
}
|
||||
}
|
||||
|
||||
void OnGUI()
|
||||
{
|
||||
if (GUI.Button(new Rect(10, Screen.height - 40, 200, 30), "Run Comparison"))
|
||||
{
|
||||
RunComparison();
|
||||
}
|
||||
|
||||
if (GUI.Button(new Rect(220, Screen.height - 40, 150, 30), "Save to File"))
|
||||
{
|
||||
var jsonSize = CalculateJSONSystemSize();
|
||||
var binarySize = CalculateUDPBinarySize();
|
||||
SaveComparisonToFile(jsonSize, binarySize);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user