20 const int DEFAULT_MAX_BUDGET = 100;
21 const int DEFAULT_MIN_COST = 1;
24 protected ref array<ref SCR_EntityBudgetValue> m_MaxBudgets;
29 protected ref map<EEditableEntityBudget, SCR_EditableEntityCoreBudgetSetting> m_BudgetSettingsMap =
new map<EEditableEntityBudget, SCR_EditableEntityCoreBudgetSetting>;
34 ref ScriptInvoker Event_OnBudgetPreviewUpdated =
new ScriptInvoker();
35 ref ScriptInvoker Event_OnBudgetPreviewReset =
new ScriptInvoker();
38 protected ref map<EEditableEntityBudget, int> m_DelayedSetMaxBudgetsMap =
new map<EEditableEntityBudget, int>();
39 protected bool m_bListenToMaxBudgetDelay =
false;
49 array<ref SCR_EntityBudgetValue> budgetCosts = {};
50 return CanPlaceEntityInfo(info, budgetCosts, blockingBudget, showNotification);
62 if (!IsBudgetCapEnabled())
65 bool canPlace =
false;
66 if (GetEntityPreviewBudgetCosts(info, budgetCosts))
67 canPlace = CanPlace(budgetCosts, blockingBudget);
69 canPlace = CanPlaceEntityType(info.GetEntityType(), budgetCosts, blockingBudget);
72 CanPlaceResult(canPlace, showNotification);
85 bool CanPlaceEntitySource(IEntityComponentSource editableEntitySource, out
EEditableEntityBudget blockingBudget,
bool isPlacingPlayer =
false,
bool updatePreview =
true,
bool showNotification =
true)
88 if (editableEntitySource && IsBudgetCapEnabled())
90 array<ref SCR_EntityBudgetValue> budgetCosts = {};
91 if (!GetEntitySourcePreviewBudgetCosts(editableEntitySource, budgetCosts))
100 UpdatePreviewCost(budgetCosts);
102 canPlace = canPlace && CanPlace(budgetCosts, blockingBudget);
104 return CanPlaceResult(canPlace, showNotification);
115 if (!IsBudgetCapEnabled())
118 GetEntityTypeBudgetCost(entityType, budgetCosts);
119 return CanPlace(budgetCosts, blockingBudget);
127 bool CanPlace(notnull array<ref SCR_EntityBudgetValue> budgetCosts, out
EEditableEntityBudget blockingBudget)
129 if (!IsBudgetCapEnabled() || budgetCosts.IsEmpty())
134 if (!CanPlace(budgetCost, blockingBudget))
145 if (!GetMaxBudgetValue(budgetType, maxBudgetValue))
148 int originalBudgetValue = GetCurrentBudgetValue(budgetType);
149 int budgetChange = budgetCost.GetBudgetValue();
150 if (!CanPlace(originalBudgetValue, budgetChange, maxBudgetValue))
152 blockingBudget = budgetType;
162 protected bool CanPlace(
int currentBudget,
int budgetChange,
int maxBudget)
164 return currentBudget + budgetChange <= maxBudget;
171 bool GetEntityPreviewBudgetCosts(
SCR_EditableEntityUIInfo entityUIInfo, out notnull array<ref SCR_EntityBudgetValue> budgetCosts)
176 if (!entityUIInfo.GetEntityBudgetCost(budgetCosts))
177 GetEntityTypeBudgetCost(entityUIInfo.GetEntityType(), budgetCosts);
179 array<ref SCR_EntityBudgetValue> entityChildrenBudgetCosts = {};
180 entityUIInfo.GetEntityChildrenBudgetCost(entityChildrenBudgetCosts);
184 FilterAvailableBudgets(budgetCosts);
193 bool GetEntitySourcePreviewBudgetCosts(IEntityComponentSource editableEntitySource, out notnull array<ref SCR_EntityBudgetValue> budgetCosts)
195 if (!editableEntitySource)
200 return GetEntityPreviewBudgetCosts(editableUIInfo, budgetCosts);
212 bool GetVehicleOccupiedBudgetCosts(IEntityComponentSource editableEntitySource,
EEditorPlacingFlags placingFlags, out notnull array<ref SCR_EntityBudgetValue> budgetCosts,
bool includeVehicleCost =
true)
214 if (includeVehicleCost && !GetEntitySourcePreviewBudgetCosts(editableEntitySource, budgetCosts))
218 return GetVehicleOccupiedBudgetCosts(editableUIInfo, placingFlags, budgetCosts);
231 array<ref SCR_EntityBudgetValue> vehicleOccupantsBudgetCosts = {};
235 editableUIInfo.GetFillBudgetCostsOfCrew(vehicleOccupantsBudgetCosts);
241 editableUIInfo.GetFillBudgetCostsOfPassengers(vehicleOccupantsBudgetCosts);
251 void UpdatePreviewCost(notnull array<ref SCR_EntityBudgetValue> budgetCosts)
257 int budgetValue = budgetCost.GetBudgetValue();
259 if (!GetMaxBudgetValue(budgetType, maxBudget))
262 float max = maxBudget;
264 int currentBudget = GetCurrentBudgetValue(budgetType);
265 float newBudgetPercent;
270 float currentBudgetPercent = currentBudget / max * 100;
271 int newBudget = currentBudget + budgetValue;
273 newBudgetPercent = newBudget / max * 100;
275 budgetChange = newBudgetPercent - currentBudgetPercent;
279 newBudgetPercent = 100;
283 Event_OnBudgetPreviewUpdated.Invoke(budgetType, newBudgetPercent, budgetChange);
289 void ResetPreviewCost()
291 Event_OnBudgetPreviewReset.Invoke();
298 return GetMaxBudget(
type, budget);
306 if (maxBudget.GetBudgetType() ==
type)
323 if (GetMaxBudget(
type, budgetValue))
325 maxBudget = budgetValue.GetBudgetValue();
339 if (GetMaxBudget(
type, maxBudget))
341 oldValue = maxBudget.GetBudgetValue();
342 maxBudget.SetBudgetValue(newValue);
344 Rpc(UpdateMaxBudgetOwner,
type, oldValue, newValue);
354 m_DelayedSetMaxBudgetsMap.Insert(
type, newValue);
356 if (!m_bListenToMaxBudgetDelay)
358 m_bListenToMaxBudgetDelay =
true;
359 GetGame().GetCallqueue().CallLater(DelayedSetMaxBudget, 100,
false, playerChangingBudget);
364 protected void DelayedSetMaxBudget(
int playerChangingBudget)
366 m_bListenToMaxBudgetDelay =
false;
367 SetMultiMaxBudgetValues(m_DelayedSetMaxBudgetsMap, playerChangingBudget);
368 m_DelayedSetMaxBudgetsMap.Clear();
374 void SetMultiMaxBudgetValues(notnull map<EEditableEntityBudget, int> budgets,
int playerChangingBudget)
378 SetMaxBudgetValue(
type, budget);
386 void GetEntityTypeBudgetCost(
EEditableEntityType entityType, out array<ref SCR_EntityBudgetValue> budgetCosts)
389 int minBudgetCost = GetEntityTypeBudgetCost(entityBudgetType);
400 return budgetSettings.GetMinBudgetCost();
402 return DEFAULT_MIN_COST;
412 if (!GetCurrentBudgetSettings(
type, budgetSettings))
415 return budgetSettings.GetCurrentBudget() + budgetSettings.GetReservedBudget();
424 int originalBudgetValue, budgetChange, maxBudgetValue;
426 if (GetCurrentBudgetSettings(budgetType, budgetSettings) && GetMaxBudgetValue(budgetType, maxBudgetValue))
428 originalBudgetValue = budgetSettings.GetCurrentBudget();
429 budgetChange = budgetSettings.SetCurrentBudget(value);
431 if (budgetChange != value - originalBudgetValue)
434 bool budgetMaxReached;
435 bool sendBudgetMaxEvent = CheckMaxBudgetReached(budgetType, budgetChange, originalBudgetValue, value, maxBudgetValue, budgetMaxReached);
437 Rpc(OnEntityCoreBudgetUpdatedOwner, budgetType, value, budgetChange, sendBudgetMaxEvent, budgetMaxReached);
449 if (GetCurrentBudgetSettings(budgetType, budgetSettings))
451 blockingBudgetInfo = budgetSettings.GetInfo();
459 void GetBudgets(out notnull array<ref SCR_EditableEntityCoreBudgetSetting> budgets)
463 budgets.Insert(setting);
470 return m_BudgetSettingsMap.Find(budgetType, budgetSettings);
475 protected void RefreshBudgetSettings()
477 m_BudgetSettingsMap.Clear();
482 array<ref SCR_EditableEntityCoreBudgetSetting> outBudgets = {};
486 for (
int i = outBudgets.Count() - 1; i >= 0; i--)
488 budget = outBudgets[i];
491 if (GetMaxBudgetValue(budgetType, maxBudget))
493 m_BudgetSettingsMap.Insert(budgetType, budget);
494 int currentBudgetValue = budget.GetCurrentBudget();
495 Event_OnBudgetUpdated.Invoke(budgetType, currentBudgetValue, currentBudgetValue, maxBudget);
496 Event_OnBudgetMaxUpdated.Invoke(budgetType, currentBudgetValue, maxBudget);
500 outBudgets.RemoveOrdered(i);
506 [
RplRpc(RplChannel.Reliable, RplRcver.Owner)]
507 protected void UpdateMaxBudgetOwner(
int budgetType,
int oldMaxBudget,
int newMaxBudget)
509 if (DiagMenu.GetBool(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_LOG_BUDGET_CHANGES))
510 Print(
string.Format(
"Updated maximum budget received for type %1: %2", budgetType, newMaxBudget), LogLevel.NORMAL);
513 if (GetMaxBudget(budgetType, maxBudget))
514 maxBudget.SetBudgetValue(newMaxBudget);
516 int currentBudget = GetCurrentBudgetValue(budgetType);
518 if (oldMaxBudget == 0 || (currentBudget > oldMaxBudget && currentBudget < newMaxBudget))
519 Event_OnBudgetMaxReached.Invoke(budgetType,
false);
520 else if (newMaxBudget == 0 || (currentBudget < oldMaxBudget && currentBudget > newMaxBudget))
521 Event_OnBudgetMaxReached.Invoke(budgetType,
true);
523 Event_OnBudgetMaxUpdated.Invoke(budgetType, currentBudget, newMaxBudget);
527 protected bool CanPlaceResult(
bool canPlace,
bool showNotification)
529 if (showNotification)
530 Rpc(CanPlaceOwner, canPlace);
536 [
RplRpc(RplChannel.Reliable, RplRcver.Owner)]
537 protected void CanPlaceOwner(
bool canPlace)
541 GetManager().SendNotification(
ENotification.EDITOR_PLACING_BUDGET_MAX);
550 if (!GetMaxBudgetValue(entityBudget, maxBudgetValue))
553 bool budgetMaxReached;
554 bool sendBudgetMaxEvent = CheckMaxBudgetReached(entityBudget, budgetChange, originalBudgetValue, updatedBudgetValue, maxBudgetValue, budgetMaxReached);
556 Rpc(OnEntityCoreBudgetUpdatedOwner, entityBudget, updatedBudgetValue, budgetChange, sendBudgetMaxEvent, budgetMaxReached);
560 [
RplRpc(RplChannel.Reliable, RplRcver.Owner)]
561 protected void OnEntityCoreBudgetUpdatedOwner(
EEditableEntityBudget entityBudget,
int budgetValue,
int budgetChange,
bool sendBudgetMaxEvent,
bool budgetMaxReached)
563 if (DiagMenu.GetBool(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_LOG_BUDGET_CHANGES))
564 Print(
string.Format(
"Updated budget received for type %1: %2", entityBudget, budgetValue), LogLevel.NORMAL);
568 if (GetCurrentBudgetSettings(entityBudget, budgetSettings) && GetMaxBudgetValue(entityBudget, maxBudget))
570 int currentBudget = budgetSettings.GetCurrentBudget();
571 int ownerBudgetChange = budgetSettings.SetCurrentBudget(budgetValue);
573 Event_OnBudgetUpdated.Invoke(entityBudget, currentBudget, budgetValue, maxBudget);
575 if (sendBudgetMaxEvent)
576 Event_OnBudgetMaxReached.Invoke(entityBudget, budgetMaxReached);
581 protected bool CheckMaxBudgetReached(
EEditableEntityBudget entityBudget,
int budgetChange,
int originalBudgetValue,
int updatedBudgetValue,
int maxBudgetValue, out
bool maxBudgetReached)
583 if (budgetChange >= 0 && originalBudgetValue + budgetChange >= maxBudgetValue)
586 maxBudgetReached =
true;
589 else if (budgetChange < 0 && updatedBudgetValue < maxBudgetValue)
592 if (originalBudgetValue >= maxBudgetValue * 0.9)
594 maxBudgetReached =
false;
603 protected void FilterAvailableBudgets(inout notnull array<ref SCR_EntityBudgetValue> budgetCosts)
606 for (
int i = budgetCosts.Count() - 1; i >= 0; i--)
608 budget = budgetCosts[i];
609 if (!IsBudgetAvailable(budget.GetBudgetType()))
610 budgetCosts.Remove(i);
619 return m_BudgetSettingsMap.Get(budgetType);
625 if (!m_MaxBudgets || m_MaxBudgets.IsEmpty())
628 return m_MaxBudgets[0].GetBudgetType();;
633 void DemandBudgetUpdateFromServer()
641 Rpc(RpcServer_UpdateBudget);
646 [
RplRpc(RplChannel.Reliable, RplRcver.Server)]
647 void RpcServer_UpdateBudget()
649 array<ref SCR_EditableEntityCoreBudgetSetting> outBudgets = {};
654 Rpc(RpcOwner_UpdateBudget, budgetSetting.GetBudgetType(), budgetSetting.GetCurrentBudget());
662 [
RplRpc(RplChannel.Reliable, RplRcver.Owner)]
666 if (!m_BudgetSettingsMap.Find(budgetType, budget))
669 budget.SetCurrentBudget(currentBudget);
672 if (GetMaxBudgetValue(budgetType, maxBudget))
674 m_BudgetSettingsMap.Insert(budgetType, budget);
675 int currentBudgetValue = budget.GetCurrentBudget();
676 Event_OnBudgetUpdated.Invoke(budgetType, currentBudgetValue, currentBudgetValue, maxBudget);
677 Event_OnBudgetMaxUpdated.Invoke(budgetType, currentBudgetValue, maxBudget);
682 protected bool IsBudgetCapEnabled()
685 return DiagMenu.GetBool(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_BUDGET_CAP);
692 override protected void EOnEditorDebug(array<string> debugTexts)
697 GetMaxBudget(
type, maxBudget);
698 debugTexts.Insert(
string.Format(
"%1: %2 / %3",
typename.EnumToString(
EEditableEntityBudget,
type), budgetSettings.GetCurrentBudget(), maxBudget.GetBudgetValue()));
703 protected override void EOnEditorInitServer()
706 m_EntityCore.Event_OnEntityBudgetUpdated.Insert(OnEntityCoreBudgetUpdated);
710 protected override void EOnEditorDeleteServer()
713 m_EntityCore.Event_OnEntityBudgetUpdated.Remove(OnEntityCoreBudgetUpdated);
720 protected override void EOnEditorActivate()
729 RefreshBudgetSettings();
732 Rpc(RpcServer_UpdateBudget);
736 protected override void EOnEditorInit()
741 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_LOG_BUDGET_CHANGES,
"",
"Log Budget Changes",
"Editable Entities");
742 DiagMenu.RegisterBool(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_BUDGET_CAP,
"",
"Enable Budget Cap",
"Editable Entities");
743 DiagMenu.SetValue(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_BUDGET_CAP, 1);
748 budgetSetting.SetBudgetComponent(
this);
757 DiagMenu.Unregister(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_LOG_BUDGET_CHANGES);
758 DiagMenu.Unregister(
SCR_DebugMenuID.DEBUGUI_EDITOR_ENTITIES_BUDGET_CAP);