flash.moe/public/yahtzee/game.js
2020-08-20 00:02:37 +00:00

237 lines
6.8 KiB
JavaScript

var Yaht = function() {
if(Yaht.socket !== undefined)
return;
var loading = document.getElementById('loading');
loading.textContent += '.';
Yaht.socket = new WebSocket(Yaht.ENDPOINT, 'fwahtzee');
Yaht.socket.binaryType = 'arraybuffer';
Yaht.socket.onopen = Yaht.onOpen;
Yaht.socket.onclose = Yaht.onClose;
Yaht.socket.onerror = Yaht.onError;
Yaht.socket.onmessage = Yaht.onMessage;
};
Yaht.ENDPOINT = 'ws://127.0.0.1:30566';
Yaht.socket = undefined;
Yaht.pingInterval = undefined;
Yaht.OP_PING = 0x01;
Yaht.OP_ERROR = 0x02;
Yaht.OP_RANDOM = 0x03;
Yaht.OP_CHAT_MSG = 0x21;
Yaht.OP_CHAT_DEL = 0x22;
Yaht.onOpen = function(ev) {
console.log('[+] Connected!');
if(Yaht.pingInterval)
clearInterval(Yaht.pingInterval);
Yaht.pingInterval = setInterval(Yaht.sendPing, 4.9 * 60 * 1000);
Yaht.sendPing();
};
Yaht.onClose = function(ev) {
if(Yaht.pingInterval)
clearInterval(Yaht.pingInterval);
console.log('[-] Disconnected: %s %s %s', ev.code, ev.reason, ev.wasClean.toString());
};
Yaht.onError = function(ev) {
console.error('[!]', ev);
};
Yaht.onMessage = function(ev) {
if(!ev.data)
return;
var data = new Uint8Array(ev.data),
packet = Yaht.decodePacket(data);
if(packet !== null)
Yaht.handlePacket(packet);
};
Yaht.send = function(data) {
Yaht.socket.send(data);
};
Yaht.writeInt = function(arr, val, width, off) {
val = parseInt(val);
off += width - 1;
for(var i = 0; i < width; ++i)
arr[off - i] = val / Math.pow(2, 8 * i);
};
Yaht.writeI16 = function(arr, val, off) {
Yaht.writeInt(arr, val, 2, off);
};
Yaht.writeI32 = function(arr, val, off) {
Yaht.writeInt(arr, val, 4, off);
};
Yaht.writeI48 = function(arr, val, off) {
Yaht.writeInt(arr, val, 6, off);
};
Yaht.readInt = function(arr, width, off) {
var val = 0;
off += width;
for(var i = width; i > 0; --i)
val |= arr[off - i] * Math.pow(2, 8 * (i - 1));
return val;
};
Yaht.readI16 = function(arr, off) {
return Yaht.readInt(arr, 2, off);
};
Yaht.readI32 = function(arr, off) {
return Yaht.readInt(arr, 4, off);
};
Yaht.readI48 = function(arr, off) {
return Yaht.readInt(arr, 6, off);
};
Yaht.sendPing = function() {
var now = Date.now() / 1000,
pack = new Uint8Array(5);
pack[0] = Yaht.OP_PING;
Yaht.writeI32(pack, now, 1);
Yaht.send(pack);
};
Yaht.randomIdCounter = 0;
Yaht.randomCallbacks = {};
Yaht.randomValues = {};
Yaht.getNextRandomId = function() { return Yaht.randomIdCounter = (Yaht.randomIdCounter + 1) % 0x7F; };
Yaht.registerRandomCallback = function(identifier, callback) { Yaht.randomCallbacks['_' + identifier] = callback; };
Yaht.doRandomCallback = function(identifier, buffer) {
identifier = '_' + identifier.toString();
Yaht.randomValues[identifier] = buffer;
if(Yaht.randomCallbacks[identifier]) {
Yaht.randomCallbacks[identifier](buffer);
delete Yaht.randomCallbacks[identifier];
}
};
Yaht.getRandomValue = function(identifier) {
return Yaht.randomValues['_' + identifier] || [];
};
Yaht.requestRandom = function(count, callback) {
var pack = new Uint8Array(3);
pack[0] = Yaht.OP_RANDOM;
pack[1] = Yaht.getNextRandomId();
pack[2] = parseInt(count);
if(callback)
Yaht.registerRandomCallback(pack[1], callback);
Yaht.socket.send(pack);
return pack[1];
};
Yaht.toUTF16 = function(str) {
str = str || '';
var length = str.length,
buffer = new ArrayBuffer(length * 2),
u16arr = new Uint16Array(buffer);
for(var i = 0; i < length; ++i)
u16arr[i] = str.charCodeAt(i);
return new Uint8Array(buffer);
};
Yaht.fromUTF16 = function(arr, offset, length) {
offset = typeof offset === 'undefined' ? 0 : offset;
length = typeof length === 'undefined' ? (arr.length - offset) : length;
var str = '';
for(var i = 0; i < length; i = i + 2)
str += String.fromCharCode((arr[i + offset + 1] << 8) || arr[i + offset]);
return str;
};
Yaht.sendChatMessage = function(roomId, text) {
if(text.length < 1 || text.length > 500)
return false;
var textBytes = Yaht.toUTF16(text),
pack = new Uint8Array(9 + textBytes.length);
pack[0] = Yaht.OP_CHAT_MSG;
Yaht.writeI48(pack, roomId, 1);
Yaht.writeI16(pack, textBytes.length, 7);
for(var i = 0; i < textBytes.length; ++i)
pack[9 + i] = textBytes[i];
Yaht.socket.send(pack);
return true;
};
Yaht.consoleBeep = function(freq, dur, finish) {
var ctx = new AudioContext,
osc = ctx.createOscillator();
osc.type = 'sine';
osc.frequency.value = freq;
osc.connect(ctx.destination);
osc.start();
setTimeout(function() {
osc.stop();
if(finish)
finish();
}, dur);
};
Yaht.removeElement = function(elem) {
elem.parentNode.removeChild(elem);
};
Yaht.decodePacket = function(data) {
var packet = null;
switch(data[0]) {
default:
console.debug(data);
break;
case Yaht.OP_PING:
packet = {
type: 'pong',
took: Yaht.readI32(data, 1),
};
break;
case Yaht.OP_ERROR:
packet = {
type: 'error',
msg: Yaht.fromUTF16(data, 3, Yaht.readI16(data, 1)),
};
break;
case Yaht.OP_RANDOM:
packet = {
type: 'random',
identifier: data[1],
values: data.slice(3, data[2] + 3),
};
break;
case Yaht.OP_CHAT_MSG:
packet = {
type: 'chat:msg',
room: Yaht.readI48(data, 1),
user: Yaht.readI48(data, 7),
msg: Yaht.readI48(data, 13),
text: Yaht.fromUTF16(data, 21, Yaht.readI16(data, 19)),
};
break;
case Yaht.OP_CHAT_DEL:
packet = {
type: 'chat:del',
msg: Yaht.readI48(data, 1),
};
break;
}
return packet;
};
Yaht.handlePacket = function(packet) {
switch(packet.type || null) {
default:
console.debug('[>] ' + (packet.type || ''), packet);
break;
case 'pong':
console.log('[>] ping received, took %dms.', packet.took);
break;
case 'error':
console.error('[!]', packet.msg);
alert(packet.msg);
break;
case 'random':
Yaht.doRandomCallback(packet.identifier, packet.values);
break;
case 'chat:msg':
console.log('[&] %d #%d <%d> %s', packet.msg, packet.room, packet.user, packet.text);
break;
case 'chat:del':
console.log('[&] %d deleted.', packet.msg);
break;
}
};