diff --git a/Basalt.Core/Basalt.Core.csproj b/Basalt.Core/Basalt.Core.csproj
index a031b73..14c8d4d 100644
--- a/Basalt.Core/Basalt.Core.csproj
+++ b/Basalt.Core/Basalt.Core.csproj
@@ -4,7 +4,7 @@
net8.0
enable
enable
- 1.9.0
+ 1.9.1
True
BasaltLogoBg.png
README.md
diff --git a/Basalt.Raylib/Basalt.Raylib.csproj b/Basalt.Raylib/Basalt.Raylib.csproj
index 952ccd7..383038c 100644
--- a/Basalt.Raylib/Basalt.Raylib.csproj
+++ b/Basalt.Raylib/Basalt.Raylib.csproj
@@ -5,7 +5,7 @@
enable
enable
true
- 1.9.0
+ 1.9.1
True
BasaltLogoBg.png
README.md
diff --git a/Basalt.TestField/Components/TestTrigger.cs b/Basalt.TestField/Components/TestTrigger.cs
index 0e8e351..4e44b36 100644
--- a/Basalt.TestField/Components/TestTrigger.cs
+++ b/Basalt.TestField/Components/TestTrigger.cs
@@ -1,6 +1,8 @@
using Basalt.Common.Components;
using Basalt.Common.Entities;
using Basalt.Raylib.Components;
+using System.Drawing;
+using System.Numerics;
namespace Basalt.TestField.Components
{
@@ -10,12 +12,19 @@ public TestTrigger(Entity entity) : base(entity)
{
}
+ public override void OnStart()
+ {
+ Entity.AddComponent(new RaylibParticleSystem(Entity) { Looping = true, ModelCacheKey = "cube" });
+ var ps = Entity.GetComponent();
+ ps.UpdateDefaults(new() { Color = Color.RebeccaPurple, Velocity = new Vector3(0, 1f, 0) });
+ ps.OnStartEvent(this, EventArgs.Empty);
+ }
+
public override void OnCollision(Collider other)
{
if (other.Entity.Id == "entity.player")
{
- Console.WriteLine($"Trigger collided with {other.Entity.Id}");
- Entity.GetComponent().ModelCacheKey = "sphere";
+
}
}
}
diff --git a/Basalt.TestField/Program.cs b/Basalt.TestField/Program.cs
index 0650bb7..6633278 100644
--- a/Basalt.TestField/Program.cs
+++ b/Basalt.TestField/Program.cs
@@ -15,6 +15,7 @@
using Basalt.Raylib.Sound;
using Basalt.Raylib.Utils;
using Basalt.TestField;
+using Basalt.TestField.Components;
using Basalt.Types;
using Raylib_cs;
using System.Numerics;
@@ -65,20 +66,13 @@
Engine.CreateEntity(player);
-var emitter = new Entity();
-emitter.Transform.Position = new Vector3(0, 10, 0);
-emitter.AddComponent(new RaylibParticleSystem(emitter) { ModelCacheKey = "cube" });
-Engine.CreateEntity(emitter);
-
-var ps = emitter.GetComponent()!;
-
-ps.SubscribeOnParticleReset((ref Particle p) =>
-{
- p.Velocity = new(Random.Shared.NextSingle() * 10 - 5, Random.Shared.NextSingle() * 10 - 5, Random.Shared.NextSingle() * 10 - 5);
- // Apply random rotation
- p.Rotation = Quaternion.CreateFromYawPitchRoll(Random.Shared.NextSingle() * MathF.PI * 2, Random.Shared.NextSingle() * MathF.PI * 2, Random.Shared.NextSingle() * MathF.PI * 2);
-
-});
+var trigger = new Entity();
+trigger.AddComponent(new ModelRenderer(trigger) { ModelCacheKey = "cube", Size = new Vector3(1f), ColorTint = Color.Green });
+trigger.AddComponent(new BoxCollider(trigger) { Size = new Vector3(1, 1, 1), IsTrigger = true });
+trigger.AddComponent(new TestTrigger(trigger));
+trigger.AddComponent(new Rigidbody(trigger) { IsKinematic = true });
+trigger.Transform.Position = new Vector3(0, 1, 5);
+Engine.CreateEntity(trigger);
TestingUtils.SetupTestingScene(250);
TestingUtils.SetupDebugInfo();
\ No newline at end of file
diff --git a/Basalt.Tests/Integration/EntityIntegrationTests.cs b/Basalt.Tests/Integration/EntityIntegrationTests.cs
index b4dd029..c0b72ca 100644
--- a/Basalt.Tests/Integration/EntityIntegrationTests.cs
+++ b/Basalt.Tests/Integration/EntityIntegrationTests.cs
@@ -169,30 +169,6 @@ public void EntitySerializeToJson_WhenComponentHasEntityReference_ShouldSerializ
Assert.That(json, Does.Contain("entity.target"));
}
- [Test]
- public void EntityDeserializeFromJson_WhenComponentHasEntityReference_ShouldDeserializeReference()
- {
- // Arrange
- var target = new Entity();
- target.Id = "entity.target";
- var entity = new Entity();
- entity.Id = "entity.testing";
- entity.AddComponent(new TestComponent(entity) { Target = target });
-
- // Act
- Engine.Instance.Initialize();
- Engine.CreateEntity(target);
- var json = entity.SerializeToJson();
- var newEntity = Entity.DeserializeFromJson(json);
- Engine.CreateEntity(newEntity);
-
- // Assert
- Assert.IsNotNull(newEntity, "Deserialization failed, result entity was null");
- Assert.IsNotNull(newEntity.GetComponent(), "Test component was null");
- Assert.IsTrue(newEntity.GetComponent().HasStarted, "Component did not initialize");
- Assert.IsNotNull(newEntity.GetComponent().Target, "Target was null");
- Assert.That(newEntity.GetComponent().Target.Id, Is.EqualTo(target.Id), "Ids are different");
- }
[Test]
public void EntityDeserializeToJson_WhenMissingIdField_ShouldGenerateNew()
diff --git a/Basalt/Basalt.csproj b/Basalt/Basalt.csproj
index 9a957ea..015cd5b 100644
--- a/Basalt/Basalt.csproj
+++ b/Basalt/Basalt.csproj
@@ -5,7 +5,7 @@
enable
enable
true
- 1.9.0
+ 1.9.1
True
Basalt
BasaltLogoBg.png
diff --git a/Basalt/Common/Components/BaseParticleSystem.cs b/Basalt/Common/Components/BaseParticleSystem.cs
index 5b02ffa..dfbae23 100644
--- a/Basalt/Common/Components/BaseParticleSystem.cs
+++ b/Basalt/Common/Components/BaseParticleSystem.cs
@@ -186,6 +186,7 @@ public void UnsubscribeOnParticleReset(ParticleUpdateDelegate update)
/// The new default particle value
public void UpdateDefaults(Particle particle)
{
+ particle.Position = Entity.Transform.Position;
defaults = particle;
}
@@ -198,6 +199,7 @@ public void Reset()
for (int i = 0; i < _particles.Length; i++)
{
_particles[i] = defaults;
+ _particles[i].Lifetime = ParticleLifetime / _length * i;
}
}
diff --git a/Basalt/Common/Entities/Entity.cs b/Basalt/Common/Entities/Entity.cs
index 4f3b401..acb43fd 100644
--- a/Basalt/Common/Entities/Entity.cs
+++ b/Basalt/Common/Entities/Entity.cs
@@ -21,6 +21,11 @@ public class Entity
private List componentDtos = new();
private List components = new();
+ [JsonIgnore]
+ internal bool created = false;
+ [JsonIgnore]
+ private int componentCount = 0;
+
[JsonProperty("Id")]
public string Id { get; set; } = System.Guid.NewGuid().ToString();
///
@@ -113,6 +118,9 @@ public string SerializeToJson()
///
/// The json string to deserialize from
/// An entity instance from the JSON string
+ ///
+ /// It is not recommended to rely on deserialization to keep references as they will break.
+ ///
public static Entity DeserializeFromJson(string json)
{
JObject jObject = JObject.Parse(json);
@@ -208,6 +216,11 @@ public void AddComponent(Component component, bool overwrite = false)
break;
}
+ if(created)
+ component.OnStartEvent(this, EventArgs.Empty);
+
+ componentCount++;
+
}
///
@@ -244,6 +257,7 @@ private void ForceAddComponent(Component component)
// Handle other cases if necessary
break;
}
+ componentCount++;
}
///
@@ -257,6 +271,7 @@ public void RemoveComponent(Component component)
if (component.GetType() == typeof(Rigidbody))
Rigidbody = null;
+ componentCount--;
}
///
@@ -273,8 +288,9 @@ public void RemoveComponent(Component component)
if (typeof(T) == typeof(Collider))
return Collider as T;
- foreach (var component in components)
+ for (int i = 0; i < components.Count; i++)
{
+ Component? component = components[i];
if (component is T match)
{
return match;
@@ -344,13 +360,16 @@ public void Destroy()
{
Destroyed = true;
Engine.RemoveEntity(this);
- foreach (var child in Children)
+ for (int i = 0; i < Children.Count; i++)
{
+ Entity? child = Children[i];
child.Destroy();
}
- foreach (var component in components)
+ var count = componentCount;
+ for (int i = 0; i < count; i++)
{
+ Component? component = components[i];
component.onDestroy();
}
}
@@ -361,8 +380,9 @@ public void Destroy()
public void Create()
{
Engine.CreateEntity(this);
- foreach (var child in Children)
+ for (int i = 0; i < Children.Count; i++)
{
+ Entity? child = Children[i];
child.Create();
}
}
@@ -371,8 +391,10 @@ public void CallOnCollision(Collider other)
{
if (Destroyed)
return;
- foreach (var component in components)
- component.OnCollision(other);
+
+ var count = componentCount;
+ for (int i = 0; i < count; i++)
+ components[i].OnCollision(other);
}
private static Type? ByName(string name)
@@ -394,8 +416,10 @@ public void CallOnCollision(Collider other)
internal void CallStart()
{
- foreach (var component in components)
+ var count = componentCount;
+ for (int i = 0; i < count; i++)
{
+ Component? component = components[i];
if (!component.started)
{
var dependencyAttribute = component.GetType().GetCustomAttribute();
@@ -431,8 +455,9 @@ public Entity Clone()
{
var result = new Entity();
result.Id = Id + Guid.NewGuid().ToString();
- foreach (var component in components)
+ for (int i = 0; i < components.Count; i++)
{
+ Component? component = components[i];
var c = Activator.CreateInstance(component.GetType(), result) as Component;
foreach (var prop in c.GetType().GetProperties())
{
diff --git a/Basalt/Common/Events/EventBus.cs b/Basalt/Common/Events/EventBus.cs
index 4e38c28..1591b16 100644
--- a/Basalt/Common/Events/EventBus.cs
+++ b/Basalt/Common/Events/EventBus.cs
@@ -1,4 +1,5 @@
using Basalt.Core.Common.Abstractions.Engine;
+using System.Collections.Concurrent;
namespace Basalt.Common.Events
{
///
@@ -6,17 +7,15 @@ namespace Basalt.Common.Events
///
public class EventBus : IEventBus
{
- private readonly List observers;
private readonly object lockObject;
// Game Events
- private Dictionary eventHandlers = new Dictionary();
+ private ConcurrentDictionary eventHandlers = new ConcurrentDictionary();
///
/// Initializes a new instance of the class.
///
public EventBus()
{
- observers = new List();
lockObject = new object();
}
diff --git a/Basalt/Engine.cs b/Basalt/Engine.cs
index 99628fa..e8a2d77 100644
--- a/Basalt/Engine.cs
+++ b/Basalt/Engine.cs
@@ -176,6 +176,7 @@ public static void CreateEntity(Entity entity)
Instance.Logger?.LogDebug($"Creating entity {entity.Id}...");
Instance.EntityManager.AddEntity(entity);
Instance.GetEngineComponent()?.AddEntityToSimulation(entity);
+ entity.created = true;
entity.CallStart();
}
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 52f11c7..d7e2f2f 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,15 @@
All notable changes to this project will be documented in this file. See [versionize](https://github.com/versionize/versionize) for commit guidelines.
+
+## [1.9.1](https://www.github.com/thiagomvas/Basalt/releases/tag/v1.9.1) (2024-06-18)
+
+### Bug Fixes
+
+* Adding components during some events would crash the engine ([c13a6cf](https://www.github.com/thiagomvas/Basalt/commit/c13a6cf34094cee8841c5e2cbace019422ca04f2))
+* Components are now initialized when added after entity creation ([7aab969](https://www.github.com/thiagomvas/Basalt/commit/7aab9696b8da0ddda0076eef0be87d29e28461ec))
+* Particle Lifetime and starting position now work as expected ([7d19af5](https://www.github.com/thiagomvas/Basalt/commit/7d19af5b30834bbce56df88c45e4697cf361e610))
+
## [1.9.0](https://www.github.com/thiagomvas/Basalt/releases/tag/v1.9.0) (2024-06-18)