mirror of
https://github.com/tobspr/shapez.io.git
synced 2026-03-02 03:39:21 +00:00
Support dynamic tick rates
This commit is contained in:
@@ -109,78 +109,98 @@ export class BeltSystem extends GameSystemWithFilter {
|
||||
this.forEachMatchingEntityOnScreen(parameters, this.drawEntityItems.bind(this));
|
||||
}
|
||||
|
||||
update() {
|
||||
/**
|
||||
* Updates a given entity
|
||||
* @param {Entity} entity
|
||||
* @param {Set} processedEntities
|
||||
*/
|
||||
updateBelt(entity, processedEntities) {
|
||||
if (processedEntities.has(entity.uid)) {
|
||||
return;
|
||||
}
|
||||
|
||||
processedEntities.add(entity.uid);
|
||||
|
||||
// Divide by item spacing on belts since we use throughput and not speed
|
||||
const beltSpeed =
|
||||
this.root.hubGoals.getBeltBaseSpeed() *
|
||||
globalConfig.physicsDeltaSeconds *
|
||||
this.root.dynamicTickrate.deltaSeconds *
|
||||
globalConfig.itemSpacingOnBelts;
|
||||
const beltComp = entity.components.Belt;
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
const items = beltComp.sortedItems;
|
||||
|
||||
if (items.length === 0) {
|
||||
// Fast out for performance
|
||||
return;
|
||||
}
|
||||
|
||||
const ejectorComp = entity.components.ItemEjector;
|
||||
let maxProgress = 1;
|
||||
|
||||
// When ejecting, we can not go further than the item spacing since it
|
||||
// will be on the corner
|
||||
if (ejectorComp.isAnySlotEjecting()) {
|
||||
maxProgress = 1 - globalConfig.itemSpacingOnBelts;
|
||||
} else {
|
||||
// Find follow up belt to make sure we don't clash items
|
||||
const followUpDirection = staticComp.localDirectionToWorld(beltComp.direction);
|
||||
const followUpVector = enumDirectionToVector[followUpDirection];
|
||||
|
||||
const followUpTile = staticComp.origin.add(followUpVector);
|
||||
const followUpEntity = this.root.map.getTileContent(followUpTile);
|
||||
|
||||
if (followUpEntity) {
|
||||
const followUpBeltComp = followUpEntity.components.Belt;
|
||||
if (followUpBeltComp) {
|
||||
// Update follow up belt first
|
||||
this.updateBelt(followUpEntity, processedEntities);
|
||||
|
||||
const spacingOnBelt = followUpBeltComp.getDistanceToFirstItemCenter();
|
||||
maxProgress = Math_min(1, 1 - globalConfig.itemSpacingOnBelts + spacingOnBelt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let speedMultiplier = 1;
|
||||
if (beltComp.direction !== enumDirection.top) {
|
||||
// Shaped belts are longer, thus being quicker
|
||||
speedMultiplier = 1.41;
|
||||
}
|
||||
|
||||
for (let itemIndex = items.length - 1; itemIndex >= 0; --itemIndex) {
|
||||
const itemAndProgress = items[itemIndex];
|
||||
|
||||
const newProgress = itemAndProgress[0] + speedMultiplier * beltSpeed;
|
||||
if (newProgress >= 1.0) {
|
||||
// Try to give this item to a new belt
|
||||
const freeSlot = ejectorComp.getFirstFreeSlot();
|
||||
|
||||
if (freeSlot === null) {
|
||||
// So, we don't have a free slot - damned!
|
||||
itemAndProgress[0] = 1.0;
|
||||
maxProgress = 1 - globalConfig.itemSpacingOnBelts;
|
||||
} else {
|
||||
// We got a free slot, remove this item and keep it on the ejector slot
|
||||
if (!ejectorComp.tryEject(freeSlot, itemAndProgress[1])) {
|
||||
assert(false, "Ejection failed");
|
||||
}
|
||||
items.splice(itemIndex, 1);
|
||||
maxProgress = 1;
|
||||
}
|
||||
} else {
|
||||
itemAndProgress[0] = Math_min(newProgress, maxProgress);
|
||||
maxProgress = itemAndProgress[0] - globalConfig.itemSpacingOnBelts;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
update() {
|
||||
const processedEntities = new Set();
|
||||
|
||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||
const entity = this.allEntities[i];
|
||||
const beltComp = entity.components.Belt;
|
||||
const staticComp = entity.components.StaticMapEntity;
|
||||
const items = beltComp.sortedItems;
|
||||
if (items.length === 0) {
|
||||
// Fast out for performance
|
||||
continue;
|
||||
}
|
||||
|
||||
const ejectorComp = entity.components.ItemEjector;
|
||||
let maxProgress = 1;
|
||||
|
||||
// When ejecting, we can not go further than the item spacing since it
|
||||
// will be on the corner
|
||||
if (ejectorComp.isAnySlotEjecting()) {
|
||||
maxProgress = 1 - globalConfig.itemSpacingOnBelts;
|
||||
} else {
|
||||
// Find follow up belt to make sure we don't clash items
|
||||
const followUpDirection = staticComp.localDirectionToWorld(beltComp.direction);
|
||||
const followUpVector = enumDirectionToVector[followUpDirection];
|
||||
|
||||
const followUpTile = staticComp.origin.add(followUpVector);
|
||||
const followUpEntity = this.root.map.getTileContent(followUpTile);
|
||||
|
||||
if (followUpEntity) {
|
||||
const followUpBeltComp = followUpEntity.components.Belt;
|
||||
if (followUpBeltComp) {
|
||||
const spacingOnBelt = followUpBeltComp.getDistanceToFirstItemCenter();
|
||||
maxProgress = Math_min(1, 1 - globalConfig.itemSpacingOnBelts + spacingOnBelt);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let speedMultiplier = 1;
|
||||
if (beltComp.direction !== enumDirection.top) {
|
||||
// Shaped belts are longer, thus being quicker
|
||||
speedMultiplier = 1.41;
|
||||
}
|
||||
|
||||
for (let itemIndex = items.length - 1; itemIndex >= 0; --itemIndex) {
|
||||
const itemAndProgress = items[itemIndex];
|
||||
|
||||
const newProgress = itemAndProgress[0] + speedMultiplier * beltSpeed;
|
||||
if (newProgress >= 1.0) {
|
||||
// Try to give this item to a new belt
|
||||
const freeSlot = ejectorComp.getFirstFreeSlot();
|
||||
|
||||
if (freeSlot === null) {
|
||||
// So, we don't have a free slot - damned!
|
||||
itemAndProgress[0] = 1.0;
|
||||
maxProgress = 1 - globalConfig.itemSpacingOnBelts;
|
||||
} else {
|
||||
// We got a free slot, remove this item and keep it on the ejector slot
|
||||
if (!ejectorComp.tryEject(freeSlot, itemAndProgress[1])) {
|
||||
assert(false, "Ejection failed");
|
||||
}
|
||||
items.splice(itemIndex, 1);
|
||||
maxProgress = 1;
|
||||
}
|
||||
} else {
|
||||
itemAndProgress[0] = Math_min(newProgress, maxProgress);
|
||||
maxProgress = itemAndProgress[0] - globalConfig.itemSpacingOnBelts;
|
||||
}
|
||||
}
|
||||
this.updateBelt(entity, processedEntities);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -31,7 +31,7 @@ export class ItemAcceptorSystem extends GameSystemWithFilter {
|
||||
for (let animIndex = 0; animIndex < aceptorComp.itemConsumptionAnimations.length; ++animIndex) {
|
||||
const anim = aceptorComp.itemConsumptionAnimations[animIndex];
|
||||
anim.animProgress +=
|
||||
globalConfig.physicsDeltaSeconds *
|
||||
this.root.dynamicTickrate.deltaSeconds *
|
||||
this.root.hubGoals.getBeltBaseSpeed() *
|
||||
2 *
|
||||
globalConfig.itemSpacingOnBelts;
|
||||
|
||||
@@ -14,7 +14,7 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
||||
|
||||
update() {
|
||||
const effectiveBeltSpeed = this.root.hubGoals.getBeltBaseSpeed() * globalConfig.itemSpacingOnBelts;
|
||||
const progressGrowth = (effectiveBeltSpeed / 0.5) * globalConfig.physicsDeltaSeconds;
|
||||
const progressGrowth = (effectiveBeltSpeed / 0.5) * this.root.dynamicTickrate.deltaSeconds;
|
||||
|
||||
// Try to find acceptors for every ejector
|
||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||
|
||||
@@ -23,7 +23,7 @@ export class ItemProcessorSystem extends GameSystemWithFilter {
|
||||
// First of all, process the current recipe
|
||||
processorComp.secondsUntilEject = Math_max(
|
||||
0,
|
||||
processorComp.secondsUntilEject - globalConfig.physicsDeltaSeconds
|
||||
processorComp.secondsUntilEject - this.root.dynamicTickrate.deltaSeconds
|
||||
);
|
||||
|
||||
// Check if we have any finished items we can eject
|
||||
|
||||
@@ -31,7 +31,7 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
|
||||
// Decrease remaining time of all items in belt
|
||||
for (let k = 0; k < undergroundComp.pendingItems.length; ++k) {
|
||||
const item = undergroundComp.pendingItems[k];
|
||||
item[1] = Math_max(0, item[1] - globalConfig.physicsDeltaSeconds);
|
||||
item[1] = Math_max(0, item[1] - this.root.dynamicTickrate.deltaSeconds);
|
||||
}
|
||||
|
||||
if (undergroundComp.mode === enumUndergroundBeltMode.sender) {
|
||||
|
||||
Reference in New Issue
Block a user