Skip to content

Instantly share code, notes, and snippets.

@seleb
Last active November 22, 2020 22:14
Show Gist options
  • Save seleb/19bae2ac7e73177e8623d9af96f4c180 to your computer and use it in GitHub Desktop.
Save seleb/19bae2ac7e73177e8623d9af96f4c180 to your computer and use it in GitHub Desktop.
simple client for zone usable from console as a bot
// avatar utils (mostly copied from blitsy)
function encodeM1(pixels) {
var pixels32 = new Uint32Array(pixels);
var data = new Uint8ClampedArray(Math.ceil(pixels32.length / 8));
for (var i = 0; i < data.length; ++i) {
var byte = 0;
for (var bit = 0; bit < 8; ++bit) {
byte <<= 1;
byte |= pixels32[i * 8 + (7 - bit)] > 0 ? 1 : 0;
}
data[i] = byte;
}
return data;
}
function uint8ToBase64(u8Arr) {
var CHUNK_SIZE = 0x8000; // arbitrary number
var index = 0;
var length = u8Arr.length;
var result = '';
while (index < length) {
var slice = u8Arr.subarray(index, Math.min(index + CHUNK_SIZE, length));
result += String.fromCharCode.apply(null, slice);
index += CHUNK_SIZE;
}
return btoa(result);
}
function stringToAvatar(string) {
return uint8ToBase64(
encodeM1(
string
.replace(/\s/g, '')
.split('')
.map(i => parseInt(i, 2))
)
);
}
function stringToAvatars(string) {
return string.trim().split(/\n\n+/).map(stringToAvatar);
}
// zonebot
class ZoneBot {
constructor() {
this.connect();
this.intervalAvatar = undefined;
this._name = '';
}
connect() {
// socket setup
this.socket = new WebSocket(`${window.location.origin.replace('http', 'ws')}/zone`);
this.connectionPromise = new Promise((resolve, reject) => {
this.socket.onopen = resolve;
this.socket.onerror = reject;
});
this.socket.onmessage = event => {
const data = JSON.parse(event.data);
if (data.type === 'heartbeat') {
this.send({ type: 'heartbeat' });
return;
}
if (this.onmessage) {
this.onmessage(data);
}
};
}
async send(data) {
await this.connectionPromise;
this.socket.send(JSON.stringify(data));
}
// api
join(name) {
this._name = name;
this.send({ type: 'join', name });
}
disconnect() {
if (this.socket) {
this.stopCycle();
this.socket.close();
this.socket = undefined;
}
}
say(text) {
this.send({ type: 'chat', text });
}
name(name) {
this._name = name;
this.send({ type: 'user', name });
}
move(x, y) {
this.send({ type: 'user', position: [x, 0, y] });
}
emotes(emotes) {
this.send({ type: 'user', emotes });
}
_avatar(avatar) {
this.send({ type: 'user', avatar });
}
avatar(avatar) {
this._avatar(stringToAvatar(avatar));
}
cycleAvatars(avatars, interval) {
const frames = stringToAvatars(avatars);
this.stopCycle();
let frame = 0;
this.intervalAvatar = setInterval(() => {
++frame;
frame %= frames.length;
this._avatar(frames[frame]);
}, interval || 400);
}
stopCycle() {
clearInterval(this.intervalAvatar);
this.intervalAvatar = undefined;
}
}
// demo
(function () {
const bot = new ZoneBot();
bot.join('zonebot');
bot.move(Math.random() * 16, Math.random() * 16);
bot.cycleAvatars(`
00011000
00001001
00111110
00011000
11111000
00011000
00001000
00001000
00011000
00001000
00011000
00111000
00111000
00011110
00010000
00010000
`);
bot.emotes(['wvy', 'spn']);
bot.say('jumping is not a crime');
// simple chat response
bot.onmessage = data => {
if (data.type === 'chat') {
if (data.text.includes(bot._name)) {
bot.say('THE ZONE');
}
}
};
return bot;
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment