Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
8 changes: 8 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# Do NOT commit common editor backup files and stuff:
*~
.#*
*.bak

# Don't commit these NodeJS compile-time artifacts either:
node_modules/
package-lock.json
8 changes: 5 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,11 @@ v1.2.0 - Added Rotation Option
v1.3.0 - Fixed compatibility with Artemis v2.3.0+; Added flag to support Artemis <=2.2.0.
Perspective option is now only available for use with older clients.

v1.4.0-NN - Does not use chalk or path. Fix Buffer() DeprecationWarning

v1.5.0-NN - Updated for Artemis 2.8.x. Tidied packet Parsing.
Parse Version packets (obsolete --oldVersion).

MVM takes these arguments:
* -l/--listen \[port\] Specifies the port MVM should use to accept Artemis client connections.
This should match the "networkPort" setting in Artemis.ini.
Expand All @@ -23,11 +28,8 @@ MVM takes these arguments:
3=Aft, 4=Tactical, 5=Long Range Sensors, and 6=Ship Status 90,180,270=Rotate by
x Degrees from actual mainscreen view in 90º increments.


* -s/--server \[hostname or IP address\] \(Optional\) The hostname or IP address of the real Artemis server.
If not specified, this defaults to 'localhost'.
* -o/--oldVersion \(Optional\) Enables compatibility with Artemis clients v2.1.1 thru 2.2.0
Note: MVM will either crash or produce inconsistent behavior in your client if this flag is incorrectly assigned due to changes in the protocol.

* -p/--perspective \[1,3\] \(Optional, Requires -o \) Specifiy which perspective should be displayed. 1 = First person, 3 = Third person.
Note: Will almost certainly need to manually toggle perspective before it will lock.
Expand Down
193 changes: 85 additions & 108 deletions mvm.js
Original file line number Diff line number Diff line change
@@ -1,38 +1,38 @@
//Based almost entirely on "tcpslow" by llambda - https://github.com/llambda/tcpslow
//I just removed the "slow" parts and shoe-horned my code into the loop.
//UserMcUser just removed the "slow" parts and shoe-horned MVM code into the loop.
//NoseyNick obsoleted --oldVersion by parsing server version, support Artemis 2.8.x
//
//Version History
// v1.0 - First public release
// v1.1 - Added perspective option, changed "-h" for host to "-s" for server to avoid collision wiht "-h" for help.
// v1.2 - Added "Dynamic" switching in 90º increments.
// v1.3 - Updated for Artemis 2.5.1; added option to support old client versions.
// Removed a bunch of unused code from tcpslow. Removed perspective option, except for compatibility mode.
// v1.4-NN - Does not use chalk or path. Fix Buffer() DeprecationWarning. Tidied.
// v1.5-NN - Updated for Artemis 2.8.x. Tidied packet Parsing.
// Parse Version packets (obsolete --oldVersion).

'use strict';

var net = require('net');
var chalk = require('chalk');
var path = require('path');
var program = require('commander');
var packagejson = require('./package.json');

var MainPlayerPacket = new Buffer(5);
MainPlayerPacket.writeUIntBE(0xf93d808001,0,5);
var PerspectivePacket = new Buffer(5);
PerspectivePacket.writeUIntBE(0xfec854f712,0,5);
var minor_ver = 8; // Artemis v2.X - assume Artemis 2.8 until we find otherwise
var VersionPacket = Buffer.from([0x4a, 0xe7, 0x48, 0xe5]);
var MainPlayerPacket = Buffer.from([0xf9, 0x3d, 0x80, 0x80, 0x01]);
var PerspectivePacket = Buffer.from([0xfe, 0xc8, 0x54, 0xf7, 0x12]);

var temp = Buffer(0);
var temp;
var realMainScreenView = 0;
var viewTemp = 0;
var screenRotation = 0;
var viewArrayFore = [0,2,3,1]; //Because the order of the screens isn't layed out spatially we can't use simple math to determine the rotation. So rather than fuck around with lots of logic, I just pre-built these arrays.
var viewArrayPort = [1,0,2,3];
var viewArrayStar = [2,3,1,0];
var viewArrayAft = [3,1,0,2];
var viewArrayAft = [3,1,0,2];
var showInstead = 0;
var perspectiveInstead = -1;
var oldVersion = 0;
var perspectiveOffset = 25;
var verbose = 1;

program
Expand All @@ -41,7 +41,6 @@ program
.option('-f, --forward [port]', 'TCP port to forward to (Optional, default is\n 2010)\n', parseInt)
.option('-v, --view [0-6,90,180,270]', 'What should the mainscreen show?\n 0=Fore, 1=Port, 2=Starboard, 3=Aft, 4=Tactical\n 5=Long Range Sensors, and 6=Ship Status\n 90,180,270=Rotate by x Degrees from actual\n mainscreen view in 90º increments.\n')
.option('-s, --server [hostname]', 'IP or Hostname of the real Artemis Server.\n (Optional, default is \'localhost\')\n')
.option('-o, --oldVersion', 'Setting this option will allow MVM to work\n with Artemis v2.1.1 thru 2.2.0\n')
.option('-p, --perspective [1,3]', 'Force mainscreen perspective to 1st or 3rd\n person. (Optional, requires -o)\n Toggle perspective once to initialize.\n Note: Not compatible with Artemis >=2.3.0\n', parseInt)
.option('-q, --quiet', 'Suppress console messages after initialization')
.parse(process.argv);
Expand All @@ -66,27 +65,12 @@ if (!program.view) {
} else {
if (program.view > 270) {
console.error('\nERROR: A rotation value greater than 270º is not allowed. Or useful.');
return 0; //
return 0;
}; //End If
}; //End If
}; //End If
} //End If

if (program.oldVersion) {
oldVersion = 1;
perspectiveOffset = 28; // Artemis <=2.1.5
} else {
oldVersion = 0;
perspectiveOffset = 25; // Artemis >=2.3.0+ Not that this value is *used* mind you...
}

if (program.perspective) {
if (!oldVersion) {
console.log('\nERROR: MVM can only provide perspective locking in Artemis v2.1.1 thru 2.2.0\nMust use \'-o/--oldVersion\' argument with \'-p/--perspective\'')
return 0;
}
}

if (program.quiet) {verbose = 0;}

function createConnection() {
Expand All @@ -105,15 +89,17 @@ function createConnection() {
}

function unpackBitmap(bufferSlice, buffer) { //Returns the number of bytes to skip.

// 0 1 2 3 4 5 6 7 8 9 10111213141516171819202122232425262728293031
var fieldBytes = [4,4,4,4,4,1,1,4,2,4,4,4,4,4,4,4,4,4,2,0,4,4,4,4,4,1,4,0,0,0,0,0]; //As of Artemis 2.1.5
var bitMapped = Array(40);
var bitmap = Array(5);
if (oldVersion) {var runTot = 34;} else {var runTot = 35;} //Running Total of bytes we can skip. 35 for 2.3.0+, 34 for <2.3.0
var i = 0;
var byte = 0;
var bit = 0;
var n = (minor_ver < 7) ? 2 : 1; // InNebula(U16) became InNebula(U8) in 2.7 :-/
// 0 1 2 3 4 5 6 7 8 9 101112131415 1617181920212223 2425262728293031 ...
var fieldBytes = [4,4,4,4,4,1,1,4, 2,4,4,4,4,4,4,4, 4,4,n,0,4,4,4,4, 4,1,4,1,1,1,4,4]; // ...
var bitMapped = Array(40);
var bitmap = Array(5);
// Running Total of bytes we can skip.
// 34 for <2.3.0, now 35 for 2.3.0+ (gained another byte of bitmap):
var runTot = (minor_ver >= 3) ? 35 : 34;
var i = 0;
var byte = 0;
var bit = 0;

for (i = 0; i < 4 ; i++) {
bitmap[i] = bufferSlice.readUInt8(i);
Expand All @@ -126,16 +112,14 @@ var bit = 0;

if (!bitMapped[27]) return 0; //We can early exit if the update does not include the Mainscreen view.

for (i=0;i<28;i++){ //Only need to look until we get to the item we want.
if (i === 19 && bitMapped[i] === 1) {
var strLen = (buffer.readUInt32LE(runTot)*2);
//var str = buffer.toString('utf16le', runTot + 4, runTot + strLen + 2);
//console.log('str: ', str);
fieldBytes[i] = strLen + 4;
};
if (bitMapped[i]) {
runTot += fieldBytes[i];
};
for (i=0;i<27;i++){ //Only need to look until we get to the item we want.
if (bitMapped[i] && fieldBytes[i]) {
runTot += fieldBytes[i];
} else if (bitMapped[i]) {
// fieldBytes=0 (ab)used to indicate len(U32)+len*ch(U16) = string
var strLen = buffer.readUInt32LE(runTot) * 2;
runTot += strLen + 4;
};
};
return runTot;
}; //End Function
Expand Down Expand Up @@ -165,49 +149,47 @@ function getPrettyPerspective(thePerspective, altMode) {
};//End getPrettyPerspective

function getViewByDegrees(theRealView, theDegrees) {
if (theRealView < 4) {
switch(theRealView) {

case 0: //Fore
return viewArrayFore[theDegrees / 90];
break;

case 1: //Port
return viewArrayPort[theDegrees / 90];
break;

case 2: //Starboard
return viewArrayStar[theDegrees / 90];
break;

case 3: //Aft
return viewArrayAft[theDegrees / 90];
break;

default:
console.error('Somehow we didn\'t switch right in getViewByDegrees.');
return -1;
break;
}//End Switch
} else {
return -1; //
};
switch(theRealView) {
case 0: return viewArrayFore[theDegrees / 90];
case 1: return viewArrayPort[theDegrees / 90];
case 2: return viewArrayStar[theDegrees / 90];
case 3: return viewArrayAft [theDegrees / 90];
}//End Switch
return theRealView;
}//End getViewByDegrees

var server = net.createServer(function(listen) {
listen.forward = createConnection();

listen.forward.on('connect', function() {});

listen.forward.on('data', function(data) {

//MVM Lie Goes here.
// MVM Lie Goes here. ++++++++++ Strongly consider proper DEADBEEF parsing?
temp = data.slice(20,25);
//console.log(temp);

if (temp.equals(MainPlayerPacket)){
if (data.slice(20,24).equals(VersionPacket)){
var major_ver = data.readUInt32LE(32);
minor_ver = data.readUInt32LE(36); // global var
var patch_ver = data.readUInt32LE(40);
if (verbose) {
console.log('Connected to Server Version:', major_ver+'.'+minor_ver+'.'+patch_ver);
}
if (major_ver < 2) {
console.error(' How quaint! DANGER! MVM probably only works with Artemis 2.X!');
minor_ver = -1; // not true but "less than v2.0" more likely to work
} else if (major_ver == 1) {
if (verbose) {
if (minor_ver < 1 ) {
console.warn(' MVM support for Artemis < 2.1 may be dubious!');
} else if ((minor_ver > 8 ) || (minor_ver == 8 && patch_ver > 1)) {
console.warn(' MVM support for Artemis > 2.8.1 may be dubious!');
}
}
} else {
console.error(' How awesome! DANGER! MVM probably only works with Artemis 2.X!');
minor_ver = 999; // not true but "v2.999" more useful than 2.x
}
} else if (temp.equals(MainPlayerPacket)) {
var bufferIndex = unpackBitmap(data.slice(29,34), data);

if (bufferIndex){
//console.log('bitmap: ', data.slice(29,34));
//console.log('Buffer Index: ', bufferIndex);
Expand All @@ -224,20 +206,22 @@ var server = net.createServer(function(listen) {
if(verbose){console.log('But we are dynamically rotating by', screenRotation, ' degrees and sending: ', getPrettyView(data.readUInt8(bufferIndex)));}
};
};//End If bufferIndex
}; //End if MainPlayerPacket

//console.log(temp);

if (temp.equals(PerspectivePacket) && perspectiveInstead != -1) {

//console.log('Contents of Perspective Buffer: ', data);
if(verbose){console.log('Server Says the mainScreen perspective is: ', getPrettyPerspective(data.readUInt8(perspectiveOffset),1));}
} else if (temp.equals(PerspectivePacket) && perspectiveInstead != -1) {
//console.log('Contents of Perspective Buffer: ', data);
var perspectiveOffset = (minor_ver < 4) ? 28 : 25;
if(verbose){console.log('Server Says the mainScreen perspective is: ', getPrettyPerspective(data.readUInt8(perspectiveOffset),1));}
if (minor_ver < 4) { // Artemis 2.3.x or lower
data.writeUInt8(perspectiveInstead, perspectiveOffset);
if(verbose){console.log('But we are sending: ', getPrettyPerspective(data.readUInt8(perspectiveOffset),1));}
}; //End if PerspectivePacket
if (verbose) {
console.log('But we are sending: ', getPrettyPerspective(data.readUInt8(perspectiveOffset),1));
}
} else {
return; // skip sending it to the listener. Not perfect, but half works?
}
}

listen.write(data);
})
listen.write(data); // possibly modified packet to client
});

listen.forward.on('error', function(err) {
listen.destroy();
Expand All @@ -253,27 +237,22 @@ var server = net.createServer(function(listen) {
listen.forward.write(data);
});

listen.on('error', function(err) {
listen.forward.destroy();
});
listen.on('end', function() {
listen.forward.end();
listen.end();
});
listen.on('error', function(err) {
listen.forward.destroy();
});

listen.on('close', function() {
listen.forward.end();
});
})
});


server.listen(program.listen, function() {
console.log('Mainscreen View Manager v' + packagejson.version + '\n');

if (program.oldVersion) {
console.log('Compatability mode enabled.\n')
};

if (program.listen) {
console.log('Listening on port ' + program.listen);
};
Expand All @@ -290,11 +269,9 @@ server.listen(program.listen, function() {
}

if (program.perspective) {
if (oldVersion) {
perspectiveInstead = getPerspective(program.perspective);
console.log('Perspective will be set to: ' + getPrettyPerspective(program.perspective,0));
}
};
console.log('\nUse Control+C to quit.');
if(!verbose){console.log('\nNo further console messages will be shown.')};
perspectiveInstead = getPerspective(program.perspective);
console.log('Perspective will be set to: ' + getPrettyPerspective(program.perspective,0));
}
console.log('\nUse Control+C to quit.');
if(!verbose){console.log('\nNo further console messages will be shown.')};
});
11 changes: 5 additions & 6 deletions package.json
Original file line number Diff line number Diff line change
@@ -1,21 +1,20 @@
{
"name": "node-mvm",
"version": "1.3.0",
"version": "1.5.0-NN",
"description": "Mainscreen View Manager - Mod for Artemis Space Ship Bridge Simulator - Control what is shown on your Main Screen clients! Uses a TCP proxy that injects changes into Artemis packets.",
"main": "mvm.js",
"repository": {
"type": "git",
"url": "https://github.com/UserMcUser/node-MVM"
"url": "https://github.com/NoseyNick/node-MVM"
Copy link
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Oh this you are obviously more than welcome to edit back to your URL of course! 😆

},
"keywords": [
"artemis",
"proxy"
"artemis",
"proxy"
],
"author": "UserMcUser",
"license": "Custom",
"dependencies": {
"chalk": "^0.5.1",
"commander": "^2.6.0"
"commander": "^2.20.3"
},
"bin": {
"MVM": "./mvm.js"
Expand Down