UI/StartMenu.razor

Razor UI panel for the game's start menu. Renders top bar and a list of scene vials from the ResourceLibrary, handles opening scenes, pausing/unpausing (by setting Scene.TimeScale), navigation to start scene, settings, and exit actions.

File AccessNetworking
@using Sandbox;
@using Sandbox.UI;
@inherits PanelComponent
@namespace Sandbox

<root class=@(isPaused?"":"resumed")>
	<!--https://sbox.game/dev/doc/ui/razor-panels/razor-components-->
	<!--<div class="title">@MyStringValue</div>-->
	<div class="topBar">

		<div class="topLeft">
			<p><a class="resumeButton @(@isInStart?"hidden":"")" onClick=@ResumeGame><iconify icon="material-symbols:arrow-back" size=@(48)/></a></p>
			<p class="topTitle">🪛 Testpen!</p>
			<p><a class="homeButton @(isInStart?"hidden":"")" onClick=@ReturnToMenu>🏠</a></p>
		</div>
		<div class="topCenter">
			<p>@openedSceneName</p>
		</div>
		<div class="topRight">
			<p><a class="settingButton" onClick=@SettingGame>⚙️</a></p>
			<p><a class="selfInfoButton" onClick=@SelfInfoGame>ℹ️</a></p>
			<p><a class="exitButton" onClick=@ExitGame>❌</a></p>
		</div>
	</div>
	<hr/>
	<div class="body">
		<div class="manualSceneList">
			<!--<p><a onClick=@TestGoToScene>Go To Scene</a></p>-->
			<!--<p class=@(@isInStart?"hidden":"")><a onClick=@ReturnToMenu>Go To Home</a></p>-->
		</div>
		<div class="sceneList">
			@foreach (var sceneVial in ResourceLibrary.GetAll<SceneFile>().Where(x => x.ResourcePath.Contains("/vials/")).OrderBy(x => x.GetMetadata("Title")))
            {
                <SceneVialSelectable Scene="@sceneVial" OnSelected=@OpenScene></SceneVialSelectable>

            }
		</div>
	</div>
</root>

@code
{
	/*
	//@foreach (var sceneVial in ResourceLibrary.GetAll<SceneFile>().Where(x => x.ResourcePath.Contains("/Vials/") && x.GetMetadata("Group", "None") == SceneCategory).OrderBy(x => x.GetMetadata("Title")))
	//@foreach (var sceneVial in ResourceLibrary.GetAll<SceneFile>().Where(x => x.ResourcePath.Contains("/vials/")).OrderBy(x => x.GetMetadata("Title")))
	@foreach (var sceneVial in ResourceLibrary.GetAll<SceneFile>())
	*/

	[Property] public bool isPaused {get; internal set;} = false;
	protected bool hathPaused {get;set;} = false;
	[Property] public bool isInStart {get;set;} = false;
	[Property, TextArea] public string MyStringValue { get; set; } = "Testpen!";
	protected string openedSceneName {get;set;} = "Select test";
	[Property] public SceneInformation ObtainSceneInfo {get;set;}

	//[Property] protected DoNotFreezeOnPause? noFreeze {get; set;}
	[Property] public bool PlsDoNotFreeze {get;set;} = false;
	protected bool hathFrozen {get; set;} = false;

	// Yoink Scene List from Facepunch!
	// https://github.com/Facepunch/sbox-scenestaging/blob/main/Code/SceneMenu/SceneMenuPanel.razor
	[ConVar( "testbed_category", ConVarFlags.Saved )]
    public static string SceneCategory { get; set; } = "Random";

	protected override void OnStart()
	{
		base.OnStart();

		//TODO: Make it singleton, find other UI like this. If found other instance, let that guy alone, and self destruct. Just like Unity.

		// Search these SceneProperties Components!
		//noFreeze = Scene.Directory.FindByName( "DoNotFreezeOnPause" ).First().GetComponent<DoNotFreezeOnPause>();
		//ObtainSceneInfo = Scene.Directory.FindByName("Scene Information").First().GetComponent<SceneInformation>();
	}

	protected override void OnUpdate()
	{
		base.OnUpdate();

		if(Input.EscapePressed)
		{
			//Log.Info("escape press");
			if(!isInStart){
				Input.EscapePressed = false;
				TogglePause();
			}
		}

		if(Input.Pressed("Jump"))
		{
			//Log.Info("aaa");
		}

		if(isPaused)
		{
			if(!hathPaused)
			{
				if(!hathFrozen)
				{
					/*
					if(!noFreeze.IsValid())
					{
						//Log.Info("try find if noPause");
						//noFreeze = Scene.Directory.FindByName( "DoNotFreezeOnPause" ).First().GetComponent<DoNotFreezeOnPause>();
					}
					if(noFreeze.IsValid())
					{
						// then we won't freeze time
					} else
					{
						// freeze it now!
						if(!hathFrozen)
						{
							Log.Info("try freeze");
							Scene.TimeScale = 0f;
							hathFrozen = true;
						}
					}
					*/
					if(PlsDoNotFreeze)
					{
						// then we won't freeze
					} else
					{
						// Freeze Now!
						Scene.TimeScale = 0f;
						hathFrozen = true;
					}
				}
				hathPaused = true;
			}
		} else {
			if(hathFrozen)
			{
				// unfreeze just in case there was
				Scene.TimeScale = 1f;
				hathFrozen = false;
			}
			hathPaused = false;
		}
	}

	protected void TestGoToScene()
	{
		Log.Info("Let\'s go!");
		Scene.LoadFromFile("scenes/Vials/minimal.scene");
		isInStart = false;
	}

	protected void OpenScene( SceneFile file )
    {
    	// https://github.com/Facepunch/sbox-scenestaging/blob/main/Code/SceneMenu/SceneMenuPanel.razor
     	// https://github.com/Facepunch/sbox-public/blob/master/engine/Sandbox.Engine/Scene/Scene/Scene.cs
      	// https://github.com/Facepunch/sbox-public/blob/master/engine/Sandbox.Engine/Game/Game/Game.Scene.cs
       	// https://github.com/Facepunch/sbox-public/blob/master/engine/Sandbox.Engine/Systems/SceneSystem/SceneLoadOptions.cs
     	// pls I was just had to learn.
      	var toThisScene = new SceneLoadOptions();
       	toThisScene.SetScene(file);


        //Game.ActiveScene.Load(file);
		Game.ChangeScene(toThisScene);
		//Scene.LoadFromFile(file);
        //var go = new GameObject(true, "Return To Menu");
        //go.Components.Create<ReturnToMenu>();
    }

    /*
    protected void OpenScene( String filename)
    {

    }
    */

	protected void ReturnToMenu()
	{
		Log.Info("Let\'s go home!");
		//Scene.LoadFromFile("scenes/start.scene");
		var toThisScene = new SceneLoadOptions();
       	toThisScene.SetScene("scenes/start.scene");
        Game.ChangeScene(toThisScene);
		isInStart = true;
	}

	protected void ResumeGame()
	{
		Log.Info("Resume Now!");
		if(!isInStart)
			isPaused = false;
	}

	protected void TogglePause()
	{

		isPaused = !isPaused;
		//Log.Info("isPaused is now " + isPaused);
	}

	protected void SettingGame()
	{
		Log.Info("Open Setting!!");
		// found!
		//https://github.com/Facepunch/sbox-public/blob/master/engine/Sandbox.Engine/Game/Game/Game.Overlay.cs
		// Jesus Christ on an Innova, at least copy paste the old docs to sbox docs until you can remake the new one, wtf!

		Game.Overlay.ShowSettingsModal("");
	}

	protected void SelfInfoGame()
	{
		Log.Info("Open Self Info!!");
		Game.Overlay.ShowPauseMenu();
	}

	protected void ExitGame()
	{
		Log.Info("Exit Game Now!");
		// We had to scour examples, coz the documentation as of rn is infancy
		// https://github.com/Facepunch/sbox-battlebugs/blob/main/code/UI/PanelComponents/MainMenu.razor
		// https://github.com/Facepunch/sbox-public/blob/master/engine/Sandbox.Engine/Game/Game/Game.cs
		// if(Game.IsEditor) return;
		Game.Close();
		// Oh Hey, Carson, what's up?
	}

	/// <summary>
	/// the hash determines if the system should be rebuilt. If it changes, it will be rebuilt
	/// </summary>
	//protected override int BuildHash() => System.HashCode.Combine( MyStringValue );
	protected override int BuildHash() {
		return System.HashCode.Combine(
		MyStringValue,
		"",
		isInStart,
		ResourceLibrary.GetAll<SceneFile>().Where(x => x.ResourcePath.Contains("/vials/")).OrderBy(x => x.GetMetadata("Title")),
		isPaused
		);
	}
}