Skip to content

Instantly share code, notes, and snippets.

@andronedev
Created April 2, 2026 17:46
Show Gist options
  • Select an option

  • Save andronedev/ebc745a8df9d28af8fa0fa4c40916746 to your computer and use it in GitHub Desktop.

Select an option

Save andronedev/ebc745a8df9d28af8fa0fa4c40916746 to your computer and use it in GitHub Desktop.
drifted king Region Switcher userscript
// ==UserScript==
// @name Drift King - Region Switcher
// @namespace drifted-bot
// @version 2.1
// @description Affiche et permet de changer la région, le serveur et la room
// @match https://www.drifted.com/*
// @grant none
// @run-at document-start
// ==/UserScript==
(function () {
'use strict';
const origWS = WebSocket;
const info = { region: null, room: null, master: null, game: null };
let forcedRegion = null;
const REGION_LIST = [
{ code: 'eu', name: 'Europe', flag: '🇪🇺' },
{ code: 'us', name: 'US East', flag: '🇺🇸' },
{ code: 'usw', name: 'US West', flag: '🇺🇸' },
{ code: 'ussc', name: 'US South', flag: '🇺🇸' },
{ code: 'cae', name: 'Canada', flag: '🇨🇦' },
{ code: 'sa', name: 'South America', flag: '🇧🇷' },
{ code: 'asia', name: 'Asia', flag: '🌏' },
{ code: 'jp', name: 'Japan', flag: '🇯🇵' },
{ code: 'kr', name: 'South Korea', flag: '🇰🇷' },
{ code: 'hk', name: 'Hong Kong', flag: '🇭🇰' },
{ code: 'au', name: 'Australia', flag: '🇦🇺' },
{ code: 'in', name: 'India', flag: '🇮🇳' },
{ code: 'ru', name: 'Russia', flag: '🇷🇺' },
{ code: 'rue', name: 'Russia East', flag: '🇷🇺' },
{ code: 'tr', name: 'Turkey', flag: '🇹🇷' },
{ code: 'uae', name: 'UAE', flag: '🇦🇪' },
{ code: 'za', name: 'South Africa', flag: '🇿🇦' },
];
const REGION_NAMES = {};
const REGION_FLAGS = {};
REGION_LIST.forEach(r => { REGION_NAMES[r.code] = r.name; REGION_FLAGS[r.code] = r.flag; });
const SERVER_REGIONS = {
GCAMS: 'eu', GCASH: 'us', GCTOK: 'jp', GCSYD: 'au', GCSP: 'sa',
GCIST: 'tr', GCDXB: 'uae', GCHK: 'hk', GCLUX: 'eu',
};
// ========== PROTOCOL ==========
function readCompactString(arr, offset) {
const first = arr[offset];
let len, start;
if (first < 128) { len = first; start = offset + 1; }
else { len = (first & 0x7F) | (arr[offset + 1] << 7); start = offset + 2; }
return { str: String.fromCharCode.apply(null, arr.slice(start, start + len)), end: start + len };
}
function findString(arr, key) {
for (var i = 0; i < arr.length - 3; i++) {
if (arr[i] === key && arr[i + 1] === 0x07) {
var r = readCompactString(arr, i + 2);
if (r.str && /^[\x20-\x7e]+$/.test(r.str)) return r;
}
}
return null;
}
function replaceRegionInPacket(data, newRegion) {
var arr = new Uint8Array(data);
for (var i = 0; i < arr.length - 3; i++) {
if (arr[i] === 0xD2 && arr[i + 1] === 0x07) {
var parsed = readCompactString(arr, i + 2);
if (!parsed.str || parsed.str.length > 5) continue;
var newBytes = new TextEncoder().encode(newRegion);
var before = arr.slice(0, i + 2);
var after = arr.slice(parsed.end);
var result = new Uint8Array(before.length + 1 + newBytes.length + after.length);
var off = 0;
result.set(before, off); off += before.length;
result[off++] = newBytes.length;
result.set(newBytes, off); off += newBytes.length;
result.set(after, off);
console.log('[DK] Region: ' + parsed.str + ' → ' + newRegion);
return result.buffer;
}
}
return data;
}
function detectRegionFromURL(url) {
for (var prefix in SERVER_REGIONS) {
if (url.toUpperCase().indexOf(prefix) !== -1) return SERVER_REGIONS[prefix];
}
return null;
}
// ========== UI ==========
var overlay, dropdown;
function createUI() {
if (overlay) return;
overlay = document.createElement('div');
overlay.style.cssText = 'position:fixed;top:8px;left:50%;transform:translateX(-50%);z-index:2147483647;background:rgba(0,0,0,.92);color:#0f0;font:bold 13px/1.4 Consolas,Monaco,monospace;padding:7px 16px;border-radius:8px;border:2px solid rgba(0,255,0,.3);display:flex;gap:14px;align-items:center;user-select:none;pointer-events:auto';
document.body.appendChild(overlay);
dropdown = document.createElement('div');
dropdown.style.cssText = 'position:fixed;top:42px;left:50%;transform:translateX(-50%);z-index:2147483647;background:rgba(8,8,8,.97);color:#ccc;font:12px Consolas,Monaco,monospace;border-radius:8px;border:1px solid rgba(0,255,0,.2);display:none;flex-direction:column;max-height:400px;overflow-y:auto;min-width:230px;box-shadow:0 8px 32px rgba(0,0,0,.7)';
var title = document.createElement('div');
title.style.cssText = 'padding:8px 14px;color:#0f0;font-size:13px;border-bottom:1px solid rgba(0,255,0,.1);font-weight:bold';
title.textContent = 'Changer de région';
dropdown.appendChild(title);
REGION_LIST.forEach(function (r) {
var item = document.createElement('div');
item.style.cssText = 'padding:7px 14px;cursor:pointer;display:flex;gap:10px;transition:background .15s';
item.innerHTML = '<span style="font-size:15px">' + r.flag + '</span><span style="color:#888;width:35px">' + r.code + '</span><span>' + r.name + '</span>';
item.onmouseenter = function () { item.style.background = 'rgba(0,255,0,.1)'; };
item.onmouseleave = function () { item.style.background = 'transparent'; };
item.onclick = function () { selectRegion(r.code); };
dropdown.appendChild(item);
});
var autoItem = document.createElement('div');
autoItem.style.cssText = 'padding:8px 14px;cursor:pointer;border-top:1px solid rgba(0,255,0,.1);color:#888;transition:background .15s';
autoItem.textContent = '↩ Auto (défaut du jeu)';
autoItem.onmouseenter = function () { autoItem.style.background = 'rgba(255,255,255,.05)'; };
autoItem.onmouseleave = function () { autoItem.style.background = 'transparent'; };
autoItem.onclick = function () { selectRegion(null); };
dropdown.appendChild(autoItem);
document.body.appendChild(dropdown);
document.addEventListener('click', function (e) {
if (!dropdown.contains(e.target) && !overlay.contains(e.target)) {
dropdown.style.display = 'none';
}
});
updateUI();
}
function selectRegion(code) {
forcedRegion = code;
dropdown.style.display = 'none';
updateUI();
if (code) {
showToast(REGION_FLAGS[code] + ' ' + code.toUpperCase() + ' (' + REGION_NAMES[code] + ')\nRetourne au menu → PLAY → Online');
} else {
showToast('Région → Auto');
}
}
function showToast(msg) {
var t = document.createElement('div');
t.style.cssText = 'position:fixed;bottom:60px;left:50%;transform:translateX(-50%);z-index:2147483647;background:rgba(0,0,0,.92);color:#0f0;font:13px Consolas,monospace;padding:12px 24px;border-radius:8px;border:1px solid rgba(0,255,0,.2);white-space:pre-line;text-align:center';
t.textContent = msg;
document.body.appendChild(t);
setTimeout(function () {
t.style.transition = 'opacity .5s';
t.style.opacity = '0';
setTimeout(function () { t.remove(); }, 500);
}, 3000);
}
function updateUI() {
if (!overlay) return;
var r = info.region;
var flag = r ? (REGION_FLAGS[r] || '🌐') : '🌐';
var name = r ? (REGION_NAMES[r] || '?') : '—';
var room = info.room || '—';
var srv = info.game ? info.game.replace(/^wss?:\/\//, '').replace(/\.exitgames.*/, '') : '—';
var forced = forcedRegion ? ' <span style="color:#ff0;font-size:11px">→ ' + (REGION_FLAGS[forcedRegion] || '') + ' ' + forcedRegion.toUpperCase() + '</span>' : '';
overlay.innerHTML =
'<span id="dk-rbtn" style="cursor:pointer;padding:2px 6px;border-radius:4px;transition:background .2s">' +
flag + ' <b>' + (r ? r.toUpperCase() : '—') + '</b> ' +
'<span style="color:#999;font-size:11px">' + name + '</span>' + forced +
' <span style="color:#555;font-size:10px">▼</span></span>' +
'<span style="color:#333">│</span>' +
'<span>🏠 <b>' + room + '</b></span>' +
'<span style="color:#333">│</span>' +
'<span style="color:#888">🖥 ' + srv + '</span>';
var btn = document.getElementById('dk-rbtn');
if (btn) {
btn.onmouseenter = function () { btn.style.background = 'rgba(0,255,0,.15)'; };
btn.onmouseleave = function () { btn.style.background = 'transparent'; };
btn.onclick = function (e) {
e.stopPropagation();
dropdown.style.display = dropdown.style.display === 'flex' ? 'none' : 'flex';
};
}
}
// ========== WS HOOK ==========
window.WebSocket = function (url, protocols) {
var ws = protocols ? new origWS(url, protocols) : new origWS(url);
var isNS = url.indexOf('photonengine.io') !== -1;
if (url.indexOf('/Master') !== -1) {
info.master = url.split('?')[0];
var r = detectRegionFromURL(url);
if (r) info.region = r;
}
if (url.indexOf('/game') !== -1) {
info.game = url.split('?')[0];
var r2 = detectRegionFromURL(url);
if (r2) info.region = r2;
}
updateUI();
var origSend = ws.send.bind(ws);
ws.send = function (data) {
if (data instanceof ArrayBuffer) {
var arr = new Uint8Array(data);
if (arr[1] === 0x02) {
// Auth on NameServer — replace region if forced
if (arr[2] === 0xE6 && isNS && forcedRegion) {
var ri = findString(arr, 0xD2);
if (ri && ri.str.length <= 5) {
data = replaceRegionInPacket(data, forcedRegion);
info.region = forcedRegion;
updateUI();
}
}
// Detect current region
if (arr[2] === 0xE6) {
var ri2 = findString(new Uint8Array(data), 0xD2);
if (ri2 && ri2.str.length <= 5) { info.region = ri2.str; updateUI(); }
}
// Detect room
if (arr[2] === 0xE2) {
var ri3 = findString(arr, 0xFF);
if (ri3) { info.room = ri3.str; updateUI(); }
}
}
}
return origSend(data);
};
ws.addEventListener('message', function (evt) {
if (!(evt.data instanceof ArrayBuffer)) return;
var arr = new Uint8Array(evt.data);
if (arr[1] === 0x03) {
var ai = findString(arr, 0xE6);
if (ai && ai.str.indexOf('exitgames.com') !== -1) {
if (ai.str.indexOf('/game') !== -1) info.game = ai.str;
else if (ai.str.indexOf('/Master') !== -1) info.master = ai.str;
var r = detectRegionFromURL(ai.str);
if (r) info.region = r;
updateUI();
}
}
});
return ws;
};
window.WebSocket.prototype = origWS.prototype;
window.WebSocket.CONNECTING = 0;
window.WebSocket.OPEN = 1;
window.WebSocket.CLOSING = 2;
window.WebSocket.CLOSED = 3;
// ========== INIT ==========
function init() {
if (document.body) { createUI(); }
else { document.addEventListener('DOMContentLoaded', createUI); }
}
init();
window.__dkInfo = info;
window.__dkSetRegion = function (r) { selectRegion(r); };
console.log('[DK] Region Switcher v2.1 loaded');
})();
@andronedev

Copy link
Copy Markdown
Author

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment