969 lines
32 KiB
JavaScript
969 lines
32 KiB
JavaScript
#include channel.js
|
|
#include channels.js
|
|
#include common.js
|
|
#include message.js
|
|
#include messages.js
|
|
#include mszauth.js
|
|
#include user.js
|
|
#include users.js
|
|
#include parsing.js
|
|
#include servers.js
|
|
#include settings.js
|
|
#include txtrigs.js
|
|
#include websock.js
|
|
#include ui/emotes.js
|
|
#include ui/markup.js
|
|
#include ui/menus.js
|
|
#include ui/messages.jsx
|
|
#include ui/view.js
|
|
#include ui/loading-overlay.jsx
|
|
#include sound/umisound.js
|
|
|
|
if(!Umi) window.Umi = {};
|
|
if(!Umi.Protocol) Umi.Protocol = {};
|
|
if(!Umi.Protocol.SockChat) Umi.Protocol.SockChat = {};
|
|
if(!Umi.Protocol.SockChat.Protocol) Umi.Protocol.SockChat.Protocol = {};
|
|
|
|
Umi.Protocol.SockChat.Protocol = function(views) {
|
|
const pub = {};
|
|
Umi.Protocol.SockChat.Protocol.Instance = pub;
|
|
|
|
const chatBot = new Umi.User('-1', 'Server');
|
|
|
|
let noReconnect = false,
|
|
connectAttempts = 0,
|
|
wasKicked = false,
|
|
isRestarting = false;
|
|
|
|
let userId = null,
|
|
channelName = null,
|
|
pmUserName = null;
|
|
|
|
let sock = null;
|
|
|
|
const send = function(opcode, data) {
|
|
if(!sock) return;
|
|
let msg = opcode;
|
|
if(data) msg += "\t" + data.join("\t");
|
|
console.log(msg);
|
|
sock.send(msg);
|
|
};
|
|
const sendPing = function() {
|
|
if(userId === null)
|
|
return;
|
|
lastPing = Date.now();
|
|
send('0', [userId]);
|
|
};
|
|
const sendAuth = function(args) {
|
|
if(userId !== null)
|
|
return;
|
|
send('1', args);
|
|
};
|
|
const sendMessage = function(text) {
|
|
if(userId === null)
|
|
return;
|
|
|
|
if(text.substring(0, 1) !== '/' && pmUserName !== null)
|
|
text = '/msg ' + pmUserName + ' ' + text;
|
|
|
|
send('2', [userId, text]);
|
|
};
|
|
|
|
const switchChannel = function(name) {
|
|
if(channelName === name)
|
|
return;
|
|
|
|
channelName = name;
|
|
sendMessage('/join ' + name);
|
|
};
|
|
|
|
const startKeepAlive = function() {
|
|
if(!sock) return;
|
|
sock.sendInterval("0\t" + userId, futami.get('ping') * 1000);
|
|
};
|
|
const stopKeepAlive = function() {
|
|
if(!sock) return;
|
|
sock.clearIntervals();
|
|
};
|
|
|
|
const getLoadingOverlay = async (icon, header, message) => {
|
|
const currentView = views.current();
|
|
|
|
if('setIcon' in currentView) {
|
|
currentView.setIcon(icon);
|
|
currentView.setHeader(header);
|
|
currentView.setMessage(message);
|
|
return currentView;
|
|
}
|
|
|
|
const loading = new Umi.UI.LoadingOverlay(icon, header, message);
|
|
await views.push(loading);
|
|
|
|
return loading;
|
|
};
|
|
|
|
const playBannedSfx = function() {
|
|
if(!mami.hasSound())
|
|
return;
|
|
|
|
const urls = {
|
|
mp3: '//static.flash.moe/sounds/touhou-death.mp3',
|
|
ogg: '//static.flash.moe/sounds/touhou-death.ogg'
|
|
};
|
|
|
|
mami.getSound().load('banSFX', urls, function(success, buffer) {
|
|
if(!success) {
|
|
console.log('Failed to load kick/ban SFX: ' + buffer);
|
|
return;
|
|
}
|
|
|
|
buffer.createSource().play();
|
|
});
|
|
};
|
|
const playBannedBgm = function(preload) {
|
|
if(!mami.hasSound())
|
|
return;
|
|
|
|
const urls = {
|
|
opus: '//static.flash.moe/sounds/players-score.opus',
|
|
caf: '//static.flash.moe/sounds/players-score.caf'
|
|
};
|
|
|
|
mami.getSound().load('banBGM', urls, function(success, buffer) {
|
|
if(!success) {
|
|
console.log('Failed to load kick/ban SFX: ' + buffer);
|
|
return;
|
|
}
|
|
|
|
if(!preload) {
|
|
const source = buffer.createSource();
|
|
source.setLoopStart(10.512);
|
|
source.setLoopEnd(38.074);
|
|
source.setLoop();
|
|
source.play();
|
|
}
|
|
});
|
|
};
|
|
|
|
const onOpen = function(ev) {
|
|
if(Umi.Settings.get('dumpPackets'))
|
|
console.log(ev);
|
|
|
|
wasKicked = false;
|
|
isRestarting = false;
|
|
|
|
getLoadingOverlay('spinner', 'Loading...', 'Authenticating...');
|
|
|
|
const authInfo = MamiMisuzuAuth.getInfo();
|
|
sendAuth([authInfo.method, authInfo.token]);
|
|
};
|
|
|
|
const closeReasons = {
|
|
'_1000': 'The connection has been ended.',
|
|
'_1001': 'Something went wrong on the server side.',
|
|
'_1002': 'Your client sent broken data to the server.',
|
|
'_1003': 'Your client sent data to the server that it doesn\'t understand.',
|
|
'_1005': 'No additional information was provided.',
|
|
'_1006': 'You lost connection unexpectedly!',
|
|
'_1007': 'Your client sent broken data to the server.',
|
|
'_1008': 'Your client did something the server did not agree with.',
|
|
'_1009': 'Your client sent too much data to the server at once.',
|
|
'_1011': 'Something went wrong on the server side.',
|
|
'_1012': 'The server is restarting, reconnecting soon...',
|
|
'_1013': 'You cannot connect to the server right now, try again later.',
|
|
'_1015': 'Your client and the server could not establish a secure connection.',
|
|
};
|
|
|
|
const onClose = function(ev) {
|
|
if(Umi.Settings.get('dumpPackets'))
|
|
console.log(ev);
|
|
|
|
userId = null;
|
|
channelName = null;
|
|
pmUserName = null;
|
|
stopKeepAlive();
|
|
|
|
if(wasKicked)
|
|
return;
|
|
|
|
let code = ev.code;
|
|
if(isRestarting && code === 1006) {
|
|
code = 1012;
|
|
} else if(code === 1012)
|
|
isRestarting = true;
|
|
|
|
const msg = closeReasons['_' + code.toString()]
|
|
|| ('Something caused an unexpected connection loss, the error code was: ' + ev.code.toString() + '.');
|
|
|
|
getLoadingOverlay('unlink', 'Disconnected!', msg);
|
|
|
|
//Umi.Messages.Clear();
|
|
Umi.Users.Clear();
|
|
|
|
connectAttempts = 0;
|
|
|
|
setTimeout(function() {
|
|
beginConnecting();
|
|
}, 5000);
|
|
};
|
|
|
|
const parseBotMessage = function(parts) {
|
|
let text = '';
|
|
|
|
switch(parts[1]) {
|
|
case 'silence':
|
|
text = 'You have been silenced!';
|
|
break;
|
|
|
|
case 'unsil':
|
|
text = 'You are no longer silenced!';
|
|
break;
|
|
|
|
case 'silok':
|
|
text = '{0} is now silenced.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'usilok':
|
|
text = '{0} is no longer silenced.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'flood':
|
|
text = '{0} got kicked for flood protection.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'flwarn':
|
|
text = 'You are about to hit the flood limit! If you continue you will be kicked.';
|
|
break;
|
|
|
|
case 'unban':
|
|
text = '{0} is no longer banned.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'banlist':
|
|
const blentries = parts[2].split(', ');
|
|
for(const i in blentries)
|
|
blentries[i] = blentries[i].slice(92, -4);
|
|
|
|
text = 'Banned: {0}'.replace('{0}', blentries.join(', '));
|
|
break;
|
|
|
|
case 'who':
|
|
const wentries = parts[2].split(', ');
|
|
for(const i in wentries) {
|
|
const isSelf = wentries[i].includes(' style="font-weight: bold;"');
|
|
wentries[i] = wentries[i].slice(isSelf ? 102 : 75, -4);
|
|
if(isSelf) wentries[i] += ' (You)';
|
|
}
|
|
|
|
text = 'Online: {0}'.replace('{0}', wentries.join(', '));
|
|
break;
|
|
|
|
case 'whochan':
|
|
const wcentries = (parts[3] || '').split(', ');
|
|
for(const i in wcentries) {
|
|
const isSelf = wcentries[i].includes(' style="font-weight: bold;"');
|
|
wcentries[i] = wcentries[i].slice(isSelf ? 102 : 75, -4);
|
|
if(isSelf) wcentries[i] += ' (You)';
|
|
}
|
|
|
|
text = 'Online in {0}: {1}'.replace('{0}', parts[2]).replace('{1}', wcentries.join(', '));
|
|
break;
|
|
|
|
case 'silerr':
|
|
text = 'This user has already been silenced!';
|
|
break;
|
|
|
|
case 'usilerr':
|
|
text = "This user isn't silenced!";
|
|
break;
|
|
|
|
case 'silperr':
|
|
text = "You aren't allowed to silence this user!";
|
|
break;
|
|
|
|
case 'usilperr':
|
|
text = "You aren't allowed to remove the silence on this user!";
|
|
break;
|
|
|
|
case 'silself':
|
|
text = 'Why would you even try to silence yourself?';
|
|
break;
|
|
|
|
case 'delerr':
|
|
text = "You aren't allowed to delete this message!";
|
|
break;
|
|
|
|
case 'notban':
|
|
text = "{0} isn't banned!".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'whoerr':
|
|
text = '{0} does not exist!'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'join':
|
|
text = '{0} joined.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'jchan':
|
|
text = '{0} joined the channel.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'leave':
|
|
text = '{0} left.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'timeout':
|
|
text = '{0} exploded.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'lchan':
|
|
text = '{0} left the channel.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'kick':
|
|
text = '{0} got kicked.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'nick':
|
|
text = '{0} changed their name to {1}.'.replace('{0}', parts[2]).replace('{1}', parts[3]);
|
|
break;
|
|
|
|
case 'crchan':
|
|
text = '{0} has been created.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'delchan':
|
|
text = '{0} has been deleted.'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'cpwdchan':
|
|
text = 'Changed the channel password!';
|
|
break;
|
|
|
|
case 'cprivchan':
|
|
text = 'Change access level of the channel!';
|
|
break;
|
|
|
|
case 'ipaddr':
|
|
text = 'IP of {0}: {1}'.replace('{0}', parts[2]).replace('{1}', parts[3]);
|
|
break;
|
|
|
|
case 'cmdna':
|
|
text = "You aren't allowed to use '{0}'.".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'nocmd':
|
|
text = "The command '{0}' does not exist.".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'cmderr':
|
|
text = "You didn't format the command correctly!";
|
|
break;
|
|
|
|
case 'usernf':
|
|
text = "{0} isn't logged in to the chat right now!".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'kickna':
|
|
text = "You aren't allowed to kick {0}!".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'samechan':
|
|
text = 'You are already in {0}!'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'ipchan':
|
|
case 'nochan':
|
|
text = "{0} doesn't exist!".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'nopwchan':
|
|
text = "{0} has a password! Use '/join {0} [password]'.".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'ipwchan':
|
|
text = "Wrong password! Couldn't join {0}.".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'inchan':
|
|
text = "Channel names can't start with @ or *!";
|
|
break;
|
|
|
|
case 'nischan':
|
|
text = '{0} already exists!'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'ndchan':
|
|
text = "You aren't allowed to delete {0}!".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'namchan':
|
|
text = "You aren't allowed to edit {0}!".replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'nameinuse':
|
|
text = '{0} is currently taken!'.replace('{0}', parts[2]);
|
|
break;
|
|
|
|
case 'rankerr':
|
|
text = "You can't set the access level of a channel higher than your own!";
|
|
break;
|
|
|
|
case 'reconnect':
|
|
text = 'Connection lost! Attempting to reconnect...';
|
|
break;
|
|
|
|
case 'generr':
|
|
text = 'Something happened.';
|
|
break;
|
|
|
|
case 'say':
|
|
default:
|
|
text = parts[2];
|
|
}
|
|
|
|
return text;
|
|
};
|
|
|
|
const unfuckText = function(text) {
|
|
const elem = document.createElement('div');
|
|
elem.innerHTML = text.replace(/ <br\/> /g, "\n");
|
|
text = elem.innerText;
|
|
return text;
|
|
};
|
|
|
|
const onMessage = function(ev) {
|
|
const data = ev.data.split("\t");
|
|
|
|
if(Umi.Settings.get('dumpPackets'))
|
|
console.log(data);
|
|
|
|
switch(data[0]) {
|
|
case '0': // ping
|
|
// nothing to do
|
|
break;
|
|
|
|
case '1': // join
|
|
if(userId === null) {
|
|
if(data[1] == 'y') {
|
|
userId = data[2];
|
|
channelName = data[6];
|
|
|
|
views.pop(ctx => MamiAnimate({
|
|
async: true,
|
|
duration: 120,
|
|
easing: 'easeInOutSine',
|
|
start: () => {
|
|
ctx.toElem.style.zIndex = '100';
|
|
ctx.fromElem.style.pointerEvents = 'none';
|
|
ctx.fromElem.style.zIndex = '200';
|
|
},
|
|
update: t => {
|
|
ctx.fromElem.style.transform = `scale(${1 + (.25 * t)})`;
|
|
ctx.fromElem.style.opacity = 1 - (1 * t).toString();
|
|
},
|
|
end: () => {
|
|
ctx.toElem.style.zIndex = null;
|
|
},
|
|
}));
|
|
|
|
startKeepAlive();
|
|
|
|
if(Umi.Settings.get('playSoundOnConnect'))
|
|
Umi.Sound.Play('join');
|
|
} else {
|
|
switch (data[2]) {
|
|
case 'joinfail':
|
|
wasKicked = true;
|
|
|
|
const jfuntil = new Date(parseInt(data[3]) * 1000);
|
|
let banmsg = 'You were banned until {0}!'.replace('{0}', jfuntil.toLocaleString());
|
|
|
|
if(data[3] === '-1')
|
|
banmsg = 'You have been banned till the end of time, please try again in a different dimension.';
|
|
|
|
getLoadingOverlay('hammer', 'Banned!', banmsg);
|
|
playBannedBgm();
|
|
break;
|
|
|
|
case 'authfail':
|
|
let message = 'Authentication failed!';
|
|
const afredir = futami.get('login');
|
|
|
|
if(afredir) {
|
|
message = 'Authentication failed, redirecting to login page...';
|
|
setTimeout(function() {
|
|
location.assign(afredir);
|
|
}, 2000);
|
|
}
|
|
|
|
getLoadingOverlay('cross', 'Failed!', message);
|
|
break;
|
|
|
|
case 'sockfail':
|
|
getLoadingOverlay('cross', 'Failed!', 'Too many active connections.');
|
|
break;
|
|
|
|
default:
|
|
getLoadingOverlay('cross', 'Failed!', 'Connection failed!');
|
|
break;
|
|
}
|
|
break;
|
|
}
|
|
}
|
|
|
|
const juser = new Umi.User(data[2], data[3], data[4], data[5]);
|
|
|
|
if(userId === juser.getId())
|
|
Umi.User.setCurrentUser(juser);
|
|
|
|
Umi.Users.Add(juser);
|
|
|
|
if(Umi.User.isCurrentUser(juser)) {
|
|
Umi.UI.Markup.Reset();
|
|
Umi.UI.Emoticons.Init();
|
|
Umi.Parsing.Init();
|
|
break;
|
|
}
|
|
|
|
Umi.Messages.Add(new Umi.Message(
|
|
data[6],
|
|
data[1],
|
|
chatBot,
|
|
'{0} joined.'.replace('{0}', juser.getName()),
|
|
channelName,
|
|
false,
|
|
{
|
|
type: 'join',
|
|
isError: false,
|
|
args: [juser.getName()],
|
|
target: juser,
|
|
}
|
|
));
|
|
Umi.Sound.Play('join');
|
|
break;
|
|
|
|
case '2': // message
|
|
let text = data[3],
|
|
sound = 'incoming';
|
|
const muser = Umi.Users.Get(data[2]) || chatBot,
|
|
textParts = text.split("\f");
|
|
isPM = data[5][4] === '1',
|
|
isAction = data[5][1] === '1' && data[5][3] === '0',
|
|
isBot = data[2] === '-1',
|
|
pmChannel = '@' + muser.getName(),
|
|
botInfo = {};
|
|
|
|
text = unfuckText(text);
|
|
|
|
if(isBot) {
|
|
sound = 'server';
|
|
botInfo.isError = textParts[0] !== '0';
|
|
botInfo.type = textParts[1];
|
|
botInfo.args = textParts.slice(2);
|
|
text = parseBotMessage(textParts);
|
|
|
|
if(botInfo.isError)
|
|
sound = 'error';
|
|
else if(textParts[1] === 'unban')
|
|
sound = 'unban';
|
|
}
|
|
|
|
if(isPM) {
|
|
if(muser.getId() === userId) {
|
|
const tmpMsg = text.split(' ');
|
|
pmChannel = '@' + tmpMsg.shift();
|
|
text = tmpMsg.join(' ');
|
|
}
|
|
|
|
if(muser.getName() !== pmUserName)
|
|
sound = 'private';
|
|
|
|
if(Umi.Channels.Get(pmChannel) === null)
|
|
Umi.Channels.Add(new Umi.Channel(pmChannel, false, true, true));
|
|
|
|
Umi.UI.Menus.Attention('channels');
|
|
}
|
|
|
|
if(muser.getId() === userId)
|
|
sound = 'outgoing';
|
|
|
|
if(Umi.Settings.get('playJokeSounds'))
|
|
try {
|
|
const trigger = mami.getTextTriggers().getTrigger(text);
|
|
if(trigger.isSoundType()) {
|
|
sound = '';
|
|
mami.playLibrarySound(
|
|
trigger.getRandomSoundName(),
|
|
null,
|
|
trigger.getVolume(),
|
|
trigger.getRate()
|
|
);
|
|
}
|
|
} catch(ex) {}
|
|
|
|
Umi.Messages.Add(new Umi.Message(
|
|
data[4],
|
|
data[1],
|
|
muser,
|
|
text,
|
|
isPM ? pmChannel : (data[6] || channelName),
|
|
false,
|
|
botInfo,
|
|
isAction
|
|
));
|
|
|
|
if(!Umi.Settings.get('onlySoundOnMention') && sound !== '')
|
|
Umi.Sound.Play(sound);
|
|
break;
|
|
|
|
case '3': // leave
|
|
const luser = Umi.Users.Get(data[1]);
|
|
let ltext = '',
|
|
lsound = null;
|
|
|
|
switch(data[3]) {
|
|
case 'flood':
|
|
ltext = '{0} got kicked for flood protection.';
|
|
lsound = 'flood';
|
|
break;
|
|
|
|
case 'timeout':
|
|
ltext = '{0} exploded.';
|
|
lsound = 'timeout';
|
|
break;
|
|
|
|
case 'kick':
|
|
ltext = '{0} got bludgeoned to death.';
|
|
lsound = 'kick';
|
|
break;
|
|
|
|
case 'leave':
|
|
default:
|
|
ltext = '{0} left.';
|
|
lsound = 'leave';
|
|
break;
|
|
}
|
|
|
|
Umi.Messages.Add(new Umi.Message(
|
|
data[5],
|
|
data[4],
|
|
chatBot,
|
|
ltext.replace('{0}', luser.getName()),
|
|
channelName,
|
|
false,
|
|
{
|
|
type: data[3],
|
|
isError: false,
|
|
args: [luser.getName()],
|
|
target: luser,
|
|
}
|
|
));
|
|
Umi.Users.Remove(luser);
|
|
|
|
if(lsound !== null)
|
|
Umi.Sound.Play(lsound);
|
|
break;
|
|
|
|
case '4': // channel
|
|
switch(data[1]) {
|
|
case '0':
|
|
Umi.Channels.Add(new Umi.Channel(data[2], data[3] === '1', data[4] === '1'));
|
|
break;
|
|
|
|
case '1':
|
|
const uchannel = Umi.Channels.Get(data[2]);
|
|
uchannel.setName(data[3]);
|
|
uchannel.setHasPassword(data[4] === '1');
|
|
uchannel.setTemporary(data[5] === '1');
|
|
Umi.Channels.Update(data[2], uchannel);
|
|
break;
|
|
|
|
case '2':
|
|
Umi.Channels.Remove(Umi.Channels.Get(data[2]));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case '5': // user move
|
|
switch(data[1]) {
|
|
case '0':
|
|
const umuser = new Umi.User(data[2], data[3], data[4], data[5]),
|
|
text = '{0} joined the channel.';
|
|
|
|
Umi.Users.Add(umuser);
|
|
Umi.Messages.Add(new Umi.Message(
|
|
data[6],
|
|
null,
|
|
chatBot,
|
|
text.replace('{0}', umuser.getName()),
|
|
channelName,
|
|
false,
|
|
{
|
|
type: 'jchan',
|
|
isError: false,
|
|
args: [
|
|
umuser.getName()
|
|
],
|
|
target: umuser,
|
|
}
|
|
));
|
|
Umi.Sound.Play('join');
|
|
break;
|
|
|
|
case '1':
|
|
if(data[2] === userId)
|
|
return;
|
|
|
|
const mouser = Umi.Users.Get(+data[2]),
|
|
motext = '{0} has left the channel.';
|
|
|
|
Umi.Messages.Add(new Umi.Message(
|
|
data[3],
|
|
null,
|
|
chatBot,
|
|
motext.replace('{0}', mouser.getName()),
|
|
channelName,
|
|
false,
|
|
{
|
|
type: 'lchan',
|
|
isError: false,
|
|
args: [
|
|
mouser.getName()
|
|
],
|
|
target: mouser,
|
|
}
|
|
));
|
|
Umi.Sound.Play('leave');
|
|
Umi.Users.Remove(mouser);
|
|
break;
|
|
|
|
case '2':
|
|
Umi.Channels.Switch(Umi.Channels.Get(data[2]));
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case '6': // message delete
|
|
Umi.Messages.Remove(Umi.Messages.Get(data[1]));
|
|
break;
|
|
|
|
case '7': // context populate
|
|
switch(data[1]) {
|
|
case '0': // users
|
|
const cpuamount = parseInt(data[2]);
|
|
let cpustart = 3;
|
|
|
|
for(let i = 0; i < cpuamount; i++) {
|
|
const user = new Umi.User(data[cpustart], data[cpustart + 1], data[cpustart + 2], data[cpustart + 3]);
|
|
Umi.Users.Add(user);
|
|
cpustart += 5;
|
|
}
|
|
break;
|
|
|
|
case '1': // message
|
|
let cmid = +data[8],
|
|
cmtext = data[7],
|
|
cmflags = data[10];
|
|
const cmuser = new Umi.User(data[3], data[4], data[5], data[6]),
|
|
cmtextParts = cmtext.split("\f"),
|
|
cmbotInfo = {};
|
|
|
|
cmtext = unfuckText(cmtext);
|
|
|
|
if(isNaN(cmid))
|
|
cmid = -Math.ceil(Math.random() * 10000000000);
|
|
|
|
if(cmtextParts[1]) {
|
|
cmbotInfo.isError = cmtextParts[0] !== '0';
|
|
cmbotInfo.type = cmtextParts[1];
|
|
cmbotInfo.args = cmtextParts.slice(2);
|
|
cmtext = parseBotMessage(cmtextParts);
|
|
}
|
|
|
|
Umi.Messages.Add(new Umi.Message(
|
|
cmid,
|
|
data[2],
|
|
cmuser,
|
|
cmtext,
|
|
channelName,
|
|
false,
|
|
cmbotInfo,
|
|
cmflags[1] === '1' && cmflags[3] === '0',
|
|
));
|
|
break;
|
|
|
|
case '2': // channels
|
|
const ecpamount = +data[2];
|
|
let ecpstart = 3;
|
|
|
|
for(let i = 0; i < ecpamount; i++) {
|
|
const channel = new Umi.Channel(
|
|
data[ecpstart],
|
|
data[ecpstart + 1] === '1',
|
|
data[ecpstart + 2] === '1'
|
|
);
|
|
Umi.Channels.Add(channel);
|
|
|
|
if(channel.getName() === channelName)
|
|
Umi.Channels.Switch(channel);
|
|
|
|
ecpstart = ecpstart + 3;
|
|
}
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case '8': // context clear
|
|
const cckeep = Umi.Users.Get(userId);
|
|
|
|
switch(data[1]) {
|
|
case '0':
|
|
Umi.UI.Messages.RemoveAll();
|
|
break;
|
|
|
|
case '1':
|
|
Umi.Users.Clear();
|
|
Umi.Users.Add(cckeep);
|
|
break;
|
|
|
|
case '2':
|
|
Umi.Channels.Clear();
|
|
break;
|
|
|
|
case '3':
|
|
Umi.Messages.Clear();
|
|
Umi.Users.Clear();
|
|
Umi.Users.Add(cckeep);
|
|
break;
|
|
|
|
case '4':
|
|
Umi.UI.Messages.RemoveAll();
|
|
Umi.Users.Clear();
|
|
Umi.Users.Add(cckeep);
|
|
Umi.Channels.Clear();
|
|
break;
|
|
}
|
|
break;
|
|
|
|
case '9': // baka
|
|
noReconnect = true;
|
|
wasKicked = true;
|
|
|
|
const isBan = data[1] === '1';
|
|
|
|
let message = 'You were kicked, refresh to log back in!';
|
|
if(isBan) {
|
|
if(data[2] === '-1') {
|
|
message = 'You have been banned till the end of time, please try again in a different dimension.';
|
|
} else {
|
|
const until = new Date(parseInt(data[2]) * 1000);
|
|
message = 'You were banned until {0}!'.replace('{0}', until.toLocaleString());
|
|
}
|
|
}
|
|
|
|
|
|
let icon, header;
|
|
if(isBan) {
|
|
icon = 'hammer';
|
|
header = 'Banned!';
|
|
} else {
|
|
icon = 'bomb';
|
|
header = 'Kicked!';
|
|
}
|
|
|
|
const currentView = views.currentElement();
|
|
|
|
MamiAnimate({
|
|
duration: 550,
|
|
easing: 'easeOutExpo',
|
|
start: function() {
|
|
playBannedBgm(true);
|
|
playBannedSfx();
|
|
},
|
|
update: function(t) {
|
|
const scale = 'scale(' + (1 - .5 * t).toString() + ', ' + (1 - 1 * t).toString() + ')';
|
|
currentView.style.transform = scale;
|
|
},
|
|
end: function() {
|
|
getLoadingOverlay(icon, header, message).then(() => {
|
|
playBannedBgm();
|
|
|
|
// there's currently no way to reconnect after a kick/ban so just dispose of the ui entirely
|
|
if(views.count() > 1)
|
|
views.shift();
|
|
});
|
|
},
|
|
});
|
|
break;
|
|
|
|
case '10': // user update
|
|
const spuser = Umi.Users.Get(+data[1]);
|
|
spuser.setName(data[2]);
|
|
spuser.setColour(data[3]);
|
|
spuser.setPermissions(data[4]);
|
|
Umi.Users.Update(spuser.getId(), spuser);
|
|
break;
|
|
}
|
|
};
|
|
|
|
const beginConnecting = function() {
|
|
if(noReconnect)
|
|
return;
|
|
|
|
++connectAttempts;
|
|
|
|
let str = 'Connecting to server...';
|
|
if(connectAttempts > 1)
|
|
str += ' (Attempt ' + connectAttempts.toString() + ')';
|
|
|
|
getLoadingOverlay('spinner', 'Loading...', str);
|
|
|
|
UmiServers.getServer(function(server) {
|
|
if(Umi.Settings.get('dumpPackets'))
|
|
console.log('Connecting to ' + server);
|
|
|
|
sock = new UmiWebSocket(server, function(ev) {
|
|
switch(ev.act) {
|
|
case 'ws:open':
|
|
onOpen(ev);
|
|
break;
|
|
case 'ws:close':
|
|
onClose(ev);
|
|
break;
|
|
case 'ws:message':
|
|
onMessage(ev);
|
|
break;
|
|
default:
|
|
console.log(ev.data);
|
|
break;
|
|
}
|
|
});
|
|
});
|
|
};
|
|
|
|
Umi.Channels.OnSwitch.push(function(old, channel) {
|
|
if(channel.isUserChannel()) {
|
|
pmUserName = channel.getName().substring(1);
|
|
} else {
|
|
pmUserName = null;
|
|
switchChannel(channel.getName());
|
|
}
|
|
});
|
|
|
|
pub.sendMessage = sendMessage;
|
|
|
|
pub.open = function() {
|
|
noReconnect = false;
|
|
beginConnecting();
|
|
};
|
|
|
|
pub.close = function() {
|
|
noReconnect = true;
|
|
sock.close();
|
|
};
|
|
|
|
return pub;
|
|
};
|