This commit is contained in:
2025-03-14 19:53:29 +01:00
commit 0d3516774e
159 changed files with 9069 additions and 0 deletions

View File

@@ -0,0 +1,22 @@
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Services.Console;
using RebootKit.Engine.Services.Game;
using RebootKit.Engine.Services.Input;
using RebootKit.Engine.Services.Simulation;
using UnityEngine;
namespace RebootKit.Engine {
[CreateAssetMenu(menuName = RConsts.AssetMenu + RConsts.EngineConfigAssetName, fileName = RConsts.EngineConfigAssetName)]
public class EngineConfigAsset : ScriptableObject {
[Header("<color=#ff0000>REQUIRED</color>: core assets")]
public ServiceAsset<ConsoleService> ConsoleService;
public ServiceAsset<InputService> InputService;
public ServiceAsset<WorldService> WorldService;
public ServiceAsset<GameService> GameService;
[Space]
public ServiceAsset[] Services;
public GameModeAsset StartingGameMode;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ae5fb4e9fdf89f64b8d2e2d147cb0231

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 68a77eab007d4aa39f16e9cc3485fab9
timeCreated: 1740755614

View File

@@ -0,0 +1,13 @@
using UnityEngine;
namespace RebootKit.Engine.Foundation
{
public abstract class ControllerAsset<TController> : ScriptableObject where TController : IController
{
public abstract TController Create();
}
public abstract class ControllerAsset : ControllerAsset<IController>
{
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 44e7c0513ef44634cbe6c6814772bfe1

View File

@@ -0,0 +1,51 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
using UnityEngine.SceneManagement;
namespace RebootKit.Engine.Foundation {
public static class EntryPoint {
private static readonly Logger _logger = new(nameof(EntryPoint));
private static CancellationTokenSource _cancellationTokenSource;
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.AfterSceneLoad)]
public static void Start() {
if (_cancellationTokenSource != null) {
_cancellationTokenSource.Cancel();
}
RR.Shared = null;
ServicesLocator.Shared.UnRegisterAll();
_cancellationTokenSource = new CancellationTokenSource();
SceneManager.LoadScene(0, LoadSceneMode.Single);
RunAsync(_cancellationTokenSource.Token).Forget();
#if UNITY_EDITOR
static void OnPlayerModeState(UnityEditor.PlayModeStateChange state) {
if (state == UnityEditor.PlayModeStateChange.ExitingPlayMode) {
_cancellationTokenSource.Cancel();
}
}
UnityEditor.EditorApplication.playModeStateChanged -= OnPlayerModeState;
UnityEditor.EditorApplication.playModeStateChanged += OnPlayerModeState;
#endif
}
public static async UniTask RunAsync(CancellationToken cancellationToken) {
using RR instance = new RR();
RR.Shared = instance;
_logger.Debug("running");
await instance.Init(cancellationToken);
await instance.Run(cancellationToken);
_logger.Debug("stopped");
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 83bc8a98e30147babef3641863699cd9
timeCreated: 1740670775

View File

@@ -0,0 +1,93 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
namespace RebootKit.Engine.Foundation {
public interface IController : IDisposable {
UniTask OnStart(CancellationToken cancellationToken);
void OnStop();
void OnTick();
}
public class ControllersManager : IDisposable {
private readonly List<IController> _controllers = new();
private bool _isRunning;
private readonly CancellationToken _cancellationToken;
public ControllersManager(CancellationToken cancellationToken) {
_cancellationToken = cancellationToken;
}
public void Dispose() {
foreach (IController controller in _controllers) {
controller.Dispose();
}
}
public void Add(IController controller) {
_controllers.Add(controller);
if (_isRunning) {
controller.OnStart(_cancellationToken);
}
}
public void Remove(IController controller) {
if (_isRunning) {
controller.OnStop();
}
_controllers.Remove(controller);
}
public async UniTask Start(CancellationToken cancellationToken) {
if (_isRunning) {
return;
}
foreach (IController controller in _controllers) {
await controller.OnStart(cancellationToken);
}
_isRunning = true;
}
public void Stop() {
if (!_isRunning) {
return;
}
foreach (IController controller in _controllers) {
controller.OnStop();
}
_isRunning = false;
}
public void Tick() {
foreach (IController controller in _controllers) {
controller.OnTick();
}
}
}
public static class ControllersManagerUtils {
public static void Add(this ControllersManager manager, ControllerAsset controllerAsset) {
manager.Add(controllerAsset.Create());
}
public static void Add(this ControllersManager manager, List<ControllerAsset> controllerAsset) {
foreach (ControllerAsset asset in controllerAsset) {
manager.Add(asset.Create());
}
}
public static void Add(this ControllersManager manager, ControllerAsset[] controllerAsset) {
foreach (ControllerAsset asset in controllerAsset) {
manager.Add(asset.Create());
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 9a78e7e501a24257a006967827a937ab
timeCreated: 1740757906

View File

@@ -0,0 +1,85 @@
using System;
using System.Diagnostics;
namespace RebootKit.Engine.Foundation {
public enum LogLevel {
Info,
Debug,
Warning,
Error
}
public readonly struct Logger {
private readonly string _name;
public Logger(string name) {
_name = name;
}
public void Log(LogLevel level, string message) {
switch (level) {
case LogLevel.Info:
UnityEngine.Debug.Log(FormatMessage(level, _name, message, true));
break;
case LogLevel.Debug:
UnityEngine.Debug.Log(FormatMessage(level, _name, message, true));
break;
case LogLevel.Warning:
UnityEngine.Debug.LogWarning(FormatMessage(level, _name, message, true));
break;
case LogLevel.Error:
UnityEngine.Debug.LogError(FormatMessage(level, _name, message, true));
break;
default:
throw new ArgumentOutOfRangeException(nameof(level), level, null);
}
}
[Conditional(RConsts.BuildFlagDebug)]
public void Info(string message) {
Log(LogLevel.Info, message);
}
[Conditional(RConsts.BuildFlagDebug)]
public void Debug(string message) {
Log(LogLevel.Debug, message);
}
[Conditional(RConsts.BuildFlagDebug)]
public void Warning(string message) {
Log(LogLevel.Warning, message);
}
public void Error(string message) {
Log(LogLevel.Error, message);
}
private static string FormatMessage(LogLevel level, string name, string message, bool richText) {
if (!richText) {
string prefix = level switch {
LogLevel.Info => "",
LogLevel.Debug => "[DEBUG]",
LogLevel.Warning => "[WARNING]",
LogLevel.Error => "[ERROR]",
_ => throw new ArgumentOutOfRangeException(nameof(level), level, null)
};
return $"{prefix}[{name}] {message}";
}
switch (level) {
case LogLevel.Info:
return $"[<b>{name}</b>] {message}";
case LogLevel.Debug:
return $"[D][<b>{name}</b>] <color=#ffffff>{message}</color>";
case LogLevel.Warning:
return $"[W][<b>{name}</b>] <color=#ffffff>{message}</color>";
case LogLevel.Error:
return $"[<b><color=#ff0000>ERROR</color></b>][<b>{name}</b>] <color=#ffffff>{message}</color>";
default:
throw new ArgumentOutOfRangeException(nameof(level), level, null);
}
return "";
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f8a58e1bf60c4db6a35171b65538fcea
timeCreated: 1741027327

View File

@@ -0,0 +1,94 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using UnityEngine;
namespace RebootKit.Engine.Foundation {
public interface IService : IDisposable {
UniTask OnInit(CancellationToken cancellationToken);
}
public abstract class ServiceMonoBehaviour : MonoBehaviour, IService {
public abstract UniTask OnInit(CancellationToken cancellationToken);
public abstract void Dispose();
}
public abstract class ServiceAsset<T> : ScriptableObject where T : IService {
public abstract T Create();
}
public abstract class ServiceAsset : ServiceAsset<IService> {
}
public class ServicesLocator {
private static readonly Logger _logger = new(nameof(ServicesLocator));
private static ServicesLocator _shared;
public static ServicesLocator Shared {
get {
if (_shared == null) {
_shared = new ServicesLocator();
}
return _shared;
}
}
private readonly Dictionary<Type, IService> _servicesMap = new();
public void Register(IService service, Type type) {
if (!_servicesMap.TryAdd(type, service)) {
_logger.Error($"There is already game service of type `{type}`");
return;
}
service.OnInit(default);
_logger.Info($"Registered service of type {type.Name}");
}
public void Register<T>(T service) where T : IService {
Register(service, service.GetType());
}
public async UniTask RegisterAsync<T>(T service, CancellationToken cancellationToken = default) where T : IService {
if (!_servicesMap.TryAdd(typeof(T), service)) {
_logger.Error($"There is already game service of type `{typeof(T).Name}`");
return;
}
await service.OnInit(cancellationToken);
_logger.Info($"Registered service of type {typeof(T).Name}");
}
public void UnRegister(Type type) {
if (_servicesMap.TryGetValue(type, out IService service)) {
service.Dispose();
_servicesMap.Remove(type);
_logger.Info($"Unregistered service of type {type.Name}");
}
}
public void UnRegisterAll() {
foreach (IService service in _servicesMap.Values) {
service.Dispose();
}
_servicesMap.Clear();
}
public IService Get(Type type) {
if (_servicesMap.TryGetValue(type, out IService service)) {
return service;
}
Debug.LogAssertionFormat($"Couldn't find service of type `{type}`");
return null;
}
public T Get<T>() where T : IService {
return (T) Get(typeof(T));
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: db549c154c4b413587c25dbfbadb7f49
timeCreated: 1741119753

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 2bad8b2bb3b0c0447bd252702e9503a3
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 162830275afaa9a40b54532a4a597593
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,136 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!21 &2100000
Material:
serializedVersion: 8
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_Name: M_CRT_Default
m_Shader: {fileID: -6465566751694194690, guid: 4d0e8896444a6f84690b4862dc0f7452,
type: 3}
m_Parent: {fileID: 0}
m_ModifiedSerializedProperties: 0
m_ValidKeywords: []
m_InvalidKeywords: []
m_LightmapFlags: 4
m_EnableInstancingVariants: 0
m_DoubleSidedGI: 0
m_CustomRenderQueue: -1
stringTagMap: {}
disabledShaderPasses: []
m_LockedProperties:
m_SavedProperties:
serializedVersion: 3
m_TexEnvs:
- _BaseMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _BumpMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailAlbedoMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailMask:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _DetailNormalMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _EmissionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MainTex:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _MetallicGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _OcclusionMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _ParallaxMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- _SpecGlossMap:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_Lightmaps:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_LightmapsInd:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
- unity_ShadowMasks:
m_Texture: {fileID: 0}
m_Scale: {x: 1, y: 1}
m_Offset: {x: 0, y: 0}
m_Ints: []
m_Floats:
- _AlphaClip: 0
- _AlphaToMask: 0
- _Blend: 0
- _BlendModePreserveSpecular: 1
- _BlurOffset: 0.00179
- _BumpScale: 1
- _ClearCoatMask: 0
- _ClearCoatSmoothness: 0
- _Cull: 2
- _Cutoff: 0.5
- _DetailAlbedoMapScale: 1
- _DetailNormalMapScale: 1
- _DstBlend: 0
- _DstBlendAlpha: 0
- _EnvironmentReflections: 1
- _GlossMapScale: 0
- _Glossiness: 0
- _GlossyReflections: 0
- _Metallic: 0
- _NumberOfScanLines: 200
- _OcclusionStrength: 1
- _Parallax: 0.005
- _QueueOffset: 0
- _ReceiveShadows: 1
- _ScanLinesSpeed: -0.001
- _Smoothness: 0.5
- _SmoothnessTextureChannel: 0
- _SpecularHighlights: 1
- _SrcBlend: 1
- _SrcBlendAlpha: 1
- _Surface: 0
- _WorkflowMode: 1
- _ZWrite: 1
m_Colors:
- _BaseColor: {r: 1, g: 1, b: 1, a: 1}
- _Color: {r: 16.948381, g: 16.948381, b: 16.948381, a: 1}
- _EmissionColor: {r: 0, g: 0, b: 0, a: 1}
- _SpecColor: {r: 0.19999996, g: 0.19999996, b: 0.19999996, a: 1}
m_BuildTextureStacks: []
--- !u!114 &7239824129281003057
MonoBehaviour:
m_ObjectHideFlags: 11
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 0}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d0353a89b1f911e48b9e16bdc9f2e058, type: 3}
m_Name:
m_EditorClassIdentifier:
version: 7

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 212bec7ca33591a489a68c541995db87
NativeFormatImporter:
externalObjects: {}
mainObjectFileID: 2100000
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 4d0e8896444a6f84690b4862dc0f7452
ScriptedImporter:
internalIDToNameTable: []
externalObjects: {}
serializedVersion: 2
userData:
assetBundleName:
assetBundleVariant:
script: {fileID: 11500000, guid: 625f186215c104763be7675aa2d941aa, type: 3}

View File

@@ -0,0 +1,18 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using UnityEngine;
namespace RebootKit.Engine.Graphics {
public class MainCameraService : ServiceMonoBehaviour {
[field: SerializeField]
public Camera Camera { get; private set; }
public override async UniTask OnInit(CancellationToken cancellationToken) {
await UniTask.Yield(cancellationToken);
}
public override void Dispose() {
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 351d6b8577644d599058e76fa02a11c0
timeCreated: 1740769963

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 48eb2fb8f4d8a2445a73abbb9623838f
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
Shader "Hidden/Szafa/Pixelize"
{
Properties
{
_MainTex ("Texture", 2D) = "white"
}
SubShader
{
Tags
{
"RenderType"="Opaque" "RenderPipeline" = "UniversalPipeline"
}
HLSLINCLUDE
#pragma vertex vert
#pragma fragment frag
#include "Packages/com.unity.render-pipelines.universal/ShaderLibrary/Core.hlsl"
struct Attributes
{
float4 positionOS : POSITION;
float2 uv : TEXCOORD0;
};
struct Varyings
{
float4 positionHCS : SV_POSITION;
float2 uv : TEXCOORD0;
};
TEXTURE2D(_MainTex);
float4 _MainTex_TexelSize;
float4 _MainTex_ST;
SamplerState sampler_point_clamp;
uniform float2 _BlockCount;
uniform float2 _BlockSize;
uniform float2 _HalfBlockSize;
Varyings vert(Attributes IN)
{
Varyings OUT;
OUT.positionHCS = TransformObjectToHClip(IN.positionOS.xyz);
OUT.uv = TRANSFORM_TEX(IN.uv, _MainTex);
return OUT;
}
ENDHLSL
Pass
{
Name "Pixelation"
HLSLPROGRAM
half4 frag(Varyings IN) : SV_TARGET
{
float2 blockPos = floor(IN.uv * _BlockCount);
float2 blockCenter = blockPos * _BlockSize + _HalfBlockSize;
float4 tex = SAMPLE_TEXTURE2D(_MainTex, sampler_point_clamp, blockCenter);
return tex;
}
ENDHLSL
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 782df0a61dfc4acf8fe4ec5a7204f205
timeCreated: 1740752799

View File

@@ -0,0 +1,37 @@
using System;
using UnityEngine;
using UnityEngine.Rendering.Universal;
namespace RebootKit.Engine.Graphics.Pixelize
{
public class PixelizeFeature : ScriptableRendererFeature
{
[Serializable]
public class PassSettings
{
public RenderPassEvent RenderPassEvent = RenderPassEvent.BeforeRenderingPostProcessing;
public int FrameHeight = 240;
}
[SerializeField]
private PassSettings _settings;
private PixelizePass _pass;
public override void Create()
{
_pass = new PixelizePass(_settings);
}
public override void AddRenderPasses(ScriptableRenderer renderer, ref RenderingData renderingData)
{
#if UNITY_EDITOR
if (renderingData.cameraData.isSceneViewCamera)
{
return;
}
#endif
renderer.EnqueuePass(_pass);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 4dde9574f26949228f5a5ac71254a478
timeCreated: 1740752516

View File

@@ -0,0 +1,69 @@
using UnityEngine;
using UnityEngine.Rendering;
using UnityEngine.Rendering.Universal;
namespace RebootKit.Engine.Graphics.Pixelize
{
public class PixelizePass : ScriptableRenderPass
{
private static int PixelBufferID = Shader.PropertyToID("_PixelBuffer");
private PixelizeFeature.PassSettings _settings;
private RenderTargetIdentifier _colorBuffer;
private RenderTargetIdentifier _pixelBuffer;
private Material _material;
private int _frameWidth;
private int _frameHeight;
public PixelizePass(PixelizeFeature.PassSettings settings)
{
_settings = settings;
renderPassEvent = settings.RenderPassEvent;
_material = CoreUtils.CreateEngineMaterial("Hidden/Szafa/Pixelize");
}
public override void OnCameraSetup(CommandBuffer cmd, ref RenderingData renderingData)
{
_colorBuffer = renderingData.cameraData.renderer.cameraColorTargetHandle;
RenderTextureDescriptor descriptor = renderingData.cameraData.cameraTargetDescriptor;
_frameHeight = _settings.FrameHeight;
_frameWidth = (int) (_frameHeight * renderingData.cameraData.camera.aspect + 0.5f);
_material.SetVector("_BlockCount", new Vector2(_frameWidth, _frameHeight));
_material.SetVector("_BlockSize", new Vector2(1.0f / _frameWidth, 1.0f / _frameHeight));
_material.SetVector("_HalfBlockSize", new Vector2(0.5f / _frameWidth, 0.5f / _frameHeight));
descriptor.height = _frameWidth;
descriptor.width = _frameWidth;
cmd.GetTemporaryRT(PixelBufferID, descriptor, FilterMode.Point);
_pixelBuffer = new RenderTargetIdentifier(PixelBufferID);
}
public override void OnCameraCleanup(CommandBuffer cmd)
{
if (cmd == null)
{
throw new System.ArgumentNullException(nameof(cmd));
}
cmd.ReleaseTemporaryRT(PixelBufferID);
}
public override void Execute(ScriptableRenderContext context, ref RenderingData renderingData)
{
CommandBuffer cmd = CommandBufferPool.Get();
using (new ProfilingScope(cmd, new ProfilingSampler("Pixelize Pass")))
{
// Blit(cmd, _colorBuffer, _pixelBuffer, _material);
// Blit(cmd, _pixelBuffer, _colorBuffer);
}
context.ExecuteCommandBuffer(cmd);
CommandBufferPool.Release(cmd);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 5eb50486f41a47bb96c549c3cba1865d
timeCreated: 1740752552

View File

@@ -0,0 +1,18 @@
namespace RebootKit.Engine
{
public static class RConsts {
public const int MainSceneBuildIndex = 0;
public const string EngineConfigAssetName = "RealityRebootKit";
public const string EngineConfigResourcesPath = "TheGame/" + EngineConfigAssetName;
public const string AssetMenu = "Reboot Reality/";
public const string FPPKitAssetMenu = AssetMenu + "FPP Kit/";
public const string ServiceAssetMenu = AssetMenu + "Services/";
public const string UnitsAssetMenu = AssetMenu + "Units/";
public const string GameModeAssetMenu = AssetMenu + "GameModes/";
public const string WorldAssetMenu = AssetMenu + "World/";
public const string BuildFlagDebug = "RR_DEBUG";
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 273e7245d4cf02b4295f0f1e158a9c54

154
Runtime/Engine/Code/RR.cs Normal file
View File

@@ -0,0 +1,154 @@
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Services.Console;
using RebootKit.Engine.Services.Game;
using RebootKit.Engine.Services.Input;
using RebootKit.Engine.Services.Simulation;
using UnityEngine;
using UnityEngine.SceneManagement;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootKit.Engine {
public abstract class RAsset : ScriptableObject {
}
public class RR : IDisposable {
public static RR Shared { get; set; }
private static readonly Logger _logger = new Logger("RR");
private EngineConfigAsset _engineConfigAsset;
private ConsoleService _consoleService;
private InputService _inputService;
private WorldService _worldService;
private GameService _gameService;
public void Dispose() {
}
public async UniTask Init(CancellationToken cancellationToken) {
_logger.Info("Waking up");
_logger.Info("Loading engine config");
_engineConfigAsset = Resources.Load<EngineConfigAsset>(RConsts.EngineConfigResourcesPath);
if (_engineConfigAsset == null) {
_logger.Error($"Couldn't load engine config from resources: {RConsts.EngineConfigResourcesPath}");
return;
}
_logger.Info("Loading engine found");
await CreateCoreServices(cancellationToken);
await RegisterServiceAssetsFromConfig(cancellationToken);
await RegisterServicesFromMainSceneAsync(cancellationToken);
}
public async UniTask Run(CancellationToken cancellationToken) {
_logger.Info($"Starting initial game mode");
await _gameService.Start(_engineConfigAsset.StartingGameMode, cancellationToken);
}
private async UniTask<TService> CreateServiceAsync<TService>(ServiceAsset<TService> asset, CancellationToken cancellationToken = default) where TService : IService {
TService service = asset.Create();
await ServicesLocator.Shared.RegisterAsync(service, cancellationToken);
return service;
}
private async UniTask CreateCoreServices(CancellationToken cancellationToken) {
_logger.Debug("Registering core services");
_consoleService = await CreateServiceAsync(_engineConfigAsset.ConsoleService, cancellationToken);
_inputService = await CreateServiceAsync(_engineConfigAsset.InputService, cancellationToken);
_worldService = await CreateServiceAsync(_engineConfigAsset.WorldService, cancellationToken);
_gameService = await CreateServiceAsync(_engineConfigAsset.GameService, cancellationToken);
}
private async UniTask RegisterServiceAssetsFromConfig(CancellationToken cancellationToken = default) {
if (_engineConfigAsset.Services.Length == 0) {
return;
}
_logger.Info($"Registering {_engineConfigAsset.Services.Length} services");
foreach (ServiceAsset service in _engineConfigAsset.Services) {
await ServicesLocator.Shared.RegisterAsync(service.Create(), cancellationToken);
}
}
private async UniTask RegisterServicesFromMainSceneAsync(CancellationToken cancellationToken = default) {
_logger.Info("Looking for services in mainscene");
int foundCount = 0;
GameObject[] gameObjects = SceneManager.GetSceneByBuildIndex(RConsts.MainSceneBuildIndex).GetRootGameObjects();
if (gameObjects.Length == 0) {
_logger.Info("No services found in main scene");
return;
}
foreach (GameObject root in gameObjects) {
ServiceMonoBehaviour[] services = root.GetComponentsInChildren<ServiceMonoBehaviour>();
foreach (ServiceMonoBehaviour service in services) {
await ServicesLocator.Shared.RegisterAsync(service, cancellationToken);
foundCount += 1;
}
}
_logger.Info($"Found and registered {foundCount} services from active scene");
}
//
// API
//
/// Services
public static T Service<T>() where T : IService {
return ServicesLocator.Shared.Get<T>();
}
public static ConsoleService Console() => Shared._consoleService;
public static InputService Input() => Shared._inputService;
public static WorldService World() => Shared._worldService;
public static GameService Game() => Shared._gameService;
/// CVars
public static CVar CVarIndex(string name, int defaultValue = -1) {
CVar cvar = Console().GetCVar(name);
if (cvar != null) {
return cvar;
}
cvar = new CVar(name, defaultValue);
Console().Replace(cvar);
return cvar;
}
public static CVar CVarNumber(string name, double defaultValue = 0) {
CVar cvar = Console().GetCVar(name);
if (cvar != null) {
return cvar;
}
cvar = new CVar(name, defaultValue);
Console().Replace(cvar);
return cvar;
}
public static CVar CVarString(string name, string defaultValue = "") {
CVar cvar = Console().GetCVar(name);
if (cvar != null) {
return cvar;
}
cvar = new CVar(name, defaultValue);
Console().Replace(cvar);
return cvar;
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 56749d0dd0042ce41b20d46fc486476c

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ac31ad3431a84354ab7c73a84039be3f
timeCreated: 1741791385

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: d059b7f04b524c6fbd39c7b14af4a299
timeCreated: 1740779746

View File

@@ -0,0 +1,169 @@
using System;
namespace RebootKit.Engine.Services.Console {
public enum CVarValueKind {
Number, String
}
[Serializable]
public struct CVarValue {
public CVarValueKind Kind;
public double NumberValue;
public string StringValue;
public CVarValue(int value) {
Kind = CVarValueKind.Number;
NumberValue = value;
StringValue = null;
}
public CVarValue(float value) {
Kind = CVarValueKind.Number;
NumberValue = value;
StringValue = null;
}
public CVarValue(double value) {
Kind = CVarValueKind.Number;
NumberValue = value;
StringValue = null;
}
public CVarValue(string value) {
Kind = CVarValueKind.String;
NumberValue = 0;
StringValue = value;
}
public void CopyFrom(CVarValue value) {
Kind = value.Kind;
NumberValue = value.NumberValue;
StringValue = value.StringValue;
}
public override string ToString() {
return Kind switch {
CVarValueKind.Number => NumberValue.ToString(),
CVarValueKind.String => $"\"{StringValue}\"",
_ => throw new ArgumentOutOfRangeException()
};
}
}
[Flags]
public enum CVarFlags {
None, Persistent, ReadOnly
}
[Serializable]
public class CVar {
public CVarFlags Flags;
public string Name;
public string Description;
public CVarValue DefaultValue;
public CVarValue Value { get; private set; }
public int IndexValue => (int) Value.NumberValue;
public float FloatValue => (float) Value.NumberValue;
public double NumberValue => Value.NumberValue;
public string StringValue => Value.StringValue;
public event Action OnChanged = delegate { };
public CVar(CVar other) {
Flags = other.Flags;
Name = other.Name;
Description = other.Description;
DefaultValue = other.DefaultValue;
Value = other.Value;
}
public CVar(string name, CVarValue value, string description = "") {
Name = name;
Description = description;
DefaultValue = value;
Value = DefaultValue;
}
public CVar(string name, int value, string description = "") {
Name = name;
Description = description;
DefaultValue = new CVarValue(value);
Value = DefaultValue;
}
public CVar(string name, float value, string description = "") {
Name = name;
Description = description;
DefaultValue = new CVarValue(value);
Value = DefaultValue;
}
public CVar(string name, double value, string description = "") {
Name = name;
Description = description;
DefaultValue = new CVarValue(value);
Value = DefaultValue;
}
public CVar(string name, string value, string description = "") {
Name = name;
Description = description;
DefaultValue = new CVarValue(value);
Value = DefaultValue;
}
public void Set(int value) {
if (Flags.HasFlag(CVarFlags.ReadOnly)) {
return;
}
Value = new CVarValue(value);
OnChanged?.Invoke();
}
public void Set(float value) {
if (Flags.HasFlag(CVarFlags.ReadOnly)) {
return;
}
Value = new CVarValue(value);
OnChanged?.Invoke();
}
public void Set(string value) {
if (Flags.HasFlag(CVarFlags.ReadOnly)) {
return;
}
Value = new CVarValue(value);
OnChanged?.Invoke();
}
public void ParseFromString(string str) {
if (Flags.HasFlag(CVarFlags.ReadOnly)) {
return;
}
if (float.TryParse(str, out float f)) {
Set(f);
} else {
Set(str);
}
}
public void Reset() {
if (Flags.HasFlag(CVarFlags.ReadOnly)) {
return;
}
Value = DefaultValue;
OnChanged?.Invoke();
}
public override string ToString() {
return Value.ToString();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0f560b25a893456c90fac62ad278c02b
timeCreated: 1740779755

View File

@@ -0,0 +1,19 @@
using UnityEngine;
namespace RebootKit.Engine.Services.Console {
[CreateAssetMenu(fileName = RConsts.AssetMenu + "cvar")]
public class CVarAsset : ScriptableObject {
[SerializeField]
private CVar _cvar;
public CVar Create(string name = null) {
CVar cvar = new CVar(_cvar);
if (name != null) {
cvar.Name = name;
}
return cvar;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 443a66c3a441450d96d222872a567df0
timeCreated: 1741639598

View File

@@ -0,0 +1,193 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using RebootKit.Engine.Services.Input;
using UnityEngine.InputSystem;
using Logger = RebootKit.Engine.Foundation.Logger;
namespace RebootKit.Engine.Services.Console {
public interface IConsoleCommand {
string Name { get; }
string Description { get; }
void Execute(string[] args);
}
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 ConsoleService : IService {
private static readonly Logger _logger = new(nameof(ConsoleService));
[Serializable]
public class Config {
public ConsoleUI ConsoleUIPrefab;
public ScriptableInputAction ToggleAction;
}
private ConsoleUI _ui;
private Config _config;
private List<IConsoleCommand> _commands = new();
private List<CVar> _cvars = new();
public bool IsVisible => _ui.IsVisible;
public ConsoleService(Config config) {
_config = config;
}
public async UniTask OnInit(CancellationToken cancellationToken) {
_logger.Info("Waking up");
_ui = UnityEngine.Object.Instantiate(_config.ConsoleUIPrefab);
UnityEngine.Object.DontDestroyOnLoad(_ui.gameObject);
await UniTask.Yield(cancellationToken);
_config.ToggleAction.Action.Enable();
_config.ToggleAction.Action.performed += OnToggleAction;
RegisterCommand(new HelpCommand());
_ui.SetVisibility(false);
_ui.Clear();
_ui.Write("Hello shelf\n");
}
public void Dispose() {
if (_ui != null) {
UnityEngine.Object.Destroy(_ui);
_ui = null;
}
_config.ToggleAction.Action.performed -= OnToggleAction;
}
public CVar GetCVar(string name) {
foreach (CVar cvar in _cvars) {
if (cvar.Name.Equals(name)) {
return cvar;
}
}
return null;
}
public CVar ReplaceOrDefault(CVar cvar) {
CVar foundCVar = GetCVar(cvar.Name);
if (foundCVar != null) {
return foundCVar;
}
_cvars.Add(cvar);
return cvar;
}
public void Replace(CVar cvar) {
CVar foundCVar = GetCVar(cvar.Name);
if (foundCVar != null) {
_cvars.Remove(foundCVar);
}
_cvars.Add(cvar);
}
private string[] ParseCommandInputArguments(string text) {
if (text.Length == 0) {
return Array.Empty<string>();
}
return new string[] {text};
}
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 = ParseCommandInputArguments(input.Substring(commandName.Length));
foreach (IConsoleCommand command in _commands) {
if (command.Name.Equals(commandName)) {
command.Execute(arguments);
return;
}
}
foreach (CVar cvar in _cvars) {
if (cvar.Name.Equals(commandName)) {
if (arguments.Length == 1) {
cvar.ParseFromString(arguments[0]);
}
_ui.Write($"<b>{cvar.Name}</b> - {cvar.ToString()}\n");
return;
}
}
_ui.Write($"ERROR: Command/CVar `{commandName}` not found.");
}
public void ToggleVisibility() {
_ui.SetVisibility(!_ui.IsVisible);
if (_ui.IsVisible) {
// RR.Input().DisableControls();
} else {
RR.Input().EnableControls();
}
}
public void RegisterCommand(IConsoleCommand command) {
if (_commands.Any(t => t.Name.Equals(command.Name))) {
_logger.Error($"`{command.Name}` command is already registered");
return;
}
_commands.Add(command);
_logger.Info($"Registered command: {command.Name}");
}
public void PrintHelp() {
StringBuilder message = new();
message.AppendLine("Available commands:");
foreach (IConsoleCommand command in _commands) {
message.Append(" ");
message.Append(command.Name);
message.Append(" - ");
message.Append(command.Description);
message.AppendLine();
}
message.AppendLine("Available cvars:");
foreach (CVar cvar in _cvars) {
message.Append(" ");
message.Append(cvar.Name);
message.Append(" - ");
message.Append(cvar.Description);
message.AppendLine();
}
_ui.Write(message.ToString());
}
private void OnToggleAction(InputAction.CallbackContext obj) {
ToggleVisibility();
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b841238f225048e88d8d8d89cfeafaa7
timeCreated: 1740884588

View File

@@ -0,0 +1,34 @@
using RebootKit.Engine.Foundation;
using UnityEngine;
namespace RebootKit.Engine.Services.Console {
[CreateAssetMenu(menuName = RConsts.ServiceAssetMenu + "Console")]
public class ConsoleServiceAsset : ServiceAsset<ConsoleService> {
[SerializeField]
private ConsoleService.Config _config;
[SerializeField]
private CVar[] _initialCVars;
[SerializeField]
private bool _loadCVarsFromResources = true;
public override ConsoleService Create() {
ConsoleService service = new(_config);
foreach (CVar cvar in _initialCVars) {
service.Replace(cvar);
cvar.Reset();
}
if (_loadCVarsFromResources) {
CVarAsset[] cvarsAssets = Resources.LoadAll<CVarAsset>("cvar");
foreach (CVarAsset cvarAsset in cvarsAssets) {
CVar cvar = cvarAsset.Create();
service.Replace(cvar);
}
}
return new ConsoleService(_config);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 577b018c25510774aaccba06137e264d

View File

@@ -0,0 +1,52 @@
using System.Text;
using UnityEngine;
using UnityEngine.UIElements;
namespace RebootKit.Engine.Services.Console {
public class ConsoleUI : MonoBehaviour {
private StringBuilder _content = new();
[SerializeField]
private UIDocument _document;
private TextField _textField;
private Button _submitButton;
public bool IsVisible { get; private set; }
private void Awake() {
VisualElement root = _document.rootVisualElement;
return;
// _textField = root.Q<TextField>("console-text-field");
// _submitButton = root.Q<Button>("console-btn-submit");
// _submitButton.clicked += OnSubmitButtonClicked;
}
private void OnSubmit(string input) {
RR.Console().Execute(input);
_textField.value = input;
}
public void SetVisibility(bool visible) {
_document.enabled = visible;
}
public void Write(string message) {
_content.Append(message);
//_textField.value = _content.ToString();
}
public void Clear() {
_content.Clear();
if (_textField != null) {
_textField.value = "";
}
}
private void OnSubmitButtonClicked() {
OnSubmit(_textField.value);
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: ca844a0157054677b2f129fdbf6ddc45
timeCreated: 1740780314

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 1177ea3903bdba5419ad3347250cb3b7
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,68 @@
using System;
using System.Threading;
using RebootKit.Engine.Foundation;
using UnityEngine;
namespace RebootKit.Engine.Services.Game {
[Serializable]
public class GameModeConfig {
public ControllerAsset[] Controllers;
}
public abstract class GameModeAsset : ScriptableObject {
[field: SerializeField]
public GameModeConfig GameModeConfig { get; private set; }
public GameMode Create() {
GameMode gameMode = new GameMode(GameModeConfig);
ConfigureGameMode(gameMode);
return gameMode;
}
public abstract void ConfigureGameMode(GameMode gameMode);
}
public class GameMode : IDisposable {
private readonly GameModeConfig _config;
private readonly ControllersManager _controllersManager;
private CancellationTokenSource _destroyCancellationTokenSource;
private bool _isRunning;
public GameMode(GameModeConfig config) {
_config = config;
_isRunning = false;
_destroyCancellationTokenSource = new CancellationTokenSource();
_controllersManager = new ControllersManager(_destroyCancellationTokenSource.Token);
}
public void Dispose() {
_destroyCancellationTokenSource.Cancel();
_controllersManager.Dispose();
}
public async Awaitable<bool> Start(CancellationToken cancellationToken) {
_controllersManager.Add(_config.Controllers);
await _controllersManager.Start(cancellationToken);
_isRunning = true;
return true;
}
public void Stop() {
_isRunning = false;
_controllersManager.Stop();
}
public void Tick() {
_controllersManager.Tick();
}
public void AddController(IController controller) {
_controllersManager.Add(controller);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 73f15dc489209cc4a9ff6963e0fbd2c6

View File

@@ -0,0 +1,42 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
namespace RebootKit.Engine.Services.Game {
public class GameService : IService {
private static readonly Logger _logger = new(nameof(GameService));
private GameModeAsset _gameModeAsset;
private GameMode _gameMode;
private bool _running;
public async UniTask OnInit(CancellationToken cancellationToken) {
await UniTask.Yield(cancellationToken);
}
public void Dispose() {
_running = false;
_gameMode.Dispose();
}
public async UniTask Start(GameModeAsset asset, CancellationToken cancellationToken) {
_gameMode = asset.Create();
await _gameMode.Start(cancellationToken);
Run(cancellationToken).Forget();
}
private async UniTask Run(CancellationToken cancellationToken) {
if (_gameMode == null) {
_logger.Error("Trying to run game without game mode");
return;
}
_running = true;
while (_running) {
await UniTask.Yield(PlayerLoopTiming.Update, cancellationToken);
_gameMode.Tick();
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 82082a4d082be274bbec52347d25b836

View File

@@ -0,0 +1,11 @@
using RebootKit.Engine.Foundation;
using UnityEngine;
namespace RebootKit.Engine.Services.Game {
[CreateAssetMenu(menuName = RConsts.ServiceAssetMenu + "Game")]
public class GameServiceAsset : ServiceAsset<GameService> {
public override GameService Create() {
return new GameService();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 51f134b6c2abcd34fa8e376b3afc757d

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 1b0c063e9b7a4190894f338b2fdef3b4
timeCreated: 1740768141

View File

@@ -0,0 +1,50 @@
using System;
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using UnityEngine;
using UnityEngine.InputSystem;
namespace RebootKit.Engine.Services.Input {
public class InputService : IService {
[Serializable]
public class Config {
public InputActionAsset InputAsset;
}
private Config _config;
public InputService(Config config) {
_config = config;
}
public void Dispose() {
}
public async UniTask OnInit(CancellationToken cancellationToken) {
await UniTask.Yield(cancellationToken);
}
public void EnableControls() {
_config.InputAsset.Enable();
}
public void DisableControls() {
_config.InputAsset.Disable();
}
public InputAction FindInputAction(string path) {
return _config.InputAsset.FindAction(path);
}
public void LockCursor() {
Cursor.lockState = CursorLockMode.Locked;
Cursor.visible = false;
}
public void UnlockCursor() {
Cursor.lockState = CursorLockMode.None;
Cursor.visible = true;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a6ee7382dba74afe84aaf53259b1cf8a
timeCreated: 1740769896

View File

@@ -0,0 +1,14 @@
using RebootKit.Engine.Foundation;
using UnityEngine;
namespace RebootKit.Engine.Services.Input {
[CreateAssetMenu(menuName = RConsts.ServiceAssetMenu + "Input")]
public class InputServiceAsset : ServiceAsset<InputService> {
[SerializeField]
private InputService.Config _config;
public override InputService Create() {
return new InputService(_config);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8fcf71fe79ef1ed4cbfdefde09e708d9

View File

@@ -0,0 +1,12 @@
using UnityEngine;
using UnityEngine.InputSystem;
namespace RebootKit.Engine.Services.Input
{
[CreateAssetMenu(menuName = RConsts.AssetMenu + "Input Action", fileName = "Input Action")]
public class ScriptableInputAction : ScriptableObject
{
[field: SerializeField]
public InputAction Action { get; private set; }
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: e8d574cf0e024ec7bc4363a675dbb2c9
timeCreated: 1740768148

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f5fb2de6697247618aa0dc36a659ddcc
timeCreated: 1741791621

View File

@@ -0,0 +1,7 @@
namespace RebootKit.Engine.Services.LoadigScreen
{
public class LoadingScreenService
{
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0a45f8f7ea6f45198713694a39790614
timeCreated: 1740671052

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 663488f6dc6f4f23a2fb88ab0b2a8daa
timeCreated: 1741043532

View File

@@ -0,0 +1,15 @@
using System;
namespace RebootKit.Engine.Services.Persistance {
[Serializable]
public class SaveData {
public string ProfileName;
}
public class SaveSystemService {
public void Save() {
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 0fd19386b9584594bac09c3f43489a1a
timeCreated: 1741043540

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 8fda1b5a08e44d878d326cd3b7692e42
timeCreated: 1740766816

View File

@@ -0,0 +1,6 @@
using UnityEngine;
namespace RebootKit.Engine.Services.Simulation {
public class Actor : MonoBehaviour {
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: db64eadf8c93c8e47b954139078cb3bc

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: cf2d5c590c224ae6a7acbdbfa0b79b57
timeCreated: 1740770300

View File

@@ -0,0 +1,160 @@
using UnityEngine;
namespace RebootKit.Engine.Services.Simulation.Characters
{
public class CharacterLocomotion : MonoBehaviour
{
[SerializeField]
private CharacterController _characterController;
public float MaxMovementSpeed = 4.0f;
public float MaxSprintSpeed = 15.0f;
public float JumpHeight = 1.0f;
public float Gravity = 10f;
public float MaxFallSpeed = 20f;
public float Damping = 20.0f;
private Vector3 _pendingInputValue;
private Vector3 _currentVelocity;
private bool _isSprinting;
private bool _jumpRequested;
private bool _isFalling;
public bool IsGrounded => _characterController.isGrounded;
public Vector3 Velocity => _currentVelocity;
private void Update()
{
ConsumePendingInput();
UpdateVerticalVelocity();
_characterController.Move(_currentVelocity * Time.deltaTime);
ApplyFriction();
DetectFall();
}
private void DetectFall()
{
if (_isFalling && _characterController.isGrounded)
{
_isFalling = false;
}
else if (!_characterController.isGrounded)
{
_isFalling = true;
}
}
private void ConsumePendingInput()
{
if (!IsGrounded)
{
_pendingInputValue = Vector3.zero;
return;
}
_pendingInputValue.y = 0.0f;
float pendingInputMagnitude = _pendingInputValue.magnitude;
Vector3 direction = Vector3.zero;
if (pendingInputMagnitude > 0.0f)
{
// normalize vector, reusing magnitude to avoid multiple sqrt calls
direction = _pendingInputValue / pendingInputMagnitude;
}
float movementSpeed = _isSprinting ? MaxSprintSpeed : MaxMovementSpeed;
Vector3 movementVelocity = _currentVelocity;
movementVelocity.y = 0.0f;
movementVelocity += direction * (movementSpeed * pendingInputMagnitude);
movementVelocity.y = 0.0f;
// Clamp speed
float movementVelocityMagnitude = movementVelocity.magnitude;
Vector3 movementVelocityDirection = movementVelocityMagnitude > 0.0f ? movementVelocity / movementVelocityMagnitude : Vector3.zero;
if (movementVelocityMagnitude > movementSpeed)
{
movementVelocityMagnitude = movementSpeed;
}
movementVelocity = movementVelocityDirection * movementVelocityMagnitude;
_currentVelocity.x = movementVelocity.x;
_currentVelocity.z = movementVelocity.z;
_pendingInputValue = Vector3.zero;
}
private void UpdateVerticalVelocity()
{
if (_characterController.isGrounded)
{
if (_jumpRequested)
{
_currentVelocity.y = Mathf.Sqrt(2.0f * Gravity * JumpHeight);
_jumpRequested = false;
}
else
{
_currentVelocity.y = -1f;
}
}
else
{
_currentVelocity.y -= Gravity * Time.deltaTime;
_currentVelocity.y = Mathf.Max(_currentVelocity.y, -MaxFallSpeed);
}
}
private void ApplyFriction()
{
if (!IsGrounded)
{
return;
}
Vector3 movementVelocity = _currentVelocity;
movementVelocity.y = 0.0f;
movementVelocity = Vector3.MoveTowards(movementVelocity, Vector3.zero, Damping * Time.deltaTime);
_currentVelocity.x = movementVelocity.x;
_currentVelocity.z = movementVelocity.z;
}
public void AddVelocity(Vector3 velocity)
{
_currentVelocity += velocity;
}
public void AddMovementInput(Vector3 input, float scale)
{
_pendingInputValue += input * scale;
}
public void Jump()
{
if (!_characterController.isGrounded)
{
return;
}
_jumpRequested = true;
}
public void StartSprint()
{
_isSprinting = true;
}
public void StopSprint()
{
_isSprinting = false;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 6e909888e8f2465fb2f032b66bbd20a4
timeCreated: 1740766822

View File

@@ -0,0 +1,6 @@
using UnityEngine;
namespace RebootKit.Engine.Services.Simulation.Characters {
public class GameCharacter : MonoBehaviour {
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: c4dd42e93f8a469685be596f305ed985
timeCreated: 1741791931

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: 89332296442a469281fddf681dcf176e
timeCreated: 1740881642

View File

@@ -0,0 +1,30 @@
using System;
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
namespace RebootKit.Engine.Services.Simulation.Interactors {
public interface IInteractorAsync<in TInteractable> {
UniTask Interact(TInteractable target, CancellationToken cancellationToken);
}
public interface IInteractor<in TInteractable> {
public static Type InteractableType() => typeof(TInteractable);
void Interact(TInteractable target);
}
public class GroupInteractor<TInteractable> : IInteractor<TInteractable> {
private readonly List<IInteractor<TInteractable>> _interactors = new();
public void Add(IInteractor<TInteractable> interactor) => _interactors.Add(interactor);
public void Remove(IInteractor<TInteractable> interactor) => _interactors.Remove(interactor);
public void RemoveAll() => _interactors.Clear();
public void Interact(TInteractable target) {
foreach (IInteractor<TInteractable> interactor in _interactors) {
interactor.Interact(target);
}
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: bbb4d95dfc6a479caeeaa9078c45f5b8
timeCreated: 1740881665

View File

@@ -0,0 +1,50 @@
using UnityEngine;
namespace RebootKit.Engine.Services.Simulation {
public class PhysicsObjectDragger : MonoBehaviour {
[field: SerializeField]
public float DampingFactor { get; private set; } = 1.0f;
[field: SerializeField]
public float AngularSlowdown { get; private set; } = 90.0f;
[field: SerializeField]
public float DragForce { get; private set; } = 10.0f;
public Rigidbody Current { get; private set; }
public Vector3 TargetWorldPosition { get; set; }
public bool IsDragging => Current != null;
public void Grab(Rigidbody physicsObject) {
Current = physicsObject;
Current.linearDamping = 5.0f;
}
public void Drop() {
if (Current == null) {
return;
}
Current.linearDamping = 0.0f;
Current = null;
}
public void FixedUpdate() {
if (Current == null) {
return;
}
Vector3 direction = (TargetWorldPosition - Current.position).normalized;
float distance = Vector3.Distance(TargetWorldPosition, Current.position);
Vector3 damping = Current.linearVelocity * DampingFactor;
Vector3 force = direction * Mathf.Clamp(distance * DragForce, 0, DragForce) - damping;
Current.AddForce(force, ForceMode.Force);
Current.angularVelocity = Vector3.MoveTowards(Current.angularVelocity, Vector3.zero, Time.fixedDeltaTime * AngularSlowdown);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 8498955cf5ff17145aa4bbd96edd8ca6

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: f5e9be517bad4d0ea6d175fd19cc9e98
timeCreated: 1740880682

View File

@@ -0,0 +1,7 @@
using UnityEngine;
namespace RebootKit.Engine.Services.Simulation.Sensors {
public interface ISensor {
GameObject Sense();
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a25d318166444cdea14df9c89554436d
timeCreated: 1740880690

View File

@@ -0,0 +1,29 @@
using UnityEngine;
namespace RebootKit.Engine.Services.Simulation.Sensors {
public class RaycastSensor : ISensor {
public Ray Ray;
public LayerMask LayerMask;
public float MaxDistance;
public bool HasHit { get; private set; }
public RaycastHit Hit { get; private set; }
public void Clear() {
HasHit = false;
Hit = default;
}
public GameObject Sense() {
HasHit = Physics.Raycast(Ray, out RaycastHit hit, MaxDistance, LayerMask);
if (HasHit) {
Hit = hit;
return Hit.transform.gameObject;
}
Hit = default;
return null;
}
}
}

View File

@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: b56194d1060a4b4da3e8a2acf7453a2f
timeCreated: 1740880749

View File

@@ -0,0 +1,22 @@
using System;
using UnityEngine;
using UnityEngine.AddressableAssets;
namespace RebootKit.Engine.Services.Simulation {
[Serializable]
public struct WorldConfig {
public string Name;
// @NOTE: stays loaded during world lifetime
public AssetReference MainScene;
}
[CreateAssetMenu(menuName = RConsts.WorldAssetMenu + "World")]
public class WorldConfigAsset : ScriptableObject {
[SerializeField]
private WorldConfig _config;
public WorldConfig Config => _config;
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: dff210be181a0cd408f6b35eff2f38af

View File

@@ -0,0 +1,64 @@
using System.Collections.Generic;
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
using UnityEngine;
using UnityEngine.AddressableAssets;
using UnityEngine.ResourceManagement.AsyncOperations;
using UnityEngine.ResourceManagement.ResourceProviders;
using UnityEngine.SceneManagement;
namespace RebootKit.Engine.Services.Simulation {
public class WorldService : IService {
private WorldConfig _config;
private List<Actor> _actors = new();
public async UniTask OnInit(CancellationToken cancellationToken) {
await UniTask.Yield(cancellationToken);
}
public void Dispose() {
KillAllActors();
}
public async UniTask Load(WorldConfig worldConfig) {
_config = worldConfig;
AsyncOperationHandle<SceneInstance> handle = worldConfig.MainScene.LoadSceneAsync(LoadSceneMode.Additive);
await handle.ToUniTask();
SceneManager.SetActiveScene(handle.Result.Scene);
}
public async UniTask<TActor> SpawnActor<TActor>(AssetReferenceT<GameObject> asset, CancellationToken cancellationToken) where TActor : Actor {
GameObject gameObject = await Addressables.InstantiateAsync(asset);
if (cancellationToken.IsCancellationRequested) {
asset.ReleaseInstance(gameObject);
return null;
}
if (gameObject.TryGetComponent(out TActor actor)) {
return actor;
}
asset.ReleaseInstance(gameObject);
return null;
}
public async UniTask RegisterActor(Actor actor) {
_actors.Add(actor);
await UniTask.Yield();
}
public void KillActor(Actor actor) {
Addressables.ReleaseInstance(actor.gameObject);
}
public void KillAllActors() {
foreach (Actor actor in _actors) {
Addressables.ReleaseInstance(actor.gameObject);
}
_actors.Clear();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 5e5e78f7ea7dacc42b9a0ea9a4bb1c00

View File

@@ -0,0 +1,11 @@
using RebootKit.Engine.Foundation;
using UnityEngine;
namespace RebootKit.Engine.Services.Simulation {
[CreateAssetMenu(menuName = RConsts.ServiceAssetMenu + "World")]
public class WorldServiceAsset : ServiceAsset<WorldService> {
public override WorldService Create() {
return new WorldService();
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 3f449396a11e05e41990dbddfb992815

View File

@@ -0,0 +1,17 @@
using System.Threading;
using Cysharp.Threading.Tasks;
using RebootKit.Engine.Foundation;
namespace RebootKit.Engine.Services {
public class UpdateLoopService : IService {
public async UniTask OnInit(CancellationToken cancellationToken) {
await UniTask.Yield(cancellationToken);
}
public void Dispose() {
}
public void Add(PlayerLoopTiming playerLoopTiming) {
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 0f0892c234a3a3a40a7f2516fa4dd1e0