### Vector3 and Quaternion Math Operations in C# Source: https://context7.com/beatleader/replaydecoder/llms.txt Demonstrates various mathematical operations for 3D vectors (Vector3) and rotations (Quaternion) using the ReplayDecoder library. Includes basic arithmetic, normalization, dot and cross products, interpolation, and conversions. Assumes the ReplayDecoder namespace and relevant Vector3/Quaternion classes are available. ```csharp using ReplayDecoder; using System; // Vector3 operations Vector3 v1 = new Vector3(1.0f, 2.0f, 3.0f); Vector3 v2 = new Vector3(4.0f, 5.0f, 6.0f); // Basic operations Vector3 sum = v1 + v2; Vector3 diff = v2 - v1; Vector3 scaled = v1 * 2.0f; Vector3 divided = v2 / 2.0f; Console.WriteLine($"Sum: ({sum.x}, {sum.y}, {sum.z})"); Console.WriteLine($"Magnitude of v1: {Vector3.Magnitude(v1)}"); // Normalization Vector3 normalized = Vector3.Normalize(v1); Console.WriteLine($"Normalized: ({normalized.x}, {normalized.y}, {normalized.z})"); // Dot product float dot = Vector3.Dot(v1, v2); Console.WriteLine($"Dot product: {dot}"); // Cross product Vector3 cross = Vector3.Cross(v1, v2); Console.WriteLine($"Cross product: ({cross.x}, {cross.y}, {cross.z})"); // Angle between vectors float angle = Vector3.Angle(v1, v2); Console.WriteLine($"Angle between vectors: {angle}°"); // Linear interpolation Vector3 lerped = Vector3.Lerp(v1, v2, 0.5f); Console.WriteLine($"Lerp 50%: ({lerped.x}, {lerped.y}, {lerped.z})"); // Static vectors Console.WriteLine($"Up: ({Vector3.up.x}, {Vector3.up.y}, {Vector3.up.z})"); Console.WriteLine($"Forward: ({Vector3.forward.x}, {Vector3.forward.y}, {Vector3.forward.z})"); Console.WriteLine($"Right: ({Vector3.right.x}, {Vector3.right.y}, {Vector3.right.z})"); // Quaternion operations Quaternion q1 = new Quaternion(0.0f, 0.707f, 0.0f, 0.707f); Quaternion q2 = new Quaternion(0.0f, 0.0f, 0.707f, 0.707f); // Quaternion multiplication Quaternion qMult = q1 * q2; Console.WriteLine($"Q multiply: ({qMult.x}, {qMult.y}, {qMult.z}, {qMult.w})"); // Rotate vector by quaternion Vector3 rotated = q1 * v1; Console.WriteLine($"Rotated vector: ({rotated.x}, {rotated.y}, {rotated.z})"); // Convert quaternion to axis-angle var (axis, axisAngle) = Quaternion.QuatToAxisAngle(q1); Console.WriteLine($"Axis: ({axis.x}, {axis.y}, {axis.z}), Angle: {axisAngle} radians"); // Create quaternion from axis-angle Quaternion fromAxis = Quaternion.AxisAngleToQuat(Vector3.up, 1.57f); Console.WriteLine($"From axis-angle: ({fromAxis.x}, {fromAxis.y}, {fromAxis.z}, {fromAxis.w})"); // Create rotation from one vector to another Quaternion rotation = Quaternion.FromToRotation(Vector3.forward, Vector3.up); Console.WriteLine($"From-to rotation: ({rotation.x}, {rotation.y}, {rotation.z}, {rotation.w})"); // Quaternion lerp Quaternion qLerped = Quaternion.Lerp(q1, q2, 0.5f); Console.WriteLine($"Q lerp 50%: ({qLerped.x}, {qLerped.y}, {qLerped.z}, {qLerped.w})"); ``` -------------------------------- ### Async Decode Replay from Stream (C#) Source: https://context7.com/beatleader/replaydecoder/llms.txt Asynchronously decodes a replay file from a stream, supporting progressive loading. It first retrieves basic replay information and then loads the full replay data, including frames, events, and custom data. Requires the ReplayDecoder library and System.IO, System.Threading.Tasks namespaces. ```csharp using ReplayDecoder; using System.IO; using System.Threading.Tasks; async Task DecodeReplayAsync(string filePath) { var decoder = new AsyncReplayDecoder(); using (FileStream stream = File.OpenRead(filePath)) { // Start decoding and get info immediately var (info, continueTask) = await decoder.StartDecodingStream(stream); if (info != null && continueTask != null) { // Info is available immediately Console.WriteLine($"Player: {info.playerName}"); Console.WriteLine($"Score: {info.score}"); Console.WriteLine($"Song: {info.songName} by {info.mapper}"); Console.WriteLine($"Hash: {info.hash}"); Console.WriteLine($"Game Version: {info.gameVersion}"); Console.WriteLine($"Timestamp: {info.timestamp}"); // Continue loading the rest of the replay Replay? fullReplay = await continueTask; if (fullReplay != null) { Console.WriteLine($"Loaded {fullReplay.frames.Count} frames"); Console.WriteLine($"Loaded {fullReplay.notes.Count} note events"); Console.WriteLine($"Loaded {fullReplay.walls.Count} wall events"); Console.WriteLine($"Loaded {fullReplay.pauses.Count} pauses"); // Access saber offsets var saberOffsets = fullReplay.saberOffsets; Console.WriteLine($"Left saber offset: ({saberOffsets.leftSaberLocalPosition.x}, {saberOffsets.leftSaberLocalPosition.y}, {saberOffsets.leftSaberLocalPosition.z})"); // Access custom data foreach (var kvp in fullReplay.customData) { Console.WriteLine($"Custom data key: {kvp.Key}, size: {kvp.Value.Length} bytes"); } } } else { Console.WriteLine("Invalid replay file format"); } } } await DecodeReplayAsync("replay.bsor"); ``` -------------------------------- ### Average Replay Statistics for Leaderboards in C# Source: https://context7.com/beatleader/replaydecoder/llms.txt Aggregates statistics from multiple replay files asynchronously to compute average leaderboard metrics. It decodes replay data, processes individual replay statistics, and then averages them into a comprehensive score statistic object. Requires ReplayDecoder, System.Collections.Generic, System.Threading.Tasks, and System.Linq namespaces. Outputs average win rate, score, combo, misses, and accuracy. ```csharp using ReplayDecoder; using System.Collections.Generic; using System.Threading.Tasks; using System.Linq; async Task AggregateLeaderboardStats(List replayFiles) { // Create async tasks for processing each replay var statisticsTasks = replayFiles.Select(async data => { var (replay, offsets) = ReplayDecoder.ReplayDecoder.Decode(data); if (replay != null) { var (stats, error) = ReplayStatistic.ProcessReplay(replay); return stats; } return null; }); // Create result container ScoreStatistic leaderboardStats = new ScoreStatistic(); // Average all statistics await ReplayStatistic.AverageStatistic(statisticsTasks, leaderboardStats); // Access averaged results Console.WriteLine("Leaderboard Aggregated Statistics:"); Console.WriteLine($"Average Win Rate: {(leaderboardStats.winTracker.won ? 100 : 0)}%"); Console.WriteLine($"Average Score: {leaderboardStats.winTracker.totalScore}"); Console.WriteLine($"Average End Time: {leaderboardStats.winTracker.endTime}s"); Console.WriteLine($"Average Combo: {leaderboardStats.hitTracker.maxCombo}"); Console.WriteLine($"Average Left Misses: {leaderboardStats.hitTracker.leftMiss}"); Console.WriteLine($"Average Right Misses: {leaderboardStats.hitTracker.rightMiss}"); Console.WriteLine($"Average Accuracy: {(leaderboardStats.accuracyTracker.accLeft + leaderboardStats.accuracyTracker.accRight) / 2:F2}"); // Access averaged score graph Console.WriteLine($"Score graph data points: {leaderboardStats.scoreGraphTracker.graph.Count}"); } // Usage example var replayData = new List { File.ReadAllBytes("replay1.bsor"), File.ReadAllBytes("replay2.bsor"), File.ReadAllBytes("replay3.bsor") }; await AggregateLeaderboardStats(replayData); ``` -------------------------------- ### Analyze Note Cut Details in C# Source: https://context7.com/beatleader/replaydecoder/llms.txt Extracts and displays detailed information about individual note cuts from replay data. This includes note properties, scoring details, and cut analysis for both good and bad cuts. It requires the ReplayDecoder library and assumes bsorData is available. ```csharp using ReplayDecoder; var (replay, offsets) = ReplayDecoder.ReplayDecoder.Decode(bsorData); if (replay != null && replay.notes.Count > 0) { foreach (var note in replay.notes) { Console.WriteLine($"\nNote ID: {note.noteID}"); Console.WriteLine($"Event Time: {note.eventTime}s"); Console.WriteLine($"Spawn Time: {note.spawnTime}s"); Console.WriteLine($"Event Type: {note.eventType}"); // Parse note parameters var noteParams = new NoteParams(note.noteID, note.eventType); Console.WriteLine($"Scoring Type: {noteParams.scoringType}"); Console.WriteLine($"Line Index: {noteParams.lineIndex}"); Console.WriteLine($"Note Line Layer: {noteParams.noteLineLayer}"); Console.WriteLine($"Color: {(noteParams.colorType == 0 ? "Left/Red" : "Right/Blue")}"); Console.WriteLine($"Cut Direction: {noteParams.cutDirection}"); // Analyze cut info for good/bad cuts if (note.eventType == NoteEventType.good || note.eventType == NoteEventType.bad) { var cutInfo = note.noteCutInfo; Console.WriteLine($"\nCut Analysis:"); Console.WriteLine($" Speed OK: {cutInfo.speedOK}"); Console.WriteLine($" Direction OK: {cutInfo.directionOK}"); Console.WriteLine($" Saber Type OK: {cutInfo.saberTypeOK}"); Console.WriteLine($" Cut Too Soon: {cutInfo.wasCutTooSoon}"); Console.WriteLine($" Saber Speed: {cutInfo.saberSpeed:F2}"); Console.WriteLine($" Saber Direction: ({cutInfo.saberDir.x:F2}, {cutInfo.saberDir.y:F2}, {cutInfo.saberDir.z:F2})"); Console.WriteLine($" Saber Type: {(cutInfo.saberType == 0 ? "Left" : "Right")}"); Console.WriteLine($" Time Deviation: {cutInfo.timeDeviation:F4}s"); Console.WriteLine($" Cut Direction Deviation: {cutInfo.cutDirDeviation:F2}°"); Console.WriteLine($" Cut Point: ({cutInfo.cutPoint.x:F2}, {cutInfo.cutPoint.y:F2}, {cutInfo.cutPoint.z:F2})"); Console.WriteLine($" Cut Normal: ({cutInfo.cutNormal.x:F2}, {cutInfo.cutNormal.y:F2}, {cutInfo.cutNormal.z:F2})"); Console.WriteLine($" Distance to Center: {cutInfo.cutDistanceToCenter:F2}"); Console.WriteLine($" Cut Angle: {cutInfo.cutAngle:F2}°"); Console.WriteLine($" Before Cut Rating: {cutInfo.beforeCutRating:F2}"); Console.WriteLine($" After Cut Rating: {cutInfo.afterCutRating:F2}"); // Calculate score if (note.score != null) { Console.WriteLine($"\nScore Breakdown:"); Console.WriteLine($" Pre Score: {note.score.pre_score}"); Console.WriteLine($" Post Score: {note.score.post_score}"); Console.WriteLine($" Acc Score: {note.score.acc_score}"); Console.WriteLine($" Total: {note.score.value}"); } } } } ``` -------------------------------- ### Decode Replay Info Only (C#) Source: https://context7.com/beatleader/replaydecoder/llms.txt Efficiently extracts only the metadata (ReplayInfo) from a replay file without loading the full frame data. This is useful when only player and score information is needed. Requires the ReplayDecoder library and System.IO, System.Threading.Tasks namespaces. ```csharp using ReplayDecoder; using System.IO; using System.Threading.Tasks; async Task GetReplayMetadata(string filePath) { var decoder = new AsyncReplayDecoder(); using (FileStream stream = File.OpenRead(filePath)) { ReplayInfo? info = await decoder.DecodeInfoOnly(stream); return info; } } // Usage var metadata = await GetReplayMetadata("replay.bsor"); if (metadata != null) { Console.WriteLine($"Player ID: {metadata.playerID}"); Console.WriteLine($"Player Name: {metadata.playerName}"); Console.WriteLine($"Score: {metadata.score}"); Console.WriteLine($"Mode: {metadata.mode}"); Console.WriteLine($"Environment: {metadata.environment}"); Console.WriteLine($"Modifiers: {metadata.modifiers}"); Console.WriteLine($"Speed: {metadata.speed}"); Console.WriteLine($"Left Handed: {metadata.leftHanded}"); Console.WriteLine($"Height: {metadata.height}m"); Console.WriteLine($"Start Time: {metadata.startTime}s"); Console.WriteLine($"Fail Time: {metadata.failTime}s (negative means completed)"); } ``` -------------------------------- ### Process Replay Statistics with C# Source: https://context7.com/beatleader/replaydecoder/llms.txt This C# code snippet demonstrates how to decode a replay using the ReplayDecoder library and then process the decoded replay to extract comprehensive gameplay statistics. It accesses various trackers like winTracker, hitTracker, accuracyTracker, and scoreGraphTracker to provide detailed insights into player performance. The output includes metrics such as score, accuracy, misses, timing, and accuracy over time. Requires the ReplayDecoder library and bsorData representing the replay. ```csharp using ReplayDecoder; using System; // Assuming you have a decoded replay var (replay, offsets) = ReplayDecoder.ReplayDecoder.Decode(bsorData); if (replay != null) { // Process statistics var (statistics, error) = ReplayStatistic.ProcessReplay(replay); if (statistics != null) { // Win tracker information Console.WriteLine($"Won: {statistics.winTracker.won}"); Console.WriteLine($"Total Score: {statistics.winTracker.totalScore}"); Console.WriteLine($"Max Score: {statistics.winTracker.maxScore}"); Console.WriteLine($"Accuracy: {(float)statistics.winTracker.totalScore / statistics.winTracker.maxScore * 100:F2}%"); Console.WriteLine($"Fail Time: {statistics.winTracker.failTime}s"); Console.WriteLine($"End Time: {statistics.winTracker.endTime}s"); Console.WriteLine($"Pauses: {statistics.winTracker.nbOfPause}"); Console.WriteLine($"Total Pause Duration: {statistics.winTracker.totalPauseDuration}ms"); Console.WriteLine($"Jump Distance: {statistics.winTracker.jumpDistance}"); Console.WriteLine($"Average Height: {statistics.winTracker.averageHeight}m"); // Hit tracker information Console.WriteLine($"\nMax Combo: {statistics.hitTracker.maxCombo}"); if (statistics.hitTracker.maxStreak.HasValue) { Console.WriteLine($"Max Streak (115 cuts): {statistics.hitTracker.maxStreak.Value}"); } Console.WriteLine($"Left Hand - Misses: {statistics.hitTracker.leftMiss}, Bad Cuts: {statistics.hitTracker.leftBadCuts}, Bombs: {statistics.hitTracker.leftBombs}"); Console.WriteLine($"Right Hand - Misses: {statistics.hitTracker.rightMiss}, Bad Cuts: {statistics.hitTracker.rightBadCuts}, Bombs: {statistics.hitTracker.rightBombs}"); Console.WriteLine($"Left Timing: {statistics.hitTracker.leftTiming}s"); Console.WriteLine($"Right Timing: {statistics.hitTracker.rightTiming}s"); // Accuracy tracker information Console.WriteLine($"\nLeft Hand Accuracy: {statistics.accuracyTracker.accLeft:F2}"); Console.WriteLine($"Right Hand Accuracy: {statistics.accuracyTracker.accRight:F2}"); Console.WriteLine($"FC Accuracy: {statistics.accuracyTracker.fcAcc * 100:F2}%"); Console.WriteLine($"Left Preswing: {statistics.accuracyTracker.leftPreswing:F2}"); Console.WriteLine($"Right Preswing: {statistics.accuracyTracker.rightPreswing:F2}"); Console.WriteLine($"Left Postswing: {statistics.accuracyTracker.leftPostswing:F2}"); Console.WriteLine($"Right Postswing: {statistics.accuracyTracker.rightPostswing:F2}"); Console.WriteLine($"Left Time Dependence: {statistics.accuracyTracker.leftTimeDependence:F2}"); Console.WriteLine($"Right Time Dependence: {statistics.accuracyTracker.rightTimeDependence:F2}"); // Average cut scores [before, acc, after] if (statistics.accuracyTracker.leftAverageCut.Count >= 3) { Console.WriteLine($"Left Average Cut: Before={statistics.accuracyTracker.leftAverageCut[0]:F2}, Acc={statistics.accuracyTracker.leftAverageCut[1]:F2}, After={statistics.accuracyTracker.leftAverageCut[2]:F2}"); } if (statistics.accuracyTracker.rightAverageCut.Count >= 3) { Console.WriteLine($"Right Average Cut: Before={statistics.accuracyTracker.rightAverageCut[0]:F2}, Acc={statistics.accuracyTracker.rightAverageCut[1]:F2}, After={statistics.accuracyTracker.rightAverageCut[2]:F2}"); } // Grid accuracy (12 positions: 4 columns x 3 rows) Console.WriteLine("\nGrid Accuracy (4x3):"); for (int layer = 0; layer < 3; layer++) { for (int line = 0; line < 4; line++) { int index = layer * 4 + line; Console.Write($"{statistics.accuracyTracker.gridAcc[index]:F1} "); } Console.WriteLine(); } // Score graph tracker (accuracy over time) Console.WriteLine($"\nScore graph points: {statistics.scoreGraphTracker.graph.Count}"); // Example: Plot accuracy at 10-second intervals for (int i = 0; i < statistics.scoreGraphTracker.graph.Count; i += 10) { Console.WriteLine($"Time {i}s: {statistics.scoreGraphTracker.graph[i] * 100:F2}% accuracy"); } } else { Console.WriteLine($"Error processing replay: {error}"); } } ``` -------------------------------- ### Encode Replay to Binary in C# Source: https://context7.com/beatleader/replaydecoder/llms.txt Encodes a Replay object into the BSOR binary format and writes it to a file. This function requires the ReplayDecoder library and standard .NET file I/O operations. It takes a Replay object as input and outputs a file stream. ```csharp using ReplayDecoder; using System.IO; // Assuming you have a Replay object (decoded or created) Replay replay = new Replay(); // Populate replay info replay.info = new ReplayInfo { version = "2.0.0", gameVersion = "1.29.1", timestamp = "2024-12-08T12:00:00Z", playerID = "76561198000000000", playerName = "TestPlayer", platform = "steam", trackingSystem = "OpenVR", hmd = "Valve Index", controller = "Valve Index Controllers", hash = "abc123def456", songName = "Test Song", mapper = "Test Mapper", difficulty = "ExpertPlus", score = 500000, mode = "Standard", environment = "DefaultEnvironment", modifiers = "SS,FS", jumpDistance = 23.0f, leftHanded = false, height = 1.75f, startTime = 0.0f, failTime = -1.0f, speed = 1.0f }; // Add frames, notes, etc. // replay.frames.Add(...); // replay.notes.Add(...); // Encode to file using (FileStream fs = File.Create("output.bsor")) using (BinaryWriter writer = new BinaryWriter(fs)) { ReplayOffsets offsets = ReplayEncoder.Encode(replay, writer); Console.WriteLine($"Replay encoded successfully"); Console.WriteLine($"Frames offset: {offsets.Frames}"); Console.WriteLine($"Notes offset: {offsets.Notes}"); Console.WriteLine($"Walls offset: {offsets.Walls}"); Console.WriteLine($"Heights offset: {offsets.Heights}"); Console.WriteLine($"Pauses offset: {offsets.Pauses}"); Console.WriteLine($"Saber offsets: {offsets.SaberOffsets}"); Console.WriteLine($"Custom data offset: {offsets.CustomData}"); } ``` -------------------------------- ### Decode BSOR Replay from Byte Array in C# Source: https://context7.com/beatleader/replaydecoder/llms.txt Synchronously decodes a Beat Saber replay file from a byte array. This function reads the BSOR data, parses metadata, frame data, and note events, providing access to player information, scoring, and gameplay details. It requires the ReplayDecoder namespace and System.IO. ```csharp using ReplayDecoder; using System.IO; // Load BSOR file from disk byte[] bsorData = File.ReadAllBytes("replay.bsor"); // Decode the replay var (replay, offsets) = ReplayDecoder.ReplayDecoder.Decode(bsorData); if (replay != null) { // Access replay information Console.WriteLine($"Player: {replay.info.playerName}"); Console.WriteLine($"Score: {replay.info.score}"); Console.WriteLine($"Song: {replay.info.songName}"); Console.WriteLine($"Difficulty: {replay.info.difficulty}"); Console.WriteLine($"Platform: {replay.info.platform}"); Console.WriteLine($"HMD: {replay.info.hmd}"); Console.WriteLine($"Controller: {replay.info.controller}"); // Access frame data Console.WriteLine($"Total frames: {replay.frames.Count}"); if (replay.frames.Count > 0) { var firstFrame = replay.frames[0]; Console.WriteLine($"First frame time: {firstFrame.time}s"); Console.WriteLine($"FPS: {firstFrame.fps}"); Console.WriteLine($"Head position: ({firstFrame.head.position.x}, {firstFrame.head.position.y}, {firstFrame.head.position.z})"); } // Access note events Console.WriteLine($"Total notes: {replay.notes.Count}"); int goodCuts = replay.notes.Count(n => n.eventType == NoteEventType.good); int badCuts = replay.notes.Count(n => n.eventType == NoteEventType.bad); int misses = replay.notes.Count(n => n.eventType == NoteEventType.miss); Console.WriteLine($"Good cuts: {goodCuts}, Bad cuts: {badCuts}, Misses: {misses}"); } else { Console.WriteLine("Failed to decode replay"); } ``` === COMPLETE CONTENT === This response contains all available snippets from this library. No additional content exists. Do not make further requests.