Skip to content

Instantly share code, notes, and snippets.

@chrahunt
Last active August 29, 2015 14:14
Show Gist options
  • Save chrahunt/4843f0258c516882eea0 to your computer and use it in GitHub Desktop.
Save chrahunt/4843f0258c516882eea0 to your computer and use it in GitHub Desktop.
// ==UserScript==
// @name Socket.io Loopback Interface
// @namespace http://www.reddit.com/user/snaps_/
// @description Adds a loopback capability to socketio sockets. Emitting a message with the event name prepended with "local:" will emit the message to the client-side socket listeners.
// @include http://tagpro-*.koalabeast.com:*
// @include http://tagpro-*.koalabeast.com/groups/*
// @include http://tangent.jukejuice.com:*
// @include http://tangent.jukejuice.com/groups/*
// @include http://maptest*.newcompte.fr:*
// @include http://maptest*.newcompte.fr/groups/*
// @require https://gist.github.com/chrahunt/4843f0258c516882eea0/raw/8d5f273ca484e3c480ec0fde70cdc5861344388a/loopback.user.js
// @run-at document-start
// @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @author snaps
// @version 0.1.0
// ==/UserScript==
// Example usage: Messaging the user information via chat.
// Wait for conditions that indicate chats are able to be received in-game or on group page.
var waitForChat = function(fn) {
if (typeof tagpro !== 'undefined' && (typeof tagpro.playerId == 'number' || tagpro.group.socket)) {
// On group page.
if (tagpro.group.socket && tagpro.group.socket.playerLocation == "page") {
fn();
} else { // In game.
tagpro.ready(function() {
// Additional delay is for compatibility with chat enhancer userscript; if not using chat enhancer, then
// calling fn here immediately would work.
setTimeout(fn, 1000);
});
}
} else {
setTimeout(function() {
waitForChat(fn);
}, 0);
}
}
waitForChat(function() {
if (io && io.__loopback) {
console.log("Loopback loaded.");
// In-game chat messages.
if (tagpro.socket) {
// System message.
tagpro.socket.emit("local:chat", {
to: "all",
from: null,
message: "Wow, you installed a userscript!"
});
// Add information so id can be used in 'from' field.
tagpro.players[999] = {
name: "Example Userscript",
auth: true, // Shows green check next to name.
team: tagpro.players[tagpro.playerId].team // Same team as player, team impacts name color in chat and text color when 'from' field is 'team'.
};
// Public chat.
tagpro.socket.emit("local:chat", {
to: "all",
from: 999,
message: "Great job!!"
});
// Team chat (team id must match in added player above).
tagpro.socket.emit("local:chat", {
to: "team",
from: 999,
message: "No really, just stellar!"
});
}
// Group chat messages.
if (tagpro.group.socket) {
// Notice the different 'to' field and 'from' takes a string directly. You can use a string with the game
// chat too, but then you wouldn't be able to get a green check or the team text color.
tagpro.group.socket.emit("local:chat", {
to: "group",
from: "Example Userscript.",
message: "Example group chat!"
});
// Use 'null' in the 'from' field for a system message.
tagpro.group.socket.emit("local:chat", {
to: "group",
from: null,
message: "Example system group chat!"
});
}
} else {
console.log("Loopback not loaded.");
}
});
// ==UserScript==
// @name Socket.io Loopback Interface
// @namespace http://www.reddit.com/user/snaps_/
// @description Adds a loopback capability to socketio sockets. Emitting a message with the event name prepended with "local:" will emit the message to the client-side socket listeners.
// @include http://tagpro-*.koalabeast.com:*
// @include http://tagpro-*.koalabeast.com/groups/*
// @include http://tangent.jukejuice.com:*
// @include http://tangent.jukejuice.com/groups/*
// @include http://maptest*.newcompte.fr:*
// @include http://maptest*.newcompte.fr/groups/*
// @run-at document-start
// @license GPL version 3 or any later version; http://www.gnu.org/copyleft/gpl.html
// @author snaps
// @version 0.1.0
// ==/UserScript==
// Start Socket.io override.
// Wait until socket.io is loaded before executing function.
var runOnSocketIo = function(fn) {
if (typeof io !== 'undefined') {
fn();
} else {
setTimeout(function() {
runOnSocketIo(fn);
}, 0);
}
}
// Check that Socket.io is defined.
runOnSocketIo(function() {
var stdConnect = io.connect;
var stdEmit = io.Socket.prototype.emit;
var newEmit = function() {
if (arguments.length > 0) {
var evtName = arguments[0];
var local = /local:(\w+)/.exec(evtName);
if (local) {
// Reassign event name to parsed name.
arguments[0] = local[1];
// Send back to socket listeners.
this.onevent({data: arguments});
} else {
return stdEmit.apply(this, arguments);
}
} else {
return stdEmit.apply(this, arguments);
}
}
// Override connect function, this handles the unexposed in-game socket and the exposed,
// but late connecting, in-game group socket.
io.connect = function() {
var socket = stdConnect.apply(null, arguments);
socket.emit = newEmit;
return socket;
}
// This handles the exposed, but very quickly connecting, group page socket.
if (typeof tagpro !== 'undefined' && tagpro.group && tagpro.group.socket) {
tagpro.group.socket.__proto__.emit = newEmit;
}
io.__loopback = true;
});
// End Socket.io override.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment