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