mirror of
https://github.com/tobspr/shapez.io.git
synced 2025-06-13 13:04:03 +00:00
Performance optimizations (#1154)
* 1.3.1 preparations * Minor fixes, update translations * Fix achievements not working * Lots of belt optimizations, ~15% performance boost
This commit is contained in:
parent
fa25deb761
commit
3318d869b3
@ -74,20 +74,8 @@ function createWindow() {
|
|||||||
win.on("closed", () => {
|
win.on("closed", () => {
|
||||||
console.log("Window closed");
|
console.log("Window closed");
|
||||||
win = null;
|
win = null;
|
||||||
app.quit();
|
|
||||||
});
|
});
|
||||||
|
|
||||||
function handleWindowBeforeunload(event) {
|
|
||||||
const confirmed = dialog.showMessageBox(remote.getCurrentWindow(), options) === 1;
|
|
||||||
if (confirmed) {
|
|
||||||
remote.getCurrentWindow().close();
|
|
||||||
} else {
|
|
||||||
event.returnValue = false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
win.on("", handleWindowBeforeunload);
|
|
||||||
|
|
||||||
if (isDev) {
|
if (isDev) {
|
||||||
menu = new Menu();
|
menu = new Menu();
|
||||||
|
|
||||||
|
@ -10,10 +10,10 @@
|
|||||||
"start": "electron --disable-direct-composition --in-process-gpu ."
|
"start": "electron --disable-direct-composition --in-process-gpu ."
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
"electron": "10.4.0"
|
"electron": "10.4.3"
|
||||||
},
|
},
|
||||||
"optionalDependencies": {
|
"optionalDependencies": {
|
||||||
"shapez.io-private-artifacts": "github:tobspr/shapez.io-private-artifacts#abi-v85"
|
"shapez.io-private-artifacts": "github:tobspr/shapez.io-private-artifacts#abi-v82"
|
||||||
},
|
},
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"async-lock": "^1.2.8"
|
"async-lock": "^1.2.8"
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
const fs = require('fs');
|
const fs = require("fs");
|
||||||
const path = require('path');
|
const path = require("path");
|
||||||
const { ipcMain } = require("electron");
|
const { ipcMain } = require("electron");
|
||||||
|
|
||||||
let greenworks = null;
|
let greenworks = null;
|
||||||
@ -11,10 +11,10 @@ try {
|
|||||||
appId = parseInt(fs.readFileSync(path.join(__dirname, "steam_appid.txt"), "utf8"));
|
appId = parseInt(fs.readFileSync(path.join(__dirname, "steam_appid.txt"), "utf8"));
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
// greenworks is not installed
|
// greenworks is not installed
|
||||||
// throw err;
|
console.warn("Failed to load steam api:", err);
|
||||||
}
|
}
|
||||||
|
|
||||||
function init (isDev) {
|
function init(isDev) {
|
||||||
if (!greenworks) {
|
if (!greenworks) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -34,11 +34,16 @@ function init (isDev) {
|
|||||||
initialized = true;
|
initialized = true;
|
||||||
}
|
}
|
||||||
|
|
||||||
function listen () {
|
function listen() {
|
||||||
ipcMain.handle("steam:is-initialized", isInitialized);
|
ipcMain.handle("steam:is-initialized", isInitialized);
|
||||||
|
|
||||||
if (!greenworks || !initialized) {
|
if (!initialized) {
|
||||||
console.log("Ignoring Steam IPC events");
|
console.warn("Steam not initialized, won't be able to listen");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!greenworks) {
|
||||||
|
console.warn("Greenworks not loaded, won't be able to listen");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -53,7 +58,7 @@ function isInitialized(event) {
|
|||||||
function getAchievementNames(event) {
|
function getAchievementNames(event) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
try {
|
try {
|
||||||
const achievements = greenworks.getAchievementNames()
|
const achievements = greenworks.getAchievementNames();
|
||||||
resolve(achievements);
|
resolve(achievements);
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
reject(err);
|
reject(err);
|
||||||
@ -63,11 +68,15 @@ function getAchievementNames(event) {
|
|||||||
|
|
||||||
function activateAchievement(event, id) {
|
function activateAchievement(event, id) {
|
||||||
return new Promise((resolve, reject) => {
|
return new Promise((resolve, reject) => {
|
||||||
greenworks.activateAchievement(id, () => resolve(), err => reject(err))
|
greenworks.activateAchievement(
|
||||||
|
id,
|
||||||
|
() => resolve(),
|
||||||
|
err => reject(err)
|
||||||
|
);
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
init,
|
init,
|
||||||
listen
|
listen,
|
||||||
};
|
};
|
||||||
|
@ -146,10 +146,10 @@ duplexer3@^0.1.4:
|
|||||||
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
resolved "https://registry.yarnpkg.com/duplexer3/-/duplexer3-0.1.4.tgz#ee01dd1cac0ed3cbc7fdbea37dc0a8f1ce002ce2"
|
||||||
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
|
integrity sha1-7gHdHKwO08vH/b6jfcCo8c4ALOI=
|
||||||
|
|
||||||
electron@10.4.0:
|
electron@10.4.3:
|
||||||
version "10.4.0"
|
version "10.4.3"
|
||||||
resolved "https://registry.yarnpkg.com/electron/-/electron-10.4.0.tgz#018385914474b56110a5a43087a53c114b67c08d"
|
resolved "https://registry.yarnpkg.com/electron/-/electron-10.4.3.tgz#8d1c0f5e562d1b78dcec8074c0d59e58137fd508"
|
||||||
integrity sha512-qK8OOCWuNvEFWThmjkukkqDwIpBqULlDuMXVC9MC/2P4UaWJEjIYvBmBuTyxtFcKoE3kWvcWyeRDUuvzVxxXjA==
|
integrity sha512-qL8XZBII9KQHr1+YmVMj1AqyTR2I8/lxozvKEWoKKSkF8Hl6GzzxrLXRfISP7aDAvsJEyyhc6b2/42ME8hG5JA==
|
||||||
dependencies:
|
dependencies:
|
||||||
"@electron/get" "^1.0.1"
|
"@electron/get" "^1.0.1"
|
||||||
"@types/node" "^12.0.12"
|
"@types/node" "^12.0.12"
|
||||||
@ -503,9 +503,9 @@ serialize-error@^7.0.1:
|
|||||||
dependencies:
|
dependencies:
|
||||||
type-fest "^0.13.1"
|
type-fest "^0.13.1"
|
||||||
|
|
||||||
"shapez.io-private-artifacts@github:tobspr/shapez.io-private-artifacts#abi-v85":
|
"shapez.io-private-artifacts@github:tobspr/shapez.io-private-artifacts#abi-v82":
|
||||||
version "0.1.0"
|
version "0.1.0"
|
||||||
resolved "git+ssh://git@github.com/tobspr/shapez.io-private-artifacts.git#63adf7e0ea4b90c2a29053ce1f0ec9d573b3ac0a"
|
resolved "git+ssh://git@github.com/tobspr/shapez.io-private-artifacts.git#8aa3bfd3b569eb5695fc8a585a3f2ee3ed2db290"
|
||||||
|
|
||||||
sprintf-js@^1.1.2:
|
sprintf-js@^1.1.2:
|
||||||
version "1.1.2"
|
version "1.1.2"
|
||||||
|
@ -17,7 +17,7 @@
|
|||||||
@include S(border-radius, 3px);
|
@include S(border-radius, 3px);
|
||||||
|
|
||||||
@include DarkThemeOverride {
|
@include DarkThemeOverride {
|
||||||
background: #424242;
|
background: #33343c;
|
||||||
}
|
}
|
||||||
|
|
||||||
.version {
|
.version {
|
||||||
|
@ -2,10 +2,21 @@ export const CHANGELOG = [
|
|||||||
{
|
{
|
||||||
version: "1.3.1",
|
version: "1.3.1",
|
||||||
date: "beta",
|
date: "beta",
|
||||||
entries: [
|
entries: G_CHINA_VERSION
|
||||||
"Fixed savegames getting corrupt in rare conditions",
|
? [
|
||||||
"Fixed game crashing sometimes since the achievements update",
|
"第13关的交付目标更改为:中国古代指南针。(感谢玩家:凯风入心 创作并提供",
|
||||||
],
|
"第17关的交付目标更改为:永乐通宝。(感谢玩家:金天赐 创作并提供",
|
||||||
|
"第22关的交付目标更改为:凤凰。(感谢玩家:我没得眼镜 创作并提供",
|
||||||
|
"第23关的交付目标更改为:古代车轮。(感谢玩家:我没得眼镜 创作并提供",
|
||||||
|
"第24关的交付目标更改为:大熊猫。(感谢玩家:窝囸倪现任 创作并提供",
|
||||||
|
|
||||||
|
"修复了一些特定情况下偶尔会发生的存档损坏问题",
|
||||||
|
"修复了成就更新后有时候游戏崩溃的问题",
|
||||||
|
]
|
||||||
|
: [
|
||||||
|
"Fixed savegames getting corrupt in rare conditions",
|
||||||
|
"Fixed game crashing sometimes since the achievements update",
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
version: "1.3.0",
|
version: "1.3.0",
|
||||||
|
@ -11,6 +11,7 @@ export const itemTypes = ["shape", "color", "boolean"];
|
|||||||
export class BaseItem extends BasicSerializableObject {
|
export class BaseItem extends BasicSerializableObject {
|
||||||
constructor() {
|
constructor() {
|
||||||
super();
|
super();
|
||||||
|
this._type = this.getItemType();
|
||||||
}
|
}
|
||||||
|
|
||||||
static getId() {
|
static getId() {
|
||||||
|
@ -13,8 +13,6 @@ import { GameRoot } from "./root";
|
|||||||
const logger = createLogger("belt_path");
|
const logger = createLogger("belt_path");
|
||||||
|
|
||||||
// Helpers for more semantic access into interleaved arrays
|
// Helpers for more semantic access into interleaved arrays
|
||||||
const _nextDistance = 0;
|
|
||||||
const _item = 1;
|
|
||||||
|
|
||||||
const DEBUG = G_IS_DEV && false;
|
const DEBUG = G_IS_DEV && false;
|
||||||
|
|
||||||
@ -174,7 +172,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
* Recomputes cache variables once the path was changed
|
* Recomputes cache variables once the path was changed
|
||||||
*/
|
*/
|
||||||
onPathChanged() {
|
onPathChanged() {
|
||||||
this.acceptorTarget = this.computeAcceptingEntityAndSlot();
|
this.boundAcceptor = this.computeAcceptingEntityAndSlot();
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* How many items past the first item are compressed
|
* How many items past the first item are compressed
|
||||||
@ -192,7 +190,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
/**
|
/**
|
||||||
* Finds the entity which accepts our items
|
* Finds the entity which accepts our items
|
||||||
* @param {boolean=} debug_Silent Whether debug output should be silent
|
* @param {boolean=} debug_Silent Whether debug output should be silent
|
||||||
* @return {{ entity: Entity, slot: number, direction?: enumDirection }}
|
* @return { (BaseItem, number) => boolean }
|
||||||
*/
|
*/
|
||||||
computeAcceptingEntityAndSlot(debug_Silent = false) {
|
computeAcceptingEntityAndSlot(debug_Silent = false) {
|
||||||
DEBUG && !debug_Silent && logger.log("Recomputing acceptor target");
|
DEBUG && !debug_Silent && logger.log("Recomputing acceptor target");
|
||||||
@ -214,55 +212,142 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
"regular"
|
"regular"
|
||||||
);
|
);
|
||||||
|
|
||||||
if (targetEntity) {
|
if (!targetEntity) {
|
||||||
DEBUG && !debug_Silent && logger.log(" Found target entity", targetEntity.uid);
|
return;
|
||||||
const targetStaticComp = targetEntity.components.StaticMapEntity;
|
}
|
||||||
const targetBeltComp = targetEntity.components.Belt;
|
|
||||||
|
|
||||||
// Check for belts (special case)
|
const noSimplifiedBelts = !this.root.app.settings.getAllSettings().simplifiedBelts;
|
||||||
if (targetBeltComp) {
|
|
||||||
const beltAcceptingDirection = targetStaticComp.localDirectionToWorld(enumDirection.top);
|
DEBUG && !debug_Silent && logger.log(" Found target entity", targetEntity.uid);
|
||||||
DEBUG &&
|
const targetStaticComp = targetEntity.components.StaticMapEntity;
|
||||||
!debug_Silent &&
|
const targetBeltComp = targetEntity.components.Belt;
|
||||||
logger.log(
|
|
||||||
" Entity is accepting items from",
|
// Check for belts (special case)
|
||||||
ejectSlotWsDirection,
|
if (targetBeltComp) {
|
||||||
"vs",
|
const beltAcceptingDirection = targetStaticComp.localDirectionToWorld(enumDirection.top);
|
||||||
beltAcceptingDirection,
|
DEBUG &&
|
||||||
"Rotation:",
|
!debug_Silent &&
|
||||||
targetStaticComp.rotation
|
logger.log(
|
||||||
|
" Entity is accepting items from",
|
||||||
|
ejectSlotWsDirection,
|
||||||
|
"vs",
|
||||||
|
beltAcceptingDirection,
|
||||||
|
"Rotation:",
|
||||||
|
targetStaticComp.rotation
|
||||||
|
);
|
||||||
|
if (ejectSlotWsDirection === beltAcceptingDirection) {
|
||||||
|
return item => {
|
||||||
|
const path = targetBeltComp.assignedPath;
|
||||||
|
assert(path, "belt has no path");
|
||||||
|
return path.tryAcceptItem(item);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Check for item acceptors
|
||||||
|
const targetAcceptorComp = targetEntity.components.ItemAcceptor;
|
||||||
|
if (!targetAcceptorComp) {
|
||||||
|
// Entity doesn't accept items
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const ejectingDirection = targetStaticComp.worldDirectionToLocal(ejectSlotWsDirection);
|
||||||
|
const matchingSlot = targetAcceptorComp.findMatchingSlot(
|
||||||
|
targetStaticComp.worldToLocalTile(ejectSlotTargetWsTile),
|
||||||
|
ejectingDirection
|
||||||
|
);
|
||||||
|
|
||||||
|
if (!matchingSlot) {
|
||||||
|
// No matching slot found
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchingSlotIndex = matchingSlot.index;
|
||||||
|
const passOver = this.computePassOverFunctionWithoutBelts(targetEntity, matchingSlotIndex);
|
||||||
|
if (!passOver) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const matchingDirection = enumInvertedDirections[ejectingDirection];
|
||||||
|
const filter = matchingSlot.slot.filter;
|
||||||
|
|
||||||
|
return function (item, remainingProgress = 0.0) {
|
||||||
|
// Check if the acceptor has a filter
|
||||||
|
if (filter && item._type !== filter) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to pass over
|
||||||
|
if (passOver(item, matchingSlotIndex)) {
|
||||||
|
// Trigger animation on the acceptor comp
|
||||||
|
if (noSimplifiedBelts) {
|
||||||
|
targetAcceptorComp.onItemAccepted(
|
||||||
|
matchingSlotIndex,
|
||||||
|
matchingDirection,
|
||||||
|
item,
|
||||||
|
remainingProgress
|
||||||
);
|
);
|
||||||
if (ejectSlotWsDirection === beltAcceptingDirection) {
|
|
||||||
return {
|
|
||||||
entity: targetEntity,
|
|
||||||
direction: null,
|
|
||||||
slot: 0,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
return true;
|
||||||
}
|
}
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
// Check for item acceptors
|
/**
|
||||||
const targetAcceptorComp = targetEntity.components.ItemAcceptor;
|
* Computes a method to pass over the item to the entity
|
||||||
if (!targetAcceptorComp) {
|
* @param {Entity} entity
|
||||||
// Entity doesn't accept items
|
* @param {number} matchingSlotIndex
|
||||||
return;
|
* @returns {(item: BaseItem, slotIndex: number) => boolean | void}
|
||||||
}
|
*/
|
||||||
|
computePassOverFunctionWithoutBelts(entity, matchingSlotIndex) {
|
||||||
|
const systems = this.root.systemMgr.systems;
|
||||||
|
const hubGoals = this.root.hubGoals;
|
||||||
|
|
||||||
const ejectingDirection = targetStaticComp.worldDirectionToLocal(ejectSlotWsDirection);
|
// NOTICE: THIS IS COPIED FROM THE ITEM EJECTOR SYSTEM FOR PEROFMANCE REASONS
|
||||||
const matchingSlot = targetAcceptorComp.findMatchingSlot(
|
|
||||||
targetStaticComp.worldToLocalTile(ejectSlotTargetWsTile),
|
|
||||||
ejectingDirection
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!matchingSlot) {
|
const itemProcessorComp = entity.components.ItemProcessor;
|
||||||
// No matching slot found
|
if (itemProcessorComp) {
|
||||||
return;
|
// Its an item processor ..
|
||||||
}
|
return function (item) {
|
||||||
|
// Check for potential filters
|
||||||
|
if (!systems.itemProcessor.checkRequirements(entity, item, matchingSlotIndex)) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
return itemProcessorComp.tryTakeItem(item, matchingSlotIndex);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
return {
|
const undergroundBeltComp = entity.components.UndergroundBelt;
|
||||||
entity: targetEntity,
|
if (undergroundBeltComp) {
|
||||||
slot: matchingSlot.index,
|
// Its an underground belt. yay.
|
||||||
direction: enumInvertedDirections[ejectingDirection],
|
return function (item) {
|
||||||
|
return undergroundBeltComp.tryAcceptExternalItem(
|
||||||
|
item,
|
||||||
|
hubGoals.getUndergroundBeltBaseSpeed()
|
||||||
|
);
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const storageComp = entity.components.Storage;
|
||||||
|
if (storageComp) {
|
||||||
|
// It's a storage
|
||||||
|
return function (item) {
|
||||||
|
if (storageComp.canAcceptItem(item)) {
|
||||||
|
storageComp.takeItem(item);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
const filterComp = entity.components.Filter;
|
||||||
|
if (filterComp) {
|
||||||
|
// It's a filter! Unfortunately the filter has to know a lot about it's
|
||||||
|
// surrounding state and components, so it can't be within the component itself.
|
||||||
|
return function (item) {
|
||||||
|
if (systems.filter.tryAcceptItem(entity, matchingSlotIndex, item)) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -365,17 +450,17 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
for (let i = 0; i < this.items.length; ++i) {
|
for (let i = 0; i < this.items.length; ++i) {
|
||||||
const item = this.items[i];
|
const item = this.items[i];
|
||||||
|
|
||||||
if (item[_nextDistance] < 0 || item[_nextDistance] > this.totalLength + 0.02) {
|
if (item[0 /* nextDistance */] < 0 || item[0 /* nextDistance */] > this.totalLength + 0.02) {
|
||||||
return fail(
|
return fail(
|
||||||
"Item has invalid offset to next item: ",
|
"Item has invalid offset to next item: ",
|
||||||
item[_nextDistance],
|
item[0 /* nextDistance */],
|
||||||
"(total length:",
|
"(total length:",
|
||||||
this.totalLength,
|
this.totalLength,
|
||||||
")"
|
")"
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
currentPos += item[_nextDistance];
|
currentPos += item[0 /* nextDistance */];
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check the total sum matches
|
// Check the total sum matches
|
||||||
@ -387,7 +472,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
this.spacingToFirstItem,
|
this.spacingToFirstItem,
|
||||||
") and items does not match total length (",
|
") and items does not match total length (",
|
||||||
this.totalLength,
|
this.totalLength,
|
||||||
") -> items: " + this.items.map(i => i[_nextDistance]).join("|")
|
") -> items: " + this.items.map(i => i[0 /* nextDistance */]).join("|")
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -399,43 +484,14 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
|
|
||||||
// Check acceptor
|
// Check acceptor
|
||||||
const acceptor = this.computeAcceptingEntityAndSlot(true);
|
const acceptor = this.computeAcceptingEntityAndSlot(true);
|
||||||
if (!!acceptor !== !!this.acceptorTarget) {
|
if (!!acceptor !== !!this.boundAcceptor) {
|
||||||
return fail("Acceptor target mismatch, acceptor", !!acceptor, "vs stored", !!this.acceptorTarget);
|
return fail("Acceptor target mismatch, acceptor", !!acceptor, "vs stored", !!this.boundAcceptor);
|
||||||
}
|
|
||||||
|
|
||||||
if (acceptor) {
|
|
||||||
if (this.acceptorTarget.entity !== acceptor.entity) {
|
|
||||||
return fail(
|
|
||||||
"Mismatching entity on acceptor target:",
|
|
||||||
acceptor.entity.uid,
|
|
||||||
"vs",
|
|
||||||
this.acceptorTarget.entity.uid
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.acceptorTarget.slot !== acceptor.slot) {
|
|
||||||
return fail(
|
|
||||||
"Mismatching entity on acceptor target:",
|
|
||||||
acceptor.slot,
|
|
||||||
"vs stored",
|
|
||||||
this.acceptorTarget.slot
|
|
||||||
);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (this.acceptorTarget.direction !== acceptor.direction) {
|
|
||||||
return fail(
|
|
||||||
"Mismatching direction on acceptor target:",
|
|
||||||
acceptor.direction,
|
|
||||||
"vs stored",
|
|
||||||
this.acceptorTarget.direction
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check first nonzero offset
|
// Check first nonzero offset
|
||||||
let firstNonzero = 0;
|
let firstNonzero = 0;
|
||||||
for (let i = this.items.length - 2; i >= 0; --i) {
|
for (let i = this.items.length - 2; i >= 0; --i) {
|
||||||
if (this.items[i][_nextDistance] < globalConfig.itemSpacingOnBelts + 1e-5) {
|
if (this.items[i][0 /* nextDistance */] < globalConfig.itemSpacingOnBelts + 1e-5) {
|
||||||
++firstNonzero;
|
++firstNonzero;
|
||||||
} else {
|
} else {
|
||||||
break;
|
break;
|
||||||
@ -483,11 +539,11 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
DEBUG &&
|
DEBUG &&
|
||||||
logger.log(
|
logger.log(
|
||||||
" Extended spacing of last item from",
|
" Extended spacing of last item from",
|
||||||
lastItem[_nextDistance],
|
lastItem[0 /* nextDistance */],
|
||||||
"to",
|
"to",
|
||||||
lastItem[_nextDistance] + additionalLength
|
lastItem[0 /* nextDistance */] + additionalLength
|
||||||
);
|
);
|
||||||
lastItem[_nextDistance] += additionalLength;
|
lastItem[0 /* nextDistance */] += additionalLength;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Assign reference
|
// Assign reference
|
||||||
@ -618,7 +674,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
DEBUG &&
|
DEBUG &&
|
||||||
logger.log(
|
logger.log(
|
||||||
"Old items are",
|
"Old items are",
|
||||||
this.items.map(i => i[_nextDistance])
|
this.items.map(i => i[0 /* nextDistance */])
|
||||||
);
|
);
|
||||||
|
|
||||||
// Create second path
|
// Create second path
|
||||||
@ -628,7 +684,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
let itemPos = this.spacingToFirstItem;
|
let itemPos = this.spacingToFirstItem;
|
||||||
for (let i = 0; i < this.items.length; ++i) {
|
for (let i = 0; i < this.items.length; ++i) {
|
||||||
const item = this.items[i];
|
const item = this.items[i];
|
||||||
const distanceToNext = item[_nextDistance];
|
const distanceToNext = item[0 /* nextDistance */];
|
||||||
|
|
||||||
DEBUG && logger.log(" Checking item at", itemPos, "with distance of", distanceToNext, "to next");
|
DEBUG && logger.log(" Checking item at", itemPos, "with distance of", distanceToNext, "to next");
|
||||||
|
|
||||||
@ -643,7 +699,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
// Check if its on the second path (otherwise its on the removed belt and simply lost)
|
// Check if its on the second path (otherwise its on the removed belt and simply lost)
|
||||||
if (itemPos >= secondPathStart) {
|
if (itemPos >= secondPathStart) {
|
||||||
// Put item on second path
|
// Put item on second path
|
||||||
secondPath.items.push([distanceToNext, item[_item]]);
|
secondPath.items.push([distanceToNext, item[1 /* item */]]);
|
||||||
DEBUG &&
|
DEBUG &&
|
||||||
logger.log(
|
logger.log(
|
||||||
" Put item to second path @",
|
" Put item to second path @",
|
||||||
@ -672,7 +728,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
"to",
|
"to",
|
||||||
clampedDistanceToNext
|
clampedDistanceToNext
|
||||||
);
|
);
|
||||||
item[_nextDistance] = clampedDistanceToNext;
|
item[0 /* nextDistance */] = clampedDistanceToNext;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -683,13 +739,13 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
DEBUG &&
|
DEBUG &&
|
||||||
logger.log(
|
logger.log(
|
||||||
"New items are",
|
"New items are",
|
||||||
this.items.map(i => i[_nextDistance])
|
this.items.map(i => i[0 /* nextDistance */])
|
||||||
);
|
);
|
||||||
|
|
||||||
DEBUG &&
|
DEBUG &&
|
||||||
logger.log(
|
logger.log(
|
||||||
"And second path items are",
|
"And second path items are",
|
||||||
secondPath.items.map(i => i[_nextDistance])
|
secondPath.items.map(i => i[0 /* nextDistance */])
|
||||||
);
|
);
|
||||||
|
|
||||||
// Adjust our total length
|
// Adjust our total length
|
||||||
@ -776,9 +832,17 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
DEBUG && logger.log("Item", i, "is at", itemOffset, "with next offset", item[_nextDistance]);
|
DEBUG &&
|
||||||
|
logger.log(
|
||||||
|
"Item",
|
||||||
|
i,
|
||||||
|
"is at",
|
||||||
|
itemOffset,
|
||||||
|
"with next offset",
|
||||||
|
item[0 /* nextDistance */]
|
||||||
|
);
|
||||||
lastItemOffset = itemOffset;
|
lastItemOffset = itemOffset;
|
||||||
itemOffset += item[_nextDistance];
|
itemOffset += item[0 /* nextDistance */];
|
||||||
}
|
}
|
||||||
|
|
||||||
// If we still have an item, make sure the last item matches
|
// If we still have an item, make sure the last item matches
|
||||||
@ -805,7 +869,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
this.totalLength,
|
this.totalLength,
|
||||||
")"
|
")"
|
||||||
);
|
);
|
||||||
this.items[this.items.length - 1][_nextDistance] = lastDistance;
|
this.items[this.items.length - 1][0 /* nextDistance */] = lastDistance;
|
||||||
} else {
|
} else {
|
||||||
DEBUG && logger.log(" Removed all items so we'll update spacing to total length");
|
DEBUG && logger.log(" Removed all items so we'll update spacing to total length");
|
||||||
|
|
||||||
@ -893,7 +957,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
DEBUG &&
|
DEBUG &&
|
||||||
logger.log(
|
logger.log(
|
||||||
" Items:",
|
" Items:",
|
||||||
this.items.map(i => i[_nextDistance])
|
this.items.map(i => i[0 /* nextDistance */])
|
||||||
);
|
);
|
||||||
|
|
||||||
// Find offset to first item
|
// Find offset to first item
|
||||||
@ -912,7 +976,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
// This item must be dropped
|
// This item must be dropped
|
||||||
this.items.splice(i, 1);
|
this.items.splice(i, 1);
|
||||||
i -= 1;
|
i -= 1;
|
||||||
itemOffset += item[_nextDistance];
|
itemOffset += item[0 /* nextDistance */];
|
||||||
continue;
|
continue;
|
||||||
} else {
|
} else {
|
||||||
// This item can be kept, thus its the first we know
|
// This item can be kept, thus its the first we know
|
||||||
@ -990,9 +1054,13 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
// Now, update the distance of our last item
|
// Now, update the distance of our last item
|
||||||
if (this.items.length !== 0) {
|
if (this.items.length !== 0) {
|
||||||
const lastItem = this.items[this.items.length - 1];
|
const lastItem = this.items[this.items.length - 1];
|
||||||
lastItem[_nextDistance] += otherPath.spacingToFirstItem;
|
lastItem[0 /* nextDistance */] += otherPath.spacingToFirstItem;
|
||||||
DEBUG &&
|
DEBUG &&
|
||||||
logger.log(" Add distance to last item, effectively being", lastItem[_nextDistance], "now");
|
logger.log(
|
||||||
|
" Add distance to last item, effectively being",
|
||||||
|
lastItem[0 /* nextDistance */],
|
||||||
|
"now"
|
||||||
|
);
|
||||||
} else {
|
} else {
|
||||||
// Seems we have no items, update our first item distance
|
// Seems we have no items, update our first item distance
|
||||||
this.spacingToFirstItem = oldLength + otherPath.spacingToFirstItem;
|
this.spacingToFirstItem = oldLength + otherPath.spacingToFirstItem;
|
||||||
@ -1012,7 +1080,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
// Aaand push the other paths items
|
// Aaand push the other paths items
|
||||||
for (let i = 0; i < otherPath.items.length; ++i) {
|
for (let i = 0; i < otherPath.items.length; ++i) {
|
||||||
const item = otherPath.items[i];
|
const item = otherPath.items[i];
|
||||||
this.items.push([item[_nextDistance], item[_item]]);
|
this.items.push([item[0 /* nextDistance */], item[1 /* item */]]);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update bounds
|
// Update bounds
|
||||||
@ -1046,6 +1114,11 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
this.debug_checkIntegrity("pre-update");
|
this.debug_checkIntegrity("pre-update");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Skip empty belts
|
||||||
|
if (this.items.length === 0) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
// Divide by item spacing on belts since we use throughput and not speed
|
// Divide by item spacing on belts since we use throughput and not speed
|
||||||
let beltSpeed =
|
let beltSpeed =
|
||||||
this.root.hubGoals.getBeltBaseSpeed() *
|
this.root.hubGoals.getBeltBaseSpeed() *
|
||||||
@ -1074,30 +1147,40 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
lastItemProcessed === this.items.length - 1 ? 0 : globalConfig.itemSpacingOnBelts;
|
lastItemProcessed === this.items.length - 1 ? 0 : globalConfig.itemSpacingOnBelts;
|
||||||
|
|
||||||
// Compute how much we can advance
|
// Compute how much we can advance
|
||||||
const clampedProgress = Math.max(
|
let clampedProgress = nextDistanceAndItem[0 /* nextDistance */] - minimumSpacing;
|
||||||
0,
|
|
||||||
Math.min(remainingVelocity, nextDistanceAndItem[_nextDistance] - minimumSpacing)
|
// Make sure we don't advance more than the remaining velocity has stored
|
||||||
);
|
if (remainingVelocity < clampedProgress) {
|
||||||
|
clampedProgress = remainingVelocity;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Make sure we don't advance back
|
||||||
|
if (clampedProgress < 0) {
|
||||||
|
clampedProgress = 0;
|
||||||
|
}
|
||||||
|
|
||||||
// Reduce our velocity by the amount we consumed
|
// Reduce our velocity by the amount we consumed
|
||||||
remainingVelocity -= clampedProgress;
|
remainingVelocity -= clampedProgress;
|
||||||
|
|
||||||
// Reduce the spacing
|
// Reduce the spacing
|
||||||
nextDistanceAndItem[_nextDistance] -= clampedProgress;
|
nextDistanceAndItem[0 /* nextDistance */] -= clampedProgress;
|
||||||
|
|
||||||
// Advance all items behind by the progress we made
|
// Advance all items behind by the progress we made
|
||||||
this.spacingToFirstItem += clampedProgress;
|
this.spacingToFirstItem += clampedProgress;
|
||||||
|
|
||||||
// If the last item can be ejected, eject it and reduce the spacing, because otherwise
|
// If the last item can be ejected, eject it and reduce the spacing, because otherwise
|
||||||
// we lose velocity
|
// we lose velocity
|
||||||
if (isFirstItemProcessed && nextDistanceAndItem[_nextDistance] < 1e-7) {
|
if (isFirstItemProcessed && nextDistanceAndItem[0 /* nextDistance */] < 1e-7) {
|
||||||
// Store how much velocity we "lost" because we bumped the item to the end of the
|
// Store how much velocity we "lost" because we bumped the item to the end of the
|
||||||
// belt but couldn't move it any farther. We need this to tell the item acceptor
|
// belt but couldn't move it any farther. We need this to tell the item acceptor
|
||||||
// animation to start a tad later, so everything matches up. Yes I'm a perfectionist.
|
// animation to start a tad later, so everything matches up. Yes I'm a perfectionist.
|
||||||
const excessVelocity = beltSpeed - clampedProgress;
|
const excessVelocity = beltSpeed - clampedProgress;
|
||||||
|
|
||||||
// Try to directly get rid of the item
|
// Try to directly get rid of the item
|
||||||
if (this.tryHandOverItem(nextDistanceAndItem[_item], excessVelocity)) {
|
if (
|
||||||
|
this.boundAcceptor &&
|
||||||
|
this.boundAcceptor(nextDistanceAndItem[1 /* item */], excessVelocity)
|
||||||
|
) {
|
||||||
this.items.pop();
|
this.items.pop();
|
||||||
|
|
||||||
const itemBehind = this.items[lastItemProcessed - 1];
|
const itemBehind = this.items[lastItemProcessed - 1];
|
||||||
@ -1108,11 +1191,11 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
// Also see #999
|
// Also see #999
|
||||||
const fixupProgress = Math.max(
|
const fixupProgress = Math.max(
|
||||||
0,
|
0,
|
||||||
Math.min(remainingVelocity, itemBehind[_nextDistance])
|
Math.min(remainingVelocity, itemBehind[0 /* nextDistance */])
|
||||||
);
|
);
|
||||||
|
|
||||||
// See above
|
// See above
|
||||||
itemBehind[_nextDistance] -= fixupProgress;
|
itemBehind[0 /* nextDistance */] -= fixupProgress;
|
||||||
remainingVelocity -= fixupProgress;
|
remainingVelocity -= fixupProgress;
|
||||||
this.spacingToFirstItem += fixupProgress;
|
this.spacingToFirstItem += fixupProgress;
|
||||||
}
|
}
|
||||||
@ -1145,8 +1228,8 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
|
|
||||||
// Check if we have an item which is ready to be emitted
|
// Check if we have an item which is ready to be emitted
|
||||||
const lastItem = this.items[this.items.length - 1];
|
const lastItem = this.items[this.items.length - 1];
|
||||||
if (lastItem && lastItem[_nextDistance] === 0 && this.acceptorTarget) {
|
if (lastItem && lastItem[0 /* nextDistance */] === 0) {
|
||||||
if (this.tryHandOverItem(lastItem[_item])) {
|
if (this.boundAcceptor && this.boundAcceptor(lastItem[1 /* item */])) {
|
||||||
this.items.pop();
|
this.items.pop();
|
||||||
this.numCompressedItemsAfterFirstItem = Math.max(
|
this.numCompressedItemsAfterFirstItem = Math.max(
|
||||||
0,
|
0,
|
||||||
@ -1160,50 +1243,6 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
|
||||||
* Tries to hand over the item to the end entity
|
|
||||||
* @param {BaseItem} item
|
|
||||||
*/
|
|
||||||
tryHandOverItem(item, remainingProgress = 0.0) {
|
|
||||||
if (!this.acceptorTarget) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const targetAcceptorComp = this.acceptorTarget.entity.components.ItemAcceptor;
|
|
||||||
|
|
||||||
// Check if the acceptor has a filter for example
|
|
||||||
if (targetAcceptorComp && !targetAcceptorComp.canAcceptItem(this.acceptorTarget.slot, item)) {
|
|
||||||
// Well, this item is not accepted
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to pass over
|
|
||||||
if (
|
|
||||||
this.root.systemMgr.systems.itemEjector.tryPassOverItem(
|
|
||||||
item,
|
|
||||||
this.acceptorTarget.entity,
|
|
||||||
this.acceptorTarget.slot
|
|
||||||
)
|
|
||||||
) {
|
|
||||||
// Trigger animation on the acceptor comp
|
|
||||||
const targetAcceptorComp = this.acceptorTarget.entity.components.ItemAcceptor;
|
|
||||||
if (targetAcceptorComp) {
|
|
||||||
if (!this.root.app.settings.getAllSettings().simplifiedBelts) {
|
|
||||||
targetAcceptorComp.onItemAccepted(
|
|
||||||
this.acceptorTarget.slot,
|
|
||||||
this.acceptorTarget.direction,
|
|
||||||
item,
|
|
||||||
remainingProgress
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Computes a world space position from the given progress
|
* Computes a world space position from the given progress
|
||||||
* @param {number} progress
|
* @param {number} progress
|
||||||
@ -1270,11 +1309,11 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
parameters.context.font = "6px GameFont";
|
parameters.context.font = "6px GameFont";
|
||||||
parameters.context.fillStyle = "#111";
|
parameters.context.fillStyle = "#111";
|
||||||
parameters.context.fillText(
|
parameters.context.fillText(
|
||||||
"" + round4Digits(nextDistanceAndItem[_nextDistance]),
|
"" + round4Digits(nextDistanceAndItem[0 /* nextDistance */]),
|
||||||
worldPos.x + 5,
|
worldPos.x + 5,
|
||||||
worldPos.y + 2
|
worldPos.y + 2
|
||||||
);
|
);
|
||||||
progress += nextDistanceAndItem[_nextDistance];
|
progress += nextDistanceAndItem[0 /* nextDistance */];
|
||||||
|
|
||||||
if (this.items.length - 1 - this.numCompressedItemsAfterFirstItem === i) {
|
if (this.items.length - 1 - this.numCompressedItemsAfterFirstItem === i) {
|
||||||
parameters.context.fillStyle = "red";
|
parameters.context.fillStyle = "red";
|
||||||
@ -1370,7 +1409,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
const centerPos = staticComp.localTileToWorld(centerPosLocal).toWorldSpaceCenterOfTile();
|
const centerPos = staticComp.localTileToWorld(centerPosLocal).toWorldSpaceCenterOfTile();
|
||||||
|
|
||||||
parameters.context.globalAlpha = 0.5;
|
parameters.context.globalAlpha = 0.5;
|
||||||
firstItem[_item].drawItemCenteredClipped(centerPos.x, centerPos.y, parameters);
|
firstItem[1 /* item */].drawItemCenteredClipped(centerPos.x, centerPos.y, parameters);
|
||||||
parameters.context.globalAlpha = 1;
|
parameters.context.globalAlpha = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1402,7 +1441,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
|
|
||||||
const distanceAndItem = this.items[currentItemIndex];
|
const distanceAndItem = this.items[currentItemIndex];
|
||||||
|
|
||||||
distanceAndItem[_item].drawItemCenteredClipped(
|
distanceAndItem[1 /* item */].drawItemCenteredClipped(
|
||||||
worldPos.x,
|
worldPos.x,
|
||||||
worldPos.y,
|
worldPos.y,
|
||||||
parameters,
|
parameters,
|
||||||
@ -1410,7 +1449,7 @@ export class BeltPath extends BasicSerializableObject {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Check for the next item
|
// Check for the next item
|
||||||
currentItemPos += distanceAndItem[_nextDistance];
|
currentItemPos += distanceAndItem[0 /* nextDistance */];
|
||||||
++currentItemIndex;
|
++currentItemIndex;
|
||||||
|
|
||||||
if (currentItemIndex >= this.items.length) {
|
if (currentItemIndex >= this.items.length) {
|
||||||
|
@ -71,6 +71,8 @@ export class ItemAcceptorComponent extends Component {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Returns if this acceptor can accept a new item at slot N
|
* Returns if this acceptor can accept a new item at slot N
|
||||||
|
*
|
||||||
|
* NOTICE: The belt path ignores this for performance reasons and does his own check
|
||||||
* @param {number} slotIndex
|
* @param {number} slotIndex
|
||||||
* @param {BaseItem=} item
|
* @param {BaseItem=} item
|
||||||
*/
|
*/
|
||||||
|
@ -157,9 +157,7 @@ export class GameHUD {
|
|||||||
this.parts.colorBlindHelper = new HUDColorBlindHelper(this.root);
|
this.parts.colorBlindHelper = new HUDColorBlindHelper(this.root);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (queryParamOptions.sandboxMode || G_IS_DEV) {
|
this.parts.sandboxController = new HUDSandboxController(this.root);
|
||||||
this.parts.sandboxController = new HUDSandboxController(this.root);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (!G_IS_RELEASE && !G_IS_DEV) {
|
if (!G_IS_RELEASE && !G_IS_DEV) {
|
||||||
this.parts.betaOverlay = new HUDBetaOverlay(this.root);
|
this.parts.betaOverlay = new HUDBetaOverlay(this.root);
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
import { queryParamOptions } from "../../../core/query_parameters";
|
||||||
import { makeDiv } from "../../../core/utils";
|
import { makeDiv } from "../../../core/utils";
|
||||||
import { BaseHUDPart } from "../base_hud_part";
|
import { BaseHUDPart } from "../base_hud_part";
|
||||||
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
import { DynamicDomAttach } from "../dynamic_dom_attach";
|
||||||
@ -144,11 +145,25 @@ export class HUDSandboxController extends BaseHUDPart {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
this.visible = !G_IS_DEV;
|
this.visible = false;
|
||||||
this.domAttach = new DynamicDomAttach(this.root, this.element);
|
this.domAttach = new DynamicDomAttach(this.root, this.element);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
isAvailable() {
|
||||||
|
if (queryParamOptions.sandboxMode || G_IS_DEV) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
// @ts-ignore
|
||||||
|
if (window.sandboxMode) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
toggle() {
|
toggle() {
|
||||||
|
if (!this.visible && !this.isAvailable()) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
this.visible = !this.visible;
|
this.visible = !this.visible;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -118,7 +118,14 @@ function generateUpgrades(limitedVersion = false) {
|
|||||||
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
|
required: [{ shape: "CwCwCwCw:WbWbWbWb", amount: 23000 }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
required: [{ shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", amount: 50000 }],
|
required: [
|
||||||
|
{
|
||||||
|
shape: G_CHINA_VERSION
|
||||||
|
? "CyCyCyCy:CyCyCyCy:RyRyRyRy:RuRuRuRu"
|
||||||
|
: "CbRbRbCb:CwCwCwCw:WbWbWbWb",
|
||||||
|
amount: 50000,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
required: [{ shape: preparementShape, amount: 25000 }],
|
required: [{ shape: preparementShape, amount: 25000 }],
|
||||||
@ -172,7 +179,12 @@ function generateUpgrades(limitedVersion = false) {
|
|||||||
required: [{ shape: "WrWrWrWr", amount: 3800 }],
|
required: [{ shape: "WrWrWrWr", amount: 3800 }],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
required: [{ shape: "RpRpRpRp:CwCwCwCw", amount: 6500 }],
|
required: [
|
||||||
|
{
|
||||||
|
shape: G_CHINA_VERSION ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw",
|
||||||
|
amount: 6500,
|
||||||
|
},
|
||||||
|
],
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
|
required: [{ shape: "WpWpWpWp:CwCwCwCw:WpWpWpWp", amount: 25000 }],
|
||||||
@ -346,7 +358,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
|
|||||||
// 13
|
// 13
|
||||||
// Tunnel Tier 2
|
// Tunnel Tier 2
|
||||||
{
|
{
|
||||||
shape: "RpRpRpRp:CwCwCwCw", // painting t3
|
shape: G_CHINA_VERSION ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw", // painting t3
|
||||||
required: 3800,
|
required: 3800,
|
||||||
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
|
reward: enumHubGoalRewards.reward_underground_belt_tier_2,
|
||||||
},
|
},
|
||||||
@ -355,7 +367,7 @@ export function generateLevelDefinitions(limitedVersion = false) {
|
|||||||
...(limitedVersion
|
...(limitedVersion
|
||||||
? [
|
? [
|
||||||
{
|
{
|
||||||
shape: "RpRpRpRp:CwCwCwCw",
|
shape: G_CHINA_VERSION ? "CuCuCuCu:CwCwCwCw:Sb--Sr--" : "RpRpRpRp:CwCwCwCw",
|
||||||
required: 0,
|
required: 0,
|
||||||
reward: enumHubGoalRewards.reward_demo_end,
|
reward: enumHubGoalRewards.reward_demo_end,
|
||||||
},
|
},
|
||||||
@ -389,7 +401,9 @@ export function generateLevelDefinitions(limitedVersion = false) {
|
|||||||
// 17
|
// 17
|
||||||
// Double painter
|
// Double painter
|
||||||
{
|
{
|
||||||
shape: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
|
shape: G_CHINA_VERSION
|
||||||
|
? "CyCyCyCy:CyCyCyCy:RyRyRyRy:RuRuRuRu"
|
||||||
|
: "CbRbRbCb:CwCwCwCw:WbWbWbWb", // miner t4 (two variants)
|
||||||
required: 20000,
|
required: 20000,
|
||||||
reward: enumHubGoalRewards.reward_painter_double,
|
reward: enumHubGoalRewards.reward_painter_double,
|
||||||
},
|
},
|
||||||
@ -429,7 +443,9 @@ export function generateLevelDefinitions(limitedVersion = false) {
|
|||||||
// 22
|
// 22
|
||||||
// Constant signal
|
// Constant signal
|
||||||
{
|
{
|
||||||
shape: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
|
shape: G_CHINA_VERSION
|
||||||
|
? "RrSySrSy:RyCrCwCr:CyCyRyCy"
|
||||||
|
: "Cg----Cr:Cw----Cw:Sy------:Cy----Cy",
|
||||||
required: 25000,
|
required: 25000,
|
||||||
reward: enumHubGoalRewards.reward_constant_signal,
|
reward: enumHubGoalRewards.reward_constant_signal,
|
||||||
},
|
},
|
||||||
@ -437,14 +453,18 @@ export function generateLevelDefinitions(limitedVersion = false) {
|
|||||||
// 23
|
// 23
|
||||||
// Display
|
// Display
|
||||||
{
|
{
|
||||||
shape: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
|
shape: G_CHINA_VERSION
|
||||||
|
? "CrCrCrCr:CwCwCwCw:WwWwWwWw:CrCrCrCr"
|
||||||
|
: "CcSyCcSy:SyCcSyCc:CcSyCcSy",
|
||||||
required: 25000,
|
required: 25000,
|
||||||
reward: enumHubGoalRewards.reward_display,
|
reward: enumHubGoalRewards.reward_display,
|
||||||
},
|
},
|
||||||
|
|
||||||
// 24 Logic gates
|
// 24 Logic gates
|
||||||
{
|
{
|
||||||
shape: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
|
shape: G_CHINA_VERSION
|
||||||
|
? "Su----Su:RwRwRwRw:Cu----Cu:CwCwCwCw"
|
||||||
|
: "CcRcCcRc:RwCwRwCw:Sr--Sw--:CyCyCyCy",
|
||||||
required: 25000,
|
required: 25000,
|
||||||
reward: enumHubGoalRewards.reward_logic_gates,
|
reward: enumHubGoalRewards.reward_logic_gates,
|
||||||
},
|
},
|
||||||
|
@ -239,6 +239,14 @@ export class ItemEjectorSystem extends GameSystemWithFilter {
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
//
|
||||||
|
// NOTICE ! THIS CODE IS DUPLICATED IN THE BELT PATH FOR PERFORMANCE REASONS
|
||||||
|
//
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
////////////////////////////////////////////////////////////////////////////////
|
||||||
|
|
||||||
const itemProcessorComp = receiver.components.ItemProcessor;
|
const itemProcessorComp = receiver.components.ItemProcessor;
|
||||||
if (itemProcessorComp) {
|
if (itemProcessorComp) {
|
||||||
// Check for potential filters
|
// Check for potential filters
|
||||||
|
@ -224,13 +224,16 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
|
|||||||
update() {
|
update() {
|
||||||
this.staleAreaWatcher.update();
|
this.staleAreaWatcher.update();
|
||||||
|
|
||||||
|
const sender = enumUndergroundBeltMode.sender;
|
||||||
|
const now = this.root.time.now();
|
||||||
|
|
||||||
for (let i = 0; i < this.allEntities.length; ++i) {
|
for (let i = 0; i < this.allEntities.length; ++i) {
|
||||||
const entity = this.allEntities[i];
|
const entity = this.allEntities[i];
|
||||||
const undergroundComp = entity.components.UndergroundBelt;
|
const undergroundComp = entity.components.UndergroundBelt;
|
||||||
if (undergroundComp.mode === enumUndergroundBeltMode.sender) {
|
if (undergroundComp.mode === sender) {
|
||||||
this.handleSender(entity);
|
this.handleSender(entity);
|
||||||
} else {
|
} else {
|
||||||
this.handleReceiver(entity);
|
this.handleReceiver(entity, now);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -327,14 +330,15 @@ export class UndergroundBeltSystem extends GameSystemWithFilter {
|
|||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {Entity} entity
|
* @param {Entity} entity
|
||||||
|
* @param {number} now
|
||||||
*/
|
*/
|
||||||
handleReceiver(entity) {
|
handleReceiver(entity, now) {
|
||||||
const undergroundComp = entity.components.UndergroundBelt;
|
const undergroundComp = entity.components.UndergroundBelt;
|
||||||
|
|
||||||
// Try to eject items, we only check the first one because it is sorted by remaining time
|
// Try to eject items, we only check the first one because it is sorted by remaining time
|
||||||
const nextItemAndDuration = undergroundComp.pendingItems[0];
|
const nextItemAndDuration = undergroundComp.pendingItems[0];
|
||||||
if (nextItemAndDuration) {
|
if (nextItemAndDuration) {
|
||||||
if (this.root.time.now() > nextItemAndDuration[1]) {
|
if (now > nextItemAndDuration[1]) {
|
||||||
const ejectorComp = entity.components.ItemEjector;
|
const ejectorComp = entity.components.ItemEjector;
|
||||||
|
|
||||||
const nextSlotIndex = ejectorComp.getFirstFreeSlot();
|
const nextSlotIndex = ejectorComp.getFirstFreeSlot();
|
||||||
|
1208
translations/base-he.yml
Normal file
1208
translations/base-he.yml
Normal file
File diff suppressed because it is too large
Load Diff
Loading…
Reference in New Issue
Block a user