mirror of
https://gitlab.com/MaddoScientisto/cirnogodot.git
synced 2026-06-01 11:15:33 +00:00
307 lines
No EOL
9.2 KiB
C#
307 lines
No EOL
9.2 KiB
C#
using System;
|
|
using System.Linq;
|
|
using System.Threading.Tasks;
|
|
using Cirno.Scripts.Enums;
|
|
using Cirno.Scripts.Resources;
|
|
using Cirno.Scripts.Utils;
|
|
using Godot;
|
|
using Godot.Collections;
|
|
using GTweens.Builders;
|
|
using GTweensGodot.Extensions;
|
|
|
|
public partial class GlobalState : Node
|
|
{
|
|
public static GlobalState Instance { get; private set; }
|
|
public static SessionSettings Session => GlobalState.Instance.SessionSettings;
|
|
public Node CurrentScene { get; set; }
|
|
private ColorRect _fader { get; set; }
|
|
|
|
public SessionSettings SessionSettings { get; set; } = new();
|
|
|
|
private PackedScene _plaqueTemplate;
|
|
|
|
private Control _loadingPlaque;
|
|
|
|
private readonly StringName _menuMouseTexturePath = "uid://d3oxwik1uoe4j";
|
|
private readonly StringName _reticuleMouseTexturePath = "uid://b76bhqv247nft";
|
|
|
|
private readonly StringName _mapsDatabaseResource = "uid://blf2ii0j3fqil";
|
|
|
|
private MapsDatabase _mapsDatabase;
|
|
|
|
private Texture2D _menuMouseTexture;
|
|
private Image _menuMouseImage;
|
|
private Texture2D _reticuleMouseTexture;
|
|
private Image _reticuleMouseImage;
|
|
|
|
public bool UseMenuCursor { get; set; } = true;
|
|
|
|
public override void _Ready()
|
|
{
|
|
Instance = this;
|
|
|
|
this.ProcessMode = ProcessModeEnum.Always;
|
|
|
|
_mapsDatabase = ResourceLoader.Load<MapsDatabase>(_mapsDatabaseResource);
|
|
|
|
Viewport root = GetTree().Root;
|
|
// Using a negative index counts from the end, so this gets the last child node of `root`.
|
|
CurrentScene = root.GetChild(-1);
|
|
|
|
_fader = CreateFader();
|
|
|
|
_menuMouseTexture = ResourceLoader.Load<Texture2D>(_menuMouseTexturePath);
|
|
_menuMouseImage = _menuMouseTexture.GetImage();
|
|
|
|
_reticuleMouseTexture = ResourceLoader.Load<Texture2D>(_reticuleMouseTexturePath);
|
|
_reticuleMouseImage = _reticuleMouseTexture.GetImage();
|
|
|
|
GetTree().GetRoot().SizeChanged += OnSizeChanged;
|
|
//_mouseTexture =
|
|
OnSizeChanged();
|
|
//LoadPlaque();
|
|
}
|
|
|
|
private void OnSizeChanged()
|
|
{
|
|
ResizeCursor();
|
|
}
|
|
|
|
public void ChangeCursor(bool useMenu)
|
|
{
|
|
UseMenuCursor = useMenu;
|
|
ResizeCursor();
|
|
}
|
|
|
|
public void ResizeCursor()
|
|
{
|
|
var root = GetTree().GetRoot();
|
|
var baseSize = root.ContentScaleSize;
|
|
var newSize = root.Size;
|
|
|
|
int scaleX = newSize.X / baseSize.X;
|
|
int scaleY = newSize.Y / baseSize.Y;
|
|
int scale = Math.Min(scaleX, scaleY); // Ensure pixel-perfect scaling
|
|
|
|
ResizeCursor(UseMenuCursor ? scale / 2 : scale, UseMenuCursor);
|
|
}
|
|
|
|
public void GotoScene(string path)
|
|
{
|
|
// This function will usually be called from a signal callback,
|
|
// or some other function from the current scene.
|
|
// Deleting the current scene at this point is
|
|
// a bad idea, because it may still be executing code.
|
|
// This will result in a crash or unexpected behavior.
|
|
|
|
// The solution is to defer the load to a later time, when
|
|
// we can be sure that no code from the current scene is running:
|
|
|
|
//CallDeferred(MethodName.DeferredGotoScene, path, new MapStartDataResource());
|
|
|
|
GoToScene(path, new MapStartDataResource());
|
|
}
|
|
|
|
public void GoToScene(string path, MapStartDataResource startData)
|
|
{
|
|
GTweenSequenceBuilder.New()
|
|
.AppendCallback(() => { _loadingPlaque?.Show(); })
|
|
//.Append(_fader.TweenModulateAlpha(0, 0f))
|
|
.Append(_fader.TweenModulateAlpha(1, 0.5f))
|
|
.AppendCallback(() => { CallDeferred(MethodName.DeferredGotoScene, path, startData); })
|
|
.Build()
|
|
.PlayUnpausable();
|
|
|
|
//CallDeferred(MethodName.DeferredGotoScene, path, startData);
|
|
}
|
|
|
|
public void GotoScene(MapResource map)
|
|
{
|
|
this.SessionSettings.LevelNumber = map.LevelId;
|
|
GoToScene(map.ScenePath.ToString(), map.StartData);
|
|
}
|
|
|
|
private void DeferredGotoScene(string path, MapStartDataResource startData = null)
|
|
{
|
|
// It is now safe to remove the current scene.
|
|
CurrentScene.Free();
|
|
|
|
//var sceneParent = CurrentScene.GetParent();
|
|
//sceneParent.RemoveChild(CurrentScene);
|
|
//sceneParent.QueueFree();
|
|
|
|
// Load a new scene.
|
|
var nextScene = GD.Load<PackedScene>(path);
|
|
|
|
// Instance the new scene.
|
|
CurrentScene = nextScene.Instantiate();
|
|
|
|
// Add it to the active scene, as child of root.
|
|
GetTree().Root.AddChild(CurrentScene);
|
|
|
|
// Optionally, to make it compatible with the SceneTree.change_scene_to_file() API.
|
|
GetTree().CurrentScene = CurrentScene;
|
|
|
|
// // Update current scene here too
|
|
// CurrentScene = GetTree().Root.GetChild(-1);
|
|
|
|
if (startData is not null && GameManager.Instance is not null)
|
|
{
|
|
// Call deferred if it gives issues
|
|
DeferredAddStartDataToGameManager(startData);
|
|
}
|
|
|
|
// Do not do this here because it might get the old gamemanager instead
|
|
// if (GameManager.Instance is not null) {
|
|
// GameManager.Instance.ApplySessionState(SessionSettings);
|
|
// }
|
|
|
|
FadeIn();
|
|
}
|
|
|
|
private void DeferredAddStartDataToGameManager(MapStartDataResource resource)
|
|
{
|
|
GameManager.Instance?.ApplyMapStartData(resource);
|
|
}
|
|
|
|
private Control LoadPlaque()
|
|
{
|
|
_plaqueTemplate = GD.Load<PackedScene>("res://Scenes/HUD/LoadingPlaque.tscn");
|
|
|
|
return _plaqueTemplate.Instantiate<Control>();
|
|
}
|
|
|
|
private ColorRect CreateFader()
|
|
{
|
|
var canvas = new CanvasLayer();
|
|
canvas.ProcessMode = ProcessModeEnum.Always;
|
|
|
|
var rect = new ColorRect();
|
|
rect.ZAsRelative = false;
|
|
rect.ZIndex = 100;
|
|
rect.SetAnchorsPreset(Control.LayoutPreset.FullRect);
|
|
rect.Color = new Color(Colors.Black, 1f);
|
|
rect.ProcessMode = ProcessModeEnum.Always;
|
|
|
|
rect.Modulate = new Color(0, 0, 0, 0);
|
|
|
|
rect.MouseFilter = Control.MouseFilterEnum.Ignore;
|
|
|
|
canvas.CallDeferred("add_child", rect);
|
|
|
|
this.CallDeferred("add_child", canvas);
|
|
|
|
_loadingPlaque = LoadPlaque();
|
|
canvas.CallDeferred("add_child", _loadingPlaque);
|
|
_loadingPlaque.Hide();
|
|
|
|
return rect;
|
|
}
|
|
|
|
public void FadeOut()
|
|
{
|
|
_fader.TweenModulateAlpha(1, 0.5f).PlayUnpausable();
|
|
_loadingPlaque?.Show();
|
|
}
|
|
|
|
public void FadeIn()
|
|
{
|
|
_loadingPlaque?.Hide();
|
|
_fader.TweenModulateAlpha(0, 1f).PlayUnpausable();
|
|
}
|
|
|
|
private readonly string SaveNameFile = "user://savegame.save";
|
|
|
|
public void SaveGame()
|
|
{
|
|
var items = InventoryManager.Instance.Save();
|
|
|
|
SessionSettings.Items = items;
|
|
|
|
var serializedSavedata = new Godot.Collections.Dictionary<string, Variant>()
|
|
{
|
|
{ "Items", items },
|
|
{ "Level", SessionSettings.LevelNumber },
|
|
{ "Difficulty", (int)SessionSettings.Difficulty }
|
|
};
|
|
|
|
var saveFile = FileAccess.Open(SaveNameFile, FileAccess.ModeFlags.Write);
|
|
|
|
var jsonString = Json.Stringify(serializedSavedata);
|
|
|
|
saveFile.StoreLine(jsonString);
|
|
|
|
GD.Print("Saved data successfully");
|
|
}
|
|
|
|
public bool LoadGame()
|
|
{
|
|
if (!FileAccess.FileExists(SaveNameFile))
|
|
{
|
|
return false; // Error! We don't have a save to load.
|
|
}
|
|
|
|
using var saveFile = FileAccess.Open(SaveNameFile, FileAccess.ModeFlags.Read);
|
|
|
|
var jsonString = saveFile.GetLine();
|
|
var json = new Json();
|
|
|
|
var parseResult = json.Parse(jsonString);
|
|
if (parseResult != Error.Ok)
|
|
{
|
|
GD.Print($"JSON Parse Error: {json.GetErrorMessage()} in {jsonString} at line {json.GetErrorLine()}");
|
|
return false;
|
|
}
|
|
|
|
var deserializedSaveData = new Dictionary<string, Variant>((Dictionary)json.Data);
|
|
|
|
Dictionary<string, int> items = (Dictionary<string, int>)deserializedSaveData["Items"];
|
|
|
|
DifficultyLevel difficulty = (DifficultyLevel)deserializedSaveData["Difficulty"].AsInt32();
|
|
|
|
int levelNumber = (int)deserializedSaveData["Level"];
|
|
|
|
var levelData = _mapsDatabase.Maps.FirstOrDefault(x => x.LevelId == levelNumber);
|
|
if (levelData is null)
|
|
{
|
|
return false;
|
|
}
|
|
|
|
this.SessionSettings.NewSession();
|
|
SessionSettings.LevelNumber = levelNumber;
|
|
SessionSettings.Items = items;
|
|
SessionSettings.Difficulty = difficulty;
|
|
|
|
this.GotoScene(levelData);
|
|
|
|
return true;
|
|
}
|
|
|
|
private void ResizeCursor(float scale, bool useMenuCursor)
|
|
{
|
|
Image scaled;
|
|
Vector2I size;
|
|
if (useMenuCursor)
|
|
{
|
|
scaled = (Image)_menuMouseImage.Duplicate();
|
|
size = (Vector2I)(scale * _menuMouseTexture.GetSize());
|
|
|
|
}
|
|
else
|
|
{
|
|
scaled = (Image)_reticuleMouseImage.Duplicate();
|
|
size = (Vector2I)(scale * _reticuleMouseTexture.GetSize());
|
|
}
|
|
|
|
scaled.Resize(size.X, size.Y, Image.Interpolation.Nearest);
|
|
|
|
Input.SetCustomMouseCursor(scaled, Input.CursorShape.Arrow, useMenuCursor ? Vector2.Zero : new Vector2(size.X / 2,size.Y / 2));
|
|
|
|
//DisplayServer.CursorSetCustomImage(scaled);
|
|
}
|
|
|
|
public void RestartLevel()
|
|
{
|
|
GotoScene(CurrentScene.GetSceneFilePath());
|
|
}
|
|
} |