Skip to content

Commit

Permalink
logistic transport implemented
Browse files Browse the repository at this point in the history
  • Loading branch information
doubleaxe committed Mar 22, 2023
1 parent 0b72404 commit e3e2685
Show file tree
Hide file tree
Showing 17 changed files with 272 additions and 115 deletions.
1 change: 0 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,6 @@ Query string `?gameId=<game>` may be added to quickly open desired game, for exa

# TODO list

- Conveyors/Robotic arms/Pipes/etc.. support for link
- Color/Icon states for link and item (overflow, underflow, warning, etc..)
- Move/Delete entire blueprint, production chain or multiple factories (selection, edit)
- Apply counts calculated in locked mode to current factories
Expand Down
15 changes: 12 additions & 3 deletions data/evospace/calculator/calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ Author: Alexey Usov ([email protected], https://github.com/doubleaxe)
Please don't remove this comment if you use unmodified file
*/
import type {Calculator} from '#types/calculator';
import type {GameRecipeDictionary} from '#types/game-data';
import type {FromatCountPerSecond, GameItem, GameRecipeDictionary} from '#types/game-data';
import {GameItemType} from '#types/contants';
import {GameRecipeDictionaryExData, GameRecipeIOType} from '../types/custom-game-data';

Expand Down Expand Up @@ -48,8 +48,8 @@ export function useCalculator(): Calculator {
return (io.count * unitMul * Math.pow(1.5, tierDiff) * TICKS_PER_SECOND) / io.recipe.time;
};

const formatCountPerSecond: Calculator['formatCountPerSecond'] = function(io, count) {
const productType = io.product.type;
function formatCount(item: GameItem, count: number): FromatCountPerSecond {
const productType = item.type;
if(productType == GameItemType.Energy) {
//energy measured in Watts, 1 Resource Item [R] * 20 = 20 Watt
count *= 20;
Expand All @@ -62,6 +62,14 @@ export function useCalculator(): Calculator {
count,
unit: 'ps',
};
}

const formatCountPerSecond: Calculator['formatCountPerSecond'] = function(io, count) {
return formatCount(io.product, count);
};

const formatTransportFlow: Calculator['formatTransportFlow'] = function(transport, flow) {
return formatCount(transport.item, flow);
};

const isCommonIo: Calculator['isCommonIo'] = function(io) {
Expand All @@ -73,6 +81,7 @@ export function useCalculator(): Calculator {
return {
getCountPerSecond,
formatCountPerSecond,
formatTransportFlow,
isCommonIo,
};
}
2 changes: 2 additions & 0 deletions data/evospace/static/custom-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@ import type {GameLogisticSerialized} from '#types/game-data-serialized';

export const logistic: GameLogisticSerialized[] = [{
name: 'RobotArm90',
label: 'Robot Arm 90°',
items: [{
name: 'AnySolidStaticItem',
}],
Expand Down Expand Up @@ -38,6 +39,7 @@ export const logistic: GameLogisticSerialized[] = [{
stackable: true,
}, {
name: 'RobotArm180',
label: 'Robot Arm 180°',
items: [{
name: 'AnySolidStaticItem',
}],
Expand Down
13 changes: 11 additions & 2 deletions data/sample/calculator/calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -5,17 +5,25 @@ Please don't remove this comment if you use unmodified file
import type {
Calculator,
} from '#types/calculator';
import type {FromatCountPerSecond, GameItem} from '#types/game-data';

export function useCalculator(): Calculator {
const getCountPerSecond: Calculator['getCountPerSecond'] = function(item, io) {
return io.count * (item.recipe?.tier || 1) / io.recipe.time;
};

const formatCountPerSecond: Calculator['formatCountPerSecond'] = function(io, count) {
function formatCount(item: GameItem, count: number): FromatCountPerSecond {
return {
count,
unit: (io.product.name == 'R') ? 'W' : 'ps',
unit: (item.name == 'R') ? 'W' : 'ps',
};
}
const formatCountPerSecond: Calculator['formatCountPerSecond'] = function(io, count) {
return formatCount(io.product, count);
};

const formatTransportFlow: Calculator['formatTransportFlow'] = function(transport, flow) {
return formatCount(transport.item, flow);
};

const isCommonIo: Calculator['isCommonIo'] = function(io) {
Expand All @@ -25,6 +33,7 @@ export function useCalculator(): Calculator {
return {
getCountPerSecond,
formatCountPerSecond,
formatTransportFlow,
isCommonIo,
};
}
2 changes: 2 additions & 0 deletions site/data/types/calculator.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,11 +6,13 @@ Please don't remove this comment if you use unmodified file
import type {
FromatCountPerSecond,
GameItem,
GameLogisticTransport,
GameRecipeIO,
} from './game-data';

export interface Calculator {
getCountPerSecond: (item: GameItem, io: GameRecipeIO) => number;
formatCountPerSecond: (io: GameRecipeIO, count: number) => FromatCountPerSecond;
formatTransportFlow: (transport: GameLogisticTransport, flow: number) => FromatCountPerSecond;
isCommonIo: (io: GameRecipeIO) => boolean;
}
1 change: 1 addition & 0 deletions site/data/types/game-data-serialized.ts
Original file line number Diff line number Diff line change
Expand Up @@ -85,6 +85,7 @@ export interface GameLogisticTransportSerialized {
export interface GameLogisticSerialized {
name: string;
longName?: string;
label?: string;
items: GameLogisticItemSerialized[];
transport: GameLogisticTransportSerialized[];
time: number;
Expand Down
1 change: 1 addition & 0 deletions site/data/types/game-data.ts
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ export interface GameLogisticTransportRaw extends GameLogisticTransportSerialize
logistic: GameLogistic;
item: GameItem;
countPerSecond: number;
formatCountPerSecond: (count: number) => FromatCountPerSecond;
}
export type GameLogisticTransport = Readonly<GameLogisticTransportRaw>;

Expand Down
24 changes: 21 additions & 3 deletions site/src/components/main-panel/link-menu.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@ Please don't remove this comment if you use unmodified file
-->
<script setup lang="ts">
import type {LinkModel} from '@/scripts/model/store';
import {computed, ref} from 'vue';
import {computed, ref, watch} from 'vue';
import {mdiLinkOff} from '@mdi/js';
import {formatIo} from '@/scripts/format';
Expand All @@ -23,8 +23,16 @@ const logisticSet = computed(() => {
}
return [..._logistic.logistic];
});
const flowTotal = computed(() => props.link?.input ? formatIo(props.link.flow, props.link.input) : '');
const flowTotal = computed(() => {
const io = props.link?.input || props.link?.output;
return io ? formatIo(props.link.flow, io) : '';
});
watch(menuOpened, (value, oldValue) => {
if(!oldValue && value) {
props.link?.logistic?.resetSelectedTransport();
}
});
</script>

<template>
Expand All @@ -41,7 +49,13 @@ const flowTotal = computed(() => props.link?.input ? formatIo(props.link.flow, p
@click="props.link?.deleteThis(); menuOpened = false;"
/>
<template v-if="logisticSet.length">
<v-list-item :title="flowTotal" />
<v-list-item class="minwidth">
<v-list-item-title>
<div class="transport-menu-item">
<icon-component :image="props.link?.input?.image" /> {{ flowTotal }}
</div>
</v-list-item-title>
</v-list-item>
<template v-for="logistic in logisticSet" :key="logistic.name">
<logistic-panel :logistic="logistic" />
</template>
Expand All @@ -51,4 +65,8 @@ const flowTotal = computed(() => props.link?.input ? formatIo(props.link.flow, p
</template>
<style scoped>
.transport-menu-item {
display: flex;
align-items: center;
}
</style>
57 changes: 53 additions & 4 deletions site/src/components/main-panel/logistic-panel.vue
Original file line number Diff line number Diff line change
Expand Up @@ -4,19 +4,68 @@ Please don't remove this comment if you use unmodified file
-->
<script setup lang="ts">
import type {LogisticModel} from '@/scripts/model/store';
import {computed} from 'vue';
import {computed, unref} from 'vue';
import {formatTransport} from '@/scripts/format';
import {mdiTransferLeft, mdiTransferRight, mdiLock, mdiLockOpenVariant} from '@mdi/js';
const props = defineProps<{
logistic?: LogisticModel;
}>();
const countPerSecond = computed(() => props.logistic?.calculateTransport()?.countPerSecond);
const selectedTransport = computed(() => props.logistic?.selectedTransport);
const count = computed(() => unref(selectedTransport)?.count || 0);
const countPerSecond = computed(() => {
const _selectedTransport = unref(selectedTransport);
const _count = unref(count) || 0;
if(_selectedTransport && (_count > 1)) {
return formatTransport(_selectedTransport.countPerSecond, _selectedTransport);
}
return '';
});
const totalCountPerSecond = computed(() => {
const _selectedTransport = unref(selectedTransport);
const _count = unref(count) || 0;
if(_selectedTransport) {
const _countPerSecond = _count * _selectedTransport.countPerSecond;
return formatTransport(_countPerSecond, _selectedTransport);
}
return '';
});
const isLocked = computed(() => props.logistic?.isLocked);
</script>

<template>
<v-list-item :title="countPerSecond" />
<v-list-item>
<v-list-item-title>
<div class="font-weight-bold text-caption">
{{ selectedTransport?.label }}
</div>
<div class="transport-menu-item">
{{ count }}&nbsp;x&nbsp;
<icon-component :image="selectedTransport?.item?.image" />&nbsp;
{{ totalCountPerSecond }}&nbsp;
<span class="text-caption">{{ countPerSecond }}</span>
</div>
</v-list-item-title>
<template #prepend>
<v-btn icon size="x-small" @click="props.logistic?.switchSelectedTransport(-1)">
<v-icon :icon="mdiTransferLeft" />
</v-btn>
<v-btn icon size="x-small" class="mr-2" @click="props.logistic?.switchSelectedTransport(1)">
<v-icon :icon="mdiTransferRight" />
</v-btn>
</template>
<template #append>
<v-btn icon size="x-small" class="ml-2" @click="props.logistic?.toggleLockSelected()">
<v-icon :icon="isLocked ? mdiLock : mdiLockOpenVariant" :color="isLocked ? 'success' : ''" />
</v-btn>
</template>
</v-list-item>
</template>

<style scoped>
.transport-menu-item {
display: flex;
align-items: center;
}
</style>
4 changes: 3 additions & 1 deletion site/src/scripts/data/game-data-holder.ts
Original file line number Diff line number Diff line change
Expand Up @@ -72,7 +72,7 @@ export function useGameDataHolder(gameImplementation: GameImplementation) {

const emptyRecipeDictionary = parsedGameData.emptyRecipeDictionary;

return {
const gameData = {
gameItemsMap,
gameItemsArray,
gameAbstractItems: freezeMap(gameAbstractItems),
Expand All @@ -91,6 +91,8 @@ export function useGameDataHolder(gameImplementation: GameImplementation) {
getImage: (name: string) => parsedGameData.images[name],
gameDescription: parsedGameData.description,
};
Object.freeze(gameData);
return gameData;
}

export type GameData = ReturnType<typeof useGameDataHolder>;
43 changes: 29 additions & 14 deletions site/src/scripts/data/game-data-parser.ts
Original file line number Diff line number Diff line change
Expand Up @@ -238,37 +238,52 @@ function createRecipeDictionaryImpl(calculator: Calculator, _recipeDictionary: G
return recipeDictionaryImpl;
}

function createLogisticTransportImpl(logistic: GameLogistic, _transport: GameLogisticTransportSerialized, item: GameItem) {
const transportImpl: GameLogisticTransportRaw = {
function createLogisticTransportImpl(logisticImpl: Readonly<GameLogisticImpl>, _transport: GameLogisticTransportSerialized, item: GameItem) {
const {calculator, logistic} = logisticImpl;
const transport: GameLogisticTransportRaw = {
..._transport,
logistic,
item,
countPerSecond: _transport.count / logistic.time,
formatCountPerSecond(count: number) {
return calculator.formatTransportFlow(this, count);
},
};
Object.freeze(transportImpl);
const transport: GameLogisticTransport = transportImpl;
return transport;
Object.freeze(transport);
const transportResult: GameLogisticTransport = transport;
return transportResult;
}

function createLogisticImpl(_logistic: GameLogisticSerialized, parsedItems: ParsedItems) {
const logisticImpl: GameLogisticRaw = {
//package private recipe dictionary
type GameLogisticImpl = {
logistic: GameLogistic;
calculator: Calculator;
};
function createLogisticImpl(_logistic: GameLogisticSerialized, parsedItems: ParsedItems, calculator: Calculator) {
const logistic: GameLogisticRaw = {
..._logistic,
transport: [],
};
const logisticImpl: GameLogisticImpl = {
logistic,
calculator,
};

for(const transport of logisticImpl.transport) {
for(const transport of _logistic.transport) {
const item = parsedItems.get(transport.name);
if(!item)
continue;
const transportImpl = createLogisticTransportImpl(logisticImpl, transport, item);
logisticImpl.transport.push(transportImpl);
logistic.transport.push(transportImpl);
}

logisticImpl.transport.sort((a, b) => (a.countPerSecond - b.countPerSecond));
logistic.transport.sort((a, b) => (a.countPerSecond - b.countPerSecond));

Object.freeze(logisticImpl);
const logistic: GameLogistic = logisticImpl;
return logistic;
Object.freeze(logistic);
Object.freeze(logistic.transport);
Object.freeze(logistic.items);
const logisticResult: GameLogistic = logistic;
return logisticResult;
}

type DescriptionData = {
Expand Down Expand Up @@ -338,7 +353,7 @@ export function useGameDataParser(gameImplementation: GameImplementation): Parse
recipeDictionaryImpl._postInit(parsedItemsImpl);
}

const parsedLogistic = gameData.logistic?.map((logistic) => createLogisticImpl(logistic, parsedItems)) || [];
const parsedLogistic = gameData.logistic?.map((logistic) => createLogisticImpl(logistic, parsedItems, calculator)) || [];
Object.freeze(parsedLogistic);

const description = createDescriptionImpl(gameData.description, {minTier, maxTier});
Expand Down
5 changes: 5 additions & 0 deletions site/src/scripts/filter.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
Author: Alexey Usov ([email protected], https://github.com/doubleaxe)
Please don't remove this comment if you use unmodified file
*/
import type {GameItemType} from '#types/contants';
import type {GameItem} from '#types/game-data';
import {type InjectionKey, provide, reactive, inject} from 'vue';
import type {GameData} from './data';
Expand All @@ -13,6 +14,7 @@ class Filter {
private _tierEqual = 0;
private _groupTier = true;
private _key?: string;
private _type?: GameItemType;
private _direction = 0;
private _filtered?: GameItem[][];

Expand All @@ -32,6 +34,9 @@ class Filter {
get key() { return this._key; }
set key(key: string | undefined) { this._key = key; this._filtered = undefined; }

get type() { return this._type; }
set type(type: GameItemType | undefined) { this._type = type; this._filtered = undefined; }

get direction() { return this._direction; }
set direction(direction: number) { this._direction = direction; this._filtered = undefined; }

Expand Down
9 changes: 8 additions & 1 deletion site/src/scripts/format.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@
Author: Alexey Usov ([email protected], https://github.com/doubleaxe)
Please don't remove this comment if you use unmodified file
*/
import type {RecipeIOModel} from './model/store';
import type {RecipeIOModel, TransportModel} from './model/store';

const decimals = 3;
const upperPrefixes = ['k', 'M', 'G', 'T', 'P', 'E', 'Z', 'Y', 'R', 'Q'];
Expand Down Expand Up @@ -49,3 +49,10 @@ export function formatIo(n: number | undefined, io: RecipeIOModel) {
const format = io.formatCountPerSecond(n);
return formatNumber(format.count, format.unit);
}

export function formatTransport(n: number | undefined, transport: TransportModel) {
if(n === undefined)
return '';
const format = transport.formatCountPerSecond(n);
return formatNumber(format.count, format.unit);
}
Loading

0 comments on commit e3e2685

Please sign in to comment.