refactor
This commit is contained in:
@@ -1,22 +1,18 @@
|
||||
using System.Collections.Generic;
|
||||
using RebootKit.Engine;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using RebootKit.Engine.UI;
|
||||
using UnityEditor;
|
||||
using UnityEditor.UIElements;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace RebootKitEditor.RebootWindow {
|
||||
namespace RebootKit.Editor.RebootWindow {
|
||||
public class GameServicesView : IView {
|
||||
VisualElement m_RootElement;
|
||||
|
||||
readonly List<Editor> m_ServiceEditors = new List<Editor>();
|
||||
readonly List<UnityEditor.Editor> m_ServiceEditors = new List<UnityEditor.Editor>();
|
||||
|
||||
[Inject] EngineConfigAsset m_EngineConfigAsset;
|
||||
|
||||
public void Dispose() {
|
||||
foreach (Editor editor in m_ServiceEditors) {
|
||||
foreach (UnityEditor.Editor editor in m_ServiceEditors) {
|
||||
if (editor != null) {
|
||||
Object.DestroyImmediate(editor);
|
||||
}
|
||||
@@ -93,7 +89,7 @@ namespace RebootKitEditor.RebootWindow {
|
||||
};
|
||||
root.Add(editorView);
|
||||
|
||||
Editor editor = Editor.CreateEditor(serviceAsset);
|
||||
UnityEditor.Editor editor = UnityEditor.Editor.CreateEditor(serviceAsset);
|
||||
m_ServiceEditors.Add(editor);
|
||||
|
||||
InspectorElement inspectorElement = new InspectorElement(editor);
|
||||
|
||||
@@ -1,9 +1,11 @@
|
||||
using RebootKit.Engine;
|
||||
using RebootKit.Editor.RebootWindow;
|
||||
using RebootKit.Engine;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
using TabView = RebootKit.Editor.RebootWindow.TabView;
|
||||
|
||||
namespace RebootKitEditor.RebootWindow {
|
||||
static class RTheme {
|
||||
@@ -27,7 +29,6 @@ namespace RebootKitEditor.RebootWindow {
|
||||
static readonly Logger s_logger = new Logger(nameof(RebootEditorWindow));
|
||||
|
||||
EngineConfigAsset m_EngineConfigAsset;
|
||||
DIContext m_DIContext;
|
||||
|
||||
VisualElement m_RootElement;
|
||||
TabView m_TabView;
|
||||
@@ -55,15 +56,11 @@ namespace RebootKitEditor.RebootWindow {
|
||||
}
|
||||
}
|
||||
|
||||
m_DIContext = new DIContext();
|
||||
m_DIContext.Bind(this);
|
||||
m_DIContext.Bind(m_EngineConfigAsset);
|
||||
|
||||
m_TabView = m_DIContext.Create<TabView>();
|
||||
m_TabView.AddTab("Home", m_DIContext.Create<HomeView>());
|
||||
m_TabView.AddTab("Config Vars", m_DIContext.Create<ConfigVarsView>());
|
||||
m_TabView.AddTab("Game Services", m_DIContext.Create<GameServicesView>());
|
||||
m_TabView.AddTab("Worlds", m_DIContext.Create<WorldsView>());
|
||||
m_TabView = new TabView();
|
||||
m_TabView.AddTab("Home", new HomeView());
|
||||
m_TabView.AddTab("Config Vars", new ConfigVarsView());
|
||||
m_TabView.AddTab("Game Services", new GameServicesView());
|
||||
m_TabView.AddTab("Worlds", new WorldsView());
|
||||
}
|
||||
|
||||
void CreateGUI() {
|
||||
|
||||
@@ -1,10 +1,11 @@
|
||||
using System.Collections.Generic;
|
||||
using RebootKit.Engine.UI;
|
||||
using RebootKitEditor.RebootWindow;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace RebootKitEditor.RebootWindow {
|
||||
namespace RebootKit.Editor.RebootWindow {
|
||||
public class TabView : IView {
|
||||
struct Tab {
|
||||
public string name;
|
||||
|
||||
@@ -74,8 +74,8 @@ namespace RebootKit.Engine.Console {
|
||||
|
||||
ConfigVar.StateChanged -= OnCVarStateChanged;
|
||||
|
||||
m_LogFileWriter.Dispose();
|
||||
m_LogFileStream.Dispose();
|
||||
m_LogFileWriter?.Dispose();
|
||||
m_LogFileStream?.Dispose();
|
||||
|
||||
m_LogFileStream = null;
|
||||
m_LogFileWriter = null;
|
||||
|
||||
@@ -1,55 +1,122 @@
|
||||
using System.Text;
|
||||
using RebootKit.Engine.Main;
|
||||
using RebootKit.Engine.Simulation;
|
||||
using RebootKit.Engine.UI;
|
||||
using Unity.Netcode;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UIElements;
|
||||
|
||||
namespace RebootKit.Engine.Development {
|
||||
public class DebugOverlayView : UIDocumentView {
|
||||
const string k_DebugLabelClassName = "rr__debug-label";
|
||||
const string k_DebugLabelClassName = "rr__debug-overlay-label";
|
||||
|
||||
string m_HeaderText;
|
||||
|
||||
VisualElement m_RootElement;
|
||||
|
||||
Label m_FPSLabel;
|
||||
Label m_NetworkStatsLabel;
|
||||
Label m_Label;
|
||||
|
||||
readonly StringBuilder m_StringBuilder = new StringBuilder();
|
||||
|
||||
//
|
||||
// @MARK: Unity callbacks
|
||||
//
|
||||
void Update() {
|
||||
if (m_RootElement == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
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_StringBuilder.AppendLine(m_HeaderText);
|
||||
AppendFPSInfo();
|
||||
AppendNetworkStateInfo();
|
||||
AppendActorsStateInfo();
|
||||
|
||||
NetworkManager nm = NetworkManager.Singleton;
|
||||
|
||||
StringBuilder sb = new StringBuilder();
|
||||
|
||||
sb.Append("Network: ");
|
||||
sb.Append($"IsServer: {nm.IsServer.ToString()}");
|
||||
sb.Append($" | IsClient: {nm.IsClient.ToString()}");
|
||||
sb.Append($" | IsHost: {nm.IsHost.ToString()}");
|
||||
|
||||
m_NetworkStatsLabel.text = sb.ToString();
|
||||
m_Label.text = m_StringBuilder.ToString();
|
||||
m_StringBuilder.Clear();
|
||||
}
|
||||
|
||||
void AppendFPSInfo() {
|
||||
Resolution resolution = Screen.currentResolution;
|
||||
|
||||
m_StringBuilder.Append("fps: ");
|
||||
m_StringBuilder.Append(Mathf.RoundToInt(1f / Time.deltaTime));
|
||||
m_StringBuilder.Append(" | dt: ");
|
||||
m_StringBuilder.Append(Time.deltaTime.ToString("F4"));
|
||||
m_StringBuilder.Append("ms | runtime: ");
|
||||
m_StringBuilder.Append(Time.time.ToString("F4"));
|
||||
m_StringBuilder.Append("s | resolution: ");
|
||||
m_StringBuilder.Append(resolution.width);
|
||||
m_StringBuilder.Append("x");
|
||||
m_StringBuilder.Append(resolution.height);
|
||||
m_StringBuilder.Append("@");
|
||||
m_StringBuilder.Append(resolution.refreshRateRatio);
|
||||
m_StringBuilder.AppendLine();
|
||||
}
|
||||
|
||||
void AppendNetworkStateInfo() {
|
||||
NetworkSystem network = RR.NetworkSystemInstance;
|
||||
|
||||
if (network == null) {
|
||||
m_StringBuilder.AppendLine("NetworkSystem not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
m_StringBuilder.Append($"IsServer: {RR.IsServer().ToString()}");
|
||||
m_StringBuilder.Append($" | IsClient: {RR.IsClient().ToString()}");
|
||||
m_StringBuilder.Append($" | WorldID: {network.WorldID.ToString()}");
|
||||
m_StringBuilder.Append($" | Clients: {network.Clients.Count.ToString()}");
|
||||
m_StringBuilder.Append($" | ReadyClientsCount: {network.GetReadyClientsCount().ToString()}");
|
||||
|
||||
m_StringBuilder.AppendLine();
|
||||
if (network.TryGetClientState(network.LocalClientID, out NetworkClientState clientState)) {
|
||||
m_StringBuilder.Append($"LocalClientID: {clientState.ClientID.ToString()}");
|
||||
m_StringBuilder.Append($" | SyncState: {clientState.SyncState.ToString()}");
|
||||
m_StringBuilder.Append($" | ActorsSyncPacketsLeft: {clientState.ActorsSyncPacketsLeft.ToString()}");
|
||||
m_StringBuilder.Append($" | IsReady: {clientState.IsReady.ToString()}");
|
||||
} else {
|
||||
m_StringBuilder.Append("ClientState not found for LocalClientID: ");
|
||||
m_StringBuilder.Append(network.LocalClientID.ToString());
|
||||
}
|
||||
|
||||
m_StringBuilder.AppendLine();
|
||||
}
|
||||
|
||||
void AppendActorsStateInfo() {
|
||||
NetworkSystem network = RR.NetworkSystemInstance;
|
||||
if (network == null) {
|
||||
return;
|
||||
}
|
||||
|
||||
ActorsManager actorsManager = network.Actors;
|
||||
if (actorsManager == null) {
|
||||
m_StringBuilder.Append("ActorsManager not initialized");
|
||||
return;
|
||||
}
|
||||
|
||||
m_StringBuilder.Append("InScene Actors Count: ");
|
||||
m_StringBuilder.Append(actorsManager.InSceneActorsCount.ToString());
|
||||
m_StringBuilder.Append(" | Dynamic Actors Count: ");
|
||||
m_StringBuilder.Append(actorsManager.SpawnedActorsCount.ToString());
|
||||
m_StringBuilder.Append(" | Total Actors Count: ");
|
||||
m_StringBuilder.Append(actorsManager.TotalActorsCount.ToString());
|
||||
|
||||
m_StringBuilder.AppendLine();
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: UIDocumentView
|
||||
//
|
||||
public override VisualElement Build() {
|
||||
if (m_HeaderText == null) {
|
||||
m_HeaderText =
|
||||
$"Toggle Overlay [F3] | RebootKit | game: {Application.productName}, version: {Application.version}";
|
||||
}
|
||||
|
||||
m_RootElement = new VisualElement();
|
||||
|
||||
CreateLabel($"Toggle Overlay [F3] | RebootKit | game: {Application.productName}, version: {Application.version}");
|
||||
m_FPSLabel = CreateLabel($"FPS: {Application.targetFrameRate.ToString()}");
|
||||
|
||||
m_NetworkStatsLabel = CreateLabel("Network Stats");
|
||||
m_Label = (Label)LabelBuilder.New("").Build();
|
||||
m_Label.AddToClassList(k_DebugLabelClassName);
|
||||
m_RootElement.Add(m_Label);
|
||||
|
||||
return m_RootElement;
|
||||
}
|
||||
|
||||
Label CreateLabel(string text) {
|
||||
Label label = (Label)LabelBuilder.New(text).Build();
|
||||
label.AddToClassList(k_DebugLabelClassName);
|
||||
|
||||
m_RootElement.Add(label);
|
||||
return label;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
using System;
|
||||
using RebootKit.Engine.Foundation;
|
||||
using Unity.Multiplayer.Tools.NetStatsMonitor;
|
||||
using UnityEngine;
|
||||
using UnityEngine.InputSystem;
|
||||
|
||||
@@ -18,7 +19,7 @@ namespace RebootKit.Engine.Development {
|
||||
public class DevToolsService : ServiceMonoBehaviour {
|
||||
[SerializeField] DebugOverlayView m_DebugOverlayView;
|
||||
[SerializeField] GameVersionOverlay m_GameVersionOverlay;
|
||||
[SerializeField] GameObject m_NetworkStatsOverlay;
|
||||
[SerializeField] RuntimeNetStatsMonitor m_NetworkStatsOverlay;
|
||||
|
||||
IDisposable m_CVarChangedListener;
|
||||
|
||||
@@ -41,6 +42,10 @@ namespace RebootKit.Engine.Development {
|
||||
if (InputSystem.GetDevice<Keyboard>().f3Key.wasReleasedThisFrame) {
|
||||
DebugCVars.OverlayMode.Set(DebugCVars.OverlayMode.IndexValue == 1 ? 0 : 1);
|
||||
}
|
||||
|
||||
if (InputSystem.GetDevice<Keyboard>().f4Key.wasReleasedThisFrame) {
|
||||
DebugCVars.ShowNetworkStats.Set(DebugCVars.ShowNetworkStats.IndexValue == 1 ? 0 : 1);
|
||||
}
|
||||
}
|
||||
|
||||
void OnOverlayModeChanged(int mode) {
|
||||
@@ -57,7 +62,7 @@ namespace RebootKit.Engine.Development {
|
||||
} else if (cvar == DebugCVars.ShowGameVersion) {
|
||||
m_GameVersionOverlay.gameObject.SetActive(cvar.IndexValue > 0);
|
||||
} else if (cvar == DebugCVars.ShowNetworkStats) {
|
||||
m_NetworkStatsOverlay.SetActive(cvar.IndexValue > 0);
|
||||
m_NetworkStatsOverlay.Visible = cvar.IndexValue > 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,127 +0,0 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Reflection;
|
||||
using ZLinq;
|
||||
|
||||
namespace RebootKit.Engine.Foundation {
|
||||
[AttributeUsage(AttributeTargets.Field | AttributeTargets.Method)]
|
||||
public class InjectAttribute : Attribute {
|
||||
}
|
||||
|
||||
public class DIContext {
|
||||
const BindingFlags k_fieldsBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
const BindingFlags k_methodsBindingFlags = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
|
||||
|
||||
static readonly Logger s_logger = new Logger(nameof(DIContext));
|
||||
|
||||
readonly Dictionary<Type, object> m_BindingsMaps = new Dictionary<Type, object>();
|
||||
readonly List<IFieldInjector> m_FieldInjectors = new List<IFieldInjector>();
|
||||
|
||||
public DIContext() {
|
||||
Bind(this);
|
||||
|
||||
AddInjector(new InjectAttributeFieldInjector());
|
||||
}
|
||||
|
||||
public void AddInjector(IFieldInjector injector) {
|
||||
m_FieldInjectors.Add(injector);
|
||||
}
|
||||
|
||||
public void Bind(Type type, object obj) {
|
||||
if (!m_BindingsMaps.TryAdd(type, obj)) {
|
||||
s_logger.Error($"Cannot bind to '{type}', slot is already occupied");
|
||||
}
|
||||
}
|
||||
|
||||
public void Bind<TBind>(TBind obj) {
|
||||
Bind(typeof(TBind), obj);
|
||||
}
|
||||
|
||||
public object Resolve(Type type) {
|
||||
if (m_BindingsMaps.TryGetValue(type, out object obj)) return obj;
|
||||
|
||||
s_logger.Error($"Couldn't resolve `{type}`");
|
||||
return null;
|
||||
}
|
||||
|
||||
public T Resolve<T>() {
|
||||
return (T) Resolve(typeof(T));
|
||||
}
|
||||
|
||||
// @brief creates new instance of an object and injects dependencies
|
||||
public T Create<T>() {
|
||||
T instance = Activator.CreateInstance<T>();
|
||||
|
||||
Inject(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public T Create<T>(params object[] args) {
|
||||
T instance = (T) Activator.CreateInstance(typeof(T), args);
|
||||
Inject(instance);
|
||||
return instance;
|
||||
}
|
||||
|
||||
public void Inject(object target) {
|
||||
Type type = target.GetType();
|
||||
|
||||
foreach (FieldInfo field in type.GetFields(k_fieldsBindingFlags)) {
|
||||
InjectField(field, target);
|
||||
}
|
||||
|
||||
foreach (MethodInfo method in type.GetMethods(k_methodsBindingFlags)) {
|
||||
if (!Attribute.IsDefined(method, typeof(InjectAttribute))) {
|
||||
continue;
|
||||
}
|
||||
|
||||
Type[] paramsTypes = method.GetParameters()
|
||||
.AsValueEnumerable()
|
||||
.Select(t => t.ParameterType)
|
||||
.ToArray();
|
||||
|
||||
object[] instances = new object[paramsTypes.Length];
|
||||
|
||||
for (int i = 0; i < paramsTypes.Length; ++i) {
|
||||
instances[i] = Resolve(paramsTypes[i]);
|
||||
|
||||
if (instances[i] == null) {
|
||||
s_logger.Error($"Failed to resolve method parameter of type `{paramsTypes[i]}`");
|
||||
}
|
||||
}
|
||||
|
||||
method.Invoke(target, instances);
|
||||
}
|
||||
}
|
||||
|
||||
bool InjectField(FieldInfo field, object target) {
|
||||
for (int i = m_FieldInjectors.Count - 1; i >= 0; i--) {
|
||||
if (m_FieldInjectors[i].Inject(field, target, this)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
public interface IFieldInjector {
|
||||
bool Inject(FieldInfo field, object target, DIContext context);
|
||||
}
|
||||
|
||||
class InjectAttributeFieldInjector : IFieldInjector {
|
||||
public bool Inject(FieldInfo field, object target, DIContext context) {
|
||||
if (!Attribute.IsDefined(field, typeof(InjectAttribute))) return false;
|
||||
|
||||
object instance = context.Resolve(field.FieldType);
|
||||
|
||||
if (instance == null) {
|
||||
s_logger.Error($"Cannot resolve `{field.FieldType}`");
|
||||
return false;
|
||||
}
|
||||
|
||||
field.SetValue(target, instance);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: cee4133e4a594126868703cc035663cd
|
||||
timeCreated: 1742001112
|
||||
@@ -5,10 +5,6 @@ namespace RebootKit.Engine.Foundation {
|
||||
TProd Create();
|
||||
}
|
||||
|
||||
public interface IFactoryDI<out TProd> {
|
||||
TProd Create(DIContext context);
|
||||
}
|
||||
|
||||
public abstract class FactoryAsset<TProd> : ScriptableObject, IFactory<TProd> where TProd : class {
|
||||
public abstract TProd Create();
|
||||
}
|
||||
|
||||
@@ -1,45 +0,0 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace RebootKit.Engine.Foundation {
|
||||
public interface IDependencyInstaller {
|
||||
void Install(DIContext context);
|
||||
}
|
||||
|
||||
public abstract class SceneDependencyInstaller : MonoBehaviour, IDependencyInstaller {
|
||||
public abstract void Install(DIContext context);
|
||||
}
|
||||
|
||||
[DefaultExecutionOrder(-1000)]
|
||||
public class SceneContext : MonoBehaviour {
|
||||
static readonly Logger s_logger = new Logger(nameof(SceneContext));
|
||||
|
||||
[SerializeField] SceneDependencyInstaller[] m_Installers;
|
||||
|
||||
DIContext m_DIContext;
|
||||
|
||||
void Awake() {
|
||||
m_DIContext = new DIContext();
|
||||
|
||||
s_logger.Info("Installing scene dependency installers");
|
||||
foreach (SceneDependencyInstaller installer in m_Installers) {
|
||||
installer.Install(m_DIContext);
|
||||
}
|
||||
|
||||
foreach (GameObject root in gameObject.scene.GetRootGameObjects()) {
|
||||
m_DIContext.InjectGameObject(root);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class DIContextGameObjectEx {
|
||||
public static void InjectGameObject(this DIContext context, GameObject gameObject, bool injectChildren = true) {
|
||||
Assert.IsNotNull(gameObject);
|
||||
|
||||
Component[] components = injectChildren ? gameObject.GetComponentsInChildren<Component>() : gameObject.GetComponents<Component>();
|
||||
foreach (Component component in components) {
|
||||
context.Inject(component);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8dd28652b58c4d689ab3f2f9354d7589
|
||||
timeCreated: 1742006992
|
||||
@@ -1,6 +1,9 @@
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.CompilerServices;
|
||||
using System.Threading;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using NUnit.Framework;
|
||||
using RebootKit.Engine.Simulation;
|
||||
using Unity.Collections;
|
||||
using Unity.Netcode;
|
||||
@@ -8,14 +11,31 @@ using UnityEngine;
|
||||
using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
|
||||
namespace RebootKit.Engine.Main {
|
||||
class NetworkClientState {
|
||||
enum NetworkClientSyncState {
|
||||
NotReady,
|
||||
LoadingWorld,
|
||||
PreparingForActorsSync,
|
||||
SyncingActors,
|
||||
Ready
|
||||
}
|
||||
|
||||
struct NetworkClientState : INetworkSerializable {
|
||||
public ulong ClientID;
|
||||
public bool IsWorldLoaded;
|
||||
public bool AreActorsSynced;
|
||||
public bool IsReadyForActorsSync;
|
||||
public NetworkClientSyncState SyncState;
|
||||
public int ActorsSyncPacketsLeft;
|
||||
|
||||
public bool IsReady;
|
||||
public bool IsReady {
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get {
|
||||
return SyncState == NetworkClientSyncState.Ready;
|
||||
}
|
||||
}
|
||||
|
||||
public void NetworkSerialize<T>(BufferSerializer<T> serializer) where T : IReaderWriter {
|
||||
serializer.SerializeValue(ref ClientID);
|
||||
serializer.SerializeValue(ref SyncState);
|
||||
serializer.SerializeValue(ref ActorsSyncPacketsLeft);
|
||||
}
|
||||
}
|
||||
|
||||
public class NetworkSystem : NetworkBehaviour {
|
||||
@@ -25,13 +45,26 @@ namespace RebootKit.Engine.Main {
|
||||
|
||||
internal readonly Dictionary<ulong, NetworkClientState> Clients = new Dictionary<ulong, NetworkClientState>();
|
||||
|
||||
FixedString512Bytes m_WorldID = new FixedString512Bytes("");
|
||||
public FixedString512Bytes WorldID { get; private set; } = new FixedString512Bytes("");
|
||||
bool m_IsChangingWorld = false;
|
||||
|
||||
public ulong LocalClientID {
|
||||
[MethodImpl(MethodImplOptions.AggressiveInlining)]
|
||||
get {
|
||||
return NetworkManager.Singleton.LocalClientId;
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Unity callbacks
|
||||
//
|
||||
void Awake() {
|
||||
RR.NetworkSystemInstance = this;
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: NetworkBehaviour callbacks
|
||||
//
|
||||
public override void OnNetworkSpawn() {
|
||||
base.OnNetworkSpawn();
|
||||
|
||||
@@ -55,35 +88,42 @@ namespace RebootKit.Engine.Main {
|
||||
|
||||
NetworkClientState newClientState = new NetworkClientState {
|
||||
ClientID = clientID,
|
||||
IsWorldLoaded = false,
|
||||
AreActorsSynced = false,
|
||||
IsReadyForActorsSync = false,
|
||||
IsReady = false
|
||||
SyncState = NetworkClientSyncState.NotReady
|
||||
};
|
||||
Clients.Add(clientID, newClientState);
|
||||
|
||||
if (!m_WorldID.IsEmpty) {
|
||||
s_Logger.Info($"Synchronizing world load for client {clientID} with world ID '{m_WorldID}'");
|
||||
ClientLoadWorldRpc(m_WorldID.ToString(), RpcTarget.Single(clientID, RpcTargetUse.Temp));
|
||||
if (clientID != NetworkManager.Singleton.LocalClientId) {
|
||||
foreach (NetworkClientState state in Clients.Values) {
|
||||
UpdateClientStateRpc(state, RpcTarget.Single(clientID, RpcTargetUse.Temp));
|
||||
}
|
||||
}
|
||||
|
||||
if (!WorldID.IsEmpty) {
|
||||
s_Logger.Info($"Synchronizing world load for client {clientID} with world ID '{WorldID}'");
|
||||
ClientLoadWorldRpc(WorldID.ToString(), RpcTarget.Single(clientID, RpcTargetUse.Temp));
|
||||
}
|
||||
}
|
||||
|
||||
void OnClientDisconnect(ulong clientID) {
|
||||
if (!IsServer) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_Logger.Info($"OnClientDisconnect: {clientID}");
|
||||
Clients.Remove(clientID);
|
||||
}
|
||||
|
||||
internal NetworkClientState GetClientState(ulong clientID) {
|
||||
if (Clients.TryGetValue(clientID, out NetworkClientState clientState)) {
|
||||
return clientState;
|
||||
|
||||
//
|
||||
// @MARK: Server API
|
||||
//
|
||||
public void KickClient(ulong clientID, string reason = "Kicked by server") {
|
||||
if (!IsServer) {
|
||||
s_Logger.Error("Only server can kick clients.");
|
||||
return;
|
||||
}
|
||||
|
||||
s_Logger.Error($"Client state for {clientID} not found.");
|
||||
return null;
|
||||
if (NetworkManager.Singleton.ConnectedClients.TryGetValue(clientID, out NetworkClient client)) {
|
||||
NetworkManager.Singleton.DisconnectClient(clientID, reason);
|
||||
s_Logger.Info($"Kicked client {clientID}: {reason}");
|
||||
} else {
|
||||
s_Logger.Error($"Client {clientID} not found.");
|
||||
}
|
||||
}
|
||||
|
||||
public void SetCurrentWorld(string worldID) {
|
||||
@@ -93,7 +133,7 @@ namespace RebootKit.Engine.Main {
|
||||
}
|
||||
|
||||
if (m_IsChangingWorld) {
|
||||
s_Logger.Error($"Already changing world to '{m_WorldID}'. Please wait until the current world change is complete.");
|
||||
s_Logger.Error($"Already changing world to '{WorldID}'. Please wait until the current world change is complete.");
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -103,13 +143,12 @@ namespace RebootKit.Engine.Main {
|
||||
return;
|
||||
}
|
||||
|
||||
m_WorldID = worldID;
|
||||
|
||||
foreach (KeyValuePair<ulong, NetworkClientState> kv in Clients) {
|
||||
kv.Value.IsWorldLoaded = false;
|
||||
kv.Value.AreActorsSynced = false;
|
||||
kv.Value.IsReadyForActorsSync = false;
|
||||
kv.Value.IsReady = false;
|
||||
WorldID = worldID;
|
||||
|
||||
foreach ((ulong _, NetworkClientState clientState) in Clients.ToList()) {
|
||||
NetworkClientState state = clientState;
|
||||
state.SyncState = NetworkClientSyncState.LoadingWorld;
|
||||
UpdateClientState(state);
|
||||
}
|
||||
|
||||
ServerLoadWorldAsync(worldConfigAsset, destroyCancellationToken).Forget();
|
||||
@@ -127,8 +166,14 @@ namespace RebootKit.Engine.Main {
|
||||
|
||||
m_IsChangingWorld = false;
|
||||
|
||||
NetworkClientState localClientState = GetClientState(NetworkManager.Singleton.LocalClientId);
|
||||
localClientState.IsReady = true;
|
||||
if (!TryGetClientState(NetworkManager.Singleton.LocalClientId, out NetworkClientState localClientState)) {
|
||||
s_Logger.Error($"Local client state not found for client ID {NetworkManager.Singleton.LocalClientId}.");
|
||||
RR.Disconnect();
|
||||
return;
|
||||
}
|
||||
|
||||
localClientState.SyncState = NetworkClientSyncState.Ready;
|
||||
UpdateClientState(localClientState);
|
||||
|
||||
RR.GameInstance.PlayerBecameReady(localClientState.ClientID);
|
||||
|
||||
@@ -161,7 +206,7 @@ namespace RebootKit.Engine.Main {
|
||||
|
||||
await RR.World.LoadAsync(worldConfigAsset.Config, cancellationToken);
|
||||
|
||||
m_WorldID = worldID;
|
||||
WorldID = worldID;
|
||||
ClientLoadedWorldRpc(worldID);
|
||||
}
|
||||
|
||||
@@ -169,30 +214,60 @@ namespace RebootKit.Engine.Main {
|
||||
void ClientLoadedWorldRpc(string worldID, RpcParams rpcParams = default) {
|
||||
ulong clientID = rpcParams.Receive.SenderClientId;
|
||||
|
||||
if (!m_WorldID.Equals(worldID)) {
|
||||
s_Logger.Error($"Client {clientID} tried to load world '{worldID}', but server is in world '{m_WorldID}'.");
|
||||
if (!WorldID.Equals(worldID)) {
|
||||
s_Logger.Error($"Client {clientID} tried to load world '{worldID}', but server is in world '{WorldID}'.");
|
||||
NetworkManager.Singleton.DisconnectClient(clientID, "World mismatch!");
|
||||
return;
|
||||
}
|
||||
|
||||
if (Clients.TryGetValue(clientID, out NetworkClientState clientState)) {
|
||||
clientState.IsWorldLoaded = true;
|
||||
clientState.IsReadyForActorsSync = false;
|
||||
Actors.SynchronizeActorsForClient(clientID);
|
||||
Actors.InitializeActorsForClient(clientID);
|
||||
} else {
|
||||
NetworkManager.Singleton.DisconnectClient(clientID, "Client is not registered!");
|
||||
}
|
||||
}
|
||||
|
||||
internal void ClientSynchronizedActors(ulong clientID) {
|
||||
NetworkClientState clientState = GetClientState(clientID);
|
||||
if (clientState is null) {
|
||||
s_Logger.Error($"Client state for {clientID} not found.");
|
||||
|
||||
//
|
||||
// @MARK: Internal
|
||||
//
|
||||
internal bool TryGetClientState(ulong clientID, out NetworkClientState clientState) {
|
||||
return Clients.TryGetValue(clientID, out clientState);
|
||||
}
|
||||
|
||||
internal void UpdateClientState(NetworkClientState clientState) {
|
||||
if (!IsServer) {
|
||||
s_Logger.Error("UpdateClientState can only be called on the server.");
|
||||
return;
|
||||
}
|
||||
|
||||
Clients[clientState.ClientID] = clientState;
|
||||
UpdateClientStateRpc(clientState, RpcTarget.NotServer);
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams, Delivery = RpcDelivery.Reliable)]
|
||||
void UpdateClientStateRpc(NetworkClientState newState, RpcParams rpcParams) {
|
||||
Clients[newState.ClientID] = newState;
|
||||
}
|
||||
|
||||
clientState.IsReady = true;
|
||||
RR.GameInstance.PlayerBecameReady(clientID);
|
||||
internal void ClientSynchronizedActors(ulong clientID) {
|
||||
if (TryGetClientState(clientID, out NetworkClientState state)) {
|
||||
state.SyncState = NetworkClientSyncState.Ready;
|
||||
UpdateClientState(state);
|
||||
|
||||
RR.GameInstance.PlayerBecameReady(clientID);
|
||||
} else {
|
||||
s_Logger.Error($"Client state for {clientID} not found.");
|
||||
}
|
||||
}
|
||||
|
||||
internal int GetReadyClientsCount() {
|
||||
int count = 0;
|
||||
foreach (NetworkClientState clientState in Clients.Values) {
|
||||
if (clientState.IsReady) {
|
||||
count++;
|
||||
}
|
||||
}
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,15 +0,0 @@
|
||||
using RebootKit.Engine.Foundation;
|
||||
using UnityEngine;
|
||||
|
||||
namespace RebootKit.Engine {
|
||||
public class MainSceneInstaller : SceneDependencyInstaller {
|
||||
public override void Install(DIContext context) {
|
||||
foreach (GameObject rootGameObject in gameObject.scene.GetRootGameObjects()) {
|
||||
IService[] services = rootGameObject.GetComponentsInParent<IService>();
|
||||
foreach (IService service in services) {
|
||||
context.Bind(service.GetType(), service);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4238ea1a17e342e583cdd929103a22c6
|
||||
timeCreated: 1742007242
|
||||
@@ -259,25 +259,35 @@ namespace RebootKit.Engine.Simulation {
|
||||
public bool IsDataDirty { get; protected internal set; }
|
||||
|
||||
internal ActorsManager Manager;
|
||||
|
||||
internal DateTime LastCoreStateSyncTime = DateTime.MinValue;
|
||||
|
||||
//
|
||||
// @MARK: Unity callbacks
|
||||
//
|
||||
void OnValidate() {
|
||||
if (ActorID == 0) {
|
||||
ActorID = UniqueID.NewULongFromGuid();
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Callbacks to override in derived classes
|
||||
//
|
||||
|
||||
protected abstract IActorData CreateActorData();
|
||||
|
||||
// Override this method to implement server-side logic
|
||||
public virtual void ServerTick(float deltaTime) { }
|
||||
|
||||
// Override this method to implement client-side logic
|
||||
public virtual void ClientTick(float deltaTime) { }
|
||||
|
||||
// @NOTE: Server-side method to handle actor commands
|
||||
// @MARK: Server side
|
||||
public virtual void OnServerTick(float deltaTime) { }
|
||||
protected virtual void OnActorCommandServer(ActorCommand actorCommand) { }
|
||||
|
||||
// @NOTE: Client-side method to handle actor events
|
||||
// Override this method to implement client-side logic
|
||||
public virtual void OnClientTick(float deltaTime) { }
|
||||
protected virtual void OnActorEventClient(ActorEvent actorEvent) { }
|
||||
protected virtual void OnClientFinishedInitialSync() { }
|
||||
|
||||
//
|
||||
// @MARK: Server API
|
||||
//
|
||||
public void SetHidden(bool hidden) {
|
||||
if (!RR.IsServer()) {
|
||||
s_ActorLogger.Error($"Only the server can set actor visibility. Actor: {name} (ID: {ActorID})");
|
||||
@@ -383,7 +393,9 @@ namespace RebootKit.Engine.Simulation {
|
||||
Manager.SynchronizeActorCoreStateWithOther(this);
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Common API
|
||||
//
|
||||
public bool IsHidden() {
|
||||
return !gameObject.activeSelf;
|
||||
}
|
||||
@@ -457,7 +469,9 @@ namespace RebootKit.Engine.Simulation {
|
||||
return false;
|
||||
}
|
||||
|
||||
// @MARK: Internal API
|
||||
//
|
||||
// @MARK: Internal
|
||||
//
|
||||
internal ActorCoreStateSnapshot GetCoreStateSnapshot() {
|
||||
ActorCoreStateSnapshot snapshot = new ActorCoreStateSnapshot();
|
||||
snapshot.Timestamp = DateTime.UtcNow;
|
||||
@@ -637,7 +651,11 @@ namespace RebootKit.Engine.Simulation {
|
||||
internal IActorData InternalCreateActorData() {
|
||||
return CreateActorData();
|
||||
}
|
||||
|
||||
|
||||
internal void InitialSyncFinished() {
|
||||
OnClientFinishedInitialSync();
|
||||
}
|
||||
|
||||
internal void HandleActorCommand(ActorCommand actorCommand) {
|
||||
if (!RR.IsServer()) {
|
||||
s_ActorLogger.Error($"Only the server can handle actor commands. Actor: {name} (ID: {ActorID})");
|
||||
@@ -672,13 +690,5 @@ namespace RebootKit.Engine.Simulation {
|
||||
|
||||
OnActorEventClient(actorEvent);
|
||||
}
|
||||
|
||||
|
||||
// @MARK: Unity lifecycle methods
|
||||
void OnValidate() {
|
||||
if (ActorID == 0) {
|
||||
ActorID = UniqueID.NewULongFromGuid();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -11,12 +11,20 @@ using Logger = RebootKit.Engine.Foundation.Logger;
|
||||
namespace RebootKit.Engine.Simulation {
|
||||
// @TODO:
|
||||
// - Actors States might be packed into chunks to reduce the number of RPCs sent.
|
||||
// - Release addressables when they are no longer needed.
|
||||
public class ActorsManager : NetworkBehaviour {
|
||||
static readonly Logger s_Logger = new Logger(nameof(ActorsManager));
|
||||
|
||||
readonly List<Actor> m_InSceneActors = new List<Actor>();
|
||||
readonly List<Actor> m_SpawnedActors = new List<Actor>();
|
||||
|
||||
public int InSceneActorsCount { get { return m_InSceneActors.Count; } }
|
||||
public int SpawnedActorsCount { get { return m_SpawnedActors.Count; } }
|
||||
public int TotalActorsCount { get { return m_InSceneActors.Count + m_SpawnedActors.Count; } }
|
||||
|
||||
//
|
||||
// @MARK: NetworkBehaviour callbacks
|
||||
//
|
||||
public override void OnNetworkSpawn() {
|
||||
base.OnNetworkSpawn();
|
||||
RR.ServerTick += OnServerTick;
|
||||
@@ -27,16 +35,22 @@ namespace RebootKit.Engine.Simulation {
|
||||
RR.ServerTick -= OnServerTick;
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Unity callbacks
|
||||
//
|
||||
void Update() {
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
actor.ClientTick(Time.deltaTime);
|
||||
actor.OnClientTick(Time.deltaTime);
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
actor.ClientTick(Time.deltaTime);
|
||||
actor.OnClientTick(Time.deltaTime);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Server-side logic
|
||||
//
|
||||
void OnServerTick(ulong tick) {
|
||||
if (!IsServer) {
|
||||
return;
|
||||
@@ -50,14 +64,14 @@ namespace RebootKit.Engine.Simulation {
|
||||
|
||||
void TickActorsList(List<Actor> actors, float deltaTime) {
|
||||
foreach (Actor actor in actors) {
|
||||
actor.ServerTick(deltaTime);
|
||||
actor.OnServerTick(deltaTime);
|
||||
|
||||
if (actor.IsDataDirty) {
|
||||
actor.IsDataDirty = false;
|
||||
|
||||
NativeArray<byte> data = SerializeActorState(actor);
|
||||
if (data.IsCreated) {
|
||||
SynchronizeActorStateWithClients(actor.ActorID, data);
|
||||
SendActorStateToClients(actor.ActorID, data);
|
||||
} else {
|
||||
s_Logger.Error($"Failed to serialize actor data for {actor.name}");
|
||||
}
|
||||
@@ -84,7 +98,7 @@ namespace RebootKit.Engine.Simulation {
|
||||
SynchronizeCoreActorStateRpc(actor.ActorID, actor.GetCoreStateSnapshot(), RpcTarget.NotMe);
|
||||
}
|
||||
|
||||
void SynchronizeActorStateWithClients(ulong actorID, NativeArray<byte> data) {
|
||||
void SendActorStateToClients(ulong actorID, NativeArray<byte> data) {
|
||||
if (!RR.IsServer()) {
|
||||
s_Logger.Error("Only the server can synchronize actor states with clients.");
|
||||
return;
|
||||
@@ -103,9 +117,8 @@ namespace RebootKit.Engine.Simulation {
|
||||
if (actor is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
s_Logger.Info($"Synchronizing actor state for {actor.name} with ID {actorID}");
|
||||
|
||||
s_Logger.Info($"Synchronizing actor state for {actor.name} with ID {actorID}");
|
||||
DeserializeActorState(actor, data);
|
||||
}
|
||||
|
||||
@@ -127,197 +140,10 @@ namespace RebootKit.Engine.Simulation {
|
||||
void DeserializeActorState(Actor actor, NativeArray<byte> data) {
|
||||
DataSerializationUtils.Deserialize(data, ref actor.Data);
|
||||
}
|
||||
|
||||
internal void SynchronizeActorsForClient(ulong clientID) {
|
||||
NetworkClientState clientState = RR.NetworkSystemInstance.GetClientState(clientID);
|
||||
if (clientState == null) {
|
||||
s_Logger.Error($"Client state for {clientID} not found. Cannot synchronize actors.");
|
||||
return;
|
||||
}
|
||||
|
||||
PrepareClientForActorsSyncRpc(RpcTarget.Single(clientState.ClientID, RpcTargetUse.Temp));
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams, Delivery = RpcDelivery.Reliable)]
|
||||
void PrepareClientForActorsSyncRpc(RpcParams rpcParams) {
|
||||
foreach (Actor spawnedActor in m_SpawnedActors) {
|
||||
Destroy(spawnedActor.gameObject);
|
||||
}
|
||||
|
||||
m_SpawnedActors.Clear();
|
||||
|
||||
ClientIsReadyForActorsSyncRpc();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server)]
|
||||
void ClientIsReadyForActorsSyncRpc(RpcParams rpcParams = default) {
|
||||
ulong clientID = rpcParams.Receive.SenderClientId;
|
||||
NetworkClientState clientState = RR.NetworkSystemInstance.GetClientState(clientID);
|
||||
if (clientState == null) {
|
||||
s_Logger.Error($"Client state for {clientID} not found. Cannot mark client as ready for actors sync.");
|
||||
return;
|
||||
}
|
||||
|
||||
clientState.IsReadyForActorsSync = true;
|
||||
clientState.ActorsSyncPacketsLeft = m_InSceneActors.Count;
|
||||
|
||||
RpcSendParams sendParams = RpcTarget.Single(clientID, RpcTargetUse.Temp);
|
||||
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
NativeArray<byte> data = SerializeActorState(actor);
|
||||
if (!data.IsCreated) {
|
||||
s_Logger.Error($"Failed to serialize actor data for {actor.name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
SynchronizeActorStateForClientRpc(actor.ActorID, actor.GetCoreStateSnapshot(), data, sendParams);
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
NativeArray<byte> data = SerializeActorState(actor);
|
||||
if (!data.IsCreated) {
|
||||
s_Logger.Error($"Failed to serialize actor data for {actor.name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
ActorCoreStateSnapshot coreStateSnapshot = actor.GetCoreStateSnapshot();
|
||||
SpawnActorRpc(actor.SourceActorPath,
|
||||
actor.ActorID,
|
||||
coreStateSnapshot,
|
||||
data,
|
||||
sendParams);
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams, Delivery = RpcDelivery.Reliable)]
|
||||
void SynchronizeActorStateForClientRpc(ulong actorID,
|
||||
ActorCoreStateSnapshot coreStateSnapshot,
|
||||
NativeArray<byte> data,
|
||||
RpcParams rpcParams) {
|
||||
Actor actor = FindActorByID(actorID);
|
||||
if (actor is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
actor.RestoreCoreState(coreStateSnapshot);
|
||||
DeserializeActorState(actor, data);
|
||||
ClientSynchronizedActorRpc();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams, Delivery = RpcDelivery.Reliable)]
|
||||
void SynchronizeCoreActorStateRpc(ulong actorID, ActorCoreStateSnapshot snapshot, RpcParams rpcParams) {
|
||||
Actor actor = FindActorByID(actorID);
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"Actor with ID {actorID} not found for core state synchronization.");
|
||||
return;
|
||||
}
|
||||
|
||||
actor.RestoreCoreState(snapshot);
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server, Delivery = RpcDelivery.Reliable)]
|
||||
void ClientSynchronizedActorRpc(RpcParams rpcParams = default) {
|
||||
ulong clientID = rpcParams.Receive.SenderClientId;
|
||||
|
||||
NetworkClientState clientState = RR.NetworkSystemInstance.GetClientState(clientID);
|
||||
if (clientState == null) {
|
||||
s_Logger.Error($"Client state for {clientID} not found. Cannot mark client as synchronized.");
|
||||
return;
|
||||
}
|
||||
|
||||
clientState.ActorsSyncPacketsLeft--;
|
||||
if (clientState.ActorsSyncPacketsLeft == 0) {
|
||||
RR.NetworkSystemInstance.ClientSynchronizedActors(clientID);
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server, Delivery = RpcDelivery.Reliable)]
|
||||
internal void SendActorCommandToServerRpc(ActorCommand cmd) {
|
||||
if (!IsServer) {
|
||||
s_Logger.Error("Only the server can handle actor events.");
|
||||
return;
|
||||
}
|
||||
|
||||
Actor actor = FindActorByID(cmd.ActorID);
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"Actor with ID {cmd.ActorID} not found for command {cmd.CommandID}");
|
||||
return;
|
||||
}
|
||||
|
||||
actor.HandleActorCommand(cmd);
|
||||
}
|
||||
|
||||
internal void SendActorEvent(ActorEvent actorEvent) {
|
||||
if (!RR.IsServer()) {
|
||||
s_Logger.Error("Only the server can send actor events.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ((ulong clientID, NetworkClientState state) in RR.NetworkSystemInstance.Clients) {
|
||||
if (state.IsReady) {
|
||||
SendActorEventRpc(actorEvent, RpcTarget.Single(clientID, RpcTargetUse.Temp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams)]
|
||||
void SendActorEventRpc(ActorEvent actorEvent, RpcParams rpcParams) {
|
||||
Actor actor = FindActorByID(actorEvent.ActorID);
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"Actor with ID {actorEvent.ActorID} not found for event {actorEvent.EventID}");
|
||||
return;
|
||||
}
|
||||
|
||||
actor.HandleActorEvent(actorEvent);
|
||||
}
|
||||
|
||||
public void RegisterInSceneActor(Actor actor) {
|
||||
if (actor.Data == null) {
|
||||
actor.Data = actor.InternalCreateActorData();
|
||||
}
|
||||
|
||||
actor.Manager = this;
|
||||
|
||||
m_InSceneActors.Add(actor);
|
||||
}
|
||||
|
||||
public void CleanUp() {
|
||||
if (IsServer) {
|
||||
CleanUpRpc();
|
||||
}
|
||||
|
||||
m_InSceneActors.Clear();
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
if (actor.OrNull() != null) {
|
||||
Destroy(actor.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
m_SpawnedActors.Clear();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.NotMe)]
|
||||
void CleanUpRpc() {
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
public Actor FindActorByID(ulong actorID) {
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
if (actor.ActorID == actorID) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
if (actor.ActorID == actorID) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// @MARK: Server API
|
||||
//
|
||||
public Actor SpawnActor(AssetReferenceGameObject assetReference, Vector3 position, Quaternion rotation) {
|
||||
if (!IsServer) {
|
||||
s_Logger.Error("Only the server can spawn actors.");
|
||||
@@ -412,5 +238,205 @@ namespace RebootKit.Engine.Simulation {
|
||||
|
||||
Destroy(actor.gameObject);
|
||||
}
|
||||
|
||||
public void CleanUp() {
|
||||
if (IsServer) {
|
||||
CleanUpRpc();
|
||||
}
|
||||
|
||||
m_InSceneActors.Clear();
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
if (actor.OrNull() != null) {
|
||||
Destroy(actor.gameObject);
|
||||
}
|
||||
}
|
||||
|
||||
m_SpawnedActors.Clear();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.NotMe)]
|
||||
void CleanUpRpc() {
|
||||
CleanUp();
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Common API
|
||||
//
|
||||
public void RegisterInSceneActor(Actor actor) {
|
||||
if (actor.Data == null) {
|
||||
actor.Data = actor.InternalCreateActorData();
|
||||
}
|
||||
|
||||
actor.Manager = this;
|
||||
|
||||
m_InSceneActors.Add(actor);
|
||||
}
|
||||
|
||||
public Actor FindActorByID(ulong actorID) {
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
if (actor.ActorID == actorID) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
if (actor.ActorID == actorID) {
|
||||
return actor;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Initial synchronization
|
||||
//
|
||||
internal void InitializeActorsForClient(ulong clientID) {
|
||||
if (RR.NetworkSystemInstance.TryGetClientState(clientID, out NetworkClientState clientState)) {
|
||||
clientState.SyncState = NetworkClientSyncState.PreparingForActorsSync;
|
||||
RR.NetworkSystemInstance.UpdateClientState(clientState);
|
||||
PrepareClientForActorsSyncRpc(RpcTarget.Single(clientState.ClientID, RpcTargetUse.Temp));
|
||||
} else {
|
||||
s_Logger.Error($"Client state for {clientID} not found. Cannot synchronize actors.");
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams, Delivery = RpcDelivery.Reliable)]
|
||||
void PrepareClientForActorsSyncRpc(RpcParams rpcParams) {
|
||||
foreach (Actor spawnedActor in m_SpawnedActors) {
|
||||
Destroy(spawnedActor.gameObject);
|
||||
}
|
||||
|
||||
m_SpawnedActors.Clear();
|
||||
|
||||
ClientIsReadyForActorsSyncRpc();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server)]
|
||||
void ClientIsReadyForActorsSyncRpc(RpcParams rpcParams = default) {
|
||||
ulong clientID = rpcParams.Receive.SenderClientId;
|
||||
if (!RR.NetworkSystemInstance.TryGetClientState(clientID, out NetworkClientState clientState)) {
|
||||
s_Logger.Error($"Client state for {clientID} not found. Cannot mark client as ready for actors sync.");
|
||||
return;
|
||||
}
|
||||
|
||||
clientState.SyncState = NetworkClientSyncState.SyncingActors;
|
||||
clientState.ActorsSyncPacketsLeft = m_InSceneActors.Count;
|
||||
RR.NetworkSystemInstance.UpdateClientState(clientState);
|
||||
|
||||
RpcSendParams sendParams = RpcTarget.Single(clientID, RpcTargetUse.Temp);
|
||||
|
||||
foreach (Actor actor in m_InSceneActors) {
|
||||
NativeArray<byte> data = SerializeActorState(actor);
|
||||
if (!data.IsCreated) {
|
||||
s_Logger.Error($"Failed to serialize actor data for {actor.name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
SynchronizeActorStateForClientRpc(actor.ActorID, actor.GetCoreStateSnapshot(), data, sendParams);
|
||||
}
|
||||
|
||||
foreach (Actor actor in m_SpawnedActors) {
|
||||
NativeArray<byte> data = SerializeActorState(actor);
|
||||
if (!data.IsCreated) {
|
||||
s_Logger.Error($"Failed to serialize actor data for {actor.name}");
|
||||
continue;
|
||||
}
|
||||
|
||||
ActorCoreStateSnapshot coreStateSnapshot = actor.GetCoreStateSnapshot();
|
||||
SpawnActorRpc(actor.SourceActorPath,
|
||||
actor.ActorID,
|
||||
coreStateSnapshot,
|
||||
data,
|
||||
sendParams);
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams, Delivery = RpcDelivery.Reliable)]
|
||||
void SynchronizeActorStateForClientRpc(ulong actorID,
|
||||
ActorCoreStateSnapshot coreStateSnapshot,
|
||||
NativeArray<byte> data,
|
||||
RpcParams rpcParams) {
|
||||
Actor actor = FindActorByID(actorID);
|
||||
if (actor is null) {
|
||||
return;
|
||||
}
|
||||
|
||||
actor.RestoreCoreState(coreStateSnapshot);
|
||||
DeserializeActorState(actor, data);
|
||||
ClientSynchronizedActorRpc();
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams, Delivery = RpcDelivery.Reliable)]
|
||||
void SynchronizeCoreActorStateRpc(ulong actorID, ActorCoreStateSnapshot snapshot, RpcParams rpcParams) {
|
||||
Actor actor = FindActorByID(actorID);
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"Actor with ID {actorID} not found for core state synchronization.");
|
||||
return;
|
||||
}
|
||||
|
||||
actor.RestoreCoreState(snapshot);
|
||||
}
|
||||
|
||||
[Rpc(SendTo.Server, Delivery = RpcDelivery.Reliable)]
|
||||
void ClientSynchronizedActorRpc(RpcParams rpcParams = default) {
|
||||
ulong clientID = rpcParams.Receive.SenderClientId;
|
||||
|
||||
if (!RR.NetworkSystemInstance.TryGetClientState(clientID, out NetworkClientState clientState)) {
|
||||
s_Logger.Error($"Client state for {clientID} not found. Cannot mark client as synchronized.");
|
||||
return;
|
||||
}
|
||||
|
||||
clientState.ActorsSyncPacketsLeft--;
|
||||
RR.NetworkSystemInstance.UpdateClientState(clientState);
|
||||
|
||||
if (clientState.ActorsSyncPacketsLeft == 0) {
|
||||
RR.NetworkSystemInstance.ClientSynchronizedActors(clientID);
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// @MARK: Actor Commands and Events
|
||||
//
|
||||
[Rpc(SendTo.Server, Delivery = RpcDelivery.Reliable)]
|
||||
internal void SendActorCommandToServerRpc(ActorCommand cmd) {
|
||||
if (!IsServer) {
|
||||
s_Logger.Error("Only the server can handle actor events.");
|
||||
return;
|
||||
}
|
||||
|
||||
Actor actor = FindActorByID(cmd.ActorID);
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"Actor with ID {cmd.ActorID} not found for command {cmd.CommandID}");
|
||||
return;
|
||||
}
|
||||
|
||||
actor.HandleActorCommand(cmd);
|
||||
}
|
||||
|
||||
internal void SendActorEvent(ActorEvent actorEvent) {
|
||||
if (!RR.IsServer()) {
|
||||
s_Logger.Error("Only the server can send actor events.");
|
||||
return;
|
||||
}
|
||||
|
||||
foreach ((ulong clientID, NetworkClientState state) in RR.NetworkSystemInstance.Clients) {
|
||||
if (state.IsReady) {
|
||||
SendActorEventRpc(actorEvent, RpcTarget.Single(clientID, RpcTargetUse.Temp));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
[Rpc(SendTo.SpecifiedInParams)]
|
||||
void SendActorEventRpc(ActorEvent actorEvent, RpcParams rpcParams) {
|
||||
Actor actor = FindActorByID(actorEvent.ActorID);
|
||||
if (actor is null) {
|
||||
s_Logger.Error($"Actor with ID {actorEvent.ActorID} not found for event {actorEvent.EventID}");
|
||||
return;
|
||||
}
|
||||
|
||||
actor.HandleActorEvent(actorEvent);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -16,7 +16,9 @@
|
||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||
"GUID:f2d49d9fa7e7eb3418e39723a7d3b92f",
|
||||
"GUID:324caed91501a9c47a04ebfd87b68794",
|
||||
"GUID:1491147abca9d7d4bb7105af628b223e"
|
||||
"GUID:1491147abca9d7d4bb7105af628b223e",
|
||||
"GUID:b1cd7326e664a434ab35daa802773c7f",
|
||||
"GUID:2c360f3794ebc41388fc11424ddbfdd0"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
|
||||
8
Runtime/Engine/core_assets/fonts.meta
Normal file
8
Runtime/Engine/core_assets/fonts.meta
Normal file
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1ef6cf326b7733c4b88b6fcc7f9cfd36
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Bold.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Bold.ttf
Normal file
Binary file not shown.
21
Runtime/Engine/core_assets/fonts/JetBrainsMono-Bold.ttf.meta
Normal file
21
Runtime/Engine/core_assets/fonts/JetBrainsMono-Bold.ttf.meta
Normal file
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e0588287147a97a4f9c935f5c65bd309
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-BoldItalic.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-BoldItalic.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 60c63702be318df4bb321722e4771886
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-ExtraBold.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-ExtraBold.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 63cae67a8dd6d314c9f90b4015047330
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: bd60d77bddcc9e841985da2eb7b885df
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-ExtraLight.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-ExtraLight.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 46679f55857999344b12abedb0b7851a
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c6183785f78a93b4ea0d67248008f675
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Italic.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Italic.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 1d3c74f3bed9a7c4eaec31c47785ba7f
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Light.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Light.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8cf077f0384b7ae4c9d8d56492da4232
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-LightItalic.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-LightItalic.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 23ff663a7d9068040aab4eb93825c0ce
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Medium.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-Medium.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c726f57dfd3fd6d4facf5f713795cfad
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-MediumItalic.ttf
Normal file
BIN
Runtime/Engine/core_assets/fonts/JetBrainsMono-MediumItalic.ttf
Normal file
Binary file not shown.
@@ -0,0 +1,21 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2060a838e688b8644ae8a08b867f1740
|
||||
TrueTypeFontImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 4
|
||||
fontSize: 16
|
||||
forceTextureCase: -2
|
||||
characterSpacing: 0
|
||||
characterPadding: 1
|
||||
includeFontData: 1
|
||||
fontNames:
|
||||
- JetBrains Mono
|
||||
fallbackFontReferences: []
|
||||
customCharacters:
|
||||
fontRenderingMode: 0
|
||||
ascentCalculationMode: 1
|
||||
useLegacyBoundsCalculation: 0
|
||||
shouldRoundAdvanceValue: 1
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -132,6 +132,7 @@ GameObject:
|
||||
- component: {fileID: 330585544}
|
||||
- component: {fileID: 330585547}
|
||||
- component: {fileID: 330585548}
|
||||
- component: {fileID: 330585549}
|
||||
m_Layer: 0
|
||||
m_Name: camera_main
|
||||
m_TagString: MainCamera
|
||||
@@ -194,7 +195,7 @@ Camera:
|
||||
m_HDR: 1
|
||||
m_AllowMSAA: 1
|
||||
m_AllowDynamicResolution: 0
|
||||
m_ForceIntoRT: 0
|
||||
m_ForceIntoRT: 1
|
||||
m_OcclusionCulling: 1
|
||||
m_StereoConvergence: 10
|
||||
m_StereoSeparation: 0.022
|
||||
@@ -289,6 +290,19 @@ MonoBehaviour:
|
||||
m_PostInfinity: 2
|
||||
m_RotationOrder: 4
|
||||
CustomBlends: {fileID: 0}
|
||||
--- !u!114 &330585549
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 330585543}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 351d6b8577644d599058e76fa02a11c0, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
<Camera>k__BackingField: {fileID: 330585545}
|
||||
--- !u!1 &379890219
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -337,7 +351,7 @@ MonoBehaviour:
|
||||
m_PanelSettings: {fileID: 11400000, guid: c4c93f1ef3cc3324696c439305139cbb, type: 2}
|
||||
m_ParentUI: {fileID: 0}
|
||||
sourceAsset: {fileID: 9197481963319205126, guid: 15eee085e73feee4eba58c073b1455c5, type: 3}
|
||||
m_SortingOrder: 0
|
||||
m_SortingOrder: 10000
|
||||
m_WorldSpaceSizeMode: 1
|
||||
m_WorldSpaceWidth: 1920
|
||||
m_WorldSpaceHeight: 1080
|
||||
@@ -386,7 +400,7 @@ MonoBehaviour:
|
||||
Rules:
|
||||
- Type: 0
|
||||
Name:
|
||||
GameObject: {fileID: 647954086}
|
||||
GameObject: {fileID: 0}
|
||||
Ordinal: 0
|
||||
Priority: 0
|
||||
IconType: 0
|
||||
@@ -444,7 +458,7 @@ MonoBehaviour:
|
||||
m_PanelSettings: {fileID: 11400000, guid: c4c93f1ef3cc3324696c439305139cbb, type: 2}
|
||||
m_ParentUI: {fileID: 0}
|
||||
sourceAsset: {fileID: 9197481963319205126, guid: c2f32d01bf5f9d644aee3c2a41b14a66, type: 3}
|
||||
m_SortingOrder: 1000
|
||||
m_SortingOrder: 9999
|
||||
m_WorldSpaceSizeMode: 1
|
||||
m_WorldSpaceWidth: 1920
|
||||
m_WorldSpaceHeight: 1080
|
||||
@@ -476,79 +490,6 @@ MonoBehaviour:
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Document: {fileID: 638618785}
|
||||
--- !u!1 &647954086
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
serializedVersion: 6
|
||||
m_Component:
|
||||
- component: {fileID: 647954090}
|
||||
- component: {fileID: 647954089}
|
||||
- component: {fileID: 647954088}
|
||||
- component: {fileID: 647954087}
|
||||
m_Layer: 0
|
||||
m_Name: scene_context
|
||||
m_TagString: Untagged
|
||||
m_Icon: {fileID: 0}
|
||||
m_NavMeshLayer: 0
|
||||
m_StaticEditorFlags: 0
|
||||
m_IsActive: 1
|
||||
--- !u!114 &647954087
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 647954086}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 4238ea1a17e342e583cdd929103a22c6, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
--- !u!114 &647954088
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 647954086}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 351d6b8577644d599058e76fa02a11c0, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
<Camera>k__BackingField: {fileID: 330585545}
|
||||
--- !u!114 &647954089
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 647954086}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 11500000, guid: 8dd28652b58c4d689ab3f2f9354d7589, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
m_Installers:
|
||||
- {fileID: 647954087}
|
||||
--- !u!4 &647954090
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 647954086}
|
||||
serializedVersion: 2
|
||||
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
|
||||
m_LocalPosition: {x: 0, y: 0, z: 0}
|
||||
m_LocalScale: {x: 1, y: 1, z: 1}
|
||||
m_ConstrainProportionsScale: 0
|
||||
m_Children: []
|
||||
m_Father: {fileID: 0}
|
||||
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
|
||||
--- !u!1 &735095186
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -680,7 +621,7 @@ MonoBehaviour:
|
||||
m_EditorClassIdentifier:
|
||||
m_DebugOverlayView: {fileID: 1809244332}
|
||||
m_GameVersionOverlay: {fileID: 638618787}
|
||||
m_NetworkStatsOverlay: {fileID: 735095186}
|
||||
m_NetworkStatsOverlay: {fileID: 735095187}
|
||||
--- !u!4 &1493735124
|
||||
Transform:
|
||||
m_ObjectHideFlags: 0
|
||||
@@ -747,7 +688,7 @@ MonoBehaviour:
|
||||
m_PanelSettings: {fileID: 11400000, guid: c4c93f1ef3cc3324696c439305139cbb, type: 2}
|
||||
m_ParentUI: {fileID: 0}
|
||||
sourceAsset: {fileID: 9197481963319205126, guid: efa5e4d1b21059c448f8a23fbe41890a, type: 3}
|
||||
m_SortingOrder: 0
|
||||
m_SortingOrder: 9999
|
||||
m_WorldSpaceSizeMode: 1
|
||||
m_WorldSpaceWidth: 1920
|
||||
m_WorldSpaceHeight: 1080
|
||||
@@ -768,7 +709,6 @@ MonoBehaviour:
|
||||
SceneRoots:
|
||||
m_ObjectHideFlags: 0
|
||||
m_Roots:
|
||||
- {fileID: 647954090}
|
||||
- {fileID: 330585546}
|
||||
- {fileID: 1468139327}
|
||||
- {fileID: 1493735124}
|
||||
|
||||
File diff suppressed because one or more lines are too long
4
Runtime/Engine/core_assets/ui/panel_rebootkit.asset → Runtime/Engine/core_assets/ui/panel_rebootkit_overlay.asset
Executable file → Normal file
4
Runtime/Engine/core_assets/ui/panel_rebootkit.asset → Runtime/Engine/core_assets/ui/panel_rebootkit_overlay.asset
Executable file → Normal file
@@ -10,7 +10,7 @@ MonoBehaviour:
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 19101, guid: 0000000000000000e000000000000000, type: 0}
|
||||
m_Name: panel_rebootkit
|
||||
m_Name: panel_rebootkit_overlay
|
||||
m_EditorClassIdentifier:
|
||||
themeUss: {fileID: -4733365628477956816, guid: 5dd55e8f9f3419144b6d6fc3fcc478d0, type: 3}
|
||||
m_DisableNoThemeWarning: 0
|
||||
@@ -26,7 +26,7 @@ MonoBehaviour:
|
||||
m_ReferenceResolution: {x: 1200, y: 800}
|
||||
m_ScreenMatchMode: 0
|
||||
m_Match: 0
|
||||
m_SortingOrder: 0
|
||||
m_SortingOrder: 500
|
||||
m_TargetDisplay: 0
|
||||
m_BindingLogLevel: 0
|
||||
m_ClearDepthStencil: 1
|
||||
0
Runtime/Engine/core_assets/ui/panel_rebootkit.asset.meta → Runtime/Engine/core_assets/ui/panel_rebootkit_overlay.asset.meta
Executable file → Normal file
0
Runtime/Engine/core_assets/ui/panel_rebootkit.asset.meta → Runtime/Engine/core_assets/ui/panel_rebootkit_overlay.asset.meta
Executable file → Normal file
@@ -1,4 +1,3 @@
|
||||
|
||||
@import url("/Assets/UI Toolkit/UnityThemes/UnityDefaultRuntimeTheme.tss");
|
||||
|
||||
.rr-base {
|
||||
@@ -66,10 +65,10 @@
|
||||
/* Text Field */
|
||||
.rr-text-field {
|
||||
min-height: 32px;
|
||||
|
||||
|
||||
padding: 0;
|
||||
margin: 4px;
|
||||
|
||||
|
||||
--unity-cursor-color: #dedede;
|
||||
}
|
||||
|
||||
@@ -78,7 +77,7 @@
|
||||
border-color: #373737;
|
||||
border-radius: 3px;
|
||||
border-width: 1px;
|
||||
|
||||
|
||||
padding: 4px;
|
||||
}
|
||||
|
||||
@@ -136,9 +135,11 @@
|
||||
width: 72px;
|
||||
}
|
||||
|
||||
.rr__debug-label {
|
||||
color: #00ff00;
|
||||
-unity-font-style: bold;
|
||||
font-size: 18px;
|
||||
text-shadow: 1px 1px 16px rgba(0, 0, 0, 0.75);
|
||||
.rr__debug-overlay-label {
|
||||
color: #ffffff;
|
||||
-unity-text-outline-color: black;
|
||||
-unity-text-outline-width: 1px;
|
||||
font-size: 16px;
|
||||
-unity-font-definition: url("project://database/Assets/RebootKit/Runtime/Engine/core_assets/fonts/JetBrainsMono-Bold.ttf");
|
||||
text-shadow: 0 2px 16px rgba(0, 0, 0, 0.75);
|
||||
}
|
||||
|
||||
@@ -1,9 +0,0 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<engine:UXML
|
||||
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
|
||||
xmlns:engine="UnityEngine.UIElements"
|
||||
xmlns:editor="UnityEditor.UIElements"
|
||||
xsi:noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd"
|
||||
>
|
||||
|
||||
</engine:UXML>
|
||||
6
Runtime/Engine/core_assets/ui/ui_root_container.uxml → Runtime/Engine/core_assets/ui/ui_debug_overlay_container.uxml
Executable file → Normal file
6
Runtime/Engine/core_assets/ui/ui_root_container.uxml → Runtime/Engine/core_assets/ui/ui_debug_overlay_container.uxml
Executable file → Normal file
@@ -1,3 +1,3 @@
|
||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<engine:VisualElement name="root__container" style="flex-grow: 1;" />
|
||||
</engine:UXML>
|
||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<engine:VisualElement name="root__container" picking-mode="Ignore" style="flex-grow: 1;" />
|
||||
</engine:UXML>
|
||||
0
Runtime/Engine/core_assets/ui/ui_root_container.uxml.meta → Runtime/Engine/core_assets/ui/ui_debug_overlay_container.uxml.meta
Executable file → Normal file
0
Runtime/Engine/core_assets/ui/ui_root_container.uxml.meta → Runtime/Engine/core_assets/ui/ui_debug_overlay_container.uxml.meta
Executable file → Normal file
5
Runtime/Engine/core_assets/ui/ui_game_version.uxml
Normal file
5
Runtime/Engine/core_assets/ui/ui_game_version.uxml
Normal file
@@ -0,0 +1,5 @@
|
||||
<engine:UXML xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:engine="UnityEngine.UIElements" xmlns:editor="UnityEditor.UIElements" noNamespaceSchemaLocation="../../../UIElementsSchema/UIElements.xsd" editor-extension-mode="False">
|
||||
<engine:VisualElement picking-mode="Ignore" style="flex-grow: 1;">
|
||||
<engine:Label text="ver. 0.1.0 (RR_DEBUG)" name="rr-dev__version_label" style="position: absolute; right: 0; bottom: 0; -unity-text-align: upper-right; font-size: 14px; -unity-font-style: bold; -unity-font-definition: url("project://database/Assets/TextMesh%20Pro/Fonts/LiberationSans.ttf?fileID=12800000&guid=e3265ab4bf004d28a9537516768c1c75&type=3#LiberationSans"); color: rgba(255, 255, 255, 0.7); -unity-text-outline-width: 1px; -unity-text-outline-color: rgba(0, 0, 0, 0.99); text-shadow: 0 1px 10px rgba(0, 0, 0, 0.59);" />
|
||||
</engine:VisualElement>
|
||||
</engine:UXML>
|
||||
2
Runtime/Engine/core_assets/ui/ui_debug_overlay.uxml.meta → Runtime/Engine/core_assets/ui/ui_game_version.uxml.meta
Executable file → Normal file
2
Runtime/Engine/core_assets/ui/ui_debug_overlay.uxml.meta → Runtime/Engine/core_assets/ui/ui_game_version.uxml.meta
Executable file → Normal file
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f775bf05b095519478da40645323ba90
|
||||
guid: c2f32d01bf5f9d644aee3c2a41b14a66
|
||||
ScriptedImporter:
|
||||
internalIDToNameTable: []
|
||||
externalObjects: {}
|
||||
@@ -1,75 +0,0 @@
|
||||
using NUnit.Framework;
|
||||
using RebootKit.Engine.Foundation;
|
||||
|
||||
namespace Tests.Runtime.Engine {
|
||||
interface ITestService {
|
||||
int Value();
|
||||
}
|
||||
|
||||
class TestServiceA : ITestService {
|
||||
public const int k_ReturnValue = 1;
|
||||
|
||||
public int Value() {
|
||||
return k_ReturnValue;
|
||||
}
|
||||
}
|
||||
|
||||
class TestServiceB : ITestService {
|
||||
public const int k_ReturnValue = 2;
|
||||
|
||||
public int Value() {
|
||||
return k_ReturnValue;
|
||||
}
|
||||
}
|
||||
|
||||
public class DIContextTests {
|
||||
[Test]
|
||||
public void Single_Bind_And_Resolve() {
|
||||
DIContext context = new DIContext();
|
||||
context.Bind<ITestService>(new TestServiceA());
|
||||
|
||||
ITestService testService = context.Resolve<ITestService>();
|
||||
Assert.IsNotNull(testService, "Resolved service is null!");
|
||||
|
||||
Assert.IsTrue(testService.Value() == TestServiceA.k_ReturnValue, "Invalid return value of resolved service");
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Single_Bind_And_Field_Inject() {
|
||||
DIContext context = new DIContext();
|
||||
context.Bind<ITestService>(new TestServiceB());
|
||||
|
||||
TestObject obj = new TestObject();
|
||||
context.Inject(obj);
|
||||
|
||||
Assert.IsNotNull(obj.Service, "obj.Service != null");
|
||||
Assert.IsTrue(obj.Service.Value() == TestServiceB.k_ReturnValue);
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void Single_Bind_And_Method_Inject() {
|
||||
DIContext context = new DIContext();
|
||||
context.Bind<ITestService>(new TestServiceA());
|
||||
|
||||
TestObjectMethod obj = new TestObjectMethod();
|
||||
context.Inject(obj);
|
||||
|
||||
Assert.IsNotNull(obj.Service, "obj.Service != null");
|
||||
Assert.IsTrue(obj.Service.Value() == TestServiceA.k_ReturnValue);
|
||||
}
|
||||
|
||||
class TestObject {
|
||||
[Inject] public ITestService Service;
|
||||
}
|
||||
|
||||
|
||||
class TestObjectMethod {
|
||||
public ITestService Service;
|
||||
|
||||
[Inject]
|
||||
public void Setup(ITestService service) {
|
||||
Service = service;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,3 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fb99eda81d534ddcb15cff09441d98bc
|
||||
timeCreated: 1742002479
|
||||
Reference in New Issue
Block a user