overte/unpublishedScripts/marketplace/camera-move/modules/EnumMeta.js
2017-06-16 16:07:50 -04:00

238 lines
8.4 KiB
JavaScript

// EnumMeta.js -- helper module that maps related enum values to printable names and ids
/* eslint-env commonjs */
/* global DriveKeys, console */
var VERSION = '0.0.1';
var WANT_DEBUG = false;
function _debugPrint() {
// eslint-disable-next-line no-console
(typeof Script === 'object' ? print : console.log)('EnumMeta | ' + [].slice.call(arguments).join(' '));
}
var debugPrint = WANT_DEBUG ? _debugPrint : function(){};
try {
/* global process */
if (process.title === 'node') {
_defineNodeJSMocks();
}
} catch (e) { /* eslint-disable-line empty-block */ }
_debugPrint(VERSION);
// FIXME: C++ emits this action event, but doesn't expose it yet to scripting
// (ie: as Actions.ZOOM or Actions.TranslateCameraZ)
var ACTION_TRANSLATE_CAMERA_Z = {
actionName: 'TranslateCameraZ',
actionID: 12,
driveKeyName: 'ZOOM'
};
module.exports = {
version: VERSION,
DriveKeyNames: invertKeys(DriveKeys),
Controller: {
Hardware: Object.keys(Controller.Hardware).reduce(function(names, prop) {
names[prop+'Names'] = invertKeys(Controller.Hardware[prop]);
return names;
}, {}),
ActionNames: _getActionNames(),
StandardNames: invertKeys(Controller.Standard)
},
getDriveKeyNameFromActionName: getDriveKeyNameFromActionName,
getActionNameFromDriveKeyName: getActionNameFromDriveKeyName,
eventKeyText2KeyboardName: eventKeyText2KeyboardName,
keyboardName2eventKeyText: keyboardName2eventKeyText,
ACTION_TRANSLATE_CAMERA_Z: ACTION_TRANSLATE_CAMERA_Z,
INVALID_ACTION_ID: Controller.findAction('INVALID_ACTION_ID_FOO')
};
_debugPrint('///'+VERSION, Object.keys(module.exports));
var actionsMapping = {}, driveKeyMapping = {};
initializeMappings(actionsMapping, driveKeyMapping);
function invertKeys(object) {
if (!object) {
return object;
}
return Object.keys(object).reduce(function(out, key) {
out[object[key]] = key;
return out;
}, {});
}
function _getActionNames() {
var ActionNames = invertKeys(Controller.Hardware.Actions);
ActionNames[ACTION_TRANSLATE_CAMERA_Z.actionID] = ACTION_TRANSLATE_CAMERA_Z.actionName;
function mapActionName(actionName) {
var actionKey = Controller.Hardware.Actions[actionName],
actionID = Controller.findAction(actionName),
similarName = eventKeyText2KeyboardName(actionName),
existingName = ActionNames[actionID];
var keyName = actionName;
if (actionID === module.exports.INVALID_ACTION_ID) {
_debugPrint('actionID === INVALID_ACTION_ID', actionName);
}
switch (actionName) {
case 'StepTranslateX': actionName = 'StepTranslate'; break;
case 'StepTranslateY': actionName = 'StepTranslate'; break;
case 'StepTranslateZ': actionName = 'StepTranslate'; break;
case 'ACTION1': actionName = 'PrimaryAction'; break;
case 'ACTION2': actionName = 'SecondaryAction'; break;
}
debugPrint(keyName, actionName, actionKey, actionID);
similarName = similarName.replace('Lateral','Strafe').replace(/^(?:Longitudinal|Vertical)/, '');
if (actionID in ActionNames) {
// check if overlap is just BoomIn <=> BOOM_IN
if (similarName !== existingName && actionName !== existingName) {
throw new Error('assumption failed: overlapping actionID:'+JSON.stringify({
actionID: actionID,
actionKey: actionKey,
actionName: actionName,
similarName: similarName,
keyName: keyName,
existingName: existingName
},0,2));
}
} else {
ActionNames[actionID] = actionName;
ActionNames[actionKey] = keyName;
}
}
// first map non-legacy (eg: Up and not VERTICAL_UP) actions
Object.keys(Controller.Hardware.Actions).filter(function(name) {
return /[a-z]/.test(name);
}).sort().reverse().forEach(mapActionName);
// now legacy actions
Object.keys(Controller.Hardware.Actions).filter(function(name) {
return !/[a-z]/.test(name);
}).sort().reverse().forEach(mapActionName);
return ActionNames;
}
// attempts to brute-force translate an Action name into a DriveKey name
// eg: _translateActionName('TranslateX') === 'TRANSLATE_X'
// eg: _translateActionName('Yaw') === 'YAW'
function _translateActionName(name, _index) {
name = name || '';
var key = name;
var re = new RegExp('[A-Z][a-z0-9]+', 'g');
key = key.replace(re, function(Word) {
return Word.toUpperCase()+'_';
})
.replace(/_$/, '');
if (key in DriveKeys) {
debugPrint('getDriveKeyFromEventName', _index, name, key, DriveKeys[key]);
return key;
}
}
function getActionNameFromDriveKeyName(driveKeyName) {
return driveKeyMapping[driveKeyName];
}
// maps an action lookup value to a DriveKey name
// eg: actionName: 'Yaw' === 'YAW'
// actionKey: Controller.Actions.Yaw => 'YAW'
// actionID: Controller.findAction('Yaw') => 'YAW'
function getDriveKeyNameFromActionName(lookupValue) {
if (lookupValue === ACTION_TRANSLATE_CAMERA_Z.actionName ||
lookupValue === ACTION_TRANSLATE_CAMERA_Z.actionID) {
return ACTION_TRANSLATE_CAMERA_Z.driveKeyName;
}
if (typeof lookupValue === 'string') {
lookupValue = Controller.findAction(lookupValue);
}
return actionsMapping[lookupValue];
}
// maps a Controller.key*Event event.text -> Controller.Hardware.Keyboard[name]
// eg: ('Page Up') === 'PgUp'
// eg: ('LEFT') === 'Left'
function eventKeyText2KeyboardName(text) {
if (eventKeyText2KeyboardName[text]) {
// use memoized value
return eventKeyText2KeyboardName[text];
}
var keyboardName = (text||'').toUpperCase().split(/[ _]/).map(function(WORD) {
return WORD.replace(/([A-Z])(\w*)/g, function(_, A, b) {
return (A.toUpperCase() + b.toLowerCase());
});
}).join('').replace('Page','Pg');
return eventKeyText2KeyboardName[text] = eventKeyText2KeyboardName[keyboardName] = keyboardName;
}
// maps a Controller.Hardware.Keyboard[name] -> Controller.key*Event event.text
// eg: ('PgUp') === 'PAGE UP'
// eg: ('Shift') === 'SHIFT'
function keyboardName2eventKeyText(keyName) {
if (keyboardName2eventKeyText[keyName]) {
// use memoized value
return keyboardName2eventKeyText[keyName];
}
var text = keyName.replace('Pg', 'Page');
var caseWords = text.match(/[A-Z][a-z0-9]+/g) || [ text ];
var eventText = caseWords.map(function(str) {
return str.toUpperCase();
}).join('_');
return keyboardName2eventKeyText[keyName] = eventText;
}
function initializeMappings(actionMap, driveKeyMap) {
_debugPrint('creating mapping');
var ref = ACTION_TRANSLATE_CAMERA_Z;
actionMap[ref.actionName] = actionMap[ref.actionID] = ref.driveKeyName;
actionMap.BoomIn = 'ZOOM';
actionMap.BoomOut = 'ZOOM';
Controller.getActionNames().sort().reduce(
function(out, name, index, arr) {
var actionKey = arr[index];
var actionID = Controller.findAction(name);
var value = actionID in out ? out[actionID] : _translateActionName(name, index);
if (value !== undefined) {
var prefix = (actionID in out ? '+++' : '---');
debugPrint(prefix + ' Action2DriveKeyName['+name+'('+actionID+')] = ' + value);
driveKeyMap[value] = driveKeyMap[value] || name;
}
out[name] = out[actionID] = out[actionKey] = value;
return out;
}, actionMap);
}
// ----------------------------------------------------------------------------
// mocks for litmus testing using Node.js command line tools
function _defineNodeJSMocks() {
/* eslint-disable no-global-assign */
DriveKeys = {
TRANSLATE_X: 12345
};
Controller = {
getActionNames: function() {
return Object.keys(this.Hardware.Actions);
},
findAction: function(name) {
return this.Hardware.Actions[name] || 4095;
},
Hardware: {
Actions: {
TranslateX: 54321
},
Application: {
Grounded: 1
},
Keyboard: {
A: 65
}
}
};
/* eslint-enable no-global-assign */
}