diff --git a/package-lock.json b/package-lock.json index e81bff1a..4770cf04 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,6 +1,6 @@ { "name": "coriolis_shipyard", - "version": "2.5.0", + "version": "2.5.1", "lockfileVersion": 1, "requires": true, "dependencies": { @@ -11961,6 +11961,17 @@ } } }, + "webpack-notifier": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/webpack-notifier/-/webpack-notifier-1.6.0.tgz", + "integrity": "sha1-/6yOVf+MRpdSuMG7sBGhbxCYbgI=", + "dev": true, + "requires": { + "node-notifier": "5.1.2", + "object-assign": "4.1.1", + "strip-ansi": "3.0.1" + } + }, "webpack-sources": { "version": "0.1.5", "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-0.1.5.tgz", diff --git a/package.json b/package.json index 395a33d9..4805e18d 100644 --- a/package.json +++ b/package.json @@ -87,10 +87,11 @@ "rollup": "0.41", "rollup-plugin-node-resolve": "3", "style-loader": "^0.16.1", + "uglify-js": "^2.4.11", "url-loader": "^0.5.8", "webpack": "^2.4.1", "webpack-dev-server": "^2.4.4", - "uglify-js": "^2.4.11" + "webpack-notifier": "^1.6.0" }, "dependencies": { "babel-polyfill": "*", diff --git a/src/app/Coriolis.jsx b/src/app/Coriolis.jsx index 9fc6b0a3..cb2178c1 100644 --- a/src/app/Coriolis.jsx +++ b/src/app/Coriolis.jsx @@ -12,6 +12,7 @@ import ModalHelp from './components/ModalHelp'; import ModalImport from './components/ModalImport'; import ModalPermalink from './components/ModalPermalink'; import * as CompanionApiUtils from './utils/CompanionApiUtils'; +import * as JournalUtils from './utils/JournalUtils'; import AboutPage from './pages/AboutPage'; import NotFoundPage from './pages/NotFoundPage'; @@ -92,7 +93,14 @@ export default class Coriolis extends React.Component { // Need to decode and gunzip the data, then build the ship const data = zlib.inflate(new Buffer(r.params.data, 'base64'), { to: 'string' }); const json = JSON.parse(data); - const ship = CompanionApiUtils.shipFromJson(json); + console.log('Ship import data: '); + console.log(json); + let ship; + if (json && json.modules) { + ship = CompanionApiUtils.shipFromJson(json); + } else if (json && json.Modules) { + ship = JournalUtils.shipFromLoadoutJSON(json); + } r.params.ship = ship.id; r.params.code = ship.toString(); this._setPage(OutfittingPage, r); diff --git a/src/app/utils/CompanionApiUtils.js b/src/app/utils/CompanionApiUtils.js index 383addf9..80519945 100644 --- a/src/app/utils/CompanionApiUtils.js +++ b/src/app/utils/CompanionApiUtils.js @@ -115,7 +115,7 @@ function _shipModelFromEDName(edName) { * @return {string} the Coriolis model of the ship */ export function shipModelFromJson(json) { - return _shipModelFromEDName(json.name); + return _shipModelFromEDName(json.name || json.Ship); } /** @@ -145,7 +145,7 @@ export function shipFromJson(json) { } let rootModule; - + // Add the bulkheads const armourJson = json.modules.Armour.module; if (armourJson.name.endsWith('_Armour_Grade1')) { diff --git a/src/app/utils/JournalUtils.js b/src/app/utils/JournalUtils.js new file mode 100644 index 00000000..457f33a0 --- /dev/null +++ b/src/app/utils/JournalUtils.js @@ -0,0 +1,228 @@ +import Ship from '../shipyard/Ship' +import { shipModelFromJson } from './CompanionApiUtils' +import { Ships } from 'coriolis-data/dist' +import Module from '../shipyard/Module' +import { Modules } from '../../../../coriolis-data/dist' + +/** + * Obtain a module given its FD Name + * @param {string} fdname the FD Name of the module + * @return {Module} the module + */ +function _moduleFromFdName(fdname) { + if (!fdname) return null; + + // Check standard modules + for (const grp in Modules.standard) { + if (Modules.standard.hasOwnProperty(grp)) { + for (const i in Modules.standard[grp]) { + if (Modules.standard[grp][i].fdname === fdname) { + // Found it + return new Module({ template: Modules.standard[grp][i] }); + } + } + } + } + + // Check hardpoint modules + for (const grp in Modules.hardpoints) { + if (Modules.hardpoints.hasOwnProperty(grp)) { + for (const i in Modules.hardpoints[grp]) { + if (Modules.hardpoints[grp][i].fdname === fdname) { + // Found it + return new Module({ template: Modules.hardpoints[grp][i] }); + } + } + } + } + + // Check internal modules + for (const grp in Modules.internal) { + if (Modules.internal.hasOwnProperty(grp)) { + for (const i in Modules.internal[grp]) { + if (Modules.internal[grp][i].fdname === fdname) { + // Found it + return new Module({ template: Modules.internal[grp][i] }); + } + } + } + } + + // Not found + return null; +} +/** + * Build a ship from the journal Loadout event JSON + * @param {object} json the Loadout event JSON + * @return {Ship} the built ship + */ +export function shipFromLoadoutJSON(json) { +// Start off building a basic ship + const shipModel = shipModelFromJson(json); + if (!shipModel) { + throw 'No such ship found: "' + json.Ship + '"'; + } + const shipTemplate = Ships[shipModel]; + + let ship = new Ship(shipModel, shipTemplate.properties, shipTemplate.slots); + ship.buildWith(null); + // Initial Ship building, don't do engineering yet. + for (const module of json.Modules) { + switch (module.Slot) { + // Cargo Hatch. + case 'CargoHatch': + ship.cargoHatch.enabled = module.On; + ship.cargoHatch.priority = module.Priority; + break; + // Add the bulkheads + case 'Armour': + if (module.Item.endsWith('_Armour_Grade1')) { + ship.useBulkhead(0, true); + } else if (module.Item.endsWith('_Armour_Grade2')) { + ship.useBulkhead(1, true); + } else if (module.Item.endsWith('_Armour_Grade3')) { + ship.useBulkhead(2, true); + } else if (module.Item.endsWith('_Armour_Mirrored')) { + ship.useBulkhead(3, true); + } else if (module.Item.endsWith('_Armour_Reactive')) { + ship.useBulkhead(4, true); + } else { + throw 'Unknown bulkheads "' + module.Item + '"'; + } + ship.bulkheads.enabled = true; + break; + case 'PowerPlant': + const powerplant = _moduleFromFdName(module.Item); + ship.use(ship.standard[0], powerplant, true); + ship.standard[0].enabled = module.On; + ship.standard[0].priority = module.Priority; + break; + case 'MainEngines': + const thrusters = _moduleFromFdName(module.Item); + ship.use(ship.standard[1], thrusters, true); + ship.standard[1].enabled = module.On; + ship.standard[1].priority = module.Priority; + break; + case 'FrameShiftDrive': + const frameshiftdrive = _moduleFromFdName(module.Item); + ship.use(ship.standard[2], frameshiftdrive, true); + ship.standard[2].enabled = module.On; + ship.standard[2].priority = module.Priority; + break; + case 'LifeSupport': + const lifesupport = _moduleFromFdName(module.Item); + ship.use(ship.standard[3], lifesupport, true); + ship.standard[3].enabled = module.On === true; + ship.standard[3].priority = module.Priority; + break; + case 'PowerDistributor': + const powerdistributor = _moduleFromFdName(module.Item); + ship.use(ship.standard[4], powerdistributor, true); + ship.standard[4].enabled = module.On; + ship.standard[4].priority = module.Priority; + break; + case 'Radar': + const sensors = _moduleFromFdName(module.Item); + ship.use(ship.standard[5], sensors, true); + ship.standard[5].enabled = module.On; + ship.standard[5].priority = module.Priority; + break; + case 'FuelTank': + const fueltank = _moduleFromFdName(module.Item); + ship.use(ship.standard[6], fueltank, true); + ship.standard[6].enabled = true; + ship.standard[6].priority = 0; + break; + default: + } + if (module.Slot.search(/Hardpoint/) !== -1) { + console.log(module); + } + + } + // We don't have any information on it so guess it's priority 5 and disabled + if (!ship.cargoHatch) { + ship.cargoHatch.enabled = false; + ship.cargoHatch.priority = 4; + } + console.log(ship); + let rootModule; + + // Add hardpoints + let hardpointClassNum = -1; + let hardpointSlotNum = -1; + let hardpointArrayNum = 0; + for (let i in shipTemplate.slots.hardpoints) { + if (shipTemplate.slots.hardpoints[i] === hardpointClassNum) { + // Another slot of the same class + hardpointSlotNum++; + } else { + // The first slot of a new class + hardpointClassNum = shipTemplate.slots.hardpoints[i]; + hardpointSlotNum = 1; + } + + // Now that we know what we're looking for, find it + const hardpointName = HARDPOINT_NUM_TO_CLASS[hardpointClassNum] + 'Hardpoint' + hardpointSlotNum; + const hardpointSlot = json.Modules[hardpointName]; + if (!hardpointSlot) { + // This can happen with old imports that don't contain new hardpoints + } else if (!hardpointSlot.module) { + // No module + } else { + const hardpointJson = hardpointSlot.module; + const hardpoint = _moduleFromFdName(hardpointJson.id); + rootModule = hardpointSlot; + if (rootModule.Engineering) _addModifications(hardpoint, rootModule.Engineering, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel, rootModule.specialModifications); + ship.use(ship.hardpoints[hardpointArrayNum], hardpoint, true); + ship.hardpoints[hardpointArrayNum].enabled = hardpointJson.on === true; + ship.hardpoints[hardpointArrayNum].priority = hardpointJson.Priority; + } + hardpointArrayNum++; + } + + // Add internal compartments + let internalSlotNum = 1; + let militarySlotNum = 1; + for (let i in shipTemplate.slots.internal) { + const isMilitary = isNaN(shipTemplate.slots.internal[i]) ? shipTemplate.slots.internal[i].name == 'Military' : false; + + // The internal slot might be a standard or a military slot. Military slots have a different naming system + let internalSlot = null; + if (isMilitary) { + const internalName = 'Military0' + militarySlotNum; + internalSlot = json.Modules[internalName]; + militarySlotNum++; + } else { + // Slot numbers are not contiguous so handle skips. + while (internalSlot === null && internalSlotNum < 99) { + // Slot sizes have no relationship to the actual size, either, so check all possibilities + for (let slotsize = 0; slotsize < 9; slotsize++) { + const internalName = 'Slot' + (internalSlotNum <= 9 ? '0' : '') + internalSlotNum + '_Size' + slotsize; + if (json.Modules[internalName]) { + internalSlot = json.Modules[internalName]; + break; + } + } + internalSlotNum++; + } + } + + if (!internalSlot) { + // This can happen with old imports that don't contain new slots + } else if (!internalSlot.module) { + // No module + } else { + const internalJson = internalSlot.module; + const internal = _moduleFromFdName(internalJson.id); + rootModule = internalSlot; + if (rootModule.Engineering) _addModifications(internal, rootModule.Engineering, rootModule.engineer.recipeName, rootModule.engineer.recipeLevel); + ship.use(ship.internal[i], internal, true); + ship.internal[i].enabled = internalJson.on === true; + ship.internal[i].priority = internalJson.Priority; + } + } + + // Now update the ship's codes before returning it + return ship.updatePowerPrioritesString().updatePowerEnabledString().updateModificationsString(); +} diff --git a/webpack.config.dev.js b/webpack.config.dev.js index 0613aa29..e9fdde54 100644 --- a/webpack.config.dev.js +++ b/webpack.config.dev.js @@ -4,6 +4,7 @@ var webpack = require('webpack'); var pkgJson = require('./package'); var HtmlWebpackPlugin = require("html-webpack-plugin"); var ExtractTextPlugin = require("extract-text-webpack-plugin"); +var WebpackNotifierPlugin = require('webpack-notifier'); function CopyDirPlugin(source, destination) { this.source = source; @@ -51,6 +52,7 @@ module.exports = { disable: false, allChunks: true }), + new WebpackNotifierPlugin({alwaysNotify: true}), new webpack.HotModuleReplacementPlugin(), new webpack.NoEmitOnErrorsPlugin() ],