Skip to content

Commit

Permalink
Merge pull request #400 from Pulsar4xDevs/Racing
Browse files Browse the repository at this point in the history
Racing
  • Loading branch information
se5a committed Jan 3, 2024
2 parents ec58b41 + 4094e00 commit 318d158
Show file tree
Hide file tree
Showing 10 changed files with 126 additions and 57 deletions.
32 changes: 22 additions & 10 deletions Pulsar4X/GameEngine/Engine/Entities/AEntityChangeListener.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,16 +9,26 @@ namespace Pulsar4X.Engine

public abstract class AEntityChangeListener
{
private object _lockObj = new object();
public bool IsProcessing { get; private set; } = false;

protected ConcurrentQueue<EntityChangeData> EntityChanges { get; } = new ConcurrentQueue<EntityChangeData>();
internal ConcurrentHashSet<Entity> ListningToEntites { get; } = new ConcurrentHashSet<Entity>();
//internal List<int> IncludeDBTypeIndexFilter = new List<int>();
//internal List<int> ExcludeDBTypeIndexFilter = new List<int>();


internal AEntityChangeListener(EntityManager manager)
{
manager.EntityListeners.Add(this);
}

public void TagIsProcessing(bool isProcessing)
{
lock (_lockObj)
IsProcessing = isProcessing;
}

internal virtual void AddChange(EntityChangeData changeData)
{
if (changeData.ChangeType != EntityChangeData.EntityChangeType.EntityAdded)
Expand All @@ -30,8 +40,6 @@ internal virtual void AddChange(EntityChangeData changeData)
}
else
{
bool isvalid = changeData.Entity.IsValid;

ListningToEntites.Add(changeData.Entity);
EntityChanges.Enqueue(changeData);
}
Expand All @@ -46,12 +54,18 @@ public bool HasUpdates()
return (EntityChanges.Count > 0);
}


internal void Enqueue(EntityChangeData changeData)
public bool HasBeenProcessed()
{
EntityChanges.Enqueue(changeData);
lock (_lockObj)
{
if (!IsProcessing && EntityChanges.Count == 0)
return true;
}
return false;
}

private ConcurrentHashSet<Entity> entityNew = new ConcurrentHashSet<Entity>();

public bool TryDequeue(out EntityChangeData changeData)
{

Expand Down Expand Up @@ -140,11 +154,11 @@ public EntityChangeListener(EntityManager manager, Entity factionEntity, List<Ty
ListningToEntites.Add(entityitem);
}
}




internal override void AddChange(EntityChangeData changeData)
{
if (changeData.Entity is null)
throw new Exception();
switch (changeData.ChangeType)
{
case EntityChangeData.EntityChangeType.EntityAdded:
Expand Down Expand Up @@ -176,8 +190,6 @@ private void OnEntityAdded(EntityChangeData changeData)

if (changeData.Entity.HasDataBlob(includeitem))
{


include = true;
}
else
Expand Down
11 changes: 4 additions & 7 deletions Pulsar4X/GameEngine/Engine/Entities/Entity.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,13 +154,10 @@ public void RemoveComponent(ComponentInstance instance)

public void Destroy()
{
if (!IsValid)
{
throw new InvalidOperationException("Invalid Entities cannot be destroyed. Either this entity has already been destroyed, or it was destroyed before it was fully initialized.");
}
Manager.RemoveEntity(this);
Manager = null;
FactionOwnerID = -1;
Manager.TagEntityForRemoval(this);
//manager does this:
//Manager = null;
//FactionOwnerID = -1;
}

public bool Equals(Entity? other)
Expand Down
7 changes: 7 additions & 0 deletions Pulsar4X/GameEngine/Engine/Entities/EntityChangeData.cs
Original file line number Diff line number Diff line change
Expand Up @@ -16,5 +16,12 @@ public enum EntityChangeType
public EntityChangeType ChangeType;
public Entity Entity;
public BaseDataBlob? Datablob; //will be null if ChangeType is EntityAdded or EntityRemoved.

public EntityChangeData(Entity entity, EntityChangeType changeType)
{
Entity = entity;
ChangeType = changeType;
}

}
}
91 changes: 69 additions & 22 deletions Pulsar4X/GameEngine/Engine/Entities/EntityManager.cs
Original file line number Diff line number Diff line change
Expand Up @@ -43,8 +43,21 @@ public class EntityManager
[JsonIgnore]
public DateTime StarSysDateTime => ManagerSubpulses.StarSysDateTime;

private object _lockObj = new object();
internal List<AEntityChangeListener> EntityListeners { get; set; } = new ();
internal List<Entity> _entitiesTaggedForRemoval = new List<Entity>();

internal bool HaveAllListnersProcessed()
{
foreach (var listener in EntityListeners)
{
if (!listener.HasBeenProcessed())
return false;
}
return true;
}


[JsonProperty]
public ManagerSubPulse ManagerSubpulses { get; internal set; }

Expand All @@ -58,6 +71,8 @@ public class EntityManager
[PublicAPI]
public static readonly EntityManager InvalidManager = new EntityManager();



#region Constructors
internal EntityManager() { }

Expand Down Expand Up @@ -161,7 +176,7 @@ public void Transfer(Entity entity)
if(entity.Manager != null)
{
dataBlobs = entity.Manager.GetAllDataBlobsForEntity(entity.Id);
entity.Manager.RemoveEntity(entity);
entity.Manager.TagEntityForRemoval(entity);
}

AddEntity(entity, dataBlobs);
Expand All @@ -182,34 +197,64 @@ private bool IsValidID(int entityID)
return _entities.ContainsKey(entityID);
}

internal void RemoveEntity(Entity entity)
internal void TagEntityForRemoval(Entity entity)
{
if (!IsValidEntity(entity))
{
throw new ArgumentException("Provided Entity is not valid in this manager.");
}

if(!_entities.Remove(entity.Id))
//check we've not already tagged this.
if (!_entitiesTaggedForRemoval.Contains(entity))
{
throw new KeyNotFoundException($"Entity with ID {entity.Id} not found in manager.");
//do we really need to check this?
//if so, do we really need to throw an exception?
if (!IsValidEntity(entity))
{
throw new ArgumentException("Provided Entity is not valid in this manager.");
}
entity.IsValid = false;
ManagerSubpulses.RemoveEntity(entity);
_entitiesTaggedForRemoval.Add(entity);
UpdateListeners(entity, null, EntityChangeData.EntityChangeType.EntityRemoved);
}
}

foreach(var storeEntry in _datablobStores)
/// <summary>
/// This should happen at the beginning of a managers time pulse,
/// eg entites get removed at the start of the next pulse.
/// </summary>
internal void RemoveTaggedEntitys()
{
foreach (var entity in _entitiesTaggedForRemoval)
{
storeEntry.Value.Remove(entity.Id);
}
foreach (var storeEntry in _datablobStores)
{
storeEntry.Value.Remove(entity.Id);
}
foreach (var (key, value) in _factionSensorContacts)
{
value.RemoveContact(entity.Id);
}

//remove each of the datablobs.
foreach (var db in entity.GetAllDataBlobs())
{
var type = db.GetType();
if (_datablobStores.ContainsKey(type))
{
var blob = _datablobStores[type][entity.Id];
blob.OwningEntity = null;
_datablobStores[type].Remove(entity.Id);
}
}
//actualy remove it from the manager here.
if (!_entities.Remove(entity.Id))
{
throw new KeyNotFoundException($"Entity with ID {entity.Id} not found in manager.");
}
entity.Manager = null;
entity.FactionOwnerID = -1;
Event e = Event.Create(EventType.EntityDestroyed, StarSysDateTime, "Entity Removed From Manager", entity.FactionOwnerID, ManagerGuid, entity.Id);
EventManager.Instance.Publish(e);

foreach(var (key, value) in _factionSensorContacts)
{
value.RemoveContact(entity.Id);
}

entity.IsValid = false;

UpdateListeners(entity, null, EntityChangeData.EntityChangeType.EntityRemoved);

Event e = Event.Create(EventType.EntityDestroyed, StarSysDateTime, "Entity Removed From Manager", entity.FactionOwnerID, ManagerGuid, entity.Id);
EventManager.Instance.Publish(e);
_entitiesTaggedForRemoval = new List<Entity>();
}

public List<BaseDataBlob> GetAllDataBlobsForEntity(int entityID)
Expand Down Expand Up @@ -317,6 +362,8 @@ public void RemoveDatablob<T>(int entityId) where T : BaseDataBlob

private void UpdateListeners(Entity entity, BaseDataBlob? db, EntityChangeData.EntityChangeType change)
{
if (entity is null)
throw new Exception();
//listners to this work on thier own threads and are not affected by this one.
if (EntityListeners.Count > 0)
{
Expand Down
5 changes: 5 additions & 0 deletions Pulsar4X/GameEngine/Engine/ManagerSubPulse.cs
Original file line number Diff line number Diff line change
Expand Up @@ -282,6 +282,11 @@ internal void ProcessSystem(DateTime targetDateTime)
//keep processing the system till we've reached the wanted datetime
Performance.BeginInterval();
IsProcessing = true;

if (!SpinWait.SpinUntil(_entityManager.HaveAllListnersProcessed, TimeSpan.FromMilliseconds(250)))
throw new Exception("timeout on listnerProcessing.");

_entityManager.RemoveTaggedEntitys();
while (StarSysDateTime < targetDateTime)
{
Performance.BeingSubInterval();
Expand Down
2 changes: 1 addition & 1 deletion Pulsar4X/GameEngine/Engine/Orders/Actions/FleetOrder.cs
Original file line number Diff line number Diff line change
Expand Up @@ -172,7 +172,7 @@ internal override void Execute(DateTime atDateTime)
navyDB.ParentDB.RemoveChild(_entityCommanding);
}

_entityCommanding.Manager.RemoveEntity(_entityCommanding);
_entityCommanding.Manager.TagEntityForRemoval(_entityCommanding);
break;
case FleetOrderType.ChangeParent:
// Remove the entity from the parent tree
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -195,7 +195,7 @@ internal static void SpawnWreck(Entity DestroyedShip)

//Does anything else need to be done to delete a ship?

mySystem.RemoveEntity(DestroyedShip);
mySystem.TagEntityForRemoval(DestroyedShip);
}

/// <summary>
Expand Down Expand Up @@ -230,7 +230,7 @@ internal static void SpawnSubAsteroids(Entity Asteroid, DateTime atDateTime)
//var newOrbit = OrbitDB.FromVector(origOrbit.Parent, )
Entity newAsteroid2 = AsteroidFactory.CreateAsteroid4(pDB.AbsolutePosition, origOrbit, atDateTime, newMass);

mySystem.RemoveEntity(Asteroid);
mySystem.TagEntityForRemoval(Asteroid);

//Randomize the number of created asteroids?
}
Expand All @@ -244,7 +244,7 @@ internal static void SpawnSubAsteroids(Entity Asteroid, DateTime atDateTime)
if(mySystem == null)
throw new NullReferenceException($"Unable to find the system {pDB.SystemGuid}");

mySystem.RemoveEntity(Asteroid);
mySystem.TagEntityForRemoval(Asteroid);
}
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -28,14 +28,6 @@ public int ProcessManager(EntityManager manager, int deltaSeconds)

private void UpdateWeapons(GenericFiringWeaponsDB db)
{
//reload all internal magazines.
for (int i = 0; i < db.WpnIDs.Length ; i++)
{
var tickReloadAmount = db.ReloadAmountsPerSec[i];
db.InternalMagQty[i] += tickReloadAmount;
db.WeaponStates[i].InternalMagCurAmount = db.InternalMagQty[i];
}

//fire weapons that are able.
for (int i = 0; i < db.WpnIDs.Length; i++)
{
Expand All @@ -49,6 +41,17 @@ private void UpdateWeapons(GenericFiringWeaponsDB db)
db.WeaponStates[i].InternalMagCurAmount = db.InternalMagQty[i];
}
}

//reload all internal magazines.
for (int i = 0; i < db.WpnIDs.Length ; i++)
{
var tickReloadAmount = db.ReloadAmountsPerSec[i];
var magQty = Math.Max(db.InternalMagQty[i] + tickReloadAmount, db.InternalMagSizes[i]);
db.InternalMagQty[i] = magQty;
db.WeaponStates[i].InternalMagCurAmount = magQty;
}


}

public TimeSpan RunFrequency { get; } = TimeSpan.FromSeconds(1);
Expand Down
2 changes: 1 addition & 1 deletion Pulsar4X/Pulsar4X.Client/EntityManagement/FireControl.cs
Original file line number Diff line number Diff line change
Expand Up @@ -194,7 +194,7 @@ void ShowWeapon(WeaponState wpn, int i = 0)
ImGui.Text(GetRichWeaponName(wpn));
var selectableSize = new Vector2(ImGui.GetColumnWidth(0) - 24, ImGui.GetTextLineHeightWithSpacing());
Vector2 progsize = new Vector2(selectableSize.X - nameSize, selectableSize.Y);
float reloadAmountPerc = (reloadAmount / reloadMax) * 100;
float reloadAmountPerc = (reloadAmount / reloadMax);
ImGui.SetCursorPos(new Vector2( nameSize, cpos.Y));
ImGui.ProgressBar(reloadAmountPerc, progsize);

Expand Down
8 changes: 3 additions & 5 deletions Pulsar4X/Pulsar4X.Client/MapRendering/SystemState.cs
Original file line number Diff line number Diff line change
Expand Up @@ -101,7 +101,6 @@ private SystemState(StarSystem system)

void HandleUpdates(EntityChangeData change)
{

switch (change.ChangeType)
{
case EntityChangeData.EntityChangeType.EntityAdded:
Expand All @@ -114,7 +113,6 @@ void HandleUpdates(EntityChangeData change)
EntitysToBin.Add(change.Entity.Id);
break;
}

}

/// <summary>
Expand All @@ -123,6 +121,7 @@ void HandleUpdates(EntityChangeData change)
/// </summary>
public void PreFrameSetup()
{
_changeListener.TagIsProcessing(true);
while (_changeListener.TryDequeue(out EntityChangeData change))
{
SystemChanges.Add(change);
Expand All @@ -133,8 +132,7 @@ public void PreFrameSetup()
SensorChanges.Add(change);
HandleUpdates(change);
}



foreach (var item in EntityStatesWithPosition.Values)
{
if (item.IsDestroyed) //items get flagged via an event triggered by worker threads.
Expand All @@ -143,7 +141,6 @@ public void PreFrameSetup()
EntitysToBin.Add(item.Entity.Id);
}
}

}

/// <summary>
Expand All @@ -164,6 +161,7 @@ public void PostFrameCleanup()
{
item.PostFrameCleanup();
}
_changeListener.TagIsProcessing(false);
}
}
}

0 comments on commit 318d158

Please sign in to comment.