Surviv.io input replay recorder

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

当前为 2022-08-06 提交的版本,查看 最新版本

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