Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
26 commits
Select commit Hold shift + click to select a range
6dd0dd9
Modify TTS initialization to remove Discord auth
heisthecat31 Nov 25, 2025
9ba63c1
Update join button to use echo taxi HTTPS link
heisthecat31 Nov 26, 2025
920a800
Update link format for echo taxi link
heisthecat31 Nov 26, 2025
c947930
Update link generation to echo taxi link, fixed spelling mistake
heisthecat31 Nov 27, 2025
478c912
Add auto-follow timer functionality to spectator camera
heisthecat31 Nov 29, 2025
bd01bc9
Remove Rumble buttons and update warning text
heisthecat31 Nov 29, 2025
3e258c1
Remove Rumble installation and download logic
heisthecat31 Nov 29, 2025
8e29d39
Update Discord API version from v6 to v10
heisthecat31 Nov 29, 2025
4dd5c1b
Refactor CreateServerControls.xaml layout and styles
heisthecat31 Dec 3, 2025
7a71543
Refactor CreateServerControls with new features
heisthecat31 Dec 3, 2025
fc29b3f
Revise README with new features and installation info
heisthecat31 Dec 3, 2025
759e000
Add files via upload
heisthecat31 Dec 6, 2025
053d856
Delete Windows/LiveWindow/PlayerStats.xaml
heisthecat31 Dec 6, 2025
d0c8870
Delete Windows/LiveWindow/PlayerStats.xaml.cs
heisthecat31 Dec 6, 2025
715f1b4
Update TTS string to reflect new functionality
heisthecat31 Dec 10, 2025
d08b3f0
Update README with new features and installation
heisthecat31 Dec 10, 2025
17f4091
Add screenshots to README for visual enhancement
heisthecat31 Dec 10, 2025
b29219d
Clarify colour themes section in README
heisthecat31 Dec 10, 2025
6b60e38
Add new screenshot to README
heisthecat31 Dec 14, 2025
2caf9f8
Refactor player statistics data parsing
heisthecat31 Dec 29, 2025
25a1a2f
Refactor xplatformid validation logic
heisthecat31 Dec 29, 2025
b7b19dd
add ttsSpeedIndex
heisthecat31 Dec 30, 2025
d42df04
Refactor TTSController for clarity and speed handling
heisthecat31 Dec 30, 2025
5963a1e
Change license
Germ-99 Jan 2, 2026
e1bd20b
Change license from Commons Clause to GPLv3
Germ-99 Jan 2, 2026
c5740b9
Merge pull request #1 from Germ-99/patch-2
heisthecat31 Jan 4, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
87 changes: 78 additions & 9 deletions Controllers/CameraWrite/CameraWriteController.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
using Newtonsoft.Json;
using Newtonsoft.Json;
using System;
using System.Collections.Generic;
using System.Diagnostics;
Expand All @@ -17,6 +17,7 @@ class CameraWriteController
{
private static string BaseUrl => "http://127.0.0.1:" + (Program.spectateMeController.spectateMe ? SpectateMeController.SPECTATEME_PORT : "6721") + "/";
private static Dictionary<string, int> playerCameraIndices = new Dictionary<string, int>();
private static System.Timers.Timer autoFollowTimer;

public const float Deg2Rad = 1 / 57.29578f;
public const float Rad2Deg = 57.29578f;
Expand All @@ -42,7 +43,14 @@ public CameraWriteController()
{
UseCameraControlKeys();
playerCameraIndices.Clear();
StartAutoFollowTimer();
};

Program.LeftGame += (_) =>
{
StopAutoFollowTimer();
};

Program.PlayerJoined += (_, _, _) => { UseCameraControlKeys(); };
Program.PlayerLeft += (_, _, _) => { UseCameraControlKeys(); };
Program.PlayerSwitchedTeams += (_, _, _, _) => { UseCameraControlKeys(); };
Expand All @@ -55,6 +63,47 @@ public CameraWriteController()
};
}

private static void StartAutoFollowTimer()
{
StopAutoFollowTimer();

// Only start timer if we're in specific player follow mode
if (SparkSettings.instance.spectatorCamera == 3 &&
!string.IsNullOrEmpty(SparkSettings.instance.followPlayerName))
{
autoFollowTimer = new System.Timers.Timer(2000); // 10 seconds
autoFollowTimer.Elapsed += (sender, e) => AutoFollowPlayer();
autoFollowTimer.AutoReset = true;
autoFollowTimer.Start();
LogRow(LogType.File, "Started auto-follow timer for player: " + SparkSettings.instance.followPlayerName);
}
}

private static void StopAutoFollowTimer()
{
autoFollowTimer?.Stop();
autoFollowTimer?.Dispose();
autoFollowTimer = null;
}

private static void AutoFollowPlayer()
{
if (Program.lastFrame == null) return;

// Only auto-follow if we're still in the specific player follow mode
if (SparkSettings.instance.spectatorCamera == 3 &&
!string.IsNullOrEmpty(SparkSettings.instance.followPlayerName))
{
LogRow(LogType.File, "Auto-following player: " + SparkSettings.instance.followPlayerName);
SpectatorCamFindPlayer(SparkSettings.instance.followPlayerName, null, true);
}
else
{
// Stop timer if we're no longer in follow mode
StopAutoFollowTimer();
}
}

public static void UseCameraControlKeys()
{
try
Expand All @@ -68,20 +117,25 @@ public static void UseCameraControlKeys()
{
// auto
case 0:
StopAutoFollowTimer();
break;
// sideline
case 1:
StopAutoFollowTimer();
SetCameraMode(CameraMode.side);
break;
// follow client
case 2:
StopAutoFollowTimer();
if (Program.spectateMeController.spectateMe) SpectatorCamFindPlayer();
break;
// follow specific player
case 3:
SpectatorCamFindPlayer(SparkSettings.instance.followPlayerName);
StartAutoFollowTimer(); // Start timer when manually switching to this mode
break;
case 4:
StopAutoFollowTimer();
FollowDischolder(null, SparkSettings.instance.discHolderFollowCamMode == 1, SparkSettings.instance.discHolderFollowRestrictTeam);
break;
}
Expand All @@ -92,15 +146,18 @@ public static void UseCameraControlKeys()
}
}

public static void SpectatorCamFindPlayer(string playerName = null, CameraMode? mode = null)
public static void SpectatorCamFindPlayer(string playerName = null, CameraMode? mode = null, bool isAutoFollow = false)
{
if (Program.lastFrame == null) return;

playerName ??= Program.lastFrame.client_name;

if (Program.lastFrame.GetPlayer(playerName) == null)
{
LogRow(LogType.File, Program.lastFrame.sessionid, "Requested follow player not in the game.");
if (!isAutoFollow) // Only log if this wasn't an automatic attempt
{
LogRow(LogType.File, Program.lastFrame.sessionid, "Requested follow player not in the game.");
}
return;
}

Expand All @@ -118,7 +175,10 @@ public static void SpectatorCamFindPlayer(string playerName = null, CameraMode?
SetCameraMode(CameraMode.pov, playerCameraIndices[playerName]);
await Task.Delay(50);
(Player minPlayer, float dist) = await CheckNearestPlayer();
LoggerEvents.Log(Program.lastFrame, $"Initial player camera distance: {dist:N3} m. Name: {minPlayer.name}");
if (!isAutoFollow)
{
LoggerEvents.Log(Program.lastFrame, $"Initial player camera distance: {dist:N3} m. Name: {minPlayer.name}");
}
found = minPlayer.name == playerName;
foundIndex = playerCameraIndices[playerName];
}
Expand All @@ -136,7 +196,10 @@ public static void SpectatorCamFindPlayer(string playerName = null, CameraMode?
await Task.Delay(50);

(Player minPlayer, float dist) = await CheckNearestPlayer();
LoggerEvents.Log(Program.lastFrame, $"Player {i} camera distance: {dist:N3} m. Name: {minPlayer.name}");
if (!isAutoFollow)
{
LoggerEvents.Log(Program.lastFrame, $"Player {i} camera distance: {dist:N3} m. Name: {minPlayer.name}");
}
found = minPlayer.name == playerName;
playerCameraIndices[minPlayer.name] = i;

Expand All @@ -153,7 +216,10 @@ public static void SpectatorCamFindPlayer(string playerName = null, CameraMode?

if (found)
{
LogRow(LogType.File, Program.lastFrame.sessionid, "Correct player found.");
if (!isAutoFollow)
{
LogRow(LogType.File, Program.lastFrame.sessionid, "Correct player found.");
}
if (mode != null)
{
SetCameraMode((CameraMode)mode, foundIndex);
Expand All @@ -173,7 +239,7 @@ public static void SpectatorCamFindPlayer(string playerName = null, CameraMode?
}
}
}
else
else if (!isAutoFollow) // Only log failure if this wasn't an automatic attempt
{
LogRow(LogType.File, Program.lastFrame.sessionid,
"Failed to find player, switching to auto instead.");
Expand All @@ -184,7 +250,10 @@ public static void SpectatorCamFindPlayer(string playerName = null, CameraMode?
}
catch (Exception ex)
{
LogRow(LogType.Error, $"Error with finding player camera to follow.\n{ex}");
if (!isAutoFollow) // Only log errors if this wasn't an automatic attempt
{
LogRow(LogType.Error, $"Error with finding player camera to follow.\n{ex}");
}
}
}

Expand Down Expand Up @@ -412,4 +481,4 @@ public static float Exponential(float value, float expo)
}
}
}
}
}
Loading