Posting here always seems to get my brain juices flowing a bit better and I've re-written my code to use events more extensively.
Explanation of my event call chain.
When the user makes a power request (by clicking on an increase subsystem power icon), the button notifies the appropriate subsystem via an event that it needs to start a power request. The subsystem then first checks to make sure its even capable of getting more power and if possible, notifies its parent power relay via calling a power request event. The appropriate relay receives this event and checks to make sure that the relay can handle more power flowing through it. If it cannot, it does a callback event to the subsystem denying the power request, if it can, it calls another power request event that the WarpCore is listening to. The warp core checks if it has any available power and either allocates power and does a successful power request callback, or if it cannot, it calls a refused power request callback. Finally if warpcore sends back a successful request then the relay will increase its power load and the subsystem will allocate more power to itself. If the call wasn't a success, the relay will notify the subsystem of the failure and neither will increase their power usage. ....Wow that sounds way more complicated than it was to code.
I've posted the classes below to get any potential feedback on my method! I love code reviews. The classes are in event call order as best as possible.
public class ControlButton : MonoBehaviour
{
private EventButton eventButton = null;
private Subsystem subsystem = null;
public void Initialize(Subsystem subsystem)
{
eventButton = this.gameObject.ValidateComponent<EventButton>();
eventButton.onLeftClick += subsystem.AllocatePowerRequest;
eventButton.onRightClick += subsystem.DeallocatePowerRequest;
this.subsystem = subsystem;
}
}
public class Subsystem : MonoBehaviour
{
public event EventHandler OnAllocationChange;
public event EventHandler OnPotentialAllocationChange;
public event EventHandler OnWantPower;
public Console console = null;
public Equipment equipment = null;
public Relay relay = null;
public virtual void InitializeNew(int currentHitPoints, int maximumHitPoints, int currentLevel, int maximumLevel, object[] abilities)
{
equipment.CurrentHitPoints = currentHitPoints;
equipment.MaximumHitPoints = maximumHitPoints;
IsActive = true;
CurrentLevel = currentLevel;
MaximumLevel = maximumLevel;
Abilities = abilities;
HookEvents();
}
private void HookEvents()
{
equipment.Damaged += EquipmentDamaged;
console.Damaged += ConsoleDamaged;
relay.OnApprovedRequestPower += AllocatePower;
relay.OnRefuseRequestPower += NotGivenPower;
}
private void AllocatePower(object sender, EventArgs e)
{
PowerTransferInfoEventArgs powerTransferInfo = (PowerTransferInfoEventArgs)e;
if (powerTransferInfo.Subsystem == this)
DoAllocation();
}
private void NotGivenPower(object sender, EventArgs e)
{
// TODO: Do something showing we were not given power.
}
public virtual void AllocatePowerRequest(object sender, EventArgs e)
{
if (ActiveLevel < CurrentLevel)
{
if (OnWantPower != null)
{
PowerTransferInfoEventArgs powerTransferInfo = new PowerTransferInfoEventArgs();
powerTransferInfo.Subsystem = this;
OnWantPower(this, powerTransferInfo);
}
}
}
public virtual void DeallocatePowerRequest(object sender, EventArgs e)
{
DoDeallocation();
}
public virtual void DoAllocation()
{
Debug.Log("Increase Active Level...");
ActiveLevel = Mathf.Clamp(ActiveLevel + 1, 0, CurrentLevel);
AllocationChangeNotify();
}
public virtual void DoDeallocation()
{
ActiveLevel = Mathf.Clamp(ActiveLevel - 1, 0, CurrentLevel);
AllocationChangeNotify();
}
public virtual void IncreaseAllocationPotential()
{
CurrentLevel = Mathf.Clamp(CurrentLevel + 1, 0, MaximumLevel);
AllocationChangeNotify();
}
public virtual void DecreaseAllocationPotential()
{
CurrentLevel = Mathf.Clamp(CurrentLevel - 1, 0, MaximumLevel);
AllocationChangeNotify();
}
private void AllocationChangeNotify()
{
Debug.Log("Active Level Notidy...");
if (OnAllocationChange == null)
return;
SubsystemPowerLevelEventArgs info = new SubsystemPowerLevelEventArgs(CurrentLevel, ActiveLevel, MaximumLevel);
OnAllocationChange(this, info);
}
}
public class Relay : MonoBehaviour
{
public event EventHandler OnRequestPower;
public event EventHandler OnRefuseRequestPower;
public event EventHandler OnApprovedRequestPower;
private int currentLevel = 0;
private int maxLevel = 0;
public Relay()
{
}
public void ListenForPowerRequestFrom(Subsystem subsystem)
{
subsystem.OnWantPower += RequestPowerFromWarpCore;
}
public void RequestPowerFromWarpCore(object sender, EventArgs e)
{
// Cancel the power request if the relay is at capacity.
if (currentLevel == maxLevel)
{
RefusePowerRequest(this, e);
return;
}
if (OnRequestPower != null)
{
PowerTransferInfoEventArgs powerTransferInfo = (PowerTransferInfoEventArgs)e;
powerTransferInfo.Relay = this;
OnRequestPower(this, powerTransferInfo);
}
}
public void ApprovePowerRequest(object sender, EventArgs e)
{
PowerTransferInfoEventArgs powerTransferInfo = (PowerTransferInfoEventArgs)e;
if (powerTransferInfo.Relay == this)
{
if (OnApprovedRequestPower != null)
OnApprovedRequestPower(this, powerTransferInfo);
IncreaseLevel();
}
}
public void RefusePowerRequest(object sender, EventArgs e)
{
PowerTransferInfoEventArgs powerTransferInfo = (PowerTransferInfoEventArgs)e;
if (powerTransferInfo.Relay == this)
{
if (OnRefuseRequestPower != null)
OnRefuseRequestPower(this, powerTransferInfo);
}
}
private bool IncreaseLevel()
{
if (currentLevel < maxLevel)
{
currentLevel++;
return true;
}
return false;
}
private bool DecreaseLevel()
{
if (currentLevel > 0)
{
currentLevel--;
return true;
}
return false;
}
}
public class WarpCore
{
public EventHandler OnSuccesfulAllocation;
public EventHandler OnSuccessfulDeallocation;
public EventHandler OnFailedAllocation;
public EventHandler OnFailedDeallocation;
private int absoluteMaximumAllocation = 31;
private int maximumAllocators = 0;
private Dictionary<PowerAllocator, Subsystem> allocators = new Dictionary<PowerAllocator, Subsystem>();
public WarpCore(int maximumPowerCells, int currentUpgradeLevel, int maximumUpgradeLevel)
{
for (int i = 0; i < absoluteMaximumAllocation; i++)
{
PowerAllocator powerAllocator = new PowerAllocator(i, AllocatorStatus.Hidden);
allocators.Add(powerAllocator, null);
}
}
public void ListenForRelayPowerRequests(Relay relay)
{
relay.OnRequestPower += PowerAllocationRequest;
//Setup callbacks to the relay
OnSuccesfulAllocation += relay.ApprovePowerRequest;
OnFailedAllocation += relay.RefusePowerRequest;
}
public void PowerAllocationRequest(object sender, EventArgs e)
{
PowerTransferInfoEventArgs powerTransferInfo = (PowerTransferInfoEventArgs)e;
if (GetAvailablePowerCell() != null)
{
AllocateTo(powerTransferInfo.Subsystem);
if (OnSuccesfulAllocation != null)
OnSuccesfulAllocation(this, powerTransferInfo);
}
else
{
if (OnFailedAllocation != null)
OnFailedAllocation(this, powerTransferInfo);
}
}
public void IncreaseWarpCoreAllocationPotential()
{
foreach (KeyValuePair<PowerAllocator, Subsystem> allocationSet in allocators)
{
if (allocationSet.Key.AllocatorStatus == AllocatorStatus.Hidden)
allocationSet.Key.SetStatus(AllocatorStatus.Unused);
}
maximumAllocators++;
}
public void AllocateTo(Subsystem subsystem)
{
PowerAllocator allocation = GetAvailablePowerCell();
allocators[allocation] = subsystem;
allocation.SetStatus(AllocatorStatus.Used);
}
// TODO: Add deallocation methods
}