Skip to content

Instantly share code, notes, and snippets.

@notarikon-nz
Created August 27, 2024 06:58
Show Gist options
  • Select an option

  • Save notarikon-nz/2342cfaad7e1883daa7faf2610452416 to your computer and use it in GitHub Desktop.

Select an option

Save notarikon-nz/2342cfaad7e1883daa7faf2610452416 to your computer and use it in GitHub Desktop.
HackMUD T2 Scraper including QR Decoder
function(context, args){// t:#s.weyland.members
function getActiveT2() {
let aa = "bunnybat_hut,cyberdine,setec_gas,soylentbean,suborbital_airlines,tandoori,tyrell,weyland".split(","), // known corp locations, without .public
bb = "members,memberlogin,members_only,member_access,private,internal,priv,employees,intern,employee_login,emplogin".split(","), // known t2/t3 suffixes, e.g. memberz
t2 = new Array()
for (let first of aa) {
for (let second of bb) {
let domain = first + "." + second
let r = #fs.scripts.get_level({ name: domain })
if (Number.isInteger(r)) {
if (r == 2 || r == 3)
t2.push(domain)
}
}
}
return t2;
}
// OOG CLIENT LISTING
if (args && args.portal && !args.t) {
let a = new Array();
const list = #fs.nokiraton.status({portal:true})
list.forEach(n =>
a.push(n.domain)
)
return a.reverse().join("\n");
}
if (!args || !args.t || args.t == null) {
const shift = getActiveT2()
return "\n`HAPERTURE SCIENCE TIER 2`\n\nUsage: aperture.t2 { t: #s.weyland.members }\n\nAvailable corps:\n\n" + shift;
}
let debug = "";
let t = args.t,
u = args.u,
r = "",
o = "\n`HAPERTURE SCIENCE TIER 2`\n\n"
let safe = t.call({})
if (safe.ok == false)
return {ok:false,msg:"Location does not exist"}
let rating_short = "_jr,_dd,_wb,_pr,_ls".split(","),
rating_long = "`0junk`,`1deck`,`2wrck`,`3phrk`,`4leet`".split(","),
class_short = "wvr_,ttl_,wlf_,rvn_,stg_".split(","),
class_long = "`Narch`,`Olock`,`Pinfl`,`Qscav`,`Sexec`".split(","),
s = ["NUL","LOW ","MID ","HIG","FUL"],
rst = "????",
// um = "",
lm = "",
eo = 0
// first, find the username type
var p1 = decorrupt(t)
u = p1.indexOf("username") > -1 ? "username" : p1.indexOf("user") > -1 ? "user" : "u"
let users = new Set(
"_123lt_jack,_3rd_3y3_grill,3rd_3y3_grill,ad4m4,ada_love,aeryn_s,amelie,arr_too_d_to,b_sisko,b3nd3r,b4cca,b4rry_vv,bassy_thecount,be_lavar,bella_swan,bella_swann,boba_the_hutt,bobranator,boris,brohda_99,bus_and_parks,c_vader,carrie_on_,catness,chad_bose,cheechfiend91,childishg4mb,cking,computer_blue,corg_train,corgitruthsayer,crichton_j,curtfields0fmay,d_bowman,d_jackson,d4ft,d4ria,daa_freak,daurmith,delete_me_first,derek_zoo,diamond_dogz,do_u_need_hal,doc_brown,dr00gy_lex,du_boyz,duke_ell,e_ponine,etceteraco,firebreathingdragon,foxy_guy,frank_einstein,frantimike,free_man_morg,geyser_sore,geyser_soze,ginnypig,gwashc,h_jimi,h4chguy,hand_solo,hermione,htubman,huey_n,hypati4_370,i_am_the_eggman,ice_ventura,indie_jones,inigo,ireneadler,jack_sparrow,jamesb,janeway,jermaine,jim_c_kirk,journer_of_truth,juno_macguff,killa_kara,king_in_yellow,king_luther,lass_doug,leia_it_ontheline,leon,lion_eyes,lizzie_regna,lt_col_j_shep,lt_col_j_shepp,luke_5kywalker,m_ali,m_c_fly,m_clarke_dunk,m_poppins,madthugpug,marc_garv,mary_shell,med_evarz,med_evzrz,mh_hamilton,mjay_m_walker,muld0r,neoone,oz,pick4rluc,poitier_27,pugluv4vr,purple1,q_bey,r0bertm4rley,rain3y,raygun_chandler,renaldos_malc,revolution808,rey_tr4cer,ripley_or_not,rob_rob_taylor,robo_deckard,rocky_b,runningman23,sam_cart,sammy_l_jack,scook,seria_mau_g,seven_out_of_9,shareef_j,shawn_aa,sidney_prescott,sp0ck_08,sportsfan2031,tam_riv,tchalla,terrance_cruz,thadd_0s,thedude,theformalartist,thegreat,thegreatvandross,thepowerful,theshrillery,troy_cole,turn_a_nat,turner_t,uhur4,universe,wc_handy,whois_hermano,wiley_curry,will_de_vaughn,wonderous_steve,x_mal,youngtwokay,yung_lespaul,zap_dweezil,zap_franscisco,zap_moon,zoe_wash".split(",")
),
active = new Set(),
verified = new Set(),
regex_key = /[a-z]/g,
a = "",
key = "",
first = 1
users.forEach(handle => {
const args = {username:handle}
const r = decorrupt (t, args)
if (r.includes("faq")) {
if (first) {
key = r.split("\n")[2]
key = key.substring(2,key.length-1)
first = 0
}
active.add(handle)
}
})
const user_list = [...active].map((handle, index) => {
const paddedHandle = handle.padEnd(20, " ")
return (index % 4 === 3) ? ` ${paddedHandle}\n` : ` ${paddedHandle}`
}).join("");
let loc_set = new Set(),
early = false
let count = 0, qr_count = 0, call_count = 0
for (const handle of active) {
a = {} // username:handle,key:"faq"}
a[u] = handle
a[key] = "order_qrs"
let jsonArray = fast_qr(t, a) // r = #fs.notarikon.qr_decode ( {t:t,a:a} ) // dtr is faster for now
var idArray = []
jsonArray.forEach(jsonObject => {
if (typeof jsonObject == 'string') idArray.push(jsonObject)
qr_count++
});
for (var i in idArray) {
a[key] = "cust_service"
a["order_id"] = idArray[i]
var locs = decorrupt(t, a).split(" ")
const locationRegex = /^[\w]+\.[\w]+$/
for (const location of locs) {
if (!location.match(locationRegex)) continue
verified.add(location)
//const sl = #fs.scripts.get_level({ name: location })
//const sec = s[sl]
const rat = get_rating(location)
const cls = get_class(location)
loc_set.add({ loc: location, rat, cls })
isNPC(location) ? insertNPC(location) : insertPlayer(location);
}
if ((Date.now() - _START) > 4750) break;
}
if ((Date.now() - _START) > 4750) break;
}
if (args.portal)
return `Found: ${loc_set.size} NPCs`
let output = get_return_string()
if (context.caller == 'aperture') output += debug
return output
function get_return_string() {
let et = Date.now()-_START
o += "Found " + verified.size + " NPCs from " + qr_count + " QR Codes in " + et + "ms\n\n"
// Convert the Set to an Array for sorting
let arrayData = Array.from(loc_set);
// Sort the Array
arrayData.sort((a, b) => {
//if (a.sec < b.sec) return -1;
//if (a.sec > b.sec) return 1;
if (a.rat < b.rat) return -1;
if (a.rat > b.rat) return 1;
if (a.cls < b.cls) return -1;
if (a.cls > b.cls) return 1;
return 0;
})
// If you need the sorted data back as a Set (this is uncommon since Sets are not ordered)
loc_set = new Set(arrayData);
o += convertSetToJsonTable(loc_set)
if (early) o+= "\n\nWarning: Script terminated early to avoid timeout, more locs available\n"
return o
}
function decorrupt(target, args) {
const corruption = /`.[¡¢Á¤Ã¦§¨©ª]`/g
let r1 = target.call(args), // t is a global var, so no need to pass it as an argument
r2 = target.call(args) // could probably do the same with b but oh well
if (Array.isArray(r1)) r1 = r1.join("\n");
if (Array.isArray(r2)) r2 = r2.join("\n");
r1 = r1.replace(corruption, "§");
r2 = r2.replace(corruption, "§");
const timeout = 100;
while (Date.now() - _START < timeout) {
let cor_index = r1.indexOf("§")
if (cor_index === -1) {
return r1
}
let r2char = r2[cor_index]
if (r2char === "§") {
r2 = target.call(args);
if (Array.isArray(r2)) r2 = r2.join("\n");
r2 = r2.replace(corruption, "§");
continue
}
r1 = r1.slice(0, cor_index) + r2char + r1.slice(cor_index + 1);
}
return r1
}
function get_rating(um) {
let rst = "----"
for (var x = 0; x < 5; x++) {
var r = rating_short[x];
var sp = um.split(".")[0];
if (!sp.includes("_") && (rst = "`5plyr`")) continue;
if (sp.includes(r) && (rst = rating_long[x])) continue;
}
return rst;
}
function get_class(um) {
let rst = "----"
for (var x = 0; x < 5; x++) {
var r = class_short[x];
var sp = um.split(".")[0];
if (!sp.includes("_") && (rst = "")) continue;
if (sp.includes(r) && (rst = class_long[x])) continue;
}
return rst;
}
function convertSetToJsonTable(set) {
if (set.size === 0) return "No data available";
// Initialize headers and column width trackers
let headers = [];
let columnWidths = {};
// First, determine headers and initialize widths by examining the first object in the set
set.forEach(item => {
headers = Object.keys(item);
headers.forEach(header => {
let l = header.length
let i = ("" + decolor(item[header] || ''))
columnWidths[header] = Math.max(l, i.length)
});
return true; // Exit after processing the first item
});
// Update columnWidths based on all data in the set
set.forEach(item => {
headers.forEach(header => {
const dataLength = ("" + decolor(item[header] || '')).length;
if (dataLength > columnWidths[header]) {
columnWidths[header] = dataLength;
}
});
});
// ━━━━━━━━━╋
// Create header row
let headerRow = headers.map(header => ("`1" + header.padEnd(columnWidths[header])).toUpperCase() + "`").join(' ┃ ')
let rows = [headerRow];
// Separator row
let separatorRow = headers.map(header => '━'.repeat(columnWidths[header])).join('━━╋━━');
rows.push(separatorRow);
// Data rows
set.forEach(item => {
let row = headers.map(header => ("" + (item[header] || '')).padEnd(columnWidths[header])).join(' ┃ ');
rows.push(row);
});
// Join all rows into a single string with new lines
return rows.join('\n');
}
function decolor (val) {
return val.replaceAll(/`\w(.*?)`/g, '$1')
}
function printColumns(arr, width) {
const spacing = 6; // fixed spacing between columns
let maxStrLength = 0;
let output = ""
// Calculate the maximum string length
for (let i = 0; i < arr.length; i++) {
if (arr[i].length > maxStrLength) {
maxStrLength = arr[i].length;
}
}
const colWidth = maxStrLength + spacing; // width of each column including spacing
const numCols = Math.floor(width / colWidth); // number of columns that fit in the given width
const numRows = Math.ceil(arr.length / numCols); // number of rows needed
for (let row = 0; row < numRows; row++) {
let rowStr = '';
for (let col = 0; col < numCols; col++) {
const index = row + col * numRows;
if (index < arr.length) {
rowStr += arr[index].padEnd(colWidth, ' ');
}
}
output += (rowStr) + "\n";
}
return output
}
function fast_qr(target, _args) {
let sa = _args
const MASK = [
(i, j) => (i + j) % 2 == 0, // 0
(i, j) => i % 2 == 0, // 1
(i, j) => j % 3 == 0, // 2
(i, j) => (i + j) % 3 == 0, // 3
(i, j) => (((i / 2) | 0) + ((j / 3) | 0)) % 2 == 0, // 4
(i, j) => (i * j) % 2 + (i * j) % 3 == 0, // 5
(i, j) => ((i * j) % 3 + (i * j)) % 2 == 0, // 6
(i, j) => ((i * j) % 3 + i + j) % 2 == 0 // 7
],
REG = /[<>]/;
let tot_calls = 1;
let rsp = target.call(_args);
let CALLS;
try {
CALLS = [rsp.filter(o => !REG.test(o)).map(o => o.replace(/`.([^`])`/g, '@'))];
} catch (e) {
CALLS = [];
}
function bit(ind, w, x, y) {
const z = (y / 2 | 0) * (w + 1) + x,
ch = y % 2 ? '▄' : '▀'
for (let i = 0; i < CALLS.length; ++i) {
const c = CALLS[i][ind][z];
if (c == '@') continue;
return c == '█' || c == ch
}
while (true) {
++tot_calls;
const t = target.call(_args).filter(o => !REG.test(o)).map(o => o.replace(/`.([^`])`/g, '@'));
CALLS.push(t);
const c = t[ind][z];
if (c == '@') continue;
return c == '█' || c == ch
}
}
function eitherbit(ind, w, x, y, x1, y1) {
const z = (y / 2 | 0) * (w + 1) + x,
z1 = (y1 / 2 | 0) * (w + 1) + x1,
ch = y % 2 ? '▄' : '▀',
ch1 = y1 % 2 ? '▄' : '▀'
for (let i = 0; i < CALLS.length; ++i) {
let c = CALLS[i][ind][z];
if (c == '@') {
c = CALLS[i][ind][z1];
if (c == '@') continue;
return c == '█' || c == ch1
}
return c == '█' || c == ch
}
while (true) {
++tot_calls;
const t = target.call(_args).filter(o => !REG.test(o)).map(o => o.replace(/`.([^`])`/g, '@'));
CALLS.push(t);
let c = t[ind][z];
if (c == '@') {
c = t[ind][z1];
if (c == '@') continue;
return c == '█' || c == ch1
}
return c == '█' || c == ch
}
}
const LOCS = {
/*9*/53: [
/* 7*/[[39, 40], 0, [39, 39], [40, 10], [39, 10], [40, 9], [39, 9]],
/* 8*/[[39, 8], 0, [39, 7], [38, 23], [37, 23], [38, 24], [37, 24]],
/* 9*/[[37, 25], 0, [37, 26], [36, 50], [35, 50], [36, 49], [35, 49]],
/*10*/[[35, 48], 0, [35, 47], [52, 48], [51, 48], [52, 47], [51, 47]],
/*11*/[[51, 46], 0, [51, 45], [52, 16], [51, 16], [52, 15], [51, 15]],
/*12*/[[51, 14], 0, [51, 13], [50, 33], [49, 33], [50, 34], [49, 34]]
],
/*8*/49: [
/* 7*/[[37, 21], 0, [37, 22], [38, 43], [37, 43], [38, 44], [37, 44]],
/* 8*/[[37, 45], 0, [37, 46], [36, 30], [35, 30], [36, 29], [35, 29]],
/* 9*/[[35, 28], 0, [35, 27], [36, 5], [35, 5], [36, 4], [35, 4]],
/*10*/[[35, 3], 0, [35, 2], [34, 19], [33, 19], [34, 20], [33, 20]],
/*11*/[[33, 21], 0, [33, 22], [34, 43], [33, 43], [34, 44], [33, 44]],
/*12*/[[33, 45], 0, [33, 46], [48, 44], [47, 44], [48, 43], [47, 43]]
],
/*7*/45: [
/* 7*/[[33, 9], 0, [33, 10], [34, 27], [33, 27], [34, 28], [33, 28]],
/* 8*/[[33, 29], 0, [33, 30], [32, 42], [31, 42], [32, 41], [31, 41]],
/* 9*/[[31, 40], 0, [31, 39], [32, 22], [31, 22], [32, 21], [31, 21]],
/*10*/[[31, 20], 0, [31, 19], [32, 1], [31, 1], [32, 0], [31, 0]],
/*11*/[[29, 0], 0, [29, 1], [44, 40], [43, 40], [44, 39], [43, 39]],
/*12*/[[43, 38], 0, [43, 37], [44, 20], [43, 20], [44, 19], [43, 19]]
]
}
const SM = { 1058: 45, 1250: 49, 1458: 53 }
function qr(ind) {
const ver = SM[CALLS[0][ind].length],
m = ((eitherbit(ind, ver, 2, 8, 8, ver - 3) << 2) | (eitherbit(ind, ver, 3, 8, 8, ver - 4) << 1) | eitherbit(ind, ver, 4, 8, 8, ver - 5)) ^ 5
let answer = String.fromCharCode(...LOCS[ver].map(byte => '0b' + byte.map(a => +!a || bit(ind, ver, a[0], a[1]) ^ MASK[m](a[1], a[0])).join('')))
// debug += `\n${JSON.stringify(sa)} : ${answer} (${ver})`
return answer
}
let res = Array(CALLS[0].length)
for (let i = 0; i < res.length; ++i) {
res[i] = qr(i)
}
return res;
}
function isNPC(handle) {
const npcs = "abandoned,abndnd,anon,anonymous,derelict,uknown,unidentified,unknown".split(",")
for (var ih = 0; ih < npcs.length; ih++) {
if (handle.includes(npcs[ih])) {
return true
}
}
return false
}
function insertPlayer(pvpLocation) {
let level = String(#fs.scripts.get_level({name:pvpLocation}))
if (!isNumeric(level)) return false;
const pvpUsername = pvpLocation.split(".")[0]
const query = { group: "pvp", pvpUsername };
const update = { $set: { pvpLocation,source:'aperture.t2' } };
try {
#db.us(
query,
update
);
} catch (e) {}
}
function isNumeric(str) {
if (typeof str != "string") return false // we only process strings!
return !isNaN(str) && // use type coercion to parse the _entirety_ of the string (`parseFloat` alone does not do this)...
!isNaN(parseFloat(str)) // ...and ensure strings of whitespace fail
}
function insertNPC(location) {
// const tier = #fs.scripts.get_level({ name: location })
const timestamp = Date.now()
const _id = 'locs';
const query = { tier:2, location };
const update = { $set: { timestamp,source:'aperture.t2' } };
try {
#db.us(
query,
update //, { upsert: true }
);
} catch (e) { }
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment