src/utils/throttle.ts
declare global {
interface Memory {
throttleInfo: {
bucket: {
normal: number;
warning: number;
critical: number;
};
};
}
interface CreepHeapMemory {
_tO?: number;
}
}
const throttleNumbers = [];
let throttleOffset = 0;
/**
* Choose whether an operation should currently run based on priorities.
*
* @param {number} offset
* Offset to add to time, so not all operations get throttled on the same tick.
* @param {number} minBucket
* Minimum amount of bucket needed for this operation to run.
* @param {number} maxBucket
* Amount of bucket at which this operation should always run.
*
* @return {boolean}
* True if the operation is allowed to run.
*/
function throttle(offset: number, minBucket?: number, maxBucket?: number) {
initThrottleMemory();
if (!offset) offset = 0;
if (typeof minBucket !== 'number') minBucket = Memory.throttleInfo.bucket.critical;
if (typeof maxBucket !== 'number') maxBucket = Memory.throttleInfo.bucket.normal;
const bucket = Game.cpu.bucket;
if (bucket >= maxBucket) return false;
if (bucket < minBucket) return true;
const tick = (Game.time + offset) % throttleNumbers.length;
const ratio = (bucket - minBucket) / (maxBucket - minBucket);
if (ratio >= throttleNumbers[tick]) return false;
return true;
}
/**
* Gets a new offset for a throttled operation.
*
* @return {number}
* Offset to store for a throttled operation.
*/
function getThrottleOffset(): number {
return throttleOffset++;
}
/**
* Initializes memory with general throttling information.
*/
function initThrottleMemory(): void {
if (!Memory.throttleInfo) {
Memory.throttleInfo = {
bucket: {
normal: 8000,
warning: 5000,
critical: 2000,
},
};
}
if (throttleNumbers.length === 0) {
const sequence = generateEvenSequence(8, 2);
const max = sequence[0];
_.each(sequence, (number, index) => {
throttleNumbers[index] = 1 - (number / max);
});
throttleNumbers[0] = 1;
}
}
/**
* Generates a Van der Corput sequence.
*
* @param {number} power
* Number of "digits" relative to base to generate a sequence for.
* @param {number} base
* Base for the sequence. Detemines spacing of the sequence.
*
* @return {number[]}
* The generated sequence, containing all numbers from 1 to base^power.
*/
function generateEvenSequence(power: number, base: number): number[] {
const numbers: number[] = [];
const digits: number[] = [];
for (let i = 0; i < power; i++) {
digits[i] = 0;
}
function increase(digit: number) {
if (digit >= power) return;
digits[digit]++;
if (digits[digit] >= base) {
digits[digit] = 0;
increase(digit + 1);
}
}
function getNumber() {
let sum = 0;
for (let i = 0; i < power; i++) {
sum *= base;
sum += digits[i];
}
return sum;
}
increase(0);
let number = getNumber();
const max = number * base;
numbers.push(max);
while (number !== 0) {
numbers.push(number);
increase(0);
number = getNumber();
}
return numbers;
}
export {
throttle,
getThrottleOffset,
};