Пример #1
0
    /// <summary>
    ///   Calculates the maximum speed a process can run at in a biome
    ///   based on the environmental compounds.
    /// </summary>
    private static ProcessSpeedInformation CalculateProcessMaximumSpeed(TweakedProcess process,
                                                                        BiomeConditions biome)
    {
        var result = new ProcessSpeedInformation(process.Process);

        float speedFactor = 1.0f;

        // Environmental inputs need to be processed first
        foreach (var entry in process.Process.Inputs)
        {
            if (!entry.Key.IsEnvironmental)
            {
                continue;
            }

            // Environmental compound that can limit the rate

            var input = new ProcessSpeedInformation.EnvironmentalInput(entry.Key, entry.Value);

            var availableInEnvironment = GetDissolvedInBiome(entry.Key, biome);

            input.AvailableAmount = availableInEnvironment;

            // More than needed environment value boosts the effectiveness
            input.AvailableRate = availableInEnvironment / entry.Value;

            speedFactor *= input.AvailableRate;

            result.EnvironmentInputs[entry.Key] = input;
        }

        speedFactor *= process.Rate;

        // So that the speedfactor is available here
        foreach (var entry in process.Process.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            // Normal, cloud input

            var input = new ProcessSpeedInformation.CompoundAmount(entry.Key, entry.Value * speedFactor);

            result.OtherInputs.Add(entry.Key, input);
        }

        foreach (var entry in process.Process.Outputs)
        {
            var output = new ProcessSpeedInformation.CompoundAmount(entry.Key,
                                                                    entry.Value * speedFactor);

            result.Outputs[entry.Key] = output;
        }

        result.SpeedFactor = speedFactor;

        return(result);
    }
Пример #2
0
    public SingleProcessStatistics GetAndMarkUsed(TweakedProcess forProcess)
    {
        if (Processes.ContainsKey(forProcess))
        {
            var result = Processes[forProcess];
            result.Used = true;
            return(result);
        }

        var newEntry = new SingleProcessStatistics(forProcess.Process);

        Processes[forProcess] = newEntry;
        newEntry.Used         = true;
        return(newEntry);
    }
Пример #3
0
    private void RunProcess(float delta, BioProcess processData, CompoundBag bag, TweakedProcess process,
                            SingleProcessStatistics currentProcessStatistics, float inverseDelta)
    {
        // Can your cell do the process
        bool canDoProcess = true;

        // Loop through to make sure you can follow through with your
        // whole process so nothing gets wasted as that would be
        // frustrating.
        float environmentModifier = 1.0f;

        // First check the environmental compounds so that we can build the right environment modifier for accurate
        // check of normal compound input amounts
        foreach (var entry in processData.Inputs)
        {
            // Set used compounds to be useful, we dont want to purge
            // those
            bag.SetUseful(entry.Key);

            if (!entry.Key.IsEnvironmental)
            {
                continue;
            }

            var dissolved = GetDissolved(entry.Key);

            // currentProcessStatistics?.AddInputAmount(entry.Key, entry.Value * inverseDelta);
            currentProcessStatistics?.AddInputAmount(entry.Key, dissolved);

            // do environmental modifier here, and save it for later
            environmentModifier *= dissolved / entry.Value;

            if (environmentModifier <= MathUtils.EPSILON)
            {
                currentProcessStatistics?.AddLimitingFactor(entry.Key);
            }
        }

        if (environmentModifier <= MathUtils.EPSILON)
        {
            canDoProcess = false;
        }

        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * process.Rate * delta;

            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta);

            // currentProcessStatistics?.AddInputAmount(entry.Key, 0);

            // If not enough compound we can't do the process
            if (bag.GetCompoundAmount(entry.Key) < inputRemoved)
            {
                canDoProcess = false;
                currentProcessStatistics?.AddLimitingFactor(entry.Key);
            }
        }

        // Output
        // This is now always looped (even when we can't do the process)
        // because the is useful part is needs to be always be done
        foreach (var entry in processData.Outputs)
        {
            // For now lets assume compounds we produce are also
            // useful
            bag.SetUseful(entry.Key);

            // Apply the general modifiers and
            // apply the environmental modifier
            var outputAdded = entry.Value * process.Rate * delta * environmentModifier;

            currentProcessStatistics?.AddOutputAmount(entry.Key, outputAdded * inverseDelta);

            // currentProcessStatistics?.AddOutputAmount(entry.Key, 0);

            // If no space we can't do the process, and if environmental
            // right now this isn't released anywhere
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            if (bag.GetCompoundAmount(entry.Key) + outputAdded > bag.Capacity)
            {
                canDoProcess = false;
                currentProcessStatistics?.AddCapacityProblem(entry.Key);
            }
        }

        // Only carry out this process if you have all the required
        // ingredients and enough space for the outputs
        if (!canDoProcess)
        {
            return;
        }

        if (currentProcessStatistics != null)
        {
            currentProcessStatistics.CurrentSpeed = process.Rate * environmentModifier;
        }

        // Consume inputs
        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * process.Rate * delta *
                               environmentModifier;

            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta);

            // This should always succeed (due to the earlier check) so
            // it is always assumed here that the process succeeded
            bag.TakeCompound(entry.Key, inputRemoved);
        }

        // Add outputs
        foreach (var entry in processData.Outputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var outputGenerated = entry.Value * process.Rate * delta *
                                  environmentModifier;

            currentProcessStatistics?.AddOutputAmount(entry.Key, outputGenerated * inverseDelta);

            bag.AddCompound(entry.Key, outputGenerated);
        }
    }
Пример #4
0
    private void RunProcess(float delta, BioProcess processData, CompoundBag bag, TweakedProcess process,
                            SingleProcessStatistics currentProcessStatistics, float inverseDelta)
    {
        // Can your cell do the process
        bool canDoProcess = true;

        float environmentModifier = 1.0f;

        // This modifies the process overall speed to allow really fast processes to run, for example if there are
        // a ton of one organelle it might consume 100 glucose per go, which might be unlikely for the cell to have
        // so if there is *some* but not enough space for results (and also inputs) this can run the process as
        // fraction of the speed to allow the cell to still function well
        float spaceConstraintModifier = 1.0f;

        // First check the environmental compounds so that we can build the right environment modifier for accurate
        // check of normal compound input amounts
        foreach (var entry in processData.Inputs)
        {
            // Set used compounds to be useful, we dont want to purge those
            bag.SetUseful(entry.Key);

            if (!entry.Key.IsEnvironmental)
            {
                continue;
            }

            var dissolved = GetDissolved(entry.Key);

            // currentProcessStatistics?.AddInputAmount(entry.Key, entry.Value * inverseDelta);
            currentProcessStatistics?.AddInputAmount(entry.Key, dissolved);

            // do environmental modifier here, and save it for later
            environmentModifier *= dissolved / entry.Value;

            if (environmentModifier <= MathUtils.EPSILON)
            {
                currentProcessStatistics?.AddLimitingFactor(entry.Key);
            }
        }

        if (environmentModifier <= MathUtils.EPSILON)
        {
            canDoProcess = false;
        }

        // Compute spaceConstraintModifier before updating the final use and input amounts
        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * process.Rate * environmentModifier;

            // currentProcessStatistics?.AddInputAmount(entry.Key, 0);
            // We don't multiply by delta here because we report the per-second values anyway. In the actual process
            // output numbers (computed after testing the speed), we need to multiply by inverse delta
            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved);

            inputRemoved = inputRemoved * delta * spaceConstraintModifier;

            // If not enough we can't run the process unless we can lower spaceConstraintModifier enough
            var availableAmount = bag.GetCompoundAmount(entry.Key);
            if (availableAmount < inputRemoved)
            {
                bool canRun = false;

                if (availableAmount > MathUtils.EPSILON)
                {
                    var neededModifier = availableAmount / inputRemoved;

                    if (neededModifier > Constants.MINIMUM_RUNNABLE_PROCESS_FRACTION)
                    {
                        spaceConstraintModifier = neededModifier;
                        canRun = true;

                        // Due to rounding errors there can be very small disparity here between the amount available
                        // and what we will take with the modifiers. See the comment in outputs for more details
                    }
                }

                if (!canRun)
                {
                    canDoProcess = false;
                    currentProcessStatistics?.AddLimitingFactor(entry.Key);
                }
            }
        }

        foreach (var entry in processData.Outputs)
        {
            // For now lets assume compounds we produce are also useful
            bag.SetUseful(entry.Key);

            var outputAdded = entry.Value * process.Rate * environmentModifier;

            // currentProcessStatistics?.AddOutputAmount(entry.Key, 0);
            currentProcessStatistics?.AddOutputAmount(entry.Key, outputAdded);

            outputAdded = outputAdded * delta * spaceConstraintModifier;

            // if environmental right now this isn't released anywhere
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            // If no space we can't do the process, if we can't adjust the space constraint modifier enough
            var remainingSpace = bag.Capacity - bag.GetCompoundAmount(entry.Key);
            if (outputAdded > remainingSpace)
            {
                bool canRun = false;

                if (remainingSpace > MathUtils.EPSILON)
                {
                    var neededModifier = remainingSpace / outputAdded;

                    if (neededModifier > Constants.MINIMUM_RUNNABLE_PROCESS_FRACTION)
                    {
                        spaceConstraintModifier = neededModifier;
                        canRun = true;
                    }

                    // With all of the modifiers we can lose a tiny bit of compound that won't fit due to rounding
                    // errors, but we ignore that here
                }

                if (!canRun)
                {
                    canDoProcess = false;
                    currentProcessStatistics?.AddCapacityProblem(entry.Key);
                }
            }
        }

        // Only carry out this process if you have all the required ingredients and enough space for the outputs
        if (!canDoProcess)
        {
            if (currentProcessStatistics != null)
            {
                currentProcessStatistics.CurrentSpeed = 0;
            }
            return;
        }

        float totalModifier = process.Rate * delta * environmentModifier * spaceConstraintModifier;

        if (currentProcessStatistics != null)
        {
            currentProcessStatistics.CurrentSpeed = process.Rate * environmentModifier * spaceConstraintModifier;
        }

        // Consume inputs
        foreach (var entry in processData.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var inputRemoved = entry.Value * totalModifier;

            currentProcessStatistics?.AddInputAmount(entry.Key, inputRemoved * inverseDelta);

            // This should always succeed (due to the earlier check) so it is always assumed here that this succeeded
            bag.TakeCompound(entry.Key, inputRemoved);
        }

        // Add outputs
        foreach (var entry in processData.Outputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            var outputGenerated = entry.Value * totalModifier;

            currentProcessStatistics?.AddOutputAmount(entry.Key, outputGenerated * inverseDelta);

            bag.AddCompound(entry.Key, outputGenerated);
        }
    }
Пример #5
0
    /// <summary>
    ///   Calculates the maximum speed a process can run at in a biome
    ///   based on the environmental compounds.
    /// </summary>
    private static ProcessSpeedInformation CalculateProcessMaximumSpeed(TweakedProcess process,
                                                                        BiomeConditions biome)
    {
        var result = new ProcessSpeedInformation(process.Process);

        float speedFactor = 1.0f;

        // Environmental inputs need to be processed first
        foreach (var entry in process.Process.Inputs)
        {
            if (!entry.Key.IsEnvironmental)
            {
                continue;
            }

            // Environmental compound that can limit the rate

            var availableInEnvironment = GetDissolvedInBiome(entry.Key, biome);

            var availableRate = availableInEnvironment / entry.Value;

            result.AvailableAmounts[entry.Key] = availableInEnvironment;

            // More than needed environment value boosts the effectiveness
            result.AvailableRates[entry.Key] = availableRate;

            speedFactor *= availableRate;

            result.WritableInputs[entry.Key] = entry.Value;
        }

        speedFactor *= process.Rate;

        // Note that we don't consider storage constraints here so we don't use spaceConstraintModifier calculations

        // So that the speed factor is available here
        foreach (var entry in process.Process.Inputs)
        {
            if (entry.Key.IsEnvironmental)
            {
                continue;
            }

            // Normal, cloud input

            result.WritableInputs.Add(entry.Key, entry.Value * speedFactor);
        }

        foreach (var entry in process.Process.Outputs)
        {
            var amount = entry.Value * speedFactor;

            result.WritableOutputs[entry.Key] = amount;

            if (amount <= 0)
            {
                result.WritableLimitingCompounds.Add(entry.Key);
            }
        }

        result.CurrentSpeed = speedFactor;

        return(result);
    }