#5 Implement replay URLs

This commit is contained in:
Andrio Celos 2022-12-26 14:36:04 +11:00
parent 42956e9e9e
commit 0cdfc3bbbd
4 changed files with 28 additions and 14 deletions

View File

@ -608,9 +608,7 @@ shareReplayLinkButton.addEventListener('click', _ => {
req.addEventListener('load', _ => {
if (req.status == 200) {
const array = new Uint8Array(req.response as ArrayBuffer);
let base64 = Base64.base64EncArr(array);
base64 = base64.replaceAll('+', '-');
base64 = base64.replaceAll('/', '_');
const base64 = encodeToUrlSafeBase64(array);
const url = new URL(`${canPushState ? '' : '#'}replay/${base64}`, baseUrl);
shareReplayLinkButton.disabled = false;
if (canShareReplay) {

View File

@ -163,9 +163,6 @@ preGameDeckEditorButton.addEventListener('click', e => {
preGameReplayButton.addEventListener('click', e => {
e.preventDefault();
if (stageDatabase.stages == null)
throw new Error('Game data not loaded');
const s = prompt('Enter a replay link or code.');
if (!s) return;
const m = /(?:^|replay\/)([A-Za-z0-9+/=\-_]+)$/i.exec(s);
@ -174,7 +171,13 @@ preGameReplayButton.addEventListener('click', e => {
return;
}
let base64 = m[1];
loadReplay(m[1]);
});
function loadReplay(base64: string) {
if (stageDatabase.stages == null)
throw new Error('Game data not loaded');
base64 = base64.replaceAll('-', '+');
base64 = base64.replaceAll('_', '/');
const bytes = Base64.base64DecToArr(base64);
@ -189,7 +192,7 @@ preGameReplayButton.addEventListener('click', e => {
let pos = 2;
const players = [ ];
currentReplay = { turns: [ ], drawOrder: [ ], initialDrawOrder: [ ] };
currentReplay = { turns: [ ], placements: [ ], drawOrder: [ ], initialDrawOrder: [ ] };
for (let i = 0; i < numPlayers; i++) {
const len = dataView.getUint8(pos + 34);
const player: Player = {
@ -254,8 +257,9 @@ preGameReplayButton.addEventListener('click', e => {
board.refresh();
loadPlayers(players);
setUrl(`replay/${encodeToUrlSafeBase64(bytes)}`)
initReplay();
});
}
let playerName = localStorage.getItem('name');
(document.getElementById('nameBox') as HTMLInputElement).value = playerName || '';

View File

@ -351,10 +351,13 @@ function processUrl() {
onInitialise(showDeckList);
else {
showPage('preGame');
const m = /^(.*)\/game\/([0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12})$/.exec(location.toString());
if (m)
presetGameID(m[2]);
else if (location.hash) {
const m = /[/#](?:(game)|replay)\/([A-Za-z0-9+/=\-_]+)$/.exec(location.toString());
if (m) {
if (m[1])
presetGameID(m[2]);
else
onInitialise(() => loadReplay(m[2]));
} else if (location.hash) {
canPushState = false;
presetGameID(location.hash);
} else {
@ -374,6 +377,13 @@ function presetGameID(url: string) {
});
}
function encodeToUrlSafeBase64(array: Uint8Array) {
let base64 = Base64.base64EncArr(array);
base64 = base64.replaceAll('+', '-');
base64 = base64.replaceAll('/', '_');
return base64;
}
function isInternetExplorer() {
return !!(window.document as any).documentMode; // This is a non-standard property implemented only by Internet Explorer.
}

View File

@ -65,7 +65,9 @@ internal class Program {
private static void HttpServer_OnRequest(object? sender, HttpRequestEventArgs e) {
e.Response.AppendHeader("Access-Control-Allow-Origin", "*");
if (!e.Request.RawUrl.StartsWith("/api/")) {
var path = e.Request.RawUrl == "/" || e.Request.RawUrl.StartsWith("/game/") ? "index.html" : e.Request.RawUrl[1..];
var path = e.Request.RawUrl == "/" || e.Request.RawUrl.StartsWith("/game/") || e.Request.RawUrl.StartsWith("/replay/")
? "index.html"
: e.Request.RawUrl[1..];
if (e.TryReadFile(path, out var bytes))
SetResponse(e.Response, HttpStatusCode.OK,
Path.GetExtension(path) switch {