refactor
This commit is contained in:
@@ -2,40 +2,35 @@
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using System.Text;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using RebootKit.Engine.Main;
|
||||
using UnityEngine;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootKit.Engine.Services.Console {
|
||||
public interface IConsoleCommand {
|
||||
string Name { get; }
|
||||
string Description { get; }
|
||||
void Execute(string[] args);
|
||||
}
|
||||
[AttributeUsage(AttributeTargets.Method)]
|
||||
public class RCCMD : Attribute {
|
||||
public string name;
|
||||
public string description;
|
||||
|
||||
public class HelpCommand : IConsoleCommand {
|
||||
public string Name { get; } = "help";
|
||||
public string Description { get; } = "Prints available commands/cvars and their descriptions.";
|
||||
|
||||
public void Execute(string[] args) {
|
||||
RR.Console.PrintHelp();
|
||||
}
|
||||
}
|
||||
|
||||
public class PrintCVarsCommand : IConsoleCommand {
|
||||
public string Name { get; } = "print_cvars";
|
||||
public string Description { get; } = "Prints all cvars and their values.";
|
||||
|
||||
public void Execute(string[] args) {
|
||||
RR.Console.PrintCVars();
|
||||
public RCCMD(string name, string description) {
|
||||
this.name = name;
|
||||
this.description = description;
|
||||
}
|
||||
}
|
||||
|
||||
public class ConsoleService : IService {
|
||||
static readonly Logger s_logger = new(nameof(ConsoleService));
|
||||
|
||||
readonly List<IConsoleCommand> m_ConsoleCommands = new();
|
||||
public struct ConsoleCommand {
|
||||
public string name;
|
||||
public string description;
|
||||
public Action<string[]> action;
|
||||
}
|
||||
|
||||
readonly List<ConsoleCommand> m_ConsoleCommands = new();
|
||||
|
||||
FileStream m_LogFileStream;
|
||||
TextWriter m_LogFileWriter;
|
||||
@@ -60,8 +55,7 @@ namespace RebootKit.Engine.Services.Console {
|
||||
|
||||
Load();
|
||||
|
||||
RegisterCommand(new PrintCVarsCommand());
|
||||
RegisterCommand(new HelpCommand());
|
||||
RegisterCommands();
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
@@ -97,37 +91,34 @@ namespace RebootKit.Engine.Services.Console {
|
||||
OnOutputMessage?.Invoke(message);
|
||||
}
|
||||
|
||||
string[] ParseCommandInputArguments(string text) {
|
||||
if (text.Length == 0) {
|
||||
return Array.Empty<string>();
|
||||
}
|
||||
|
||||
return new[] {text};
|
||||
string[] ParseCommandInput(string text) {
|
||||
return text.Split(' ');
|
||||
}
|
||||
|
||||
// @NOTE: Input must be in format: "command arg1 arg2 arg3", one command = one call
|
||||
public void Execute(string input) {
|
||||
if (input.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
string commandName = input;
|
||||
if (input.IndexOf(' ') != -1) {
|
||||
commandName = input.Substring(0, input.IndexOf(' '));
|
||||
string[] arguments = ParseCommandInput(input);
|
||||
if (arguments.Length == 0) {
|
||||
return;
|
||||
}
|
||||
|
||||
string[] arguments = ParseCommandInputArguments(input.Substring(commandName.Length));
|
||||
string commandName = arguments[0];
|
||||
|
||||
foreach (IConsoleCommand command in m_ConsoleCommands) {
|
||||
if (command.Name.Equals(commandName)) {
|
||||
command.Execute(arguments);
|
||||
foreach (ConsoleCommand command in m_ConsoleCommands) {
|
||||
if (command.name.Equals(commandName)) {
|
||||
command.action(arguments);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
|
||||
if (cvar.name.Equals(commandName)) {
|
||||
if (arguments.Length == 1) {
|
||||
cvar.ParseFromString(arguments[0]);
|
||||
if (arguments.Length == 2) {
|
||||
cvar.ParseFromString(arguments[1]);
|
||||
}
|
||||
|
||||
WriteToOutput($"<b>{cvar.name}</b> - {cvar}\n");
|
||||
@@ -138,25 +129,84 @@ namespace RebootKit.Engine.Services.Console {
|
||||
WriteToOutput($"ERROR: Command/CVar `{commandName}` not found.");
|
||||
}
|
||||
|
||||
public void RegisterCommand(IConsoleCommand command) {
|
||||
if (m_ConsoleCommands.Any(t => t.Name.Equals(command.Name))) {
|
||||
s_logger.Error($"`{command.Name}` command is already registered");
|
||||
public void RegisterCommand(string name, string description, Action<string[]> action) {
|
||||
if (IsCommandRegistered(name)) {
|
||||
s_logger.Error($"`{name}` command is already registered");
|
||||
return;
|
||||
}
|
||||
|
||||
m_ConsoleCommands.Add(command);
|
||||
s_logger.Info($"Registered command: {command.Name}");
|
||||
m_ConsoleCommands.Add(new ConsoleCommand {
|
||||
name = name,
|
||||
description = description,
|
||||
action = action
|
||||
});
|
||||
s_logger.Info($"Registered command: {name}");
|
||||
}
|
||||
|
||||
public void PrintHelp() {
|
||||
public static ConsoleCommand[] GenerateCommandsToRegister() {
|
||||
IEnumerable<MethodInfo> methods = AppDomain.CurrentDomain.GetAssemblies()
|
||||
.SelectMany(assembly => assembly.GetTypes())
|
||||
.SelectMany(type => type.GetMethods(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Static))
|
||||
.Where(method => method.GetCustomAttributes(typeof(RCCMD), false).Length > 0);
|
||||
|
||||
List<ConsoleCommand> commands = new();
|
||||
foreach (MethodInfo method in methods) {
|
||||
RCCMD attribute = (RCCMD)method.GetCustomAttributes(typeof(RCCMD), false)[0];
|
||||
|
||||
if (!method.IsStatic) {
|
||||
s_logger.Error($"Command `{attribute.name}` is not static, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.GetParameters().Length != 1) {
|
||||
s_logger.Error($"Command `{attribute.name}` has invalid number of parameters, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
if (method.GetParameters()[0].ParameterType != typeof(string[])) {
|
||||
s_logger.Error($"Command `{attribute.name}` has invalid parameter type, skipping");
|
||||
continue;
|
||||
}
|
||||
|
||||
Action<string[]> action = (Action<string[]>)Delegate.CreateDelegate(typeof(Action<string[]>), method);
|
||||
|
||||
commands.Add(new ConsoleCommand {
|
||||
name = attribute.name,
|
||||
description = attribute.description,
|
||||
action = action
|
||||
});
|
||||
}
|
||||
|
||||
return commands.ToArray();
|
||||
}
|
||||
|
||||
public void RegisterCommands() {
|
||||
ConsoleCommand[] commands = GenerateCommandsToRegister();
|
||||
foreach (ConsoleCommand command in commands) {
|
||||
RegisterCommand(command.name, command.description, command.action);
|
||||
}
|
||||
}
|
||||
|
||||
bool IsCommandRegistered(string name) {
|
||||
foreach (ConsoleCommand command in m_ConsoleCommands) {
|
||||
if (command.name.Equals(name)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
[RCCMD("help", "Prints help message with all commands and cvars")]
|
||||
public static void PrintHelpCommand(string[] args) {
|
||||
StringBuilder message = new();
|
||||
|
||||
message.AppendLine("Available commands:");
|
||||
foreach (IConsoleCommand command in m_ConsoleCommands) {
|
||||
foreach (ConsoleCommand command in RR.Console.m_ConsoleCommands) {
|
||||
message.Append(" ");
|
||||
message.Append(command.Name);
|
||||
message.Append(command.name);
|
||||
message.Append(" - ");
|
||||
message.Append(command.Description);
|
||||
message.Append(command.description);
|
||||
message.AppendLine();
|
||||
}
|
||||
|
||||
@@ -169,17 +219,18 @@ namespace RebootKit.Engine.Services.Console {
|
||||
message.AppendLine();
|
||||
}
|
||||
|
||||
WriteToOutput(message.ToString());
|
||||
RR.Console.WriteToOutput(message.ToString());
|
||||
}
|
||||
|
||||
public void PrintCVars() {
|
||||
[RCCMD("cvars", "Prints all cvars")]
|
||||
public static void PrintCVars(string[] args) {
|
||||
StringBuilder message = new();
|
||||
|
||||
foreach (ConfigVar cvar in ConfigVarsContainer.All()) {
|
||||
message.AppendLine($"{cvar.name} - {cvar}");
|
||||
}
|
||||
|
||||
WriteToOutput(message.ToString());
|
||||
RR.Console.WriteToOutput(message.ToString());
|
||||
}
|
||||
|
||||
void Save() {
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
using System.Text;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootKit.Engine.Services.Input;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
@@ -44,6 +44,10 @@ namespace RebootKit.Engine.Services.ConsoleUI {
|
||||
public event Action ClearRequested = () => { };
|
||||
|
||||
public void SetMessageContent(string message) {
|
||||
if (m_LabelMessage == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_LabelMessage.text = message;
|
||||
m_ScrollView.schedule.Execute(() => { m_ScrollView.scrollOffset = new Vector2(0, m_ScrollView.contentContainer.contentRect.height); }).StartingIn(16);
|
||||
}
|
||||
|
||||
3
Runtime/Engine/Code/Services/Crosshair.meta
Normal file
3
Runtime/Engine/Code/Services/Crosshair.meta
Normal file
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d31f3fe40394defabe1b77f6ddf8861
|
||||
timeCreated: 1746665551
|
||||
13
Runtime/Engine/Code/Services/Crosshair/CrosshairService.cs
Normal file
13
Runtime/Engine/Code/Services/Crosshair/CrosshairService.cs
Normal file
@@ -0,0 +1,13 @@
|
||||
using RebootKit.Engine.Foundation;
|
||||
|
||||
namespace RebootKit.Engine.Services.Crosshair {
|
||||
public class CrosshairService : IService {
|
||||
|
||||
public CrosshairService() {
|
||||
|
||||
}
|
||||
|
||||
public void Dispose() {
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f23a52c23aae46e8bd6b77222b10e5e2
|
||||
timeCreated: 1746665562
|
||||
@@ -1,4 +1,5 @@
|
||||
using System;
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootKit.Engine.UI;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
@@ -10,13 +11,18 @@ namespace RebootKit.Engine.Services.Development {
|
||||
VisualElement m_RootElement;
|
||||
|
||||
Label m_FPSLabel;
|
||||
Label m_GameModeLabel;
|
||||
|
||||
void Update() {
|
||||
if (m_RootElement == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_FPSLabel.text = $"fps: {Mathf.RoundToInt(1f / Time.deltaTime)} | dt: {Time.deltaTime:F4}ms | runtime: {Time.time:F4}s";
|
||||
Resolution resolution = Screen.currentResolution;
|
||||
m_FPSLabel.text = $"fps: {Mathf.RoundToInt(1f / Time.deltaTime)} | dt: {Time.deltaTime:F4}ms | runtime: {Time.time:F4}s | resolution: {resolution.width}x{resolution.height}@{resolution.refreshRateRatio}Hz";
|
||||
m_GameModeLabel.text = RR.GameModes.ActiveGameMode.CurrentValue != null
|
||||
? $"Game Mode: {RR.GameModes.ActiveGameMode.CurrentValue.GetType().Name}"
|
||||
: "Game Mode: none";
|
||||
}
|
||||
|
||||
public override VisualElement Build() {
|
||||
@@ -24,7 +30,8 @@ namespace RebootKit.Engine.Services.Development {
|
||||
|
||||
CreateLabel($"Toggle Overlay [F3] | RebootKit | game: {Application.productName}, version: {Application.version}");
|
||||
m_FPSLabel = CreateLabel($"FPS: {Application.targetFrameRate}");
|
||||
|
||||
|
||||
m_GameModeLabel = CreateLabel("Game Mode: none");
|
||||
return m_RootElement;
|
||||
}
|
||||
|
||||
|
||||
@@ -1,57 +0,0 @@
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using R3;
|
||||
using RebootKit.Engine.Foundation;
|
||||
|
||||
namespace RebootKit.Engine.Services.Game {
|
||||
public class GameService : IService {
|
||||
static readonly Logger s_logger = new(nameof(GameService));
|
||||
|
||||
[Inject] DIContext m_DIContext;
|
||||
|
||||
GameModeAsset m_GameModeAsset;
|
||||
|
||||
CancellationTokenSource m_DestroyCancellationTokenSource = new();
|
||||
DisposableBag m_ActiveGameModeDisposableBag;
|
||||
IGameMode m_ActiveGameMode;
|
||||
|
||||
public void Dispose() {
|
||||
m_DestroyCancellationTokenSource.Cancel();
|
||||
m_DestroyCancellationTokenSource.Dispose();
|
||||
m_ActiveGameModeDisposableBag.Dispose();
|
||||
}
|
||||
|
||||
public void Start(GameModeAsset asset) {
|
||||
if (m_ActiveGameMode != null) {
|
||||
s_logger.Warning("Game is already running");
|
||||
return;
|
||||
}
|
||||
|
||||
Stop();
|
||||
|
||||
m_ActiveGameModeDisposableBag = new DisposableBag();
|
||||
m_ActiveGameMode = asset.Create(m_DIContext);
|
||||
m_ActiveGameModeDisposableBag.Add(m_ActiveGameMode);
|
||||
|
||||
InitializeGameModeAsync().Forget();
|
||||
}
|
||||
|
||||
async UniTask InitializeGameModeAsync() {
|
||||
await m_ActiveGameMode.OnInit(m_DestroyCancellationTokenSource.Token);
|
||||
|
||||
m_ActiveGameMode.OnStart();
|
||||
Observable.EveryUpdate().Subscribe(_ => { m_ActiveGameMode?.OnTick(); }).AddTo(ref m_ActiveGameModeDisposableBag);
|
||||
}
|
||||
|
||||
public void Stop() {
|
||||
if (m_ActiveGameMode == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_ActiveGameMode.OnStop();
|
||||
m_ActiveGameMode = null;
|
||||
|
||||
m_ActiveGameModeDisposableBag.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +0,0 @@
|
||||
using RebootKit.Engine.Foundation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RebootKit.Engine.Services.Game {
|
||||
[CreateAssetMenu(menuName = RConsts.k_ServiceAssetMenu + "Game")]
|
||||
public class GameServiceAsset : ServiceAsset<GameService> {
|
||||
public override GameService Create(DIContext context) {
|
||||
GameService service = context.Create<GameService>();
|
||||
return service;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
namespace RebootKit.Engine.Services.Game {
|
||||
public class Player {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: be94d631484b4bd2a2c9825290b74b36
|
||||
timeCreated: 1744413325
|
||||
62
Runtime/Engine/Code/Services/GameMode/GameModesService.cs
Normal file
62
Runtime/Engine/Code/Services/GameMode/GameModesService.cs
Normal file
@@ -0,0 +1,62 @@
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using R3;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootKit.Engine.Services.Simulation;
|
||||
|
||||
namespace RebootKit.Engine.Services.GameMode {
|
||||
public class GameModesService : IService {
|
||||
static readonly Logger s_logger = new(nameof(GameModesService));
|
||||
|
||||
[Inject] DIContext m_DIContext;
|
||||
|
||||
GameModeAsset m_GameModeAsset;
|
||||
|
||||
readonly CancellationTokenSource m_DestroyCancellationTokenSource = new();
|
||||
DisposableBag m_ActiveGameModeDisposableBag;
|
||||
readonly ReactiveProperty<IGameMode> m_ActiveGameMode = new(null);
|
||||
|
||||
public ReadOnlyReactiveProperty<IGameMode> ActiveGameMode => m_ActiveGameMode;
|
||||
|
||||
public void Dispose() {
|
||||
m_DestroyCancellationTokenSource.Cancel();
|
||||
m_DestroyCancellationTokenSource.Dispose();
|
||||
m_ActiveGameModeDisposableBag.Dispose();
|
||||
}
|
||||
|
||||
public void Start(GameModeAsset asset, WorldConfig worldConfig) {
|
||||
if (m_ActiveGameMode.Value != null) {
|
||||
s_logger.Warning("Game is already running");
|
||||
return;
|
||||
}
|
||||
|
||||
Stop();
|
||||
|
||||
m_ActiveGameModeDisposableBag = new DisposableBag();
|
||||
m_ActiveGameMode.Value = asset.Create(m_DIContext);
|
||||
m_ActiveGameModeDisposableBag.Add(m_ActiveGameMode);
|
||||
|
||||
InitializeGameModeAsync(worldConfig, CancellationToken.None).Forget();
|
||||
}
|
||||
|
||||
async UniTask InitializeGameModeAsync(WorldConfig worldConfig, CancellationToken cancellationToken) {
|
||||
await m_ActiveGameMode.Value.OnInit(m_DestroyCancellationTokenSource.Token);
|
||||
|
||||
await RR.World.LoadAsync(worldConfig, cancellationToken);
|
||||
m_ActiveGameMode.Value.OnStart();
|
||||
Observable.EveryUpdate().Subscribe(_ => { m_ActiveGameMode.Value?.OnTick(); }).AddTo(ref m_ActiveGameModeDisposableBag);
|
||||
}
|
||||
|
||||
public void Stop() {
|
||||
if (m_ActiveGameMode.Value == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
m_ActiveGameMode.Value.OnStop();
|
||||
m_ActiveGameMode.Value = null;
|
||||
|
||||
m_ActiveGameModeDisposableBag.Dispose();
|
||||
}
|
||||
}
|
||||
}
|
||||
12
Runtime/Engine/Code/Services/GameMode/GameServiceAsset.cs
Normal file
12
Runtime/Engine/Code/Services/GameMode/GameServiceAsset.cs
Normal file
@@ -0,0 +1,12 @@
|
||||
using RebootKit.Engine.Foundation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RebootKit.Engine.Services.GameMode {
|
||||
[CreateAssetMenu(menuName = RConsts.k_ServiceAssetMenu + "Game")]
|
||||
public class GameServiceAsset : ServiceAsset<GameModesService> {
|
||||
public override GameModesService Create(DIContext context) {
|
||||
GameModesService service = context.Create<GameModesService>();
|
||||
return service;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,7 @@ using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using RebootKit.Engine.Foundation;
|
||||
|
||||
namespace RebootKit.Engine.Services.Game {
|
||||
namespace RebootKit.Engine.Services.GameMode {
|
||||
public interface IGameMode : IDisposable {
|
||||
UniTask OnInit(CancellationToken cancellationToken);
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using RebootKit.Engine.Foundation;
|
||||
@@ -7,30 +8,72 @@ using UnityEngine.AddressableAssets;
|
||||
using UnityEngine.ResourceManagement.AsyncOperations;
|
||||
using UnityEngine.ResourceManagement.ResourceProviders;
|
||||
using UnityEngine.SceneManagement;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootKit.Engine.Services.Simulation {
|
||||
public class WorldService : IService {
|
||||
readonly List<Actor> m_Actors = new();
|
||||
WorldConfig m_Config;
|
||||
|
||||
public void Dispose() {
|
||||
KillAllActors();
|
||||
static readonly Logger s_logger = new(nameof(WorldService));
|
||||
|
||||
enum WorldState {
|
||||
Unloaded,
|
||||
Loading,
|
||||
Loaded
|
||||
}
|
||||
|
||||
public async UniTask Load(WorldConfig worldConfig) {
|
||||
WorldState m_WorldState = WorldState.Unloaded;
|
||||
WorldConfig m_Config;
|
||||
AsyncOperationHandle<SceneInstance> m_SceneInstance;
|
||||
|
||||
readonly List<Actor> m_Actors = new();
|
||||
|
||||
public void Dispose() {
|
||||
Unload();
|
||||
}
|
||||
|
||||
public async UniTask LoadAsync(WorldConfig worldConfig, CancellationToken cancellationToken) {
|
||||
await UniTask.WaitWhile(() => m_WorldState == WorldState.Loading, cancellationToken: cancellationToken);
|
||||
|
||||
Unload();
|
||||
|
||||
m_WorldState = WorldState.Loading;
|
||||
m_Config = worldConfig;
|
||||
|
||||
AsyncOperationHandle<SceneInstance> handle = worldConfig.mainScene.LoadSceneAsync(LoadSceneMode.Additive, false);
|
||||
await handle.ToUniTask();
|
||||
m_SceneInstance = worldConfig.mainScene.LoadSceneAsync(LoadSceneMode.Additive, false);
|
||||
await m_SceneInstance.ToUniTask(cancellationToken: cancellationToken);
|
||||
|
||||
await handle.Result.ActivateAsync();
|
||||
SceneManager.SetActiveScene(handle.Result.Scene);
|
||||
await m_SceneInstance.Result.ActivateAsync();
|
||||
SceneManager.SetActiveScene(m_SceneInstance.Result.Scene);
|
||||
|
||||
foreach (GameObject root in handle.Result.Scene.GetRootGameObjects()) {
|
||||
foreach (GameObject root in m_SceneInstance.Result.Scene.GetRootGameObjects()) {
|
||||
foreach (Actor actor in root.GetComponentsInChildren<Actor>()) {
|
||||
RegisterActor(actor);
|
||||
}
|
||||
}
|
||||
|
||||
m_WorldState = WorldState.Loaded;
|
||||
}
|
||||
|
||||
public async UniTask<TRequiredActor> LoadAsync<TRequiredActor>(WorldConfig worldConfig, CancellationToken cancellationToken) where TRequiredActor : Actor {
|
||||
await LoadAsync(worldConfig, cancellationToken);
|
||||
|
||||
TRequiredActor actor = m_Actors.FirstOrDefault(t => t is TRequiredActor) as TRequiredActor;
|
||||
if (actor is null) {
|
||||
s_logger.Error($"Actor of type {typeof(TRequiredActor)} not found in the scene");
|
||||
return null;
|
||||
}
|
||||
|
||||
return actor;
|
||||
}
|
||||
|
||||
public void Unload() {
|
||||
KillAllActors();
|
||||
|
||||
if (m_SceneInstance.IsValid()) {
|
||||
m_SceneInstance.Release();
|
||||
m_SceneInstance = default;
|
||||
}
|
||||
|
||||
m_WorldState = WorldState.Unloaded;
|
||||
}
|
||||
|
||||
public async UniTask<TActor> SpawnActor<TActor>(AssetReferenceT<GameObject> asset, CancellationToken cancellationToken) where TActor : Actor {
|
||||
|
||||
Reference in New Issue
Block a user