/// <summary> /// Recomputes power distribution in subset of all priority groups (in range /// from startPriorityIdx until the end). Passing index 0 recomputes all priority groups. /// </summary> private static MyResourceStateEnum RecomputeResourceDistributionPartial( ref MyDefinitionId typeId, int startPriorityIdx, MySinkGroupData[] sinkDataByPriority, MySourceGroupData[] sourceDataByPriority, ref MyTuple<MySinkGroupData, MySourceGroupData> sinkSourceData, HashSet<MyResourceSinkComponent>[] sinksByPriority, HashSet<MyResourceSourceComponent>[] sourcesByPriority, List<MyTuple<MyResourceSinkComponent, MyResourceSourceComponent>> sinkSourcePairs, List<int> stockpilingStorageList, List<int> otherStorageList, float availableResource) { ProfilerShort.Begin("MyResourceDistributor.RecomputeResourceDistributionPartial"); ProfilerShort.Begin("Non-zero inputs"); float totalAvailableResource = availableResource; int sinkPriorityIndex = startPriorityIdx; // Distribute power over the sinks by priority for (; sinkPriorityIndex < sinksByPriority.Length; ++sinkPriorityIndex) { sinkDataByPriority[sinkPriorityIndex].RemainingAvailableResource = availableResource; if (sinkDataByPriority[sinkPriorityIndex].RequiredInput <= availableResource) { // Run everything in the group at max. availableResource -= sinkDataByPriority[sinkPriorityIndex].RequiredInput; foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex]) sink.SetInputFromDistributor(typeId, sink.RequiredInputByType(typeId), sinkDataByPriority[sinkPriorityIndex].IsAdaptible); } else if (sinkDataByPriority[sinkPriorityIndex].IsAdaptible && availableResource > 0.0f) { // Distribute power in this group based on ratio of its requirement vs. group requirement. foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex]) { float ratio = sink.RequiredInputByType(typeId) / sinkDataByPriority[sinkPriorityIndex].RequiredInput; sink.SetInputFromDistributor(typeId, ratio * availableResource, true); } availableResource = 0.0f; } else { // Not enough power for this group and members can't adapt. // None of the lower priority groups will get any power either. foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex]) sink.SetInputFromDistributor(typeId, 0.0f, sinkDataByPriority[sinkPriorityIndex].IsAdaptible); sinkDataByPriority[sinkPriorityIndex].RemainingAvailableResource = availableResource; ++sinkPriorityIndex; // move on to next group break; } } ProfilerShort.End(); ProfilerShort.Begin("Zero inputs"); // Set remaining data. for (; sinkPriorityIndex < sinkDataByPriority.Length; ++sinkPriorityIndex) { sinkDataByPriority[sinkPriorityIndex].RemainingAvailableResource = 0.0f; foreach (MyResourceSinkComponent sink in sinksByPriority[sinkPriorityIndex]) sink.SetInputFromDistributor(typeId, 0.0f, sinkDataByPriority[sinkPriorityIndex].IsAdaptible); } ProfilerShort.End(); float consumptionForNonStorage = totalAvailableResource - availableResource + (startPriorityIdx != 0 ? sinkDataByPriority[0].RemainingAvailableResource - sinkDataByPriority[startPriorityIdx].RemainingAvailableResource : 0f); // Distribute remaining energy over stockpiling storage float totalAvailableResourcesForStockpiles = Math.Max(totalAvailableResource - consumptionForNonStorage, 0); float availableResourcesForStockpiles = totalAvailableResourcesForStockpiles; if (stockpilingStorageList.Count > 0) { ProfilerShort.Begin("Stockpiles"); float stockpilesRequiredInput = sinkSourceData.Item1.RequiredInputCumulative; if (stockpilesRequiredInput <= availableResourcesForStockpiles) { availableResourcesForStockpiles -= stockpilesRequiredInput; //ToArray = Hotfix for collection modified exception foreach (int pairIndex in stockpilingStorageList.ToArray()) { var sink = sinkSourcePairs[pairIndex].Item1; sink.SetInputFromDistributor(typeId, sink.RequiredInputByType(typeId), true); } sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStockpiles; } else { //ToArray = Hotfix for collection modified exception foreach (int pairIndex in stockpilingStorageList.ToArray()) { var sink = sinkSourcePairs[pairIndex].Item1; float ratio = sink.RequiredInputByType(typeId) / stockpilesRequiredInput; sink.SetInputFromDistributor(typeId, ratio * totalAvailableResourcesForStockpiles, true); } availableResourcesForStockpiles = 0f; sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStockpiles; } ProfilerShort.End(); } // Distribute remaining power over non-stockpiling storage float consumptionForStockpiles = totalAvailableResourcesForStockpiles - availableResourcesForStockpiles; float totalAvailableResourcesForStorage = Math.Max(totalAvailableResource - (sinkSourceData.Item2.MaxAvailableResource - sinkSourceData.Item2.MaxAvailableResource * sinkSourceData.Item2.UsageRatio) - consumptionForNonStorage - consumptionForStockpiles, 0); float availableResourcesForStorage = totalAvailableResourcesForStorage; if (otherStorageList.Count > 0) { ProfilerShort.Begin("Non-stockpiling storage"); float ordinaryStorageRequiredInput = sinkSourceData.Item1.RequiredInput - sinkSourceData.Item1.RequiredInputCumulative; if (ordinaryStorageRequiredInput <= availableResourcesForStorage) { availableResourcesForStorage -= ordinaryStorageRequiredInput; foreach (int pairIndex in otherStorageList) { var sink = sinkSourcePairs[pairIndex].Item1; sink.SetInputFromDistributor(typeId, sink.RequiredInputByType(typeId), true); } sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStorage; } else { foreach (int pairIndex in otherStorageList) { var sink = sinkSourcePairs[pairIndex].Item1; float ratio = sink.RequiredInputByType(typeId) / ordinaryStorageRequiredInput; sink.SetInputFromDistributor(typeId, ratio * availableResourcesForStorage, true); } availableResourcesForStorage = 0f; sinkSourceData.Item1.RemainingAvailableResource = availableResourcesForStorage; } ProfilerShort.End(); } ProfilerShort.Begin("Sources"); float consumptionForStorage = totalAvailableResourcesForStorage - availableResourcesForStorage; float consumptionForNonStorageAndStockpiles = consumptionForStockpiles + consumptionForNonStorage; if (sinkSourceData.Item2.MaxAvailableResource > 0) { float amountToSupply = consumptionForNonStorageAndStockpiles; sinkSourceData.Item2.UsageRatio = Math.Min(1f, amountToSupply/sinkSourceData.Item2.MaxAvailableResource); consumptionForNonStorageAndStockpiles -= Math.Min(amountToSupply, sinkSourceData.Item2.MaxAvailableResource); } else sinkSourceData.Item2.UsageRatio = 0f; sinkSourceData.Item2.ActiveCount = 0; foreach (int pairIndex in otherStorageList) { var source = sinkSourcePairs[pairIndex].Item2; if (!source.Enabled || !source.ProductionEnabledByType(typeId) || !source.HasCapacityRemainingByType(typeId)) continue; ++sinkSourceData.Item2.ActiveCount; ProfilerShort.Begin("Set CurrentOutput"); source.SetOutputByType(typeId, sinkSourceData.Item2.UsageRatio * source.MaxOutputByType(typeId)); ProfilerShort.End(); } int sourcePriorityIndex = 0; float totalRemainingConsumption = consumptionForNonStorageAndStockpiles + consumptionForStorage; for (; sourcePriorityIndex < sourcesByPriority.Length; ++sourcePriorityIndex) { if (sourceDataByPriority[sourcePriorityIndex].MaxAvailableResource > 0f) { float amountToSupply = Math.Max(totalRemainingConsumption, 0f); sourceDataByPriority[sourcePriorityIndex].UsageRatio = Math.Min(1f, amountToSupply/sourceDataByPriority[sourcePriorityIndex].MaxAvailableResource); totalRemainingConsumption -= Math.Min(amountToSupply, sourceDataByPriority[sourcePriorityIndex].MaxAvailableResource); } else sourceDataByPriority[sourcePriorityIndex].UsageRatio = 0f; sourceDataByPriority[sourcePriorityIndex].ActiveCount = 0; foreach (MyResourceSourceComponent source in sourcesByPriority[sourcePriorityIndex]) { if (!source.Enabled || !source.HasCapacityRemainingByType(typeId)) continue; ++sourceDataByPriority[sourcePriorityIndex].ActiveCount; ProfilerShort.Begin("Set CurrentOutput"); source.SetOutputByType(typeId, sourceDataByPriority[sourcePriorityIndex].UsageRatio * source.MaxOutputByType(typeId)); ProfilerShort.End(); } } MyResourceStateEnum resultState; if (totalAvailableResource == 0.0f) resultState = MyResourceStateEnum.NoPower; else if (sinkDataByPriority[m_sinkGroupPrioritiesTotal - 1].RequiredInputCumulative > totalAvailableResource) { MySinkGroupData lastGroup = sinkDataByPriority.Last(); if (lastGroup.IsAdaptible && lastGroup.RemainingAvailableResource != 0.0f) resultState = MyResourceStateEnum.OverloadAdaptible; else resultState = MyResourceStateEnum.OverloadBlackout; } else resultState = MyResourceStateEnum.Ok; ProfilerShort.End(); ProfilerShort.End(); return resultState; }
private void InitializeNewType(ref MyDefinitionId typeId) { m_typeIdToIndex.Add(typeId, m_typeGroupCount++); m_typeIdToConveyorConnectionRequired.Add(typeId, IsConveyorConnectionRequiredTotal(ref typeId)); var sinksByPriority = new HashSet<MyResourceSinkComponent>[m_sinkGroupPrioritiesTotal]; var sourceByPriority = new HashSet<MyResourceSourceComponent>[m_sourceGroupPrioritiesTotal]; var inputOutputList = new List<MyTuple<MyResourceSinkComponent, MyResourceSourceComponent>>(); for (int priorityIndex = 0; priorityIndex < sinksByPriority.Length; ++priorityIndex) sinksByPriority[priorityIndex] = new HashSet<MyResourceSinkComponent>(); for (int priorityIndex = 0; priorityIndex < sourceByPriority.Length; ++priorityIndex) sourceByPriority[priorityIndex] = new HashSet<MyResourceSourceComponent>(); List<MyPhysicalDistributionGroup> distributionGroups = null; int distributionGroupsInUse = 0; MySinkGroupData[] sinkGroupDataByPriority = null; MySourceGroupData[] sourceGroupDatabyPriority = null; List<int> stockpilingStorageIndices = null; List<int> otherStorageIndices = null; if (IsConveyorConnectionRequired(ref typeId)) { distributionGroups = new List<MyPhysicalDistributionGroup>(); } else { sinkGroupDataByPriority = new MySinkGroupData[m_sinkGroupPrioritiesTotal]; sourceGroupDatabyPriority = new MySourceGroupData[m_sourceGroupPrioritiesTotal]; stockpilingStorageIndices = new List<int>(); otherStorageIndices = new List<int>(); } m_dataPerType.Add(new PerTypeData { SinkDataByPriority = sinkGroupDataByPriority, SourceDataByPriority = sourceGroupDatabyPriority, InputOutputData = new MyTuple<MySinkGroupData, MySourceGroupData>(), SinksByPriority = sinksByPriority, SourcesByPriority = sourceByPriority, InputOutputList = inputOutputList, StockpilingStorageIndices = stockpilingStorageIndices, OtherStorageIndices = otherStorageIndices, DistributionGroups = distributionGroups, DistributionGroupsInUse = distributionGroupsInUse, NeedsRecompute = true, GroupsDirty = true, SourceCount = 0, RemainingFuelTime = 0, RemainingFuelTimeDirty = true, LastFuelTimeCompute = 0, MaxAvailableResource = 0, SourcesEnabled = MyMultipleEnabledEnum.NoObjects, SourcesEnabledDirty = true, ResourceState = MyResourceStateEnum.NoPower, }); m_initializedTypes.Add(typeId); }
private static void ComputeInitialDistributionData( ref MyDefinitionId typeId, MySinkGroupData[] sinkDataByPriority, MySourceGroupData[] sourceDataByPriority, ref MyTuple<MySinkGroupData, MySourceGroupData> sinkSourceData, HashSet<MyResourceSinkComponent>[] sinksByPriority, HashSet<MyResourceSourceComponent>[] sourcesByPriority, List<MyTuple<MyResourceSinkComponent, MyResourceSourceComponent>> sinkSourcePairs, List<int> stockpilingStorageList, List<int> otherStorageList, out float maxAvailableResource) { // Clear state of all sources and sinks. Also find out how // much of resource is available for distribution. maxAvailableResource = 0.0f; Debug.Assert(sourceDataByPriority.Length == sourcesByPriority.Length); for (int i = 0; i < sourceDataByPriority.Length; ++i) { var resourceSources = sourcesByPriority[i]; MySourceGroupData sourceGroupData = sourceDataByPriority[i]; sourceGroupData.MaxAvailableResource = 0f; foreach (MyResourceSourceComponent source in resourceSources) { if (!source.Enabled || !source.HasCapacityRemainingByType(typeId)) continue; sourceGroupData.MaxAvailableResource += source.MaxOutputByType(typeId); sourceGroupData.InfiniteCapacity = source.IsInfiniteCapacity; } maxAvailableResource += sourceGroupData.MaxAvailableResource; sourceDataByPriority[i] = sourceGroupData; } float requiredInputCumulative = 0.0f; for (int i = 0; i < sinksByPriority.Length; ++i) { float requiredInput = 0.0f; bool isAdaptible = true; foreach (MyResourceSinkComponent sink in sinksByPriority[i]) { requiredInput += sink.RequiredInputByType(typeId); isAdaptible = isAdaptible && IsAdaptible(sink); } sinkDataByPriority[i].RequiredInput = requiredInput; sinkDataByPriority[i].IsAdaptible = isAdaptible; requiredInputCumulative += requiredInput; sinkDataByPriority[i].RequiredInputCumulative = requiredInputCumulative; } PrepareSinkSourceData(ref typeId, ref sinkSourceData, sinkSourcePairs, stockpilingStorageList, otherStorageList); maxAvailableResource += sinkSourceData.Item2.MaxAvailableResource; }