├── babel.config.js
├── .prettierrc
├── README.assets
└── index.png
├── src
├── assets
│ └── images
│ │ ├── lab.png
│ │ ├── gitee.png
│ │ ├── lab-2.png
│ │ ├── piler.png
│ │ ├── belt-1.png
│ │ ├── belt-2.png
│ │ ├── belt-3.png
│ │ ├── bilibili.png
│ │ ├── github.png
│ │ ├── monitor.png
│ │ ├── smelter.png
│ │ ├── fuel-plant.png
│ │ ├── inserter-1.png
│ │ ├── inserter-2.png
│ │ ├── inserter-3.png
│ │ ├── inserter-4.png
│ │ ├── smelter-2.png
│ │ ├── smelter-3.png
│ │ ├── storage-1.png
│ │ ├── storage-2.png
│ │ ├── tesla-coil.png
│ │ ├── water-pump.png
│ │ ├── accumulator.png
│ │ ├── assembler-1.png
│ │ ├── assembler-2.png
│ │ ├── assembler-3.png
│ │ ├── assembler-4.png
│ │ ├── battle-base.png
│ │ ├── charging-pole.png
│ │ ├── fractionator.png
│ │ ├── mining-drill.png
│ │ ├── oil-extractor.png
│ │ ├── oil-refinery.png
│ │ ├── ray-receiver.png
│ │ ├── solar-panel.png
│ │ ├── splitter-4dir.png
│ │ ├── spray-coater.png
│ │ ├── storage-tank.png
│ │ ├── terrain-tool.png
│ │ ├── turret-cannon.png
│ │ ├── turret-gauss.png
│ │ ├── turret-laser.png
│ │ ├── turret-plasma.png
│ │ ├── turret-shield.png
│ │ ├── turret-signal.png
│ │ ├── wind-turbine.png
│ │ ├── chemical-plant.png
│ │ ├── em-rail-ejector.png
│ │ ├── fusion-reactor.png
│ │ ├── hadron-collider.png
│ │ ├── turret-disturb.png
│ │ ├── turret-missile.png
│ │ ├── accumulator-full.png
│ │ ├── energy-exchanger.png
│ │ ├── logistic-station.png
│ │ ├── mining-drill-mk2.png
│ │ ├── orbital-collector.png
│ │ ├── orbital-substation.png
│ │ ├── fusion-power-station.png
│ │ ├── turret-plasma-ground.png
│ │ ├── logistics-distributor.png
│ │ ├── quantum-chemical-plant.png
│ │ ├── vertical-launching-silo.png
│ │ ├── geothermal-power-station.png
│ │ └── interstellar-logistic-station.png
├── main.js
├── utils
│ ├── paramParser
│ │ ├── paramOptions
│ │ │ ├── paramOpt.js
│ │ │ ├── funParamOpt.js
│ │ │ ├── enumParamOpt.js
│ │ │ └── boolParamOpt.js
│ │ ├── defaultParamParser.js
│ │ ├── paramParser.js
│ │ └── paramParserFactory.js
│ ├── index.js
│ ├── md5.js
│ ├── itemsUtil.js
│ └── parser.js
├── App.vue
├── components
│ ├── ScrollCardItem.vue
│ └── ScrollCard.vue
└── data
│ └── itemsData.js
├── jsconfig.json
├── .gitignore
├── package.json
├── vue.config.js
├── public
└── index.html
├── LICENSE
└── README.md
/babel.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | presets: [
3 | '@vue/cli-plugin-babel/preset'
4 | ]
5 | }
6 |
--------------------------------------------------------------------------------
/.prettierrc:
--------------------------------------------------------------------------------
1 | {
2 | "singleQuote": false,
3 | "semi": true,
4 | "printWidth": 100,
5 | "tabWidth": 2
6 | }
--------------------------------------------------------------------------------
/README.assets/index.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/README.assets/index.png
--------------------------------------------------------------------------------
/src/assets/images/lab.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/lab.png
--------------------------------------------------------------------------------
/src/assets/images/gitee.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/gitee.png
--------------------------------------------------------------------------------
/src/assets/images/lab-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/lab-2.png
--------------------------------------------------------------------------------
/src/assets/images/piler.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/piler.png
--------------------------------------------------------------------------------
/src/assets/images/belt-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/belt-1.png
--------------------------------------------------------------------------------
/src/assets/images/belt-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/belt-2.png
--------------------------------------------------------------------------------
/src/assets/images/belt-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/belt-3.png
--------------------------------------------------------------------------------
/src/assets/images/bilibili.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/bilibili.png
--------------------------------------------------------------------------------
/src/assets/images/github.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/github.png
--------------------------------------------------------------------------------
/src/assets/images/monitor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/monitor.png
--------------------------------------------------------------------------------
/src/assets/images/smelter.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/smelter.png
--------------------------------------------------------------------------------
/src/assets/images/fuel-plant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/fuel-plant.png
--------------------------------------------------------------------------------
/src/assets/images/inserter-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/inserter-1.png
--------------------------------------------------------------------------------
/src/assets/images/inserter-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/inserter-2.png
--------------------------------------------------------------------------------
/src/assets/images/inserter-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/inserter-3.png
--------------------------------------------------------------------------------
/src/assets/images/inserter-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/inserter-4.png
--------------------------------------------------------------------------------
/src/assets/images/smelter-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/smelter-2.png
--------------------------------------------------------------------------------
/src/assets/images/smelter-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/smelter-3.png
--------------------------------------------------------------------------------
/src/assets/images/storage-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/storage-1.png
--------------------------------------------------------------------------------
/src/assets/images/storage-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/storage-2.png
--------------------------------------------------------------------------------
/src/assets/images/tesla-coil.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/tesla-coil.png
--------------------------------------------------------------------------------
/src/assets/images/water-pump.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/water-pump.png
--------------------------------------------------------------------------------
/src/assets/images/accumulator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/accumulator.png
--------------------------------------------------------------------------------
/src/assets/images/assembler-1.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/assembler-1.png
--------------------------------------------------------------------------------
/src/assets/images/assembler-2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/assembler-2.png
--------------------------------------------------------------------------------
/src/assets/images/assembler-3.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/assembler-3.png
--------------------------------------------------------------------------------
/src/assets/images/assembler-4.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/assembler-4.png
--------------------------------------------------------------------------------
/src/assets/images/battle-base.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/battle-base.png
--------------------------------------------------------------------------------
/src/assets/images/charging-pole.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/charging-pole.png
--------------------------------------------------------------------------------
/src/assets/images/fractionator.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/fractionator.png
--------------------------------------------------------------------------------
/src/assets/images/mining-drill.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/mining-drill.png
--------------------------------------------------------------------------------
/src/assets/images/oil-extractor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/oil-extractor.png
--------------------------------------------------------------------------------
/src/assets/images/oil-refinery.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/oil-refinery.png
--------------------------------------------------------------------------------
/src/assets/images/ray-receiver.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/ray-receiver.png
--------------------------------------------------------------------------------
/src/assets/images/solar-panel.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/solar-panel.png
--------------------------------------------------------------------------------
/src/assets/images/splitter-4dir.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/splitter-4dir.png
--------------------------------------------------------------------------------
/src/assets/images/spray-coater.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/spray-coater.png
--------------------------------------------------------------------------------
/src/assets/images/storage-tank.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/storage-tank.png
--------------------------------------------------------------------------------
/src/assets/images/terrain-tool.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/terrain-tool.png
--------------------------------------------------------------------------------
/src/assets/images/turret-cannon.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-cannon.png
--------------------------------------------------------------------------------
/src/assets/images/turret-gauss.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-gauss.png
--------------------------------------------------------------------------------
/src/assets/images/turret-laser.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-laser.png
--------------------------------------------------------------------------------
/src/assets/images/turret-plasma.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-plasma.png
--------------------------------------------------------------------------------
/src/assets/images/turret-shield.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-shield.png
--------------------------------------------------------------------------------
/src/assets/images/turret-signal.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-signal.png
--------------------------------------------------------------------------------
/src/assets/images/wind-turbine.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/wind-turbine.png
--------------------------------------------------------------------------------
/src/assets/images/chemical-plant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/chemical-plant.png
--------------------------------------------------------------------------------
/src/assets/images/em-rail-ejector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/em-rail-ejector.png
--------------------------------------------------------------------------------
/src/assets/images/fusion-reactor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/fusion-reactor.png
--------------------------------------------------------------------------------
/src/assets/images/hadron-collider.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/hadron-collider.png
--------------------------------------------------------------------------------
/src/assets/images/turret-disturb.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-disturb.png
--------------------------------------------------------------------------------
/src/assets/images/turret-missile.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-missile.png
--------------------------------------------------------------------------------
/src/assets/images/accumulator-full.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/accumulator-full.png
--------------------------------------------------------------------------------
/src/assets/images/energy-exchanger.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/energy-exchanger.png
--------------------------------------------------------------------------------
/src/assets/images/logistic-station.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/logistic-station.png
--------------------------------------------------------------------------------
/src/assets/images/mining-drill-mk2.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/mining-drill-mk2.png
--------------------------------------------------------------------------------
/src/assets/images/orbital-collector.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/orbital-collector.png
--------------------------------------------------------------------------------
/src/assets/images/orbital-substation.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/orbital-substation.png
--------------------------------------------------------------------------------
/src/assets/images/fusion-power-station.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/fusion-power-station.png
--------------------------------------------------------------------------------
/src/assets/images/turret-plasma-ground.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/turret-plasma-ground.png
--------------------------------------------------------------------------------
/src/assets/images/logistics-distributor.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/logistics-distributor.png
--------------------------------------------------------------------------------
/src/assets/images/quantum-chemical-plant.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/quantum-chemical-plant.png
--------------------------------------------------------------------------------
/src/assets/images/vertical-launching-silo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/vertical-launching-silo.png
--------------------------------------------------------------------------------
/src/assets/images/geothermal-power-station.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/geothermal-power-station.png
--------------------------------------------------------------------------------
/src/assets/images/interstellar-logistic-station.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/cying314/edit-dspblue-print/HEAD/src/assets/images/interstellar-logistic-station.png
--------------------------------------------------------------------------------
/jsconfig.json:
--------------------------------------------------------------------------------
1 | {
2 | "compilerOptions": {
3 | "baseUrl": "./",
4 | "paths": {
5 | "@/*": ["src/*"]
6 | }
7 | },
8 | "exclude": ["node_modules", "dist", "static", "public"]
9 | }
10 |
--------------------------------------------------------------------------------
/src/main.js:
--------------------------------------------------------------------------------
1 | import Vue from 'vue';
2 | import ElementUI from 'element-ui';
3 | import 'element-ui/lib/theme-chalk/index.css';
4 | import App from './App.vue';
5 |
6 | Vue.config.productionTip = false
7 |
8 | Vue.use(ElementUI);
9 |
10 | new Vue({
11 | render: h => h(App)
12 | }).$mount('#app')
13 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | node_modules
3 | /dist
4 | /history
5 |
6 |
7 | # local env files
8 | .env.local
9 | .env.*.local
10 |
11 | # Log files
12 | npm-debug.log*
13 | yarn-debug.log*
14 | yarn-error.log*
15 | pnpm-debug.log*
16 |
17 | # Editor directories and files
18 | .idea
19 | .vscode
20 | *.suo
21 | *.ntvs*
22 | *.njsproj
23 | *.sln
24 | *.sw?
25 |
--------------------------------------------------------------------------------
/src/utils/paramParser/paramOptions/paramOpt.js:
--------------------------------------------------------------------------------
1 | /**
2 | * 建筑参数配置
3 | */
4 | export default class ParamOpt {
5 | /**
6 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
7 | */
8 | constructor(pos) {
9 | this.pos = pos;
10 | }
11 | /**
12 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
13 | */
14 | static of(pos) {
15 | return new ParamOpt(pos);
16 | }
17 | /**
18 | * @param {DataView} v
19 | * @param value 属性值
20 | */
21 | setParam(v, value) {
22 | let pos = typeof this.pos === 'function' ? this.pos(v) : this.pos; // 若pos为函数则动态获取
23 | setParam(v, pos, value);
24 | }
25 | /**
26 | * @param {DataView} v
27 | */
28 | getParam(v) {
29 | let pos = typeof this.pos === 'function' ? this.pos(v) : this.pos; // 若pos为函数则动态获取
30 | return getParam(v, pos);
31 | }
32 | }
33 |
34 | export function setParam(v, pos, value) {
35 | v.setInt32(pos * Int32Array.BYTES_PER_ELEMENT, value, true);
36 | }
37 |
38 | export function getParam(v, pos) {
39 | return v.getInt32(pos * Int32Array.BYTES_PER_ELEMENT, true);
40 | }
--------------------------------------------------------------------------------
/src/utils/paramParser/paramOptions/funParamOpt.js:
--------------------------------------------------------------------------------
1 | import ParamOpt from "./paramOpt";
2 | /**
3 | * 自定义转换方法 建筑参数配置
4 | */
5 | export default class FunParamOpt extends ParamOpt {
6 | /**
7 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
8 | * @param {Function} encode 编码转换方法(对象值->原始值)
9 | * @param {Function} decode 解码转换方法(原始值->对象值)
10 | */
11 | constructor(pos, encode, decode) {
12 | super(pos);
13 | this.encode = encode;
14 | this.decode = decode;
15 | }
16 | /**
17 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
18 | * @param {Function} encode 编码转换方法(对象值->原始值)
19 | * @param {Function} decode 解码转换方法(原始值->对象值)
20 | */
21 | static of(pos, encode, decode) {
22 | return new FunParamOpt(pos, encode, decode);
23 | }
24 | /**
25 | * @param {DataView} v
26 | * @param value 属性值
27 | */
28 | setParam(v, value) {
29 | // 编码转为原始值
30 | super.setParam(v, this.encode(value, v));
31 | }
32 | /**
33 | * @param {DataView} v
34 | */
35 | getParam(v) {
36 | // 解码转换
37 | return this.decode(super.getParam(v), v);
38 | }
39 | }
--------------------------------------------------------------------------------
/src/utils/paramParser/defaultParamParser.js:
--------------------------------------------------------------------------------
1 | import { setParam, getParam } from "./paramOptions/paramOpt";
2 | /**
3 | * 默认建筑参数解析器
4 | */
5 | export default class DefaultParamParser {
6 | /**
7 | * 获取参数长度(每单位:4字节)
8 | * @param {Object} p 建筑参数
9 | */
10 | getLength(p) {
11 | if (p._defaultParams instanceof Int32Array) {
12 | return p._defaultParams.length;
13 | } if (p._defaultParams) {
14 | return Object.keys(p._defaultParams).length;
15 | } else {
16 | return 0;
17 | }
18 | }
19 | /**
20 | * @param {Object} p 建筑参数
21 | * @param {DataView} v
22 | */
23 | encode(p, v) {
24 | for (let i = 0; i < this.getLength(p); i++) {
25 | setParam(v, i, p._defaultParams[i]);
26 | }
27 | }
28 | /**
29 | * @param {DataView} v
30 | * @return {Object} 建筑参数
31 | */
32 | decode(v) {
33 | const p = {
34 | _defaultParams: new Int32Array(v.byteLength / Int32Array.BYTES_PER_ELEMENT),
35 | };
36 | for (let i = 0; i < p._defaultParams.length; i++) {
37 | p._defaultParams[i] = getParam(v, i);
38 | }
39 | return p;
40 | }
41 | }
--------------------------------------------------------------------------------
/package.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "edit_dsp_blueprint",
3 | "version": "0.1.0",
4 | "private": true,
5 | "scripts": {
6 | "serve": "vue-cli-service serve",
7 | "build": "vue-cli-service build",
8 | "lint": "vue-cli-service lint"
9 | },
10 | "dependencies": {
11 | "core-js": "^3.6.5",
12 | "element-ui": "^2.15.5",
13 | "file-saver": "^2.0.5",
14 | "pako": "^2.0.4",
15 | "sass": "^1.69.5",
16 | "sass-loader": "^8.0.2",
17 | "vue": "^2.6.11"
18 | },
19 | "devDependencies": {
20 | "@vue/cli-plugin-babel": "~4.5.0",
21 | "@vue/cli-plugin-eslint": "~4.5.0",
22 | "@vue/cli-plugin-router": "~4.5.0",
23 | "@vue/cli-service": "~4.5.0",
24 | "babel-eslint": "^10.1.0",
25 | "eslint": "^6.7.2",
26 | "eslint-plugin-vue": "^6.2.2",
27 | "html-webpack-inline-source-plugin": "^0.0.10",
28 | "vue-template-compiler": "^2.6.11"
29 | },
30 | "eslintConfig": {
31 | "root": true,
32 | "env": {
33 | "node": true
34 | },
35 | "extends": [
36 | "plugin:vue/essential",
37 | "eslint:recommended"
38 | ],
39 | "parserOptions": {
40 | "parser": "babel-eslint"
41 | },
42 | "rules": {}
43 | },
44 | "browserslist": [
45 | "> 1%",
46 | "last 2 versions",
47 | "not dead"
48 | ]
49 | }
50 |
--------------------------------------------------------------------------------
/src/utils/paramParser/paramOptions/enumParamOpt.js:
--------------------------------------------------------------------------------
1 | import ParamOpt from "./paramOpt";
2 | /**
3 | * 枚举 建筑参数配置
4 | */
5 | export default class EnumParamOpt extends ParamOpt {
6 | /**
7 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
8 | * @param {Map} enumMap 枚举Map
9 | */
10 | constructor(pos, enumMap) {
11 | super(pos);
12 | this.enumMap = enumMap;
13 | }
14 | /**
15 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
16 | * @param {Map} enumMap 枚举Map
17 | */
18 | static of(pos, enumMap) {
19 | return new EnumParamOpt(pos, enumMap);
20 | }
21 | /**
22 | * @param {DataView} v
23 | * @param value 属性值
24 | */
25 | setParam(v, value) {
26 | // 从枚举值转回原始值
27 | const et = this.enumMap.entries();
28 | while (!et.done) {
29 | if (value === et.value[1]) {
30 | value = et.value[0];
31 | break;
32 | }
33 | }
34 | super.setParam(v, value);
35 | }
36 | /**
37 | * @param {DataView} v
38 | */
39 | getParam(v) {
40 | let value = super.getParam(v);
41 | // 转为枚举值
42 | if (this.enumMap.has(value)) {
43 | value = this.enumMap.get(value);
44 | }
45 | return value;
46 | }
47 | }
--------------------------------------------------------------------------------
/src/utils/paramParser/paramOptions/boolParamOpt.js:
--------------------------------------------------------------------------------
1 | import ParamOpt from "./paramOpt";
2 | /**
3 | * 布尔 建筑参数配置
4 | */
5 | export default class BoolParamOpt extends ParamOpt {
6 | /**
7 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
8 | * @param {Number} trueValue true对应的值(默认1)
9 | * @param {Number} falseValue false对应的值(默认-1)
10 | */
11 | constructor(pos, trueValue = 1, falseValue = -1) {
12 | super(pos);
13 | this.trueValue = trueValue;
14 | this.falseValue = falseValue;
15 | }
16 | /**
17 | * @param {Number | Function} pos 参数相对位置(在DataView中的字节偏移量/4)
18 | * @param {Number} trueValue true对应的值(默认1)
19 | * @param {Number} falseValue false对应的值(默认-1)
20 | */
21 | static of(pos, trueValue = 1, falseValue = -1) {
22 | return new BoolParamOpt(pos, trueValue, falseValue);
23 | }
24 | /**
25 | * @param {DataView} v
26 | * @param value 属性值
27 | */
28 | setParam(v, value) {
29 | // 从布尔值转回原始值
30 | if (value === true) {
31 | value = this.trueValue;
32 | } else if (value === false) {
33 | value = this.falseValue;
34 | }
35 | super.setParam(v, value);
36 | }
37 | /**
38 | * @param {DataView} v
39 | */
40 | getParam(v) {
41 | let value = super.getParam(v);
42 | // 转为布尔值
43 | if (value === this.trueValue) {
44 | value = true;
45 | } else if (value === this.falseValue) {
46 | value = false;
47 | }
48 | return value;
49 | }
50 | }
--------------------------------------------------------------------------------
/vue.config.js:
--------------------------------------------------------------------------------
1 | module.exports = {
2 | publicPath: './',
3 | productionSourceMap: false,
4 | outputDir: "dist",
5 | chainWebpack: config => {
6 | config.module
7 | .rule('images')
8 | .test(/\.(png|jpe?g|gif|webp|bmp)$/)
9 | .use('url-loader')
10 | .loader('url-loader')
11 | .tap(options => Object.assign(options, { limit: 500000 }))
12 | config.module
13 | .rule('fonts')
14 | .test(/\.(ttf|woff)$/)
15 | .use('url-loader')
16 | .loader('url-loader')
17 | .tap(options => Object.assign(options, { limit: 500000 }))
18 | config.plugin('preload')
19 | .tap(args => {
20 | args[0].fileBlacklist.push(/\.css/, /\.js/)
21 | return args
22 | })
23 | config.plugin('inline-source')
24 | .use(require('html-webpack-inline-source-plugin'))
25 | config
26 | .plugin('html')
27 | .tap(args => {
28 | args[0].inlineSource = '(\.css|\.js$)'
29 | return args
30 | })
31 | config.optimization.minimizer('terser').tap((args) => {
32 | args[0].terserOptions.compress.drop_console = true //删除打印
33 | args[0].terserOptions.compress.drop_debugger = true
34 | args[0].terserOptions.compress.pure_funcs = ['console.log'] // 移除console.log方法
35 | args[0].terserOptions.output = { comments: false } //删除所有注释
36 | args[0].extractComments = false //是否将注释全部集中到一个文件中
37 | return args
38 | })
39 | }
40 | }
--------------------------------------------------------------------------------
/src/App.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
63 |
69 |
--------------------------------------------------------------------------------
/src/utils/paramParser/paramParser.js:
--------------------------------------------------------------------------------
1 | import DefaultParamParser from "./defaultParamParser";
2 | import ParamOpt from "./paramOptions/paramOpt";
3 |
4 | /**
5 | * 建筑参数解析器
6 | */
7 | export default class ParamParser extends DefaultParamParser {
8 | /**
9 | * @param {Number} size 参数长度(每单位:4字节)
10 | * @param {Object} params 参数模板 {
11 | * ...key: @param {ParamOpt} 建筑参数配置
12 | * }
13 | */
14 | constructor(size, params) {
15 | super();
16 | this.size = size;
17 | this.params = params;
18 | }
19 | /**
20 | * 获取参数长度(每单位:4字节)
21 | * @param {Object} p 建筑参数
22 | */
23 | getLength(p) {
24 | if (!this.size) return super.getLength(p);
25 | return this.size;
26 | }
27 | /**
28 | * @param {Object} p 建筑参数
29 | * @param {DataView} v
30 | */
31 | encode(p, v) {
32 | if (!this.params) return super.encode(p, v);
33 | deepEncode(this.params, p, v);
34 | }
35 | /**
36 | * @param {DataView} v
37 | * @return {Object} 建筑参数
38 | */
39 | decode(v) {
40 | if (!this.params) return super.decode(v);
41 | return deepDecode(this.params, v);
42 | }
43 | }
44 |
45 | /**
46 | * 递归遍历参数模板对象,将建筑参数 解析回 字节数据
47 | * @param _params 参数模板
48 | * @param _pValue 建筑参数
49 | * @param {DataView} v
50 | */
51 | function deepEncode(_params, _pValue, v) {
52 | if (_params === null || typeof _params !== "object") {
53 | return;
54 | }
55 | if (_params instanceof ParamOpt) {
56 | return _params.setParam(v, _pValue);
57 | }
58 | for (var key in _params) {
59 | if (Object.prototype.hasOwnProperty.call(_params, key)) {
60 | if (_pValue === null || typeof _pValue !== "object") {
61 | deepEncode(_params[key], null, v);
62 | } else {
63 | deepEncode(_params[key], _pValue[key], v);
64 | }
65 | }
66 | }
67 | }
68 |
69 | /**
70 | * 递归遍历参数模板对象,从字节数据中 解析出 实际的建筑参数
71 | * @param _params 参数模板
72 | * @param {DataView} v
73 | * @return {Object} 建筑参数
74 | */
75 | function deepDecode(_params, v) {
76 | if (_params === null || typeof _params !== "object") {
77 | return _params;
78 | }
79 | if (_params instanceof ParamOpt) {
80 | return _params.getParam(v);
81 | }
82 | var p = Array.isArray(_params) ? [] : {};
83 | for (var key in _params) {
84 | if (Object.prototype.hasOwnProperty.call(_params, key)) {
85 | p[key] = deepDecode(_params[key], v);
86 | }
87 | }
88 | return p;
89 | }
--------------------------------------------------------------------------------
/src/utils/index.js:
--------------------------------------------------------------------------------
1 | import { Notification, Message, MessageBox } from "element-ui";
2 |
3 | /**
4 | * 使元素动画滚动到指定高度
5 | * @param {Element} element 滚动元素
6 | * @param {number} targetScrollTop 目标高度
7 | * @param {function} callback 完成滚动回调
8 | * @param {number} duration 滚动动画时间(默认300ms)
9 | * @param {number} moveInterval 滚动移动间隔(默认10ms)
10 | * @return {{stop:function}} 返回动画帧定时器绑定对象,调用stop可停止动画
11 | */
12 | export function elementScrollTo(
13 | element,
14 | targetScrollTop,
15 | callback,
16 | duration = 300,
17 | moveInterval = 10
18 | ) {
19 | targetScrollTop = Math.max(0, targetScrollTop);
20 | let curScrollTop = element.scrollTop; // 当前scrollTop
21 | let distance = targetScrollTop - curScrollTop; //滚动距离
22 | let step = Math.round(distance / (duration / moveInterval)); // 步进,将距离细分为n小段,10ms滚动一次
23 | if (step == 0) {
24 | if (distance < 0) step = -1;
25 | else step = 1;
26 | }
27 | let bind = {
28 | _scrollTimer: null,
29 | stop() {
30 | clearTimeout(this._scrollTimer);
31 | },
32 | };
33 | startAnimation();
34 | function startAnimation() {
35 | // 距离目标小于步进时,直接到达终点
36 | if (Math.abs(targetScrollTop - curScrollTop) <= Math.abs(step)) {
37 | element.scrollTop = targetScrollTop;
38 | if (callback && typeof callback === "function") {
39 | callback();
40 | }
41 | } else {
42 | curScrollTop += step;
43 | element.scrollTop = curScrollTop;
44 | bind._scrollTimer = setTimeout(() => startAnimation(), 10);
45 | }
46 | }
47 | return bind;
48 | }
49 |
50 | /**
51 | * 成功信息
52 | */
53 | export function _success(mes) {
54 | Message({
55 | message: mes,
56 | type: "success",
57 | duration: 1000,
58 | });
59 | }
60 |
61 | /**
62 | * 警告信息
63 | */
64 | export function _warn(mes) {
65 | Message({
66 | message: mes,
67 | type: "warning",
68 | });
69 | }
70 |
71 | /**
72 | * 异常信息
73 | */
74 | export function _err(mes, e) {
75 | console.error(mes, e);
76 | Notification({
77 | title: "错误",
78 | message: mes + " " + e,
79 | type: "error",
80 | });
81 | }
82 |
83 | /**
84 | * 弹窗html内容提示确认
85 | */
86 | export function _confirmHtml(html, otherOption = {}) {
87 | return MessageBox.confirm(html, "提示", {
88 | confirmButtonText: "确定",
89 | cancelButtonText: "取消",
90 | type: "warning",
91 | dangerouslyUseHTMLString: true, // 渲染html
92 | ...otherOption,
93 | });
94 | }
95 |
96 | /**
97 | * 弹窗输入框提示确认
98 | * @param {string} title 输入框标题
99 | * @param {string} inputValue 输入框默认内容
100 | * @param {object} otherOption 其他MessageBox.prompt option参数
101 | */
102 | export function _prompt(title, inputValue, otherOption = {}) {
103 | return MessageBox.prompt(title, "提示", {
104 | confirmButtonText: "确定",
105 | cancelButtonText: "取消",
106 | inputValue,
107 | ...otherOption,
108 | }).then(({ value }) => value);
109 | }
110 |
--------------------------------------------------------------------------------
/src/utils/md5.js:
--------------------------------------------------------------------------------
1 | const K = Int32Array.of(0xd76aa478, 0xe8d7b756, 0x242070db, 0xc1bdceee, 0xf57c0faf, 0x4787c62a, 0xa8304623, 0xfd469501, 0x698098d8, 0x8b44f7af, 0xffff5bb1, 0x895cd7be, 0x6b9f1122, 0xfd987193, 0xa679438e, 0x39b40821, 0xf61e2562, 0xc040b340, 0x265e5a51, 0xc9b6c7aa, 0xd62f105d, 0x02443453, 0xd8a1e681, 0xe7d3fbc8, 0x21f1cde6, 0xc33707d6, 0xf4d50d87, 0x475a14ed, 0xa9e3e905, 0xfcefa3f8, 0x676f02d9, 0x8d2a4c8a, 0xfffa3942, 0x8771f681, 0x6d9d6122, 0xfde5380c, 0xa4beea44, 0x4bdecfa9, 0xf6bb4b60, 0xbebfbc70, 0x289b7ec6, 0xeaa127fa, 0xd4ef3085, 0x04881d05, 0xd9d4d039, 0xe6db99e5, 0x1fa27cf8, 0xc4ac5665, 0xf4292244, 0x432aff97, 0xab9423a7, 0xfc93a039, 0x655b59c3, 0x8f0ccc92, 0xffeff47d, 0x85845dd1, 0x6fa87e4f, 0xfe2ce6e0, 0xa3014314, 0x4e0811a1, 0xf7537e82, 0xbd3af235, 0x2ad7d2bb, 0xeb86d391);
2 | const S = Uint8Array.of(7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 7, 12, 17, 22, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 5, 9, 14, 20, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 4, 11, 16, 23, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21, 6, 10, 15, 21);
3 | const INIT_MD5F = new DataView(Uint8Array.of(0x01, 0x23, 0x45, 0x67, 0x89, 0xab, 0xdc, 0xef, 0xfe, 0xdc, 0xba, 0x98, 0x46, 0x57, 0x32, 0x10).buffer);
4 | const MASK32 = -1;
5 | function rotateLeft(x, s) {
6 | return ((x << s) | (x >>> (32 - s))) & MASK32;
7 | }
8 | function updateBlock(s, buf) {
9 | let a = s[0];
10 | let b = s[1];
11 | let c = s[2];
12 | let d = s[3];
13 | for (let i = 0; i < 64; i++) {
14 | let f, g;
15 | if (i < 16) {
16 | f = (b & c) | (~b & d);
17 | g = i;
18 | }
19 | else if (i < 32) {
20 | f = (d & b) | (~d & c);
21 | g = (5 * i + 1) % 16;
22 | }
23 | else if (i < 48) {
24 | f = b ^ c ^ d;
25 | g = (3 * i + 5) % 16;
26 | }
27 | else {
28 | f = c ^ (b | ~d);
29 | g = (7 * i) % 16;
30 | }
31 | f = (f + a + K[i] + buf.getInt32(g * Int32Array.BYTES_PER_ELEMENT, true)) & MASK32;
32 | a = d;
33 | d = c;
34 | c = b;
35 | b = b + rotateLeft(f, S[i]);
36 | }
37 | s[0] = (s[0] + a) & MASK32;
38 | s[1] = (s[1] + b) & MASK32;
39 | s[2] = (s[2] + c) & MASK32;
40 | s[3] = (s[3] + d) & MASK32;
41 | }
42 | const BLOCK_SIZE = 64;
43 | export function digest(data) {
44 | const s = Int32Array.of(INIT_MD5F.getInt32(0 * Int32Array.BYTES_PER_ELEMENT, true), INIT_MD5F.getInt32(1 * Int32Array.BYTES_PER_ELEMENT, true), INIT_MD5F.getInt32(2 * Int32Array.BYTES_PER_ELEMENT, true), INIT_MD5F.getInt32(3 * Int32Array.BYTES_PER_ELEMENT, true));
45 | let i = 0;
46 | for (; i <= data.byteLength - BLOCK_SIZE; i += BLOCK_SIZE) {
47 | updateBlock(s, new DataView(data, i, BLOCK_SIZE));
48 | }
49 | const last = new ArrayBuffer(Math.ceil((data.byteLength - i + 9) / BLOCK_SIZE) * BLOCK_SIZE);
50 | const dataView = new Uint8Array(data);
51 | const lastView = new DataView(last);
52 | let j = 0;
53 | for (; i + j < data.byteLength; j++) {
54 | lastView.setUint8(j, dataView[i + j]);
55 | }
56 | lastView.setUint8(j, 0x80);
57 | lastView.setUint32(last.byteLength - 8, data.byteLength * 8, true);
58 | for (i = 0; i <= last.byteLength - BLOCK_SIZE; i += BLOCK_SIZE) {
59 | updateBlock(s, new DataView(last, i, BLOCK_SIZE));
60 | }
61 | const result = new ArrayBuffer(16);
62 | const resultView = new DataView(result);
63 | for (let i = 0; i < s.length; i++) {
64 | resultView.setInt32(i * Int32Array.BYTES_PER_ELEMENT, s[i], true);
65 | }
66 | return result;
67 | }
--------------------------------------------------------------------------------
/src/components/ScrollCardItem.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
16 |
17 |
18 |
19 |
20 |
21 |
103 |
104 |
--------------------------------------------------------------------------------
/public/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 |
7 |
8 | DSP蓝图变换工具v5.8
9 |
10 |
11 |
14 |
15 |
16 |
17 |
18 |
--------------------------------------------------------------------------------
/src/components/ScrollCard.vue:
--------------------------------------------------------------------------------
1 |
2 |
3 |
26 |
27 |
28 |
146 |
147 |
--------------------------------------------------------------------------------
/src/utils/itemsUtil.js:
--------------------------------------------------------------------------------
1 | import { items } from "@/data/itemsData";
2 | export const itemsMap = new Map();
3 | for (const i of items) {
4 | itemsMap.set(i.id, i);
5 | }
6 |
7 | /** 传送带类 建筑id */
8 | export const beltBuildIds = new Set([
9 | 2001, // 传送带
10 | 2002, // 高速传送带
11 | 2003, // 极速传送带
12 | ]);
13 |
14 | /** 是否 传送带 */
15 | export function isBelt(id) { return beltBuildIds.has(id); }
16 |
17 | /** 分拣器类 建筑id */
18 | export const inserterBuildIds = new Set([
19 | 2011, // 分拣器
20 | 2012, // 高速分拣器
21 | 2013, // 极速分拣器
22 | 2014, // 集装分拣器
23 | ]);
24 |
25 | /** 是否 分拣器 */
26 | export function isInserter(id) { return inserterBuildIds.has(id); }
27 |
28 | /**
29 | * 获取分拣器速度
30 | * @param itemId 物品ID
31 | * @param length 分拣器长度(默认1)
32 | */
33 | export function getInserterSpeed(itemId, length) {
34 | if (itemId === 2014) {
35 | return 30; // 白爪不受长度影响
36 | }
37 | let speed;
38 | switch (itemId) {
39 | case 2011:
40 | speed = 1.5;
41 | break;
42 | case 2012:
43 | speed = 3;
44 | break;
45 | case 2013:
46 | speed = 6;
47 | break;
48 | }
49 | // 计入分拣器长度影响的速度
50 | return speed / (length || 1);
51 | }
52 |
53 | /** 制造厂类(需指定制造配方的建筑) 建筑id */
54 | export const assemblerBuildIds = new Set([
55 | 2303, // 制造台 Mk.I
56 | 2304, // 制造台 Mk.II
57 | 2305, // 制造台 Mk.III
58 | 2318, // 重组式制造台
59 | 2302, // 电弧熔炉
60 | 2315, // 位面熔炉
61 | 2319, // 负熵熔炉
62 | 2308, // 原油精炼厂
63 | 2309, // 化工厂
64 | 2317, // 量子化工厂
65 | 2310, // 微型粒子对撞机
66 | ]);
67 |
68 | /** 是否 制造厂类建筑(需指定制造配方的建筑) */
69 | export function isAssembler(id) { return assemblerBuildIds.has(id); }
70 |
71 | /** 是否 研究站 */
72 | export function isLab(id) { return id === 2901 || id === 2902; }
73 |
74 | /** 是否 运输站类建筑(物流运输站、大型采矿机) */
75 | export function isStation(id) { return id === 2103 || id === 2104 || id === 2316; }
76 |
77 | /** 可悬空建造 建筑id */
78 | export const hangingBuildIds = new Set([
79 | ...Array.from(beltBuildIds), // 传送带
80 | ...Array.from(inserterBuildIds), // 分拣器
81 | 2030, // 流速监测器
82 | 2313, // 喷涂机(不能用地基当底)
83 | ]);
84 |
85 | /** 是否 可悬空建造 */
86 | export function isHanging(id) { return hangingBuildIds.has(id); }
87 |
88 | /** 可堆叠建造 建筑id */
89 | export const stackableBuildIds = new Set([
90 | 2020, // 四向分流器
91 | 2040, // 自动集装器
92 | 2101, // 小型储物仓
93 | 2102, // 大型储物仓
94 | 2106, // 储液罐
95 | 2901, // 矩阵研究站
96 | 2902, // 自演化研究站
97 | 2313, // 喷涂机
98 | ]);
99 |
100 | /** 是否 可堆叠建造 */
101 | export function isStackable(id) { return stackableBuildIds.has(id); }
102 |
103 | /** 带分拣器插槽的建筑 翻转信息 */
104 | export const inserterSlotBuildInfos = {
105 | // axis:模型不旋转(yaw=0)时的对称轴方向(x纬线 y经线) alterSlot:翻转时需调换的插槽索引(y轴对称插槽)
106 | 2101: { // 小型储物仓
107 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
108 | },
109 | 2102: { // 大型储物仓
110 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
111 | },
112 | 2204: { // 火力发电厂
113 | axis: "y", alterSlot: [[0, 4], [1, 3]], // 2不对称
114 | },
115 | 2211: { // 微型聚变发电站
116 | axis: "y", alterSlot: [[0, 4], [1, 3]], // 2不对称
117 | },
118 | 2302: { // 电弧熔炉
119 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
120 | },
121 | 2315: { // 位面熔炉
122 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
123 | },
124 | 2319: { // 负熵熔炉
125 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
126 | },
127 | 2303: { // 制造台 Mk.I
128 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
129 | },
130 | 2304: { // 制造台 Mk.II
131 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
132 | },
133 | 2305: { // 制造台 Mk.III
134 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
135 | },
136 | 2318: { // 重组式制造台
137 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
138 | },
139 | 2308: { // 原油精炼厂
140 | axis: "y", alterSlot: [[0, 5], [1, 4], [2, 3], [6, 8]],
141 | },
142 | 2309: { // 化工厂
143 | axis: "x", alterSlot: [[0, 6], [1, 5], [2, 4], [3, 7]],
144 | },
145 | 2317: { // 量子化工厂
146 | axis: "x", alterSlot: [[0, 6], [1, 5], [2, 4], [3, 7]],
147 | },
148 | 2310: { // 微型粒子对撞机
149 | axis: "x", alterSlot: [[0, 8], [1, 7], [2, 6], [3, 5]],
150 | },
151 | 2311: { // 电磁轨道弹射器
152 | axis: "y", alterSlot: [[0, 1]],
153 | },
154 | 2210: { // 人造恒星
155 | axis: "y", alterSlot: [[1, 3]],
156 | },
157 | 2312: { // 垂直发射井
158 | axis: "y", alterSlot: [[1, 2]],
159 | },
160 | 2901: { // 矩阵研究站
161 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
162 | },
163 | 2902: { // 自演化研究站
164 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
165 | },
166 | 3009: { // 战场分析基站
167 | axis: "y", alterSlot: [[0, 8], [1, 7], [2, 6], [3, 5]],
168 | },
169 | };
170 |
171 |
172 | /** 是否 带分拣器插槽的建筑 */
173 | export function isInserterSlotBuild(id) { return Object.prototype.hasOwnProperty.call(inserterSlotBuildInfos, id); }
174 |
175 | /** 获取 带分拣器插槽的建筑 翻转信息 */
176 | export function getInserterSlotBuildInfo(id) { return inserterSlotBuildInfos[id] }
177 |
178 | /** 获取 带分拣器插槽的建筑 的对称方向 */
179 | export function getInserterSlotBuildAxis(id) { return getInserterSlotBuildInfo(id)?.axis }
180 |
181 | /**
182 | * 翻转调换 分拣器插槽索引
183 | * @param id 带分拣器插槽的建筑itemId
184 | * @param originSlot 原插槽索引
185 | */
186 | export function alterInserterSlot(id, originSlot) {
187 | const alterSlot = getInserterSlotBuildInfo(id)?.alterSlot;
188 | if (alterSlot) {
189 | for (let arr of alterSlot) {
190 | if (arr[0] == originSlot) return arr[1];
191 | if (arr[1] == originSlot) return arr[0];
192 | }
193 | }
194 | return null;
195 | }
196 |
197 | /** 带传送带插槽的建筑 翻转信息 */
198 | export const beltSlotBuildInfos = {
199 | // axis:模型不旋转(yaw=0)时的对称轴方向(x纬线 y经线) alterSlot:翻转时需调换的插槽索引(y轴对称插槽)
200 | 2020: { // 四向分流器
201 | multiModel: true,
202 | models: {
203 | 38: { // 十字单层
204 | axis: "y", alterSlot: [[1, 3]],
205 | },
206 | 39: { // 一字双层
207 | axis: "y", alterSlot: [],
208 | },
209 | 40: { // 十字双层
210 | axis: "y", alterSlot: [[1, 3]],
211 | }
212 | }
213 | },
214 | 2103: { // 行星内物流运输站
215 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
216 | },
217 | 2104: { // 星际物流运输站
218 | axis: "y", alterSlot: [[0, 2], [3, 11], [4, 10], [5, 9], [6, 8]],
219 | },
220 | 2316: { // 大型采矿机
221 | axis: "y", alterSlot: [[0, 2], [3, 8], [4, 7], [5, 6]],
222 | },
223 | }
224 |
225 | /** 是否 带传送带插槽的建筑 */
226 | export function isBeltSlotBuild(id) { return Object.prototype.hasOwnProperty.call(beltSlotBuildInfos, id); }
227 |
228 | /** 获取 传送带插槽的建筑 翻转信息 */
229 | export function getBeltSlotBuildInfo(id, modelIndex) {
230 | let item = beltSlotBuildInfos[id];
231 | if (item?.multiModel) return item.models[modelIndex];
232 | return item;
233 | }
234 |
235 | /** 获取 传送带插槽的建筑 的对称方向 */
236 | export function getBeltSlotBuildAxis(id, modelIndex) { return getBeltSlotBuildInfo(id, modelIndex)?.axis }
237 |
238 | /**
239 | * 翻转调换 传送带插槽索引
240 | * @param id 带传送带插槽的建筑itemId
241 | * @param modelIndex 模型索引
242 | * @param originSlot 原插槽索引
243 | */
244 | export function alterBeltSlot(id, modelIndex, originSlot) {
245 | const alterSlot = getBeltSlotBuildInfo(id, modelIndex)?.alterSlot;
246 | if (alterSlot) {
247 | for (let arr of alterSlot) {
248 | if (arr[0] == originSlot) return arr[1];
249 | if (arr[1] == originSlot) return arr[0];
250 | }
251 | }
252 | return null;
253 | }
254 |
255 | /** 炮台类 建筑id */
256 | export const turretBuildIds = new Set([
257 | 3001, // 高斯机枪塔
258 | 3002, // 高频激光塔
259 | 3003, // 聚爆加农炮
260 | 3004, // 磁化电浆炮
261 | 3005, // 导弹防御塔
262 | 3006, // 干扰塔
263 | 3010, // 近程电浆塔
264 | ]);
265 |
266 | /** 是否 炮台 */
267 | export function isTurret(id) { return turretBuildIds.has(id); }
--------------------------------------------------------------------------------
/src/data/itemsData.js:
--------------------------------------------------------------------------------
1 | export const items = [
2 | { id: 1131, models: [], name: "地基", icon: "terrain-tool" },
3 | { id: 2001, models: [35], name: "传送带", icon: "belt-1" },
4 | { id: 2002, models: [36], name: "高速传送带", icon: "belt-2" },
5 | { id: 2003, models: [37], name: "极速传送带", icon: "belt-3" },
6 | { id: 2011, models: [41], name: "分拣器", alias: "黄爪", icon: "inserter-1" },
7 | { id: 2012, models: [42], name: "高速分拣器", alias: "绿爪", icon: "inserter-2" },
8 | { id: 2013, models: [43], name: "极速分拣器", alias: "蓝爪", icon: "inserter-3" },
9 | { id: 2014, models: [483], name: "集装分拣器", alias: "白爪", icon: "inserter-4" },
10 | { id: 2020, models: [38, 39, 40], name: "四向分流器", icon: "splitter-4dir" },
11 | { id: 2040, models: [257], name: "自动集装机", icon: "piler" },
12 | { id: 2030, models: [208], name: "流速监测器", icon: "monitor" },
13 | { id: 2313, models: [120], name: "喷涂机", icon: "spray-coater" },
14 | { id: 2101, models: [51], name: "小型储物仓", icon: "storage-1" },
15 | { id: 2102, models: [52], name: "大型储物仓", icon: "storage-2" },
16 | { id: 2106, models: [121], name: "储液罐", icon: "storage-tank" },
17 | { id: 2303, models: [65], name: "制造台 Mk.I", icon: "assembler-1" },
18 | { id: 2304, models: [66], name: "制造台 Mk.II", icon: "assembler-2" },
19 | { id: 2305, models: [67], name: "制造台 Mk.III", icon: "assembler-3" },
20 | { id: 2318, models: [456], name: "重组式制造台", icon: "assembler-4" },
21 | { id: 2201, models: [44], name: "电力感应塔", icon: "tesla-coil" },
22 | { id: 2202, models: [71], name: "无线输电塔", icon: "charging-pole" },
23 | { id: 2212, models: [68], name: "卫星配电站", icon: "orbital-substation" },
24 | { id: 2203, models: [53], name: "风力涡轮机", icon: "wind-turbine" },
25 | { id: 2204, models: [54], name: "火力发电厂", icon: "fuel-plant" },
26 | { id: 2211, models: [118], name: "微型聚变发电站", icon: "fusion-power-station" },
27 | { id: 2213, models: [255], name: "地热发电站", icon: "geothermal-power-station" },
28 | { id: 2301, models: [57], name: "采矿机", icon: "mining-drill" },
29 | { id: 2316, models: [256], name: "大型采矿机", icon: "mining-drill-mk2" },
30 | { id: 2306, models: [60], name: "抽水站", icon: "water-pump" },
31 | { id: 2302, models: [62], name: "电弧熔炉", icon: "smelter" },
32 | { id: 2315, models: [194], name: "位面熔炉", icon: "smelter-2" },
33 | { id: 2319, models: [457], name: "负熵熔炉", icon: "smelter-3" },
34 | { id: 2307, models: [61], name: "原油萃取站", icon: "oil-extractor" },
35 | { id: 2308, models: [63], name: "原油精炼厂", icon: "oil-refinery" },
36 | { id: 2309, models: [64], name: "化工厂", icon: "chemical-plant" },
37 | { id: 2314, models: [119], name: "分馏塔", icon: "fractionator" },
38 | { id: 2317, models: [64], name: "量子化工厂", icon: "quantum-chemical-plant" },
39 | { id: 2205, models: [55], name: "太阳能板", icon: "solar-panel" },
40 | { id: 2206, models: [46], name: "蓄电器", icon: "accumulator" },
41 | { id: 2207, models: [46], name: "蓄电器(满)", icon: "accumulator-full" },
42 | { id: 2311, models: [72], name: "电磁轨道弹射器", icon: "em-rail-ejector" },
43 | { id: 2208, models: [73], name: "射线接收站", icon: "ray-receiver" },
44 | { id: 2312, models: [74], name: "垂直发射井", icon: "vertical-launching-silo" },
45 | { id: 2209, models: [45], name: "能量枢纽", icon: "energy-exchanger" },
46 | { id: 2310, models: [69], name: "微型粒子对撞机", icon: "hadron-collider" },
47 | { id: 2210, models: [56], name: "人造恒星", icon: "fusion-reactor" },
48 | { id: 2107, models: [371], name: "物流配送器", icon: "logistics-distributor" },
49 | { id: 2103, models: [49], name: "行星内物流运输站", icon: "logistic-station" },
50 | { id: 2104, models: [50], name: "星际物流运输站", icon: "interstellar-logistic-station" },
51 | { id: 2105, models: [117], name: "轨道采集器", icon: "orbital-collector" },
52 | { id: 2901, models: [70], name: "矩阵研究站", icon: "lab" },
53 | { id: 2902, models: [70], name: "自演化研究站", icon: "lab-2" },
54 | { id: 3001, models: [374], name: "高斯机枪塔", icon: "turret-gauss" },
55 | { id: 3002, models: [373], name: "高频激光塔", icon: "turret-laser" },
56 | { id: 3003, models: [375], name: "聚爆加农炮", icon: "turret-cannon" },
57 | { id: 3004, models: [408], name: "磁化电浆炮", icon: "turret-plasma" },
58 | { id: 3005, models: [407], name: "导弹防御塔", icon: "turret-missile" },
59 | { id: 3006, models: [422], name: "干扰塔", icon: "turret-disturb" },
60 | { id: 3007, models: [403], name: "信号塔", icon: "turret-signal" },
61 | { id: 3008, models: [402], name: "行星护盾发生器", icon: "turret-shield" },
62 | { id: 3009, models: [453], name: "战场分析基站", icon: "battle-base" },
63 | { id: 3010, models: [482], name: "近程电浆塔", icon: "turret-plasma-ground" },
64 | { id: 1001, name: "铁矿" },
65 | { id: 1002, name: "铜矿" },
66 | { id: 1003, name: "硅石" },
67 | { id: 1004, name: "钛石" },
68 | { id: 1005, name: "石矿" },
69 | { id: 1006, name: "煤矿" },
70 | { id: 1030, name: "木材" },
71 | { id: 1031, name: "植物燃料" },
72 | { id: 1011, name: "可燃冰" },
73 | { id: 1012, name: "金伯利矿石" },
74 | { id: 1013, name: "分形硅石" },
75 | { id: 1014, name: "光栅石" },
76 | { id: 1015, name: "刺笋结晶" },
77 | { id: 1016, name: "单极磁石" },
78 | { id: 1101, name: "铁块" },
79 | { id: 1104, name: "铜块" },
80 | { id: 1105, name: "高纯硅块" },
81 | { id: 1106, name: "钛块" },
82 | { id: 1108, name: "石材" },
83 | { id: 1109, name: "高能石墨" },
84 | { id: 1103, name: "钢材" },
85 | { id: 1107, name: "钛合金" },
86 | { id: 1110, name: "玻璃" },
87 | { id: 1119, name: "钛化玻璃" },
88 | { id: 1111, name: "棱镜" },
89 | { id: 1112, name: "金刚石" },
90 | { id: 1113, name: "晶格硅" },
91 | { id: 1201, name: "齿轮" },
92 | { id: 1102, name: "磁铁" },
93 | { id: 1202, name: "磁线圈" },
94 | { id: 1203, name: "电动机" },
95 | { id: 1204, name: "电磁涡轮" },
96 | { id: 1205, name: "超级磁场环" },
97 | { id: 1206, name: "粒子容器" },
98 | { id: 1127, name: "奇异物质" },
99 | { id: 1301, name: "电路板" },
100 | { id: 1303, name: "处理器" },
101 | { id: 1305, name: "量子芯片" },
102 | { id: 1302, name: "微晶元件" },
103 | { id: 1304, name: "位面过滤器" },
104 | { id: 1402, name: "粒子宽带" },
105 | { id: 1401, name: "电浆激发器" },
106 | { id: 1404, name: "光子合并器" },
107 | { id: 1501, name: "太阳帆" },
108 | { id: 1000, name: "水" },
109 | { id: 1007, name: "原油" },
110 | { id: 1114, name: "精炼油" },
111 | { id: 1116, name: "硫酸" },
112 | { id: 1120, name: "氢" },
113 | { id: 1121, name: "重氢" },
114 | { id: 1122, name: "反物质" },
115 | { id: 1208, name: "临界光子" },
116 | { id: 1801, name: "氢燃料棒" },
117 | { id: 1802, name: "氘核燃料棒" },
118 | { id: 1803, name: "反物质燃料棒" },
119 | { id: 1804, name: "奇异湮灭燃料棒" },
120 | { id: 1115, name: "塑料" },
121 | { id: 1123, name: "石墨烯" },
122 | { id: 1124, name: "碳纳米管" },
123 | { id: 1117, name: "有机晶体" },
124 | { id: 1118, name: "钛晶石" },
125 | { id: 1126, name: "卡西米尔晶体" },
126 | { id: 1128, name: "燃烧单元" },
127 | { id: 1129, name: "爆破单元" },
128 | { id: 1130, name: "晶石爆破单元" },
129 | { id: 1209, name: "引力透镜" },
130 | { id: 1210, name: "空间翘曲器" },
131 | { id: 1403, name: "湮灭约束球" },
132 | { id: 1407, name: "动力引擎" },
133 | { id: 1405, name: "推进器" },
134 | { id: 1406, name: "加力推进器" },
135 | { id: 5003, name: "配送运输机" },
136 | { id: 5001, name: "物流运输机" },
137 | { id: 5002, name: "星际物流运输船" },
138 | { id: 1125, name: "框架材料" },
139 | { id: 1502, name: "戴森球组件" },
140 | { id: 1503, name: "小型运载火箭" },
141 | { id: 1141, name: "增产剂 Mk.I" },
142 | { id: 1142, name: "增产剂 Mk.II" },
143 | { id: 1143, name: "增产剂 Mk.III" },
144 | { id: 1601, name: "机枪弹箱" },
145 | { id: 1602, name: "钛化弹箱" },
146 | { id: 1603, name: "超合金弹箱" },
147 | { id: 1604, name: "炮弹组" },
148 | { id: 1605, name: "高爆炮弹组" },
149 | { id: 1606, name: "晶石炮弹组" },
150 | { id: 1607, name: "等离子胶囊" },
151 | { id: 1608, name: "反物质胶囊" },
152 | { id: 1609, name: "导弹组" },
153 | { id: 1610, name: "超音速导弹组" },
154 | { id: 1611, name: "引力导弹组" },
155 | { id: 5101, name: "原型机" },
156 | { id: 5102, name: "精准无人机" },
157 | { id: 5103, name: "攻击无人机" },
158 | { id: 5111, name: "护卫舰" },
159 | { id: 5112, name: "驱逐舰" },
160 | { id: 5201, name: "黑雾矩阵" },
161 | { id: 5202, name: "硅基神经元" },
162 | { id: 5203, name: "物质重组器" },
163 | { id: 5204, name: "负熵奇点" },
164 | { id: 5205, name: "核心素" },
165 | { id: 5206, name: "能量碎片" },
166 | { id: 6001, name: "电磁矩阵" },
167 | { id: 6002, name: "能量矩阵" },
168 | { id: 6003, name: "结构矩阵" },
169 | { id: 6004, name: "信息矩阵" },
170 | { id: 6005, name: "引力矩阵" },
171 | { id: 6006, name: "宇宙矩阵" },
172 | { id: 1099, name: "沙土" },
173 | ];
174 |
--------------------------------------------------------------------------------
/src/utils/parser.js:
--------------------------------------------------------------------------------
1 | import pako from 'pako';
2 | import { digest } from './md5';
3 | import { getParamParser } from '@/utils/paramParser/paramParserFactory';
4 | import { itemsMap } from "@/utils/itemsUtil";
5 |
6 | class BufferIO {
7 | view;
8 | pos = 0;
9 | constructor(view) {
10 | this.view = view;
11 | }
12 | getView(length) {
13 | const r = new DataView(this.view.buffer, this.view.byteOffset + this.pos, length);
14 | this.pos += length;
15 | return r;
16 | }
17 | }
18 | class BufferReader extends BufferIO {
19 | getUint8() { const v = this.view.getUint8(this.pos); this.pos += 1; return v; }
20 | getInt8() { const v = this.view.getInt8(this.pos); this.pos += 1; return v; }
21 | getInt16() { const v = this.view.getInt16(this.pos, true); this.pos += 2; return v; }
22 | getInt32() { const v = this.view.getInt32(this.pos, true); this.pos += 4; return v; }
23 | getFloat32() { const v = this.view.getFloat32(this.pos, true); this.pos += 4; return v; }
24 | }
25 | class BufferWriter extends BufferIO {
26 | setUint8(value) { this.view.setUint8(this.pos, value); this.pos += 1; }
27 | setInt8(value) { this.view.setInt8(this.pos, value); this.pos += 1; }
28 | setInt16(value) { this.view.setInt16(this.pos, value, true); this.pos += 2; }
29 | setInt32(value) { this.view.setInt32(this.pos, value, true); this.pos += 4; }
30 | setFloat32(value) { this.view.setFloat32(this.pos, value, true); this.pos += 4; }
31 | }
32 | function btoUint8Array(b) {
33 | const arr = new Uint8Array(b.length);
34 | for (let i = 0; i < b.length; i++) {
35 | arr[i] = b.charCodeAt(i);
36 | }
37 | return arr;
38 | }
39 | function Uint8ArrayTob(a) {
40 | let out = '';
41 | for (let i = 0; i < a.length; i++) {
42 | out += String.fromCharCode(a[i]);
43 | }
44 | return out;
45 | }
46 | const uint8ToHex = new Array(0x100);
47 | for (let i = 0; i < uint8ToHex.length; i++) {
48 | uint8ToHex[i] = i.toString(16).toUpperCase().padStart(2, '0');
49 | }
50 | function hex(buffer) {
51 | const view = new Uint8Array(buffer);
52 | const hexBytes = new Array(view.length);
53 | for (let i = 0; i < view.length; i++) {
54 | hexBytes[i] = uint8ToHex[view[i]];
55 | }
56 | return hexBytes.join('');
57 | }
58 | function importArea(r) {
59 | return {
60 | index: r.getInt8(),
61 | parentIndex: r.getInt8(),
62 | tropicAnchor: r.getInt16(),
63 | areaSegments: r.getInt16(),
64 | anchorLocalOffset: {
65 | x: r.getInt16(),
66 | y: r.getInt16(),
67 | },
68 | size: {
69 | x: r.getInt16(),
70 | y: r.getInt16(),
71 | },
72 | };
73 | }
74 | function exportArea(w, area) {
75 | w.setInt8(area.index);
76 | w.setInt8(area.parentIndex);
77 | w.setInt16(area.tropicAnchor);
78 | w.setInt16(area.areaSegments);
79 | w.setInt16(area.anchorLocalOffset.x);
80 | w.setInt16(area.anchorLocalOffset.y);
81 | w.setInt16(area.size.x);
82 | w.setInt16(area.size.y);
83 | }
84 |
85 | function importBuilding(r) {
86 | function fix(num) {
87 | // 保留4位小数
88 | return +num?.toFixed(4) || 0;
89 | }
90 | function readXYZ() {
91 | return {
92 | x: fix(r.getFloat32()),
93 | y: fix(r.getFloat32()),
94 | z: fix(r.getFloat32()),
95 | };
96 | }
97 | const num = r.getInt32();
98 | const b = { parameters: null };
99 | if (num <= -101) {
100 | // 兼容(V0.10.31.24646)[2024/11/30]更新,前缀改为-101
101 | b.index = r.getInt32();
102 | b.itemId = r.getInt16();
103 | b.modelIndex = r.getInt16();
104 | b.areaIndex = r.getInt8();
105 | b.localOffset = [readXYZ()];
106 | b.yaw = [fix(r.getFloat32())];
107 | if (b.itemId > 2000 && b.itemId < 2010) {
108 | // 传送带参数
109 | b.tilt = r.getFloat32();
110 | b.pitch = 0;
111 | b.localOffset[1] = {...b.localOffset[0]};
112 | b.yaw[1] = b.yaw[0];
113 | b.tilt2 = b.tilt;
114 | b.pitch2 = 0;
115 | } else if (b.itemId > 2010 && b.itemId < 2020) {
116 | // 分拣器参数
117 | b.tilt = r.getFloat32();
118 | b.pitch = r.getFloat32();
119 | b.localOffset[1] = readXYZ();
120 | b.yaw[1] = fix(r.getFloat32());
121 | b.tilt2 = r.getFloat32();
122 | b.pitch2 = r.getFloat32();
123 | } else {
124 | b.tilt = 0;
125 | b.pitch = 0;
126 | b.localOffset[1] = {...b.localOffset[0]};
127 | b.yaw[1] = b.yaw[0];
128 | b.tilt2 = 0;
129 | b.pitch2 = 0;
130 | }
131 | b.outputObjIdx = r.getInt32();
132 | b.inputObjIdx = r.getInt32();
133 | b.outputToSlot = r.getInt8();
134 | b.inputFromSlot = r.getInt8();
135 | b.outputFromSlot = r.getInt8();
136 | b.inputToSlot = r.getInt8();
137 | b.outputOffset = r.getInt8();
138 | b.inputOffset = r.getInt8();
139 | b.recipeId = r.getInt16();
140 | b.filterId = r.getInt16();
141 | } else if (num <= -100) {
142 | // 兼容(V0.10.30.22239)[2024/05/29]后更新的倾斜字段,新版蓝图数据前缀多个-100
143 | b.index = r.getInt32();
144 | b.areaIndex = r.getInt8();
145 | b.localOffset = [readXYZ(), readXYZ()];
146 | b.yaw = [fix(r.getFloat32()), fix(r.getFloat32())];
147 | b.tilt = r.getFloat32();
148 | b.itemId = r.getInt16();
149 | b.modelIndex = r.getInt16();
150 | b.outputObjIdx = r.getInt32();
151 | b.inputObjIdx = r.getInt32();
152 | b.outputToSlot = r.getInt8();
153 | b.inputFromSlot = r.getInt8();
154 | b.outputFromSlot = r.getInt8();
155 | b.inputToSlot = r.getInt8();
156 | b.outputOffset = r.getInt8();
157 | b.inputOffset = r.getInt8();
158 | b.recipeId = r.getInt16();
159 | b.filterId = r.getInt16();
160 | } else {
161 | b.index = num;
162 | b.areaIndex = r.getInt8();
163 | b.localOffset = [readXYZ(), readXYZ()];
164 | b.yaw = [fix(r.getFloat32()), fix(r.getFloat32())];
165 | b.tilt = 0;
166 | b.itemId = r.getInt16();
167 | b.modelIndex = r.getInt16();
168 | b.outputObjIdx = r.getInt32();
169 | b.inputObjIdx = r.getInt32();
170 | b.outputToSlot = r.getInt8();
171 | b.inputFromSlot = r.getInt8();
172 | b.outputFromSlot = r.getInt8();
173 | b.inputToSlot = r.getInt8();
174 | b.outputOffset = r.getInt8();
175 | b.inputOffset = r.getInt8();
176 | b.recipeId = r.getInt16();
177 | b.filterId = r.getInt16();
178 | }
179 | b.itemName = itemsMap.get(b.itemId)?.name || `未知物品_${b.itemId}`;
180 | b.parameters = null;
181 | const length = r.getInt16();
182 | if (length > 0) {
183 | const v = r.getView(length * Int32Array.BYTES_PER_ELEMENT);
184 | b.parameters = getParamParser(b.itemId).decode(v);
185 | }
186 | return b;
187 | }
188 | function exportBuilding(w, b) {
189 | function writeXYZ(v) {
190 | w.setFloat32(v.x);
191 | w.setFloat32(v.y);
192 | w.setFloat32(v.z);
193 | }
194 | // w.setInt32(-100); // 兼容(V0.10.30.22239)[2024/05/29]后更新的倾斜字段,新版蓝图数据前缀多个-100
195 | w.setInt32(-101); // 兼容(V0.10.31.24646)[2024/11/30]更新,前缀改为-101
196 | w.setInt32(b.index);
197 | w.setInt16(b.itemId);
198 | w.setInt16(b.modelIndex);
199 | w.setInt8(b.areaIndex);
200 | writeXYZ(b.localOffset[0]);
201 | w.setFloat32(b.yaw[0]);
202 | if (b.itemId > 2000 && b.itemId < 2010) {
203 | // 传送带参数
204 | w.setFloat32(b.tilt);
205 | } else if (b.itemId > 2010 && b.itemId < 2020) {
206 | // 分拣器参数
207 | w.setFloat32(b.tilt);
208 | w.setFloat32(b.pitch);
209 | writeXYZ(b.localOffset[1]);
210 | w.setFloat32(b.yaw[1]);
211 | w.setFloat32(b.tilt2);
212 | w.setFloat32(b.pitch2);
213 | }
214 | w.setInt32(b.outputObjIdx);
215 | w.setInt32(b.inputObjIdx);
216 | w.setInt8(b.outputToSlot);
217 | w.setInt8(b.inputFromSlot);
218 | w.setInt8(b.outputFromSlot);
219 | w.setInt8(b.inputToSlot);
220 | w.setInt8(b.outputOffset);
221 | w.setInt8(b.inputOffset);
222 | w.setInt16(b.recipeId);
223 | w.setInt16(b.filterId);
224 | if (b.parameters !== null) {
225 | const parser = getParamParser(b.itemId);
226 | const length = parser.getLength(b.parameters);
227 | w.setInt16(length);
228 | parser.encode(b.parameters, w.getView(length * Int32Array.BYTES_PER_ELEMENT));
229 | }
230 | else {
231 | w.setInt16(0);
232 | }
233 | }
234 | const START = 'BLUEPRINT:';
235 | const TIME_BASE = new Date(0).setUTCFullYear(1);
236 | export function fromStr(strData) {
237 | if (!strData.startsWith(START))
238 | throw Error('Invalid start');
239 | const p1 = strData.indexOf('"', START.length);
240 | const cells = strData.substring(START.length, p1).split(',');
241 | if (cells.length < 12)
242 | throw Error('Header too short');
243 | const header = {
244 | layout: parseInt(cells[1]),
245 | icons: cells.slice(2, 7).map(s => parseInt(s)),
246 | time: new Date(TIME_BASE + parseInt(cells[8]) / 10000),
247 | gameVersion: cells[9],
248 | shortDesc: decodeURIComponent(cells[10]),
249 | desc: decodeURIComponent(cells[11]),
250 | };
251 | const p2 = strData.length - 33;
252 | if (strData[p2] !== '"')
253 | throw Error('Checksum not found');
254 | const d = hex(digest(btoUint8Array(strData.substring(0, p2)).buffer));
255 | const expectedD = strData.substring(p2 + 1);
256 | if (d !== expectedD)
257 | throw Error('Checksum mismatch');
258 | const encoded = strData.substring(p1 + 1, p2);
259 | const decoded = pako.ungzip(btoUint8Array(atob(encoded)));
260 | const reader = new BufferReader(new DataView(decoded.buffer));
261 | const meta = {
262 | version: reader.getInt32(),
263 | cursorOffset: {
264 | x: reader.getInt32(),
265 | y: reader.getInt32(),
266 | },
267 | cursorTargetArea: reader.getInt32(),
268 | dragBoxSize: {
269 | x: reader.getInt32(),
270 | y: reader.getInt32(),
271 | },
272 | primaryAreaIdx: reader.getInt32(),
273 | };
274 | const numAreas = reader.getUint8();
275 | const areas = [];
276 | for (let i = 0; i < numAreas; i++)
277 | areas.push(importArea(reader));
278 | const numBuildings = reader.getInt32();
279 | const buildings = [];
280 | for (let i = 0; i < numBuildings; i++)
281 | buildings.push(importBuilding(reader));
282 | return {
283 | header,
284 | ...meta,
285 | areas,
286 | buildings,
287 | };
288 | }
289 | function encodedSize(bp) {
290 | let result = 28 // meta
291 | + 1 // numAreas
292 | + 14 * bp.areas.length
293 | + 4 // numBuildings
294 | + 81 * bp.buildings.length;
295 | for (const b of bp.buildings) {
296 | if (b.parameters === null)
297 | continue;
298 | const parser = getParamParser(b.itemId);
299 | result += parser.getLength(b.parameters) * Int32Array.BYTES_PER_ELEMENT;
300 | }
301 | return result;
302 | }
303 | export function toStr(bp) {
304 | let result = START;
305 | result += '0,';
306 | result += bp.header.layout;
307 | result += ',';
308 | for (const i of bp.header.icons) {
309 | result += i;
310 | result += ',';
311 | }
312 | result += '0,';
313 | result += (new Date(bp.header.time).getTime() - TIME_BASE) * 10000;
314 | result += ',';
315 | result += bp.header.gameVersion;
316 | result += ',';
317 | result += encodeURIComponent(bp.header.shortDesc);
318 | result += ',';
319 | result += encodeURIComponent(bp.header.desc);
320 | result += '"';
321 | const decoded = new Uint8Array(encodedSize(bp));
322 | const writer = new BufferWriter(new DataView(decoded.buffer));
323 | writer.setInt32(bp.version);
324 | writer.setInt32(bp.cursorOffset.x);
325 | writer.setInt32(bp.cursorOffset.y);
326 | writer.setInt32(bp.cursorTargetArea);
327 | writer.setInt32(bp.dragBoxSize.x);
328 | writer.setInt32(bp.dragBoxSize.y);
329 | writer.setInt32(bp.primaryAreaIdx);
330 | writer.setUint8(bp.areas.length);
331 | for (const a of bp.areas)
332 | exportArea(writer, a);
333 | writer.setInt32(bp.buildings.length);
334 | for (const b of bp.buildings)
335 | exportBuilding(writer, b);
336 | result += btoa(Uint8ArrayTob(pako.gzip(decoded)));
337 | const d = hex(digest(btoUint8Array(result).buffer));
338 | result += '"';
339 | result += d;
340 | return result;
341 | }
--------------------------------------------------------------------------------
/src/utils/paramParser/paramParserFactory.js:
--------------------------------------------------------------------------------
1 | import DefaultParamParser from "./defaultParamParser";
2 | import BoolParamOpt from "./paramOptions/boolParamOpt";
3 | import FunParamOpt from "./paramOptions/funParamOpt";
4 | import ParamOpt, { getParam } from "./paramOptions/paramOpt";
5 | import ParamParser from "./paramParser";
6 | import * as itemUtil from "../itemsUtil";
7 |
8 | export function getParamParser(itemId) {
9 | if (itemUtil.isBelt(itemId)) {
10 | // 传送带
11 | return beltParamParser;
12 | } else if (itemUtil.isInserter(itemId)) {
13 | // 分拣器
14 | return inserterParamParser;
15 | } else if (itemUtil.isAssembler(itemId)) {
16 | // 制造厂类建筑(需指定制造配方的建筑)
17 | return assembleParamParser;
18 | } else if (itemUtil.isLab(itemId)) {
19 | // 研究站
20 | return labParamParser;
21 | } else if (itemUtil.isTurret(itemId)) {
22 | // 炮台
23 | return turretParamParser;
24 | } else {
25 | const parameterParsers = new Map([
26 | [2103, getStationParamsParser(4, 12)], // 行星内物流运输站
27 | [2104, getStationParamsParser(5, 12)], // 星际物流运输站
28 | [2316, getStationParamsParser(1, 9)], // 大型采矿机
29 | [2101, getStorageParamParser(30)], // 小型储物仓
30 | [2102, getStorageParamParser(60)], // 大型储物仓
31 | [3009, battleBaseParamParser], // 战场分析基站
32 | [2020, splitterParamParser], // 四向分流器
33 | [2106, tankParamParser], // 储液罐
34 | [2311, ejectorParamParser], // 电磁轨道弹射器
35 | [2208, powerGeneratorParamParser], // 射线接收站
36 | [2209, energyExchangerParamParser], // 能量枢纽
37 | [2312, verticalLaunchingSiloParamParser], // 垂直发射井
38 | [2030, MonitorParamParser], // 流速监测器
39 | [2107, dispenserParamParser], // 物流配送器
40 | ]);
41 | const parser = parameterParsers.get(itemId);
42 | if (parser !== undefined) return parser;
43 | }
44 | // 无匹配特定解析器,使用默认
45 | return unknownParamParser;
46 | }
47 |
48 | // 最大充能功率 MW -> 原始值
49 | function workEnergyPerTickEncode(pVal) { return Math.round(pVal * 50000 / 3) }
50 | // 最大充能功率 原始值 -> MW
51 | function workEnergyPerTickDecode(oVal) { return Math.round(oVal / 5000 * 3) / 10 }
52 |
53 | /**
54 | * 获取 运输站类建筑 ParamParser
55 | * @param maxItemKind 最大物品栏位
56 | * @param numSlots 建筑传送带插槽数目
57 | */
58 | export function getStationParamsParser(maxItemKind, numSlots) {
59 | let offset = 0; // 偏移量
60 | // 物品栏位参数
61 | const storage = [];
62 | const storageStride = 6; // 物品栏参数 每行长度
63 | for (var i = 0; i < maxItemKind; i++) {
64 | storage.push({
65 | itemId: ParamOpt.of(offset + i * storageStride + 0), // 物品id
66 | localRole: ParamOpt.of(offset + i * storageStride + 1), // 本地供需配置 -> 0:本地仓储 1:本地供应 2:本地需求
67 | remoteRole: ParamOpt.of(offset + i * storageStride + 2), // 星际供需配置 -> 0:星际仓储 1:星际供应 2:星际需求
68 | max: ParamOpt.of(offset + i * storageStride + 3), // 物品上限
69 | lockAmount: ParamOpt.of(offset + i * storageStride + 4), // 锁定数量 -> 0:不锁定 1:锁定满仓 2:锁定半仓
70 | });
71 | }
72 |
73 | // 传送带插槽参数
74 | const slots = [];
75 | offset = 192; // 插槽参数偏移量
76 | const slotsStride = 4; // 物品栏参数 每行长度
77 | for (i = 0; i < numSlots; i++) {
78 | slots.push({
79 | dir: ParamOpt.of(offset + i * slotsStride + 0), // 传送带接入方向 -> 0:未接入 1:输出 2:输入
80 | storageIdx: ParamOpt.of(offset + i * slotsStride + 1), // 输出货物对应物品栏索引 -> 0:不输出 1-5:物品栏索引 6:翘曲器
81 | });
82 | }
83 |
84 | // 主参数
85 | offset = 320; // 主参数偏移量
86 | return new ParamParser(2048, {
87 | storage: storage, // 物品栏位参数
88 | slots: slots, // 传送带插槽参数
89 | workEnergyPerTick: FunParamOpt.of(offset + 0, workEnergyPerTickEncode, workEnergyPerTickDecode), // 最大充能功率(单位:MW) -> 30-300
90 | tripRangeOfDrones: FunParamOpt.of(offset + 1, (pVal) => {
91 | return Math.round(Math.sin((90 - pVal) * Math.PI / 180) * 100000000);
92 | }, (oVal) => {
93 | return 90 - Math.round(Math.asin(oVal / 100000000) * 180 / Math.PI);
94 | }), // 运输机最远路程(单位:度) -> 20-180
95 | tripRangeOfShips: FunParamOpt.of(offset + 2, (pVal) => pVal * 24000, (oVal) => oVal / 24000), // 运输船最远路程 -> 1-60:有限路程(单位:ly) 10000:无限
96 | includeOrbitCollector: BoolParamOpt.of(offset + 3), // 是否会去轨道采集器取货 Boolean
97 | warpEnableDistance: FunParamOpt.of(offset + 4, (pVal) => pVal * 40000, (oVal) => oVal / 40000), // 曲速启用路程(单位:AU) -> 0.5-60
98 | warperNecessary: BoolParamOpt.of(offset + 5), // 是否翘曲器必备 Boolean
99 | deliveryAmountOfDrones: ParamOpt.of(offset + 6), // 运输机起送量(单位:%) -> 1-100
100 | deliveryAmountOfShips: ParamOpt.of(offset + 7), // 运输船起送量(单位:%) -> 1-100
101 | pilerCount: ParamOpt.of(offset + 8), // 输出货物集装数量 -> 0:使用科技上限 1-4:指定数量
102 | miningSpeed: ParamOpt.of(offset + 9), // 开采速度
103 | droneAutoReplenish: BoolParamOpt.of(offset + 10, 1, 0), // 是否自动补充运输机 Boolean_1_0
104 | shipAutoReplenish: BoolParamOpt.of(offset + 11, 1, 0), // 是否自动补充运输船 Boolean_1_0
105 | });
106 | }
107 |
108 | /**
109 | * 获取 储物仓 ParamParser
110 | * @param gridNum 格子数目
111 | */
112 | export function getStorageParamParser(gridNum = 60) {
113 | // 储物仓物品过滤器
114 | const storageFilters = [];
115 | for (let i = 0; i < gridNum; i++) {
116 | storageFilters.push(ParamOpt.of(10 + i)); // 过滤物品id
117 | }
118 | return new ParamParser(110, {
119 | bans: ParamOpt.of(0), // 限制不可自动放入的格子数
120 | storageType: ParamOpt.of(1), // 储物仓类型 -> 0:不过滤 9:存在过滤器
121 | filters: storageFilters, // 储物仓物品过滤器
122 | });
123 | }
124 |
125 | // 战场分析基站 ParamParser
126 | export const battleBaseParamParser = (() => {
127 | // 储物仓物品过滤器
128 | const storageFilters = [];
129 | const gridNum = 60;
130 | const baseOffset = 10; // 基础参数偏移量
131 | const filterDecode = (val, v) => {
132 | let storageType = getParam(v, 1); // 储物仓类型 -> 0:不过滤 9:存在过滤器
133 | return storageType === 9 ? val : 0; // 不存在过滤器时置为0
134 | }
135 | for (let i = 0; i < gridNum; i++) {
136 | storageFilters.push(FunParamOpt.of(baseOffset + i, e => e, filterDecode)); // 过滤物品id
137 | }
138 | // 动态获取偏移量方法(storageType为0时忽略filters,不占偏移量)
139 | let getPos = (pos) => {
140 | return (v) => {
141 | let storageType = getParam(v, 1); // 储物仓类型 -> 0:不过滤 9:存在过滤器
142 | const filtersOffset = storageType === 9 ? gridNum : 0; // 存在过滤器时增加偏移量gridNum
143 | return baseOffset + filtersOffset + pos;
144 | }
145 | };
146 | // 战斗无人机组
147 | const fighters = [];
148 | const fightersNum = 12;
149 | for (let i = 0; i < fightersNum; i++) {
150 | fighters.push(ParamOpt.of(getPos(7 + i))); // 无人机物品id
151 | }
152 | return new ParamParser(110, {
153 | bans: ParamOpt.of(0), // 限制不可自动放入的格子数
154 | storageType: ParamOpt.of(1), // 储物仓类型 -> 0:不过滤 9:存在过滤器
155 | filters: storageFilters, // 储物仓物品过滤器
156 | workEnergyPerTick: FunParamOpt.of(getPos(0), workEnergyPerTickEncode, workEnergyPerTickDecode), // 最大充能功率(单位:MW) -> 30-300
157 | autoPickEnabled: BoolParamOpt.of(getPos(1), 1, 0), // 是否自动拾取 Boolean_1_0
158 | autoReplenishFleet: BoolParamOpt.of(getPos(2), 1, 0), // 是否自动补充编队 Boolean_1_0
159 | moduleEnabled: BoolParamOpt.of(getPos(3), 1, 0), // 是否开启战斗无人机 Boolean_1_0
160 | autoReconstruct: BoolParamOpt.of(getPos(4), 1, 0), // 是否自动标记重建 Boolean_1_0
161 | droneEnabled: BoolParamOpt.of(getPos(5), 1, 0), // 是否开启建设无人机 Boolean_1_0
162 | dronesPriority: ParamOpt.of(getPos(6)), // 建设无人机模式 -> 0:优先修理 1:均衡模式 2:优先建造
163 | fighters: fighters, // 战斗无人机编队
164 | });
165 | })();
166 |
167 | // 四向分流器 ParamParser
168 | export const splitterParamParser = (() => {
169 | const splitterPriority = [];
170 | for (let i = 0; i < 4; i++) {
171 | splitterPriority[i] = BoolParamOpt.of(i, 1, 0); // 是否优先接口 Boolean_1_0
172 | }
173 | return new ParamParser(6, {
174 | priority: splitterPriority, // 四向四个接口的优先级
175 | })
176 | })();
177 |
178 | // 矩阵研究站 ParamParser
179 | export const labParamParser = new ParamParser(2, {
180 | researchMode: ParamOpt.of(0), // 研究模式 -> 0:未选择 1:矩阵合成 2:科研模式
181 | acceleratorMode: ParamOpt.of(1), // 增产效果 -> 0:额外产出 1:生产加速
182 | });
183 |
184 | // 制造厂类建筑(需指定制造配方的建筑) ParamParser
185 | export const assembleParamParser = new ParamParser(1, {
186 | acceleratorMode: ParamOpt.of(0), // 增产效果 -> 0:额外产出 1:生产加速
187 | });
188 |
189 | // 传送带 ParamParser
190 | export const beltParamParser = new ParamParser(2, {
191 | iconId: ParamOpt.of(0), // 图标标签物品id
192 | count: ParamOpt.of(1), // 图标标签下的数字
193 | });
194 |
195 | // 分拣器 ParamParser
196 | export const inserterParamParser = new ParamParser(1, {
197 | length: ParamOpt.of(0), // 分拣器长度 -> 1-3
198 | });
199 |
200 | // 储液罐 ParamParser
201 | export const tankParamParser = new ParamParser(2, {
202 | output: BoolParamOpt.of(0), // 是否输出 Boolean
203 | input: BoolParamOpt.of(1), // 是否输入 Boolean
204 | });
205 |
206 | // 电磁轨道弹射器 ParamParser
207 | export const ejectorParamParser = new ParamParser(2, {
208 | orbitId: ParamOpt.of(0), // 送入轨道编号 -> 0:无 1-20:轨道列表编号
209 | tenfoldSpeed: BoolParamOpt.of(1, 1, 0), // 是否开启十倍射速 Boolean_1_0
210 | });
211 |
212 | // 射线接收站 ParamParser
213 | export const powerGeneratorParamParser = new ParamParser(1, {
214 | productId: ParamOpt.of(0), // 模式 -> 0:直接发电 1208:光子生成
215 | });
216 |
217 | // 能量枢纽 ParamParser
218 | export const energyExchangerParamParser = new ParamParser(1, {
219 | mode: ParamOpt.of(0), // 模式 -> -1:放电 0:待机 1:充电
220 | });
221 |
222 | // 垂直发射井 ParamParser
223 | export const verticalLaunchingSiloParamParser = new ParamParser(1, {
224 | tenfoldSpeed: BoolParamOpt.of(0, 1, 0), // 是否开启十倍射速 Boolean_1_0
225 | });
226 |
227 | // 流速监测器 ParamParser
228 | export const MonitorParamParser = new ParamParser(128, {
229 | targetBeltId: ParamOpt.of(0), // 绑定的传送带节点ID(实际id,不是蓝图index,疑似无效参数)
230 | offset: ParamOpt.of(1), // ?
231 |
232 | targetCargoAmount: ParamOpt.of(2), // 目标流量(单位:0.1个)
233 | periodTicksCount: ParamOpt.of(3), // 监测周期(单位:秒)
234 | passOperator: ParamOpt.of(4), // 监测条件 -> 0:等于 1:不等于 2:大于等于 3:大于 4:小于等于 5:小于
235 | passColorId: ParamOpt.of(5), // 满足条件颜色索引 -> 0-255
236 | failColorId: ParamOpt.of(6), // 不满足条件颜色索引 -> 0-255
237 | cargoFilter: ParamOpt.of(14), // 货物过滤物品id -> 0:不过滤 物品id->过滤
238 | spawnItemOperator: ParamOpt.of(20), // 生成/消耗货物模式 -> 0:不勾选 1:生成货物 2:消耗货物
239 |
240 | systemWarningMode: ParamOpt.of(10), // 系统警报模式 -> 0:无 1:未满足条件 2:满足条件 3:有货物响 4:无货物响 5:未满足且有货物 6:未满足且无货物
241 | systemWarningIconId: ParamOpt.of(17), // 系统警报图标id
242 |
243 | alarmMode: ParamOpt.of(12), // 声音警报模式 -> 0:无 1:未满足条件 2:满足条件 3:有货物响 4:无货物响 5:未满足且有货物 6:未满足且无货物
244 | tone: ParamOpt.of(7), // 声音警报-音色 -> 20-24:警报 1-2:钢琴 3-4:贝斯 5-6:风琴 7-9:铺底 10:铜管乐 11:梦铃 12:玻璃 13:吉他 14:音乐盒 15:电子琴 16:小号 17:小提琴 18:低音贝斯 19:鼓
245 | falloffRadius: [ // 声音警报-声音衰减范围
246 | FunParamOpt.of(18, (pVal) => pVal * 10, (oVal) => oVal / 10), // 开始衰减距离(单位:米) -> 默认为 衰减为0距离/3(0-133)
247 | FunParamOpt.of(19, (pVal) => pVal * 10, (oVal) => oVal / 10), // 衰减为0距离(单位:米) -> 1-400
248 | ],
249 | repeat: BoolParamOpt.of(11, 1, 0), // 声音警报-是否循环 Boolean_1_0
250 | pitch: ParamOpt.of(9), // 声音警报-音阶 -> 例:25:C2 26:C#2 27:D2 ...
251 | volume: ParamOpt.of(8), // 声音警报-音量 -> 0-100
252 | length: FunParamOpt.of(13, (pVal) => pVal * 10000, (oVal) => oVal / 10000), // 声音警报-时长(只有音色为警报时有该参数) -> 0.1-20
253 | });
254 |
255 | // 物流配送器 ParamParser
256 | export const dispenserParamParser = new ParamParser(128, {
257 | playerMode: ParamOpt.of(0), // 机甲供需模式 -> 1:从伊卡洛斯回收 2:向伊卡洛斯供应和回收 3:向伊卡洛斯供应
258 | storageMode: ParamOpt.of(1), // 配送器间模式 -> 0:不勾选 1:向其他配送器供应 2:向其他配送器需求
259 | workEnergyPerTick: FunParamOpt.of(2, workEnergyPerTickEncode, workEnergyPerTickDecode), // 最大充能功率(单位:MW) -> 0.9-9
260 | courierAutoReplenish: BoolParamOpt.of(3, 1, 0), // 是否自动补充运输单位 Boolean_1_0
261 | });
262 |
263 | // 炮台类建筑 ParamParser
264 | export const turretParamParser = new ParamParser(128, {
265 | group: ParamOpt.of(1), // 分组编号 -> 0:不分组 1-5:分组
266 | vsSettings: FunParamOpt.of(2, (pVal) => {
267 | if (!pVal) return 0;
268 | return (pVal[0] << 0) + (pVal[1] << 2) + (pVal[2] << 4) + (pVal[3] << 6)
269 | }, (oVal) => {
270 | // 使用8位二进制数代表4个开关分别4种状态
271 | // 0:关闭
272 | // 1:地面低优先 2:地面均衡 3:地面高优先 01 10 11
273 | // 4:低空低优先 8:低空均衡 12:低空高优先 0100 1000 1100
274 | // 16:高空低优先 32:高空均衡 48:高空高优先 010000 100000 110000
275 | // 64:太空低优先 128:太空均衡 192:太空高优先 01000000 10000000 11000000
276 | return [
277 | oVal & 3, // 地面优先级 -> 0:关闭 1:低优先 2:均衡 3:高优先
278 | oVal >> 2 & 3, // 低空优先级 -> 0:关闭 1:低优先 2:均衡 3:高优先
279 | oVal >> 4 & 3, // 高空优先级 -> 0:关闭 1:低优先 2:均衡 3:高优先
280 | oVal >> 6 & 3, // 太空优先级 -> 0:关闭 1:低优先 2:均衡 3:高优先
281 | ]
282 | }), // 攻击设置优先级
283 | phasePos: FunParamOpt.of(3, (pVal) => pVal * 60, (oVal) => oVal / 60), // 干扰塔相位偏移(单位:秒) -> 0-5
284 | });
285 |
286 | // 默认 ParamParser
287 | export const unknownParamParser = new DefaultParamParser();
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | GNU GENERAL PUBLIC LICENSE
2 | Version 2, June 1991
3 |
4 | Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
5 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
6 | Everyone is permitted to copy and distribute verbatim copies
7 | of this license document, but changing it is not allowed.
8 |
9 | Preamble
10 |
11 | The licenses for most software are designed to take away your
12 | freedom to share and change it. By contrast, the GNU General Public
13 | License is intended to guarantee your freedom to share and change free
14 | software--to make sure the software is free for all its users. This
15 | General Public License applies to most of the Free Software
16 | Foundation's software and to any other program whose authors commit to
17 | using it. (Some other Free Software Foundation software is covered by
18 | the GNU Lesser General Public License instead.) You can apply it to
19 | your programs, too.
20 |
21 | When we speak of free software, we are referring to freedom, not
22 | price. Our General Public Licenses are designed to make sure that you
23 | have the freedom to distribute copies of free software (and charge for
24 | this service if you wish), that you receive source code or can get it
25 | if you want it, that you can change the software or use pieces of it
26 | in new free programs; and that you know you can do these things.
27 |
28 | To protect your rights, we need to make restrictions that forbid
29 | anyone to deny you these rights or to ask you to surrender the rights.
30 | These restrictions translate to certain responsibilities for you if you
31 | distribute copies of the software, or if you modify it.
32 |
33 | For example, if you distribute copies of such a program, whether
34 | gratis or for a fee, you must give the recipients all the rights that
35 | you have. You must make sure that they, too, receive or can get the
36 | source code. And you must show them these terms so they know their
37 | rights.
38 |
39 | We protect your rights with two steps: (1) copyright the software, and
40 | (2) offer you this license which gives you legal permission to copy,
41 | distribute and/or modify the software.
42 |
43 | Also, for each author's protection and ours, we want to make certain
44 | that everyone understands that there is no warranty for this free
45 | software. If the software is modified by someone else and passed on, we
46 | want its recipients to know that what they have is not the original, so
47 | that any problems introduced by others will not reflect on the original
48 | authors' reputations.
49 |
50 | Finally, any free program is threatened constantly by software
51 | patents. We wish to avoid the danger that redistributors of a free
52 | program will individually obtain patent licenses, in effect making the
53 | program proprietary. To prevent this, we have made it clear that any
54 | patent must be licensed for everyone's free use or not licensed at all.
55 |
56 | The precise terms and conditions for copying, distribution and
57 | modification follow.
58 |
59 | GNU GENERAL PUBLIC LICENSE
60 | TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
61 |
62 | 0. This License applies to any program or other work which contains
63 | a notice placed by the copyright holder saying it may be distributed
64 | under the terms of this General Public License. The "Program", below,
65 | refers to any such program or work, and a "work based on the Program"
66 | means either the Program or any derivative work under copyright law:
67 | that is to say, a work containing the Program or a portion of it,
68 | either verbatim or with modifications and/or translated into another
69 | language. (Hereinafter, translation is included without limitation in
70 | the term "modification".) Each licensee is addressed as "you".
71 |
72 | Activities other than copying, distribution and modification are not
73 | covered by this License; they are outside its scope. The act of
74 | running the Program is not restricted, and the output from the Program
75 | is covered only if its contents constitute a work based on the
76 | Program (independent of having been made by running the Program).
77 | Whether that is true depends on what the Program does.
78 |
79 | 1. You may copy and distribute verbatim copies of the Program's
80 | source code as you receive it, in any medium, provided that you
81 | conspicuously and appropriately publish on each copy an appropriate
82 | copyright notice and disclaimer of warranty; keep intact all the
83 | notices that refer to this License and to the absence of any warranty;
84 | and give any other recipients of the Program a copy of this License
85 | along with the Program.
86 |
87 | You may charge a fee for the physical act of transferring a copy, and
88 | you may at your option offer warranty protection in exchange for a fee.
89 |
90 | 2. You may modify your copy or copies of the Program or any portion
91 | of it, thus forming a work based on the Program, and copy and
92 | distribute such modifications or work under the terms of Section 1
93 | above, provided that you also meet all of these conditions:
94 |
95 | a) You must cause the modified files to carry prominent notices
96 | stating that you changed the files and the date of any change.
97 |
98 | b) You must cause any work that you distribute or publish, that in
99 | whole or in part contains or is derived from the Program or any
100 | part thereof, to be licensed as a whole at no charge to all third
101 | parties under the terms of this License.
102 |
103 | c) If the modified program normally reads commands interactively
104 | when run, you must cause it, when started running for such
105 | interactive use in the most ordinary way, to print or display an
106 | announcement including an appropriate copyright notice and a
107 | notice that there is no warranty (or else, saying that you provide
108 | a warranty) and that users may redistribute the program under
109 | these conditions, and telling the user how to view a copy of this
110 | License. (Exception: if the Program itself is interactive but
111 | does not normally print such an announcement, your work based on
112 | the Program is not required to print an announcement.)
113 |
114 | These requirements apply to the modified work as a whole. If
115 | identifiable sections of that work are not derived from the Program,
116 | and can be reasonably considered independent and separate works in
117 | themselves, then this License, and its terms, do not apply to those
118 | sections when you distribute them as separate works. But when you
119 | distribute the same sections as part of a whole which is a work based
120 | on the Program, the distribution of the whole must be on the terms of
121 | this License, whose permissions for other licensees extend to the
122 | entire whole, and thus to each and every part regardless of who wrote it.
123 |
124 | Thus, it is not the intent of this section to claim rights or contest
125 | your rights to work written entirely by you; rather, the intent is to
126 | exercise the right to control the distribution of derivative or
127 | collective works based on the Program.
128 |
129 | In addition, mere aggregation of another work not based on the Program
130 | with the Program (or with a work based on the Program) on a volume of
131 | a storage or distribution medium does not bring the other work under
132 | the scope of this License.
133 |
134 | 3. You may copy and distribute the Program (or a work based on it,
135 | under Section 2) in object code or executable form under the terms of
136 | Sections 1 and 2 above provided that you also do one of the following:
137 |
138 | a) Accompany it with the complete corresponding machine-readable
139 | source code, which must be distributed under the terms of Sections
140 | 1 and 2 above on a medium customarily used for software interchange; or,
141 |
142 | b) Accompany it with a written offer, valid for at least three
143 | years, to give any third party, for a charge no more than your
144 | cost of physically performing source distribution, a complete
145 | machine-readable copy of the corresponding source code, to be
146 | distributed under the terms of Sections 1 and 2 above on a medium
147 | customarily used for software interchange; or,
148 |
149 | c) Accompany it with the information you received as to the offer
150 | to distribute corresponding source code. (This alternative is
151 | allowed only for noncommercial distribution and only if you
152 | received the program in object code or executable form with such
153 | an offer, in accord with Subsection b above.)
154 |
155 | The source code for a work means the preferred form of the work for
156 | making modifications to it. For an executable work, complete source
157 | code means all the source code for all modules it contains, plus any
158 | associated interface definition files, plus the scripts used to
159 | control compilation and installation of the executable. However, as a
160 | special exception, the source code distributed need not include
161 | anything that is normally distributed (in either source or binary
162 | form) with the major components (compiler, kernel, and so on) of the
163 | operating system on which the executable runs, unless that component
164 | itself accompanies the executable.
165 |
166 | If distribution of executable or object code is made by offering
167 | access to copy from a designated place, then offering equivalent
168 | access to copy the source code from the same place counts as
169 | distribution of the source code, even though third parties are not
170 | compelled to copy the source along with the object code.
171 |
172 | 4. You may not copy, modify, sublicense, or distribute the Program
173 | except as expressly provided under this License. Any attempt
174 | otherwise to copy, modify, sublicense or distribute the Program is
175 | void, and will automatically terminate your rights under this License.
176 | However, parties who have received copies, or rights, from you under
177 | this License will not have their licenses terminated so long as such
178 | parties remain in full compliance.
179 |
180 | 5. You are not required to accept this License, since you have not
181 | signed it. However, nothing else grants you permission to modify or
182 | distribute the Program or its derivative works. These actions are
183 | prohibited by law if you do not accept this License. Therefore, by
184 | modifying or distributing the Program (or any work based on the
185 | Program), you indicate your acceptance of this License to do so, and
186 | all its terms and conditions for copying, distributing or modifying
187 | the Program or works based on it.
188 |
189 | 6. Each time you redistribute the Program (or any work based on the
190 | Program), the recipient automatically receives a license from the
191 | original licensor to copy, distribute or modify the Program subject to
192 | these terms and conditions. You may not impose any further
193 | restrictions on the recipients' exercise of the rights granted herein.
194 | You are not responsible for enforcing compliance by third parties to
195 | this License.
196 |
197 | 7. If, as a consequence of a court judgment or allegation of patent
198 | infringement or for any other reason (not limited to patent issues),
199 | conditions are imposed on you (whether by court order, agreement or
200 | otherwise) that contradict the conditions of this License, they do not
201 | excuse you from the conditions of this License. If you cannot
202 | distribute so as to satisfy simultaneously your obligations under this
203 | License and any other pertinent obligations, then as a consequence you
204 | may not distribute the Program at all. For example, if a patent
205 | license would not permit royalty-free redistribution of the Program by
206 | all those who receive copies directly or indirectly through you, then
207 | the only way you could satisfy both it and this License would be to
208 | refrain entirely from distribution of the Program.
209 |
210 | If any portion of this section is held invalid or unenforceable under
211 | any particular circumstance, the balance of the section is intended to
212 | apply and the section as a whole is intended to apply in other
213 | circumstances.
214 |
215 | It is not the purpose of this section to induce you to infringe any
216 | patents or other property right claims or to contest validity of any
217 | such claims; this section has the sole purpose of protecting the
218 | integrity of the free software distribution system, which is
219 | implemented by public license practices. Many people have made
220 | generous contributions to the wide range of software distributed
221 | through that system in reliance on consistent application of that
222 | system; it is up to the author/donor to decide if he or she is willing
223 | to distribute software through any other system and a licensee cannot
224 | impose that choice.
225 |
226 | This section is intended to make thoroughly clear what is believed to
227 | be a consequence of the rest of this License.
228 |
229 | 8. If the distribution and/or use of the Program is restricted in
230 | certain countries either by patents or by copyrighted interfaces, the
231 | original copyright holder who places the Program under this License
232 | may add an explicit geographical distribution limitation excluding
233 | those countries, so that distribution is permitted only in or among
234 | countries not thus excluded. In such case, this License incorporates
235 | the limitation as if written in the body of this License.
236 |
237 | 9. The Free Software Foundation may publish revised and/or new versions
238 | of the General Public License from time to time. Such new versions will
239 | be similar in spirit to the present version, but may differ in detail to
240 | address new problems or concerns.
241 |
242 | Each version is given a distinguishing version number. If the Program
243 | specifies a version number of this License which applies to it and "any
244 | later version", you have the option of following the terms and conditions
245 | either of that version or of any later version published by the Free
246 | Software Foundation. If the Program does not specify a version number of
247 | this License, you may choose any version ever published by the Free Software
248 | Foundation.
249 |
250 | 10. If you wish to incorporate parts of the Program into other free
251 | programs whose distribution conditions are different, write to the author
252 | to ask for permission. For software which is copyrighted by the Free
253 | Software Foundation, write to the Free Software Foundation; we sometimes
254 | make exceptions for this. Our decision will be guided by the two goals
255 | of preserving the free status of all derivatives of our free software and
256 | of promoting the sharing and reuse of software generally.
257 |
258 | NO WARRANTY
259 |
260 | 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
261 | FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
262 | OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
263 | PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
264 | OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
265 | MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
266 | TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
267 | PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
268 | REPAIR OR CORRECTION.
269 |
270 | 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
271 | WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
272 | REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
273 | INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
274 | OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
275 | TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
276 | YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
277 | PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
278 | POSSIBILITY OF SUCH DAMAGES.
279 |
280 | END OF TERMS AND CONDITIONS
281 |
282 | How to Apply These Terms to Your New Programs
283 |
284 | If you develop a new program, and you want it to be of the greatest
285 | possible use to the public, the best way to achieve this is to make it
286 | free software which everyone can redistribute and change under these terms.
287 |
288 | To do so, attach the following notices to the program. It is safest
289 | to attach them to the start of each source file to most effectively
290 | convey the exclusion of warranty; and each file should have at least
291 | the "copyright" line and a pointer to where the full notice is found.
292 |
293 |
294 | Copyright (C)
295 |
296 | This program is free software; you can redistribute it and/or modify
297 | it under the terms of the GNU General Public License as published by
298 | the Free Software Foundation; either version 2 of the License, or
299 | (at your option) any later version.
300 |
301 | This program is distributed in the hope that it will be useful,
302 | but WITHOUT ANY WARRANTY; without even the implied warranty of
303 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
304 | GNU General Public License for more details.
305 |
306 | You should have received a copy of the GNU General Public License along
307 | with this program; if not, write to the Free Software Foundation, Inc.,
308 | 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
309 |
310 | Also add information on how to contact you by electronic and paper mail.
311 |
312 | If the program is interactive, make it output a short notice like this
313 | when it starts in an interactive mode:
314 |
315 | Gnomovision version 69, Copyright (C) year name of author
316 | Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
317 | This is free software, and you are welcome to redistribute it
318 | under certain conditions; type `show c' for details.
319 |
320 | The hypothetical commands `show w' and `show c' should show the appropriate
321 | parts of the General Public License. Of course, the commands you use may
322 | be called something other than `show w' and `show c'; they could even be
323 | mouse-clicks or menu items--whatever suits your program.
324 |
325 | You should also get your employer (if you work as a programmer) or your
326 | school, if any, to sign a "copyright disclaimer" for the program, if
327 | necessary. Here is a sample; alter the names:
328 |
329 | Yoyodyne, Inc., hereby disclaims all copyright interest in the program
330 | `Gnomovision' (which makes passes at compilers) written by James Hacker.
331 |
332 | , 1 April 1989
333 | Ty Coon, President of Vice
334 |
335 | This General Public License does not permit incorporating your program into
336 | proprietary programs. If your program is a subroutine library, you may
337 | consider it more useful to permit linking proprietary applications with the
338 | library. If this is what you want to do, use the GNU Lesser General
339 | Public License instead of this License.
340 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # DSP蓝图变换工具
2 |
3 | ### - 戴森球计划蓝图仙术工具
4 |
5 | 基于对戴森球计划游戏蓝图数据的解析与处理,实现对蓝图进行“垂直叠加”、“坐标偏移”、“水平翻转”、“线性变换”、“无带流”等转换的实用功能,并提供快捷、界面化的蓝图数据与JSON间的转换功能。
6 |
7 | - 项目框架:Vue2
8 |
9 | - 蓝图数据解析参考:
10 |
11 | > https://github.com/Wesmania/dspbp
12 |
13 | > https://github.com/huww98/dsp_blueprint_editor
14 |
15 | - 在线访问地址:
16 |
17 | > https://cying.xyz/DSP/editBluePrint/
18 |
19 | - b站演示视频:
20 |
21 | > https://www.bilibili.com/video/BV138411x7Sn/
22 |
23 | > https://www.bilibili.com/video/BV1kr4y1V73y/
24 |
25 | - 页面截图:
26 |
27 | ## 
28 |
29 |
30 |
31 | ### 蓝图数据字典
32 |
33 | > **数据主体**
34 |
35 | | 字段 | 字段类型 | 索引/长度 | 备注 |
36 | | ----------------------- | ----------------------------- | --------------------------- | ------------------------------------------------------------ |
37 | | | | *cells* **数组索引** | 截取从 `BLUEPRINT:` 后到首个 `"` 间的字符串
逗号分割为数组*cells* |
38 | | header | Object | | 蓝图文件头部信息 |
39 | | - layout | Number | *cells[1]* | 蓝图图标布局 |
40 | | - icons | Array(5) | | 蓝图图标 |
41 | | - - *_array_item* | Number | *cells[2 - 6]* | |
42 | | - time | Date | *cells[8]* | 创建时间 |
43 | | - gameVersion | String | *cells[9]* | 游戏版本号 |
44 | | - shortDesc | String | *cells[10]* | 缩略图文字 |
45 | | - desc | String | *cells[11]* | 蓝图介绍 |
46 | | | | **长度(字节)** | 首个 `"` 到第二个 `"` 间的字符串解析为字节流
**以下按蓝图数据按字节流从左到右排列** |
47 | | version | Number | 4 | 一般为1 |
48 | | cursorOffset | Object | | 预览蓝图时的鼠标锚点偏移 |
49 | | - x | Number | 4 | |
50 | | - y | Number | 4 | |
51 | | cursorTargetArea | Number | 4 | 对应areas索引,一般为0 |
52 | | dragBoxSize | Object | | 长按鼠标拖拽复制建筑时,间隔的长宽
一般与*areas.size*相同 |
53 | | - x | Number | 4 | |
54 | | - y | Number | 4 | |
55 | | primaryAreaIdx | Number | 4 | 对应areas索引,一般为0 |
56 | | numAreas | - | 1 | areas数组长度(仅读取),一般为1 |
57 | | areas | Array(*numAreas*) | | |
58 | | - *_array_item* | **[AREA](#area对象)** | 14 | |
59 | | numBuildings | - | 4 | buildings数组长度(仅读取) |
60 | | buildings | Array(*numBuildings*) | | 建筑信息 |
61 | | - *_array_item* | **[BUILDING](#building对象)** | 61 + *_parameterLength* * 4 | |
62 |
63 |
64 |
65 | #### **AREA对象**
66 |
67 | | 字段 | 字段类型 | 长度(字节) | 备注 |
68 | | ----------------- | -------- | ---------- | -------------------- |
69 | | index | Number | 1 | 数组索引 |
70 | | parentIndex | Number | 1 | |
71 | | tropicAnchor | Number | 2 | |
72 | | areaSegments | Number | 2 | |
73 | | anchorLocalOffset | Object | | |
74 | | - x | Number | 2 | |
75 | | - y | Number | 2 | |
76 | | size | Object | | 所有建筑的包围盒长宽 |
77 | | - x | Number | 2 | |
78 | | - y | Number | 2 | |
79 |
80 |
81 |
82 | #### **BUILDING对象**
83 |
84 | ##### [2024/11/30后]:游戏版本V0.10.31.24646简化蓝图结构
85 |
86 | > 变化描述:
87 |
88 | 1. 版本标识`num`改为-101
89 | 2. 移动`itemId`、`modelIndex`顺序
90 | 3. `localOffset[1]`、`yaw[1]`改为分拣器独有
91 | 4. `tilt`改为分拣器和传送带独有
92 | 5. 分拣器建筑增加`pitch`、`tilt2`、`pitch2`属性
93 |
94 | | 字段 | 字段类型 | 长度(字节) | 备注 |
95 | | ---------------- | ----------------------- | --------------------- | ------------------------------------------------------------ |
96 | | num | Number | 4 | 固定值-101,用以标识蓝图版本[V0.10.31.24646后蓝图版本标识] |
97 | | index | Number | 4 | 数组索引 |
98 | | itemId | Number | 2 | 建筑id |
99 | | itemName | String | - | 建筑名称 |
100 | | modelIndex | Number | 2 | 模型id |
101 | | areaIndex | Number | 1 | 对应areas索引,一般为0 |
102 | | localOffset[0].x | Number | 4 | 建筑物相对坐标x |
103 | | localOffset[0].y | Number | 4 | 建筑物相对坐标y |
104 | | localOffset[0].z | Number | 4 | 建筑物相对坐标z |
105 | | yaw[0] | Number | 4 | 建筑物旋转角度(单位:角度) |
106 | | tilt | Number | 4 | 建筑物倾斜角度(单位:角度)
*传送带建筑`(2000*分拣器建筑`(2010*分拣器建筑`(2010*分拣器建筑`(2010*分拣器建筑`(2010*分拣器建筑`(2010*分拣器建筑`(2010*分拣器建筑`(2010 变化描述:
132 |
133 | 1. 增加版本标识`num`,固定值-100
134 | 2. 建筑增加`tilt`属性
135 |
136 | | 字段 | 字段类型 | 长度(字节) | 备注 |
137 | | ------------------ | ----------------------- | --------------------- | ---------------------------------------------------- |
138 | | num | Number | 4 | 固定值-100,用以标识蓝图版本[V0.10.30.22239版本新增] |
139 | | index | Number | 4 | 数组索引 |
140 | | areaIndex | Number | 1 | 对应areas索引,一般为0 |
141 | | localOffset | Array(2) | | 建筑物相对坐标 |
142 | | - *_array_item* | Object | | |
143 | | - - x | Number | 4 | |
144 | | - - y | Number | 4 | |
145 | | - - z | Number | 4 | |
146 | | yaw | Array(2) | | 建筑物旋转角度(单位:角度) |
147 | | - *_array_item* | Number | 4 | |
148 | | tilt | Number | 4 | 建筑物倾斜角度(单位:角度)[V0.10.30.22239版本新增] |
149 | | itemId | Number | 2 | 建筑id |
150 | | itemName | String | - | 建筑名称 |
151 | | modelIndex | Number | 2 | 模型id |
152 | | outputObjIdx | Number | 4 | 输出端目标建筑索引 |
153 | | inputObjIdx | Number | 4 | 输入端目标建筑索引 |
154 | | outputToSlot | Number | 1 | 输出端绑定到目标建筑的插槽索引 |
155 | | inputFromSlot | Number | 1 | 输入端绑定到目标建筑的插槽索引 |
156 | | outputFromSlot | Number | 1 | (建筑物自身属性) |
157 | | inputToSlot | Number | 1 | (建筑物自身属性) |
158 | | outputOffset | Number | 1 | 输出端插槽偏移,常见于分拣器 |
159 | | inputOffset | Number | 1 | 输入端插槽偏移,常见于分拣器 |
160 | | recipeId | Number | 2 | 配方id,常见于制造厂类建筑 |
161 | | filterId | Number | 2 | 过滤物品id,常见于分拣器、四向 |
162 | | parameterLength | - | 2 | parameters长度(每单位:4字节) |
163 | | parameters | **[PARAM](#param对象)** | *parameterLength* * 4 | 建筑配置参数 |
164 |
165 |
166 |
167 | ##### [2024/05/29前]:早期蓝图版本
168 |
169 | | 字段 | 字段类型 | 长度(字节) | 备注 |
170 | | ------------------ | ----------------------- | --------------------- | ------------------------------- |
171 | | index | Number | 4 | 数组索引 |
172 | | areaIndex | Number | 1 | 对应areas索引,一般为0 |
173 | | localOffset | Array(2) | | 建筑物相对坐标 |
174 | | - *_array_item* | Object | | |
175 | | - - x | Number | 4 | |
176 | | - - y | Number | 4 | |
177 | | - - z | Number | 4 | |
178 | | yaw | Array(2) | | 建筑物旋转角度(单位:角度) |
179 | | - *_array_item* | Number | 4 | |
180 | | itemId | Number | 2 | 建筑id |
181 | | itemName | String | - | 建筑名称 |
182 | | modelIndex | Number | 2 | 模型id |
183 | | outputObjIdx | Number | 4 | 输出端目标建筑索引 |
184 | | inputObjIdx | Number | 4 | 输入端目标建筑索引 |
185 | | outputToSlot | Number | 1 | 输出端绑定到目标建筑的插槽索引 |
186 | | inputFromSlot | Number | 1 | 输入端绑定到目标建筑的插槽索引 |
187 | | outputFromSlot | Number | 1 | (建筑物自身属性) |
188 | | inputToSlot | Number | 1 | (建筑物自身属性) |
189 | | outputOffset | Number | 1 | 输出端插槽偏移,常见于分拣器 |
190 | | inputOffset | Number | 1 | 输入端插槽偏移,常见于分拣器 |
191 | | recipeId | Number | 2 | 配方id,常见于制造厂类建筑 |
192 | | filterId | Number | 2 | 过滤物品id,常见于分拣器、四向 |
193 | | parameterLength | - | 2 | parameters长度(每单位:4字节) |
194 | | parameters | **[PARAM](#param对象)** | *parameterLength* * 4 | 建筑配置参数 |
195 |
196 |
197 |
198 | #### **PARAM对象**
199 |
200 | ##### 传送带配置参数
201 |
202 | > [^2001, 2002, 2003]: 传送带, 高速传送带, 极速传送带
203 |
204 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
205 | | ----------- | -------- | ------------- | ----------- | ---------------- |
206 | | _parameters | Object | | 2 | |
207 | | - iconId | Number | 0 | 1 | 图标标签物品id |
208 | | - count | Number | 1 | 1 | 图标标签下的数字 |
209 |
210 |
211 |
212 | ##### 分拣器配置参数
213 |
214 | > [^2011, 2012, 2013, 2014]: 分拣器, 高速分拣器, 极速分拣器, 集装分拣器
215 |
216 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
217 | | ----------- | -------- | ------------- | ----------- | ------------------------- |
218 | | _parameters | Object | | 1 | |
219 | | - length | Number | 0 | 1 | 分拣器长度
-> 1 - 3 |
220 |
221 |
222 |
223 | ##### 四向分流器配置参数
224 |
225 | > [^2020]: 四向分流器
226 |
227 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
228 | | ----------------------- | -------- | ------------- | ----------- | -------------------- |
229 | | _parameters | Object | | 6 | |
230 | | - priority | Array(4) | 0 | 4 | 四向四个接口的优先级 |
231 | | - - *_array_item* | Boolean | *i* | 1 | 是否优先 |
232 |
233 |
234 |
235 | ##### 制造厂类建筑配置参数
236 |
237 | > [^2303, 2304, 2305, 2318, 2302, 2315, 2319, 2308, 2309, 2317, 2310]:制造台 Mk.I, 制造台 Mk.II, 制造台 Mk.III, 重组式制造台, 电弧熔炉, 位面熔炉, 负熵熔炉, 原油精炼厂, 化工厂, 量子化工厂, 微型粒子对撞机
238 |
239 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
240 | | -------------------- | -------- | ------------- | ----------- | --------------------------------------- |
241 | | _parameters | Object | | 1 | |
242 | | - acceleratorMode | Number | 0 | 1 | 增产效果
-> 0:额外产出 1:生产加速 |
243 |
244 |
245 |
246 | ##### 研究站配置参数
247 |
248 | > [^2901, 2902]: 矩阵研究站, 自演化研究站
249 |
250 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
251 | | -------------------- | -------- | ------------- | ----------- | ------------------------------------------------ |
252 | | _parameters | Object | | 2 | |
253 | | - researchMode | Number | 0 | 1 | 研究模式
-> 0:未选择 1:矩阵合成 2:科研模式 |
254 | | - acceleratorMode | Number | 1 | 1 | 增产效果
-> 0:额外产出 1:生产加速 |
255 |
256 |
257 |
258 | ##### 储物仓配置参数
259 |
260 | > [^2101, 2102]: 小型储物仓, 大型储物仓
261 |
262 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
263 | | ----------------------- | ---------------- | ------------- | ----------- | ------------------------------------------------- |
264 | | _parameters | Object | | 110 | |
265 | | - bans | Number | 0 | 1 | 限制不可自动放入的格子数 |
266 | | - storageType | Number | 1 | 1 | 储物仓类型
-> 0:不过滤 9:存在过滤器 |
267 | | - filters | Array(*gridNum*) | 10 | *gridNum* | 储物仓物品过滤器
*gridNum*: 建筑储物格子数目 |
268 | | - - *_array_item* | Number | 10 + *i* | 1 | 过滤物品id |
269 |
270 |
271 |
272 | ##### 储液罐配置参数
273 |
274 | > [^2106]: 储液罐
275 |
276 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
277 | | ----------- | -------- | ------------- | ----------- | -------- |
278 | | _parameters | Object | | 2 | |
279 | | - output | Boolean | 0 | 1 | 是否输出 |
280 | | - input | Boolean | 1 | 1 | 是否输入 |
281 |
282 |
283 |
284 | ##### 物流配送器配置参数
285 |
286 | > [^2107]: 物流配送器
287 |
288 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
289 | | ------------------------- | -------- | ------------- | ----------- | ------------------------------------------------------------ |
290 | | _parameters | Object | | 128 | |
291 | | - playerMode | Number | 0 | 1 | 机甲供需模式
-> 1:从伊卡洛斯回收
2:向伊卡洛斯供应和回收
3:向伊卡洛斯供应 |
292 | | - storageMode | Number | 1 | 1 | 配送器间模式
-> 0:不勾选 1:向其他配送器供应 2:向其他配送器需求 |
293 | | - workEnergyPerTick | Number | 2 | 1 | 最大充能功率(单位:MW)
-> 0.9 - 9 |
294 | | - courierAutoReplenish | Boolean | 3 | 1 | 是否自动补充运输单位 |
295 |
296 |
297 |
298 | ##### 运输站类建筑配置参数
299 |
300 | > [^2103, 2104, 2316]: 行星内物流运输站, 星际物流运输站, 大型采矿机
301 |
302 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
303 | | --------------------------- | ------------------- | ------------------- | ----------- | ------------------------------------------------------------ |
304 | | _parameters | Object | | 2048 | |
305 | | - storage | Array(*storageNum*) | 0 | 192 | 物品栏位参数
*storageNum*: 建筑栏位数目 |
306 | | - - *_array_item* | Object | *_L* = *i* * 6 | 6 | |
307 | | - - - itemId | Number | *_L* + 0 | 1 | 物品id |
308 | | - - - localRole | Number | *_L* + 1 | 1 | 本地供需配置
-> 0:本地仓储 1:本地供应 2:本地需求 |
309 | | - - - remoteRole | Number | *_L* + 2 | 1 | 星际供需配置
-> 0:星际仓储 1:星际供应 2:星际需求 |
310 | | - - - max | Number | *_L* + 3 | 1 | 物品上限 |
311 | | - - - lockAmount | Number | *_L* + 4 | 1 | 是否锁定数量
-> 0:不锁定 1:锁定满仓 2:锁定半仓 |
312 | | - slots | Array(*slotsNum*) | 192 | 320 | 传送带插槽参数
*slotsNum*: 建筑传送带插槽数目 |
313 | | - - *_array_item* | Object | *_L* =192 + *i* * 4 | 4 | |
314 | | - - - dir | Number | *_L* + 0 | 1 | 传送带接入方向
-> 0:未接入 1:输出 2:输入 |
315 | | - - - storageIdx | Number | *_L* + 1 | 1 | 输出货物对应物品栏索引
-> 0:不输出 1-5:物品栏索引 6:翘曲器 |
316 | | - workEnergyPerTick | Number | 320 | 1 | 最大充能功率(单位:MW)
-> 30 - 300 |
317 | | - tripRangeOfDrones | Number | 321 | 1 | 运输机最远路程(单位:度)
-> 20 - 180 |
318 | | - tripRangeOfShips | Number | 322 | 1 | 运输船最远路程
-> 1-60:有限路程(单位:ly) 10000:无限 |
319 | | - includeOrbitCollector | Boolean | 323 | 1 | 是否会去轨道采集器取货 |
320 | | - warpEnableDistance | Number | 324 | 1 | 曲速启用路程(单位:AU)
-> 0.5 - 60 |
321 | | - warperNecessary | Boolean | 325 | 1 | 是否翘曲器必备 |
322 | | - deliveryAmountOfDrones | Number | 326 | 1 | 运输机起送量(单位:%)
-> 1 - 100 |
323 | | - deliveryAmountOfShips | Number | 327 | 1 | 运输船起送量(单位:%)
-> 1-100 |
324 | | - pilerCount | Number | 328 | 1 | 输出货物集装数量
-> 0:使用科技上限 1-4:指定数量 |
325 | | - miningSpeed | Number | 329 | 1 | 开采速度 |
326 | | - droneAutoReplenish | Boolean | 330 | 1 | 是否自动补充运输机 |
327 | | - shipAutoReplenish | Boolean | 331 | 1 | 是否自动补充运输船 |
328 |
329 |
330 |
331 | ##### 流速监测器配置参数
332 |
333 | > [^2030]: 流速监测器
334 |
335 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
336 | | ------------------------- | -------- | ------------- | ----------- | ------------------------------------------------------------ |
337 | | _parameters | Object | | 128 | |
338 | | - targetBeltId | Number | 0 | 1 | 绑定的传送带节点ID
(实际id,不是蓝图index,疑似无效参数) |
339 | | - offset | Number | 1 | 1 | ? |
340 | | - targetCargoAmount | Number | 2 | 1 | 目标流量(单位:0.1个) |
341 | | - periodTicksCount | Number | 3 | 1 | 监测周期(单位:秒) |
342 | | - passOperator | Number | 4 | 1 | 监测条件
-> 0:等于 1:不等于 2:大于等于 3:大于 4:小于等于 5:小于 |
343 | | - passColorId | Number | 5 | 1 | 满足条件颜色索引
-> 0 - 255 |
344 | | - failColorId | Number | 6 | 1 | 不满足条件颜色索引
-> 0 - 255 |
345 | | - tone | Number | 7 | 1 | 声音警报-音色
-> 20-24:警报 1-2:钢琴 3-4:贝斯
5-6:风琴 7-9:铺底 10:铜管乐
11:梦铃 12:玻璃 13:吉他
14:音乐盒 15:电子琴 16:小号
17:小提琴 18:低音贝斯 19:鼓 |
346 | | - volume | Number | 8 | 1 | 声音警报-音量
-> 0 - 100 |
347 | | - pitch | Number | 9 | 1 | 声音警报-音阶
-> 例:25: C2 26: C#2 27: D2 ... |
348 | | - systemWarningMode | Number | 10 | 1 | 系统警报模式
-> 0:无 1:未满足条件 2:满足条件
3:有货物响 4:无货物响
5:未满足且有货物 6:未满足且无货物 |
349 | | - repeat | Boolean | 11 | 1 | 声音警报-是否循环 |
350 | | - alarmMode | Number | 12 | 1 | 声音警报模式
-> 0:无 1:未满足条件 2:满足条件
3:有货物响 4:无货物响
5:未满足且有货物 6:未满足且无货物 |
351 | | - length | Number | 13 | 1 | 声音警报-时长(只有音色为警报时有该参数)
-> 0.1 - 20 |
352 | | - cargoFilter | Number | 14 | 1 | 货物过滤物品id
-> 0:不过滤 物品id->过滤 |
353 | | - systemWarningIconId | Number | 17 | 1 | 系统警报图标id |
354 | | - falloffRadius | Array(2) | | | 声音警报-声音衰减范围 |
355 | | - - *_array_item_1* | Number | 18 | 1 | 开始衰减距离(单位:米)
-> 默认为 (*衰减为0距离* / 3)(0-133) |
356 | | - - *_array_item_2* | Number | 19 | 1 | 衰减为0距离(单位:米)
-> 1-400 |
357 | | - spawnItemOperator | Number | 20 | 1 | 生成/消耗货物模式
-> 0:不勾选 1:生成货物 2:消耗货物 |
358 |
359 |
360 |
361 | ##### 射线接收站配置参数
362 |
363 | > [^2208]: 射线接收站
364 |
365 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
366 | | -------------- | -------- | ------------- | ----------- | ------------------------------------- |
367 | | _parameters | Object | | 1 | |
368 | | - productId | Number | 0 | 1 | 模式
-> 0:直接发电 1208:光子生成 |
369 |
370 |
371 |
372 | ##### 能量枢纽配置参数
373 |
374 | > [^2209]: 能量枢纽
375 |
376 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
377 | | ----------- | -------- | ------------- | ----------- | ---------------------------------- |
378 | | _parameters | Object | | 1 | |
379 | | - mode | Number | 0 | 1 | 模式
-> -1:放电 0:待机 1:充电 |
380 |
381 |
382 |
383 | ##### 电磁轨道弹射器配置参数
384 |
385 | > [^2311]: 电磁轨道弹射器
386 |
387 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
388 | | ----------------- | -------- | ------------- | ----------- | ------------------------------------------- |
389 | | _parameters | Object | | 2 | |
390 | | - orbitId | Number | 0 | 1 | 送入轨道编号
-> 0:无 1-20:轨道列表编号 |
391 | | - tenfoldSpeed | Boolean | 1 | 1 | 是否开启十倍射速 |
392 |
393 |
394 |
395 | ##### 垂直发射井配置参数
396 |
397 | > [^2312]: 垂直发射井
398 |
399 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
400 | | ----------------- | -------- | ------------- | ----------- | ---------------- |
401 | | _parameters | Object | | 1 | |
402 | | - tenfoldSpeed | Boolean | 0 | 1 | 是否开启十倍射速 |
403 |
404 |
405 |
406 | ##### 战场分析基站配置参数
407 |
408 | > [^3009]: 战场分析基站
409 |
410 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
411 | | ----------------------- | --------- | --------------- | ---------------------------------- | -------------------------------------------------------- |
412 | | _parameters | Object | | 110 | |
413 | | - bans | Number | 0 | 1 | 限制不可自动放入的格子数 |
414 | | - storageType | Number | 1 | 1 | 储物仓类型
-> 0:不过滤 9:存在过滤器 |
415 | | - filters | Array(60) | 10 | *_L* = *storageType* == 0 ? 0 : 60 | 储物仓物品过滤器
*storageType*为0时忽略,不占偏移量 |
416 | | - - *_array_item* | Number | 10 + *i* | 1 | 过滤物品id |
417 | | - workEnergyPerTick | Number | *_L* + 10 | 1 | 最大充能功率(单位:MW)
-> 30 - 300 |
418 | | - autoPickEnabled | Boolean | *_L* + 11 | 1 | 是否自动拾取 |
419 | | - autoReplenishFleet | Boolean | *_L* + 12 | 1 | 是否自动补充编队 |
420 | | - moduleEnabled | Boolean | *_L* + 13 | 1 | 是否开启战斗无人机 |
421 | | - autoReconstruct | Boolean | *_L* + 14 | 1 | 是否自动标记重建 |
422 | | - droneEnabled | Boolean | *_L* + 15 | 1 | 是否开启建设无人机 |
423 | | - dronesPriority | Number | *_L* + 16 | 1 | 建设无人机模式
-> 0:优先修理 1:均衡模式 2:优先建造 |
424 | | - fighters | Array(12) | *_L* + 17 | 12 | 战斗无人机编队 |
425 | | - - *_array_item* | Number | *_L* + 17 + *i* | 1 | 无人机物品id |
426 |
427 |
428 |
429 | ##### 炮台类建筑配置参数
430 |
431 | > [^3001, 3002, 3003, 3004, 3005, 3006, 3010]: 高斯机枪塔, 高频激光塔, 聚爆加农炮, 磁化电浆炮, 导弹防御塔, 干扰塔, 近程电浆塔
432 |
433 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
434 | | ------------------------- | -------- | ------------- | ----------- | -------------------------------------------------- |
435 | | _parameters | Object | | 128 | |
436 | | - group | Number | 1 | 1 | 分组编号
-> 0:不分组 1-5:分组 |
437 | | - vsSettings | Array(4) | 2 | 1 | 攻击设置优先级 |
438 | | - - *_array_item_1* | Number | | | 地面优先级
-> 0:关闭 1:低优先 2:均衡 3:高优先 |
439 | | - - *_array_item_2* | Number | | | 低空优先级
-> 0:关闭 1:低优先 2:均衡 3:高优先 |
440 | | - - *_array_item_3* | Number | | | 高空优先级
-> 0:关闭 1:低优先 2:均衡 3:高优先 |
441 | | - - *_array_item_4* | Number | | | 太空优先级
-> 0:关闭 1:低优先 2:均衡 3:高优先 |
442 | | - phasePos | Number | 3 | 1 | 干扰塔相位偏移(单位:秒) -> 0-5 |
443 |
444 |
445 |
446 | ##### 默认配置参数解析(未知建筑参数)
447 |
448 | | 字段 | 字段类型 | 偏移量(Int32) | 长度(Int32) | 备注 |
449 | | ------------------- | ----------------------------- | ------------- | ----------------- | ---- |
450 | | _parameters | Object | | *parameterLength* | |
451 | | - _defaultParams | Int32Array(*parameterLength*) | 0 | *parameterLength* | |
452 |
453 |
454 |
455 |
456 |
457 | ### 安装依赖
458 |
459 | ```shell
460 | cnpm install
461 | ```
462 |
463 | ### 运行测试服务
464 |
465 | ```shell
466 | npm run serve
467 | ```
468 |
469 | ### 构建打包
470 |
471 | ```shell
472 | npm run build
473 | # 打包后可删除dist文件夹中的css及js文件夹(打包流冗余文件,所有代码已打包进html),仅保留index.html
474 | ```
475 |
--------------------------------------------------------------------------------