Commit 8158346e authored by insert's avatar insert

Added support for the rest of the api.

parent f65545e0
......@@ -25,7 +25,9 @@ console.log(identity.name); // Your character's name =)
## To-Do
- Create documentation for module
- Finish support for [ML struct](https://wiki.guildwars2.com/wiki/API:MumbleLink#MumbleLink_structure), this includes: f* vars, the context, desc and other variables.
- Figure out how to handle the context properly
- Figure out what character.front / .top and camera.front / .top are
- ~~Finish support for [ML struct](https://wiki.guildwars2.com/wiki/API:MumbleLink#MumbleLink_structure), this includes: f* vars, the context, desc and other variables.~~
## Issues
......
......@@ -6,10 +6,17 @@ if (!mumbleLink.init()) {
process.exit(1);
}
if (!mumbleLink.isGuildWars2() || !mumbleLink.hasCharacterSelected()) {
console.log('Guild Wars 2 not detected or user has not entered the world at least once!');
process.exit(1);
}
let identity = mumbleLink.getIdentity();
console.log(`Hi, ${identity.name}!
I see you are a ${MumbleLink.RaceEnum.getKey(identity.race)} ${MumbleLink.ProfessionEnum.getKey(identity.profession)}.
You are on map ${identity.map_id}, world ${identity.world_id}.
You ${identity.commander ? 'do' : 'do not'} currently have a commander tag.
Your fov is ${identity.fov} and your ui is ${MumbleLink.UISizeEnum.getKey(identity.uisz)}.`);
\ No newline at end of file
Your fov is ${identity.fov} and your ui is ${MumbleLink.UISizeEnum.getKey(identity.uisz)}.`);
mumbleLink.close();
\ No newline at end of file
......@@ -16,4 +16,8 @@ if (!mumbleLink.hasCharacterSelected()) {
process.exit(1);
}
console.log('The player is currently in-game and has selected a character!');
\ No newline at end of file
console.log('The player is currently in-game and has selected a character!');
let ui = mumbleLink.getUIvar();
console.log(`UI Version: ${ui.version}, Tick: ${ui.tick}`);
mumbleLink.close();
\ No newline at end of file
const MumbleLink = require('../');
const mumbleLink = new MumbleLink();
if (!mumbleLink.init()) {
console.log('Could not create shared memory location!');
process.exit(1);
}
if (!mumbleLink.isGuildWars2() || !mumbleLink.hasCharacterSelected()) {
console.log('Guild Wars 2 not detected or user has not entered the world at least once!');
process.exit(1);
}
let context = mumbleLink.getContext();
console.log(context);
mumbleLink.close();
\ No newline at end of file
const MumbleLink = require('../');
const mumbleLink = new MumbleLink();
const util = require('util');
if (!mumbleLink.init()) {
console.log('Could not create shared memory location!');
process.exit(1);
}
if (!mumbleLink.isGuildWars2() || !mumbleLink.hasCharacterSelected()) {
console.log('Guild Wars 2 not detected or user has not entered the world at least once!');
process.exit(1);
}
let i = 40;
setInterval(() => {
if (i == 0) {
mumbleLink.close();
process.exit();
}
let fVars = mumbleLink.getFvars();
console.log(util.inspect(fVars));
console.log(i);
i--;
}, 500);
\ No newline at end of file
......@@ -8,12 +8,24 @@ Object.prototype.getKey = function(value) {
return Object.keys(object).find(key => object[key] === value);
};
const collectWChar = (mL, attribute) => {
let arr = new Uint8Array(256);
const collectWChar = (mL, attribute, size = 256) => {
let arr = new Uint8Array(size);
mL['get' + attribute](arr);
return textDecoder.decode(arr);
};
const collectUChar = (mL, attribute, size = 48) => {
let arr = new Uint8Array(size);
mL['get' + attribute](arr);
return arr;
};
const collectFloats = (mL, attribute, size = 3) => {
let arr = new Uint8Array(size);
mL['get' + attribute](arr);
return arr;
};
/**
* @typedef {Object} identity
* @property {string} name Character Name
......@@ -59,6 +71,15 @@ class MumbleLink {
hasCharacterSelected() {
return collectWChar(this.mL, "Identity") != "";
}
/**
* Get UI variables
*/
getUIvar() {
return {
version: this.mL.uiVersion(),
tick: this.mL.uiTick()
};
}
/**
* Get the current link name.
* @returns {string} Should be 'Guild Wars 2'.
......@@ -66,6 +87,13 @@ class MumbleLink {
getName() {
return collectWChar(this.mL, "Name");
}
/**
* Get the link description
* @returns {string} A description
*/
getDescription() {
return collectWChar(this.mL, "Description", 2048);
}
/**
* Get the character's identity.
* @returns {Identity} Identity object
......@@ -85,6 +113,47 @@ class MumbleLink {
data = data.substring(0, end);
return JSON.parse(data);
}
/**
* Get character / user / camera positions
*/
getContext() {
let raw = collectUChar(this.mL, "Context", this.mL.getContextLength());
let data = {
serverAddress: raw.slice(0, 28)
};
["mapId", "mapType", "shardId", "instance", "buildId"].forEach((v, i) => {
let temp = raw.slice(29 + (i * 4), 29 + (i * 4) + 4);
let num = 0;
temp.forEach((x, i) => {
num += x << temp.length - i;
});
data[v] = num;
});
return data;
}
/**
* Get f* variables
*/
getFvars() {
return {
character: {
position: collectFloats(this.mL, "AvatarPosition"),
front: collectFloats(this.mL, "AvatarFront"),
top: collectFloats(this.mL, "AvatarTop")
},
camera: {
position: collectFloats(this.mL, "CameraPosition"),
front: collectFloats(this.mL, "CameraFront"),
top: collectFloats(this.mL, "CameraTop")
}
};
}
/**
* Probably important.
*/
close() {
this.mL.close();
}
}
module.exports = MumbleLink;
......
{
"name": "gw2mumblelink",
"version": "1.0.2",
"version": "1.0.3",
"description": "Guild Wars 2 Mumble Link integration for Node.js",
"main": "index.js",
"scripts": {
......
......@@ -25,6 +25,7 @@ class MumbleLink {
wchar_t description[2048];
};
LinkedMem *lm = NULL;
HANDLE mapObj = NULL;
inline void pushDataToBuffer(nbind::Buffer dest, wchar_t* src) {
size_t length = dest.length();
unsigned char *data = dest.data();
......@@ -34,9 +35,28 @@ class MumbleLink {
}
dest.commit();
}
inline void pushDataToBuffer(nbind::Buffer dest, unsigned char* src) {
size_t length = dest.length();
unsigned char *data = dest.data();
if (!data || !length) return;
for (size_t pos = 0; pos < length; ++pos) {
data[pos] = src[pos];
}
dest.commit();
}
inline void pushDataToBuffer(nbind::Buffer dest, float* src) {
size_t length = dest.length();
unsigned char *data = dest.data();
if (!data || !length) return;
for (size_t pos = 0; pos < length; ++pos) {
int c = src[pos];
data[pos] = c;
}
dest.commit();
}
public:
inline bool init() {
HANDLE mapObj = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LinkedMem), L"MumbleLink");
mapObj = CreateFileMappingW(INVALID_HANDLE_VALUE, NULL, PAGE_READWRITE, 0, sizeof(LinkedMem), L"MumbleLink");
if (mapObj == NULL) return false;
lm = (LinkedMem*)MapViewOfFile(mapObj, FILE_MAP_ALL_ACCESS, 0, 0, sizeof(LinkedMem));
if (lm == NULL) {
......@@ -46,12 +66,48 @@ class MumbleLink {
}
return true; // We are now ready to recieve information.
};
inline UINT32 uiVersion() {
return lm->uiVersion;
}
inline DWORD uiTick() {
return lm->uiTick;
}
inline void getName(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->name);
};
inline void getDescription(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->description);
};
inline void getIdentity(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->identity);
};
inline int getContextLength() {
return lm->context_len;
}
inline void getContext(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->context);
};
inline void getAvatarPosition(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->fAvatarPosition);
};
inline void getAvatarFront(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->fAvatarFront);
};
inline void getAvatarTop(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->fAvatarTop);
};
inline void getCameraPosition(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->fCameraPosition);
};
inline void getCameraFront(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->fCameraFront);
};
inline void getCameraTop(nbind::Buffer buf) {
pushDataToBuffer(buf, lm->fCameraTop);
};
inline void close() {
if (mapObj != NULL) CloseHandle(mapObj);
};
};
#include "nbind/nbind.h"
......@@ -59,6 +115,18 @@ class MumbleLink {
NBIND_CLASS(MumbleLink) {
construct<>();
method(init);
method(uiVersion);
method(uiTick);
method(getName);
method(getDescription);
method(getIdentity);
method(getContext);
method(getContextLength);
method(getAvatarPosition);
method(getAvatarFront);
method(getAvatarTop);
method(getCameraPosition);
method(getCameraFront);
method(getCameraTop);
method(close);
};
\ No newline at end of file
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment