Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions Assets/Scripts/IADS/IADS.cs
Original file line number Diff line number Diff line change
Expand Up @@ -126,6 +126,9 @@ public void RegisterNewAsset(IInterceptor asset) {
return;
}

if (asset is InterceptorBase interceptorBase) {
interceptorBase.CommsParent = _commsAgent;
}
_assets.Add(asset.HierarchicalAgent);
}

Expand Down
3 changes: 3 additions & 0 deletions Assets/Scripts/Interceptors/CarrierBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,9 @@ private IEnumerator ReleaseManager(float period) {
if (agent is IInterceptor subInterceptor) {
subInterceptor.OnAssignSubInterceptor += AssignSubInterceptor;
subInterceptor.OnReassignTarget += ReassignTarget;
if (subInterceptor is InterceptorBase interceptorBase) {
interceptorBase.CommsParent = this;
}
if (subInterceptor.Movement is MissileMovement movement) {
movement.FlightPhase = Simulation.FlightPhase.Boost;
}
Expand Down
93 changes: 82 additions & 11 deletions Assets/Scripts/Interceptors/InterceptorBase.cs
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,10 @@

// Base implementation of an interceptor.
public abstract class InterceptorBase : AgentBase, IInterceptor {
// Optional mailbox receiver used to route requests to the logical parent interceptor or IADS
// proxy.
public IAgent CommsParent { get; set; }

public event InterceptorEventHandler OnHit;
public event InterceptorEventHandler OnMiss;
public event InterceptorEventHandler OnDestroyed;
Expand Down Expand Up @@ -101,17 +105,17 @@ public bool EvaluateReassignedTarget(IHierarchical target) {
}

public void AssignSubInterceptor(IInterceptor subInterceptor) {
if (subInterceptor.CapacityRemaining <= 0) {
if (subInterceptor == null || subInterceptor.CapacityRemaining <= 0) {
return;
}

// Find a new target for the sub-interceptor within the parent interceptor's assigned targets.
IHierarchical target = HierarchicalAgent.FindNewTarget(subInterceptor.HierarchicalAgent,
subInterceptor.CapacityRemaining);
// Evaluate the new target and decide whether to continue searching for other targets.
if (!subInterceptor.EvaluateReassignedTarget(target)) {
// Propagate the sub-interceptor target assignment to the parent interceptor above.
OnAssignSubInterceptor?.Invoke(subInterceptor);
if (target != null) {
SendAssignTargetToSub(subInterceptor, target);
} else {
SendAssignRequestToParent(subInterceptor);
}
}

Expand All @@ -123,7 +127,7 @@ public void ReassignTarget(IHierarchical target) {
// another sub-interceptor(s) to pursue the target(s).
// 3. Propagate the target re-assignment to the parent interceptor above.
if (CapacityPlannedRemaining <= 0) {
OnReassignTarget?.Invoke(target);
SendReassignRequestToParent(target);
return;
}

Expand Down Expand Up @@ -155,7 +159,7 @@ protected override void FixedUpdate() {
List<IHierarchical> escapingTargets =
targetHierarchicals.Where(EscapeDetector.IsEscaping).ToList();
foreach (var target in escapingTargets) {
OnReassignTarget?.Invoke(target);
SendReassignRequestToParent(target);
}
if (escapingTargets.Count == targetHierarchicals.Count) {
RequestReassignment(this);
Expand Down Expand Up @@ -279,7 +283,7 @@ private void RegisterMiss(IInterceptor interceptor) {
RequestTargetReassignment(interceptor);

// Request a new target from the parent interceptor.
OnAssignSubInterceptor?.Invoke(interceptor);
SendAssignRequestToParent(interceptor);
}

private void RegisterDestroyed(IInterceptor interceptor) {
Expand All @@ -296,7 +300,7 @@ private void RequestTargetReassignment(IInterceptor interceptor) {
List<IHierarchical> targetHierarchicals =
target.LeafHierarchicals(activeOnly: true, withTargetOnly: false);
foreach (var targetHierarchical in targetHierarchicals) {
OnReassignTarget?.Invoke(targetHierarchical);
SendReassignRequestToParent(targetHierarchical);
}

RequestReassignment(interceptor);
Expand All @@ -305,7 +309,7 @@ private void RequestTargetReassignment(IInterceptor interceptor) {
private void RequestReassignment(IInterceptor interceptor) {
if (interceptor.IsReassignable) {
// Request a new target from the parent interceptor.
OnAssignSubInterceptor?.Invoke(interceptor);
SendAssignRequestToParent(interceptor);
}
}

Expand Down Expand Up @@ -335,7 +339,7 @@ private IEnumerator UnassignedTargetsManager(float period) {
filteredTargets.OrderBy(target => Vector3.Distance(Position, target.Position));
var excessTargets = orderedTargets.Skip(CapacityPlannedRemaining);
foreach (var target in excessTargets) {
OnReassignTarget?.Invoke(target);
SendReassignRequestToParent(target);
}
unassignedTargets = orderedTargets.Take(CapacityPlannedRemaining);
} else {
Expand All @@ -362,4 +366,71 @@ private IEnumerator UnassignedTargetsManager(float period) {
newSubHierarchical.RecursiveCluster(maxClusterSize: CapacityPerSubInterceptor);
}
}

// Send an AssignTargetRequest message to the parent mailbox receiver.
private void SendAssignRequestToParent(IInterceptor subInterceptor) {
IAgent parent = CommsParent;
if (subInterceptor == null) {
return;
}
if (parent == null) {
OnAssignSubInterceptor?.Invoke(subInterceptor);
return;
}
SendMailboxMessage(new AssignTargetRequestMessage(this, parent, subInterceptor));
}

// Send a ReassignTargetRequest message to the parent mailbox receiver.
private void SendReassignRequestToParent(IHierarchical target) {
IAgent parent = CommsParent;
if (target == null) {
return;
}
if (parent == null) {
OnReassignTarget?.Invoke(target);
return;
}
SendMailboxMessage(new ReassignTargetRequestMessage(this, parent, target));
}

// Send an AssignTargetResponse message to the child mailbox receiver.
private void SendAssignTargetToSub(IInterceptor subInterceptor, IHierarchical target) {
if (subInterceptor == null || target == null) {
return;
}
SendMailboxMessage(new AssignTargetResponseMessage(this, subInterceptor, target));
}

// Send a message through the mailbox.
private void SendMailboxMessage(Message message) {
if (message == null) {
return;
}
Mailbox mailbox = Mailbox.GetOrCreateInstance();
if (mailbox == null) {
return;
}
mailbox.Send(message);
}

// Execution happens here after receiving and reading message. PayloadData is read and handled.
protected override void OnMessage(Message message) {
if (message == null) {
return;
}
switch (message) {
case AssignTargetRequestMessage assignRequest:
AssignSubInterceptor(assignRequest.PayloadData.SubInterceptor);
break;
case ReassignTargetRequestMessage reassignRequest:
ReassignTarget(reassignRequest.PayloadData.Target);
break;
case AssignTargetResponseMessage assignTarget:
IHierarchical assignedTarget = assignTarget.PayloadData.Target;
if (assignedTarget != null) {
EvaluateReassignedTarget(assignedTarget);
}
break;
Comment thread
Joseph0120 marked this conversation as resolved.
}
}
}
32 changes: 32 additions & 0 deletions Assets/Tests/EditMode/IADSMailboxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,6 +174,24 @@ public void MailboxDelivery_ForDifferentReceiver_DoesNotTriggerIadsResponse() {
Assert.IsNull(deliveredResponse);
}

// Verifies that top-level launchers route mailbox requests to the IADS proxy.
[Test]
public void RegisterNewLauncher_SetsCommsParentToIadsProxy() {
var launcherObject = new GameObject("Launcher");
try {
var launcher = launcherObject.AddComponent<TestLauncherInterceptor>();
launcherObject.AddComponent<Rigidbody>();
launcher.HierarchicalAgent = new HierarchicalAgent(launcher);
launcher.InvokeAwakeForTest();

_iads.RegisterNewLauncher(launcher);

Assert.AreSame(_commsAgent, launcher.CommsParent);
} finally {
Object.DestroyImmediate(launcherObject);
}
}

private static SimManager CreateSimManagerStub() {
return (SimManager)FormatterServices.GetUninitializedObject(typeof(SimManager));
}
Expand Down Expand Up @@ -333,4 +351,18 @@ public void Terminate() {
public Transformation GetRelativeTransformation(IHierarchical target) => default;
public Transformation GetRelativeTransformation(in Vector3 waypoint) => default;
}

private sealed class TestLauncherInterceptor : InterceptorBase, IAgent {
public override bool IsPursuer => false;

public void InvokeAwakeForTest() {
base.Awake();
}

void IAgent.CreateTargetModel(IHierarchical target) {}

void IAgent.DestroyTargetModel() {}

void IAgent.UpdateTargetModel() {}
}
}
2 changes: 2 additions & 0 deletions Assets/Tests/EditMode/IADSMailboxTests.cs.meta

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading
Loading