mirror of
https://github.com/EDCD/coriolis.git
synced 2025-12-09 06:43:24 +00:00
246 lines
9.3 KiB
JavaScript
Executable File
246 lines
9.3 KiB
JavaScript
Executable File
/**
|
|
* Service managing seralization and deserialization of models for use in URLs and persistene.
|
|
*/
|
|
angular.module('app').service('Serializer', ['lodash', 'GroupMap', 'MountMap', 'ShipsDB', 'Ship', 'Components', '$state', function(_, GroupMap, MountMap, ShipsDB, Ship, Components, $state) {
|
|
|
|
/**
|
|
* Serializes the ships selected components for all slots to a URL friendly string.
|
|
* @param {Ship} ship The ship to be serialized.
|
|
* @return {string} Encoded string of components
|
|
*/
|
|
this.fromShip = function(ship) {
|
|
var power = {
|
|
enabled: [ship.cargoHatch.enabled ? 1 : 0],
|
|
priorities: [ship.cargoHatch.priority]
|
|
};
|
|
|
|
var data = [
|
|
ship.bulkheads.id,
|
|
_.map(ship.common, mapGroup, power),
|
|
_.map(ship.hardpoints, mapGroup, power),
|
|
_.map(ship.internal, mapGroup, power),
|
|
'.',
|
|
LZString.compressToBase64(power.enabled.join('')).replace(/\//g, '-'),
|
|
'.',
|
|
LZString.compressToBase64(power.priorities.join('')).replace(/\//g, '-')
|
|
];
|
|
|
|
return _.flatten(data).join('');
|
|
};
|
|
|
|
/**
|
|
* Updates an existing ship instance's slots with components determined by the
|
|
* code.
|
|
*
|
|
* @param {Ship} ship The ship instance to be updated
|
|
* @param {string} dataString The string to deserialize
|
|
*/
|
|
this.toShip = function(ship, dataString) {
|
|
var common = new Array(ship.common.length),
|
|
hardpoints = new Array(ship.hardpoints.length),
|
|
internal = new Array(ship.internal.length),
|
|
parts = dataString.split('.'),
|
|
priorities = null,
|
|
enabled = null,
|
|
code = parts[0];
|
|
|
|
if (parts[1]) {
|
|
enabled = LZString.decompressFromBase64(parts[1].replace(/-/g, '/')).split('');
|
|
}
|
|
|
|
if (parts[2]) {
|
|
priorities = LZString.decompressFromBase64(parts[2].replace(/-/g, '/')).split('');
|
|
}
|
|
|
|
decodeToArray(code, internal, decodeToArray(code, hardpoints, decodeToArray(code, common, 1)));
|
|
|
|
ship.buildWith(
|
|
{
|
|
bulkheads: code.charAt(0) * 1,
|
|
common: common,
|
|
hardpoints: hardpoints,
|
|
internal: internal
|
|
},
|
|
priorities,
|
|
enabled
|
|
);
|
|
};
|
|
|
|
this.toDetailedBuild = function(buildName, ship, code) {
|
|
var standard = ship.common,
|
|
hardpoints = ship.hardpoints,
|
|
internal = ship.internal;
|
|
|
|
var data = {
|
|
$schema: 'http://cdn.coriolis.io/schemas/ship-loadout/2.json#',
|
|
name: buildName,
|
|
ship: ship.name,
|
|
references: [{
|
|
name: 'Coriolis.io',
|
|
url: $state.href('outfit', { shipId: ship.id, code: code, bn: buildName }, { absolute: true }),
|
|
code: code,
|
|
shipId: ship.id
|
|
}],
|
|
components: {
|
|
standard: {
|
|
bulkheads: ship.bulkheads.c.name,
|
|
cargoHatch: { enabled: Boolean(ship.cargoHatch.enabled), priority: ship.cargoHatch.priority + 1 },
|
|
powerPlant: { class: standard[0].c.class, rating: standard[0].c.rating, enabled: Boolean(standard[0].enabled), priority: standard[0].priority + 1 },
|
|
thrusters: { class: standard[1].c.class, rating: standard[1].c.rating, enabled: Boolean(standard[1].enabled), priority: standard[1].priority + 1 },
|
|
frameShiftDrive: { class: standard[2].c.class, rating: standard[2].c.rating, enabled: Boolean(standard[2].enabled), priority: standard[2].priority + 1 },
|
|
lifeSupport: { class: standard[3].c.class, rating: standard[3].c.rating, enabled: Boolean(standard[3].enabled), priority: standard[3].priority + 1 },
|
|
powerDistributor: { class: standard[4].c.class, rating: standard[4].c.rating, enabled: Boolean(standard[4].enabled), priority: standard[4].priority + 1 },
|
|
sensors: { class: standard[5].c.class, rating: standard[5].c.rating, enabled: Boolean(standard[5].enabled), priority: standard[5].priority + 1 },
|
|
fuelTank: { class: standard[6].c.class, rating: standard[6].c.rating, enabled: Boolean(standard[6].enabled), priority: standard[6].priority + 1 }
|
|
},
|
|
hardpoints: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass > 0; }), slotToSchema),
|
|
utility: _.map(_.filter(hardpoints, function(slot) { return slot.maxClass === 0; }), slotToSchema),
|
|
internal: _.map(internal, slotToSchema)
|
|
},
|
|
stats: {}
|
|
};
|
|
|
|
for (var stat in ship) {
|
|
if (!isNaN(ship[stat])) {
|
|
data.stats[stat] = Math.round(ship[stat] * 100) / 100;
|
|
}
|
|
}
|
|
|
|
return data;
|
|
};
|
|
|
|
this.fromDetailedBuild = function(detailedBuild) {
|
|
var shipId = _.findKey(ShipsDB, { properties: { name: detailedBuild.ship } });
|
|
|
|
if (!shipId) {
|
|
throw 'No such ship: ' + detailedBuild.ship;
|
|
}
|
|
|
|
var comps = detailedBuild.components;
|
|
var standard = comps.standard;
|
|
var priorities = [ standard.cargoHatch && standard.cargoHatch.priority !== undefined ? standard.cargoHatch.priority - 1 : 0 ];
|
|
var enabled = [ standard.cargoHatch && standard.cargoHatch.enabled !== undefined ? standard.cargoHatch.enabled : true ];
|
|
var shipData = ShipsDB[shipId];
|
|
var ship = new Ship(shipId, shipData.properties, shipData.slots);
|
|
var bulkheads = Components.bulkheadIndex(standard.bulkheads);
|
|
|
|
if (bulkheads < 0) {
|
|
throw 'Invalid bulkheads: ' + standard.bulkheads;
|
|
}
|
|
|
|
var common = _.map(
|
|
['powerPlant', 'thrusters', 'frameShiftDrive', 'lifeSupport', 'powerDistributor', 'sensors', 'fuelTank'],
|
|
function(c) {
|
|
if (!standard[c].class || !standard[c].rating) {
|
|
throw 'Invalid value for ' + c;
|
|
}
|
|
priorities.push(standard[c].priority === undefined ? 0 : standard[c].priority - 1);
|
|
enabled.push(standard[c].enabled === undefined ? true : standard[c].enabled);
|
|
return standard[c].class + standard[c].rating;
|
|
}
|
|
);
|
|
|
|
var internal = _.map(comps.internal, function(c) { return c ? Components.findInternalId(c.group, c.class, c.rating, c.name) : 0; });
|
|
|
|
var hardpoints = _.map(comps.hardpoints, function(c) {
|
|
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount], c.missile) : 0;
|
|
}).concat(_.map(comps.utility, function(c) {
|
|
return c ? Components.findHardpointId(c.group, c.class, c.rating, c.name, MountMap[c.mount]) : 0;
|
|
}));
|
|
|
|
// The ordering of these arrays must match the order in which they are read in Ship.buildWith
|
|
priorities = priorities.concat(_.map(comps.hardpoints, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
|
|
_.map(comps.utility, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }),
|
|
_.map(comps.internal, function(c) { return (!c || c.priority === undefined) ? 0 : c.priority - 1; }));
|
|
enabled = enabled.concat(_.map(comps.hardpoints, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
|
|
_.map(comps.utility, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }),
|
|
_.map(comps.internal, function(c) { return (!c || c.enabled === undefined) ? true : c.enabled * 1; }));
|
|
|
|
ship.buildWith({ bulkheads: bulkheads, common: common, hardpoints: hardpoints, internal: internal }, priorities, enabled);
|
|
|
|
return ship;
|
|
};
|
|
|
|
this.toDetailedExport = function(builds) {
|
|
var data = [];
|
|
|
|
for (var shipId in builds) {
|
|
for (var buildName in builds[shipId]) {
|
|
var code = builds[shipId][buildName];
|
|
var shipData = ShipsDB[shipId];
|
|
var ship = new Ship(shipId, shipData.properties, shipData.slots);
|
|
this.toShip(ship, code);
|
|
data.push(this.toDetailedBuild(buildName, ship, code));
|
|
}
|
|
}
|
|
return data;
|
|
};
|
|
|
|
this.fromComparison = function(name, builds, facets, predicate, desc) {
|
|
var shipBuilds = [];
|
|
|
|
builds.forEach(function(b) {
|
|
shipBuilds.push({ s: b.id, n: b.buildName, c: this.fromShip(b) });
|
|
}.bind(this));
|
|
|
|
return LZString.compressToBase64(angular.toJson({
|
|
n: name,
|
|
b: shipBuilds,
|
|
f: facets,
|
|
p: predicate,
|
|
d: desc ? 1 : 0
|
|
})).replace(/\//g, '-');
|
|
};
|
|
|
|
this.toComparison = function(code) {
|
|
return angular.fromJson(LZString.decompressFromBase64(code.replace(/-/g, '/')));
|
|
};
|
|
|
|
/**
|
|
* Utility function to retrieve a safe string for selected component for a slot.
|
|
* Used for serialization to code only.
|
|
*
|
|
* @private
|
|
* @param {object} slot The slot object.
|
|
* @return {string} The id of the selected component or '-' if none selected
|
|
*/
|
|
function mapGroup(slot) {
|
|
this.enabled.push(slot.enabled ? 1 : 0);
|
|
this.priorities.push(slot.priority);
|
|
|
|
return slot.id === null ? '-' : slot.id;
|
|
}
|
|
|
|
function decodeToArray(code, arr, codePos) {
|
|
for (var i = 0; i < arr.length; i++) {
|
|
if (code.charAt(codePos) == '-') {
|
|
arr[i] = 0;
|
|
codePos++;
|
|
} else {
|
|
arr[i] = code.substring(codePos, codePos + 2);
|
|
codePos += 2;
|
|
}
|
|
}
|
|
return codePos;
|
|
}
|
|
|
|
function slotToSchema(slot) {
|
|
if (slot.c) {
|
|
var o = { class: slot.c.class, rating: slot.c.rating, enabled: Boolean(slot.enabled), priority: slot.priority + 1, group: GroupMap[slot.c.grp] };
|
|
if (slot.c.name) {
|
|
o.name = slot.c.name;
|
|
}
|
|
if (slot.c.mode) {
|
|
o.mount = MountMap[slot.c.mode];
|
|
}
|
|
if (slot.c.missile) {
|
|
o.missile = slot.c.missile;
|
|
}
|
|
return o;
|
|
}
|
|
return null;
|
|
}
|
|
|
|
|
|
}]);
|