359 lines
9.5 KiB
JavaScript
359 lines
9.5 KiB
JavaScript
const networkClock = 1000 / 16;
|
|
|
|
var allowedIDCharacters = "0123456789ABCDEF";
|
|
var tokenCharacters = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz._-";
|
|
|
|
var generateAccessToken = function () {
|
|
var token = "";
|
|
|
|
for (var c = 0; c < 64; c++) {
|
|
token += tokenCharacters[
|
|
Math.floor(
|
|
Math.random() * tokenCharacters.length
|
|
)
|
|
];
|
|
}
|
|
|
|
return token;
|
|
};
|
|
|
|
var initMatrixClient = function (baseURL, mxID, withCrypto = false) {
|
|
return new Promise(function (resolve, reject) {
|
|
var matrixAccessToken = localStorage.getItem("matrix_access_token");
|
|
if (!matrixAccessToken) {
|
|
matrixAccessToken = generateAccessToken();
|
|
localStorage.setItem("matrix_access_token", matrixAccessToken);
|
|
}
|
|
|
|
var matrixClient = global.matrixcs.createClient({
|
|
"baseUrl": baseURL,
|
|
"accessToken": matrixAccessToken,
|
|
"userId": mxID,
|
|
"deviceId": "XVoxel"
|
|
});
|
|
|
|
module.exports.matrixClient = matrixClient;
|
|
|
|
resolve(matrixClient);
|
|
|
|
if (withCrypto) {
|
|
matrixClient.initCrypto().then(function () {
|
|
|
|
}).catch(console.error);
|
|
}
|
|
});
|
|
};
|
|
|
|
var loginToMatrix = function (username, password) {
|
|
return new Promise(function (resolve, reject) {
|
|
if (!("matrixClient" in module.exports)) return reject(new Error("Matrix client hasn't been initialized yet"));
|
|
module.exports.matrixClient.loginWithPassword(username, password).then(function (result) {
|
|
var matrixAccessToken = module.exports.matrixClient.getAccessToken();
|
|
localStorage.setItem("matrix_access_token", matrixAccessToken);
|
|
resolve(result);
|
|
}).catch(reject);
|
|
});
|
|
};
|
|
|
|
var startMatrixClient = function () {
|
|
module.exports.matrixClient.startClient();
|
|
|
|
module.exports.matrixClient.on("sync", function (state, previousState, response) {
|
|
if (state === "PREPARED") {
|
|
var buttonReadyInterval = setInterval(function () {
|
|
var mxWJBtn = document.querySelector("#matrixworldjoin");
|
|
|
|
if (!mxWJBtn) return;
|
|
|
|
mxWJBtn.disabled = false;
|
|
clearInterval(buttonReadyInterval);
|
|
}, 256);
|
|
}
|
|
});
|
|
};
|
|
|
|
var createWorldRoom = function (name) {
|
|
return new Promise(function (resolve, reject) {
|
|
module.exports.matrixClient.createRoom({
|
|
"name": name,
|
|
"visibility": "private",
|
|
"topic": "A Voxel world",
|
|
"creation_content": {
|
|
"type": "m.world.voxel"
|
|
}
|
|
}).then(resolve).catch(reject);
|
|
});
|
|
};
|
|
|
|
var getWorldRooms = function () {
|
|
var rooms = module.exports.matrixClient.getRooms();
|
|
|
|
if (!rooms) return [];
|
|
|
|
return rooms.filter(room => room.getType() == "m.world.voxel");
|
|
};
|
|
|
|
var syncWorldFromMatrixRoom = function (room) {
|
|
return new Promise(function (resolve, reject) {
|
|
module.exports.matrixClient.getStateEvent(room.roomId, "m.world.voxel", "save").then(function (event) {
|
|
fetch(module.exports.matrixClient.mxcUrlToHttp(event["save_uri"])).then(function (response) {
|
|
response.arrayBuffer().then(function (arrayBuffer) {
|
|
global.openSave(arrayBuffer).then(function (loadedWorlds) {
|
|
for (var worldName in loadedWorlds) {
|
|
if (loadedWorlds.hasOwnProperty(worldName)) {
|
|
global.worlds[worldName] = loadedWorlds[worldName];
|
|
}
|
|
}
|
|
|
|
resolve(global.worlds[room.name]);
|
|
}).catch(reject);
|
|
}).catch(reject);
|
|
}).catch(reject);
|
|
}).catch(reject);
|
|
});
|
|
};
|
|
|
|
var syncWorldToMatrixRoom = function (room) {
|
|
return new Promise(function(resolve, reject) {
|
|
global.makeSave().then(function (archive) {
|
|
module.exports.matrixClient.uploadContent(archive, {
|
|
"name": room.name + ".zip",
|
|
"type": "application/zip"
|
|
}).then(function (response) {
|
|
module.exports.matrixClient.sendStateEvent(room.roomId, "m.world.voxel", {
|
|
"save_uri": response.content_uri
|
|
}, "save").then(resolve).catch(reject);
|
|
}).catch(reject);
|
|
}).catch(reject);
|
|
});
|
|
};
|
|
|
|
var connectMatrix = function (room) {
|
|
return new Promise(function (resolve, reject) {
|
|
var groupCall = module.exports.matrixClient.getGroupCallForRoom(room.roomId);
|
|
if (!groupCall) {
|
|
return module.exports.matrixClient.createGroupCall(
|
|
room.roomId, global.matrixcs.GroupCallType["Voice"],
|
|
false, global.matrixcs.GroupCallIntent["Room"], true
|
|
).then(function (call) {
|
|
call.initWithAudioMuted = true;
|
|
call.initWithVideoMuted = true;
|
|
call.setMicrophoneMuted(true);
|
|
call.enter();
|
|
resolve(call);
|
|
}).catch(console.error);
|
|
}
|
|
groupCall.initWithAudioMuted = true;
|
|
groupCall.initWithVideoMuted = true;
|
|
groupCall.setMicrophoneMuted(true);
|
|
groupCall.enter();
|
|
resolve(groupCall);
|
|
});
|
|
};
|
|
|
|
if (localStorage.getItem("matrix_is_connected")) {
|
|
initMatrixClient(
|
|
localStorage.getItem("matrix_baseurl"),
|
|
localStorage.getItem("matrix_mxid")
|
|
).then(function (matrixClient) {
|
|
module.exports.matrixClient = matrixClient;
|
|
startMatrixClient();
|
|
}).catch(function (error) {
|
|
console.error(error);
|
|
localStorage.removeItem("matrix_is_connected");
|
|
});
|
|
}
|
|
|
|
var connectRTC = function (options) {
|
|
var randomID = (options.username || "Guest") + "-";
|
|
for (var c = 0; c < 16; c++) {
|
|
randomID += allowedIDCharacters[
|
|
Math.floor(
|
|
Math.random() * allowedIDCharacters.length
|
|
)
|
|
];
|
|
}
|
|
|
|
var peerNetwork = new global.peer.default(randomID, {
|
|
"host": options.host,
|
|
"port": options.port,
|
|
"path": options.path
|
|
});
|
|
|
|
return peerNetwork;
|
|
};
|
|
|
|
var connect = function (url) {
|
|
try {
|
|
var connectionURL = new URL(url);
|
|
} catch (error) {
|
|
global.throwError(error);
|
|
}
|
|
|
|
var splitPathName = connectionURL.pathname.split(/[\/]/);
|
|
|
|
var pathNameParts = splitPathName[2].split("@");
|
|
|
|
if (pathNameParts.length > 1) {
|
|
var pathNameCredentials = pathNameParts.split(":");
|
|
|
|
var pathNameUsername = pathNameCredentials[0];
|
|
|
|
if (pathNameCredentials.length > 1) {
|
|
var pathNamePassword = pathNameCredentials[1];
|
|
}
|
|
|
|
var pathNameConnectionDataIndex = 1;
|
|
} else {
|
|
var pathNameConnectionDataIndex = 0;
|
|
}
|
|
|
|
var pathNameConnectionData = pathNameParts[pathNameConnectionDataIndex].split(":");
|
|
|
|
var pathNameAddress = pathNameConnectionData[0];
|
|
|
|
if (pathNameConnectionData.length > 1) {
|
|
var pathNamePort = pathNameConnectionData[1];
|
|
}
|
|
|
|
var pathNamePath = "/" + splitPathName.slice(3).join("/");
|
|
|
|
switch (connectionURL.protocol) {
|
|
case "rtc:":
|
|
return connectRTC({
|
|
"host": pathNameAddress,
|
|
"port": pathNamePort || 443,
|
|
"path": pathNamePath || "/",
|
|
"username": pathNameUsername || "Guest",
|
|
"password": pathNamePassword || null
|
|
});
|
|
break;
|
|
case "ws:":
|
|
|
|
break;
|
|
case "wss:":
|
|
|
|
break;
|
|
case "http:":
|
|
|
|
break;
|
|
case "https:":
|
|
|
|
break;
|
|
default:
|
|
|
|
}
|
|
};
|
|
|
|
module.exports = {
|
|
"initMatrixClient": initMatrixClient,
|
|
"loginToMatrix": loginToMatrix,
|
|
"startMatrixClient": startMatrixClient,
|
|
"createWorldRoom": createWorldRoom,
|
|
"getWorldRooms": getWorldRooms,
|
|
"connectMatrix": connectMatrix,
|
|
"connect": connect,
|
|
"menus": {
|
|
"play": {
|
|
"elements": [
|
|
{
|
|
"type": "button",
|
|
"label": "Multiplayer",
|
|
"action": "open-menu",
|
|
"action-args": ["serversel", 2]
|
|
}
|
|
]
|
|
},
|
|
"serversel": {
|
|
"elements": [
|
|
{
|
|
"type": "text",
|
|
"id": "serveraddressinput",
|
|
"label": global.locales.getRawString(global.currentLanguage, "play.multiplayer.serveraddressinput.label"),
|
|
"placeholder": global.locales.getRawString(global.currentLanguage, "play.multiplayer.serveraddressinput.placeholder"),
|
|
"value": "",
|
|
"action": "run",
|
|
"runnable": function (event) {
|
|
var serverConnectButton = global.document.getElementById("serverconnectbutton");
|
|
|
|
if (event.path[0].value.length < 1) {
|
|
serverConnectButton.disabled = true;
|
|
} else {
|
|
try {
|
|
new URL(event.path[0].value);
|
|
|
|
serverConnectButton.disabled = false;
|
|
} catch (e) {
|
|
serverConnectButton.disabled = true;
|
|
}
|
|
}
|
|
}
|
|
},
|
|
{
|
|
"type": "button",
|
|
"id": "serverconnectbutton",
|
|
"label": global.locales.getRawString(global.currentLanguage, "play.multiplayer.serverconnectbutton.label"),
|
|
"disabled": true,
|
|
"action": "run",
|
|
"runnable": function (event) {
|
|
var serverAddressInputBox = global.document.getElementById("serveraddressinput");
|
|
|
|
connect(serverAddressInputBox.value);
|
|
}
|
|
},
|
|
{
|
|
"type": "button",
|
|
"id": "matrixworldjoin",
|
|
"label": global.locales.getRawString(global.currentLanguage, "play.multiplayer.loadmatrixworldsbutton.label"),
|
|
"disabled": true,
|
|
"action": "run",
|
|
"runnable": function (event) {
|
|
for (var e = module.exports.menus["serversel"].elements.length - 1; e >= 0; e--) {
|
|
var menuElement = module.exports.menus["serversel"].elements[e];
|
|
|
|
if (("classes" in menuElement) && menuElement.classes.indexOf("mxworldjoinbtn") > -1) module.exports.menus["serversel"].elements.splice(e, 1);
|
|
}
|
|
|
|
var matrixWorldRooms = getWorldRooms();
|
|
|
|
for (var r = 0; r < matrixWorldRooms.length; r++) {
|
|
var matrixWorldRoom = matrixWorldRooms[r];
|
|
|
|
var menuEntry = {
|
|
"type": "button",
|
|
"label": global.locales.getFormattedString(
|
|
global.currentLanguage,
|
|
"play.singleplayer.openworld.label",
|
|
{
|
|
"WORLD_NAME": matrixWorldRoom.name
|
|
}
|
|
),
|
|
"action": "run",
|
|
"runnable": (function (event) {
|
|
syncWorldFromMatrixRoom(this).then((function (world) {
|
|
global.worlds[this.name] = world;
|
|
global.startGame(0, this.name);
|
|
}).bind(this)).catch(global.throwError);
|
|
|
|
global.menu.hideMenus(0);
|
|
}).bind(matrixWorldRoom),
|
|
"classes": [
|
|
"mxworldjoinbtn"
|
|
]
|
|
};
|
|
|
|
module.exports.menus["serversel"].elements.push(menuEntry);
|
|
}
|
|
|
|
global.menu.hideMenus(2);
|
|
|
|
global.menu.menus["serversel"] = global.menu.constructMenu("serversel", module.exports.menus["serversel"]);
|
|
|
|
global.menu.showMenu("serversel", 2);
|
|
}
|
|
}
|
|
]
|
|
}
|
|
}
|
|
};
|