SB fetch and entry

This commit is contained in:
Kilian Hofmann 2025-06-11 23:49:35 +02:00
parent 896a459bba
commit 8975ea17af
11 changed files with 156 additions and 237 deletions

View File

@ -1,6 +1,11 @@
import { FC, StrictMode, useCallback, useEffect, useState } from 'react';
import { FC, useCallback, useEffect, useState } from 'react';
import Pax from './components/pax/Pax';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_LIVE_DATA_EVENT, TFDI_SIMBRIEF_USERNAME_EVENT } from './constants';
import {
COHERENT_COMBUS_WASM_CALL,
COMM_BUS_LIVE_DATA_EVENT,
TFDI_SIMBRIEF_USERNAME_CALL,
TFDI_SIMBRIEF_USERNAME_EVENT,
} from './constants';
import { WASMDataPax } from './types/WASMData';
interface IAppProps {
@ -23,35 +28,33 @@ const App: FC<IAppProps> = ({ commBus }) => {
useEffect(() => {
console.log('Initializing CommBus');
commBus.on(COMM_BUS_LIVE_DATA_EVENT, usernameCallback);
commBus.on(TFDI_SIMBRIEF_USERNAME_EVENT, usernameCallback);
commBus.on(COMM_BUS_LIVE_DATA_EVENT, wasmCallback);
setTimeout(() => {
Coherent.call(COHERENT_COMBUS_WASM_CALL, TFDI_SIMBRIEF_USERNAME_EVENT, 'null');
Coherent.call(COHERENT_COMBUS_WASM_CALL, TFDI_SIMBRIEF_USERNAME_CALL, 'null');
}, 1000);
return () => {
commBus.off('receiveSimBriefUsername', usernameCallback);
commBus.off(TFDI_SIMBRIEF_USERNAME_EVENT, usernameCallback);
commBus.off(COMM_BUS_LIVE_DATA_EVENT, wasmCallback);
};
}, []);
return (
<StrictMode>
<div className="flex w-full justify-center pt-2 bg-zinc-900">
<div className="flex w-3/4 flex-col items-center">
{isReady && WASMData ? (
WASMData.userData.isCargo ? (
<>Not yet Implemented</>
) : (
<Pax WASMData={WASMData} username={SBUsername} />
)
<div className="flex w-full justify-center pt-2 bg-zinc-900">
<div className="flex w-3/4 flex-col items-center">
{isReady && WASMData ? (
WASMData.userData.isCargo ? (
<>Not yet Implemented</>
) : (
<h1 className="text-sm font-medium">LOADING</h1>
)}
</div>
<Pax WASMData={WASMData} username={SBUsername} />
)
) : (
<h1 className="text-sm font-medium">LOADING</h1>
)}
</div>
</StrictMode>
</div>
);
};

View File

@ -1,111 +1,43 @@
import { FC, useEffect, useState } from 'react';
import { PaxConfig, PayloadPax } from '../../configs/pax';
import { Fuel, SharedConfig } from '../../configs/shared';
import { FC, useEffect, useRef, useState } from 'react';
import { emptyAircraft } from '../../configs/shared';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
import { WASMDataPax } from '../../types/WASMData';
import { LoadingState } from '../../types/general';
import { ImportFlightPlan } from '../../utils/TFDISBImport';
import CGSelect from '../CGSelect/CGSelect';
import ActionBar from '../actionbar/ActionBar';
interface StationEntryProps {
unit: 'kg' | 'lbs';
isER: boolean;
initialPayload: PayloadPax;
fuelLive: Fuel;
payloadLive: PayloadPax;
loadingState: 'preview' | 'accepted' | 'loaded';
interface SBEntryProps {
WASMData: WASMDataPax;
loadingState: LoadingState;
username: string;
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
updateView: (payload: PayloadPax) => void;
setLoadingState: (newState: LoadingState) => void;
loadAircraft: () => void;
}
const SBEntryPax: FC<StationEntryProps> = ({
unit,
isER,
initialPayload,
fuelLive,
payloadLive,
loadingState,
username,
setLoadingState,
updateView,
loadAircraft,
}) => {
const [targetZFWCG, setTargetZFWCG] = useState(SharedConfig.CGLimits.default);
const [fuel, setFuel] = useState(
Math.round(
fuelLive.main1 +
fuelLive.main1Tip +
fuelLive.main2 +
fuelLive.main3 +
fuelLive.main3Tip +
fuelLive.upperAux +
fuelLive.lowerAux +
fuelLive.tail +
fuelLive.forwardAux1 +
fuelLive.forwardAux2
)
);
const [ZFW, setZFW] = useState(
Math.round(
PaxConfig.weights.base[unit].total +
(isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) +
payloadLive.empty +
initialPayload.business1Left +
initialPayload.business1Center +
initialPayload.business1Right +
initialPayload.business2Left +
initialPayload.business2Center +
initialPayload.business2Right +
initialPayload.economy1Left +
initialPayload.economy1Center +
initialPayload.economy1Right +
initialPayload.economy2Left +
initialPayload.economy2Center +
initialPayload.economy2Right +
initialPayload.forwardCargo +
initialPayload.rearCargo
)
);
const SBEntryPax: FC<SBEntryProps> = ({ WASMData, loadingState, username, setLoadingState, loadAircraft }) => {
const [CGTarget, setCGTarget] = useState(WASMData.targetPayload.CGTarget);
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
const [fuelEnabled, setFuelEnabled] = useState(true);
const [SBPlan, setSBPlan] = useState<any>();
const [SBInFlight, setSBInFlight] = useState(false);
const _ZFW = () => {
if (loadingState !== 'loaded') return ZFW;
const numPax = useRef(0);
const cargo = useRef(0);
return Math.round(
payloadLive.empty +
payloadLive.pilot +
payloadLive.firstOfficer +
payloadLive.engineer +
payloadLive.cabinCrewFront +
payloadLive.business1Left +
payloadLive.business1Center +
payloadLive.business1Right +
payloadLive.business2Left +
payloadLive.business2Center +
payloadLive.business2Right +
payloadLive.economy1Left +
payloadLive.economy1Center +
payloadLive.economy1Right +
payloadLive.economy2Left +
payloadLive.economy2Center +
payloadLive.economy2Right +
payloadLive.cabinCrewRear +
payloadLive.forwardCargo +
payloadLive.rearCargo +
payloadLive.leftAuxPax +
payloadLive.rightAuxPax
);
const ZFW = () => {
if (loadingState !== 'loaded') return Math.round(WASMData.targetPayload.total);
return Math.round(WASMData.livePayload.total);
};
const ZFWValid = () => {
return _ZFW() <= PaxConfig.maxZWF[unit];
return ZFW() <= WASMData.limits.maxZFW;
};
const GW = () => {
return fuel + _ZFW();
return fuel + ZFW();
};
const GWValid = () => {
return GW() <= (isER ? SharedConfig.maxTOW.er[unit] : SharedConfig.maxTOW.norm[unit]);
return GW() <= WASMData.limits.maxTOW;
};
const handleInput = (input: string, maxValue: number, setter: (value: number) => void) => {
@ -125,49 +57,89 @@ const SBEntryPax: FC<StationEntryProps> = ({
const handleSB = async () => {
setSBInFlight(true);
const SBResponse = await ImportFlightPlan(username, PaxConfig, unit, isER);
const SBResponse = await ImportFlightPlan(
username,
WASMData.limits.maxZFW,
WASMData.limits.maxTOW,
WASMData.limits.maxFuel,
WASMData.userData.isImperial
);
if (SBResponse.type === 'error') {
console.error('TODO: ERROR', SBResponse.message);
setSBInFlight(false);
return;
}
const __ZFW = Math.round(
PaxConfig.weights.base[unit].total +
(isER ? SharedConfig.erExtraWeight[unit] * 2 : 0) +
payloadLive.empty +
SBResponse.message.pax * (PaxConfig.weights.pax[unit] + PaxConfig.weights.baggage[unit]) +
SBResponse.message.cargo
);
const _fuel = SBResponse.message.fuel;
cargo.current = parseFloat(SBResponse.message.cargo) ?? 0;
numPax.current = parseInt(SBResponse.message.pax) ?? 0;
updateView(
PaxConfig.distribute(__ZFW, targetZFWCG, payloadLive.empty, fuelLive, unit, isER, SBResponse.message.pax)
);
updateData();
setSBPlan(SBResponse.message);
setZFW(__ZFW);
setFuel(_fuel);
setFuel(parseFloat(SBResponse.message.fuel) ?? 0);
setSBInFlight(false);
};
useEffect(
() =>
setFuel((prev) =>
prev > (isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit])
? isER
? SharedConfig.maxFuel.er[unit]
: SharedConfig.maxFuel.norm[unit]
: prev
),
[isER]
setFuel((prev) => {
if (prev > WASMData.limits.maxFuel) return WASMData.limits.maxFuel;
return prev;
}),
[WASMData.userData.isER]
);
useEffect(() => {
setFuelEnabled(Math.round(WASMData.livePayload.fuel) === fuel);
}, [WASMData.livePayload.fuel]);
const updateData = (_CGTarget?: number) => {
Coherent.call(
COHERENT_COMBUS_WASM_CALL,
COMM_BUS_UPDATE_TARGET_EVENT,
JSON.stringify({
mode: 0,
cargo: cargo.current ?? 0,
numPax: numPax.current ?? 0,
CGTarget: _CGTarget ?? CGTarget,
})
);
};
return (
<>
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
<div className="relative flex w-full items-center justify-between rounded-md bg-zinc-600 p-2 px-4">
<label>Fuel ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
<input
type="text"
placeholder=""
className={`w-1/2 rounded-lg border border-white bg-zinc-700 px-3 py-2 text-right`}
value={fuel}
onChange={(e) => handleInput(e.target.value, WASMData.limits.maxFuel, setFuel)}
disabled={loadingState !== 'preview'}
/>
<button
className="middle none center rounded-lg bg-green-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-green-500/20 transition-all hover:shadow-lg hover:shadow-green-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
data-ripple-light="true"
onClick={() => {
SimVar.SetSimVarValue(
'L:MD11_EFB_PAYLOAD_FUEL',
'lbs',
WASMData.userData.isImperial ? fuel : fuel * 2.20462262185
);
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
setFuelEnabled(false);
}}
disabled={loadingState !== 'preview' || !fuelEnabled}
>
Load Fuel
</button>
</div>
</div>
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
<label>Planned ZFW ({unit})</label>
<label>Planned ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
<input
type="text"
placeholder=""
@ -177,7 +149,7 @@ const SBEntryPax: FC<StationEntryProps> = ({
/>
</div>
<div className="relative flex w-full items-center justify-between bg-zinc-700 p-2 px-4">
<label>Planned ZFW ({unit})</label>
<label>Planned ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})</label>
<input
type="text"
placeholder=""
@ -188,22 +160,24 @@ const SBEntryPax: FC<StationEntryProps> = ({
</div>
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-600 p-2 px-4">
<label>
Target ZFWCG ({SharedConfig.CGLimits.min} - {SharedConfig.CGLimits.max})
Target ZFWCG ({WASMData.limits.minCG} - {WASMData.limits.maxCG})
</label>
<CGSelect
value={targetZFWCG}
minCG={WASMData.limits.minCG}
maxCG={WASMData.limits.maxCG}
value={CGTarget}
disabled={loadingState !== 'preview'}
increase={() =>
setTargetZFWCG((prev) => {
setCGTarget((prev) => {
const _new = prev + 0.1;
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
updateData(_new);
return _new;
})
}
decrease={() =>
setTargetZFWCG((prev) => {
setCGTarget((prev) => {
const _new = prev - 0.1;
updateView(PaxConfig.distribute(ZFW, _new, payloadLive.empty, fuelLive, unit, isER));
updateData(_new);
return _new;
})
}
@ -211,53 +185,22 @@ const SBEntryPax: FC<StationEntryProps> = ({
</div>
</div>
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
<div className="relative flex w-full items-center justify-between rounded-md bg-zinc-600 p-2 px-4">
<label>Fuel ({unit})</label>
<input
type="text"
placeholder=""
className={`w-1/2 rounded-lg border border-white bg-zinc-700 px-3 py-2 text-right`}
value={fuel}
onChange={(e) =>
handleInput(
e.target.value,
isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit],
setFuel
)
}
disabled
/>
<button
className="middle none center rounded-lg bg-green-600 px-6 py-3 font-sans text-xs font-bold uppercase text-white shadow-md shadow-green-500/20 transition-all hover:shadow-lg hover:shadow-green-500/40 focus:opacity-[0.85] focus:shadow-none active:opacity-[0.85] active:shadow-none disabled:pointer-events-none disabled:opacity-50 disabled:shadow-none"
data-ripple-light="true"
onClick={() => {
SimVar.SetSimVarValue('L:MD11_EFB_PAYLOAD_FUEL', 'lbs', unit === 'kg' ? fuel * 2.20462262185 : fuel);
SimVar.SetSimVarValue('L:MD11_EFB_READ_READY', 'bool', true);
}}
disabled={loadingState !== 'preview' || SBInFlight}
>
Load Fuel
</button>
</div>
</div>
<div className="block flex w-full flex-col opacity-100 transition-opacity duration-150 ease-linear mb-4">
<div className="relative flex w-full items-center justify-between rounded-t-md bg-zinc-600 p-2 px-4">
<label>
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} ZFW ({unit})
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} ZFW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})
</label>
<input
type="text"
placeholder=""
className={`w-1/2 rounded-lg border ${ZFWValid() ? 'border-white' : 'border-red-500 text-red-500'} bg-zinc-700 px-3 py-2 text-right`}
disabled
value={_ZFW()}
value={ZFW()}
/>
</div>
<div className="relative flex w-full items-center justify-between rounded-b-md bg-zinc-700 p-2 px-4">
<label>
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} GW ({unit})
{loadingState !== 'loaded' ? 'Expected' : 'Actual'} GW ({WASMData.userData.isImperial ? 'lbs' : 'kg'})
</label>
<input
type="text"
@ -272,7 +215,6 @@ const SBEntryPax: FC<StationEntryProps> = ({
<ActionBar
loadingState={loadingState}
acceptDisabled={!GWValid() || SBInFlight}
//TODO: Make GSX optional (accepted state for NON GSX)
accept={() => setLoadingState('loaded')}
reject={() => setLoadingState('preview')}
importSB={handleSB}
@ -284,7 +226,7 @@ const SBEntryPax: FC<StationEntryProps> = ({
unload={() => {
setLoadingState('preview');
PaxConfig.unload(unit, isER);
emptyAircraft();
}}
/>
</>

View File

@ -1,7 +1,8 @@
import { FC } from 'react';
import { LoadingState } from '../../types/general';
interface ActionBarProps {
loadingState: 'preview' | 'accepted' | 'loaded';
loadingState: LoadingState;
acceptDisabled: boolean;
accept: () => void;
reject: () => void;

View File

@ -1,6 +1,8 @@
import { FC, useState } from 'react';
import { LoadingState } from '../../types/general';
import { WASMDataPax } from '../../types/WASMData';
import Profile from '../profile/Profile';
import SBEntryPax from '../SBEntry/SBEntryPax';
import StationEntryPax from '../stationEntry/StationEntryPax';
import Tabbar from '../tabbar/Tabbar';
import ZFWEntryPax from '../zfwEntry/ZFWEntryPax';
@ -12,24 +14,24 @@ interface PaxProps {
const Pax: FC<PaxProps> = ({ WASMData, username }) => {
const [selectedTab, setSelectedTab] = useState(0);
const [loadingState, setLoadingState] = useState<'preview' | 'accepted' | 'loaded'>('preview');
const [loadingState, setLoadingState] = useState<LoadingState>('preview');
const upper1 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
const upper1 = (overrideState: LoadingState = loadingState) => {
if (overrideState !== 'loaded') return WASMData.targetPayload.business1;
return WASMData.livePayload.business1;
};
const upper2 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
const upper2 = (overrideState: LoadingState = loadingState) => {
if (overrideState !== 'loaded') return WASMData.targetPayload.business2;
return WASMData.livePayload.business2;
};
const upper3 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
const upper3 = (overrideState: LoadingState = loadingState) => {
if (overrideState !== 'loaded') return WASMData.targetPayload.economy1;
return WASMData.livePayload.economy1;
};
const upper4 = (overrideState: 'preview' | 'accepted' | 'loaded' = loadingState) => {
const upper4 = (overrideState: LoadingState = loadingState) => {
if (overrideState !== 'loaded') return WASMData.targetPayload.economy2;
return WASMData.livePayload.economy2;
@ -101,28 +103,17 @@ const Pax: FC<PaxProps> = ({ WASMData, username }) => {
selectedTab={selectedTab}
setSelectedTab={setSelectedTab}
/>
{/*
{username && selectedTab === 0 && (
<SBEntryPax
unit={unit}
isER={isER}
initialPayload={payload}
fuelLive={fuelLive}
payloadLive={payloadLive}
WASMData={WASMData}
loadingState={loadingState}
username={username}
setLoadingState={setLoadingState}
updateView={(_payload) => {
setPayload(_payload);
}}
loadAircraft={() => {
PaxConfig.setBaseWeight(unit, isER);
PaxConfig.setWeights(payload, unit);
console.log('SET WEIGHT SB');
}}
/>
)}
*/}
{((username && selectedTab === 1) || (!username && selectedTab === 0)) && (
<ZFWEntryPax
WASMData={WASMData}

View File

@ -1,13 +1,14 @@
import { FC, useEffect, useState } from 'react';
import { emptyAircraft } from '../../configs/shared';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
import { LoadingState } from '../../types/general';
import { WASMDataPax } from '../../types/WASMData';
import ActionBar from '../actionbar/ActionBar';
interface StationEntryProps {
WASMData: WASMDataPax;
loadingState: 'preview' | 'accepted' | 'loaded';
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
loadingState: LoadingState;
setLoadingState: (newState: LoadingState) => void;
loadAircraft: () => void;
}

View File

@ -2,22 +2,21 @@ import { FC, useEffect, useState } from 'react';
import { emptyAircraft } from '../../configs/shared';
import { COHERENT_COMBUS_WASM_CALL, COMM_BUS_UPDATE_TARGET_EVENT } from '../../constants';
import { WASMDataPax } from '../../types/WASMData';
import { LoadingState } from '../../types/general';
import CGSelect from '../CGSelect/CGSelect';
import ActionBar from '../actionbar/ActionBar';
interface StationEntryProps {
interface ZFWEntryProps {
WASMData: WASMDataPax;
loadingState: 'preview' | 'accepted' | 'loaded';
setLoadingState: (newState: StationEntryProps['loadingState']) => void;
loadingState: LoadingState;
setLoadingState: (newState: LoadingState) => void;
loadAircraft: () => void;
}
const ZFWEntryPax: FC<StationEntryProps> = ({ WASMData, loadingState, setLoadingState, loadAircraft }) => {
const ZFWEntryPax: FC<ZFWEntryProps> = ({ WASMData, loadingState, setLoadingState, loadAircraft }) => {
const [CGTarget, setCGTarget] = useState(WASMData.targetPayload.CGTarget);
const [fuel, setFuel] = useState(Math.round(WASMData.livePayload.fuel));
const [ZFWTarget, setZFWTarget] = useState(
Math.round(Math.max(WASMData.limits.minZFW, WASMData.targetPayload.total))
);
const [ZFWTarget, setZFWTarget] = useState(Math.round(WASMData.targetPayload.total));
const [fuelEnabled, setFuelEnabled] = useState(true);
const ZFW = () => {

View File

@ -1,5 +1,8 @@
export const COHERENT_COMBUS_WASM_CALL = 'COMM_BUS_WASM_CALLBACK';
export const TFDI_SIMBRIEF_USERNAME_EVENT = 'requestSimBriefUsername';
export const TFDI_SIMBRIEF_USERNAME_CALL = 'requestSimBriefUsername';
export const TFDI_SIMBRIEF_USERNAME_EVENT = 'receiveSimBriefUsername';
export const COMM_BUS_LIVE_DATA_EVENT = 'khofmann_tfdi_md-11_load_manager_live_data';
export const COMM_BUS_UPDATE_TARGET_EVENT = 'khofmann_tfdi_md-11_load_manager_update_target';

View File

@ -0,0 +1 @@
export type LoadingState = 'preview' | 'accepted' | 'loaded';

View File

@ -1,11 +0,0 @@
import { CSSProperties, DOMAttributes, ReactNode } from 'react';
type CustomElement<T> = Partial<T & DOMAttributes<T> & { children: ReactNode }>;
declare global {
namespace JSX {
interface IntrinsicElements {
['virtual-scroll']: CustomElement<{ class?: string; direction: 'x' | 'y'; style?: CSSProperties }>;
}
}
}

View File

@ -1,6 +1,3 @@
import { PaxConfig } from '../configs/pax';
import { SharedConfig } from '../configs/shared';
const getSimBriefFlightPlan = async (simBriefUsername: string) => {
const flightPlanURL = `https://www.simbrief.com/api/xml.fetcher.php?username=${simBriefUsername}&json=1`;
let response: Response;
@ -19,9 +16,10 @@ const getSimBriefFlightPlan = async (simBriefUsername: string) => {
export const ImportFlightPlan = async (
username: string,
config: typeof PaxConfig,
unit: 'kg' | 'lbs',
isER: boolean
maxZFW: number,
maxTOW: number,
maxFuel: number,
isImperial: boolean
) => {
const flightPlan = await getSimBriefFlightPlan(username);
if (!flightPlan.success) {
@ -41,23 +39,17 @@ export const ImportFlightPlan = async (
}
let convFactor = 1;
if (data.params.units === 'kgs' && unit === 'lbs') convFactor = 2.20462262185;
if (data.params.units === 'lbs' && unit === 'kg') convFactor = 1 / 2.20462262185;
if (data.params.units === 'kgs' && isImperial) convFactor = 2.20462262185;
if (data.params.units === 'lbs' && !isImperial) convFactor = 1 / 2.20462262185;
return {
type: 'data',
message: {
plannedZFW: Math.min(config.maxZWF[unit], Math.round(data.weights.est_zfw * convFactor)),
plannedGW: Math.min(
isER ? SharedConfig.maxTOW.er[unit] : SharedConfig.maxTOW.norm[unit],
Math.round(data.weights.est_ramp * convFactor)
),
plannedZFW: Math.min(maxZFW, Math.round(data.weights.est_zfw * convFactor)),
plannedGW: Math.min(maxTOW, Math.round(data.weights.est_ramp * convFactor)),
pax: data.weights.pax_count_actual,
cargo: Math.round(data.weights.freight_added * convFactor),
fuel: Math.min(
isER ? SharedConfig.maxFuel.er[unit] : SharedConfig.maxFuel.norm[unit],
Math.round(data.fuel.plan_ramp * convFactor)
),
fuel: Math.min(maxFuel, Math.round(data.fuel.plan_ramp * convFactor)),
},
};
};

View File

@ -10,12 +10,9 @@ Coherent.call("COMM_BUS_WASM_CALLBACK", "khofmann_tfdi_md-11_load_manager_update
TODO:
- JS
- Connect to WASM as Data Source (sans SB username)
- Setting target
- SB
- Stations
- GSX State?
- GSX State for displaying status fo prog. loading
- Persist SB data across page changes
- Duplicate Input pages for F
- WASM
- Setting of payload
- GSX synced setting
- GSX synced setting of payload