GameManager.cs
using Donut.UI;
using Sandbox.Audio;
using Sandbox.Services;
namespace Donut;
public sealed class GameManager : Component, Component.INetworkListener
{
public static GameManager Instance { get; private set; }
public Leaderboards.Board Leaderboard { get; private set; }
public bool LeaderboardSwitching { get; private set; } = false;
protected override async void OnAwake()
{
Instance = this;
PlaySong();
LeaderboardSwitching = true;
Leaderboard = Leaderboards.Get( "newtime" );
Leaderboard.MaxEntries = 100;
await Leaderboard?.Refresh();
LeaderboardSwitching = false;
}
protected override void OnStart()
{
Chatbox.Instance?.AddLocalMessage(
"👋",
"Welcome to S&box Donut! " +
"Press the right and left arrow keys to adjust the rotation speed and R to reset. " +
"You can press V to use the voice chat or ENTER to open up the chatbox. " +
"Finally, click on the donut or press SPACEBAR to munch on it, have fun!",
"notification"
);
}
protected override void OnUpdate()
{
UpdateInput();
UpdateLeaderboard();
UpdateTime();
UpdateDonut();
}
public MusicPlayer MusicPlayer { get; private set; }
public static string[] Songs => FileSystem.Mounted.FindFile( "sounds/music", "*.mp3" ).ToArray();
private int currentSongIndex;
private void PlaySong()
{
MusicPlayer?.Stop();
MusicPlayer?.Dispose();
if ( currentSongIndex >= Songs.Length )
currentSongIndex = 0;
string songToPlay = $"sounds/music/{Songs[currentSongIndex]}";
currentSongIndex++;
MusicPlayer = MusicPlayer.Play( FileSystem.Mounted, songToPlay );
MusicPlayer.TargetMixer = Mixer.FindMixerByName( "Music" );
MusicPlayer.OnFinished += PlaySong;
}
private void UpdateInput()
{
if ( !Canvas.Instance.IsValid() )
return;
if ( Input.Pressed( "Adjust Rotation Speed (+)" ) )
{
Canvas.Instance.DELTA_A += 0.0025;
Canvas.Instance.DELTA_B += 0.0025;
Sound.Play( "increase" ).TargetMixer = Mixer.FindMixerByName( "UI" );
}
if ( Input.Pressed( "Adjust Rotation Speed (-)" ) )
{
Canvas.Instance.DELTA_A -= 0.0025;
Canvas.Instance.DELTA_B -= 0.0025;
Sound.Play( "decrease" ).TargetMixer = Mixer.FindMixerByName( "UI" );
}
if ( Input.Pressed( "Reset Rotation Speed" ) )
{
Canvas.Instance.DELTA_A = 0.04;
Canvas.Instance.DELTA_B = 0.02;
Sound.Play( "reset" ).TargetMixer = Mixer.FindMixerByName( "UI" );
}
if ( Input.Pressed( "Munch" ) )
{
Munch();
}
}
public double Clicks { get; private set; } = 0;
private void UpdateDonut()
{
if ( Clicks >= 7 )
{
Clicks = 0;
Stats.Increment( "donuts", 1 );
Sound.Play( "splat" ).TargetMixer = Mixer.FindMixerByName( "UI" );
}
}
public void Munch()
{
if ( Clicks < 7 )
{
Clicks += 1;
Sound.Play( "munch" ).TargetMixer = Mixer.FindMixerByName( "UI" );
}
}
private readonly string[] leaderboards = new[] { "newtime", "donuts" };
private int currentLeaderboard;
public async void SwitchLeaderboard()
{
LeaderboardSwitching = true;
currentLeaderboard = (currentLeaderboard + 1) % leaderboards.Length;
Leaderboard = Leaderboards.Get( leaderboards[currentLeaderboard] );
Leaderboard.MaxEntries = 100;
await Leaderboard?.Refresh();
LeaderboardSwitching = false;
}
private RealTimeUntil leaderboardDelay;
private void UpdateLeaderboard()
{
if ( leaderboardDelay )
{
leaderboardDelay = 30f;
Leaderboard?.Refresh();
}
}
private int hours;
private int minutes;
private int seconds;
private RealTimeUntil timeDelay;
private void UpdateTime()
{
if ( timeDelay )
{
timeDelay = 1f;
seconds++;
if ( seconds == 60 )
{
seconds = 0;
minutes++;
}
if ( minutes == 60 )
{
minutes = 0;
hours++;
}
if ( Player.Local.IsValid() )
Player.Local.Time = $"{hours}h{minutes}m{seconds}s";
Stats.Increment( "time2", 1f );
}
}
public void OnConnected( Connection conn )
{
Chatbox.Instance?.AddMessage( "👋", $"{conn.DisplayName} has started the simulation!", "notification" );
}
public void OnDisconnected( Connection conn )
{
foreach ( var ply in Game.ActiveScene.GetAllComponents<Player>() )
if ( ply.Network.Owner == conn ) ply.GameObject.Destroy();
Chatbox.Instance?.AddMessage( "👋", $"{conn.DisplayName} has snapped back to reality!", "notification" );
}
public static void Kick( Connection conn )
{
// For some reason, it doesn't work on hosts. Will make do with this check for now
if ( conn == Connection.Local )
{
Networking.Disconnect();
Chatbox.Instance?.AddLocalMessage( "🔌", "Looks like you've been kicked. To reconnect, simply restart the game.", "notification" );
return;
}
Chatbox.Instance?.AddMessage( "🔌", $"{conn.DisplayName} has been kicked from the server. Good riddance!", "notification" );
conn.Kick( "You have been kicked from the server. Sorry, not sorry!" );
}
[ConCmd( "killserver" )]
public static void Shutdown()
{
if ( Connection.Local.SteamId != 76561198842119514 )
{
Log.Info( "You do not have authority to run this command!" );
return;
}
foreach ( var conn in Connection.All )
{
Kick( conn );
}
}
}