yolkbot 1.4.4 → 1.4.6

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (112) hide show
  1. package/browser/build/global.js +1 -1
  2. package/browser/build/module.js +1 -1
  3. package/dist/api.js +200 -1
  4. package/dist/bot/GamePlayer.js +74 -1
  5. package/dist/bot.js +1679 -1
  6. package/dist/comm/CommIn.js +79 -1
  7. package/dist/comm/CommOut.js +60 -1
  8. package/dist/comm/index.js +11 -1
  9. package/dist/constants/CloseCode.js +27 -1
  10. package/dist/constants/CommCode.js +53 -1
  11. package/dist/constants/challenges.js +1821 -1
  12. package/dist/constants/findItemById.js +2 -3
  13. package/dist/constants/guns.js +277 -1
  14. package/dist/constants/index.js +139 -1
  15. package/dist/constants/items.js +45042 -1
  16. package/dist/constants/maps.js +1263 -1
  17. package/dist/constants/regions.js +30 -1
  18. package/dist/dispatches/BanPlayerDispatch.js +32 -1
  19. package/dist/dispatches/BootPlayerDispatch.js +21 -1
  20. package/dist/dispatches/ChatDispatch.js +32 -1
  21. package/dist/dispatches/FireDispatch.js +15 -1
  22. package/dist/dispatches/GameOptionsDispatch.js +66 -1
  23. package/dist/dispatches/GoToAmmoDispatch.js +38 -1
  24. package/dist/dispatches/GoToCoopDispatch.js +38 -1
  25. package/dist/dispatches/GoToGrenadeDispatch.js +38 -1
  26. package/dist/dispatches/GoToPlayerDispatch.js +39 -1
  27. package/dist/dispatches/GoToSpatulaDispatch.js +26 -1
  28. package/dist/dispatches/LookAtDispatch.js +35 -1
  29. package/dist/dispatches/LookAtPosDispatch.js +29 -1
  30. package/dist/dispatches/MeleeDispatch.js +26 -1
  31. package/dist/dispatches/MovementDispatch.js +26 -1
  32. package/dist/dispatches/PauseDispatch.js +18 -1
  33. package/dist/dispatches/ReloadDispatch.js +28 -1
  34. package/dist/dispatches/ReportPlayerDispatch.js +42 -1
  35. package/dist/dispatches/ResetGameDispatch.js +19 -1
  36. package/dist/dispatches/SaveLoadoutDispatch.js +105 -1
  37. package/dist/dispatches/SpawnDispatch.js +22 -1
  38. package/dist/dispatches/SwapWeaponDispatch.js +25 -1
  39. package/dist/dispatches/SwitchTeamDispatch.js +33 -1
  40. package/dist/dispatches/ThrowGrenadeDispatch.js +21 -1
  41. package/dist/dispatches/index.js +74 -1
  42. package/dist/env/fetch.js +97 -10
  43. package/dist/env/globals.js +15 -1
  44. package/dist/index.js +14 -2
  45. package/dist/matchmaker.js +141 -1
  46. package/dist/pathing/astar.js +55 -1
  47. package/dist/pathing/binaryheap.js +79 -1
  48. package/dist/pathing/mapnode.js +179 -1
  49. package/dist/socket.js +97 -1
  50. package/dist/util.js +68 -1
  51. package/dist/wasm/bytes.js +8 -1
  52. package/dist/wasm/direct.js +84 -1
  53. package/dist/wasm/legacy.js +170 -1
  54. package/dist/wasm/util.js +19 -1
  55. package/package.json +38 -39
  56. /package/dist/{types/api.d.ts → api.d.ts} +0 -0
  57. /package/dist/{types/bot → bot}/GamePlayer.d.ts +0 -0
  58. /package/dist/{types/bot.d.ts → bot.d.ts} +0 -0
  59. /package/dist/{types/comm → comm}/CommIn.d.ts +0 -0
  60. /package/dist/{types/comm → comm}/CommOut.d.ts +0 -0
  61. /package/dist/{types/comm → comm}/index.d.ts +0 -0
  62. /package/dist/{types/constants → constants}/CloseCode.d.ts +0 -0
  63. /package/dist/{types/constants → constants}/CommCode.d.ts +0 -0
  64. /package/dist/{types/constants → constants}/challenges.d.ts +0 -0
  65. /package/dist/{types/constants → constants}/changelog.d.ts +0 -0
  66. /package/dist/{types/constants → constants}/findItemById.d.ts +0 -0
  67. /package/dist/{types/constants → constants}/guns.d.ts +0 -0
  68. /package/dist/{types/constants → constants}/housePromo.d.ts +0 -0
  69. /package/dist/{types/constants → constants}/index.d.ts +0 -0
  70. /package/dist/{types/constants → constants}/items.d.ts +0 -0
  71. /package/dist/{types/constants → constants}/language.d.ts +0 -0
  72. /package/dist/{types/constants → constants}/maps.d.ts +0 -0
  73. /package/dist/{types/constants → constants}/notices.d.ts +0 -0
  74. /package/dist/{types/constants → constants}/regions.d.ts +0 -0
  75. /package/dist/{types/constants → constants}/shellNews.d.ts +0 -0
  76. /package/dist/{types/constants → constants}/shellYoutube.d.ts +0 -0
  77. /package/dist/{types/constants → constants}/shopItems.d.ts +0 -0
  78. /package/dist/{types/constants → constants}/sounds.d.ts +0 -0
  79. /package/dist/{types/dispatches → dispatches}/BanPlayerDispatch.d.ts +0 -0
  80. /package/dist/{types/dispatches → dispatches}/BootPlayerDispatch.d.ts +0 -0
  81. /package/dist/{types/dispatches → dispatches}/ChatDispatch.d.ts +0 -0
  82. /package/dist/{types/dispatches → dispatches}/FireDispatch.d.ts +0 -0
  83. /package/dist/{types/dispatches → dispatches}/GameOptionsDispatch.d.ts +0 -0
  84. /package/dist/{types/dispatches → dispatches}/GoToAmmoDispatch.d.ts +0 -0
  85. /package/dist/{types/dispatches → dispatches}/GoToCoopDispatch.d.ts +0 -0
  86. /package/dist/{types/dispatches → dispatches}/GoToGrenadeDispatch.d.ts +0 -0
  87. /package/dist/{types/dispatches → dispatches}/GoToPlayerDispatch.d.ts +0 -0
  88. /package/dist/{types/dispatches → dispatches}/GoToSpatulaDispatch.d.ts +0 -0
  89. /package/dist/{types/dispatches → dispatches}/LookAtDispatch.d.ts +0 -0
  90. /package/dist/{types/dispatches → dispatches}/LookAtPosDispatch.d.ts +0 -0
  91. /package/dist/{types/dispatches → dispatches}/MeleeDispatch.d.ts +0 -0
  92. /package/dist/{types/dispatches → dispatches}/MovementDispatch.d.ts +0 -0
  93. /package/dist/{types/dispatches → dispatches}/PauseDispatch.d.ts +0 -0
  94. /package/dist/{types/dispatches → dispatches}/ReloadDispatch.d.ts +0 -0
  95. /package/dist/{types/dispatches → dispatches}/ReportPlayerDispatch.d.ts +0 -0
  96. /package/dist/{types/dispatches → dispatches}/ResetGameDispatch.d.ts +0 -0
  97. /package/dist/{types/dispatches → dispatches}/SaveLoadoutDispatch.d.ts +0 -0
  98. /package/dist/{types/dispatches → dispatches}/SpawnDispatch.d.ts +0 -0
  99. /package/dist/{types/dispatches → dispatches}/SwapWeaponDispatch.d.ts +0 -0
  100. /package/dist/{types/dispatches → dispatches}/SwitchTeamDispatch.d.ts +0 -0
  101. /package/dist/{types/dispatches → dispatches}/ThrowGrenadeDispatch.d.ts +0 -0
  102. /package/dist/{types/dispatches → dispatches}/index.d.ts +0 -0
  103. /package/dist/{types/matchmaker.d.ts → matchmaker.d.ts} +0 -0
  104. /package/dist/{types/pathing → pathing}/astar.d.ts +0 -0
  105. /package/dist/{types/pathing → pathing}/binaryheap.d.ts +0 -0
  106. /package/dist/{types/pathing → pathing}/mapnode.d.ts +0 -0
  107. /package/dist/{types/socket.d.ts → socket.d.ts} +0 -0
  108. /package/dist/{types/util.d.ts → util.d.ts} +0 -0
  109. /package/dist/{types/wasm → wasm}/bytes.d.ts +0 -0
  110. /package/dist/{types/wasm → wasm}/direct.d.ts +0 -0
  111. /package/dist/{types/wasm → wasm}/legacy.d.ts +0 -0
  112. /package/dist/{types/wasm → wasm}/util.d.ts +0 -0
package/dist/bot.js CHANGED
@@ -1 +1,1679 @@
1
- import y from"./api.js";import J from"./comm/CommIn.js";import R from"./comm/CommOut.js";import d from"./constants/CloseCode.js";import $ from"./constants/CommCode.js";import T from"./bot/GamePlayer.js";import s from"./matchmaker.js";import n from"./socket.js";import{ChiknWinnerDailyLimit as t,CollectType as C,CoopState as k,findItemById as V,FramesBetweenSyncs as z,GameAction as x,GameMode as O,GameOptionFlag as o,GunList as p,ItemType as r,Movement as B,PlayType as v,ShellStreak as K,StateBufferSize as b}from"./constants/index.js";import h from"./dispatches/LookAtPosDispatch.js";import D from"./dispatches/MovementDispatch.js";import l from"./env/globals.js";import{NodeList as a}from"./pathing/mapnode.js";import{coords as e}from"./wasm/direct.js";import{fetchMap as jj,initKotcZones as Ej}from"./util.js";import{Challenges as Jj}from"./constants/challenges.js";import{Maps as I}from"./constants/maps.js";import{Regions as u}from"./constants/regions.js";const c=Object.fromEntries(Object.entries(O).map(([E,j])=>[j,E])),m=Object.fromEntries(Object.entries(o).map(([E,j])=>[E[0].toLowerCase()+E.slice(1),j])),g={CHALLENGES:1,BOT_STATS:2,PATHFINDING:3,PING:5,COSMETIC_DATA:6,PLAYER_HEALTH:7,PACKET_HOOK:8,LOG_PACKETS:10,NO_LOGIN:11,DEBUG_BUFFER:12,NO_AFK_KICK:16,LOAD_MAP:17,OBSERVE_GAME:18,NO_REGION_CHECK:19,NO_EXIT_ON_ERROR:20,RENEW_SESSION:21,VIP_HIDE_BADGE:22},f=(E,j)=>(E%j+j)%j;export class Bot{static Intents=g;Intents=g;#J=[];#j={};#Q=[];#E;#U;constructor(E={}){if(E.proxy&&l.isBrowser)this.processError("proxies do not work and hence are not supported in the browser");this.intents=E.intents||[];if(this.intents.includes(this.Intents.COSMETIC_DATA)){if(!V(1001))this.processError("you cannot use the COSMETIC_DATA intent inside of the singlefile browser bundles")}this.instance=E.instance||"shellshock.io";this.protocol=E.protocol||"wss";this.proxy=E.proxy||"";this.connectionTimeout=E.connectionTimeout||5000;this.state={name:"yolkbot",weaponIdx:0,useAltGameURL:!1,inGame:!1,chatLines:0,yaw:0,pitch:0,controlKeys:0,reloading:!1,swappingGun:!1,usingMelee:!1,stateIdx:0,serverStateIdx:0,shotsFired:0,buffer:[],left:!1};this.players={};this.me=new T({});this.game={raw:{},code:"",socket:null,gameModeId:0,gameMode:c[0],mapIdx:0,map:{filename:"",hash:"",name:"",modes:{FFA:!1,Teams:!1,Spatula:!1,King:!1},availability:"both",numPlayers:"18",raw:{},nodes:{},zones:[]},playerLimit:0,isGameOwner:!1,isPrivate:!0,options:{gravity:1,damage:1,healthRegen:1,locked:!1,noTeamChange:!1,noTeamShuffle:!1,weaponsDisabled:Array(7).fill(!1),mustUseSecondary:!1},collectables:[[],[]],teamScore:[0,0,0],spatula:{coords:{x:0,y:0,z:0},controlledBy:0,controlledByTeam:0},stage:k.Capturing,zoneNumber:0,activeZone:[],capturing:0,captureProgress:0,numCapturing:0,capturePercent:0};this.#U=this.game;this.account={id:0,firebase:{idToken:"",refreshToken:"",expiresIn:"3600",localId:""},firebaseId:"",sessionId:"",session:0,email:"",password:"",cw:{atLimit:!1,limit:0,secondsUntilPlay:0,canPlayAgain:Date.now()},loadout:{hatId:null,meleeId:0,stampId:null,classIdx:0,colorIdx:0,grenadeId:0,primaryId:[3100,3600,3400,3800,4000,4200,4500],secondaryId:Array(7).fill(3000),stampPositionX:0,stampPositionY:0},ownedItemIds:[],vip:!1,emailVerified:!1,isAged:!1,eggBalance:0,adminRoles:0,rawLoginData:{},isDoubleEggWeeknd:()=>{const j=new Date().getUTCDay(),M=new Date().getUTCHours();return j>=5&&M>=20||j===6||j===0}};this.#E=this.account;this.matchmaker=null;this.api=new y({proxy:this.proxy,protocol:this.protocol,instance:this.instance,maxRetries:E?.apiMaxRetries,connectionTimeout:this.connectionTimeout});this.ping=0;this.lastPingTime=-1;this.lastDeathTime=-1;this.lastUpdateTick=0;this.pathing={nodeList:null,followingPath:!1,activePath:null,activeNode:null,activeNodeIdx:0};this.hasQuit=!1;if(this.intents.includes(this.Intents.NO_AFK_KICK))this.afkKickInterval=0;if(this.intents.includes(this.Intents.RENEW_SESSION))this.renewSessionInterval=0}dispatch(E){if(E.validate(this)){if(E.check(this))E.execute(this);else this.#J.push(E);return!0}return!1}async createAccount(E,j){this.account=this.#E;this.account.email=E;this.account.password=j;const M=await this.api.createAccount(E,j);return this.processLoginData(M)}async login(E,j){this.account=this.#E;this.account.email=E;this.account.password=j;const M=await this.api.loginWithCredentials(E,j);return this.processLoginData(M)}async loginWithRefreshToken(E){this.account=this.#E;const j=await this.api.loginWithRefreshToken(E);return this.processLoginData(j)}async loginAnonymously(){this.account=this.#E;const E=await this.api.loginAnonymously();return this.processLoginData(E)}processLoginData(E){if(typeof E!=="object"){this.emit("authFail",E);return E}if(E.banRemaining){this.emit("banned",E.banRemaining);return"account_banned"}if(!E.playerOutput){this.emit("authFail",E);return E}this.account.firebase=E.firebase||{};E=E.playerOutput;this.account.rawLoginData=E;this.account.adminRoles=E.adminRoles||0;this.account.eggBalance=E.currentBalance;this.account.emailVerified=E.emailVerified;this.account.firebaseId=E.firebaseId;this.account.id=E.id;this.account.isAged=new Date(E.dateCreated).getTime()<1714546800000;this.account.loadout=E.loadout;this.account.ownedItemIds=E.ownedItemIds;this.account.session=E.session;this.account.sessionId=E.sessionId;this.account.vip=E.active_sub==="IsVIP";if(this.intents.includes(this.Intents.BOT_STATS))this.account.stats={lifetime:E.statsLifetime,monthly:E.statsCurrent};if(this.intents.includes(this.Intents.CHALLENGES))this.#M(E.challenges);this.emit("authSuccess",this.account);if(this.intents.includes(this.Intents.RENEW_SESSION))this.renewSessionInterval=setInterval(async()=>{if(!this.account?.sessionId)return clearInterval(this.renewSessionInterval);if((await this.api.queryServices({cmd:"renewSession",sessionId:this.account.sessionId})).data!=="renewed")this.emit("sessionExpired")},600000);return this.account}#M(E){this.account.challenges=[];for(const j of E){const M=Jj.find((Q)=>Q.id===j.challengeId);if(!M)continue;delete j.playerId;this.account.challenges.push({raw:{challengeInfo:M,challengeData:j},id:j.challengeId,name:M.loc.title,desc:M.loc.desc,rewardEggs:M.reward,isRerolled:!!j.reset,isClaimed:!!j.claimed,isCompleted:!!j.completed,progressNum:j.progress,goalNum:M.goal})}}async initMatchmaker(){if(!this.account.sessionId&&!this.intents.includes(this.Intents.NO_LOGIN)){const E=await this.loginAnonymously();if(typeof E!=="object")return E}if(!this.matchmaker){this.matchmaker=new s({api:this.api,proxy:this.proxy,protocol:this.protocol,instance:this.instance,sessionId:this.account.sessionId,connectionTimeout:this.connectionTimeout,noLogin:this.intents.includes(this.Intents.NO_LOGIN)});if(!await this.matchmaker.ws.tryConnect())return"matchmaker_tryconnect_failed";this.matchmaker.on("authFail",(j)=>this.emit("authFail",j));this.matchmaker.on("error",(j)=>this.processError(j))}return!0}async findPublicGame(E,j){if(typeof E!=="string")return"no_region_passed";if(!u.find((Q)=>Q.id===E)&&!this.intents.includes(this.Intents.NO_REGION_CHECK))return"invalid_region_passed";if(typeof j!=="number")return"no_mode_passed";if(Object.values(O).indexOf(j)===-1)return"invalid_mode_passed";if(!await this.initMatchmaker())return"matchmaker_init_fail";return await new Promise((Q)=>{const _=(U)=>{if(U.command==="notice")return;this.matchmaker.off("msg",_);if(U.command==="gameFound"){if(U.useAltGameURL)this.state.useAltGameURL=!0;return Q(U)}if(U.error==="sessionNotFound")return Q("internal_session_error");this.processError("unknown matchmaker response",JSON.stringify(U))};this.matchmaker.on("msg",_);this.matchmaker.send({command:"findGame",region:E,playType:v.JoinPublic,gameType:j,sessionId:this.account.sessionId})})}async createPrivateGame(E,j,M){if(typeof E!=="string")return"no_region_passed";if(!u.find((U)=>U.id===E)&&!this.intents.includes(this.Intents.NO_REGION_CHECK))return"invalid_region_passed";if(typeof j!=="number")return"no_mode_passed";if(Object.values(O).indexOf(j)===-1)return"invalid_mode_passed";if(typeof M!=="string")return"no_map_passed";const Q=I.findIndex((U)=>U.name.toLowerCase()===M.toLowerCase());if(Q===-1)return"invalid_map_passed";if(!await this.initMatchmaker())return"matchmaker_init_fail";return await new Promise((U)=>{const q=(L)=>{if(L.command==="notice")return;this.matchmaker.off("msg",q);if(L.command==="gameFound"){if(L.useAltGameURL)this.state.useAltGameURL=!0;return U(L)}if(L.error==="sessionNotFound")return U("internal_session_error");this.processError("unknown matchmaker response",JSON.stringify(L))};this.matchmaker.on("msg",q);this.matchmaker.send({command:"findGame",region:E,playType:v.CreatePrivate,gameType:j,sessionId:this.account.sessionId,noobLobby:!1,map:Q})})}async join(E,j){this.state.name=E||"yolkbot";if(typeof j==="string"){if(j.includes("#"))j=j.split("#")[1];if(!await this.initMatchmaker())return"matchmaker_init_fail";if(await new Promise((U)=>{const q=(L)=>{if(L.command==="gameFound"){this.matchmaker.off("msg",q);this.game.raw=L;this.game.code=L.id;U(L.id)}if(L.error&&L.error==="gameNotFound"){this.processError(`game "${j}" not found, it may have expired.`);this.leave();return"gameNotFound"}};this.matchmaker.on("msg",q);this.matchmaker.send({command:"joinGame",id:j,observe:!1,sessionId:this.account.sessionId})})==="gameNotFound")return"game_not_found";if(!this.game.raw.id)return this.processError("an internal error occured while joining the game, please report this to developers")}if(typeof j==="object"){if(this.account.id===0)await this.loginAnonymously();this.game.raw=j;this.game.code=this.game.raw.id;if(!this.game.raw.id)return"invalid_game_object";if(!this.game.raw.subdomain)return"invalid_game_object";if(!this.game.raw.uuid)return"invalid_game_object"}const M=this.state.useAltGameURL?`${this.instance}/servers/${this.game.raw.subdomain}`:`${this.game.raw.subdomain}.${this.instance}`;this.game.socket=new n(`${this.protocol}://${M}/game/${this.game.raw.id}`,this.proxy);this.game.socket.binaryType="arraybuffer";this.game.socket.connectionTimeout=this.connectionTimeout;this.game.socket.onBeforeConnect=()=>{this.game.socket.onmessage=(_)=>this.processPacket(_.data);this.game.socket.onclose=(_)=>{if(this.state.left)this.state.left=!1;else{this.emit("close",_.code);this.leave(-1)}}};if(!await this.game.socket.tryConnect())return"websocket_tryconnect_fail";return!0}#_(){if(Object.entries(this.me.position).map((j)=>Math.floor(j[1])).join(",")===this.pathing.activePath[this.pathing.activePath.length-1].positionStr){this.pathing.followingPath=!1;this.pathing.activePath=null;this.pathing.activeNode=null;this.pathing.activeNodeIdx=0;this.dispatch(new D(0))}else{let j;if(this.pathing.activeNodeIdx<this.pathing.activePath.length-1){j=this.pathing.activePath[this.pathing.activeNodeIdx+1].flatCenter();this.dispatch(new h(j))}else{j=this.pathing.activePath[this.pathing.activeNodeIdx].flatCenter();this.dispatch(new h(j))}for(const M of this.pathing.activePath)if(M.flatRadialDistance(this.me.position)<0.1&&M.position.y===Math.floor(this.me.position.y)){if(this.pathing.activePath.indexOf(M)>=this.pathing.activeNodeIdx){this.pathing.activeNodeIdx=this.pathing.activePath.indexOf(M)+1;this.pathing.activeNode=this.pathing.activePath[this.pathing.activeNodeIdx];break}}if(!(this.state.controlKeys&B.Forward))this.dispatch(new D(B.Forward))}}update(){if(this.hasQuit)return;if(this.pathing.followingPath&&this.intents.includes(this.Intents.PATHFINDING))this.#_();for(let j=0;j<this.#J.length;j++){const M=this.#J[j];if(M.check(this)){M.execute(this);this.#J.splice(j,1)}}this.state.chatLines=Math.max(0,this.state.chatLines-0.008333333333333333);if(this.me.playing){const j=this.state.stateIdx;if(this.intents.includes(this.Intents.DEBUG_BUFFER)){console.log("setting buffer for idx",j);console.log("checking...shotsFired",this.state.shotsFired)}this.me.jumping=!!(this.state.controlKeys&B.Jump);this.state.buffer[j]={controlKeys:this.state.controlKeys,yaw:this.state.yaw,pitch:this.state.pitch,shotsFired:this.state.shotsFired};this.state.shotsFired=0;if(this.lastUpdateTick>=2){this.emit("tick");const M=new R;M.packInt8($.syncMe);M.packInt8(this.state.stateIdx);M.packInt8(this.state.serverStateIdx);const Q=f(this.state.stateIdx-z+1,b);for(let _=0;_<z;_++){const U=f(Q+_,b),q=this.state.buffer[U]||{},L=q.controlKeys||0,N=q.shotsFired||0,H=q.yaw??this.state.yaw,S=q.pitch??this.state.pitch;if(this.intents.includes(this.Intents.DEBUG_BUFFER))console.log("going with",this.state.stateIdx,Q,U,q);M.packInt8(L);M.packInt8(N);M.packString(e(H,S));M.packInt8(100)}M.send(this.game.socket);this.state.buffer=[];this.lastUpdateTick=0}else this.lastUpdateTick++;this.state.stateIdx=f(this.state.stateIdx+1,b)}if(!this.intents.includes(this.Intents.PLAYER_HEALTH))return;const E=0.1*(this.game.isPrivate?this.game.options.healthRegen:1);for(const j of Object.values(this.players)){if(j.playing&&j.hp>0){const M=j.streakRewards.includes(K.OverHeal);j.hp+=M?-E:E;j.hp=M?Math.max(100,j.hp):Math.min(100,j.hp)}if(j.spawnShield>0)j.spawnShield-=6}}on(E,j){if(Object.keys(this.#j).includes(E))this.#j[E].push(j);else this.#j[E]=[j]}once(E,j){const M=(...Q)=>{j(...Q);this.off(E,M)};this.on(E,M)}onAny(E){this.#Q.push(E)}off(E,j){if(j)this.#j[E]=this.#j[E].filter((M)=>M!==j);else this.#j[E]=[]}emit(E,...j){if(this.hasQuit)return;if(this.#j[E])for(const M of this.#j[E])M(...j);for(const M of this.#Q)M(E,...j)}#$(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=J.unPackString().valueOf(),Q=this.players[E];this.emit("chat",Q,M,j)}#q(){const E=J.unPackInt8U(),j=this.intents.includes(this.Intents.COSMETIC_DATA),M={id:E,uniqueId:J.unPackString(),name:J.unPackString(),safeName:J.unPackString(),charClass:J.unPackInt8U(),team:J.unPackInt8U(),primaryWeaponItem:j?V(J.unPackInt16U()):J.unPackInt16U(),secondaryWeaponItem:j?V(J.unPackInt16U()):J.unPackInt16U(),shellColor:J.unPackInt8U(),hatItem:j?V(J.unPackInt16U()):J.unPackInt16U(),stampItem:j?V(J.unPackInt16U()):J.unPackInt16U(),stampPosX:J.unPackInt8(),stampPosY:J.unPackInt8(),grenadeItem:j?V(J.unPackInt16U()):J.unPackInt16U(),meleeItem:j?V(J.unPackInt16U()):J.unPackInt16U(),x:J.unPackFloat(),y:J.unPackFloat(),z:J.unPackFloat(),$dx:J.unPackFloat(),$dy:J.unPackFloat(),$dz:J.unPackFloat(),yaw:J.unPackRadU(),pitch:J.unPackRad(),score:J.unPackInt32U(),$kills:J.unPackInt16U(),$deaths:J.unPackInt16U(),$streak:J.unPackInt16U(),totalKills:J.unPackInt32U(),totalDeaths:J.unPackInt32U(),bestStreak:J.unPackInt16U(),$bestOverallStreak:J.unPackInt16U(),shield:J.unPackInt8U(),hp:J.unPackInt8U(),playing:J.unPackInt8U(),weaponIdx:J.unPackInt8U(),$controlKeys:J.unPackInt8U(),upgradeProductId:J.unPackInt8U(),activeShellStreaks:J.unPackInt8U(),social:J.unPackLongString(),hideBadge:J.unPackInt8U()};this.game.mapIdx=J.unPackInt8U();this.game.isPrivate=J.unPackInt8U()===1;this.game.gameModeId=J.unPackInt8U();const Q=new T(M,this.game.gameMode===O.KOTC?this.game.activeZone:null);if(!this.players[M.id])this.players[M.id]=Q;this.emit("playerJoin",Q);if(this.me.id===M.id){this.me=Q;this.emit("botJoin",this.me)}}#L(){const E=J.unPackInt8U(),j=J.unPackInt16U(),M=J.unPackFloat(),Q=J.unPackFloat(),_=J.unPackFloat(),U=J.unPackInt8U(),q=J.unPackInt8U(),L=J.unPackInt8U(),N=J.unPackInt8U(),H=J.unPackInt8U(),S=this.players[E];if(S){S.playing=!0;S.randomSeed=j;if(S.weapons[0]&&S.weapons[0].ammo)S.weapons[0].ammo.rounds=U;if(S.weapons[0]&&S.weapons[0].ammo)S.weapons[0].ammo.store=q;if(S.weapons[1]&&S.weapons[1].ammo)S.weapons[1].ammo.rounds=L;if(S.weapons[1]&&S.weapons[1].ammo)S.weapons[1].ammo.store=N;S.grenades=H;S.position={x:M,y:Q,z:_};S.spawnShield=120;this.emit("playerRespawn",S)}}#S(){const E=J.unPackInt8U(),j=J.unPackFloat(),M=J.unPackFloat(),Q=J.unPackFloat(),_=J.unPackInt8U(),U=this.players[E];if(!U||U.id===this.me.id){for(let X=0;X<z;X++){J.unPackInt8U();J.unPackRadU();J.unPackRad();J.unPackInt8U()}return}for(let X=0;X<z;X++){const P=J.unPackInt8U();if(P&B.Jump)U.jumping=!0;else U.jumping=!1;if(P&B.Scope)U.scoping=!0;else U.scoping=!1;const Z={...U.view};U.view.yaw=J.unPackRadU();U.view.pitch=J.unPackRad();if(U.view.yaw!==Z.yaw||U.view.pitch!==Z.pitch)this.emit("playerRotate",U,Z,U.view);U.scale=J.unPackInt8U()}const q=U.position,L=q.x!==j||q.y!==M||q.z!==Q,N=U.climbing!==_,H=L||N,S=H?{...q}:null;if(q.x!==j)q.x=j;if(q.z!==Q)q.z=Q;if(!U.jumping||Math.abs(q.y-M)>0.5)q.y=M;if(N)U.climbing=_;if(!H)return;this.emit("playerMove",U,S,q);if(this.game.gameModeId!==O.KOTC)return;const F=this.game.activeZone,A=!!U.inKotcZone;if(!F&&A){U.inKotcZone=!1;this.emit("playerLeaveZone",U);return}U.updateKotcZone(F);const Y=!!U.inKotcZone;if(A!==Y){U.inKotcZone=Y;this.emit(Y?"playerEnterZone":"playerLeaveZone",U)}}#G(){const E=J.unPackInt8U(),j=this.players[E];if(j){j.playing=!1;if(j.streakRewards)j.streakRewards=[];this.emit("playerPause",j);if(j.inKotcZone){j.inKotcZone=!1;this.emit("playerLeaveZone",j)}}}#K(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=this.players[E];if(M){M.activeGun=j;this.emit("playerSwapWeapon",M,j)}}#O(){const E=J.unPackInt8U(),j=J.unPackInt8U();J.unPackInt8U();J.unPackInt8U();const M=J.unPackInt8U(),Q=this.players[E],_=this.players[j],U=Q?{...Q}:null;if(Q){if(Q.id===this.me.id)this.lastDeathTime=Date.now();Q.playing=!1;Q.streak=0;Q.hp=100;Q.spawnShield=0;Q.stats.totalDeaths++;Q.inKotcZone=!1;this.emit("playerLeaveZone",Q)}if(_){_.streak++;_.stats.totalKills++;if(_.streak>_.stats.bestStreak)_.stats.bestStreak=_.streak}this.emit("playerDeath",Q,_,U,M)}#V(){const E=J.unPackInt8U(),j={posX:J.unPackFloat(),posY:J.unPackFloat(),posZ:J.unPackFloat(),dirX:J.unPackFloat(),dirY:J.unPackFloat(),dirZ:J.unPackFloat()},M=this.players[E];if(!M)return;const Q=M.weapons[M.activeGun];if(Q&&Q.ammo){Q.ammo.rounds--;this.emit("playerFire",M,Q,j)}}#N(){const E=J.unPackInt16U(),j=J.unPackInt8U(),M=J.unPackFloat(),Q=J.unPackFloat(),_=J.unPackFloat();this.game.collectables[j].push({id:E,x:M,y:Q,z:_});this.emit("spawnItem",j,{x:M,y:Q,z:_},E)}#F(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=J.unPackInt8U(),Q=J.unPackInt16U(),_=this.players[E];if(!_)return;this.game.collectables[j]=this.game.collectables[j].filter((U)=>U.id!==Q);if(j===C.Ammo){const U=_.weapons[M];if(U&&U.ammo){U.ammo.store=Math.min(U.ammo.storeMax,U.ammo.store+U.ammo.pickup);this.emit("playerCollectAmmo",_,U,Q)}}if(j===C.Grenade){_.grenades++;if(_.grenades>3)_.grenades=3;this.emit("playerCollectGrenade",_,Q)}}#H(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=this.players[E];if(!M)return;const Q=M.hp;M.hp=j;this.emit("playerDamage",M,Q,M.hp)}#R(){const E=J.unPackInt8U();J.unPackFloat();J.unPackFloat();const j=this.me.hp;this.me.hp=E;this.emit("playerDamage",this.me,j,this.me.hp)}#X(){const E=J.unPackInt8U(),j=this.players[E];J.unPackInt8U();const M=J.unPackInt8U(),Q=J.unPackFloat(),_=J.unPackFloat(),U=J.unPackFloat();this.me.climbing=!!J.unPackInt8U();J.unPackInt8U();J.unPackInt8U();if(!j)return;this.state.serverStateIdx=M;const q=j.position.x,L=j.position.y,N=j.position.z;j.position.x=Q;j.position.y=_;j.position.z=U;if(q!==Q||L!==_||N!==U)this.emit("playerMove",j,{x:q,y:L,z:N},{x:Q,y:_,z:U})}#Y(){const E=new R;E.packInt8($.eventModifier);E.send(this.game.socket)}#Z(){const E=J.unPackInt8U(),j={...this.players[E]};delete this.players[E];this.emit("playerLeave",j)}#B(){if(this.game.gameModeId===O.Spatula){const E={...this.game};this.game.teamScore[1]=J.unPackInt16U();this.game.teamScore[2]=J.unPackInt16U();const j={x:J.unPackFloat(),y:J.unPackFloat(),z:J.unPackFloat()},M=J.unPackInt8U(),Q=J.unPackInt8U();this.game.spatula={coords:j,controlledBy:M,controlledByTeam:Q};this.emit("gameStateChange",E,this.game)}else if(this.game.gameModeId===O.KOTC){const E={...this.game};this.game.stage=J.unPackInt8U();this.game.zoneNumber=J.unPackInt8U();this.game.capturing=J.unPackInt8U();this.game.captureProgress=J.unPackInt16U();this.game.numCapturing=J.unPackInt8U();this.game.teamScore[1]=J.unPackInt8U();this.game.teamScore[2]=J.unPackInt8U();this.game.capturePercent=this.game.captureProgress/1000;this.game.activeZone=this.game.map.zones?this.game.map.zones[this.game.zoneNumber-1]:null;const j=Object.values(this.players).filter((M)=>M.inKotcZone&&M.playing);if(this.game.activeZone)Object.values(this.players).forEach((M)=>M.updateKotcZone(this.game.activeZone));if(this.game.numCapturing<=0)Object.values(this.players).forEach((M)=>{M.inKotcZone=!1;this.emit("playerLeaveZone",M)});this.emit("gameStateChange",E,this.game,j)}else if(this.game.gameModeId===O.Team){this.game.teamScore[1]=J.unPackInt16U();this.game.teamScore[2]=J.unPackInt16U()}if(this.game.gameModeId!==O.Spatula)delete this.game.spatula;if(this.game.gameModeId!==O.KOTC){delete this.game.stage;delete this.game.zoneNumber;delete this.game.capturing;delete this.game.captureProgress;delete this.game.numCapturing;delete this.game.numCapturing;delete this.game.activeZone}if(this.game.gameModeId===O.FFA)delete this.game.teamScore}#A(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=this.players[E];if(!M)return;switch(j){case K.HardBoiled:if(E===this.me.id)this.me.shieldHp=100;M.streakRewards.push(K.HardBoiled);break;case K.EggBreaker:M.streakRewards.push(K.EggBreaker);break;case K.Restock:{M.grenades=3;if(M.weapons[0]&&M.weapons[0].ammo){M.weapons[0].ammo.rounds=M.weapons[0].ammo.capacity;M.weapons[0].ammo.store=M.weapons[0].ammo.storeMax}if(M.weapons[1]&&M.weapons[1].ammo){M.weapons[1].ammo.rounds=M.weapons[1].ammo.capacity;M.weapons[1].ammo.store=M.weapons[1].ammo.storeMax}break}case K.OverHeal:M.hp=Math.min(200,M.hp+100);M.streakRewards.push(K.OverHeal);break;case K.DoubleEggs:M.streakRewards.push(K.DoubleEggs);break;case K.MiniEgg:M.scale=0.5;M.streakRewards.push(K.MiniEgg);break}this.emit("playerBeginStreak",M,j)}#P(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=this.players[E];if(!M)return;if([K.EggBreaker,K.OverHeal,K.DoubleEggs,K.MiniEgg].includes(j)&&M.streakRewards.includes(j))M.streakRewards=M.streakRewards.filter((_)=>_!==j);if(j===K.MiniEgg)M.scale=1;this.emit("playerEndStreak",M,j)}#z(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=J.unPackFloat(),Q=J.unPackFloat();if(!this.me)return;this.me.shieldHp=E;this.me.hp=j;if(this.me.shieldHp<=0){this.me.streakRewards=this.me.streakRewards.filter((_)=>_!==K.HardBoiled);this.emit("selfShieldLost",this.me.hp,{dx:M,dz:Q})}else this.emit("selfShieldHit",this.me.shieldHp,this.me.hp,{dx:M,dz:Q})}#T(){const E={...this.game.options};let j=J.unPackInt8U(),M=J.unPackInt8U(),Q=J.unPackInt8U();if(j<1||j>4)j=4;if(M<0||M>8)M=4;if(Q>16)Q=4;this.game.options.gravity=j/4;this.game.options.damage=M/4;this.game.options.healthRegen=Q/4;const _=J.unPackInt8U();Object.keys(m).forEach((U)=>{const q=_&m[U]?1:0;this.game.options[U]=q});this.game.options.weaponsDisabled=Array.from({length:7},()=>J.unPackInt8U()===1);this.game.options.mustUseSecondary=this.game.options.weaponsDisabled.every((U)=>U);this.emit("gameOptionsChange",E,this.game.options)}#b(){const E=J.unPackInt8U();if(E===x.Pause){this.emit("gameForcePause");setTimeout(()=>this.me.playing=!1,3000)}if(E===x.Reset){Object.values(this.players).forEach((j)=>j.streak=0);if(this.game.gameModeId!==O.FFA)this.game.teamScore=[0,0,0];if(this.game.gameModeId===O.Spatula){this.game.spatula.controlledBy=0;this.game.spatula.controlledByTeam=0;this.game.spatula.coords={x:0,y:0,z:0}}if(this.game.gameModeId===O.KOTC){this.game.stage=k.Capturing;this.game.zoneNumber=0;this.game.activeZone=null;this.game.capturing=0;this.game.captureProgress=0;this.game.numCapturing=0;this.game.capturePercent=0}this.emit("gameReset")}}#f(){if(!this.intents.includes(this.Intents.PING))return;const E=this.ping;this.ping=Date.now()-this.lastPingTime;this.emit("pingUpdate",E,this.ping);setTimeout(()=>{const j=new R;j.packInt8($.ping);j.send(this.game.socket);this.lastPingTime=Date.now()},1000)}#W(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=this.players[E];if(!M)return;const Q=M.team;M.team=j;M.streak=0;this.emit("playerSwitchTeam",M,Q,j)}#w(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=J.unPackInt16U(),Q=J.unPackInt16U(),_=J.unPackInt8U(),U=J.unPackInt16U(),q=J.unPackInt16U(),L=J.unPackInt16U(),N=J.unPackInt16U(),H=J.unPackInt8(),S=J.unPackInt8(),F=this.intents.includes(this.Intents.COSMETIC_DATA),A=F?V(M):M,Y=F?V(Q):Q,X=F?V(U):U,P=F?V(q):q,Z=F?V(L):L,i=F?V(N):N,G=this.players[E];if(G){const W={...G.character},w=G.selectedGun;G.character.eggColor=_;G.character.primaryGun=A;G.character.secondaryGun=Y;G.character.stamp=P;G.character.hat=X;G.character.grenade=Z;G.character.melee=i;G.character.stampPos.x=H;G.character.stampPos.y=S;G.selectedGun=j;G.weapons[0]=new p[j];if(w!==G.selectedGun)this.emit("playerChangeGun",G,w,G.selectedGun);if(W!==G.character)this.emit("playerChangeCharacter",G,W,G.character)}}#C(){const E=J.unPackInt32U(),j=this.account.eggBalance;this.account.eggBalance=E;this.emit("balanceUpdate",j,E)}#k(){this.me.playing=!1;this.emit("respawnDenied")}#x(){const E=J.unPackInt8U(),j=this.players[E];if(j)this.emit("playerMelee",j)}#v(){const E=J.unPackInt8U(),j=this.players[E];if(!j)return;const M=j.weapons[j.activeGun];if(M.ammo){const Q=Math.min(Math.min(M.ammo.capacity,M.ammo.reload)-M.ammo.rounds,M.ammo.store);M.ammo.rounds+=Q;M.ammo.store-=Q}this.emit("playerReload",j,M)}updateGameOptions(){const E=new R;E.packInt8($.gameOptions);E.packInt8(this.game.options.gravity*4);E.packInt8(this.game.options.damage*4);E.packInt8(this.game.options.healthRegen*4);const j=(this.game.options.locked?1:0)|(this.game.options.noTeamChange?2:0)|(this.game.options.noTeamShuffle?4:0);E.packInt8(j);this.game.options.weaponsDisabled.forEach((M)=>{E.packInt8(M?1:0)});E.send(this.game.socket)}#h(){this.game.isPrivate=!0;this.updateGameOptions()}#D(){const E=J.unPackInt8U();let j=J.unPackInt16U();const M=J.unPackFloat(),Q=J.unPackFloat(),_=J.unPackFloat(),U=J.unPackInt8U(),q=J.unPackFloat();if(this.intents.includes(this.Intents.COSMETIC_DATA))j=V(j);if(E===r.Grenade)this.emit("grenadeExplode",j,{x:M,y:Q,z:_},U,q);else this.emit("rocketHit",{x:M,y:Q,z:_},U,q)}#I(){const E=J.unPackInt8U(),j=J.unPackFloat(),M=J.unPackFloat(),Q=J.unPackFloat(),_=J.unPackFloat(),U=J.unPackFloat(),q=J.unPackFloat(),L=this.players[E];if(L){L.grenades--;this.emit("playerThrowGrenade",L,{x:j,y:M,z:Q},{x:_,y:U,z:q})}}#u(){const E=J.unPackInt8U(),j=J.unPackInt8U(),M=this.players[E];if(!M)return;if(!this.intents.includes(this.Intents.CHALLENGES))return this.emit("challengeComplete",M,j);const Q=this.account.challenges.find((_)=>_.id===j);this.emit("challengeComplete",M,Q);if(M.id===this.me.id)this.refreshChallenges()}#c(){const E=new R;E.packInt8(this.intents.includes(this.Intents.OBSERVE_GAME)?$.observeGame:$.joinGame);E.packString(this.game.raw.uuid);E.packInt8(+this.intents.includes(this.Intents.VIP_HIDE_BADGE));E.packInt8(this.state.weaponIdx||this.account?.loadout?.classIdx||0);E.packString(this.state.name);E.packInt32(this.account.session);E.packString(this.account.sessionId);E.packString(this.account.firebaseId);E.send(this.game.socket)}async#m(){this.me.id=J.unPackInt8U();this.me.team=J.unPackInt8U();this.game.gameModeId=J.unPackInt8U();this.game.gameMode=c[this.game.gameModeId];this.game.mapIdx=J.unPackInt8U();this.game.map=I[this.game.mapIdx];this.game.playerLimit=J.unPackInt8U();this.game.isGameOwner=J.unPackInt8U()===1;this.game.isPrivate=J.unPackInt8U()===1||this.game.isGameOwner;J.unPackInt8U();if(this.intents.includes(this.Intents.LOAD_MAP)||this.intents.includes(this.Intents.PATHFINDING)){this.game.map.raw=await jj(this.game.map.filename,this.game.map.hash);this.emit("mapLoad",this.game.map.raw);if(this.game.gameModeId===O.KOTC){const j=this.game.map.raw.data["DYNAMIC.capture-zone.none"];if(j){this.game.map.zones=Ej(j);if(!this.game.activeZone)this.game.activeZone=this.game.map.zones[this.game.zoneNumber-1]}else delete this.game.map.zones}if(this.intents.includes(this.Intents.PATHFINDING))this.pathing.nodeList=new a(this.game.map.raw)}this.state.inGame=!0;this.lastDeathTime=Date.now();const E=new R;E.packInt8($.clientReady);E.send(this.game.socket);this.updateIntervalId=setInterval(()=>this.update(),33.333333333333336);if(this.intents.includes(this.Intents.PING)){this.lastPingTime=Date.now();const j=new R;j.packInt8($.ping);j.send(this.game.socket)}if(this.intents.includes(this.Intents.NO_AFK_KICK))this.afkKickInterval=setInterval(()=>{if(this.state.inGame&&!this.me.playing&&Date.now()-this.lastDeathTime>=15000){const j=new R;j.packInt8($.keepAlive);j.send(this.game.socket)}},15000);this.emit("gameReady")}#g(){const E=J.unPackInt8U(),j=J.unPackString(128),M=J.unPackString(32),Q=this.players[E];if(!Q)return;Q.admin={ip:M,dbId:j};this.emit("playerInfo",Q,M,j)}packetHandlers={[$.syncThem]:()=>this.#S(),[$.fire]:()=>this.#V(),[$.hitThem]:()=>this.#H(),[$.syncMe]:()=>this.#X(),[$.hitMe]:()=>this.#R(),[$.swapWeapon]:()=>this.#K(),[$.collectItem]:()=>this.#F(),[$.respawn]:()=>this.#L(),[$.die]:()=>this.#O(),[$.pause]:()=>this.#G(),[$.chat]:()=>this.#$(),[$.addPlayer]:()=>this.#q(),[$.removePlayer]:()=>this.#Z(),[$.eventModifier]:()=>this.#Y(),[$.metaGameState]:()=>this.#B(),[$.beginShellStreak]:()=>this.#A(),[$.endShellStreak]:()=>this.#P(),[$.hitMeHardBoiled]:()=>this.#z(),[$.gameOptions]:()=>this.#T(),[$.ping]:()=>this.#f(),[$.switchTeam]:()=>this.#W(),[$.changeCharacter]:()=>this.#w(),[$.reload]:()=>this.#v(),[$.explode]:()=>this.#D(),[$.throwGrenade]:()=>this.#I(),[$.spawnItem]:()=>this.#N(),[$.melee]:()=>this.#x(),[$.updateBalance]:()=>this.#C(),[$.challengeCompleted]:()=>this.#u(),[$.socketReady]:()=>this.#c(),[$.gameJoined]:()=>this.#m(),[$.gameAction]:()=>this.#b(),[$.requestGameOptions]:()=>this.#h(),[$.respawnDenied]:()=>this.#k(),[$.playerInfo]:()=>this.#g(),[$.expireUpgrade]:()=>{},[$.clientReady]:()=>{},[$.musicInfo]:()=>J.unPackLongString()};processPacket(E){J.init(E);if(this.intents.includes(this.Intents.PACKET_HOOK))this.emit("packet",E);let j=0,M=0,Q=!1;while(J.isMoreDataAvailable()&&!Q){const _=J.unPackInt8U(),U=this.packetHandlers[_];if(U)U();else{console.error(`processPacket: I got but couldn't identify a: ${Object.keys($).find((q)=>$[q]===_)} ${_}`);if(j)console.error(`processPacket: It may be a result of the ${j} command (${M}).`);Q=!0;break}j=Object.keys($).find((q)=>$[q]===_);M=_;if(this.intents.includes(this.Intents.LOG_PACKETS))console.log(`[LOG_PACKETS] Packet ${j}: ${M}`)}}async checkChiknWinner(){const E=await this.api.queryServices({cmd:"chicknWinnerReady",id:this.account.id,sessionId:this.account.sessionId});if(typeof E==="string")return E;this.account.cw.limit=E.limit;this.account.cw.atLimit=E.limit>=4;this.account.cw.secondsUntilPlay=(this.account.cw.atLimit?E.period:E.span)||0;this.account.cw.canPlayAgain=Date.now()+this.account.cw.secondsUntilPlay*1000;return this.account.cw}async playChiknWinner(E=!0){if(this.account.cw.atLimit||this.account.cw.limit>t)return"hit_daily_limit";if(this.account.cw.canPlayAgain>Date.now()&&E)return"on_cooldown";const j=await this.api.queryServices({cmd:"incentivizedVideoReward",firebaseId:this.account.firebaseId,id:this.account.id,sessionId:this.account.sessionId,token:null});if(typeof j==="string")return j;if(j.error){if(j.error==="RATELIMITED"||j.error==="RATELMITED"){await this.checkChiknWinner();return"on_cooldown"}else if(j.error==="SESSION_EXPIRED"){this.emit("sessionExpired");return"session_expired"}console.error("Unknown Chikn Winner response, report this on Github:",j);return"unknown_error"}if(j.reward){this.account.eggBalance+=j.reward.eggsGiven;j.reward.itemIds.forEach((M)=>this.account.ownedItemIds.push(M));await this.checkChiknWinner();return j.reward}console.error("Unknown Chikn Winner response, report this on Github:",j);return"unknown_error"}async resetChiknWinner(){if(this.account.eggBalance<200)return"not_enough_eggs";if(!this.account.cw.atLimit)return"not_at_limit";const E=await this.api.queryServices({cmd:"chwReset",sessionId:this.account.sessionId});if(typeof E==="string")return E;if(E.result!=="SUCCESS"){console.error("Unknown Chikn Winner reset response, report this on Github:",E);return"unknown_error"}this.account.eggBalance-=200;await this.checkChiknWinner();return this.account.cw}canSee(E){if(!this.intents.includes(this.Intents.PATHFINDING))return this.processError("You must have the PATHFINDING intent to use this method.");return this.pathing.nodeList.hasLineOfSight(this.me.position,E.position)}async refreshChallenges(){const E=await this.api.queryServices({cmd:"challengeGetDaily",sessionId:this.account.sessionId,playerId:this.account.id});if(typeof E==="string")return E;this.#M(E);return this.account.challenges}async rerollChallenge(E){const j=await this.api.queryServices({cmd:"challengeRerollSlot",sessionId:this.account.sessionId,slotId:E});if(typeof j==="string")return j;this.#M(j);return this.account.challenges}async claimChallenge(E){const j=await this.api.queryServices({cmd:"challengeClaimReward",sessionId:this.account.sessionId,slotId:E});if(typeof j==="string")return j;this.#M(j.challenges);if(j.reward>0)this.account.eggBalance+=j.reward;return{eggReward:j.reward,updatedChallenges:this.account.challenges}}async refreshBalance(){const E=await this.api.queryServices({cmd:"checkBalance",firebaseId:this.account.firebaseId,sessionId:this.account.sessionId});if(typeof E==="string")return E;this.account.eggBalance=E.currentBalance;return E.currentBalance}async redeemCode(E){const j=await this.api.queryServices({cmd:"redeem",firebaseId:this.account.firebaseId,sessionId:this.account.sessionId,id:this.account.id,code:E});if(typeof j==="string")return j;if(j.result==="SUCCESS"){this.account.eggBalance=j.eggs_given;j.item_ids.forEach((M)=>this.account.ownedItemIds.push(M));return{result:j,eggsGiven:j.eggs_given,itemIds:j.item_ids}}return j}async claimURLReward(E){const j=await this.api.queryServices({cmd:"urlRewardParams",firebaseId:this.account.firebaseId,sessionId:this.account.sessionId,reward:E});if(typeof j==="string")return j;if(j.result==="SUCCESS"){this.account.eggBalance+=j.eggsGiven;j.itemIds.forEach((M)=>this.account.ownedItemIds.push(M))}return j}async claimSocialReward(E){const j=await this.api.queryServices({cmd:"reward",firebaseId:this.account.firebaseId,sessionId:this.account.sessionId,rewardTag:E});if(typeof j==="string")return j;if(j.result==="SUCCESS"){this.account.eggBalance+=j.eggsGiven;j.itemIds.forEach((M)=>this.account.ownedItemIds.push(M))}return j}async buyItem(E){const j=await this.api.queryServices({cmd:"buy",firebaseId:this.account.firebaseId,sessionId:this.account.sessionId,itemId:E,save:!0});if(typeof j==="string")return j;if(j.result==="SUCCESS"){this.account.eggBalance=j.currentBalance;this.account.ownedItemIds.push(j.itemId)}return j}processError(...E){const j=E.join(" ");if(this.#j.error&&this.#j.error.length)this.emit("error",j);else if(this.intents.includes(this.Intents.NO_EXIT_ON_ERROR))console.error(j);else throw Error(j)}leave(E=d.mainMenu){if(this.hasQuit)return;if(E>-1){this.game?.socket?.close(E);this.state.left=!0;this.emit("leave",E)}clearInterval(this.updateIntervalId);this.#J=[];this.state.inGame=!1;this.state.chatLines=0;this.state.reloading=!1;this.state.swappingGun=!1;this.state.usingMelee=!1;this.state.stateIdx=0;this.state.serverStateIdx=0;this.state.shotsFired=0;this.state.buffer=[];this.players={};this.me=new T({});this.game=this.#U;this.ping=0;this.lastPingTime=-1;this.lastDeathTime=-1;this.lastUpdateTick=0;this.pathing={nodeList:null,followingPath:!1,activePath:null,activeNode:null,activeNodeIdx:0}}logout(){this.account=this.#E;if(this.intents.includes(this.Intents.RENEW_SESSION))clearInterval(this.renewSessionInterval)}quit(E=!1){if(this.hasQuit)return;this.leave();if(this.matchmaker){this.matchmaker.close();if(!E)delete this.matchmaker}if(!E){delete this.account;delete this.api;delete this.game;delete this.me;delete this.pathing;delete this.players;delete this.state;this.#E={};this.#U={};this.#j={};this.#Q=[];this.#J=[]}if(this.intents.includes(this.Intents.NO_AFK_KICK))clearInterval(this.afkKickInterval);if(this.intents.includes(this.Intents.RENEW_SESSION))clearInterval(this.renewSessionInterval);this.hasQuit=!0}}export default Bot;
1
+ import API from "./api.js";
2
+ import CommIn from "./comm/CommIn.js";
3
+ import CommOut from "./comm/CommOut.js";
4
+ import CloseCode from "./constants/CloseCode.js";
5
+ import CommCode from "./constants/CommCode.js";
6
+ import GamePlayer from "./bot/GamePlayer.js";
7
+ import Matchmaker from "./matchmaker.js";
8
+ import yolkws from "./socket.js";
9
+ import {
10
+ ChiknWinnerDailyLimit,
11
+ CollectType,
12
+ CoopState,
13
+ findItemById,
14
+ FramesBetweenSyncs,
15
+ GameAction,
16
+ GameMode,
17
+ GameOptionFlag,
18
+ GunList,
19
+ ItemType,
20
+ Movement,
21
+ PlayType,
22
+ ShellStreak,
23
+ StateBufferSize
24
+ } from "./constants/index.js";
25
+ import LookAtPosDispatch from "./dispatches/LookAtPosDispatch.js";
26
+ import MovementDispatch from "./dispatches/MovementDispatch.js";
27
+ import globals from "./env/globals.js";
28
+ import { NodeList } from "./pathing/mapnode.js";
29
+ import { coords } from "./wasm/direct.js";
30
+ import { fetchMap, initKotcZones } from "./util.js";
31
+ import { Challenges } from "./constants/challenges.js";
32
+ import { Maps } from "./constants/maps.js";
33
+ import { Regions } from "./constants/regions.js";
34
+ const GameModeById = Object.fromEntries(Object.entries(GameMode).map(([key, value]) => [value, key]));
35
+ const CCGameOptionFlag = Object.fromEntries(Object.entries(GameOptionFlag).map(([k, v]) => [k[0].toLowerCase() + k.slice(1), v]));
36
+ const intents = {
37
+ CHALLENGES: 1,
38
+ BOT_STATS: 2,
39
+ PATHFINDING: 3,
40
+ PING: 5,
41
+ COSMETIC_DATA: 6,
42
+ PLAYER_HEALTH: 7,
43
+ PACKET_HOOK: 8,
44
+ LOG_PACKETS: 10,
45
+ NO_LOGIN: 11,
46
+ DEBUG_BUFFER: 12,
47
+ NO_AFK_KICK: 16,
48
+ LOAD_MAP: 17,
49
+ OBSERVE_GAME: 18,
50
+ NO_REGION_CHECK: 19,
51
+ NO_EXIT_ON_ERROR: 20,
52
+ RENEW_SESSION: 21,
53
+ VIP_HIDE_BADGE: 22
54
+ };
55
+ const mod = (n, m) => (n % m + m) % m;
56
+
57
+ export class Bot {
58
+ static Intents = intents;
59
+ Intents = intents;
60
+ #dispatches = [];
61
+ #hooks = {};
62
+ #globalHooks = [];
63
+ #initialAccount;
64
+ #initialGame;
65
+ constructor(params = {}) {
66
+ if (params.proxy && globals.isBrowser)
67
+ this.processError("proxies do not work and hence are not supported in the browser");
68
+ this.intents = params.intents || [];
69
+ if (this.intents.includes(this.Intents.COSMETIC_DATA)) {
70
+ const ballCap = findItemById(1001);
71
+ if (!ballCap)
72
+ this.processError("you cannot use the COSMETIC_DATA intent inside of the singlefile browser bundles");
73
+ }
74
+ this.instance = params.instance || "shellshock.io";
75
+ this.protocol = params.protocol || "wss";
76
+ this.proxy = params.proxy || "";
77
+ this.connectionTimeout = params.connectionTimeout || 5000;
78
+ this.state = {
79
+ name: "yolkbot",
80
+ weaponIdx: 0,
81
+ useAltGameURL: false,
82
+ inGame: false,
83
+ chatLines: 0,
84
+ yaw: 0,
85
+ pitch: 0,
86
+ controlKeys: 0,
87
+ reloading: false,
88
+ swappingGun: false,
89
+ usingMelee: false,
90
+ stateIdx: 0,
91
+ serverStateIdx: 0,
92
+ shotsFired: 0,
93
+ buffer: [],
94
+ left: false
95
+ };
96
+ this.players = {};
97
+ this.me = new GamePlayer({});
98
+ this.game = {
99
+ raw: {},
100
+ code: "",
101
+ socket: null,
102
+ gameModeId: 0,
103
+ gameMode: GameModeById[0],
104
+ mapIdx: 0,
105
+ map: {
106
+ filename: "",
107
+ hash: "",
108
+ name: "",
109
+ modes: {
110
+ FFA: false,
111
+ Teams: false,
112
+ Spatula: false,
113
+ King: false
114
+ },
115
+ availability: "both",
116
+ numPlayers: "18",
117
+ raw: {},
118
+ nodes: {},
119
+ zones: []
120
+ },
121
+ playerLimit: 0,
122
+ isGameOwner: false,
123
+ isPrivate: true,
124
+ options: {
125
+ gravity: 1,
126
+ damage: 1,
127
+ healthRegen: 1,
128
+ locked: false,
129
+ noTeamChange: false,
130
+ noTeamShuffle: false,
131
+ weaponsDisabled: Array(7).fill(false),
132
+ mustUseSecondary: false
133
+ },
134
+ collectables: [[], []],
135
+ teamScore: [0, 0, 0],
136
+ spatula: {
137
+ coords: { x: 0, y: 0, z: 0 },
138
+ controlledBy: 0,
139
+ controlledByTeam: 0
140
+ },
141
+ stage: CoopState.Capturing,
142
+ zoneNumber: 0,
143
+ activeZone: [],
144
+ capturing: 0,
145
+ captureProgress: 0,
146
+ numCapturing: 0,
147
+ capturePercent: 0
148
+ };
149
+ this.#initialGame = this.game;
150
+ this.account = {
151
+ id: 0,
152
+ firebase: {
153
+ idToken: "",
154
+ refreshToken: "",
155
+ expiresIn: "3600",
156
+ localId: ""
157
+ },
158
+ firebaseId: "",
159
+ sessionId: "",
160
+ session: 0,
161
+ email: "",
162
+ password: "",
163
+ cw: {
164
+ atLimit: false,
165
+ limit: 0,
166
+ secondsUntilPlay: 0,
167
+ canPlayAgain: Date.now()
168
+ },
169
+ loadout: {
170
+ hatId: null,
171
+ meleeId: 0,
172
+ stampId: null,
173
+ classIdx: 0,
174
+ colorIdx: 0,
175
+ grenadeId: 0,
176
+ primaryId: [
177
+ 3100,
178
+ 3600,
179
+ 3400,
180
+ 3800,
181
+ 4000,
182
+ 4200,
183
+ 4500
184
+ ],
185
+ secondaryId: new Array(7).fill(3000),
186
+ stampPositionX: 0,
187
+ stampPositionY: 0
188
+ },
189
+ ownedItemIds: [],
190
+ vip: false,
191
+ emailVerified: false,
192
+ isAged: false,
193
+ eggBalance: 0,
194
+ adminRoles: 0,
195
+ rawLoginData: {},
196
+ isDoubleEggWeeknd: () => {
197
+ const day = new Date().getUTCDay();
198
+ const hours = new Date().getUTCHours();
199
+ return day >= 5 && hours >= 20 || day === 6 || day === 0;
200
+ }
201
+ };
202
+ this.#initialAccount = this.account;
203
+ this.matchmaker = null;
204
+ this.api = new API({
205
+ proxy: this.proxy,
206
+ protocol: this.protocol,
207
+ instance: this.instance,
208
+ maxRetries: params?.apiMaxRetries,
209
+ connectionTimeout: this.connectionTimeout
210
+ });
211
+ this.ping = 0;
212
+ this.lastPingTime = -1;
213
+ this.lastDeathTime = -1;
214
+ this.lastUpdateTick = 0;
215
+ this.pathing = {
216
+ nodeList: null,
217
+ followingPath: false,
218
+ activePath: null,
219
+ activeNode: null,
220
+ activeNodeIdx: 0
221
+ };
222
+ this.hasQuit = false;
223
+ if (this.intents.includes(this.Intents.NO_AFK_KICK))
224
+ this.afkKickInterval = 0;
225
+ if (this.intents.includes(this.Intents.RENEW_SESSION))
226
+ this.renewSessionInterval = 0;
227
+ }
228
+ dispatch(dispatch) {
229
+ if (dispatch.validate(this)) {
230
+ if (dispatch.check(this))
231
+ dispatch.execute(this);
232
+ else
233
+ this.#dispatches.push(dispatch);
234
+ return true;
235
+ }
236
+ return false;
237
+ }
238
+ async createAccount(email, pass) {
239
+ this.account = this.#initialAccount;
240
+ this.account.email = email;
241
+ this.account.password = pass;
242
+ const loginData = await this.api.createAccount(email, pass);
243
+ return this.processLoginData(loginData);
244
+ }
245
+ async login(email, pass) {
246
+ this.account = this.#initialAccount;
247
+ this.account.email = email;
248
+ this.account.password = pass;
249
+ const loginData = await this.api.loginWithCredentials(email, pass);
250
+ return this.processLoginData(loginData);
251
+ }
252
+ async loginWithRefreshToken(refreshToken) {
253
+ this.account = this.#initialAccount;
254
+ const loginData = await this.api.loginWithRefreshToken(refreshToken);
255
+ return this.processLoginData(loginData);
256
+ }
257
+ async loginAnonymously() {
258
+ this.account = this.#initialAccount;
259
+ const loginData = await this.api.loginAnonymously();
260
+ return this.processLoginData(loginData);
261
+ }
262
+ processLoginData(loginData) {
263
+ if (typeof loginData !== "object") {
264
+ this.emit("authFail", loginData);
265
+ return loginData;
266
+ }
267
+ if (loginData.banRemaining) {
268
+ this.emit("banned", loginData.banRemaining);
269
+ return "account_banned";
270
+ }
271
+ if (!loginData.playerOutput) {
272
+ this.emit("authFail", loginData);
273
+ return loginData;
274
+ }
275
+ this.account.firebase = loginData.firebase || {};
276
+ loginData = loginData.playerOutput;
277
+ this.account.rawLoginData = loginData;
278
+ this.account.adminRoles = loginData.adminRoles || 0;
279
+ this.account.eggBalance = loginData.currentBalance;
280
+ this.account.emailVerified = loginData.emailVerified;
281
+ this.account.firebaseId = loginData.firebaseId;
282
+ this.account.id = loginData.id;
283
+ this.account.isAged = new Date(loginData.dateCreated).getTime() < 1714546800000;
284
+ this.account.loadout = loginData.loadout;
285
+ this.account.ownedItemIds = loginData.ownedItemIds;
286
+ this.account.session = loginData.session;
287
+ this.account.sessionId = loginData.sessionId;
288
+ this.account.vip = loginData.active_sub === "IsVIP";
289
+ if (this.intents.includes(this.Intents.BOT_STATS))
290
+ this.account.stats = {
291
+ lifetime: loginData.statsLifetime,
292
+ monthly: loginData.statsCurrent
293
+ };
294
+ if (this.intents.includes(this.Intents.CHALLENGES))
295
+ this.#importChallenges(loginData.challenges);
296
+ this.emit("authSuccess", this.account);
297
+ if (this.intents.includes(this.Intents.RENEW_SESSION)) {
298
+ this.renewSessionInterval = setInterval(async () => {
299
+ if (!this.account?.sessionId)
300
+ return clearInterval(this.renewSessionInterval);
301
+ const res = await this.api.queryServices({
302
+ cmd: "renewSession",
303
+ sessionId: this.account.sessionId
304
+ });
305
+ if (res.data !== "renewed")
306
+ this.emit("sessionExpired");
307
+ }, 600000);
308
+ }
309
+ return this.account;
310
+ }
311
+ #importChallenges(challengeArray) {
312
+ this.account.challenges = [];
313
+ for (const challengeData of challengeArray) {
314
+ const challengeInfo = Challenges.find((c) => c.id === challengeData.challengeId);
315
+ if (!challengeInfo)
316
+ continue;
317
+ delete challengeData.playerId;
318
+ this.account.challenges.push({
319
+ raw: { challengeInfo, challengeData },
320
+ id: challengeData.challengeId,
321
+ name: challengeInfo.loc.title,
322
+ desc: challengeInfo.loc.desc,
323
+ rewardEggs: challengeInfo.reward,
324
+ isRerolled: !!challengeData.reset,
325
+ isClaimed: !!challengeData.claimed,
326
+ isCompleted: !!challengeData.completed,
327
+ progressNum: challengeData.progress,
328
+ goalNum: challengeInfo.goal
329
+ });
330
+ }
331
+ }
332
+ async initMatchmaker() {
333
+ if (!this.account.sessionId && !this.intents.includes(this.Intents.NO_LOGIN)) {
334
+ const anonLogin = await this.loginAnonymously();
335
+ if (typeof anonLogin !== "object")
336
+ return anonLogin;
337
+ }
338
+ if (!this.matchmaker) {
339
+ this.matchmaker = new Matchmaker({
340
+ api: this.api,
341
+ proxy: this.proxy,
342
+ protocol: this.protocol,
343
+ instance: this.instance,
344
+ sessionId: this.account.sessionId,
345
+ connectionTimeout: this.connectionTimeout,
346
+ noLogin: this.intents.includes(this.Intents.NO_LOGIN)
347
+ });
348
+ const didConnect = await this.matchmaker.ws.tryConnect();
349
+ if (!didConnect)
350
+ return "matchmaker_tryconnect_failed";
351
+ this.matchmaker.on("authFail", (data) => this.emit("authFail", data));
352
+ this.matchmaker.on("error", (data) => this.processError(data));
353
+ }
354
+ return true;
355
+ }
356
+ async findPublicGame(region, modeId) {
357
+ if (typeof region !== "string")
358
+ return "no_region_passed";
359
+ if (!Regions.find((r) => r.id === region) && !this.intents.includes(this.Intents.NO_REGION_CHECK))
360
+ return "invalid_region_passed";
361
+ if (typeof modeId !== "number")
362
+ return "no_mode_passed";
363
+ if (Object.values(GameMode).indexOf(modeId) === -1)
364
+ return "invalid_mode_passed";
365
+ if (!await this.initMatchmaker())
366
+ return "matchmaker_init_fail";
367
+ const game = await new Promise((resolve) => {
368
+ const listener = (msg) => {
369
+ if (msg.command === "notice")
370
+ return;
371
+ this.matchmaker.off("msg", listener);
372
+ if (msg.command === "gameFound") {
373
+ if (msg.useAltGameURL)
374
+ this.state.useAltGameURL = true;
375
+ return resolve(msg);
376
+ }
377
+ if (msg.error === "sessionNotFound")
378
+ return resolve("internal_session_error");
379
+ this.processError("unknown matchmaker response", JSON.stringify(msg));
380
+ };
381
+ this.matchmaker.on("msg", listener);
382
+ this.matchmaker.send({
383
+ command: "findGame",
384
+ region,
385
+ playType: PlayType.JoinPublic,
386
+ gameType: modeId,
387
+ sessionId: this.account.sessionId
388
+ });
389
+ });
390
+ return game;
391
+ }
392
+ async createPrivateGame(region, modeId, map) {
393
+ if (typeof region !== "string")
394
+ return "no_region_passed";
395
+ if (!Regions.find((r) => r.id === region) && !this.intents.includes(this.Intents.NO_REGION_CHECK))
396
+ return "invalid_region_passed";
397
+ if (typeof modeId !== "number")
398
+ return "no_mode_passed";
399
+ if (Object.values(GameMode).indexOf(modeId) === -1)
400
+ return "invalid_mode_passed";
401
+ if (typeof map !== "string")
402
+ return "no_map_passed";
403
+ const mapIdx = Maps.findIndex((m) => m.name.toLowerCase() === map.toLowerCase());
404
+ if (mapIdx === -1)
405
+ return "invalid_map_passed";
406
+ if (!await this.initMatchmaker())
407
+ return "matchmaker_init_fail";
408
+ const game = await new Promise((resolve) => {
409
+ const listener = (msg) => {
410
+ if (msg.command === "notice")
411
+ return;
412
+ this.matchmaker.off("msg", listener);
413
+ if (msg.command === "gameFound") {
414
+ if (msg.useAltGameURL)
415
+ this.state.useAltGameURL = true;
416
+ return resolve(msg);
417
+ }
418
+ if (msg.error === "sessionNotFound")
419
+ return resolve("internal_session_error");
420
+ this.processError("unknown matchmaker response", JSON.stringify(msg));
421
+ };
422
+ this.matchmaker.on("msg", listener);
423
+ this.matchmaker.send({
424
+ command: "findGame",
425
+ region,
426
+ playType: PlayType.CreatePrivate,
427
+ gameType: modeId,
428
+ sessionId: this.account.sessionId,
429
+ noobLobby: false,
430
+ map: mapIdx
431
+ });
432
+ });
433
+ return game;
434
+ }
435
+ async join(name, data) {
436
+ this.state.name = name || "yolkbot";
437
+ if (typeof data === "string") {
438
+ if (data.includes("#"))
439
+ data = data.split("#")[1];
440
+ if (!await this.initMatchmaker())
441
+ return "matchmaker_init_fail";
442
+ const joinResult = await new Promise((resolve) => {
443
+ const listener = (message) => {
444
+ if (message.command === "gameFound") {
445
+ this.matchmaker.off("msg", listener);
446
+ this.game.raw = message;
447
+ this.game.code = message.id;
448
+ resolve(message.id);
449
+ }
450
+ if (message.error && message.error === "gameNotFound") {
451
+ this.processError(`game "${data}" not found, it may have expired.`);
452
+ this.leave();
453
+ return "gameNotFound";
454
+ }
455
+ };
456
+ this.matchmaker.on("msg", listener);
457
+ this.matchmaker.send({
458
+ command: "joinGame",
459
+ id: data,
460
+ observe: false,
461
+ sessionId: this.account.sessionId
462
+ });
463
+ });
464
+ if (joinResult === "gameNotFound")
465
+ return "game_not_found";
466
+ if (!this.game.raw.id)
467
+ return this.processError("an internal error occured while joining the game, please report this to developers");
468
+ }
469
+ if (typeof data === "object") {
470
+ if (this.account.id === 0)
471
+ await this.loginAnonymously();
472
+ this.game.raw = data;
473
+ this.game.code = this.game.raw.id;
474
+ if (!this.game.raw.id)
475
+ return "invalid_game_object";
476
+ if (!this.game.raw.subdomain)
477
+ return "invalid_game_object";
478
+ if (!this.game.raw.uuid)
479
+ return "invalid_game_object";
480
+ if (data.useAltGameURL)
481
+ this.state.useAltGameURL = true;
482
+ }
483
+ const host = this.state.useAltGameURL || this.host === "proxy.yolkbot.xyz" ? `${this.instance}/servers/${this.game.raw.subdomain}` : `${this.game.raw.subdomain}.${this.instance}`;
484
+ this.game.socket = new yolkws(`${this.protocol}://${host}/game/${this.game.raw.id}`, this.proxy);
485
+ this.game.socket.binaryType = "arraybuffer";
486
+ this.game.socket.connectionTimeout = this.connectionTimeout;
487
+ this.game.socket.onBeforeConnect = () => {
488
+ this.game.socket.onmessage = (msg) => this.processPacket(msg.data);
489
+ this.game.socket.onclose = (e) => {
490
+ if (this.state.left)
491
+ this.state.left = false;
492
+ else {
493
+ this.emit("close", e.code);
494
+ this.leave(-1);
495
+ }
496
+ };
497
+ };
498
+ const didConnect = await this.game.socket.tryConnect();
499
+ if (!didConnect)
500
+ return "websocket_tryconnect_fail";
501
+ return true;
502
+ }
503
+ #processPathfinding() {
504
+ const myPositionStr = Object.entries(this.me.position).map((entry) => Math.floor(entry[1])).join(",");
505
+ if (myPositionStr === this.pathing.activePath[this.pathing.activePath.length - 1].positionStr) {
506
+ this.pathing.followingPath = false;
507
+ this.pathing.activePath = null;
508
+ this.pathing.activeNode = null;
509
+ this.pathing.activeNodeIdx = 0;
510
+ this.dispatch(new MovementDispatch(0));
511
+ } else {
512
+ let positionTarget;
513
+ if (this.pathing.activeNodeIdx < this.pathing.activePath.length - 1) {
514
+ positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx + 1].flatCenter();
515
+ this.dispatch(new LookAtPosDispatch(positionTarget));
516
+ } else {
517
+ positionTarget = this.pathing.activePath[this.pathing.activeNodeIdx].flatCenter();
518
+ this.dispatch(new LookAtPosDispatch(positionTarget));
519
+ }
520
+ for (const node of this.pathing.activePath) {
521
+ if (node.flatRadialDistance(this.me.position) < 0.1 && node.position.y === Math.floor(this.me.position.y)) {
522
+ if (this.pathing.activePath.indexOf(node) >= this.pathing.activeNodeIdx) {
523
+ this.pathing.activeNodeIdx = this.pathing.activePath.indexOf(node) + 1;
524
+ this.pathing.activeNode = this.pathing.activePath[this.pathing.activeNodeIdx];
525
+ break;
526
+ }
527
+ }
528
+ }
529
+ if (!(this.state.controlKeys & Movement.Forward))
530
+ this.dispatch(new MovementDispatch(Movement.Forward));
531
+ }
532
+ }
533
+ update() {
534
+ if (this.hasQuit)
535
+ return;
536
+ if (this.pathing.followingPath && this.intents.includes(this.Intents.PATHFINDING))
537
+ this.#processPathfinding();
538
+ for (let i = 0;i < this.#dispatches.length; i++) {
539
+ const disp = this.#dispatches[i];
540
+ if (disp.check(this)) {
541
+ disp.execute(this);
542
+ this.#dispatches.splice(i, 1);
543
+ }
544
+ }
545
+ this.state.chatLines = Math.max(0, this.state.chatLines - 1 / (30 * 4));
546
+ if (this.me.playing) {
547
+ const currentIdx = this.state.stateIdx;
548
+ if (this.intents.includes(this.Intents.DEBUG_BUFFER)) {
549
+ console.log("setting buffer for idx", currentIdx);
550
+ console.log("checking...shotsFired", this.state.shotsFired);
551
+ }
552
+ this.me.jumping = !!(this.state.controlKeys & Movement.Jump);
553
+ this.state.buffer[currentIdx] = {
554
+ controlKeys: this.state.controlKeys,
555
+ yaw: this.state.yaw,
556
+ pitch: this.state.pitch,
557
+ shotsFired: this.state.shotsFired
558
+ };
559
+ this.state.shotsFired = 0;
560
+ if (this.lastUpdateTick >= 2) {
561
+ this.emit("tick");
562
+ const out = new CommOut;
563
+ out.packInt8(CommCode.syncMe);
564
+ out.packInt8(this.state.stateIdx);
565
+ out.packInt8(this.state.serverStateIdx);
566
+ const startIdx = mod(this.state.stateIdx - FramesBetweenSyncs + 1, StateBufferSize);
567
+ for (let i = 0;i < FramesBetweenSyncs; i++) {
568
+ const idx = mod(startIdx + i, StateBufferSize);
569
+ const frame = this.state.buffer[idx] || {};
570
+ const keys = frame.controlKeys || 0;
571
+ const shots = frame.shotsFired || 0;
572
+ const yaw = frame.yaw ?? this.state.yaw;
573
+ const pitch = frame.pitch ?? this.state.pitch;
574
+ if (this.intents.includes(this.Intents.DEBUG_BUFFER))
575
+ console.log("going with", this.state.stateIdx, startIdx, idx, frame);
576
+ out.packInt8(keys);
577
+ out.packInt8(shots);
578
+ out.packString(coords(yaw, pitch));
579
+ out.packInt8(100);
580
+ }
581
+ out.send(this.game.socket);
582
+ this.state.buffer = [];
583
+ this.lastUpdateTick = 0;
584
+ } else
585
+ this.lastUpdateTick++;
586
+ this.state.stateIdx = mod(this.state.stateIdx + 1, StateBufferSize);
587
+ }
588
+ if (!this.intents.includes(this.Intents.PLAYER_HEALTH))
589
+ return;
590
+ const regen = 0.1 * (this.game.isPrivate ? this.game.options.healthRegen : 1);
591
+ for (const player of Object.values(this.players)) {
592
+ if (player.playing && player.hp > 0) {
593
+ const overHeal = player.streakRewards.includes(ShellStreak.OverHeal);
594
+ player.hp += overHeal ? -regen : regen;
595
+ player.hp = overHeal ? Math.max(100, player.hp) : Math.min(100, player.hp);
596
+ }
597
+ if (player.spawnShield > 0)
598
+ player.spawnShield -= 6;
599
+ }
600
+ }
601
+ on(event, cb) {
602
+ if (Object.keys(this.#hooks).includes(event))
603
+ this.#hooks[event].push(cb);
604
+ else
605
+ this.#hooks[event] = [cb];
606
+ }
607
+ once(event, cb) {
608
+ const onceCb = (...args) => {
609
+ cb(...args);
610
+ this.off(event, onceCb);
611
+ };
612
+ this.on(event, onceCb);
613
+ }
614
+ onAny(cb) {
615
+ this.#globalHooks.push(cb);
616
+ }
617
+ off(event, cb) {
618
+ if (cb)
619
+ this.#hooks[event] = this.#hooks[event].filter((hook) => hook !== cb);
620
+ else
621
+ this.#hooks[event] = [];
622
+ }
623
+ emit(event, ...args) {
624
+ if (this.hasQuit)
625
+ return;
626
+ if (this.#hooks[event])
627
+ for (const cb of this.#hooks[event])
628
+ cb(...args);
629
+ for (const cb of this.#globalHooks)
630
+ cb(event, ...args);
631
+ }
632
+ #processChatPacket() {
633
+ const id = CommIn.unPackInt8U();
634
+ const msgFlags = CommIn.unPackInt8U();
635
+ const text = CommIn.unPackString().valueOf();
636
+ const player = this.players[id];
637
+ this.emit("chat", player, text, msgFlags);
638
+ }
639
+ #processAddPlayerPacket() {
640
+ const id = CommIn.unPackInt8U();
641
+ const findCosmetics = this.intents.includes(this.Intents.COSMETIC_DATA);
642
+ const playerData = {
643
+ id,
644
+ uniqueId: CommIn.unPackString(),
645
+ name: CommIn.unPackString(),
646
+ safeName: CommIn.unPackString(),
647
+ charClass: CommIn.unPackInt8U(),
648
+ team: CommIn.unPackInt8U(),
649
+ primaryWeaponItem: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
650
+ secondaryWeaponItem: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
651
+ shellColor: CommIn.unPackInt8U(),
652
+ hatItem: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
653
+ stampItem: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
654
+ stampPosX: CommIn.unPackInt8(),
655
+ stampPosY: CommIn.unPackInt8(),
656
+ grenadeItem: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
657
+ meleeItem: findCosmetics ? findItemById(CommIn.unPackInt16U()) : CommIn.unPackInt16U(),
658
+ x: CommIn.unPackFloat(),
659
+ y: CommIn.unPackFloat(),
660
+ z: CommIn.unPackFloat(),
661
+ $dx: CommIn.unPackFloat(),
662
+ $dy: CommIn.unPackFloat(),
663
+ $dz: CommIn.unPackFloat(),
664
+ yaw: CommIn.unPackRadU(),
665
+ pitch: CommIn.unPackRad(),
666
+ score: CommIn.unPackInt32U(),
667
+ $kills: CommIn.unPackInt16U(),
668
+ $deaths: CommIn.unPackInt16U(),
669
+ $streak: CommIn.unPackInt16U(),
670
+ totalKills: CommIn.unPackInt32U(),
671
+ totalDeaths: CommIn.unPackInt32U(),
672
+ bestStreak: CommIn.unPackInt16U(),
673
+ $bestOverallStreak: CommIn.unPackInt16U(),
674
+ shield: CommIn.unPackInt8U(),
675
+ hp: CommIn.unPackInt8U(),
676
+ playing: CommIn.unPackInt8U(),
677
+ weaponIdx: CommIn.unPackInt8U(),
678
+ $controlKeys: CommIn.unPackInt8U(),
679
+ upgradeProductId: CommIn.unPackInt8U(),
680
+ activeShellStreaks: CommIn.unPackInt8U(),
681
+ social: CommIn.unPackLongString(),
682
+ hideBadge: CommIn.unPackInt8U()
683
+ };
684
+ this.game.mapIdx = CommIn.unPackInt8U();
685
+ this.game.isPrivate = CommIn.unPackInt8U() === 1;
686
+ this.game.gameModeId = CommIn.unPackInt8U();
687
+ const player = new GamePlayer(playerData, this.game.gameMode === GameMode.KOTC ? this.game.activeZone : null);
688
+ if (!this.players[playerData.id])
689
+ this.players[playerData.id] = player;
690
+ this.emit("playerJoin", player);
691
+ if (this.me.id === playerData.id) {
692
+ this.me = player;
693
+ this.emit("botJoin", this.me);
694
+ }
695
+ }
696
+ #processRespawnPacket() {
697
+ const id = CommIn.unPackInt8U();
698
+ const seed = CommIn.unPackInt16U();
699
+ const x = CommIn.unPackFloat();
700
+ const y = CommIn.unPackFloat();
701
+ const z = CommIn.unPackFloat();
702
+ const rounds0 = CommIn.unPackInt8U();
703
+ const store0 = CommIn.unPackInt8U();
704
+ const rounds1 = CommIn.unPackInt8U();
705
+ const store1 = CommIn.unPackInt8U();
706
+ const grenades = CommIn.unPackInt8U();
707
+ const player = this.players[id];
708
+ if (player) {
709
+ player.playing = true;
710
+ player.randomSeed = seed;
711
+ if (player.weapons[0] && player.weapons[0].ammo)
712
+ player.weapons[0].ammo.rounds = rounds0;
713
+ if (player.weapons[0] && player.weapons[0].ammo)
714
+ player.weapons[0].ammo.store = store0;
715
+ if (player.weapons[1] && player.weapons[1].ammo)
716
+ player.weapons[1].ammo.rounds = rounds1;
717
+ if (player.weapons[1] && player.weapons[1].ammo)
718
+ player.weapons[1].ammo.store = store1;
719
+ player.grenades = grenades;
720
+ player.position = { x, y, z };
721
+ player.spawnShield = 120;
722
+ this.emit("playerRespawn", player);
723
+ }
724
+ }
725
+ #processSyncThemPacket() {
726
+ const id = CommIn.unPackInt8U();
727
+ const x = CommIn.unPackFloat();
728
+ const y = CommIn.unPackFloat();
729
+ const z = CommIn.unPackFloat();
730
+ const climbing = CommIn.unPackInt8U();
731
+ const player = this.players[id];
732
+ if (!player || player.id === this.me.id) {
733
+ for (let i2 = 0;i2 < FramesBetweenSyncs; i2++) {
734
+ CommIn.unPackInt8U();
735
+ CommIn.unPackRadU();
736
+ CommIn.unPackRad();
737
+ CommIn.unPackInt8U();
738
+ }
739
+ return;
740
+ }
741
+ for (let i2 = 0;i2 < FramesBetweenSyncs; i2++) {
742
+ const controlKeys = CommIn.unPackInt8U();
743
+ if (controlKeys & Movement.Jump)
744
+ player.jumping = true;
745
+ else
746
+ player.jumping = false;
747
+ if (controlKeys & Movement.Scope)
748
+ player.scoping = true;
749
+ else
750
+ player.scoping = false;
751
+ const oldView = { ...player.view };
752
+ player.view.yaw = CommIn.unPackRadU();
753
+ player.view.pitch = CommIn.unPackRad();
754
+ if (player.view.yaw !== oldView.yaw || player.view.pitch !== oldView.pitch)
755
+ this.emit("playerRotate", player, oldView, player.view);
756
+ player.scale = CommIn.unPackInt8U();
757
+ }
758
+ const px = player.position;
759
+ const posChanged = px.x !== x || px.y !== y || px.z !== z;
760
+ const climbingChanged = player.climbing !== climbing;
761
+ const didChange = posChanged || climbingChanged;
762
+ const oldPosition = didChange ? { ...px } : null;
763
+ if (px.x !== x)
764
+ px.x = x;
765
+ if (px.z !== z)
766
+ px.z = z;
767
+ if (!player.jumping || Math.abs(px.y - y) > 0.5)
768
+ px.y = y;
769
+ if (climbingChanged)
770
+ player.climbing = climbing;
771
+ if (!didChange)
772
+ return;
773
+ this.emit("playerMove", player, oldPosition, px);
774
+ if (this.game.gameModeId !== GameMode.KOTC)
775
+ return;
776
+ const zone = this.game.activeZone;
777
+ const wasIn = !!player.inKotcZone;
778
+ if (!zone && wasIn) {
779
+ player.inKotcZone = false;
780
+ this.emit("playerLeaveZone", player);
781
+ return;
782
+ }
783
+ player.updateKotcZone(zone);
784
+ const nowIn = !!player.inKotcZone;
785
+ if (wasIn !== nowIn) {
786
+ player.inKotcZone = nowIn;
787
+ this.emit(nowIn ? "playerEnterZone" : "playerLeaveZone", player);
788
+ }
789
+ }
790
+ #processPausePacket() {
791
+ const id = CommIn.unPackInt8U();
792
+ const player = this.players[id];
793
+ if (player) {
794
+ player.playing = false;
795
+ if (player.streakRewards)
796
+ player.streakRewards = [];
797
+ this.emit("playerPause", player);
798
+ if (player.inKotcZone) {
799
+ player.inKotcZone = false;
800
+ this.emit("playerLeaveZone", player);
801
+ }
802
+ }
803
+ }
804
+ #processSwapWeaponPacket() {
805
+ const id = CommIn.unPackInt8U();
806
+ const newWeaponId = CommIn.unPackInt8U();
807
+ const player = this.players[id];
808
+ if (player) {
809
+ player.activeGun = newWeaponId;
810
+ this.emit("playerSwapWeapon", player, newWeaponId);
811
+ }
812
+ }
813
+ #processDeathPacket() {
814
+ const killedId = CommIn.unPackInt8U();
815
+ const killerId = CommIn.unPackInt8U();
816
+ CommIn.unPackInt8U();
817
+ CommIn.unPackInt8U();
818
+ const damageCauseInt = CommIn.unPackInt8U();
819
+ const killed = this.players[killedId];
820
+ const killer = this.players[killerId];
821
+ const oldKilled = killed ? { ...killed } : null;
822
+ if (killed) {
823
+ if (killed.id === this.me.id)
824
+ this.lastDeathTime = Date.now();
825
+ killed.playing = false;
826
+ killed.streak = 0;
827
+ killed.hp = 100;
828
+ killed.spawnShield = 0;
829
+ killed.stats.totalDeaths++;
830
+ killed.inKotcZone = false;
831
+ this.emit("playerLeaveZone", killed);
832
+ }
833
+ if (killer) {
834
+ killer.streak++;
835
+ killer.stats.totalKills++;
836
+ if (killer.streak > killer.stats.bestStreak)
837
+ killer.stats.bestStreak = killer.streak;
838
+ }
839
+ this.emit("playerDeath", killed, killer, oldKilled, damageCauseInt);
840
+ }
841
+ #processFirePacket() {
842
+ const id = CommIn.unPackInt8U();
843
+ const bullet = {
844
+ posX: CommIn.unPackFloat(),
845
+ posY: CommIn.unPackFloat(),
846
+ posZ: CommIn.unPackFloat(),
847
+ dirX: CommIn.unPackFloat(),
848
+ dirY: CommIn.unPackFloat(),
849
+ dirZ: CommIn.unPackFloat()
850
+ };
851
+ const player = this.players[id];
852
+ if (!player)
853
+ return;
854
+ const playerWeapon = player.weapons[player.activeGun];
855
+ if (playerWeapon && playerWeapon.ammo) {
856
+ playerWeapon.ammo.rounds--;
857
+ this.emit("playerFire", player, playerWeapon, bullet);
858
+ }
859
+ }
860
+ #processSpawnItemPacket() {
861
+ const id = CommIn.unPackInt16U();
862
+ const type = CommIn.unPackInt8U();
863
+ const x = CommIn.unPackFloat();
864
+ const y = CommIn.unPackFloat();
865
+ const z = CommIn.unPackFloat();
866
+ this.game.collectables[type].push({ id, x, y, z });
867
+ this.emit("spawnItem", type, { x, y, z }, id);
868
+ }
869
+ #processCollectPacket() {
870
+ const playerId = CommIn.unPackInt8U();
871
+ const type = CommIn.unPackInt8U();
872
+ const applyToWeaponIdx = CommIn.unPackInt8U();
873
+ const id = CommIn.unPackInt16U();
874
+ const player = this.players[playerId];
875
+ if (!player)
876
+ return;
877
+ this.game.collectables[type] = this.game.collectables[type].filter((c) => c.id !== id);
878
+ if (type === CollectType.Ammo) {
879
+ const playerWeapon = player.weapons[applyToWeaponIdx];
880
+ if (playerWeapon && playerWeapon.ammo) {
881
+ playerWeapon.ammo.store = Math.min(playerWeapon.ammo.storeMax, playerWeapon.ammo.store + playerWeapon.ammo.pickup);
882
+ this.emit("playerCollectAmmo", player, playerWeapon, id);
883
+ }
884
+ }
885
+ if (type === CollectType.Grenade) {
886
+ player.grenades++;
887
+ if (player.grenades > 3)
888
+ player.grenades = 3;
889
+ this.emit("playerCollectGrenade", player, id);
890
+ }
891
+ }
892
+ #processHitThemPacket() {
893
+ const id = CommIn.unPackInt8U();
894
+ const hp = CommIn.unPackInt8U();
895
+ const player = this.players[id];
896
+ if (!player)
897
+ return;
898
+ const oldHealth = player.hp;
899
+ player.hp = hp;
900
+ this.emit("playerDamage", player, oldHealth, player.hp);
901
+ }
902
+ #processHitMePacket() {
903
+ const hp = CommIn.unPackInt8U();
904
+ CommIn.unPackFloat();
905
+ CommIn.unPackFloat();
906
+ const oldHealth = this.me.hp;
907
+ this.me.hp = hp;
908
+ this.emit("playerDamage", this.me, oldHealth, this.me.hp);
909
+ }
910
+ #processSyncMePacket() {
911
+ const id = CommIn.unPackInt8U();
912
+ const player = this.players[id];
913
+ CommIn.unPackInt8U();
914
+ const serverStateIdx = CommIn.unPackInt8U();
915
+ const newX = CommIn.unPackFloat();
916
+ const newY = CommIn.unPackFloat();
917
+ const newZ = CommIn.unPackFloat();
918
+ this.me.climbing = !!CommIn.unPackInt8U();
919
+ CommIn.unPackInt8U();
920
+ CommIn.unPackInt8U();
921
+ if (!player)
922
+ return;
923
+ this.state.serverStateIdx = serverStateIdx;
924
+ const oldX = player.position.x;
925
+ const oldY = player.position.y;
926
+ const oldZ = player.position.z;
927
+ player.position.x = newX;
928
+ player.position.y = newY;
929
+ player.position.z = newZ;
930
+ if (oldX !== newX || oldY !== newY || oldZ !== newZ)
931
+ this.emit("playerMove", player, { x: oldX, y: oldY, z: oldZ }, { x: newX, y: newY, z: newZ });
932
+ }
933
+ #processEventModifierPacket() {
934
+ const out = new CommOut;
935
+ out.packInt8(CommCode.eventModifier);
936
+ out.send(this.game.socket);
937
+ }
938
+ #processRemovePlayerPacket() {
939
+ const id = CommIn.unPackInt8U();
940
+ const removedPlayer = { ...this.players[id] };
941
+ delete this.players[id];
942
+ this.emit("playerLeave", removedPlayer);
943
+ }
944
+ #processGameStatePacket() {
945
+ if (this.game.gameModeId === GameMode.Spatula) {
946
+ const oldGame = { ...this.game };
947
+ this.game.teamScore[1] = CommIn.unPackInt16U();
948
+ this.game.teamScore[2] = CommIn.unPackInt16U();
949
+ const spatulaCoords = {
950
+ x: CommIn.unPackFloat(),
951
+ y: CommIn.unPackFloat(),
952
+ z: CommIn.unPackFloat()
953
+ };
954
+ const controlledBy = CommIn.unPackInt8U();
955
+ const controlledByTeam = CommIn.unPackInt8U();
956
+ this.game.spatula = { coords: spatulaCoords, controlledBy, controlledByTeam };
957
+ this.emit("gameStateChange", oldGame, this.game);
958
+ } else if (this.game.gameModeId === GameMode.KOTC) {
959
+ const oldGame = { ...this.game };
960
+ this.game.stage = CommIn.unPackInt8U();
961
+ this.game.zoneNumber = CommIn.unPackInt8U();
962
+ this.game.capturing = CommIn.unPackInt8U();
963
+ this.game.captureProgress = CommIn.unPackInt16U();
964
+ this.game.numCapturing = CommIn.unPackInt8U();
965
+ this.game.teamScore[1] = CommIn.unPackInt8U();
966
+ this.game.teamScore[2] = CommIn.unPackInt8U();
967
+ this.game.capturePercent = this.game.captureProgress / 1000;
968
+ this.game.activeZone = this.game.map.zones ? this.game.map.zones[this.game.zoneNumber - 1] : null;
969
+ const oldPlayersOnZone = Object.values(this.players).filter((p) => p.inKotcZone && p.playing);
970
+ if (this.game.activeZone)
971
+ Object.values(this.players).forEach((player) => player.updateKotcZone(this.game.activeZone));
972
+ if (this.game.numCapturing <= 0)
973
+ Object.values(this.players).forEach((player) => {
974
+ player.inKotcZone = false;
975
+ this.emit("playerLeaveZone", player);
976
+ });
977
+ this.emit("gameStateChange", oldGame, this.game, oldPlayersOnZone);
978
+ } else if (this.game.gameModeId === GameMode.Team) {
979
+ this.game.teamScore[1] = CommIn.unPackInt16U();
980
+ this.game.teamScore[2] = CommIn.unPackInt16U();
981
+ }
982
+ if (this.game.gameModeId !== GameMode.Spatula)
983
+ delete this.game.spatula;
984
+ if (this.game.gameModeId !== GameMode.KOTC) {
985
+ delete this.game.stage;
986
+ delete this.game.zoneNumber;
987
+ delete this.game.capturing;
988
+ delete this.game.captureProgress;
989
+ delete this.game.numCapturing;
990
+ delete this.game.numCapturing;
991
+ delete this.game.activeZone;
992
+ }
993
+ if (this.game.gameModeId === GameMode.FFA)
994
+ delete this.game.teamScore;
995
+ }
996
+ #processBeginStreakPacket() {
997
+ const id = CommIn.unPackInt8U();
998
+ const ksType = CommIn.unPackInt8U();
999
+ const player = this.players[id];
1000
+ if (!player)
1001
+ return;
1002
+ switch (ksType) {
1003
+ case ShellStreak.HardBoiled:
1004
+ if (id === this.me.id)
1005
+ this.me.shieldHp = 100;
1006
+ player.streakRewards.push(ShellStreak.HardBoiled);
1007
+ break;
1008
+ case ShellStreak.EggBreaker:
1009
+ player.streakRewards.push(ShellStreak.EggBreaker);
1010
+ break;
1011
+ case ShellStreak.Restock: {
1012
+ player.grenades = 3;
1013
+ if (player.weapons[0] && player.weapons[0].ammo) {
1014
+ player.weapons[0].ammo.rounds = player.weapons[0].ammo.capacity;
1015
+ player.weapons[0].ammo.store = player.weapons[0].ammo.storeMax;
1016
+ }
1017
+ if (player.weapons[1] && player.weapons[1].ammo) {
1018
+ player.weapons[1].ammo.rounds = player.weapons[1].ammo.capacity;
1019
+ player.weapons[1].ammo.store = player.weapons[1].ammo.storeMax;
1020
+ }
1021
+ break;
1022
+ }
1023
+ case ShellStreak.OverHeal:
1024
+ player.hp = Math.min(200, player.hp + 100);
1025
+ player.streakRewards.push(ShellStreak.OverHeal);
1026
+ break;
1027
+ case ShellStreak.DoubleEggs:
1028
+ player.streakRewards.push(ShellStreak.DoubleEggs);
1029
+ break;
1030
+ case ShellStreak.MiniEgg:
1031
+ player.scale = 0.5;
1032
+ player.streakRewards.push(ShellStreak.MiniEgg);
1033
+ break;
1034
+ }
1035
+ this.emit("playerBeginStreak", player, ksType);
1036
+ }
1037
+ #processEndStreakPacket() {
1038
+ const id = CommIn.unPackInt8U();
1039
+ const ksType = CommIn.unPackInt8U();
1040
+ const player = this.players[id];
1041
+ if (!player)
1042
+ return;
1043
+ const streaks = [
1044
+ ShellStreak.EggBreaker,
1045
+ ShellStreak.OverHeal,
1046
+ ShellStreak.DoubleEggs,
1047
+ ShellStreak.MiniEgg
1048
+ ];
1049
+ if (streaks.includes(ksType) && player.streakRewards.includes(ksType))
1050
+ player.streakRewards = player.streakRewards.filter((r) => r !== ksType);
1051
+ if (ksType === ShellStreak.MiniEgg)
1052
+ player.scale = 1;
1053
+ this.emit("playerEndStreak", player, ksType);
1054
+ }
1055
+ #processHitShieldPacket() {
1056
+ const shieldHealth = CommIn.unPackInt8U();
1057
+ const playerHealth = CommIn.unPackInt8U();
1058
+ const dx = CommIn.unPackFloat();
1059
+ const dz = CommIn.unPackFloat();
1060
+ if (!this.me)
1061
+ return;
1062
+ this.me.shieldHp = shieldHealth;
1063
+ this.me.hp = playerHealth;
1064
+ if (this.me.shieldHp <= 0) {
1065
+ this.me.streakRewards = this.me.streakRewards.filter((r) => r !== ShellStreak.HardBoiled);
1066
+ this.emit("selfShieldLost", this.me.hp, { dx, dz });
1067
+ } else
1068
+ this.emit("selfShieldHit", this.me.shieldHp, this.me.hp, { dx, dz });
1069
+ }
1070
+ #processGameOptionsPacket() {
1071
+ const oldOptions = { ...this.game.options };
1072
+ let gravity = CommIn.unPackInt8U();
1073
+ let damage = CommIn.unPackInt8U();
1074
+ let healthRegen = CommIn.unPackInt8U();
1075
+ if (gravity < 1 || gravity > 4) {
1076
+ gravity = 4;
1077
+ }
1078
+ if (damage < 0 || damage > 8) {
1079
+ damage = 4;
1080
+ }
1081
+ if (healthRegen > 16) {
1082
+ healthRegen = 4;
1083
+ }
1084
+ this.game.options.gravity = gravity / 4;
1085
+ this.game.options.damage = damage / 4;
1086
+ this.game.options.healthRegen = healthRegen / 4;
1087
+ const rawFlags = CommIn.unPackInt8U();
1088
+ Object.keys(CCGameOptionFlag).forEach((optionFlagName) => {
1089
+ const value = rawFlags & CCGameOptionFlag[optionFlagName] ? 1 : 0;
1090
+ this.game.options[optionFlagName] = value;
1091
+ });
1092
+ this.game.options.weaponsDisabled = Array.from({ length: 7 }, () => CommIn.unPackInt8U() === 1);
1093
+ this.game.options.mustUseSecondary = this.game.options.weaponsDisabled.every((v) => v);
1094
+ this.emit("gameOptionsChange", oldOptions, this.game.options);
1095
+ }
1096
+ #processGameActionPacket() {
1097
+ const action = CommIn.unPackInt8U();
1098
+ if (action === GameAction.Pause) {
1099
+ this.emit("gameForcePause");
1100
+ setTimeout(() => this.me.playing = false, 3000);
1101
+ }
1102
+ if (action === GameAction.Reset) {
1103
+ Object.values(this.players).forEach((player) => player.streak = 0);
1104
+ if (this.game.gameModeId !== GameMode.FFA)
1105
+ this.game.teamScore = [0, 0, 0];
1106
+ if (this.game.gameModeId === GameMode.Spatula) {
1107
+ this.game.spatula.controlledBy = 0;
1108
+ this.game.spatula.controlledByTeam = 0;
1109
+ this.game.spatula.coords = { x: 0, y: 0, z: 0 };
1110
+ }
1111
+ if (this.game.gameModeId === GameMode.KOTC) {
1112
+ this.game.stage = CoopState.Capturing;
1113
+ this.game.zoneNumber = 0;
1114
+ this.game.activeZone = null;
1115
+ this.game.capturing = 0;
1116
+ this.game.captureProgress = 0;
1117
+ this.game.numCapturing = 0;
1118
+ this.game.capturePercent = 0;
1119
+ }
1120
+ this.emit("gameReset");
1121
+ }
1122
+ }
1123
+ #processPingPacket() {
1124
+ if (!this.intents.includes(this.Intents.PING))
1125
+ return;
1126
+ const oldPing = this.ping;
1127
+ this.ping = Date.now() - this.lastPingTime;
1128
+ this.emit("pingUpdate", oldPing, this.ping);
1129
+ setTimeout(() => {
1130
+ const out = new CommOut;
1131
+ out.packInt8(CommCode.ping);
1132
+ out.send(this.game.socket);
1133
+ this.lastPingTime = Date.now();
1134
+ }, 1000);
1135
+ }
1136
+ #processSwitchTeamPacket() {
1137
+ const id = CommIn.unPackInt8U();
1138
+ const toTeam = CommIn.unPackInt8U();
1139
+ const player = this.players[id];
1140
+ if (!player)
1141
+ return;
1142
+ const oldTeam = player.team;
1143
+ player.team = toTeam;
1144
+ player.streak = 0;
1145
+ this.emit("playerSwitchTeam", player, oldTeam, toTeam);
1146
+ }
1147
+ #processChangeCharacterPacket() {
1148
+ const id = CommIn.unPackInt8U();
1149
+ const weaponIndex = CommIn.unPackInt8U();
1150
+ const primaryWeaponIdx = CommIn.unPackInt16U();
1151
+ const secondaryWeaponIdx = CommIn.unPackInt16U();
1152
+ const shellColor = CommIn.unPackInt8U();
1153
+ const hatIdx = CommIn.unPackInt16U();
1154
+ const stampIdx = CommIn.unPackInt16U();
1155
+ const grenadeIdx = CommIn.unPackInt16U();
1156
+ const meleeIdx = CommIn.unPackInt16U();
1157
+ const stampPositionX = CommIn.unPackInt8();
1158
+ const stampPositionY = CommIn.unPackInt8();
1159
+ const findCosmetics = this.intents.includes(this.Intents.COSMETIC_DATA);
1160
+ const primaryWeaponItem = findCosmetics ? findItemById(primaryWeaponIdx) : primaryWeaponIdx;
1161
+ const secondaryWeaponItem = findCosmetics ? findItemById(secondaryWeaponIdx) : secondaryWeaponIdx;
1162
+ const hatItem = findCosmetics ? findItemById(hatIdx) : hatIdx;
1163
+ const stampItem = findCosmetics ? findItemById(stampIdx) : stampIdx;
1164
+ const grenadeItem = findCosmetics ? findItemById(grenadeIdx) : grenadeIdx;
1165
+ const meleeItem = findCosmetics ? findItemById(meleeIdx) : meleeIdx;
1166
+ const player = this.players[id];
1167
+ if (player) {
1168
+ const oldCharacter = { ...player.character };
1169
+ const oldWeaponIdx = player.selectedGun;
1170
+ player.character.eggColor = shellColor;
1171
+ player.character.primaryGun = primaryWeaponItem;
1172
+ player.character.secondaryGun = secondaryWeaponItem;
1173
+ player.character.stamp = stampItem;
1174
+ player.character.hat = hatItem;
1175
+ player.character.grenade = grenadeItem;
1176
+ player.character.melee = meleeItem;
1177
+ player.character.stampPos.x = stampPositionX;
1178
+ player.character.stampPos.y = stampPositionY;
1179
+ player.selectedGun = weaponIndex;
1180
+ player.weapons[0] = new GunList[weaponIndex];
1181
+ if (oldWeaponIdx !== player.selectedGun)
1182
+ this.emit("playerChangeGun", player, oldWeaponIdx, player.selectedGun);
1183
+ if (oldCharacter !== player.character)
1184
+ this.emit("playerChangeCharacter", player, oldCharacter, player.character);
1185
+ }
1186
+ }
1187
+ #processUpdateBalancePacket() {
1188
+ const newBalance = CommIn.unPackInt32U();
1189
+ const oldBalance = this.account.eggBalance;
1190
+ this.account.eggBalance = newBalance;
1191
+ this.emit("balanceUpdate", oldBalance, newBalance);
1192
+ }
1193
+ #processRespawnDeniedPacket() {
1194
+ this.me.playing = false;
1195
+ this.emit("respawnDenied");
1196
+ }
1197
+ #processMeleePacket() {
1198
+ const id = CommIn.unPackInt8U();
1199
+ const player = this.players[id];
1200
+ if (player)
1201
+ this.emit("playerMelee", player);
1202
+ }
1203
+ #processReloadPacket() {
1204
+ const id = CommIn.unPackInt8U();
1205
+ const player = this.players[id];
1206
+ if (!player)
1207
+ return;
1208
+ const playerActiveWeapon = player.weapons[player.activeGun];
1209
+ if (playerActiveWeapon.ammo) {
1210
+ const newRounds = Math.min(Math.min(playerActiveWeapon.ammo.capacity, playerActiveWeapon.ammo.reload) - playerActiveWeapon.ammo.rounds, playerActiveWeapon.ammo.store);
1211
+ playerActiveWeapon.ammo.rounds += newRounds;
1212
+ playerActiveWeapon.ammo.store -= newRounds;
1213
+ }
1214
+ this.emit("playerReload", player, playerActiveWeapon);
1215
+ }
1216
+ updateGameOptions() {
1217
+ const out = new CommOut;
1218
+ out.packInt8(CommCode.gameOptions);
1219
+ out.packInt8(this.game.options.gravity * 4);
1220
+ out.packInt8(this.game.options.damage * 4);
1221
+ out.packInt8(this.game.options.healthRegen * 4);
1222
+ const flags = (this.game.options.locked ? 1 : 0) | (this.game.options.noTeamChange ? 2 : 0) | (this.game.options.noTeamShuffle ? 4 : 0);
1223
+ out.packInt8(flags);
1224
+ this.game.options.weaponsDisabled.forEach((v) => {
1225
+ out.packInt8(v ? 1 : 0);
1226
+ });
1227
+ out.send(this.game.socket);
1228
+ }
1229
+ #processGameRequestOptionsPacket() {
1230
+ this.game.isPrivate = true;
1231
+ this.updateGameOptions();
1232
+ }
1233
+ #processExplodePacket() {
1234
+ const itemType = CommIn.unPackInt8U();
1235
+ let item = CommIn.unPackInt16U();
1236
+ const x = CommIn.unPackFloat();
1237
+ const y = CommIn.unPackFloat();
1238
+ const z = CommIn.unPackFloat();
1239
+ const damage = CommIn.unPackInt8U();
1240
+ const radius = CommIn.unPackFloat();
1241
+ if (this.intents.includes(this.Intents.COSMETIC_DATA))
1242
+ item = findItemById(item);
1243
+ if (itemType === ItemType.Grenade)
1244
+ this.emit("grenadeExplode", item, { x, y, z }, damage, radius);
1245
+ else
1246
+ this.emit("rocketHit", { x, y, z }, damage, radius);
1247
+ }
1248
+ #processThrowGrenadePacket() {
1249
+ const id = CommIn.unPackInt8U();
1250
+ const x = CommIn.unPackFloat();
1251
+ const y = CommIn.unPackFloat();
1252
+ const z = CommIn.unPackFloat();
1253
+ const dx = CommIn.unPackFloat();
1254
+ const dy = CommIn.unPackFloat();
1255
+ const dz = CommIn.unPackFloat();
1256
+ const player = this.players[id];
1257
+ if (player) {
1258
+ player.grenades--;
1259
+ this.emit("playerThrowGrenade", player, { x, y, z }, { x: dx, y: dy, z: dz });
1260
+ }
1261
+ }
1262
+ #processChallengeCompletePacket() {
1263
+ const id = CommIn.unPackInt8U();
1264
+ const challengeId = CommIn.unPackInt8U();
1265
+ const player = this.players[id];
1266
+ if (!player)
1267
+ return;
1268
+ if (!this.intents.includes(this.Intents.CHALLENGES))
1269
+ return this.emit("challengeComplete", player, challengeId);
1270
+ const challenge = this.account.challenges.find((c) => c.id === challengeId);
1271
+ this.emit("challengeComplete", player, challenge);
1272
+ if (player.id === this.me.id)
1273
+ this.refreshChallenges();
1274
+ }
1275
+ #processSocketReadyPacket() {
1276
+ const out = new CommOut;
1277
+ out.packInt8(this.intents.includes(this.Intents.OBSERVE_GAME) ? CommCode.observeGame : CommCode.joinGame);
1278
+ out.packString(this.game.raw.uuid);
1279
+ out.packInt8(+this.intents.includes(this.Intents.VIP_HIDE_BADGE));
1280
+ out.packInt8(this.state.weaponIdx || this.account?.loadout?.classIdx || 0);
1281
+ out.packString(this.state.name);
1282
+ out.packInt32(this.account.session);
1283
+ out.packString(this.account.sessionId);
1284
+ out.packString(this.account.firebaseId);
1285
+ out.send(this.game.socket);
1286
+ }
1287
+ async#processGameJoinedPacket() {
1288
+ this.me.id = CommIn.unPackInt8U();
1289
+ this.me.team = CommIn.unPackInt8U();
1290
+ this.game.gameModeId = CommIn.unPackInt8U();
1291
+ this.game.gameMode = GameModeById[this.game.gameModeId];
1292
+ this.game.mapIdx = CommIn.unPackInt8U();
1293
+ this.game.map = Maps[this.game.mapIdx];
1294
+ this.game.playerLimit = CommIn.unPackInt8U();
1295
+ this.game.isGameOwner = CommIn.unPackInt8U() === 1;
1296
+ this.game.isPrivate = CommIn.unPackInt8U() === 1 || this.game.isGameOwner;
1297
+ CommIn.unPackInt8U();
1298
+ if (this.intents.includes(this.Intents.LOAD_MAP) || this.intents.includes(this.Intents.PATHFINDING)) {
1299
+ this.game.map.raw = await fetchMap(this.game.map.filename, this.game.map.hash);
1300
+ this.emit("mapLoad", this.game.map.raw);
1301
+ if (this.game.gameModeId === GameMode.KOTC) {
1302
+ const meshData = this.game.map.raw.data["DYNAMIC.capture-zone.none"];
1303
+ if (meshData) {
1304
+ this.game.map.zones = initKotcZones(meshData);
1305
+ if (!this.game.activeZone)
1306
+ this.game.activeZone = this.game.map.zones[this.game.zoneNumber - 1];
1307
+ } else
1308
+ delete this.game.map.zones;
1309
+ }
1310
+ if (this.intents.includes(this.Intents.PATHFINDING))
1311
+ this.pathing.nodeList = new NodeList(this.game.map.raw);
1312
+ }
1313
+ this.state.inGame = true;
1314
+ this.lastDeathTime = Date.now();
1315
+ const out = new CommOut;
1316
+ out.packInt8(CommCode.clientReady);
1317
+ out.send(this.game.socket);
1318
+ this.updateIntervalId = setInterval(() => this.update(), 100 / 3);
1319
+ if (this.intents.includes(this.Intents.PING)) {
1320
+ this.lastPingTime = Date.now();
1321
+ const out2 = new CommOut;
1322
+ out2.packInt8(CommCode.ping);
1323
+ out2.send(this.game.socket);
1324
+ }
1325
+ if (this.intents.includes(this.Intents.NO_AFK_KICK))
1326
+ this.afkKickInterval = setInterval(() => {
1327
+ if (this.state.inGame && !this.me.playing && Date.now() - this.lastDeathTime >= 15000) {
1328
+ const out3 = new CommOut;
1329
+ out3.packInt8(CommCode.keepAlive);
1330
+ out3.send(this.game.socket);
1331
+ }
1332
+ }, 15000);
1333
+ this.emit("gameReady");
1334
+ }
1335
+ #processPlayerInfoPacket() {
1336
+ const playerId = CommIn.unPackInt8U();
1337
+ const playerDBId = CommIn.unPackString(128);
1338
+ const playerIp = CommIn.unPackString(32);
1339
+ const player = this.players[playerId];
1340
+ if (!player)
1341
+ return;
1342
+ player.admin = {
1343
+ ip: playerIp,
1344
+ dbId: playerDBId
1345
+ };
1346
+ this.emit("playerInfo", player, playerIp, playerDBId);
1347
+ }
1348
+ packetHandlers = {
1349
+ [CommCode.syncThem]: () => this.#processSyncThemPacket(),
1350
+ [CommCode.fire]: () => this.#processFirePacket(),
1351
+ [CommCode.hitThem]: () => this.#processHitThemPacket(),
1352
+ [CommCode.syncMe]: () => this.#processSyncMePacket(),
1353
+ [CommCode.hitMe]: () => this.#processHitMePacket(),
1354
+ [CommCode.swapWeapon]: () => this.#processSwapWeaponPacket(),
1355
+ [CommCode.collectItem]: () => this.#processCollectPacket(),
1356
+ [CommCode.respawn]: () => this.#processRespawnPacket(),
1357
+ [CommCode.die]: () => this.#processDeathPacket(),
1358
+ [CommCode.pause]: () => this.#processPausePacket(),
1359
+ [CommCode.chat]: () => this.#processChatPacket(),
1360
+ [CommCode.addPlayer]: () => this.#processAddPlayerPacket(),
1361
+ [CommCode.removePlayer]: () => this.#processRemovePlayerPacket(),
1362
+ [CommCode.eventModifier]: () => this.#processEventModifierPacket(),
1363
+ [CommCode.metaGameState]: () => this.#processGameStatePacket(),
1364
+ [CommCode.beginShellStreak]: () => this.#processBeginStreakPacket(),
1365
+ [CommCode.endShellStreak]: () => this.#processEndStreakPacket(),
1366
+ [CommCode.hitMeHardBoiled]: () => this.#processHitShieldPacket(),
1367
+ [CommCode.gameOptions]: () => this.#processGameOptionsPacket(),
1368
+ [CommCode.ping]: () => this.#processPingPacket(),
1369
+ [CommCode.switchTeam]: () => this.#processSwitchTeamPacket(),
1370
+ [CommCode.changeCharacter]: () => this.#processChangeCharacterPacket(),
1371
+ [CommCode.reload]: () => this.#processReloadPacket(),
1372
+ [CommCode.explode]: () => this.#processExplodePacket(),
1373
+ [CommCode.throwGrenade]: () => this.#processThrowGrenadePacket(),
1374
+ [CommCode.spawnItem]: () => this.#processSpawnItemPacket(),
1375
+ [CommCode.melee]: () => this.#processMeleePacket(),
1376
+ [CommCode.updateBalance]: () => this.#processUpdateBalancePacket(),
1377
+ [CommCode.challengeCompleted]: () => this.#processChallengeCompletePacket(),
1378
+ [CommCode.socketReady]: () => this.#processSocketReadyPacket(),
1379
+ [CommCode.gameJoined]: () => this.#processGameJoinedPacket(),
1380
+ [CommCode.gameAction]: () => this.#processGameActionPacket(),
1381
+ [CommCode.requestGameOptions]: () => this.#processGameRequestOptionsPacket(),
1382
+ [CommCode.respawnDenied]: () => this.#processRespawnDeniedPacket(),
1383
+ [CommCode.playerInfo]: () => this.#processPlayerInfoPacket(),
1384
+ [CommCode.expireUpgrade]: () => {},
1385
+ [CommCode.clientReady]: () => {},
1386
+ [CommCode.musicInfo]: () => CommIn.unPackLongString()
1387
+ };
1388
+ processPacket(packet) {
1389
+ CommIn.init(packet);
1390
+ if (this.intents.includes(this.Intents.PACKET_HOOK))
1391
+ this.emit("packet", packet);
1392
+ let lastCommand = 0;
1393
+ let lastCode = 0;
1394
+ let abort = false;
1395
+ while (CommIn.isMoreDataAvailable() && !abort) {
1396
+ const cmd = CommIn.unPackInt8U();
1397
+ const handler = this.packetHandlers[cmd];
1398
+ if (handler)
1399
+ handler();
1400
+ else {
1401
+ console.error(`processPacket: I got but couldn't identify a: ${Object.keys(CommCode).find((k) => CommCode[k] === cmd)} ${cmd}`);
1402
+ if (lastCommand)
1403
+ console.error(`processPacket: It may be a result of the ${lastCommand} command (${lastCode}).`);
1404
+ abort = true;
1405
+ break;
1406
+ }
1407
+ lastCommand = Object.keys(CommCode).find((k) => CommCode[k] === cmd);
1408
+ lastCode = cmd;
1409
+ if (this.intents.includes(this.Intents.LOG_PACKETS))
1410
+ console.log(`[LOG_PACKETS] Packet ${lastCommand}: ${lastCode}`);
1411
+ }
1412
+ }
1413
+ async checkChiknWinner() {
1414
+ const response = await this.api.queryServices({
1415
+ cmd: "chicknWinnerReady",
1416
+ id: this.account.id,
1417
+ sessionId: this.account.sessionId
1418
+ });
1419
+ if (typeof response === "string")
1420
+ return response;
1421
+ this.account.cw.limit = response.limit;
1422
+ this.account.cw.atLimit = response.limit >= 4;
1423
+ this.account.cw.secondsUntilPlay = (this.account.cw.atLimit ? response.period : response.span) || 0;
1424
+ this.account.cw.canPlayAgain = Date.now() + this.account.cw.secondsUntilPlay * 1000;
1425
+ return this.account.cw;
1426
+ }
1427
+ async playChiknWinner(doPrematureCooldownCheck = true) {
1428
+ if (this.account.cw.atLimit || this.account.cw.limit > ChiknWinnerDailyLimit)
1429
+ return "hit_daily_limit";
1430
+ if (this.account.cw.canPlayAgain > Date.now() && doPrematureCooldownCheck)
1431
+ return "on_cooldown";
1432
+ const response = await this.api.queryServices({
1433
+ cmd: "incentivizedVideoReward",
1434
+ firebaseId: this.account.firebaseId,
1435
+ id: this.account.id,
1436
+ sessionId: this.account.sessionId,
1437
+ token: null
1438
+ });
1439
+ if (typeof response === "string")
1440
+ return response;
1441
+ if (response.error) {
1442
+ if (response.error === "RATELIMITED" || response.error === "RATELMITED") {
1443
+ await this.checkChiknWinner();
1444
+ return "on_cooldown";
1445
+ } else if (response.error === "SESSION_EXPIRED") {
1446
+ this.emit("sessionExpired");
1447
+ return "session_expired";
1448
+ }
1449
+ console.error("Unknown Chikn Winner response, report this on Github:", response);
1450
+ return "unknown_error";
1451
+ }
1452
+ if (response.reward) {
1453
+ this.account.eggBalance += response.reward.eggsGiven;
1454
+ response.reward.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
1455
+ await this.checkChiknWinner();
1456
+ return response.reward;
1457
+ }
1458
+ console.error("Unknown Chikn Winner response, report this on Github:", response);
1459
+ return "unknown_error";
1460
+ }
1461
+ async resetChiknWinner() {
1462
+ if (this.account.eggBalance < 200)
1463
+ return "not_enough_eggs";
1464
+ if (!this.account.cw.atLimit)
1465
+ return "not_at_limit";
1466
+ const response = await this.api.queryServices({
1467
+ cmd: "chwReset",
1468
+ sessionId: this.account.sessionId
1469
+ });
1470
+ if (typeof response === "string")
1471
+ return response;
1472
+ if (response.result !== "SUCCESS") {
1473
+ console.error("Unknown Chikn Winner reset response, report this on Github:", response);
1474
+ return "unknown_error";
1475
+ }
1476
+ this.account.eggBalance -= 200;
1477
+ await this.checkChiknWinner();
1478
+ return this.account.cw;
1479
+ }
1480
+ canSee(target) {
1481
+ if (!this.intents.includes(this.Intents.PATHFINDING))
1482
+ return this.processError("You must have the PATHFINDING intent to use this method.");
1483
+ return this.pathing.nodeList.hasLineOfSight(this.me.position, target.position);
1484
+ }
1485
+ async refreshChallenges() {
1486
+ const result = await this.api.queryServices({
1487
+ cmd: "challengeGetDaily",
1488
+ sessionId: this.account.sessionId,
1489
+ playerId: this.account.id
1490
+ });
1491
+ if (typeof result === "string")
1492
+ return result;
1493
+ this.#importChallenges(result);
1494
+ return this.account.challenges;
1495
+ }
1496
+ async rerollChallenge(challengeId) {
1497
+ const result = await this.api.queryServices({
1498
+ cmd: "challengeRerollSlot",
1499
+ sessionId: this.account.sessionId,
1500
+ slotId: challengeId
1501
+ });
1502
+ if (typeof result === "string")
1503
+ return result;
1504
+ this.#importChallenges(result);
1505
+ return this.account.challenges;
1506
+ }
1507
+ async claimChallenge(challengeId) {
1508
+ const result = await this.api.queryServices({
1509
+ cmd: "challengeClaimReward",
1510
+ sessionId: this.account.sessionId,
1511
+ slotId: challengeId
1512
+ });
1513
+ if (typeof result === "string")
1514
+ return result;
1515
+ this.#importChallenges(result.challenges);
1516
+ if (result.reward > 0)
1517
+ this.account.eggBalance += result.reward;
1518
+ return {
1519
+ eggReward: result.reward,
1520
+ updatedChallenges: this.account.challenges
1521
+ };
1522
+ }
1523
+ async refreshBalance() {
1524
+ const result = await this.api.queryServices({
1525
+ cmd: "checkBalance",
1526
+ firebaseId: this.account.firebaseId,
1527
+ sessionId: this.account.sessionId
1528
+ });
1529
+ if (typeof result === "string")
1530
+ return result;
1531
+ this.account.eggBalance = result.currentBalance;
1532
+ return result.currentBalance;
1533
+ }
1534
+ async redeemCode(code) {
1535
+ const result = await this.api.queryServices({
1536
+ cmd: "redeem",
1537
+ firebaseId: this.account.firebaseId,
1538
+ sessionId: this.account.sessionId,
1539
+ id: this.account.id,
1540
+ code
1541
+ });
1542
+ if (typeof result === "string")
1543
+ return result;
1544
+ if (result.result === "SUCCESS") {
1545
+ this.account.eggBalance = result.eggs_given;
1546
+ result.item_ids.forEach((id) => this.account.ownedItemIds.push(id));
1547
+ return {
1548
+ result,
1549
+ eggsGiven: result.eggs_given,
1550
+ itemIds: result.item_ids
1551
+ };
1552
+ }
1553
+ return result;
1554
+ }
1555
+ async claimURLReward(reward) {
1556
+ const result = await this.api.queryServices({
1557
+ cmd: "urlRewardParams",
1558
+ firebaseId: this.account.firebaseId,
1559
+ sessionId: this.account.sessionId,
1560
+ reward
1561
+ });
1562
+ if (typeof result === "string")
1563
+ return result;
1564
+ if (result.result === "SUCCESS") {
1565
+ this.account.eggBalance += result.eggsGiven;
1566
+ result.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
1567
+ }
1568
+ return result;
1569
+ }
1570
+ async claimSocialReward(rewardTag) {
1571
+ const result = await this.api.queryServices({
1572
+ cmd: "reward",
1573
+ firebaseId: this.account.firebaseId,
1574
+ sessionId: this.account.sessionId,
1575
+ rewardTag
1576
+ });
1577
+ if (typeof result === "string")
1578
+ return result;
1579
+ if (result.result === "SUCCESS") {
1580
+ this.account.eggBalance += result.eggsGiven;
1581
+ result.itemIds.forEach((id) => this.account.ownedItemIds.push(id));
1582
+ }
1583
+ return result;
1584
+ }
1585
+ async buyItem(itemId) {
1586
+ const result = await this.api.queryServices({
1587
+ cmd: "buy",
1588
+ firebaseId: this.account.firebaseId,
1589
+ sessionId: this.account.sessionId,
1590
+ itemId,
1591
+ save: true
1592
+ });
1593
+ if (typeof result === "string")
1594
+ return result;
1595
+ if (result.result === "SUCCESS") {
1596
+ this.account.eggBalance = result.currentBalance;
1597
+ this.account.ownedItemIds.push(result.itemId);
1598
+ }
1599
+ return result;
1600
+ }
1601
+ processError(...params) {
1602
+ const error = params.join(" ");
1603
+ if (this.#hooks.error && this.#hooks.error.length)
1604
+ this.emit("error", error);
1605
+ else if (this.intents.includes(this.Intents.NO_EXIT_ON_ERROR))
1606
+ console.error(error);
1607
+ else
1608
+ throw new Error(error);
1609
+ }
1610
+ leave(code = CloseCode.mainMenu) {
1611
+ if (this.hasQuit)
1612
+ return;
1613
+ if (code > -1) {
1614
+ this.game?.socket?.close(code);
1615
+ this.state.left = true;
1616
+ this.emit("leave", code);
1617
+ }
1618
+ clearInterval(this.updateIntervalId);
1619
+ this.#dispatches = [];
1620
+ this.state.inGame = false;
1621
+ this.state.chatLines = 0;
1622
+ this.state.reloading = false;
1623
+ this.state.swappingGun = false;
1624
+ this.state.usingMelee = false;
1625
+ this.state.stateIdx = 0;
1626
+ this.state.serverStateIdx = 0;
1627
+ this.state.shotsFired = 0;
1628
+ this.state.buffer = [];
1629
+ this.players = {};
1630
+ this.me = new GamePlayer({});
1631
+ this.game = this.#initialGame;
1632
+ this.ping = 0;
1633
+ this.lastPingTime = -1;
1634
+ this.lastDeathTime = -1;
1635
+ this.lastUpdateTick = 0;
1636
+ this.pathing = {
1637
+ nodeList: null,
1638
+ followingPath: false,
1639
+ activePath: null,
1640
+ activeNode: null,
1641
+ activeNodeIdx: 0
1642
+ };
1643
+ }
1644
+ logout() {
1645
+ this.account = this.#initialAccount;
1646
+ if (this.intents.includes(this.Intents.RENEW_SESSION))
1647
+ clearInterval(this.renewSessionInterval);
1648
+ }
1649
+ quit(noCleanup = false) {
1650
+ if (this.hasQuit)
1651
+ return;
1652
+ this.leave();
1653
+ if (this.matchmaker) {
1654
+ this.matchmaker.close();
1655
+ if (!noCleanup)
1656
+ delete this.matchmaker;
1657
+ }
1658
+ if (!noCleanup) {
1659
+ delete this.account;
1660
+ delete this.api;
1661
+ delete this.game;
1662
+ delete this.me;
1663
+ delete this.pathing;
1664
+ delete this.players;
1665
+ delete this.state;
1666
+ this.#initialAccount = {};
1667
+ this.#initialGame = {};
1668
+ this.#hooks = {};
1669
+ this.#globalHooks = [];
1670
+ this.#dispatches = [];
1671
+ }
1672
+ if (this.intents.includes(this.Intents.NO_AFK_KICK))
1673
+ clearInterval(this.afkKickInterval);
1674
+ if (this.intents.includes(this.Intents.RENEW_SESSION))
1675
+ clearInterval(this.renewSessionInterval);
1676
+ this.hasQuit = true;
1677
+ }
1678
+ }
1679
+ export default Bot;