feat: add initial architecture
This commit is contained in:
@@ -3,7 +3,7 @@
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://b5i827vmueyei"
|
||||
path.s3tc="res://.godot/imported/skybox_emx_19.png-bcedc2389708497367e5aad83b1663bd.s3tc.ctex"
|
||||
path.s3tc="res://.godot/imported/skybox_emx_19.png-32e3e8fe1f1a6e420d2641cab7e6f270.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
@@ -11,8 +11,8 @@ metadata={
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://Assets/Textures/Skyboxes/skybox_emx_19.png"
|
||||
dest_files=["res://.godot/imported/skybox_emx_19.png-bcedc2389708497367e5aad83b1663bd.s3tc.ctex"]
|
||||
source_file="res://assets/textures/skyboxes/skybox_emx_19.png"
|
||||
dest_files=["res://.godot/imported/skybox_emx_19.png-32e3e8fe1f1a6e420d2641cab7e6f270.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
|
||||
Binary file not shown.
@@ -0,0 +1,45 @@
|
||||
[remap]
|
||||
|
||||
importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://blkhom228sqgi"
|
||||
path="res://.godot/imported/floor_ceiling_hr_4.glb-34017de24b2c7bf5df2db25493b6d322.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/models/floor_ceiling_hr_4.glb"
|
||||
dest_files=["res://.godot/imported/floor_ceiling_hr_4.glb-34017de24b2c7bf5df2db25493b6d322.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
nodes/root_type=""
|
||||
nodes/root_name=""
|
||||
nodes/root_script=null
|
||||
mesh_library/use_node_names_as_mesh_names=false
|
||||
array_mesh/deduplicate_surfaces=true
|
||||
nodes/apply_root_scale=true
|
||||
nodes/root_scale=1.0
|
||||
nodes/import_as_skeleton_bones=false
|
||||
nodes/use_name_suffixes=true
|
||||
nodes/use_node_type_suffixes=true
|
||||
meshes/ensure_tangents=true
|
||||
meshes/generate_lods=true
|
||||
meshes/create_shadow_meshes=true
|
||||
meshes/light_baking=1
|
||||
meshes/lightmap_texel_size=0.2
|
||||
meshes/force_disable_compression=false
|
||||
skins/use_named_skins=true
|
||||
animation/import=true
|
||||
animation/fps=30
|
||||
animation/trimming=false
|
||||
animation/remove_immutable_tracks=true
|
||||
animation/import_rest_as_RESET=false
|
||||
import_script/path=""
|
||||
materials/extract=0
|
||||
materials/extract_format=0
|
||||
materials/extract_path=""
|
||||
_subresources={}
|
||||
gltf/naming_version=2
|
||||
gltf/embedded_image_handling=1
|
||||
gltf/texture_map_mode=1
|
||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://dwtldkyjqkfn2"
|
||||
path.s3tc="res://.godot/imported/floor_ceiling_hr_4_concrete_hr_1.png-18c5952fad7fed29047d5f53a9693939.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "6b68812ca1192c55adb97820fddac433"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/models/floor_ceiling_hr_4_concrete_hr_1.png"
|
||||
dest_files=["res://.godot/imported/floor_ceiling_hr_4_concrete_hr_1.png-18c5952fad7fed29047d5f53a9693939.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bmvhcu2j0mpeh"
|
||||
path.s3tc="res://.godot/imported/floor_ceiling_hr_4_tiles_floor_hr_2.png-0ab5afd20ee5925c948f8e3977df04f0.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "1db141300033565c166a12c6adf9734e"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/models/floor_ceiling_hr_4_tiles_floor_hr_2.png"
|
||||
dest_files=["res://.godot/imported/floor_ceiling_hr_4_tiles_floor_hr_2.png-0ab5afd20ee5925c948f8e3977df04f0.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://cd7ppu185gnyn"
|
||||
path.s3tc="res://.godot/imported/floor_ceiling_hr_4_wall_hr_2.png-976c9892b0e708b837cfe88549fbdddd.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "1dd1b53fe45bdc4cd8e26c2885e0a4a4"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/models/floor_ceiling_hr_4_wall_hr_2.png"
|
||||
dest_files=["res://.godot/imported/floor_ceiling_hr_4_wall_hr_2.png-976c9892b0e708b837cfe88549fbdddd.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
Binary file not shown.
@@ -0,0 +1,45 @@
|
||||
[remap]
|
||||
|
||||
importer="scene"
|
||||
importer_version=1
|
||||
type="PackedScene"
|
||||
uid="uid://b8abaxh2nxu3j"
|
||||
path="res://.godot/imported/simple-character-psx.glb-e2ab5e760b4cbcc47459e3a2153e8e6e.scn"
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/models/simple-character-psx.glb"
|
||||
dest_files=["res://.godot/imported/simple-character-psx.glb-e2ab5e760b4cbcc47459e3a2153e8e6e.scn"]
|
||||
|
||||
[params]
|
||||
|
||||
nodes/root_type=""
|
||||
nodes/root_name=""
|
||||
nodes/root_script=null
|
||||
mesh_library/use_node_names_as_mesh_names=false
|
||||
array_mesh/deduplicate_surfaces=true
|
||||
nodes/apply_root_scale=true
|
||||
nodes/root_scale=1.0
|
||||
nodes/import_as_skeleton_bones=false
|
||||
nodes/use_name_suffixes=true
|
||||
nodes/use_node_type_suffixes=true
|
||||
meshes/ensure_tangents=true
|
||||
meshes/generate_lods=true
|
||||
meshes/create_shadow_meshes=true
|
||||
meshes/light_baking=1
|
||||
meshes/lightmap_texel_size=0.2
|
||||
meshes/force_disable_compression=false
|
||||
skins/use_named_skins=true
|
||||
animation/import=true
|
||||
animation/fps=30
|
||||
animation/trimming=false
|
||||
animation/remove_immutable_tracks=true
|
||||
animation/import_rest_as_RESET=false
|
||||
import_script/path=""
|
||||
materials/extract=0
|
||||
materials/extract_format=0
|
||||
materials/extract_path=""
|
||||
_subresources={}
|
||||
gltf/naming_version=2
|
||||
gltf/embedded_image_handling=1
|
||||
gltf/texture_map_mode=1
|
||||
Binary file not shown.
@@ -0,0 +1,44 @@
|
||||
[remap]
|
||||
|
||||
importer="texture"
|
||||
type="CompressedTexture2D"
|
||||
uid="uid://bymgknsy145ap"
|
||||
path.s3tc="res://.godot/imported/simple-character-psx_character_256.png-5281280763143f8159deb85fd84320a2.s3tc.ctex"
|
||||
metadata={
|
||||
"imported_formats": ["s3tc_bptc"],
|
||||
"vram_texture": true
|
||||
}
|
||||
generator_parameters={
|
||||
"md5": "9a96d8b5a62d6005d9b1214f0f2f602d"
|
||||
}
|
||||
|
||||
[deps]
|
||||
|
||||
source_file="res://assets/models/simple-character-psx_character_256.png"
|
||||
dest_files=["res://.godot/imported/simple-character-psx_character_256.png-5281280763143f8159deb85fd84320a2.s3tc.ctex"]
|
||||
|
||||
[params]
|
||||
|
||||
compress/mode=2
|
||||
compress/high_quality=false
|
||||
compress/lossy_quality=0.7
|
||||
compress/uastc_level=0
|
||||
compress/rdo_quality_loss=0.0
|
||||
compress/hdr_compression=1
|
||||
compress/normal_map=0
|
||||
compress/channel_pack=0
|
||||
mipmaps/generate=true
|
||||
mipmaps/limit=-1
|
||||
roughness/mode=0
|
||||
roughness/src_normal=""
|
||||
process/channel_remap/red=0
|
||||
process/channel_remap/green=1
|
||||
process/channel_remap/blue=2
|
||||
process/channel_remap/alpha=3
|
||||
process/fix_alpha_border=true
|
||||
process/premult_alpha=false
|
||||
process/normal_map_invert_y=false
|
||||
process/hdr_as_srgb=false
|
||||
process/hdr_clamp_exposure=false
|
||||
process/size_limit=0
|
||||
detect_3d/compress_to=0
|
||||
+2
-3
@@ -1,8 +1,7 @@
|
||||
<Project Sdk="Godot.NET.Sdk/4.7.1">
|
||||
<PropertyGroup>
|
||||
<TargetFramework>net8.0</TargetFramework>
|
||||
<TargetFramework Condition=" '$(GodotTargetPlatform)' == 'android' ">net9.0</TargetFramework>
|
||||
<TargetFramework>net10.0</TargetFramework>
|
||||
<EnableDynamicLoading>true</EnableDynamicLoading>
|
||||
<RootNamespace>NightShift</RootNamespace>
|
||||
<RootNamespace>Game</RootNamespace>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@@ -1,15 +0,0 @@
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class Main : Node
|
||||
{
|
||||
// Called when the node enters the scene tree for the first time.
|
||||
public override void _Ready()
|
||||
{
|
||||
}
|
||||
|
||||
// Called every frame. 'delta' is the elapsed time since the previous frame.
|
||||
public override void _Process(double delta)
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -1 +0,0 @@
|
||||
uid://20xhubfcniqg
|
||||
@@ -1,19 +0,0 @@
|
||||
[gd_scene format=3 uid="uid://p766ipnev5hb"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://b5i827vmueyei" path="res://Assets/Textures/Skyboxes/skybox_emx_19.png" id="1_p8rbg"]
|
||||
|
||||
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_p8rbg"]
|
||||
panorama = ExtResource("1_p8rbg")
|
||||
|
||||
[sub_resource type="Sky" id="Sky_qtv3y"]
|
||||
sky_material = SubResource("PanoramaSkyMaterial_p8rbg")
|
||||
|
||||
[sub_resource type="Environment" id="Environment_cmk6n"]
|
||||
background_mode = 2
|
||||
sky = SubResource("Sky_qtv3y")
|
||||
glow_enabled = true
|
||||
|
||||
[node name="Main" type="Node" unique_id=118718415]
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=262568438]
|
||||
environment = SubResource("Environment_cmk6n")
|
||||
@@ -0,0 +1,8 @@
|
||||
using Game.Shared.Domain;
|
||||
|
||||
namespace Game.Features.Player.Domain;
|
||||
|
||||
public class PlayerData
|
||||
{
|
||||
public EntityId Id { get; private set; }
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://cjblpuqhlu1yf
|
||||
@@ -0,0 +1,10 @@
|
||||
using Game.Features.Player.Domain;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
namespace Game.Features.Player.Godot;
|
||||
|
||||
public partial class PlayerController : Node3D
|
||||
{
|
||||
[Export] public CharacterBody3D Body;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://mjm7ghkibnxa
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,13 @@
|
||||
[gd_scene format=3 uid="uid://curuqmbndymi6"]
|
||||
|
||||
[ext_resource type="PackedScene" uid="uid://blkhom228sqgi" path="res://assets/models/floor_ceiling_hr_4.glb" id="1_7nnv3"]
|
||||
|
||||
[sub_resource type="ConvexPolygonShape3D" id="ConvexPolygonShape3D_7nnv3"]
|
||||
points = PackedVector3Array(-2, 2.861023e-06, -2, -2, 2.861023e-06, 2, -2, 0.4000031, -2, 2, 2.861023e-06, -2, -2, 0.39996395, 2, 2, 2.861023e-06, 2, 2, 0.4000031, -2, 2, 0.39996395, 2)
|
||||
|
||||
[node name="floor_ceiling_hr_42" unique_id=33949496 instance=ExtResource("1_7nnv3")]
|
||||
|
||||
[node name="StaticBody3D" type="StaticBody3D" parent="." index="1" unique_id=1729023140]
|
||||
|
||||
[node name="CollisionShape3D" type="CollisionShape3D" parent="StaticBody3D" index="0" unique_id=1193592610]
|
||||
shape = SubResource("ConvexPolygonShape3D_7nnv3")
|
||||
@@ -0,0 +1,8 @@
|
||||
using Game.Features.Player.Godot;
|
||||
using Godot;
|
||||
using System;
|
||||
|
||||
public partial class GameWorld : Node
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://drctu5y21ey2y
|
||||
@@ -0,0 +1,56 @@
|
||||
[gd_scene format=3 uid="uid://c44pljehe0qun"]
|
||||
|
||||
[ext_resource type="Texture2D" uid="uid://b5i827vmueyei" path="res://assets/textures/skyboxes/skybox_emx_19.png" id="1_g4n7o"]
|
||||
[ext_resource type="PackedScene" uid="uid://curuqmbndymi6" path="res://src/Infrastructure/Floor/FloorCeilingHr42.tscn" id="2_1kpcd"]
|
||||
[ext_resource type="PackedScene" uid="uid://bka1dmgdi5btd" path="res://src/Features/Player/Godot/PlayerNode.tscn" id="2_mvtit"]
|
||||
|
||||
[sub_resource type="PanoramaSkyMaterial" id="PanoramaSkyMaterial_epykj"]
|
||||
panorama = ExtResource("1_g4n7o")
|
||||
|
||||
[sub_resource type="Sky" id="Sky_1kpcd"]
|
||||
sky_material = SubResource("PanoramaSkyMaterial_epykj")
|
||||
|
||||
[sub_resource type="Environment" id="Environment_mvtit"]
|
||||
background_mode = 2
|
||||
sky = SubResource("Sky_1kpcd")
|
||||
glow_enabled = true
|
||||
|
||||
[node name="GameWorld" type="Node" unique_id=222644234]
|
||||
|
||||
[node name="DirectionalLight3D" type="DirectionalLight3D" parent="." unique_id=1669211403]
|
||||
transform = Transform3D(-0.8660254, -0.43301278, 0.25, 0, 0.49999997, 0.86602545, -0.50000006, 0.75, -0.43301266, 0, 0, 0)
|
||||
shadow_enabled = true
|
||||
|
||||
[node name="WorldEnvironment" type="WorldEnvironment" parent="." unique_id=847581298]
|
||||
environment = SubResource("Environment_mvtit")
|
||||
|
||||
[node name="Player" parent="." unique_id=26823676 instance=ExtResource("2_mvtit")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 1, 0)
|
||||
|
||||
[node name="Entities" type="Node3D" parent="." unique_id=851492709]
|
||||
|
||||
[node name="floor_ceiling_hr_46" parent="Entities" unique_id=33949496 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, 4)
|
||||
|
||||
[node name="floor_ceiling_hr_47" parent="Entities" unique_id=277851190 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, 4)
|
||||
|
||||
[node name="floor_ceiling_hr_44" parent="Entities" unique_id=1904740552 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, -4)
|
||||
|
||||
[node name="floor_ceiling_hr_45" parent="Entities" unique_id=1096250035 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 0, 0, -4)
|
||||
|
||||
[node name="floor_ceiling_hr_43" parent="Entities" unique_id=1799505353 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, 4, 0, 0)
|
||||
|
||||
[node name="floor_ceiling_hr_42" parent="Entities" unique_id=1144273698 instance=ExtResource("2_1kpcd")]
|
||||
|
||||
[node name="floor_ceiling_hr_48" parent="Entities" unique_id=252704215 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4, 0, 4)
|
||||
|
||||
[node name="floor_ceiling_hr_49" parent="Entities" unique_id=1131416798 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4, 0, -4)
|
||||
|
||||
[node name="floor_ceiling_hr_50" parent="Entities" unique_id=1804933431 instance=ExtResource("2_1kpcd")]
|
||||
transform = Transform3D(1, 0, 0, 0, 1, 0, 0, 0, 1, -4, 0, 0)
|
||||
@@ -0,0 +1,6 @@
|
||||
namespace Game.Shared.Events;
|
||||
|
||||
public interface IEvent
|
||||
{
|
||||
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://bc6g3mar6am56
|
||||
@@ -0,0 +1,12 @@
|
||||
using System;
|
||||
|
||||
namespace Game.Shared.Events;
|
||||
|
||||
public interface IEventBus
|
||||
{
|
||||
IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : IEvent;
|
||||
|
||||
void Publish<TEvent>(TEvent gameEvent) where TEvent : IEvent;
|
||||
|
||||
void Clear();
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://c6txowanjmm5j
|
||||
@@ -0,0 +1,87 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
|
||||
namespace Game.Shared.Events;
|
||||
|
||||
public sealed class InMemoryEventBus : IEventBus
|
||||
{
|
||||
private readonly Dictionary<Type, List<Delegate>> _handlers = [];
|
||||
private readonly object _lock = new();
|
||||
|
||||
public IDisposable Subscribe<TEvent>(Action<TEvent> handler) where TEvent : IEvent
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(handler);
|
||||
|
||||
var eventType = typeof(TEvent);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_handlers.TryGetValue(eventType, out var list))
|
||||
{
|
||||
list = [];
|
||||
_handlers[eventType] = list;
|
||||
}
|
||||
|
||||
list.Add(handler);
|
||||
}
|
||||
|
||||
return new EventSubscription(() => Unsubscribe(eventType, handler));
|
||||
}
|
||||
|
||||
public void Publish<TEvent>(TEvent gameEvent) where TEvent : IEvent
|
||||
{
|
||||
ArgumentNullException.ThrowIfNull(gameEvent);
|
||||
|
||||
List<Delegate> snapshot = null;
|
||||
var eventType = typeof(TEvent);
|
||||
|
||||
lock (_lock)
|
||||
{
|
||||
if (_handlers.TryGetValue(eventType, out var list))
|
||||
{
|
||||
snapshot = new List<Delegate>(list);
|
||||
}
|
||||
}
|
||||
|
||||
if (snapshot == null) return;
|
||||
|
||||
foreach (var subscriber in snapshot)
|
||||
{
|
||||
((Action<TEvent>)subscriber)(gameEvent);
|
||||
}
|
||||
}
|
||||
|
||||
private void Unsubscribe(Type eventType, Delegate handler)
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
if (!_handlers.TryGetValue(eventType, out var list)) return;
|
||||
|
||||
list.Remove(handler);
|
||||
|
||||
if (list.Count == 0)
|
||||
{
|
||||
_handlers.Remove(eventType);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Clear()
|
||||
{
|
||||
lock (_lock)
|
||||
{
|
||||
_handlers.Clear();
|
||||
}
|
||||
}
|
||||
|
||||
private sealed class EventSubscription(Action unsubscribeAction) : IDisposable
|
||||
{
|
||||
private Action _unsubscribeAction = unsubscribeAction;
|
||||
|
||||
public void Dispose()
|
||||
{
|
||||
_unsubscribeAction?.Invoke();
|
||||
_unsubscribeAction = null;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
uid://dsai75jgta1v3
|
||||
Reference in New Issue
Block a user