Skip to content

Instantly share code, notes, and snippets.

@jjspace
Last active July 11, 2026 00:12
Show Gist options
  • Select an option

  • Save jjspace/eda8969f833d3ba1ab8b1855348f525b to your computer and use it in GitHub Desktop.

Select an option

Save jjspace/eda8969f833d3ba1ab8b1855348f525b to your computer and use it in GitHub Desktop.
xivsim waymark import
(function () {
// this is meant to be run as a snippet in chrome devTools
// if this is implemented in the actual sim code it doesn't need this
// wrapper function
clear();
// prompt the user for the exported json from the pWaymark plugin
const importStr = prompt('Paste the export from the pWaymark plugin. This will REPLACE all your current sim waymarks. Cancel or leave blank to stop');
if (importStr === null || importStr === '') {
console.log('canceling import');
return 'done';
}
// We only want to import waymarks for the maps that the sim has timelines for
// keep track of known ids, the name for each map (prepended to the preset name)
// and the coordinate scaling functions unique to each map
const mapIdToName = {
280: 'UCOB',
539: 'UwU',
694: 'TEA',
1006: 'FRU',
1094: 'DMU',
759: 'E12S',
788: 'DSR',
801: 'P4S',
873: 'P5S',
877: 'P7S',
881: 'P6S',
884: 'P8S',
937: 'P9S',
939: 'P10S',
941: 'P11S',
943: 'P12S',
1069: 'M9S',
1071: 'M10S',
1073: 'M11S',
1075: 'M12S',
};
const scaleCoordsForMapId = {
// seems the coord system is scaled differently than in game
// and most maps are not centered around 0, 0 in game but they are in the sim
// these help recenter the waymarks for the sim. All values were found mostly
// through trial and error and seem to be pretty accurate when I compared to in game
// most maps can use the standard conversion which is the fallback unless specified
standard: {
x: (n) => (n - 100) / -4,
z: (n) => (n - 100) / -4
},
280: {
x: (n) => n / -4.5,
z: (n) => n / -4.5,
},
759: {
x: (n) => n / -4,
z: (n) => (n + 75) / -4,
},
}
const knownMapIds = Object.keys(mapIdToName).map(key => Number.parseInt(key));
const unknown = importStr
.split('\n')
.filter(str => str !== '')
.map(str => JSON.parse(str))
.filter(preset => !knownMapIds.includes(preset.MapID));
console.log('unknown', unknown)
// parse the imported JSON and filter out any empty lines
// and only preserve maps that are in the sim
const presets = importStr
.split('\n')
.filter(str => str !== '')
.map(str => JSON.parse(str))
.filter(preset => knownMapIds.includes(preset.MapID));
console.log('importing presets:', presets);
/**
* Translate from the pWaymark format into the format that
* xivSim uses in localStorage
*/
function translate(presetIn) {
const scale = scaleCoordsForMapId[presetIn.MapID] ?? scaleCoordsForMapId.standard;
if (!scale) {
console.log('no scaling for id', presetIn.MapID)
}
return {
1: {
name: '1',
x: scale.x(presetIn.One.X),
z: scale.z(presetIn.One.Z),
visible: presetIn.One.Active,
},
2: {
name: '2',
x: scale.x(presetIn.Two.X),
z: scale.z(presetIn.Two.Z),
visible: presetIn.Two.Active,
},
3: {
name: '3',
x: scale.x(presetIn.Three.X),
z: scale.z(presetIn.Three.Z),
visible: presetIn.Three.Active,
},
4: {
name: '4',
x: scale.x(presetIn.Four.X),
z: scale.z(presetIn.Four.Z),
visible: presetIn.Four.Active,
},
A: {
name: 'A',
x: scale.x(presetIn.A.X),
z: scale.z(presetIn.A.Z),
visible: presetIn.A.Active,
},
B: {
name: 'B',
x: scale.x(presetIn.B.X),
z: scale.z(presetIn.B.Z),
visible: presetIn.B.Active,
},
C: {
name: 'C',
x: scale.x(presetIn.C.X),
z: scale.z(presetIn.C.Z),
visible: presetIn.C.Active,
},
D: {
name: 'D',
x: scale.x(presetIn.D.X),
z: scale.z(presetIn.D.Z),
visible: presetIn.D.Active,
},
}
}
// reduce the array of imported presets down to an object mapping
// the name of each preset to it's value like xivSim expects in
// the localStorage key `waymarks`
const translated = presets.reduce((acc, preset) => {
let copy = '';
let copyCount = 2;
while (acc[`${mapIdToName[preset.MapID]}: ${preset.Name} ${copy}`]) {
copy = ` (${copyCount++})`;
}
acc[`${mapIdToName[preset.MapID]}: ${preset.Name} ${copy}`] = translate(preset);
return acc;
}, {})
console.log('converted presets to:', translated)
// update localStorage then update the waymark selector in the UI so
// users can pick them without refreshing
localStorage.setItem('waymarks', JSON.stringify(translated))
function updateWaymarkDropdown() {
// copied out of the sim's game.js source to allow for reloading when running
document.querySelector('select[name="loadPreset"]').innerHTML = '<option value="0">---Select Preset---</option>';
const e = JSON.parse(localStorage.getItem("waymarks"));
if (e)
for (const t in e)
document.querySelector('select[name="loadPreset"]').innerHTML += '<option value="' + t + '">' + t + "</option>"
}
updateWaymarkDropdown()
return 'done';
})()
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment