dzura/www/js/system.js
2024-09-28 20:35:49 -07:00

452 lines
13 KiB
JavaScript

function RECONNECT() {
if(SOCKET === null) {
console.log("Websocket connecting..");
SOCKET = new WebSocket("wss://" + location.hostname + ":38612");
SOCKET.binaryType = "arraybuffer";
SOCKET.addEventListener("error", () => {
SOCKET = null;
if(SCENE.disconnect !== undefined) { SCENE.disconnect(); }
});
SOCKET.addEventListener("open", (event) => {
if(SOCKET.readyState === WebSocket.OPEN) {
console.log("Websocket connected.");
SOCKET.addEventListener("message", MESSAGE);
SOCKET.addEventListener("close", () => {
console.log("Websocket closed.");
SOCKET = null;
if(SCENE.disconnect !== undefined) { SCENE.disconnect(); }
RECONNECT();
});
RESUME();
}
});
} else {
RESUME();
}
}
function RESUME() {
let b64_auth = sessionStorage.getItem("auth");
if(b64_auth !== null) {
let auth = UNPACK.base64(b64_auth);
let secret = UNPACK.base64(sessionStorage.getItem("auth_secret"));
MESSAGE_COMPOSE([
PACK.u16(OpCode.Resume),
auth,
secret,
]);
} else {
if(SCENE.reconnect !== undefined) { SCENE.reconnect(); }
}
}
function MESSAGE(event) {
let bytes = new Uint8Array(event.data);
let code = 0;
let index = 2;
let data = null;
let result = null;
if(bytes.length >= 2) {
code = (bytes[0] << 8) + bytes[1];
}
switch(code) {
case OpCode.Register: {
console.log("RECV Register");
if(bytes.length - index == 26) {
data = {
status:(bytes[2] << 8) + bytes[3],
token:new Uint8Array(8),
secret:new Uint8Array(16),
};
index += 2;
for(let i = 0; i < 8; ++i) {
data.token[i] = bytes[index++];
}
for(let i = 0; i < 16; ++i) {
data.secret[i] = bytes[index++];
}
} else {
console.error("Register packet bad length:" + bytes.length);
return;
}
} break;
case OpCode.Authenticate: {
console.log("RECV Authenticate");
if(bytes.length - index == 26) {
data = {
status:(bytes[2] << 8) + bytes[3],
token:new Uint8Array(8),
secret:new Uint8Array(16),
};
index += 2;
for(let i = 0; i < 8; ++i) {
data.token[i] = bytes[index++];
}
for(let i = 0; i < 16; ++i) {
data.secret[i] = bytes[index++];
}
} else {
console.error("Authenticate packet bad length:" + bytes.length);
return;
}
} break;
case OpCode.Resume: {
console.log("RECV Resume");
result = UNPACK.u16(bytes, index);
index = result.index;
if(result.data != Status.Ok) {
sessionStorage.clear();
}
LOAD_URL();
} break;
case OpCode.Deauthenticate: {
console.log("RECV Deauthenticate");
} break;
case OpCode.Status: {
console.log("RECV Status");
if(bytes.length - index == 4) {
// Challenge count
result = UNPACK.u16(bytes, index);
index = result.index;
STATUS.challenge = result.data;
// Resume count
result = UNPACK.u16(bytes, index);
index = result.index;
STATUS.resume = result.data;
BADGE_UPDATE(STATUS.challenge > 0 || STATUS.resume > 0);
UI.update_status();
}
} break;
case OpCode.SessionList: {
console.log("RECV Session list");
if(bytes.length - index >= 2) {
data = {
records: [],
};
result = UNPACK.u16(bytes, index);
index = result.index;
let count = result.data;
for(let i = 0; i < count; ++i) {
let record = {
token: new Uint8Array(8),
dawn: "",
dusk: "",
turn: 0,
move: "",
viewers: 0,
player: false,
is_turn: false,
};
// Token
if(index <= bytes.length + 8) {
for(let i = 0; i < 8; ++i) {
record.token[i] = bytes[index];
index += 1;
}
}
// Flags
result = UNPACK.u32(bytes, index);
index = result.index;
let flags = result.data;
record.player = flags & 3;
record.is_turn = ((flags >> 2) & 1) != 0;
// Dawn handle
result = UNPACK.string(bytes, index);
index = result.index;
record.dawn = result.data;
// Dusk handle
result = UNPACK.string(bytes, index);
index = result.index;
record.dusk = result.data;
// Turn number
result = UNPACK.u16(bytes, index);
index = result.index;
record.turn = result.data;
// Last move
if(index <= bytes.length + 3) {
let move = new Uint8Array(3);
for(let i = 0; i < 3; ++i) {
move[i] = bytes[index];
index += 1;
}
record.move = UNPACK.move(move);
}
// Reviewer count
result = UNPACK.u32(bytes, index);
index = result.index;
record.viewers = result.data;
data.records.push(record);
}
}
} break;
case OpCode.SessionView: {
console.log("RECV SessionCreate/Join");
if(bytes.length - index == 10) {
data = {
status:0,
token:new Uint8Array(8),
};
result = UNPACK.u16(bytes, index);
index = result.index;
data.status = result.data;
for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; }
}
} break;
case OpCode.GameState: {
console.log("RECV GameState");
data = {
status:0,
token:new Uint8Array(8),
player:2,
dawn:"",
dusk:"",
history:[ ],
};
// Status
result = UNPACK.u16(bytes, index);
index = result.index;
data.status = result.data;
// Token
for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; }
// Flags
result = UNPACK.u16(bytes, index);
index = result.index;
let flags = result.data;
data.player = flags & 0x3;
// Handles
result = UNPACK.string(bytes, index);
index = result.index;
data.dawn = result.data;
result = UNPACK.string(bytes, index);
index = result.index;
data.dusk = result.data;
// History
result = UNPACK.u16(bytes, index);
index = result.index;
let history_length = result.data;
for(let i = 0; i < history_length; ++i) {
result = UNPACK.u16(bytes, index);
index = result.index;
data.history.push(new GAME.Play(
result.data & 0xF,
(result.data >> 4) & 0x3F,
(result.data >> 10) & 0x3F,
));
}
} break;
case OpCode.GamePlay: {
console.log("RECV GamePlay");
data = {
status:0,
play:new GAME.Play(0, 0, 0),
};
// Status
result = UNPACK.u16(bytes, index);
index = result.index;
data.status = result.data;
// Turn
result = UNPACK.u16(bytes, index);
index = result.index;
data.turn = result.data;
// Play description
result = UNPACK.u16(bytes, index);
index = result.index;
data.play.source = result.data & 0xF;
data.play.from = (result.data >> 4) & 0x3F;
data.play.to = (result.data >> 10) & 0x3F;
} break;
case OpCode.ChallengeAnswer: {
console.log("RECV ChallengeAnswer");
data = {
status:0,
token:new Uint8Array(8),
};
// Status
result = UNPACK.u16(bytes, index);
index = result.index;
data.status = result.data;
for(let i = 0; i < 8; ++i) { data.token[i] = bytes[index++]; }
} break;
case OpCode.ChallengeList: {
console.log("RECV ChallengeList");
data = {
status:0,
challenges:[ ],
};
// Status
result = UNPACK.u16(bytes, index);
index = result.index;
data.status = result.data;
// Records
result = UNPACK.u16(bytes, index);
index = result.index;
let length = result.data;
for(let i = 0; i < length; ++i) {
let record = {
handle:"",
};
// Handle
result = UNPACK.string(bytes, index, UNPACK.u8);
index = result.index;
record.handle = result.data;
data.challenges.push(record);
}
} break;
case OpCode.UserList: {
console.log("RECV UserList");
data = {
status:0,
users:[ ],
};
// Status
result = UNPACK.u16(bytes, index);
index = result.index;
data.status = result.data;
// Records
result = UNPACK.u16(bytes, index);
index = result.index;
let length = result.data;
for(let i = 0; i < length; ++i) {
let record = {
handle:"",
};
// Handle
result = UNPACK.string(bytes, index, UNPACK.u8);
index = result.index;
record.handle = result.data;
data.users.push(record);
}
} break;
default:
console.log("RECV Undefined " + code);
return;
}
if(SCENE.message !== undefined) { SCENE.message(code, data) };
}
function MESSAGE_COMPOSE(data) {
if(SOCKET !== null) {
let length = 0;
for(let i = 0; i < data.length; ++i) {
length += data[i].length;
}
let raw = new Uint8Array(length);
length = 0;
for(let i = 0; i < data.length; ++i) {
raw.set(data[i], length);
length += data[i].length;
}
SOCKET.send(raw);
}
}
function MESSAGE_SESSION_LIST(page, game_state, is_player, is_live) {
let flags = 0;
flags |= game_state;
flags |= (+is_player) << 2;
flags |= (+is_live) << 3;
MESSAGE_COMPOSE([
PACK.u16(OpCode.SessionList),
PACK.u16(flags),
PACK.u16(page),
]);
}
function MESSAGE_SESSION_VIEW(token, player) {
MESSAGE_COMPOSE([
PACK.u16(OpCode.SessionView),
token,
PACK.u8(player),
]);
}
function MESSAGE_CHALLENGE(handle) {
MESSAGE_COMPOSE([
PACK.u16(OpCode.Challenge),
PACK.string(handle, PACK.u8),
]);
}
function MESSAGE_CHALLENGE_ANSWER(handle, answer) {
MESSAGE_COMPOSE([
PACK.u16(OpCode.ChallengeAnswer),
PACK.u8(+answer),
PACK.string(handle, PACK.u8),
]);
}