Compare commits

...

11 Commits

Author SHA1 Message Date
Felix Linker
f747b25f26 Merge pull request #759 from alex-williams/Issue_754_Imports_need_to_be_more_graceful
Adds valid module checking to all types of modules on import
2024-05-27 08:49:11 +02:00
Felix Linker
02bf133c98 Merge branch 'develop' into Issue_754_Imports_need_to_be_more_graceful 2024-05-27 08:48:49 +02:00
Alex Williams
b0b5c82131 Merge branch 'alpha' into Issue_754_Imports_need_to_be_more_graceful 2024-05-24 18:22:53 +01:00
Alex Williams
ee92f2f2e4 Adds the Advanced MC's, AX MC's, AX MR's and Nanite Torpedo (#4) 2024-05-24 17:56:20 +01:00
Alex Williams
0d749202e2 Changing to clone single branch for deployment, not the whole repo 2024-05-24 17:41:27 +01:00
Alex Williams
4283b0b839 Changed deployment ordering 2024-05-24 17:38:47 +01:00
Alex Williams
fbd9c3d282 Improving workflow 2024-05-24 16:23:08 +01:00
Alex Williams
cd68199a41 Adding workflow for autodeploy 2024-05-24 16:23:08 +01:00
Alex Williams
f885fde04f Fix changed files issue (#3)
* Copied de.js contents to new file de-fix.js

* Copied de.js contents back from de-fix.js

* Copied contents of ko.js to ko-fix.js

* Copied ko.js contents back from ko-fix.js

* Copied contents from BlueprintFunctions.js to BlueprintFunctions-fix.js

* Copied contents back from BlueprintFunctions-fix.js to BlueprintFunctions.js

* Copied contents of LineChart.jsx to LineChart-fix.jsx

* Copied contents back from LineChart-fix.jsx to LineChart.jsx

* Copied contents of PieChart.jsx to PieChart-fix.jsx

* Copied contents back from PieChart-fix.jsx to PieChart.jsx

* Copied contents from Slider.jsx to Slider-fix.jsx

* Copied contents back from Slider-fix.jsx to Slider.jsx

* Copied contents from VerticalBarChart.jsx to VerticalBarChart-fix.jsx

* Copied contents back from VerticalBarChart-fix.jsx to VerticalBarChart.jsx

* Deleting 'fix' files
2024-05-24 16:03:03 +01:00
Alex Williams
5c8ff57d16 Changes as per comments on the PR 2024-05-17 15:24:29 +01:00
Alex Williams
14ffa26ef9 Adds valid module checking to all types of modules on import 2024-05-16 19:23:33 +01:00
17 changed files with 1501 additions and 1332 deletions

28
.github/workflows/autodeploy.yml vendored Normal file
View File

@@ -0,0 +1,28 @@
# This is a basic deployment workflow triggered by pushes to the alpha branch.
name: Auto-Deploy
# Controls when the action will run. Workflow runs when the alpha branch receives a push event
on:
workflow_dispatch:
push:
branches:
- alpha
# A workflow run is made up of one or more jobs that can run sequentially or in parallel
jobs:
downloadcode:
runs-on: self-hosted
steps:
- shell: bash
run: |
rm -Rf ./coriolis
rm -Rf ./coriolis-data
git clone https://github.com/alex-williams/coriolis.git --single-branch --branch alpha
git clone https://github.com/alex-williams/coriolis-data.git --single-branch --branch alpha
cd coriolis-data
npm install
cd ../coriolis
npm install
npm run build
sudo -u www-data cp -r ./build/* /var/www/newdisk/coriolis.brighter-applications.co.uk/

View File

@@ -217,17 +217,31 @@ export default class AvailableModulesMenu extends TranslatedComponent {
if (categories.length === 1) {
// Show category header instead of group header
if (m && grp == m.grp) {
// If this is a missing module/weapon, skip it
if (m.grp == "mh" || m.grp == "mm"){
continue;
} else {
list.push(<div ref={(elem) => this.groupElem = elem} key={category}
className={'select-category upp'}>{translate(category)}</div>);
}
} else {
if (category == "mh"){
continue;
} else {
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
}
}
} else {
// Show category header as well as group header
if (!categoryHeader) {
if (category == "mh"){
continue;
}
else {
list.push(<div key={category} className={'select-category upp'}>{translate(category)}</div>);
categoryHeader = true;
}
}
if (m && grp == m.grp) {
list.push(<div ref={(elem) => this.groupElem = elem} key={grp}
className={'select-group cap'}>{translate(grp)}</div>);
@@ -302,6 +316,10 @@ export default class AvailableModulesMenu extends TranslatedComponent {
let itemsOnThisRow = 0;
for (let i = 0; i < sortedModules.length; i++) {
let m = sortedModules[i];
if (m.grp == 'mh' || m.grp == 'mm') {
// If this is a missing module, skip it
continue;
}
let mount = null;
let disabled = false;
prevName = m.name;
@@ -316,6 +334,7 @@ export default class AvailableModulesMenu extends TranslatedComponent {
disabled = 1 <= ship.internal.filter(o => o.m && o.m.grp === 'mlc').length;
}
let active = mountedModule && mountedModule.id === m.id;
let classes = cn(m.name ? 'lc' : 'c', {
warning: !disabled && warningFunc && warningFunc(m),
active,

View File

@@ -136,6 +136,7 @@ export default class HardpointSlot extends Slot {
{showModuleResistances && m.getThermalResistance() ? <div
className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null}
{m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null}
{m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null}
{m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={modButton => this.modButton = modButton}>
<button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation}
onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}>

View File

@@ -88,6 +88,7 @@ export default class InternalSlot extends Slot {
{ m.getHullReinforcement() ? <div className='l'>{translate('armour')}: {formats.int(m.getHullReinforcement() + ship.baseArmour * m.getModValue('hullboost') / 10000)}</div> : null }
{ m.getProtection() ? <div className='l'>{translate('protection')}: {formats.rPct(m.getProtection())}</div> : null }
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
{ m && validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
</div>
</div>;

View File

@@ -99,6 +99,7 @@ export default class Slot extends TranslatedComponent {
let translate = language.translate;
let { ship, m, enabled, dropClass, dragOver, onOpen, onChange, selected, eligible, onSelect, warning, availableModules } = this.props;
let slotDetails, modificationsMarker, menu;
let missing = false;
if (!selected) {
// If not selected then sure that modifications flag is unset
@@ -108,6 +109,11 @@ export default class Slot extends TranslatedComponent {
if (m) {
slotDetails = this._getSlotDetails(m, enabled, translate, language.formats, language.units); // Must be implemented by sub classes
modificationsMarker = JSON.stringify(m);
if(typeof m.grp !== 'undefined' || m.grp !== null) {
if(m.grp == "mh" || m.grp == "mm") {
missing = true;
}
}
} else {
slotDetails = <div className={'empty'}>{translate(eligible ? 'emptyrestricted' : 'empty')}</div>;
modificationsMarker = '';
@@ -141,7 +147,10 @@ export default class Slot extends TranslatedComponent {
return (
<div className={cn('slot', dropClass, { selected })} onClick={onOpen} onKeyDown={this._keyDown} onContextMenu={this._contextMenu} onDragOver={dragOver} tabIndex="0" ref={slotDiv => this.slotDiv = slotDiv}>
<div className='details-container'>
{
// If missing module/hardpoint, set the div container to warning status.
}
<div className={ missing === true ? 'details-container warning' : 'details-container'}>
<div className='sz'>{this._getMaxClassLabel(translate)}</div>
{slotDetails}
</div>

View File

@@ -93,6 +93,11 @@ export default class StandardSlot extends TranslatedComponent {
this._modificationsSelected = false;
}
// If this is a missing module, therefore has the 'info' field, set the warning value on the module to be true when loaded.
if (m.info) {
warning = () => true;
}
const modificationsMarker = JSON.stringify(m);
if (selected) {
@@ -124,7 +129,7 @@ export default class StandardSlot extends TranslatedComponent {
<div className={cn('details-container', { warning: warning && warning(slot.m), disabled: m.grp !== 'bh' && !slot.enabled })}>
<div className={'sz'}>{m.grp == 'bh' ? m.name.charAt(0) : slot.maxClass}</div>
<div>
<div className={'l'}>{classRating} {translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
<div className={'l'}>{classRating} {m.getInfo() ? translate(m.ukName) : translate(m.name || m.grp)}{m.mods && Object.keys(m.mods).length > 0 ? <span className='r' onMouseOver={termtip.bind(null, modTT)} onMouseOut={tooltip.bind(null, null)}><Modified /></span> : null }</div>
<div className={'r'}>{formats.round(mass)}{units.T}</div>
<div/>
<div className={'cb'}>
@@ -144,7 +149,8 @@ export default class StandardSlot extends TranslatedComponent {
{ showModuleResistances && m.getKineticResistance() ? <div className='l'>{translate('kinres')}: {formats.pct(m.getKineticResistance())}</div> : null }
{ showModuleResistances && m.getThermalResistance() ? <div className='l'>{translate('thermres')}: {formats.pct(m.getThermalResistance())}</div> : null }
{ m.getIntegrity() ? <div className='l'>{translate('integrity')}: {formats.int(m.getIntegrity())}</div> : null }
{ validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
{ m.getInfo() ? <div className='l'>{translate(m.getInfo())}</div> : null }
{ m.getInfo() ? <div className='r'></div> : validMods.length > 0 ? <div className='r' tabIndex="0" ref={ modButton => this.modButton = modButton }><button tabIndex="-1" onClick={this._toggleModifications.bind(this)} onContextMenu={stopCtxPropagation} onMouseOver={termtip.bind(null, 'modifications')} onMouseOut={tooltip.bind(null, null)}><ListModifications /></button></div> : null }
</div>
</div>
</div>

View File

@@ -83,6 +83,7 @@
"HELP_MODIFICATIONS_MENU": "Click on a number to enter a new value, or drag along the bar for small changes",
"PHRASE_FAIL_EDENGINEER": "Failed to send to EDEngineer (Launch EDEngineer and make sure the API is started then refresh the page.)",
"PHRASE_FIREFOX_EDENGINEER": "Sending to EDEngineer is not compatible with Firefox's security settings. Please try again with Chrome.",
"MISSING_MODULES": "Missing Modules",
"am": "Auto Field-Maintenance Unit",
"bh": "Bulkheads",
"bl": "Beam Laser",
@@ -109,6 +110,8 @@
"kw": "Kill Warrant Scanner",
"ls": "Life Support",
"mc": "Multi-cannon",
"mh": "Missing Weapon/Utility",
"mm": "Missing Module",
"advmc": "Multi-cannon (Advanced)",
"axmc": "AX Multi-cannon",
"axmce": "AX Multi-cannon (Enhanced)",
@@ -216,6 +219,7 @@
"boost interval": "Boost interval",
"total": "Total",
"ammo": "Ammunition maximum",
"info": "Info",
"boot": "Boot time",
"hacktime": "Hack time",
"brokenregen": "Broken regeneration rate",

View File

@@ -45,6 +45,9 @@ export default class ErrorDetails extends React.Component {
return <div className='error'>
<h1>Jameson, we have a problem..</h1>
<h1><small>{error.message}</small></h1>
Import Error handling has been improved, but still isn't perfect. <br/>MOST Import failures are a result of missing modules in Coriolis, <br />OR incorrect import strings generated by third party apps. If you're seeing this page, we may have failed to handle the errors in your import correctly. Please see the data output below, specifically the 'scriptUrl:' section if it's there and then if you feel confident enough, please check the github issues page linked below and see if there is a similar issue already logged. If not, please create a new issue with the data below. If you're not confident, please ask for help on the Coriolis Channel of the EDCD Discord server.
<br/>
<br/>
<br/>
{importerror ? <div>If you are attempting to import a ship from EDDI or EDMC and are seeing a 'Z_BUF_ERROR' it means that the URL has not been provided correctly. This is a common problem when using Microsoft Internet Explorer or Microsoft Edge, and you should use another browser instead.</div> : null }
<br/>

View File

@@ -439,6 +439,15 @@ export default class Module {
return this.get('integrity', modified);
}
/**
* Get the info of this module
* @param {Boolean} [modified=false] Whether to take modifications into account
* @return {String} the info of this module
*/
getInfo(modified = false) {
return (modified && this.getModValue('info')) || this.info;
}
/**
* Get the mass of this module
* @param {Boolean} [modified=true] Whether to take modifications into account

View File

@@ -6,6 +6,22 @@ import { Modules } from 'coriolis-data/dist';
import { Modifications } from 'coriolis-data/dist';
import { getBlueprint, setQualityCB } from './BlueprintFunctions';
/**
* Check if an imported module is valid
* @param {Object} module the module to check
* @param {Object} moduleType the type of module to check
* @return {boolean} true if the module is valid
*/
function _isValidImportedModule(module, moduleType) {
// First of all, has the _moduleFromFdName function returned 'null'?
if (!module){
return false
}
else {
return true
}
}
/**
* Obtain a module given its FD Name
* @param {string} fdname the FD Name of the module
@@ -98,49 +114,90 @@ export function shipFromLoadoutJSON(json) {
if (module.Engineering) _addModifications(ship.bulkheads.m, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break;
case 'powerplant':
const powerplant = _moduleFromFdName(module.Item);
let powerplant = _moduleFromFdName(module.Item);
// Check the powerplant returned is valid
if (!_isValidImportedModule(powerplant, 'powerplant'))
{
powerplant = _moduleFromFdName('Int_Missing_Powerplant');
module.Engineering = null;
}
ship.use(ship.standard[0], powerplant, true);
ship.standard[0].enabled = module.On;
ship.standard[0].priority = module.Priority;
if (module.Engineering) _addModifications(powerplant, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break;
case 'mainengines':
const thrusters = _moduleFromFdName(module.Item);
let thrusters = _moduleFromFdName(module.Item);
// Check the thrusters returned is valid
if (!_isValidImportedModule(thrusters, 'thrusters'))
{
thrusters = _moduleFromFdName('Int_Missing_Engine');
module.Engineering = null;
}
ship.use(ship.standard[1], thrusters, true);
ship.standard[1].enabled = module.On;
ship.standard[1].priority = module.Priority;
if (module.Engineering) _addModifications(thrusters, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break;
case 'frameshiftdrive':
const frameshiftdrive = _moduleFromFdName(module.Item);
let frameshiftdrive = _moduleFromFdName(module.Item);
// Check the frameshiftdrive returned is valid
if (!_isValidImportedModule(frameshiftdrive, 'frameshiftdrive'))
{
frameshiftdrive = _moduleFromFdName('Int_Missing_Hyperdrive');
module.Engineering = null;
}
ship.use(ship.standard[2], frameshiftdrive, true);
ship.standard[2].enabled = module.On;
ship.standard[2].priority = module.Priority;
if (module.Engineering) _addModifications(frameshiftdrive, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break;
case 'lifesupport':
const lifesupport = _moduleFromFdName(module.Item);
let lifesupport = _moduleFromFdName(module.Item);
// Check the lifesupport returned is valid
if (!_isValidImportedModule(lifesupport, 'lifesupport'))
{
lifesupport = _moduleFromFdName('Int_Missing_LifeSupport');
module.Engineering = null;
}
ship.use(ship.standard[3], lifesupport, true);
ship.standard[3].enabled = module.On === true;
ship.standard[3].priority = module.Priority;
if (module.Engineering) _addModifications(lifesupport, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break;
case 'powerdistributor':
const powerdistributor = _moduleFromFdName(module.Item);
let powerdistributor = _moduleFromFdName(module.Item);
// Check the powerdistributor returned is valid
if (!_isValidImportedModule(powerdistributor, 'powerdistributor'))
{
powerdistributor = _moduleFromFdName('Int_Missing_PowerDistributor');
module.Engineering = null;
}
ship.use(ship.standard[4], powerdistributor, true);
ship.standard[4].enabled = module.On;
ship.standard[4].priority = module.Priority;
if (module.Engineering) _addModifications(powerdistributor, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break;
case 'radar':
const sensors = _moduleFromFdName(module.Item);
let sensors = _moduleFromFdName(module.Item);
// Check the sensors returned is valid
if (!_isValidImportedModule(sensors, 'sensors'))
{
sensors = _moduleFromFdName('Int_Missing_Sensors');
module.Engineering = null;
}
ship.use(ship.standard[5], sensors, true);
ship.standard[5].enabled = module.On;
ship.standard[5].priority = module.Priority;
if (module.Engineering) _addModifications(sensors, module.Engineering.Modifiers, module.Engineering.Quality, module.Engineering.BlueprintName, module.Engineering.Level, module.Engineering.ExperimentalEffect);
break;
case 'fueltank':
const fueltank = _moduleFromFdName(module.Item);
let fueltank = _moduleFromFdName(module.Item);
// Check the fueltank returned is valid
if (!_isValidImportedModule(fueltank, 'fueltank'))
{
fueltank = _moduleFromFdName('Int_Missing_FuelTank');
}
ship.use(ship.standard[6], fueltank, true);
ship.standard[6].enabled = true;
ship.standard[6].priority = 0;
@@ -170,11 +227,28 @@ export function shipFromLoadoutJSON(json) {
// This can happen with old imports that don't contain new hardpoints
} else {
hardpoint = _moduleFromFdName(hardpointSlot.Item);
// Check the hardpoint module returned is valid
if (!_isValidImportedModule(hardpoint, 'hardpoint')){
// Check if it's a Utility or Hardpoint
if (hardpointSlot.Slot.toLowerCase().search(/tiny/))
{
// Use the missing_hardpoint module 'Missing Hardpoint' which will inform the user that the module is missing
hardpoint = _moduleFromFdName('Hpt_Missing_Hardpoint');
}
else {
// Use the missing_hardpoint module 'Missing Utility' which will inform the user that the module is missing
hardpoint = _moduleFromFdName('Hpt_Missing_Utility');
}
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
} else {
ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true);
ship.hardpoints[hardpointArrayNum].enabled = hardpointSlot.On;
ship.hardpoints[hardpointArrayNum].priority = hardpointSlot.Priority;
modsToAdd.push({ coriolisMod: hardpoint, json: hardpointSlot });
}
}
hardpointArrayNum++;
}
}
@@ -187,13 +261,17 @@ export function shipFromLoadoutJSON(json) {
continue;
}
const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false;
const isPlanetary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'PlanetaryApproachSuite' : false;
// The internal slot might be a standard or a military slot. Military slots have a different naming system
// The internal slot might be a standard or a military slot, or a planetary slot. Military and Planetary slots have a different naming system
let internalSlot = null;
if (isMilitary) {
const internalName = 'Military0' + militarySlotNum;
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
militarySlotNum++;
} else if (isPlanetary) {
const internalName = 'PlanetaryApproachSuite';
internalSlot = json.Modules.find(elem => elem.Slot.toLowerCase() === internalName.toLowerCase());
} else {
// Slot numbers are not contiguous so handle skips.
for (; internalSlot === null && internalSlotNum < 99; internalSlotNum++) {
@@ -212,13 +290,24 @@ export function shipFromLoadoutJSON(json) {
// This can happen with old imports that don't contain new slots
} else {
const internalJson = internalSlot;
const internal = _moduleFromFdName(internalJson.Item);
let internal = _moduleFromFdName(internalJson.Item);
// Check the internal module returned is valid
if (!_isValidImportedModule(internal, 'internal'))
{
internal = _moduleFromFdName('Int_Missing_Module');
ship.use(ship.internal[i], internal, true);
ship.internal[i].enabled = internalJson.On === true;
ship.internal[i].priority = internalJson.Priority;
//throw 'Unknown internal module: "' + module.Item + '"';
}
else {
ship.use(ship.internal[i], internal, true);
ship.internal[i].enabled = internalJson.On === true;
ship.internal[i].priority = internalJson.Priority;
modsToAdd.push({ coriolisMod: internal, json: internalSlot });
}
}
}
for (const i of modsToAdd) {
if (i.json.Engineering) {