Surviv.io input replay recorder

Records lightweight game recordings, which can be reviewed with any custom mods applied

  1. // ==UserScript==
  2. // @name Surviv.io input replay recorder
  3. // @namespace https://github.com/notKaiAnderson/
  4. // @version 1.0.10
  5. // @description Records lightweight game recordings, which can be reviewed with any custom mods applied
  6. // @author garlic
  7. // @match *://*.zurviv.io/
  8. // @match *://*.resurviv.biz/
  9. // @match *://*.survev.io/
  10. // @match *://web.archive.org/web/*id_/http*://*surviv.io/
  11. // @grant none
  12. // @icon https://i.imgur.com/jgHdTYA.png
  13. // @license MIT
  14. // ==/UserScript==
  15. (function() {
  16. document.querySelector('#background').style.cssText = 'background-image: url(https://i.imgur.com/edob0SF.png)'
  17. })();
  18. /*** contributors
  19. * garlic
  20. * samer kizi
  21. * preacher
  22. ***/
  23.  
  24. var ifsurviv = false;
  25. if (window.zzpseudoalert && window.log) {
  26. window.zzpseudoalert("already active");
  27. } else {
  28.  
  29. var survivharplayerconfig = { silly1: false };
  30. try {
  31. let t=JSON.parse(localStorage.getItem("survivharplayerconfig"));
  32. if(t) survivharplayerconfig = t;
  33. }catch(e){};
  34. var survivharplayer = {
  35. survivharplayerconfigsave () {
  36. localStorage.setItem("survivharplayerconfig",JSON.stringify(survivharplayerconfig));
  37. },
  38. silly3dchange(param) {
  39. let r;
  40. if (
  41. (survivharplayerconfig.silly1 = !survivharplayerconfig.silly1) ===
  42. false
  43. ) {
  44. dosomething_with_send_disable();
  45. r=false;
  46. } else {
  47. r=true;
  48. }
  49. this.survivharplayerconfigsave();
  50. return r;
  51. },
  52. disableAutoFill(param) {
  53. let r= (survivharplayerconfig.disableAutoFill = !survivharplayerconfig.disableAutoFill);
  54. this.survivharplayerconfigsave();
  55. return r;
  56. },
  57. };
  58.  
  59. try {
  60. document.getElementsByClassName("ftue-header")[0].style.backgroundColor =
  61. "violet";
  62. document.getElementsByClassName("ftue-body")[0].style.backgroundColor = "red";
  63. ifsurviv = true;
  64. } catch (e) {}
  65. window.zzpseudoalert = function (e) {
  66. var x = document.createElement("div");
  67. x.style =
  68. "zIndex:255;position:fixed;left:50%;width:40%;top:20%;height:fit-content;background-color:rgba(0,0,0,.5);color:#e4d338;text-align:center;border-radius:10px;padding:10px 20px;-webkit-transform: translate(-50%, -50%);transform: translate(-50%, -50%);";
  69. x.innerHTML = e;
  70. document.body.append(x);
  71. x.style.fontSize = "20px";
  72. x.animate([{ opacity: "1" }, { opacity: "0" }], { duration: 3000 });
  73. setTimeout(() => document.body.removeChild(x), 3000);
  74. };
  75. window.zzpseudoalert.small = function (e) {
  76. var x = document.createElement("div");
  77. x.style =
  78. "zIndex:255;position:fixed;left:50%;width:40%;top:20%;height:fit-content;background-color:rgba(0,0,0,.5);color:#e4d338;text-align:center;border-radius:10px;padding:10px 20px;-webkit-transform: translate(-50%, -50%);transform: translate(-50%, -50%);";
  79. x.innerHTML = e;
  80. document.body.append(x);
  81. x.style.fontSize = "20px";
  82. x.animate([{ opacity: "1" }, { opacity: "0" }], { duration: 3000 });
  83. setTimeout(() => document.body.removeChild(x), 3000);
  84. };
  85. //zzpseudoalert("wsrapper init");
  86.  
  87. function arrayBufferToBase64(buffer) {
  88. let binary = "";
  89. let bytes = new Uint8Array(buffer);
  90. let len = bytes.byteLength;
  91. for (let i = 0; i < len; i++) {
  92. binary += String.fromCharCode(bytes[i]);
  93. }
  94. return window.btoa(binary);
  95. }
  96. window.logentries = [];
  97. window.log = {
  98. log: {
  99. version: "1.2",
  100. creator: {
  101. name: "wswrapperallium",
  102. version: "0.0031",
  103. },
  104. entries: window.logentries,
  105. },
  106. };
  107.  
  108. var lastgameforunlink;
  109.  
  110. class RecordingWebSocket extends WebSocket {
  111. /*constructor(e) {
  112. e=e.replace('wss://','ws://');
  113. e=e.replace(':449/','/');
  114. super(e);
  115. }*/
  116.  
  117. unlinkfromclient() {
  118. if (this.readyState != this.OPEN) return false;
  119.  
  120. let seq = 0;
  121. let wso = this.__lientry._webSocketMessages;
  122.  
  123. for (let i = wso.length - 1; i >= 0; i--) {
  124. if (wso[i].type == "send") {
  125. let msgab = from_base64s_ab(wso[i].data);
  126. let msgbytes = new Uint8Array(msgab);
  127. if (msgbytes[0] == 3) {
  128. seq = msgbytes[1];
  129. break;
  130. }
  131. }
  132. }
  133.  
  134. var oldsend = this.send;
  135. Object.defineProperty(this, "send", {
  136. configurable: true,
  137. get: function () {
  138. return () => {};
  139. },
  140. set: function () {},
  141. });
  142. Object.defineProperty(this, "close", {
  143. configurable: true,
  144. get: function () {
  145. return () => {};
  146. },
  147. set: function () {},
  148. });
  149.  
  150. var thisArg = this;
  151. function keepAlive() {
  152. seq = (seq + 1) & 255;
  153. let a;
  154.  
  155. if (window.spectatepinginsteadofinput) {
  156. a = new Uint8Array(4);
  157. ("C90bAA==");
  158. a[0] = 11;
  159. a[1] = 0;
  160. a[2] = 0;
  161. a[3] = 2;
  162. } else {
  163. a = new Uint8Array(9);
  164.  
  165. a[0] = 3;
  166. a[1] = seq;
  167. a[3] = 255;
  168. a[4] = 3;
  169. a[5] = 8;
  170. }
  171. oldsend.apply(thisArg, [a]);
  172. console.info("tick", seq);
  173. }
  174.  
  175. var keepAliveIt = setInterval(() => keepAlive(), 1017);
  176. console.info("unlink toggled", seq);
  177. this.onerror = () => {};
  178. this.onclose();
  179. this.onclose = () => {
  180. clearInterval(keepAliveIt);
  181. console.info("unlinked conn closed");
  182. };
  183. this.__spy_onmessage = () => {};
  184. return true;
  185. }
  186.  
  187. send(...args) {
  188. let thisArg = this;
  189. let e = args[0];
  190. if (thisArg.__lientry == undefined) {
  191. thisArg.__lientry = {
  192. startedTime: new Date().toISOString(),
  193. time: 0,
  194. request: {
  195. method: "GET",
  196. url: thisArg.url,
  197. },
  198. _webSocketMessages: [],
  199. };
  200. if (ifsurviv) {
  201. thisArg.__lientry.__survivio = {};
  202. thisArg.onEach = function () {};
  203. if (thisArg.url.includes("/play?game")) lastgameforunlink = thisArg;
  204. }
  205.  
  206. window.logentries.push(thisArg.__lientry);
  207. let wsa = thisArg.__lientry._webSocketMessages;
  208. let tos = /*thisArg.__lientry.time.toString= */ () => {
  209. let t1 = 0;
  210. if (wsa.length > 1) {
  211. t1 = wsa.slice(-1)[0].time - wsa[0].time;
  212. }
  213. return t1 + "";
  214. };
  215. thisArg.__lientry.time = {
  216. toString: tos,
  217. };
  218. zzpseudoalert(thisArg.url.replace("wss://", "").replace("/", "<p>"));
  219. thisArg.__spy_onmessage = thisArg.onmessage;
  220. let recvHandler = function (...args) {
  221. let e = args[0];
  222. {
  223. let temp = {
  224. type: "receive",
  225. time: new Date().getTime() / 1e3,
  226. opcode: 2,
  227. };
  228. this.__lientry._webSocketMessages.push(temp);
  229. if (typeof e.data !== "string") {
  230. temp.opcode = 2;
  231. new Response(e.data)
  232. .arrayBuffer()
  233. .then((ifAblob) => (temp.data = arrayBufferToBase64(ifAblob)));
  234. } else {
  235. temp.opcode = 1;
  236. temp.message = e.data;
  237. }
  238. return this.__spy_onmessage.apply(this, args);
  239. }
  240. };
  241. thisArg.onmessage = recvHandler;
  242. }
  243. let temp = {
  244. type: "send",
  245. time: new Date().getTime() / 1e3,
  246. opcode: 2,
  247. };
  248. thisArg.__lientry._webSocketMessages.push(temp);
  249. if (typeof e !== "string") {
  250. temp.opcode = 2;
  251. temp.data = arrayBufferToBase64(e);
  252. } else {
  253. temp.opcode = 1;
  254. temp.message = e;
  255. }
  256. return super.send(...args);
  257. }
  258. }
  259. RecordingWebSocket.unlink = function () {
  260. let msg = "";
  261. if (lastgameforunlink) {
  262. if (lastgameforunlink.unlinkfromclient()) msg = "unlink function activated";
  263. else msg = "unlink function not activated";
  264. } else msg = "nothing";
  265. window.zzpseudoalert(msg);
  266. };
  267.  
  268. window.WebSocket = RecordingWebSocket;
  269.  
  270. let oldopen=XMLHttpRequest.prototype.open;
  271. XMLHttpRequest.prototype.open = function (...args){
  272. if(window.WebSocket.prototype.__onharmessage && args[1].endsWith("/find_game")) {
  273. args[1]='data:application/json,{"res":[{"zone":"","data":"0123456789abcdef0123456789abcdef01234567","gameId":"0123456789abcdef0123456789abcdef01234567","useHttps":false,"hosts":["localhost"],"addrs":["localhost"]}]}';
  274. }
  275. return oldopen.apply(this,args);
  276. };
  277.  
  278. let oldsend=XMLHttpRequest.prototype.send;
  279. XMLHttpRequest.prototype.send = function (...args){
  280. if(survivharplayerconfig.disableAutoFill
  281. && typeof args[0]=="string"
  282. && args[0].startsWith('{"version":') ) {
  283. args[0]=args[0].replace('"autoFill":true','"autoFill":false');
  284. /*args[0]=args[0].replace('"region":"eu"','"region":"dev"');*/
  285. }
  286. return oldsend.apply(this,args);
  287. };
  288.  
  289.  
  290. void "surviv .har repeat script. new103. open up at surviv.io, load .har file. f1f2f3f6 -- change replay speed";
  291. {
  292. let cconsole = console.log;
  293. Object.defineProperty(console, "log", {
  294. configurable: true,
  295. get: function () {
  296. return cconsole;
  297. },
  298. set: function (e) {},
  299. });
  300. }
  301. (function () {
  302. "use strict";
  303. let cycle = (x) => (x == false ? undefined : x == undefined);
  304. let cycle2 = (x, y, z) => (x == y ? z : y);
  305. const keys = ["F1", "F2", "F3", "F4", "F6", "F7", "F8", "F9", "F10"];
  306. const disableKey = (key) => keys.push(key);
  307. ["keypress", "keydown", "keyup"].forEach((type) => {
  308. document.addEventListener(type, (e) => {
  309. if (keys.indexOf(e.key) !== -1) {
  310. if (e.type == "keydown") {
  311. if (e.key == "F1") window.slowmo = 0.33;
  312. if (e.key == "o") window.slowmo = 1;
  313. if (e.key == "0") window.slowmo = 2;
  314. if (e.key == "6") window.slowmo = 2.5;
  315. if (e.key == "p") window.slowmo = 16;
  316. if (e.key == "F6") window.slowmo = 16;
  317. if (e.key == "F7") {
  318. survivharplayer.silly3dchange(2);
  319. }
  320. window.slowmor = window.slowmo;
  321. }
  322. return e.preventDefault();
  323. }
  324. });
  325. });
  326. })();
  327.  
  328. window.slowmo = 1;
  329. window.harRead = {
  330. files: [],
  331. games: {},
  332. alert: window.alert.bind(window),
  333. ui: { window: window },
  334. };
  335. window.foo = function () {
  336. function unlinkfromUI() {
  337. RecordingWebSocket.unlink();
  338. }
  339.  
  340. function tabuntab() {
  341. if (!xpassblock) return;
  342. if (document.getElementById("missions-name").style.display === "none") {
  343. document.getElementById("missions-name").style = "display:block";
  344. document.getElementById("pass-quest-wrapper").style = "display:block";
  345. } else {
  346. document.getElementById("missions-name").style = "display:none";
  347. document.getElementById("pass-quest-wrapper").style = "display:none";
  348. }
  349. if (x.parentElement.id == "pass-block" || x.parentElement.id == "ad-block-left") {
  350. window.zzpseudoalert("FUG");
  351. x.otherwindow = window.open("", "", "height=250,width=300");
  352. x.otherwindow.document.body.append(x);
  353. window.harRead.ui.window = x.otherwindow;
  354. } else {
  355. xpassblock.insertBefore(x, xpassblock.firstElementChild);
  356. window.harRead.ui.window = window;
  357. x.otherwindow.close();
  358. }
  359. }
  360.  
  361. function saveharlog() {
  362. (function (filename, data) {
  363. try {
  364. var blob = new Blob([data], { type: "text/plain" });
  365. } catch (e) {
  366. alert("whoops, doesnt work");
  367. }
  368.  
  369. if (window.navigator.msSaveOrOpenBlob) {
  370. window.navigator.msSaveBlob(blob, filename);
  371. } else {
  372. var elem = window.document.createElement("a");
  373. elem.href = window.URL.createObjectURL(blob);
  374. elem.download = filename;
  375. document.body.appendChild(elem);
  376. elem.click();
  377. document.body.removeChild(elem);
  378. }
  379. })(
  380. document.location.host +
  381. new Date().toISOString().slice(0, 10) +
  382. Date.now() +
  383. ".har",
  384. JSON.stringify(log)
  385. );
  386. }
  387.  
  388. function selmodech(tt, event, ename) {
  389. if (ename == "change") {
  390. if (tt.value == "Tab/untab") {
  391. ('prompt("wha")');
  392. }
  393. if (tt.selectedIndex == 5) {
  394. saveharlog();
  395. tt.selectedIndex = tt.prevselectedIndex;
  396. return;
  397. }
  398. if (tt.selectedIndex == 6) {
  399. if(survivharplayer.silly3dchange(2)==false)
  400. window.zzpseudoalert("silly pseudo 3d is now: DISABLED");
  401. else
  402. window.zzpseudoalert("silly pseudo 3d is now: ENABLED");
  403. tt.selectedIndex = tt.prevselectedIndex;
  404. return;
  405. }
  406. if(tt.selectedIndex == 7) {
  407. if(survivharplayer.disableAutoFill(2)==false) {
  408. window.zzpseudoalert("force solosquads: DISABLED");
  409. } else {
  410. window.zzpseudoalert("force solosquads: ENABLED");
  411. }
  412. tt.selectedIndex = tt.prevselectedIndex;
  413. return;
  414. }
  415. tt.prevselectedIndex = tt.selectedIndex;
  416. if (tt.selectedIndex == 0) {
  417. if (window.WebSocket.name == "ReplayWebSocket")
  418. window.WebSocket = RecordingWebSocket;
  419. } else {
  420. if (window.WebSocket.name == "RecordingWebSocket")
  421. window.WebSocket = ReplayWebSocket;
  422. }
  423. if (tt.selectedIndex == 1) {
  424. applyParsedHarFile(log);
  425. }
  426. if (tt.value == "Replay from prompt") {
  427. let pp = window.harRead.ui.window.prompt(
  428. "input har file, or http/file address"
  429. );
  430. let done = false;
  431. if (
  432. pp.startsWith("file://") ||
  433. pp.startsWith("http") ||
  434. !pp.startsWith('{"log"')
  435. ) {
  436. window.zzpseudoalert("trying to fetch file");
  437. fetch(pp)
  438. .then((r) => r.json())
  439. .then((e) => applyParsedHarFile(e));
  440. } else doa(pp);
  441. function doa(pp) {
  442. if (pp.startsWith('{"log"')) {
  443. try {
  444. let yi = JSON.parse(pp);
  445. applyParsedHarFile(yi);
  446. } catch (e) {
  447. window.zzpseudoalert("could not read/parse... failed");
  448. }
  449. }
  450. }
  451. }
  452. }
  453. }
  454.  
  455. try {
  456. var xpassblock = document.getElementById("pass-block");
  457. if(!x || xpassblock.parentElement.id == 'pass-wrapper') xpassblock=(document.getElementById("ad-block-left"));
  458. ("var ifsurviv=true");
  459. }catch(e) {};
  460. var xwin, x;
  461. if (!xpassblock) {
  462. xwin = window.open("", "");
  463. x = xwin.document.createElement("div");
  464. xwin.document.body.append(x);
  465. ("ifsurviv=false");
  466. } else {
  467. x = document.createElement("div");
  468. xpassblock.insertBefore(x, xpassblock.firstElementChild);
  469. }
  470.  
  471. var mn = document.createElement("div");
  472. mn.style = "display:inline-flex;width:100%";
  473. x.insertBefore(mn, x.firstElementChild);
  474.  
  475. var tt = document.createElement("select");
  476. tt.id = "modepl";
  477. tt.style = `
  478. background: rgb(122, 122, 122);
  479. box-shadow: rgb(62 62 62) 0px -3px inset;
  480. color: rgb(255, 255, 255);
  481. cursor: pointer;
  482. width: 100%;
  483. border: none;
  484. border-radius: 5px;
  485. font-size: 18px;
  486. padding: 10px 20px;
  487. text-align: center;
  488. `;
  489. tt.innerHTML =
  490. "<option>Record</option><option>Replay recent</option><option>Replay from file</option><option>Replay from prompt</option><option>Tab/untab</option><option>save har log</option><option>silly 3d toggle</option><option>force solosquads toggle</option>";
  491. let captt = tt;
  492. tt.onchange = (e) => selmodech(captt, e, "change");
  493. tt.onclick = (e) => selmodech(captt, e, "click");
  494. x.appendChild(tt);
  495.  
  496. var tt = document.createElement("button");
  497. tt.style = `
  498. background-image: url(https://web.archive.org/web/20180606160509if_/surviv.io/img/gui/link.svg);
  499. background-size: 27px;
  500. background-repeat: no-repeat;
  501. background-position: center 42%;
  502. width: 100%;
  503. height: 45px;
  504. background-color: #cd3232;
  505. box-shadow: #781e0a 0px -4px inset;
  506. color: #fff;
  507. cursor: pointer;
  508. text-shadow: rgb(0 0 0 / 25%) 0px 1px 2px;
  509. border: none;
  510. border-radius: 5px;
  511. font-size: 18px;
  512. margin: 0 3px 0 0;
  513. `;
  514. tt.onclick = tabuntab;
  515. mn.appendChild(tt);
  516.  
  517. var tt = document.createElement("button");
  518. tt.innerHTML = "unlink & record";
  519. tt.style = `
  520. height: 45px;
  521. background-color: rgb(205, 50, 50);
  522. box-shadow: rgb(120 30 10) 0px -4px inset;
  523. color: rgb(255, 255, 255);
  524. cursor: pointer;
  525. text-shadow: rgb(0 0 0 / 25%) 0px 1px 2px;
  526. border: none;
  527. border-radius: 5px;
  528. font-size: 18px;
  529. width:300%;
  530. `;
  531. tt.onclick = unlinkfromUI;
  532. mn.appendChild(tt);
  533.  
  534. var tt = document.createElement("select");
  535. tt.id = "xyz";
  536. window.harRead.ui.matchSelectorComboBox = tt;
  537. tt.style =
  538. "background: rgb(122, 122, 122); box-shadow: rgb(62, 62, 62) 0px -2px inset; color: rgb(255, 255, 255); cursor: pointer; width: 100%; border: none; border-radius: 5px; font-size: 18px; padding: 5px 20px; margin: 5px 0px;";
  539. tt.style = `
  540. width: 100%;
  541. height: 45px;
  542. background-color: #7a7a7a;
  543. box-shadow: #3e3e3e 0px -4px inset;
  544. color: #fff;
  545. cursor: pointer;
  546. text-shadow: rgb(0 0 0 / 25%) 0px 1px 2px;
  547. border: none;
  548. border-radius: 5px;
  549. font-size: 18px;
  550. margin: 3px 0 3px 0;
  551. `;
  552. x.appendChild(tt);
  553. var t = document.createElement("input");
  554. t.type = "file";
  555. t.style = `
  556. position: absolute;
  557. margin: 62px 0 0 -126px;
  558. opacity: 0;
  559. cursor: pointer;
  560. transform: scale(2);
  561. `;
  562. t.multiple = true;
  563. t.accept = ".har";
  564. t.id = "ssk";
  565. x.appendChild(t);
  566. if (ifsurviv) {
  567. document.getElementById("missions-name").style = "display:none";
  568. document.getElementById("pass-quest-wrapper").style = "display:none";
  569. }
  570. var skk = document.createElement("button");
  571. skk.id = "skk";
  572. skk.onclick = function () {
  573. document.getElementById("ssk").click();
  574. };
  575. skk.innerHTML = "Choose file";
  576. skk.style =
  577. "background: rgb(30, 144, 255);box-shadow: rgb(24, 113, 200) 0px -5px inset;color: rgb(255, 255, 255);cursor: pointer;text-shadow: rgba(0, 0, 0, 0.25) 0px 1px 2px;font-weight: 700;width: 100%;border: none;border-radius: 5px;padding: 12px 20px;font-size: 18px;";
  578. x.appendChild(skk);
  579. tt.onchange = function () {
  580. harRead.selected = tt.value;
  581. };
  582.  
  583. let applySVGtext = function (nam, jo) {
  584. let ii = nam.indexOf("---");
  585. if (ii >= 0) nam = nam.slice(0, ii);
  586. let blob1 = new Blob([jo], {
  587. type: "image/svg+xml",
  588. });
  589. let url1 = URL.createObjectURL(blob1);
  590. nam = nam.replace(".svg", ".img");
  591. PIXI.utils.TextureCache[nam] = PIXI.Texture.fromImage(
  592. url1,
  593. undefined,
  594. undefined,
  595. 2
  596. );
  597. };
  598. let applyParsedHarFile = function (jo) {
  599. window.harRead.games = {};
  600.  
  601. window.harRead.files.push(jo);
  602. tt.innerHTML = "";
  603. if (1) {
  604. var ectr = 0;
  605. jo.log.entries.forEach((x) => {
  606. if (x.request.url.slice(0, 2) == "ws") {
  607. if (x._webSocketMessages.length < 2) return;
  608. var time =
  609. x._webSocketMessages.slice(-1)[0].time -
  610. x._webSocketMessages[0].time;
  611. time =
  612. ((time / 60) | 0) +
  613. ":" +
  614. String((time | 0) % 60).padStart(2, "0") +
  615. " ";
  616. console.log(time, x._webSocketMessages.length, x.request.url);
  617. var ww = x.request.url;
  618. var w0 = ww.lastIndexOf("=");
  619. var wi = ww.lastIndexOf("=");
  620.  
  621. if (w0 >= 0 || wi >= 0 || ww.includes(".snake.io:9092")) {
  622. var output = time;
  623. if (w0 >= 0 || wi >= 0)
  624. output += " " + ww.slice(6, 6 + 9) + ww.slice(wi);
  625. var qi = document.createElement("option");
  626. qi.value = ectr;
  627. qi.innerHTML = output + "";
  628. tt.appendChild(qi);
  629. harRead.games[ectr] = x;
  630. }
  631. }
  632. ectr += 1;
  633. });
  634. }
  635. };
  636. t.onchange = function handleFileSelect1(evt) {
  637. var filesreset = false;
  638. tt.innerHTML = "<option>loading...</option>";
  639. var files = evt.target.files;
  640. var output = [];
  641. for (var i = 0, f; (f = files[i]); i++) {
  642. if (f.name.slice(-4) == ".har" && !filesreset) {
  643. window.harRead.files = [];
  644. window.harRead.games = {};
  645. filesreset = true;
  646. }
  647. var fr = new FileReader();
  648. harRead.files.push(f);
  649. if (f.name.slice(-4) == ".har")
  650. fr.onload = function (evt) {
  651. if (evt.loaded == evt.total) {
  652. tt.innerHTML = "<option>parsing...</option>";
  653. try {
  654. var jo = JSON.parse(evt.currentTarget.result);
  655. } catch (e) {
  656. harRead.alert(
  657. "This file is not a valid .har file, or gabled/truncated"
  658. );
  659. }
  660. applyParsedHarFile(jo);
  661. }
  662. };
  663. else if (f.name.slice(-4) == ".svg") {
  664. let fname_temp = f.name;
  665. fr.onload = function (evt) {
  666. if (evt.loaded == evt.total) {
  667. applySVGtext(fname_temp, evt.currentTarget.result);
  668. }
  669. };
  670. } else
  671. harRead.alert(
  672. "I do not know what to do with " +
  673. f.name +
  674. "\nI expect .har or .svg files"
  675. );
  676. fr.readAsText(f);
  677. }
  678. console.log(output);
  679. };
  680. };
  681. if (document.readyState === "complete" || document.readyState === "interactive")
  682. foo();
  683. else window.addEventListener("DOMContentLoaded", foo);
  684.  
  685. function dosomething_with_send_disable() {
  686. cvs.style.transform = "";
  687. }
  688.  
  689. function dosomething_with_send(e) {
  690. if (survivharplayerconfig.silly1 != true) return;
  691.  
  692. let survivOneEps = 1.0001;
  693. function delerpOne10(e) {
  694. return (-1 + 2 * (e / 1023)) * survivOneEps;
  695. }
  696.  
  697. let x = from_base64s(e);
  698. try {
  699. let i = 3 + 3 * !!(x[2] & 0x80);
  700. let xdiv, ydiv;
  701. xdiv = x[i] + (x[i + 1] & 3) * 256;
  702. ydiv = (x[i + 1] >> 2) + (x[i + 2] & 15) * 64;
  703. let zlen = ((x[i + 2] >> 4) + (x[i+3]&15)*16)*64/255;
  704. xdiv = delerpOne10(xdiv);
  705. ydiv = delerpOne10(ydiv);
  706.  
  707. let az = Math.atan2(xdiv, ydiv);
  708. let cs = Math.cos(az);
  709. let sn = Math.sin(az);
  710. let pz = 1.25*Math.atan(zlen/28);
  711. let cz = Math.cos(pz);
  712. let zn = Math.sin(pz);
  713. cvs.style.transform = `perspective(800px) matrix3d(${cs}, ${-sn * cz}, ${
  714. -sn * zn
  715. }, 0, ${sn}, ${cs * cz}, ${
  716. cs * zn
  717. }, 0, 0, ${-zn}, ${cz}, 0, 0, 0, 0 , 1)`;
  718. } catch (e) {
  719. console.error(e);
  720. }
  721. }
  722.  
  723. function from_base64s(base64) {
  724. var raw = atob(base64);
  725. var rawLength = raw.length;
  726. var array = new Uint8Array(new ArrayBuffer(rawLength));
  727. for (let i = 0; i < rawLength; i++) {
  728. array[i] = raw.charCodeAt(i);
  729. }
  730. return array;
  731. }
  732.  
  733. function from_base64s_ab(base64) {
  734. var raw = atob(base64);
  735. var rawLength = raw.length;
  736. var arrayb = new ArrayBuffer(rawLength);
  737. var array = new Uint8Array(arrayb);
  738. for (let i = 0; i < rawLength; i++) {
  739. array[i] = raw.charCodeAt(i);
  740. }
  741. return arrayb;
  742. }
  743. if (1 && "weboverload") {
  744. ("var RecordingWebSocket");
  745. var oldWebSocket = window.WebSocket;
  746. var ReplayWebSocket = function (a) {
  747. console.info("ws creating:", a);
  748. if (a) a = a.replace("wss://", "ws://");
  749. this.sndwo = 0;
  750. if (a.indexOf("-p1.surviv.io") >= 0) {
  751. this.binaryType = "blob";
  752. this.stupidsum = this.static_counter + 4;
  753. this.static_counter = (this.static_counter + 3) % 19;
  754. this.url = a;
  755. this.__type = "echo";
  756. setTimeout(() => this.__onopen(), 100);
  757. } else if (a.includes("?gameId=") || a.includes(".snake.io:9092")) {
  758. this.__type = "game";
  759. this.wsh = harRead.games[window.harRead.ui.matchSelectorComboBox.value];
  760. this.wso = this.wsh["_webSocketMessages"];
  761. this.wslen = this.wso.length;
  762. this.wsi = 0;
  763. this.binaryType = "blob";
  764. this.url = a;
  765. setTimeout(() => this.__onopen(), 30);
  766. }
  767. };
  768. ReplayWebSocket.name = "ReplayWebSocket";
  769. ReplayWebSocket.prototype = {
  770. CONNECTING: 0,
  771. OPEN: 1,
  772. CLOSING: 2,
  773. CLOSED: 3,
  774. static_counter: 10,
  775. __onopen: function () {
  776. this.readyState = this.OPEN;
  777. this.onopen && this.onopen();
  778. },
  779. __onclose: function () {
  780. this.readyState = this.CLOSED;
  781. this.onclose && this.onclose();
  782. },
  783. __onmessage: function () {
  784. if (this.readyState != this.OPEN) return;
  785. this.onmessage &&
  786. this.onmessage({
  787. data: new Uint8Array(1),
  788. });
  789. },
  790. __onharmessage: function (e) {
  791. if (this.readyState != this.OPEN || !this.onmessage) return;
  792. try {
  793. this.onmessage(this.wsmsg);
  794. } catch (e) {
  795. console.error("onharmessage error");
  796. console.error(this.wsi);
  797. console.error(this.wsmsg);
  798. console.error(e);
  799. }
  800. if (this.nextmsg()) {
  801. } else "todo:close";
  802. },
  803. nextmsg: function () {
  804. while (++this.wsi < this.wslen) {
  805. if (this.wso[this.wsi].type == "receive") break;
  806. else if (this.wso[this.wsi].type == "send") {
  807. dosomething_with_send(this.wso[this.wsi].data);
  808. }
  809. }
  810. if (this.wsi >= this.wslen) return false;
  811. var a1 = this.wso[this.wsi];
  812. var datat = a1.data;
  813. this.wsmsg = {
  814. data: from_base64s_ab(datat),
  815. };
  816. let time =
  817. this.wso[this.wsi].time * 1000 +
  818. this.__timediff -
  819. new Date().getTime() * slowmo;
  820. if (time < -1000 || time > 4000) {
  821. this.__timediff =
  822. 30 - this.wso[this.wsi].time * 1000 + new Date().getTime() * slowmo;
  823. time = 30;
  824. }
  825. if (time > 1) setTimeout(() => this.__onharmessage(), time);
  826. else this.__onharmessage();
  827. return true;
  828. },
  829. send: function (a) {
  830. this.sndwo = 0;
  831. if (this.__type == "echo")
  832. setTimeout(() => this.__onmessage(), this.stupidsum);
  833. if (this.__type == "game")
  834. if (this.__starttime == undefined) {
  835. this.__starttime = new Date().getTime() + 100;
  836. this.__timediff = this.__starttime * slowmo - this.wso[0].time * 1000;
  837. this.nextmsg();
  838. }
  839. },
  840. close: function () {
  841. this.readyState = this.CLOSED;
  842. },
  843. };
  844. if(document.location.host.includes('web.archive')) window.WebSocket = ReplayWebSocket;
  845. }
  846.  
  847. let oraf=window.requestAnimationFrame;
  848. let wast=undefined;
  849.  
  850. window.requestAnimationFrame=function(user) {
  851. let temp=user;
  852. function mymethod(x) {
  853. if(wast==undefined) { wast=x; return user.call(this,x); }
  854. let tea=(window.slowmo??1);
  855. if(window.WebSocket.name!="ReplayWebSocket") tea=1;
  856.  
  857. return user.call(this,/*(x-wast)*(window.slowmo??1) + wast*/(x-wast)*tea );
  858. };
  859. oraf.call(this,mymethod);
  860. };
  861.  
  862. 0;
  863. }
  864. //nicer ui
  865. (function() {
  866. 'use strict';
  867. function GM_addStyle(cssStr){
  868.  
  869. var n = document.createElement('style');
  870. n.type = "text/css";
  871. n.innerHTML = cssStr;
  872. document.getElementsByTagName('head')[0].appendChild(n);
  873.  
  874. }
  875. // checkbox color (stole from sk :lmao:)
  876. // CSS
  877. GM_addStyle(`
  878. .ad-block-med-rect, .surviv-shirts {
  879. display: none !important;
  880. background: none !important;
  881. }
  882. `);
  883. })();