diff --git a/client/src/emote.js b/client/src/emote.js index eba07dcc..adc9148e 100644 --- a/client/src/emote.js +++ b/client/src/emote.js @@ -400,7 +400,7 @@ v([109, 101, 110, 117]); v([105, 110, 105, 116]); v([99, 104, 101, 97, 116]); EmoteBarn.prototype = { - n: function() { + free: function() { if (device.touch) { $(document).off("touchstart", this.onTouchStart); this.emoteButtonElem.off("touchstart"); @@ -689,11 +689,11 @@ EmoteBarn.prototype = { } } this.dr = r; - if ((t != r.__id || !!r.Le.he) && !this.disable) { - this.n(); + if ((t != r.__id || !!r.netData.he) && !this.disable) { + this.free(); this.disable = true; } - const z = m.perkMode && !r.Le.Te; + const z = m.perkMode && !r.netData.Te; if ( !this.disable && !z && @@ -853,7 +853,7 @@ EmoteBarn.prototype = { let G = v2.create(0, 0); let X = 0; const K = S.u(U.playerId); - if (K && !K.Le.he) { + if (K && !K.netData.he) { G = v2.copy(K.pos); X = K.layer; W = true; diff --git a/client/src/game.js b/client/src/game.js index cba0897a..b51e836c 100644 --- a/client/src/game.js +++ b/client/src/game.js @@ -11,19 +11,19 @@ import proxy from "./proxy"; import { RoleDefs } from "../../shared/defs/gameObjects/roleDefs"; import { GameObjectDefs } from "../../shared/defs/gameObjectDefs"; import firebaseManager from "./firebaseManager"; -import { AirDropPool } from "./objects/aidrop"; +import Aidrop from "./objects/aidrop"; import Bullet from "./objects/bullet"; import Camera from "./camera"; import DeadBody from "./objects/deadBody"; import debugLines from "./debugLines"; import Decal from "./objects/decal"; import emote from "./emote"; -import explosion from "./objects/explosion"; -import flare from "./objects/flare"; -import gas from "./gas"; +import Explosion from "./objects/explosion"; +import Flare from "./objects/flare"; +import Gas from "./gas"; import input from "./input"; -import loot from "./objects/loot"; -import map from "./map"; +import Loot from "./objects/loot"; +import Map from "./map"; import ObjectPool from "./objects/objectPool"; import Particles from "./objects/particles"; import Plane from "./objects/plane"; @@ -36,21 +36,8 @@ import Touch from "./touch"; import Ui from "./ui"; import Ui2 from "./ui2"; -const n = GameConfig.Input; +const Input = GameConfig.Input; -function a(e, t, r) { - if (t in e) { - Object.defineProperty(e, t, { - value: r, - enumerable: true, - configurable: true, - writable: true - }); - } else { - e[t] = r; - } - return e; -} export class Game { constructor(pixi, ft, localization, config, i, o, s, l, resourceManager, onJoin, onQuit) { this.initialized = false; @@ -72,7 +59,7 @@ export class Game { this.connected = false; } - vt(e, t, r, a, i) { + tryJoinGame(e, t, r, a, i) { const o = this; if ( !this.connecting && @@ -120,11 +107,11 @@ export class Game { if (r == net.Msg.None) { break; } - o.kt(r, t.getStream()); + o.onMsg(r, t.getStream()); } }; this.ws.onclose = function() { - const e = o.zt?.displayingStats; + const e = o.uiManager?.displayingStats; const t = o.connecting; const r = o.connected; o.connecting = false; @@ -146,84 +133,83 @@ export class Game { } } - o() { - this.canvasMode = - this.pixi.renderer.type == PIXI.RENDERER_TYPE.CANVAS; + init() { + this.canvasMode = this.pixi.renderer.type == PIXI.RENDERER_TYPE.CANVAS; this.I = false; this.It = 0; this.U = false; this.Tt = false; - this.Mt = new Touch.Pt(this.bt, this.config); - this.De = new Camera(); - this.Ct = new Renderer.At(this, this.canvasMode); - this.Ot = new Particles.ParticleBarn(this.Ct); - this.Dt = new Decal.DecalBarn(); - this.Et = new map.Bt(this.Dt); - this.Rt = new Player.Lt(); - this.qt = new Bullet.Ft(); - this.jt = new flare.Nt(); - this.Ht = new Projectile.Vt(); - this.Ut = new explosion.ExplosionBarn(); - this.Wt = new Plane.Gt(this.ft); - this.Xt = new AirDropPool(); - this.Kt = new Smoke.SmokeBarn(); - this.Zt = new DeadBody.DeadBodyBarn(); - this.Yt = new loot.Jt(); - this.Qt = new gas.Gas(this.canvasMode); - this.zt = new Ui.He( + this.touch = new Touch.Touch(this.bt, this.config); + this.camera = new Camera(); + this.renderer = new Renderer.Renderer(this, this.canvasMode); + this.particleBarn = new Particles.ParticleBarn(this.renderer); + this.decalBarn = new Decal.DecalBarn(); + this.map = new Map.Map(this.decalBarn); + this.playerBarn = new Player.PlayerBarn(); + this.bulletBarn = new Bullet.BulletBarn(); + this.flareBarn = new Flare.FlareBarn(); + this.projectileBarn = new Projectile.ProjectileBarn(); + this.explosionBarn = new Explosion.ExplosionBarn(); + this.planeBarn = new Plane.PlaneBarn(this.ft); + this.airdropBarn = new Aidrop.AirdropBarn(); + this.smokeBarn = new Smoke.SmokeBarn(); + this.deadBodyBarn = new DeadBody.DeadBodyBarn(); + this.lootBarn = new Loot.LootBarn(); + this.gas = new Gas.Gas(this.canvasMode); + this.uiManager = new Ui.He( this, this.ft, - this.Ot, - this.Wt, + this.particleBarn, + this.planeBarn, this.localization, this.canvasMode, - this.Mt, + this.touch, this.xt, this.St ); - this.er = new Ui2.Ui2(this.localization, this.xt); - this.ar = new emote.EmoteBarn( + this.ui2Manager = new Ui2.Ui2(this.localization, this.xt); + this.emoteBarn = new emote.EmoteBarn( this.ft, - this.zt, - this.Rt, - this.De, - this.Et + this.uiManager, + this.playerBarn, + this.camera, + this.map ); - this.or = new Shot.ShotBarn(this.Ot, this.ft, this.zt); - const e = {}; - a(e, GameObject.Type.Player, this.Rt.$e); - a(e, GameObject.Type.Obstacle, this.Et.Ve); - a(e, GameObject.Type.Loot, this.Yt.sr); - a(e, GameObject.Type.DeadBody, this.Zt.ot); - a(e, GameObject.Type.Building, this.Et.nr); - a(e, GameObject.Type.Structure, this.Et.lr); - a(e, GameObject.Type.Decal, this.Dt._); - a(e, GameObject.Type.Projectile, this.Ht.cr); - a(e, GameObject.Type.Smoke, this.Kt.e); - a(e, GameObject.Type.Airdrop, this.Xt.re); - const t = e; - this.mr = new ObjectPool.Creator(); + this.shotBarn = new Shot.ShotBarn(this.particleBarn, this.ft, this.uiManager); + const t = { + [GameObject.Type.Player]: this.playerBarn.$e, + [GameObject.Type.Obstacle]: this.map.Ve, + [GameObject.Type.Loot]: this.lootBarn.sr, + [GameObject.Type.DeadBody]: this.deadBodyBarn.ot, + [GameObject.Type.Building]: this.map.nr, + [GameObject.Type.Structure]: this.map.lr, + [GameObject.Type.Decal]: this.decalBarn._, + [GameObject.Type.Projectile]: this.projectileBarn.cr, + [GameObject.Type.Smoke]: this.smokeBarn.e, + [GameObject.Type.Airdrop]: this.airdropBarn.re + }; + this.objectCreator = new ObjectPool.Creator(); for (const r in t) { if (t.hasOwnProperty(r)) { - this.mr.registerType(r, t[r]); + this.objectCreator.registerType(r, t[r]); } } this.debugDisplay = new PIXI.Graphics(); for ( let i = [ - this.Et.display.ground, - this.Ct.layers[0], - this.Ct.ground, - this.Ct.layers[1], - this.Ct.layers[2], - this.Ct.layers[3], + this.map.display.ground, + this.renderer.layers[0], + this.renderer.ground, + this.renderer.layers[1], + this.renderer.layers[2], + this.renderer.layers[3], this.debugDisplay, - this.Qt.gasRenderer.display, - this.Mt.container, - this.ar.container, - this.zt.container, - this.zt.Pe.container, - this.ar.indContainer + this.gas.gasRenderer.display, + this.touch.container, + this.emoteBarn.container, + this.uiManager.container, + this.uiManager.Pe.container, + this.emoteBarn.indContainer ], s = 0; s < i.length; @@ -257,13 +243,13 @@ export class Game { this.seqSendTime = 0; this.pings = []; this.debugPingTime = 0; - this.De.setShakeEnabled(this.config.get("screenShake")); - this.Rt.anonPlayerNames = + this.camera.setShakeEnabled(this.config.get("screenShake")); + this.playerBarn.anonPlayerNames = this.config.get("anonPlayerNames"); this.initialized = true; } - n() { + free() { if (this.ws) { this.ws.onmessage = function() { }; this.ws.close(); @@ -275,15 +261,15 @@ export class Game { this.initialized = false; this.updatePass = false; this.updatePassDelay = 0; - this.ar.n(); - this.er.n(); - this.zt.n(); - this.Qt.free(); - this.Xt.n(); - this.Wt.n(); - this.Et.n(); - this.Ot.n(); - this.Ct.n(); + this.emoteBarn.free(); + this.ui2Manager.free(); + this.uiManager.free(); + this.gas.free(); + this.airdropBarn.free(); + this.planeBarn.free(); + this.map.free(); + this.particleBarn.free(); + this.renderer.free(); this.bt.n(); this.ft.stopAll(); while (this.pixi.stage.children.length > 0) { @@ -296,18 +282,18 @@ export class Game { } } - gr() { + warnPageReload() { return ( this.initialized && this.playing && !this.spectating && - !this.zt.displayingStats + !this.uiManager.displayingStats ); } - m(e) { - const t = this.Kt.particles; - const r = this.Et.Ve.p(); + update(e) { + const t = this.smokeBarn.particles; + const r = this.map.Ve.p(); let a = 0; this.I = true; const i = {}; @@ -315,58 +301,58 @@ export class Game { if (this.playing) { this.playingTicker += e; } - this.Rt.m( + this.playerBarn.m( e, this.hr, this.teamMode, - this.Ct, - this.Ot, - this.De, - this.Et, + this.renderer, + this.particleBarn, + this.camera, + this.map, this.xt, this.ft, - this.er, - this.ar.wheelKeyTriggered, - this.zt.displayingStats, + this.ui2Manager, + this.emoteBarn.wheelKeyTriggered, + this.uiManager.displayingStats, this.spectating ); this.updateAmbience(); - this.De.pos = v2.copy(this.dr.pos); - this.De.applyShake(); + this.camera.pos = v2.copy(this.dr.pos); + this.camera.applyShake(); const o = this.dr.yr(); - const l = math.min(this.De.screenWidth, this.De.screenHeight); - const g = math.max(this.De.screenWidth, this.De.screenHeight); + const l = math.min(this.camera.screenWidth, this.camera.screenHeight); + const g = math.max(this.camera.screenWidth, this.camera.screenHeight); const y = math.max(l * (16 / 9), g); - this.De.q = (y * 0.5) / (o * this.De.ppu); + this.camera.q = (y * 0.5) / (o * this.camera.ppu); const w = this.dr.zoomFast ? 3 : 2; const f = this.dr.zoomFast ? 3 : 1.4; - const _ = this.De.q > this.De.O ? w : f; - this.De.O = math.lerp(e * _, this.De.O, this.De.q); - this.ft.cameraPos = v2.copy(this.De.pos); + const _ = this.camera.q > this.camera.O ? w : f; + this.camera.O = math.lerp(e * _, this.camera.O, this.camera.q); + this.ft.cameraPos = v2.copy(this.camera.pos); if (this.bt.We(input.Key.Escape)) { - this.zt.toggleEscMenu(); + this.uiManager.toggleEscMenu(); } if ( - this.xt.isBindPressed(n.ToggleMap) || + this.xt.isBindPressed(Input.ToggleMap) || (this.bt.We(input.Key.G) && !this.xt.isKeyBound(input.Key.G)) ) { - this.zt.displayMapLarge(false); + this.uiManager.displayMapLarge(false); } - if (this.xt.isBindPressed(n.CycleUIMode)) { - this.zt.cycleVisibilityMode(); + if (this.xt.isBindPressed(Input.CycleUIMode)) { + this.uiManager.cycleVisibilityMode(); } if ( - this.xt.isBindPressed(n.HideUI) || - (this.bt.We(input.Key.Escape) && !this.zt.hudVisible) + this.xt.isBindPressed(Input.HideUI) || + (this.bt.We(input.Key.Escape) && !this.uiManager.hudVisible) ) { - this.zt.cycleHud(); + this.uiManager.cycleHud(); } const b = this.dr.pos; - const x = this.De.j(this.bt.Ue); + const x = this.camera.j(this.bt.Ue); const S = v2.sub(x, b); let v = v2.length(S); let k = v > 0.00001 ? v2.div(S, v) : v2.create(1, 0); - if (this.ar.wheelDisplayed) { + if (this.emoteBarn.wheelDisplayed) { v = this.prevInputMsg.toMouseLen; k = this.prevInputMsg.toMouseDir; } @@ -374,26 +360,26 @@ export class Game { z.seq = this.seq; if (!this.spectating) { if (device.touch) { - const I = this.Mt.getTouchMovement(this.De); - const M = this.Mt.getAimMovement(this.dr, this.De); + const I = this.touch.getTouchMovement(this.camera); + const M = this.touch.getAimMovement(this.dr, this.camera); let P = v2.copy(M.aimMovement.toAimDir); - this.Mt.turnDirTicker -= e; - if (this.Mt.moveDetected && !M.touched) { + this.touch.turnDirTicker -= e; + if (this.touch.moveDetected && !M.touched) { const C = v2.normalizeSafe( I.toMoveDir, v2.create(1, 0) ); const A = - this.Mt.turnDirTicker < 0 + this.touch.turnDirTicker < 0 ? C : M.aimMovement.toAimDir; - this.Mt.setAimDir(A); + this.touch.setAimDir(A); P = A; } if (M.touched) { - this.Mt.turnDirTicker = this.Mt.turnDirCooldown; + this.touch.turnDirTicker = this.touch.turnDirCooldown; } - if (this.Mt.moveDetected) { + if (this.touch.moveDetected) { z.touchMoveDir = v2.normalizeSafe( I.toMoveDir, v2.create(1, 0) @@ -407,25 +393,25 @@ export class Game { z.touchMoveActive = true; const O = M.aimMovement.toAimLen; const D = - math.clamp(O / this.Mt.padPosRange, 0, 1) * + math.clamp(O / this.touch.padPosRange, 0, 1) * GameConfig.player.throwableMaxMouseDist; z.toMouseLen = D; z.toMouseDir = P; } else { z.moveLeft = - this.xt.isBindDown(n.MoveLeft) || + this.xt.isBindDown(Input.MoveLeft) || (this.bt.Ye(input.Key.Left) && !this.xt.isKeyBound(input.Key.Left)); z.moveRight = - this.xt.isBindDown(n.MoveRight) || + this.xt.isBindDown(Input.MoveRight) || (this.bt.Ye(input.Key.Right) && !this.xt.isKeyBound(input.Key.Right)); z.moveUp = - this.xt.isBindDown(n.MoveUp) || + this.xt.isBindDown(Input.MoveUp) || (this.bt.Ye(input.Key.Up) && !this.xt.isKeyBound(input.Key.Up)); z.moveDown = - this.xt.isBindDown(n.MoveDown) || + this.xt.isBindDown(Input.MoveDown) || (this.bt.Ye(input.Key.Down) && !this.xt.isKeyBound(input.Key.Down)); z.toMouseDir = v2.copy(k); @@ -446,27 +432,27 @@ export class Game { net.Constants.MouseMaxDist ); z.shootStart = - this.xt.isBindPressed(n.Fire) || this.Mt.wr; - z.shootHold = this.xt.isBindDown(n.Fire) || this.Mt.wr; - z.portrait = this.De.screenWidth < this.De.screenHeight; + this.xt.isBindPressed(Input.Fire) || this.touch.wr; + z.shootHold = this.xt.isBindDown(Input.Fire) || this.touch.wr; + z.portrait = this.camera.screenWidth < this.camera.screenHeight; for ( let E = [ - n.Reload, - n.Revive, - n.Use, - n.Loot, - n.Cancel, - n.EquipPrimary, - n.EquipSecondary, - n.EquipThrowable, - n.EquipMelee, - n.EquipNextWeap, - n.EquipPrevWeap, - n.EquipLastWeap, - n.EquipOtherGun, - n.EquipPrevScope, - n.EquipNextScope, - n.StowWeapons + Input.Reload, + Input.Revive, + Input.Use, + Input.Loot, + Input.Cancel, + Input.EquipPrimary, + Input.EquipSecondary, + Input.EquipThrowable, + Input.EquipMelee, + Input.EquipNextWeap, + Input.EquipPrevWeap, + Input.EquipLastWeap, + Input.EquipOtherGun, + Input.EquipPrevScope, + Input.EquipNextScope, + Input.StowWeapons ], B = 0; B < E.length; @@ -477,9 +463,9 @@ export class Game { z.addInput(R); } } - if (this.xt.isBindPressed(n.Interact)) { + if (this.xt.isBindPressed(Input.Interact)) { const q = []; - const L = [n.Revive, n.Use, n.Loot]; + const L = [Input.Revive, Input.Use, Input.Loot]; for (let F = 0; F < L.length; F++) { const j = L[F]; if (!this.xt.getBind(j)) { @@ -487,7 +473,7 @@ export class Game { } } if (q.length == L.length) { - z.addInput(n.Interact); + z.addInput(Input.Interact); } else { for (let N = 0; N < q.length; N++) { z.addInput(q[N]); @@ -495,28 +481,28 @@ export class Game { } } if ( - this.xt.isBindPressed(n.SwapWeapSlots) || - this.zt.swapWeapSlots + this.xt.isBindPressed(Input.SwapWeapSlots) || + this.uiManager.swapWeapSlots ) { - z.addInput(n.SwapWeapSlots); + z.addInput(Input.SwapWeapSlots); this.dr.gunSwitchCooldown = 0; } - if (this.zt.reloadTouched) { - z.addInput(n.Reload); + if (this.uiManager.reloadTouched) { + z.addInput(Input.Reload); } - if (this.zt.interactionTouched) { - z.addInput(n.Interact); - z.addInput(n.Cancel); + if (this.uiManager.interactionTouched) { + z.addInput(Input.Interact); + z.addInput(Input.Cancel); } - for (let H = 0; H < this.er.uiEvents.length; H++) { - const V = this.er.uiEvents[H]; + for (let H = 0; H < this.ui2Manager.uiEvents.length; H++) { + const V = this.ui2Manager.uiEvents[H]; if (V.action == "use") { if (V.type == "weapon") { const U = { - 0: n.EquipPrimary, - 1: n.EquipSecondary, - 2: n.EquipMelee, - 3: n.EquipThrowable + 0: Input.EquipPrimary, + 1: Input.EquipSecondary, + 2: Input.EquipMelee, + 3: Input.EquipThrowable }; const W = U[V.data]; if (W) { @@ -527,18 +513,18 @@ export class Game { } } } - if (this.xt.isBindPressed(n.UseBandage)) { + if (this.xt.isBindPressed(Input.UseBandage)) { z.useItem = "bandage"; - } else if (this.xt.isBindPressed(n.UseHealthKit)) { + } else if (this.xt.isBindPressed(Input.UseHealthKit)) { z.useItem = "healthkit"; - } else if (this.xt.isBindPressed(n.UseSoda)) { + } else if (this.xt.isBindPressed(Input.UseSoda)) { z.useItem = "soda"; - } else if (this.xt.isBindPressed(n.UsePainkiller)) { + } else if (this.xt.isBindPressed(Input.UsePainkiller)) { z.useItem = "painkiller"; } let G = false; - for (let X = 0; X < this.er.uiEvents.length; X++) { - const K = this.er.uiEvents[X]; + for (let X = 0; X < this.ui2Manager.uiEvents.length; X++) { + const K = this.ui2Manager.uiEvents[X]; if (K.action == "drop") { const Z = new net.DropItemMsg(); if (K.type == "weapon") { @@ -546,7 +532,7 @@ export class Game { Z.item = Y[K.data].type; Z.weapIdx = K.data; } else if (K.type == "perk") { - const J = this.dr.Le.Me; + const J = this.dr.netData.Me; const Q = J.length > K.data ? J[K.data] : null; if (Q?.droppable) { @@ -556,9 +542,9 @@ export class Game { let $ = ""; $ = K.data == "helmet" - ? this.dr.Le.le + ? this.dr.netData.le : K.data == "chest" - ? this.dr.Le.ce + ? this.dr.netData.ce : K.data; Z.item = $; } @@ -575,19 +561,19 @@ export class Game { channel: "ui" }); } - if (this.zt.roleSelected) { + if (this.uiManager.roleSelected) { const ee = new net.PerkModeRoleSelectMsg(); - ee.role = this.zt.roleSelected; + ee.role = this.uiManager.roleSelected; this.$(net.Msg.PerkModeRoleSelect, ee, 128); this.config.set("perkModeRole", ee.role); } } - const te = this.zt.specBegin; + const te = this.uiManager.specBegin; const re = - this.zt.specNext || + this.uiManager.specNext || (this.spectating && this.bt.We(input.Key.Right)); const ae = - this.zt.specPrev || + this.uiManager.specPrev || (this.spectating && this.bt.We(input.Key.Left)); const ie = this.bt.We(input.Key.Right) || this.bt.We(input.Key.Left); @@ -599,13 +585,13 @@ export class Game { oe.specForce = ie; this.$(net.Msg.Spectate, oe, 128); } - this.zt.specBegin = false; - this.zt.specNext = false; - this.zt.specPrev = false; - this.zt.reloadTouched = false; - this.zt.interactionTouched = false; - this.zt.swapWeapSlots = false; - this.zt.roleSelected = ""; + this.uiManager.specBegin = false; + this.uiManager.specNext = false; + this.uiManager.specPrev = false; + this.uiManager.reloadTouched = false; + this.uiManager.interactionTouched = false; + this.uiManager.swapWeapSlots = false; + this.uiManager.roleSelected = ""; let se = false; for (const ne in z) { if (z.hasOwnProperty(ne)) { @@ -648,139 +634,139 @@ export class Game { this.inputMsgTimeout = 1; this.prevInputMsg = z; } - this.er.flushInput(); - this.Et.m( + this.ui2Manager.flushInput(); + this.map.m( e, this.dr, - this.Rt, - this.Ot, + this.playerBarn, + this.particleBarn, this.ft, this._t, - this.Ct, - this.De, + this.renderer, + this.camera, t, i ); - this.Yt.m(e, this.dr, this.Et, this.ft, this.De, i); - this.qt.m( + this.lootBarn.m(e, this.dr, this.map, this.ft, this.camera, i); + this.bulletBarn.m( e, - this.Rt, - this.Et, - this.De, + this.playerBarn, + this.map, + this.camera, this.dr, - this.Ct, - this.Ot, + this.renderer, + this.particleBarn, this.ft ); - this.jt.m( + this.flareBarn.m( e, - this.Rt, - this.Et, - this.De, + this.playerBarn, + this.map, + this.camera, this.dr, - this.Ct, - this.Ot, + this.renderer, + this.particleBarn, this.ft ); - this.Ht.m( + this.projectileBarn.m( e, - this.Ot, + this.particleBarn, this.ft, this.dr, - this.Et, - this.Ct, - this.De + this.map, + this.renderer, + this.camera ); - this.Ut.m( + this.explosionBarn.m( e, - this.Et, - this.Rt, - this.De, - this.Ot, + this.map, + this.playerBarn, + this.camera, + this.particleBarn, this.ft, i ); - this.Xt.m( + this.airdropBarn.m( e, this.dr, - this.De, - this.Et, - this.Ot, - this.Ct, + this.camera, + this.map, + this.particleBarn, + this.renderer, this.ft ); - this.Wt.m(e, this.De, this.dr, this.Et, this.Ct); - this.Kt.m(e, this.De, this.dr, this.Et, this.Ct); - this.or.m(e, this.hr, this.Rt, this.Ot, this.ft); - this.Ot.m(e, this.De, i); - this.Zt.m(e, this.Rt, this.dr, this.Et, this.De, this.Ct); - this.Dt.m(e, this.De, this.Ct, i); - this.zt.m( + this.planeBarn.m(e, this.camera, this.dr, this.map, this.renderer); + this.smokeBarn.m(e, this.camera, this.dr, this.map, this.renderer); + this.shotBarn.m(e, this.hr, this.playerBarn, this.particleBarn, this.ft); + this.particleBarn.m(e, this.camera, i); + this.deadBodyBarn.m(e, this.playerBarn, this.dr, this.map, this.camera, this.renderer); + this.decalBarn.m(e, this.camera, this.renderer, i); + this.uiManager.m( e, this.dr, - this.Et, - this.Qt, - this.Yt, - this.Rt, - this.De, + this.map, + this.gas, + this.lootBarn, + this.playerBarn, + this.camera, this.teamMode, - this.Et.factionMode + this.map.factionMode ); - this.er.m( + this.ui2Manager.m( e, this.dr, this.spectating, - this.Rt, - this.Yt, - this.Et, + this.playerBarn, + this.lootBarn, + this.map, this.xt ); - this.ar.m( + this.emoteBarn.m( e, this.pr, this.dr, this.teamMode, - this.Zt, - this.Et, - this.Ct, + this.deadBodyBarn, + this.map, + this.renderer, this.bt, this.xt, this.spectating ); - this.Mt.update(e, this.dr, this.Et, this.De, this.Ct); - this.Ct.m(e, this.De, this.Et, i); - if (!this.Tt && this.Et._r && this.Et.U) { + this.touch.update(e, this.dr, this.map, this.camera, this.renderer); + this.renderer.m(e, this.camera, this.map, i); + if (!this.Tt && this.map._r && this.map.U) { this.Tt = true; const me = new net.LoadoutMsg(); me.emotes = []; for ( let pe = 0; - pe < this.ar.emoteLoadout.length; + pe < this.emoteBarn.emoteLoadout.length; pe++ ) { - me.emotes.push(this.ar.emoteLoadout[pe]); + me.emotes.push(this.emoteBarn.emoteLoadout[pe]); } - me.custom = this.ar.hasCustomEmotes(); + me.custom = this.emoteBarn.hasCustomEmotes(); this.$(net.Msg.Loadout, me, 128); } - for (let he = 0; he < this.ar.newPings.length; he++) { - const de = this.ar.newPings[he]; + for (let he = 0; he < this.emoteBarn.newPings.length; he++) { + const de = this.emoteBarn.newPings[he]; const ue = new net.EmoteMsg(); ue.type = de.type; ue.pos = de.pos; ue.isPing = true; this.$(net.Msg.Emote, ue, 128); } - this.ar.newPings = []; - for (let ge = 0; ge < this.ar.newEmotes.length; ge++) { - const ye = this.ar.newEmotes[ge]; + this.emoteBarn.newPings = []; + for (let ge = 0; ge < this.emoteBarn.newEmotes.length; ge++) { + const ye = this.emoteBarn.newEmotes[ge]; const we = new net.EmoteMsg(); we.type = ye.type; we.pos = ye.pos; we.isPing = false; this.$(net.Msg.Emote, we, 128); } - this.ar.newEmotes = []; + this.emoteBarn.newEmotes = []; this.br(e, i); if (++this.It % 30 == 0) { const fe = mapHelpers.ct; @@ -806,25 +792,25 @@ export class Game { } br(e, t) { - const r = this.Et.mapLoaded - ? this.Et.getMapDef().biome.colors.grass + const r = this.map.mapLoaded + ? this.map.getMapDef().biome.colors.grass : 8433481; this.pixi.renderer.backgroundColor = r; - this.Rt.render(this.De, t); - this.qt.render(this.De, t); - this.jt.render(this.De); - this.Dt.render(this.De, t, this.dr.layer); - this.Et.render(this.De); - this.Qt.render(this.De); - this.zt.render( + this.playerBarn.render(this.camera, t); + this.bulletBarn.render(this.camera, t); + this.flareBarn.render(this.camera); + this.decalBarn.render(this.camera, t, this.dr.layer); + this.map.render(this.camera); + this.gas.render(this.camera); + this.uiManager.render( this.dr.pos, - this.Qt, - this.De, - this.Et, - this.Wt, + this.gas, + this.camera, + this.map, + this.planeBarn, t ); - this.ar.render(this.De); + this.emoteBarn.render(this.camera); debugLines.flush(); } @@ -833,20 +819,20 @@ export class Game { let t = 0; let r = 0; let a = 1; - if (this.Et.isInOcean(e)) { + if (this.map.isInOcean(e)) { t = 1; r = 0; a = 0; } else { - const i = this.Et.distanceToShore(e); + const i = this.map.distanceToShore(e); t = math.delerp(i, 50, 0); r = 0; for ( let o = 0; - o < this.Et.terrain.rivers.length; + o < this.map.terrain.rivers.length; o++ ) { - const s = this.Et.terrain.rivers[o]; + const s = this.map.terrain.rivers[o]; const n = s.spline.getClosestTtoPoint(e); const l = s.spline.getPos(n); const c = v2.length(v2.sub(l, e)); @@ -865,125 +851,125 @@ export class Game { this._t.getTrack("waves").weight = t; } - xr() { - this.De.screenWidth = device.screenWidth; - this.De.screenHeight = device.screenHeight; - this.Et.resize(this.pixi.renderer, this.canvasMode); - this.Qt.resize(); - this.zt.resize(this.Et, this.De); - this.Mt.resize(); - this.Ct.resize(this.Et, this.De); + resize() { + this.camera.screenWidth = device.screenWidth; + this.camera.screenHeight = device.screenHeight; + this.map.resize(this.pixi.renderer, this.canvasMode); + this.gas.resize(); + this.uiManager.resize(this.map, this.camera); + this.touch.resize(); + this.renderer.resize(this.map, this.camera); } - Sr(e) { + processGameUpdate(e) { const t = { audioManager: this.ft, - renderer: this.Ct, - particleBarn: this.Ot, - map: this.Et, - smokeBarn: this.Kt, - decalBarn: this.Dt + renderer: this.renderer, + particleBarn: this.particleBarn, + map: this.map, + smokeBarn: this.smokeBarn, + decalBarn: this.decalBarn }; if (e.activePlayerIdDirty) { this.hr = e.activePlayerId; } for (let r = 0; r < e.playerInfos.length; r++) { - this.Rt.vr(e.playerInfos[r]); + this.playerBarn.vr(e.playerInfos[r]); } for (let a = 0; a < e.deletedPlayerIds.length; a++) { const i = e.deletedPlayerIds[a]; - this.Rt.kr(i); + this.playerBarn.kr(i); } if ( e.playerInfos.length > 0 || e.deletedPlayerIds.length > 0 ) { - this.Rt.zr(); + this.playerBarn.zr(); } if (e.playerStatusDirty) { - const o = this.Rt.qe(this.hr).teamId; - this.Rt.Ir(o, e.playerStatus, this.Et.factionMode); + const o = this.playerBarn.qe(this.hr).teamId; + this.playerBarn.Ir(o, e.playerStatus, this.map.factionMode); } if (e.groupStatusDirty) { - const s = this.Rt.qe(this.hr).groupId; - this.Rt.Tr(s, e.groupStatus); + const s = this.playerBarn.qe(this.hr).groupId; + this.playerBarn.Tr(s, e.groupStatus); } for (let n = 0; n < e.delObjIds.length; n++) { - this.mr.deleteObj(e.delObjIds[n]); + this.objectCreator.deleteObj(e.delObjIds[n]); } for (let l = 0; l < e.fullObjects.length; l++) { const c = e.fullObjects[l]; - this.mr.updateObjFull(c.__type, c.__id, c, t); + this.objectCreator.updateObjFull(c.__type, c.__id, c, t); } for (let m = 0; m < e.partObjects.length; m++) { const p = e.partObjects[m]; - this.mr.updateObjPart(p.__id, p, t); + this.objectCreator.updateObjPart(p.__id, p, t); } this.spectating = this.hr != this.pr; - this.dr = this.Rt.u(this.hr); - this.dr.Mr(e.activePlayerData, this.Rt); + this.dr = this.playerBarn.u(this.hr); + this.dr.Mr(e.activePlayerData, this.playerBarn); if (e.activePlayerData.weapsDirty) { - this.zt.weapsDirty = true; + this.uiManager.weapsDirty = true; } if (this.spectating) { - this.zt.setSpectateTarget( + this.uiManager.setSpectateTarget( this.hr, this.pr, this.teamMode, - this.Rt + this.playerBarn ); - this.Mt.hideAll(); + this.touch.hideAll(); } - this.dr.layer = this.dr.Le.pe; - this.Ct.setActiveLayer(this.dr.layer); + this.dr.layer = this.dr.netData.pe; + this.renderer.setActiveLayer(this.dr.layer); this.ft.activeLayer = this.dr.layer; - const h = this.dr.isUnderground(this.Et); - this.Ct.setUnderground(h); + const h = this.dr.isUnderground(this.map); + this.renderer.setUnderground(h); this.ft.underground = h; if (e.gasDirty) { - this.Qt.setFullState( + this.gas.setFullState( e.gasT, e.gasData, - this.Et, - this.zt + this.map, + this.uiManager ); } if (e.gasTDirty) { - this.Qt.setProgress(e.gasT); + this.gas.setProgress(e.gasT); } for (let d = 0; d < e.bullets.length; d++) { const g = e.bullets[d]; - Bullet.createBullet(g, this.qt, this.jt, this.Rt, this.Ct); + Bullet.createBullet(g, this.bulletBarn, this.flareBarn, this.playerBarn, this.renderer); if (g.shotFx) { - this.or.addShot(g); + this.shotBarn.addShot(g); } } for (let y = 0; y < e.explosions.length; y++) { const f = e.explosions[y]; - this.Ut.addExplosion(f.type, f.pos, f.layer); + this.explosionBarn.addExplosion(f.type, f.pos, f.layer); } for (let _ = 0; _ < e.emotes.length; _++) { const b = e.emotes[_]; if (b.isPing) { - this.ar.addPing(b, this.Et.factionMode); + this.emoteBarn.addPing(b, this.map.factionMode); } else { - this.ar.addEmote(b); + this.emoteBarn.addEmote(b); } } - this.Wt.Pr(e.planes, this.Et); + this.planeBarn.Pr(e.planes, this.map); for (let x = 0; x < e.airstrikeZones.length; x++) { - this.Wt.Cr(e.airstrikeZones[x]); + this.planeBarn.Cr(e.airstrikeZones[x]); } - this.zt.je(e.mapIndicators); + this.uiManager.je(e.mapIndicators); if (e.killLeaderDirty) { const S = helpers.htmlEscape( - this.Rt.getPlayerName(e.killLeaderId, this.hr, true) + this.playerBarn.getPlayerName(e.killLeaderId, this.hr, true) ); - this.zt.updateKillLeader( + this.uiManager.updateKillLeader( e.killLeaderId, S, e.killLeaderKills, - this.Et.getMapDef().gameMode + this.map.getMapDef().gameMode ); } this.updateRecvCount++; @@ -992,7 +978,7 @@ export class Game { } } - kt(e, t) { + onMsg(e, t) { switch (e) { case net.Msg.Joined: { const r = new net.JoinedMsg(); @@ -1001,9 +987,9 @@ export class Game { this.teamMode = r.teamMode; this.pr = r.playerId; this.ur = true; - this.ar.updateEmoteWheel(r.emotes); + this.emoteBarn.updateEmoteWheel(r.emotes); if (!r.started) { - this.zt.setWaitingForPlayers(true); + this.uiManager.setWaitingForPlayers(true); } if (this.victoryMusic) { this.victoryMusic.stop(); @@ -1022,67 +1008,67 @@ export class Game { case net.Msg.Map: { const a = new net.MapMsg(); a.deserialize(t); - this.Et.loadMap( + this.map.loadMap( a, - this.De, + this.camera, this.canvasMode, - this.Ot + this.particleBarn ); - this.resourceManager.loadMapAssets(this.Et.mapName); - this.Et.renderMap( + this.resourceManager.loadMapAssets(this.map.mapName); + this.map.renderMap( this.pixi.renderer, this.canvasMode ); - this.Rt.onMapLoad(this.Et); - this.qt.onMapLoad(this.Et); - this.Ot.onMapLoad(this.Et); - this.zt.onMapLoad(this.Et, this.De); - if (this.Et.perkMode) { + this.playerBarn.onMapLoad(this.map); + this.bulletBarn.onMapLoad(this.map); + this.particleBarn.onMapLoad(this.map); + this.uiManager.onMapLoad(this.map, this.camera); + if (this.map.perkMode) { const i = this.config.get("perkModeRole"); - this.zt.setRoleMenuOptions( + this.uiManager.setRoleMenuOptions( i, - this.Et.getMapDef().gameMode.perkModeRoles + this.map.getMapDef().gameMode.perkModeRoles ); - this.zt.setRoleMenuActive(true); + this.uiManager.setRoleMenuActive(true); } else { - this.zt.setRoleMenuActive(false); + this.uiManager.setRoleMenuActive(false); } break; } case net.Msg.Update: { const o = new net.UpdateMsg(); - o.deserialize(t, this.mr); + o.deserialize(t, this.objectCreator); /* if (o.partObjects.length) { - console.log(o) - } */ + console.log(o) + } */ this.playing = true; - this.Sr(o); + this.processGameUpdate(o); break; } - case net.Msg.Kill:{ + case net.Msg.Kill: { const n = new net.KillMsg(); n.deserialize(t); const l = n.itemSourceType || n.mapSourceType; - const c = this.Rt.qe(this.hr).teamId; + const c = this.playerBarn.qe(this.hr).teamId; const m = (n.downed && !n.killed) || n.damageType == GameConfig.DamageType.Gas || n.damageType == GameConfig.DamageType.Bleeding || n.damageType == GameConfig.DamageType.Airdrop; - const h = this.Rt.qe(n.targetId); - const d = this.Rt.qe(n.killCreditId); - const g = m ? d : this.Rt.qe(n.killerId); - let y = this.Rt.getPlayerName( + const h = this.playerBarn.qe(n.targetId); + const d = this.playerBarn.qe(n.killCreditId); + const g = m ? d : this.playerBarn.qe(n.killerId); + let y = this.playerBarn.getPlayerName( h.playerId, this.hr, true ); - let w = this.Rt.getPlayerName( + let w = this.playerBarn.getPlayerName( d.playerId, this.hr, true ); - let f = this.Rt.getPlayerName( + let f = this.playerBarn.getPlayerName( g.playerId, this.hr, true @@ -1095,7 +1081,7 @@ export class Game { const b = n.killerId == n.targetId || n.killCreditId == n.targetId; - const x = this.er.getKillText( + const x = this.ui2Manager.getKillText( w, y, _, @@ -1108,54 +1094,54 @@ export class Game { ); const S = n.killed && !b - ? this.er.getKillCountText( + ? this.ui2Manager.getKillCountText( n.killerKills ) : ""; - this.er.displayKillMessage(x, S); + this.ui2Manager.displayKillMessage(x, S); } else if ( n.targetId == this.hr && n.downed && !n.killed ) { - const v = this.er.getDownedText( + const v = this.ui2Manager.getDownedText( w, y, l, n.damageType, this.spectating ); - this.er.displayKillMessage(v, ""); + this.ui2Manager.displayKillMessage(v, ""); } if (n.killCreditId == this.pr && n.killed) { - this.zt.setLocalKills(n.killerKills); + this.uiManager.setLocalKills(n.killerKills); } - const k = this.er.getKillFeedText( + const k = this.ui2Manager.getKillFeedText( y, g.teamId ? f : "", l, n.damageType, n.downed && !n.killed ); - const z = this.er.getKillFeedColor( + const z = this.ui2Manager.getKillFeedColor( c, h.teamId, d.teamId, - this.Et.factionMode + this.map.factionMode ); - this.er.addKillFeedMessage(k, z); + this.ui2Manager.addKillFeedMessage(k, z); if (n.killed) { - this.Rt.addDeathEffect( + this.playerBarn.addDeathEffect( n.targetId, n.killerId, l, this.ft, - this.Ot + this.particleBarn ); } if (n.type == GameConfig.DamageType.Player) { - this.qt.createBulletHit( - this.Rt, + this.bulletBarn.createBulletHit( + this.playerBarn, n.targetId, this.ft ); @@ -1169,15 +1155,15 @@ export class Game { if (!T) { break; } - const M = this.Rt.qe(I.playerId); + const M = this.playerBarn.qe(I.playerId); const P = helpers.htmlEscape( - this.Rt.getPlayerName(I.playerId, this.hr, true) + this.playerBarn.getPlayerName(I.playerId, this.hr, true) ); if (I.assigned) { if (T.sound?.assign) { if ( I.role == "kill_leader" && - this.Et.getMapDef().gameMode + this.map.getMapDef().gameMode .spookyKillSounds ) { this.ft.playGroup( @@ -1188,7 +1174,7 @@ export class Game { ); } else if ( I.role == "kill_leader" || - !this.Et.perkMode || + !this.map.perkMode || this.pr == I.playerId ) { this.ft.playSound(T.sound.assign, { @@ -1196,36 +1182,36 @@ export class Game { }); } } - if (this.Et.perkMode && this.pr == I.playerId) { - this.zt.setRoleMenuActive(false); + if (this.map.perkMode && this.pr == I.playerId) { + this.uiManager.setRoleMenuActive(false); } if (T.killFeed?.assign) { const C = - this.er.getRoleAssignedKillFeedText( + this.ui2Manager.getRoleAssignedKillFeedText( I.role, M.teamId, P ); - const A = this.er.getRoleKillFeedColor( + const A = this.ui2Manager.getRoleKillFeedColor( I.role, M.teamId, - this.Rt + this.playerBarn ); - this.er.addKillFeedMessage(C, A); + this.ui2Manager.addKillFeedMessage(C, A); } if (T.announce && this.pr == I.playerId) { - const O = this.er.getRoleAnnouncementText( + const O = this.ui2Manager.getRoleAnnouncementText( I.role, M.teamId ); - this.zt.displayAnnouncement( + this.uiManager.displayAnnouncement( O.toUpperCase() ); } } else if (I.killed) { if (T.killFeed?.dead) { let D = helpers.htmlEscape( - this.Rt.getPlayerName( + this.playerBarn.getPlayerName( I.killerId, this.hr, true @@ -1234,21 +1220,21 @@ export class Game { if (I.playerId == I.killerId) { D = ""; } - const E = this.er.getRoleKilledKillFeedText( + const E = this.ui2Manager.getRoleKilledKillFeedText( I.role, M.teamId, D ); - const B = this.er.getRoleKillFeedColor( + const B = this.ui2Manager.getRoleKillFeedColor( I.role, M.teamId, - this.Rt + this.playerBarn ); - this.er.addKillFeedMessage(E, B); + this.ui2Manager.addKillFeedMessage(E, B); } if (T.sound?.dead) { if ( - this.Et.getMapDef().gameMode + this.map.getMapDef().gameMode .spookyKillSounds ) { this.ft.playGroup("kill_leader_dead", { @@ -1266,8 +1252,8 @@ export class Game { case net.Msg.PlayerStats: { const R = new net.PlayerStatsMsg(); R.deserialize(t); - this.zt.setLocalStats(R.playerStats); - this.zt.showTeamAd(R.playerStats, this.er); + this.uiManager.setLocalStats(R.playerStats); + this.uiManager.showTeamAd(R.playerStats, this.ui2Manager); break; } case net.Msg.Stats: { @@ -1280,15 +1266,15 @@ export class Game { const q = new net.GameOverMsg(); q.deserialize(t); this.gameOver = q.gameOver; - const F = this.Rt.qe(this.pr).teamId; + const F = this.playerBarn.qe(this.pr).teamId; for (let j = 0; j < q.playerStats.length; j++) { const V = q.playerStats[j]; if (V.playerId == this.pr) { - this.zt.setLocalStats(V); + this.uiManager.setLocalStats(V); break; } } - this.zt.showStats( + this.uiManager.showStats( q.playerStats, q.teamId, q.teamRank, @@ -1297,10 +1283,10 @@ export class Game { F, this.teamMode, this.spectating, - this.Rt, + this.playerBarn, this.ft, - this.Et, - this.er + this.map, + this.ui2Manager ); if (F == q.winningTeamId) { this.victoryMusic = this.ft.playSound( @@ -1312,7 +1298,7 @@ export class Game { } ); } - this.Mt.hideAll(); + this.touch.hideAll(); break; } case net.Msg.Pickup: { @@ -1322,10 +1308,10 @@ export class Game { this.dr.playItemPickupSound(U.item, this.ft); const W = GameObjectDefs[U.item]; if (W && W.type == "xp") { - this.er.addRareLootMessage(U.item, true); + this.ui2Manager.addRareLootMessage(U.item, true); } } else { - this.er.displayPickupMessage(U.type); + this.ui2Manager.displayPickupMessage(U.type); } break; } @@ -1339,14 +1325,14 @@ export class Game { const G = new net.AliveCountsMsg(); G.deserialize(t); if (G.teamAliveCounts.length == 1) { - this.zt.updatePlayersAlive( + this.uiManager.updatePlayersAlive( G.teamAliveCounts[0] ); } else if (G.teamAliveCounts.length >= 2) { - this.zt.updatePlayersAliveRed( + this.uiManager.updatePlayersAliveRed( G.teamAliveCounts[0] ); - this.zt.updatePlayersAliveBlue( + this.uiManager.updatePlayersAliveBlue( G.teamAliveCounts[1] ); } diff --git a/client/src/gas.js b/client/src/gas.js index 7dba6b1d..dd32ff24 100644 --- a/client/src/gas.js +++ b/client/src/gas.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { GameConfig } from "../../shared/gameConfig"; import { math } from "../../shared/utils/math"; import { v2 } from "../../shared/utils/v2"; diff --git a/client/src/main.js b/client/src/main.js index cd2a4f71..99ca64da 100644 --- a/client/src/main.js +++ b/client/src/main.js @@ -286,7 +286,7 @@ class Application { if (window.history) { window.history.replaceState("", "", "/"); } - e.game?.n(); + e.game?.free(); e.teamMenu.leave(); }); const r = $("#news-current").data("date"); @@ -357,7 +357,7 @@ class Application { ); const onJoin = function() { e.loadoutDisplay.n(); - e.game.o(); + e.game.init(); e.onResize(); e.findGameAttempts = 0; e.ambience.onGameStart(); @@ -368,7 +368,7 @@ class Application { e.game.updatePassDelay ); } - e.game.n(); + e.game.free(); e.errorMessage = e.localization.translate(t || ""); e.teamMenu.onGameComplete(); e.ambience.onGameComplete(e.audioManager); @@ -421,7 +421,7 @@ class Application { this.loadoutMenu.onResize(); this.pixi?.renderer.resize(Device.screenWidth, Device.screenHeight); if (this.game?.initialized) { - this.game.xr(); + this.game.resize(); } if (this.loadoutDisplay?.initialized) { this.loadoutDisplay.xr(); @@ -779,7 +779,7 @@ class Application { const o = function() { e(r, a); }; - t.game.vt( + t.game.tryJoinGame( i, a.data, t.account.loadoutPriv, @@ -841,7 +841,7 @@ class Application { this.setAppActive(false); this.setPlayLockout(true); } - this.game.m(e); + this.game.update(e); } if ( this.active && @@ -889,7 +889,7 @@ window.addEventListener("hashchange", () => { App.tryJoinTeam(false); }); window.addEventListener("beforeunload", (e) => { - if (App.game?.gr() && !Device.webview) { + if (App.game?.warnPageReload() && !Device.webview) { const t = "Do you want to reload the game?"; e.returnValue = t; return t; diff --git a/client/src/map.js b/client/src/map.js index b4260bb0..c31a9526 100644 --- a/client/src/map.js +++ b/client/src/map.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { coldet } from "../../shared/utils/coldet"; import { collider } from "../../shared/utils/collider"; import { mapHelpers } from "../../shared/utils/mapHelpers"; @@ -39,7 +38,7 @@ function o(e, t, r) { const m = util.seededRand(r); i(e, terrainGen.generateJaggedAabbPoints(t, l, c, s, m)); } -function s(e) { +function Map(e) { this.decalBarn = e; this.I = false; this.Br = false; @@ -76,8 +75,8 @@ function s(e) { this.U = false; } -s.prototype = { - n: function() { +Map.prototype = { + free: function() { for (let e = this.nr.p(), t = 0; t < e.length; t++) { e[t].n(); } @@ -647,5 +646,5 @@ s.prototype = { }; export default { - Bt: s + Map }; diff --git a/client/src/objects/Smoke.js b/client/src/objects/Smoke.js index ebfd58ce..3622167a 100644 --- a/client/src/objects/Smoke.js +++ b/client/src/objects/Smoke.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../../shared/utils/collider"; import { math } from "../../../shared/utils/math"; import { util } from "../../../shared/utils/util"; diff --git a/client/src/objects/aidrop.js b/client/src/objects/aidrop.js index 33665a44..1777d59a 100644 --- a/client/src/objects/aidrop.js +++ b/client/src/objects/aidrop.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../../shared/utils/collider"; import { GameConfig } from "../../../shared/gameConfig"; import { math } from "../../../shared/utils/math"; @@ -12,7 +11,7 @@ function AirDrop() { this.sprite.anchor.set(0.5, 0.5); this.sprite.visible = false; } -export function AirDropPool() { +function AirdropBarn() { this.re = new ObjectPool.Pool(AirDrop); } @@ -45,8 +44,8 @@ AirDrop.prototype = { this.landed = e.landed; } }; -AirDropPool.prototype = { - n: function() { +AirdropBarn.prototype = { + free: function() { for (let e = this.re.p(), t = 0; t < e.length; t++) { e[t].n(); } @@ -158,3 +157,6 @@ AirDropPool.prototype = { } } }; +export default { + AirdropBarn +}; diff --git a/client/src/objects/building.js b/client/src/objects/building.js index ddaddcc3..f3105c19 100644 --- a/client/src/objects/building.js +++ b/client/src/objects/building.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../../shared/utils/collider"; import { math } from "../../../shared/utils/math"; import { mapHelpers } from "../../../shared/utils/mapHelpers"; diff --git a/client/src/objects/bullet.js b/client/src/objects/bullet.js index c1f602b3..a60242ee 100644 --- a/client/src/objects/bullet.js +++ b/client/src/objects/bullet.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { coldet } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { GameConfig } from "../../../shared/gameConfig"; @@ -158,7 +157,7 @@ BulletBarn.prototype = { const v = v2.copy(b.pos); b.pos = v2.add(b.pos, v2.mul(b.dir, S)); if ( - !s.Le.he && + !s.netData.he && util.sameAudioLayer(s.layer, b.layer) && v2.length(v2.sub(i.pos, b.pos)) < 7.5 && !b.whizHeard && @@ -208,9 +207,9 @@ BulletBarn.prototype = { const A = f[C]; if ( A.active && - !A.Le.he && - (util.sameLayer(A.Le.pe, b.layer) || - A.Le.pe & 2) && + !A.netData.he && + (util.sameLayer(A.netData.pe, b.layer) || + A.netData.pe & 2) && (A.__id != b.playerId || b.damageSelf) ) { let O = null; @@ -306,7 +305,7 @@ BulletBarn.prototype = { }); let U = false; const W = t.u(b.playerId); - if (W && (W.Le.he || W.Le.ue)) { + if (W && (W.netData.he || W.netData.ue)) { U = true; } let G = false; @@ -465,7 +464,7 @@ BulletBarn.prototype = { } }; export default { - Ft: BulletBarn, + BulletBarn, createBullet, playHitFx }; diff --git a/client/src/objects/deadBody.js b/client/src/objects/deadBody.js index 43817321..cb67d5de 100644 --- a/client/src/objects/deadBody.js +++ b/client/src/objects/deadBody.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../../shared/utils/collider"; import { util } from "../../../shared/utils/util"; import { v2 } from "../../../shared/utils/v2"; diff --git a/client/src/objects/decal.js b/client/src/objects/decal.js index 8c18a96b..c6f22a97 100644 --- a/client/src/objects/decal.js +++ b/client/src/objects/decal.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../../shared/utils/collider"; import { math } from "../../../shared/utils/math"; import { v2 } from "../../../shared/utils/v2"; diff --git a/client/src/objects/flare.js b/client/src/objects/flare.js index ba41c2cf..46105983 100644 --- a/client/src/objects/flare.js +++ b/client/src/objects/flare.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { GameConfig } from "../../../shared/gameConfig"; import { collider } from "../../../shared/utils/collider"; import { math } from "../../../shared/utils/math"; @@ -173,5 +172,5 @@ FlareBarn.prototype = { } }; export default { - Nt: FlareBarn + FlareBarn }; diff --git a/client/src/objects/loot.js b/client/src/objects/loot.js index f4e354ce..3fa0b7bd 100644 --- a/client/src/objects/loot.js +++ b/client/src/objects/loot.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { GameConfig } from "../../../shared/gameConfig"; import { math } from "../../../shared/utils/math"; import { util } from "../../../shared/utils/util"; @@ -121,7 +120,7 @@ i.prototype = { if (g.active) { if ( util.sameLayer(g.layer, t.layer) && - !t.Le.he && + !t.netData.he && (g.ownerId == 0 || g.ownerId == t.__id) ) { const y = g.pos; @@ -165,5 +164,5 @@ i.prototype = { } }; export default { - Jt: i + LootBarn: i }; diff --git a/client/src/objects/mapIndicator.js b/client/src/objects/mapIndicator.js index 2bd763ca..50cea9e4 100644 --- a/client/src/objects/mapIndicator.js +++ b/client/src/objects/mapIndicator.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { v2 } from "../../../shared/utils/v2"; import device from "../device"; import { math } from "../../../shared/utils/math"; diff --git a/client/src/objects/objectPool.js b/client/src/objects/objectPool.js index ab8118b6..2dfb5e09 100644 --- a/client/src/objects/objectPool.js +++ b/client/src/objects/objectPool.js @@ -1,22 +1,14 @@ -import firebaseManager from "../firebaseManager"; - -function Pool(e) { - // assert(e !== undefined); - this.creator = { - type: e - }; - this.mt = []; - this.activeCount = 0; -} - -function Creator(e) { - this.idToObj = {}; - this.types = {}; - this.seenCount = 0; -} +class Pool { + constructor(e) { + // assert(e !== undefined); + this.creator = { + type: e + }; + this.mt = []; + this.activeCount = 0; + } -Pool.prototype = { - alloc: function() { + alloc() { let e = null; for (let t = 0; t < this.mt.length; t++) { if (!this.mt[t].active) { @@ -33,8 +25,9 @@ Pool.prototype = { e.o(); this.activeCount++; return e; - }, - free: function(e) { + } + + free(e) { e.n(); e.active = false; this.activeCount--; @@ -50,35 +43,45 @@ Pool.prototype = { } this.mt = t; } - }, - p: function() { + } + + p() { return this.mt; } -}; +} + +class Creator { + constructor() { + this.idToObj = {}; + this.types = {}; + this.seenCount = 0; + } -Creator.prototype = { - registerType: function(e, t) { + registerType(e, t) { this.types[e] = t; - }, - getObjById: function(e) { + } + + getObjById(e) { return this.idToObj[e]; - }, - getTypeById: function(e, t) { + } + + getTypeById(e, t) { const r = this.getObjById(e); if (!r) { - const a = { + /* const a = { instId: firebaseManager.instanceId, id: e, ids: Object.keys(this.idToObj), stream: t._view._view }; firebaseManager.logError(`getTypeById${JSON.stringify(a)}`); - firebaseManager.storeGeneric("objectPoolErr", "getTypeById"); + firebaseManager.storeGeneric("objectPoolErr", "getTypeById"); */ return 0; } return r.__type; - }, - updateObjFull: function(e, t, r, a) { + } + + updateObjFull(e, t, r, a) { let i = this.getObjById(t); let o = false; if (i === undefined) { @@ -91,27 +94,30 @@ Creator.prototype = { } i.c(r, true, o, a); return i; - }, - updateObjPart: function(e, t, r) { + } + + updateObjPart(e, t, r) { const a = this.getObjById(e); if (a) { a.c(t, false, false, r); } else { console.log("updateObjPart, missing object", e); - firebaseManager.storeGeneric("objectPoolErr", "updateObjPart"); + // firebaseManager.storeGeneric("objectPoolErr", "updateObjPart"); } - }, - deleteObj: function(e) { + } + + deleteObj(e) { const t = this.getObjById(e); if (t === undefined) { console.log("deleteObj, missing object", e); - firebaseManager.storeGeneric("objectPoolErr", "deleteObj"); + // firebaseManager.storeGeneric("objectPoolErr", "deleteObj"); } else { this.types[t.__type].free(t); delete this.idToObj[e]; } } -}; +} + export default { Pool, Creator diff --git a/client/src/objects/obstacle.js b/client/src/objects/obstacle.js index 8dd3fce5..87401b8c 100644 --- a/client/src/objects/obstacle.js +++ b/client/src/objects/obstacle.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../../shared/utils/collider"; import { math } from "../../../shared/utils/math"; import { util } from "../../../shared/utils/util"; diff --git a/client/src/objects/particles.js b/client/src/objects/particles.js index 211f1ba7..856cc5b8 100644 --- a/client/src/objects/particles.js +++ b/client/src/objects/particles.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { math } from "../../../shared/utils/math"; import { util } from "../../../shared/utils/util"; import { v2 } from "../../../shared/utils/v2"; @@ -3149,7 +3148,7 @@ ParticleBarn.prototype = { onMapLoad: function(e) { this.valueAdjust = e.getMapDef().biome.valueAdjust; }, - n: function() { + free: function() { for (let e = 0; e < this.particles.length; e++) { const t = this.particles[e].sprite; t.parent?.removeChild(t); diff --git a/client/src/objects/plane.js b/client/src/objects/plane.js index e3f56099..17d1d39e 100644 --- a/client/src/objects/plane.js +++ b/client/src/objects/plane.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../../shared/utils/collider"; import { GameConfig } from "../../../shared/gameConfig"; import { math } from "../../../shared/utils/math"; @@ -134,7 +133,7 @@ AirstrikeZone.prototype = { } }; PlaneBarn.prototype = { - n: function() { + free: function() { for (let e = 0; e < this.ia.length; e++) { this.ia[e].n(this.audioManager); } @@ -322,5 +321,5 @@ PlaneBarn.prototype = { } }; export default { - Gt: PlaneBarn + PlaneBarn }; diff --git a/client/src/objects/player.js b/client/src/objects/player.js index 37853ac9..4963dae7 100644 --- a/client/src/objects/player.js +++ b/client/src/objects/player.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { GameConfig } from "../../../shared/gameConfig"; import net from "../../../shared/net"; import { util } from "../../../shared/utils/util"; @@ -191,7 +190,7 @@ function Player() { this.I = 0; this.Br = 0; this.action = {}; - this.Le = {}; + this.netData = {}; this.Re = {}; this.rad = GameConfig.player.radius; this.bodyRad = this.rad; @@ -311,7 +310,7 @@ Player.prototype = { throttleTicker: 0 }; this.playAnim(Anim.None, -1); - this.Le = { + this.netData = { ie: v2.create(0, 0), oe: v2.create(1, 0), se: "", @@ -365,45 +364,45 @@ Player.prototype = { } }, c: function(e, t, r, a) { - this.Le.ie = v2.copy(e.ie); - this.Le.oe = v2.copy(e.oe); + this.netData.ie = v2.copy(e.pos); + this.netData.oe = v2.copy(e.dir); if (t) { - this.Le.se = e.se; - this.Le.ne = e.ne; - this.Le.le = e.le; - this.Le.ce = e.ce; - this.Le.me = e.me; - this.Le.pe = e.pe; - this.Le.he = e.he; - this.Le.ue = e.ue; - this.Le.ge = e.ge; - this.Le.ye = e.ye; - this.Le.we = e.we; - this.Le.fe = e.fe; - this.Le._e = e._e; - this.Le.be = e.be; - this.Le.xe = e.xe; - this.Le.Se = e.Se; - this.Le.ve = e.ve; - this.Le.ke = e.ke; - this.Le.ze = e.ze; - this.Le.Ie = e.Ie; - this.Le.Te = e.Te; - if (!!r || !o(this.Le.Me, e.Me)) { + this.netData.se = e.outfit; + this.netData.ne = e.pack; + this.netData.le = e.helmet; + this.netData.ce = e.chest; + this.netData.me = e.activeWeapon; + this.netData.pe = e.layer; + this.netData.he = e.dead; + this.netData.ue = e.downed; + this.netData.ge = e.animType; + this.netData.ye = e.animSeq; + this.netData.we = e.actionType; + this.netData.fe = e.actionSeq; + this.netData._e = e.wearingPan; + this.netData.be = e.healEffect; + this.netData.xe = e.frozen; + this.netData.Se = e.frozenOri; + this.netData.ve = e.hasteType; + this.netData.ke = e.hasteSeq; + this.netData.ze = e.actionItem; + this.netData.Ie = e.scale; + this.netData.Te = e.role; + if (!!r || !o(this.netData.Me, e.perks)) { this.perksDirty = true; } - this.Le.Me = e.Me; + this.netData.Me = e.perks; if (e.ye != this.anim.seq) { - this.playAnim(e.ge, e.ye); + this.playAnim(e.animType, e.animSeq); } - this.action.type = e.we; - this.action.seq = e.fe; - this.action.item = e.ze; + this.action.type = e.actionType; + this.action.seq = e.actionSeq; + this.action.item = e.actionItem; this.visualsDirty = true; } if (r) { this.isNew = true; - this.renderLayer = this.Le.pe; + this.renderLayer = this.netData.pe; this.renderZOrd = 18; this.renderZIdx = this.__id; } @@ -463,34 +462,34 @@ Player.prototype = { return e; }, Nr: function() { - if (this.Le.le) { - return GameObjectDefs[this.Le.le].level; + if (this.netData.le) { + return GameObjectDefs[this.netData.le].level; } else { return 0; } }, Hr: function() { - if (this.Le.ce) { - return GameObjectDefs[this.Le.ce].level; + if (this.netData.ce) { + return GameObjectDefs[this.netData.ce].level; } else { return 0; } }, Vr: function() { - return GameObjectDefs[this.Le.ne].level; + return GameObjectDefs[this.netData.ne].level; }, Ur: function() { - return GameObjectDefs[this.Le.me].type; + return GameObjectDefs[this.netData.me].type; }, Wr: function(e) { return this.Re.tt[e].type !== ""; }, getMeleeCollider: function() { - const e = GameObjectDefs[this.Le.me]; + const e = GameObjectDefs[this.netData.me]; const t = Math.atan2(this.dir.y, this.dir.x); const r = v2.add( e.attack.offset, - v2.mul(v2.create(1, 0), this.Le.Ie - 1) + v2.mul(v2.create(1, 0), this.netData.Ie - 1) ); const a = v2.add(this.pos, v2.rotate(r, t)); const i = e.attack.rad; @@ -498,16 +497,16 @@ Player.prototype = { }, hasActivePan: function() { return ( - this.Le._e || - (this.Le.me == "pan" && this.currentAnim() != Anim.Melee) + this.netData._e || + (this.netData.me == "pan" && this.currentAnim() != Anim.Melee) ); }, getPanSegment: function() { - const e = this.Le._e ? "unequipped" : "equipped"; + const e = this.netData._e ? "unequipped" : "equipped"; return GameObjectDefs.pan.reflectSurface[e]; }, canInteract: function(e) { - return !this.Le.he && (!e.perkMode || this.Le.Te); + return !this.netData.he && (!e.perkMode || this.netData.Te); }, Gr: function(e, t, r) { const a = this; @@ -516,9 +515,9 @@ Player.prototype = { } if (this.perksDirty) { if (e && !t) { - for (let o = 0; o < this.Le.Me.length; o++) { + for (let o = 0; o < this.netData.Me.length; o++) { (function(e) { - const t = a.Le.Me[e]; + const t = a.netData.Me[e]; if ( a.perks.findIndex((e) => { return e.type == t.type; @@ -532,7 +531,7 @@ Player.prototype = { (function(e) { const t = a.perks[e]; if ( - a.Le.Me.findIndex((e) => { + a.netData.Me.findIndex((e) => { return e.type == t.type; }) === -1 ) { @@ -542,9 +541,9 @@ Player.prototype = { } } const n = []; - for (let l = 0; l < this.Le.Me.length; l++) { + for (let l = 0; l < this.netData.Me.length; l++) { (function(e) { - const t = a.Le.Me[e]; + const t = a.netData.Me[e]; const r = a.perks.findIndex((e) => { return e.type == t.type; @@ -558,8 +557,8 @@ Player.prototype = { } this.perks = n; this.perkTypes = []; - for (let c = 0; c < this.Le.Me.length; c++) { - this.perkTypes.push(this.Le.Me[c].type); + for (let c = 0; c < this.netData.Me.length; c++) { + this.perkTypes.push(this.netData.Me[c].type); } this.perksDirty = false; } @@ -568,16 +567,16 @@ Player.prototype = { return this.perkTypes.includes(e); }, m: function(e, t, r, i, o, s, n, l, c, m, p, w, x) { - const k = GameObjectDefs[this.Le.me]; + const k = GameObjectDefs[this.netData.me]; const z = this.__id == m; const I = t.u(m); this.posOld = v2.copy(this.pos); this.dirOld = v2.copy(this.dir); - this.pos = v2.copy(this.Le.ie); - this.dir = v2.copy(this.Le.oe); - this.layer = this.Le.pe; - this.downed = this.Le.ue; - this.rad = this.Le.Ie * GameConfig.player.radius; + this.pos = v2.copy(this.netData.ie); + this.dir = v2.copy(this.netData.oe); + this.layer = this.netData.pe; + this.downed = this.netData.ue; + this.rad = this.netData.Ie * GameConfig.player.radius; if (!math.eqAbs(this.rad, this.bodyRad)) { const T = this.rad - this.bodyRad; let M = Math.abs(T) > 0.0001 ? T * e * 6 : T; @@ -594,8 +593,8 @@ Player.prototype = { this.viewAabb.max = v2.add(n.pos, D); } this.Gr(z, x, c); - const E = this.weapTypeOld != this.Le.me; - this.weapTypeOld = this.Le.me; + const E = this.weapTypeOld != this.netData.me; + this.weapTypeOld = this.netData.me; this.lastThrowablePickupSfxTicker -= e; this.noCeilingRevealTicker -= e; const B = t.qe(m).groupId; @@ -607,7 +606,7 @@ Player.prototype = { let F = null; for (let j = r.Ve.p(), N = 0; N < j.length; N++) { const H = j[N]; - if (H.active && !H.dead && H.layer == this.Le.pe) { + if (H.active && !H.dead && H.layer == this.netData.pe) { if (H.isBush) { const V = this.rad * 0.25; if ( @@ -703,7 +702,7 @@ Player.prototype = { const ie = this.surface.type == "water"; this.updateSubmersion(e, r); this.updateFrozenState(e); - if (!this.Le.he) { + if (!this.netData.he) { this.stepDistance += v2.length( v2.sub(this.posOld, this.pos) ); @@ -736,8 +735,8 @@ Player.prototype = { } this.bleedTicker -= e; if ( - !this.Le.he && - ((this.Le.ue && this.action.type == Action.None) || + !this.netData.he && + ((this.netData.ue && this.action.type == Action.None) || this.hasPerk("trick_drain")) && this.bleedTicker < 0 ) { @@ -774,7 +773,7 @@ Player.prototype = { if (z && (E || this.lastSwapIdx != this.Re.rt)) { const se = this.lastSwapIdx; this.lastSwapIdx = this.Re.rt; - const ne = GameObjectDefs[this.Le.me]; + const ne = GameObjectDefs[this.netData.me]; if (ne.type == "melee" || ne.type == "throwable") { if ( ne.type != "throwable" || @@ -849,7 +848,7 @@ Player.prototype = { this.action.throttleCount--; this.action.throttleTicker = 0.25; } - if (this.Le.ve && this.Le.ke != this.hasteSeq) { + if (this.netData.ve && this.netData.ke != this.hasteSeq) { const hasteEffects = { [HasteType.None]: { particle: "", @@ -868,7 +867,7 @@ Player.prototype = { sound: "ability_stim_01" } }; - const ge = hasteEffects[this.Le.ve]; + const ge = hasteEffects[this.netData.ve]; if (!this.isNew) { i.playSound(ge.sound, { channel: "sfx", @@ -883,8 +882,8 @@ Player.prototype = { pos: this.pos, layer: this.layer }); - this.hasteSeq = this.Le.ke; - } else if (!this.Le.ve && this.hasteEmitter) { + this.hasteSeq = this.netData.ke; + } else if (!this.netData.ve && this.hasteEmitter) { this.hasteEmitter.stop(); this.hasteEmitter = null; } @@ -896,12 +895,12 @@ Player.prototype = { this.hasteEmitter.layer = this.renderLayer; this.hasteEmitter.zOrd = this.renderZOrd + 1; } - if (this.Le.be && !this.passiveHealEmitter) { + if (this.netData.be && !this.passiveHealEmitter) { this.passiveHealEmitter = o.addEmitter("heal_basic", { pos: this.pos, layer: this.layer }); - } else if (!this.Le.be && this.passiveHealEmitter) { + } else if (!this.netData.be && this.passiveHealEmitter) { this.passiveHealEmitter.stop(); this.passiveHealEmitter = null; } @@ -1000,7 +999,7 @@ Player.prototype = { I.layer & 2 || (I.layer & 1) == 1 || (this.layer & 1) == 0; - this.auraContainer.visible = !this.Le.he && Me; + this.auraContainer.visible = !this.netData.he && Me; l.addPIXIObj( this.container, this.renderLayer, @@ -1014,7 +1013,7 @@ Player.prototype = { const a = e.pixels(1); this.container.position.set(r.x, r.y); this.container.scale.set(a, a); - this.container.visible = !this.Le.he; + this.container.visible = !this.netData.he; this.auraContainer.position.set(r.x, r.y); this.auraContainer.scale.set(a, a); }, @@ -1087,7 +1086,7 @@ Player.prototype = { } const x = this.__id + - (this.Le.ue ? 0 : 262144) + + (this.netData.ue ? 0 : 262144) + (e ? 65536 : 0) + (this.rad > 1 ? 131072 : 0); this.renderLayer = f; @@ -1095,7 +1094,7 @@ Player.prototype = { this.renderZIdx = x; }, Xr: function(e, t) { - const r = GameObjectDefs[this.Le.se]; + const r = GameObjectDefs[this.netData.se]; const a = r.skinImg; const i = this.bodyRad / GameConfig.player.radius; this.bodySprite.texture = PIXI.Texture.from(a.baseSprite); @@ -1104,12 +1103,12 @@ Player.prototype = { : a.baseTint; this.bodySprite.scale.set(0.25, 0.25); this.bodySprite.visible = true; - if (this.Le.xe && this.updateFrozenImage) { + if (this.netData.xe && this.updateFrozenImage) { const o = t.getMapDef().biome.frozenSprites || []; if (o.length > 0) { const s = o[Math.floor(Math.random() * o.length)]; const n = - math.oriToRad(this.Le.Se) + + math.oriToRad(this.netData.Se) + Math.PI * 0.5 + (Math.random() - 0.5) * Math.PI * 0.25; this.bodyEffectSprite.texture = @@ -1173,10 +1172,10 @@ Player.prototype = { } else { this.flakSprite.visible = false; } - if (this.Le.ce == "" || r.ghillie) { + if (this.netData.ce == "" || r.ghillie) { this.chestSprite.visible = false; } else { - const k = GameObjectDefs[this.Le.ce]; + const k = GameObjectDefs[this.netData.ce]; const z = k.skinImg; this.chestSprite.texture = PIXI.Texture.from( z.baseSprite @@ -1196,10 +1195,10 @@ Player.prototype = { } else { this.steelskinSprite.visible = false; } - if (this.Le.le == "" || r.ghillie) { + if (this.netData.le == "" || r.ghillie) { this.helmetSprite.visible = false; } else { - const I = GameObjectDefs[this.Le.le]; + const I = GameObjectDefs[this.netData.le]; const T = I.skinImg; const M = (this.downed ? 1 : -1) * 3.33; this.helmetSprite.texture = PIXI.Texture.from( @@ -1247,7 +1246,7 @@ Player.prototype = { } else { this.backpackSprite.visible = false; } - if (this.Le._e) { + if (this.netData._e) { const B = GameObjectDefs.pan.hipImg; this.hipSprite.texture = PIXI.Texture.from(B.sprite); this.hipSprite.position.set(B.pos.x, B.pos.y); @@ -1258,12 +1257,12 @@ Player.prototype = { } else { this.hipSprite.visible = false; } - const R = GameObjectDefs[this.Le.me]; + const R = GameObjectDefs[this.netData.me]; if (R.type == "gun") { - this.gunRSprites.setType(this.Le.me, i); + this.gunRSprites.setType(this.netData.me, i); this.gunRSprites.setVisible(true); if (R.isDual) { - this.gunLSprites.setType(this.Le.me, i); + this.gunLSprites.setType(this.netData.me, i); this.gunLSprites.setVisible(true); } else { this.gunLSprites.setVisible(false); @@ -1320,7 +1319,7 @@ Player.prototype = { this.bodyContainer.addChild(this.handRContainer); } } - if (R.type == "melee" && this.Le.me != "fists") { + if (R.type == "melee" && this.netData.me != "fists") { const V = R.worldImg; this.meleeSprite.texture = PIXI.Texture.from( V.sprite @@ -1393,8 +1392,8 @@ Player.prototype = { if ( (this.action.type != Action.UseItem && this.action.type != Action.Revive) || - this.Le.he || - (this.Le.ue && !this.hasPerk("self_revive")) || + this.netData.he || + (this.netData.ue && !this.hasPerk("self_revive")) || !this.hasPerk("aoe_heal") ) { this.auraPulseTicker = 0; @@ -1417,11 +1416,11 @@ Player.prototype = { } if ( t.perkMode && - this.Le.Te != "" && - this.Le.le != "" && + this.netData.Te != "" && + this.netData.le != "" && !r.ghillie ) { - const ee = GameObjectDefs[this.Le.Te]; + const ee = GameObjectDefs[this.netData.Te]; const te = ee.visorImg; if (te) { const re = (this.downed ? 1 : -1) * 3.33; @@ -1486,7 +1485,7 @@ Player.prototype = { e(this.handRContainer, this.bones[Bones.HandR]); e(this.footLContainer, this.bones[Bones.FootL]); e(this.footRContainer, this.bones[Bones.FootR]); - const t = GameObjectDefs[this.Le.me]; + const t = GameObjectDefs[this.netData.me]; if ( !this.downed && this.currentAnim() != Anim.Revive && @@ -1590,7 +1589,7 @@ Player.prototype = { break; } case Action.Revive: - if (this.Le.ue) { + if (this.netData.ue) { i = "revive_basic"; } } @@ -1643,7 +1642,7 @@ Player.prototype = { } }, selectIdlePose: function() { - const e = GameObjectDefs[this.Le.me]; + const e = GameObjectDefs[this.netData.me]; let t = "fists"; t = this.downed ? "downed" @@ -1691,7 +1690,7 @@ Player.prototype = { case Anim.CrawlBackward: return t("crawl_backward", true); case Anim.Melee: { - const r = GameObjectDefs[this.Le.me]; + const r = GameObjectDefs[this.netData.me]; if (!r.anim?.attackAnims) { return t("fists", true); } @@ -1775,7 +1774,7 @@ Player.prototype = { } }, animPlaySound: function(e, t) { - const r = GameObjectDefs[this.Le.me]; + const r = GameObjectDefs[this.netData.me]; const a = r.sound[t.sound]; if (a) { e.audioManager.playSound(a, { @@ -1791,7 +1790,7 @@ Player.prototype = { this.throwableState = t.state; }, animThrowableParticles: function(e, t) { - if (GameObjectDefs[this.Le.me].useThrowParticles) { + if (GameObjectDefs[this.netData.me].useThrowParticles) { const r = v2.rotate( v2.create(0.75, 0.75), Math.atan2(this.dir.y, this.dir.x) @@ -1823,7 +1822,7 @@ Player.prototype = { } }, animMeleeCollision: function(e, t) { - const r = GameObjectDefs[this.Le.me]; + const r = GameObjectDefs[this.netData.me]; if (r && r.type == "melee") { const a = this.getMeleeCollider(); const i = a.rad + v2.length(v2.sub(this.pos, a.pos)); @@ -1895,7 +1894,7 @@ Player.prototype = { if ( z.active && z.__id != this.__id && - !z.Le.he && + !z.netData.he && util.sameLayer(z.layer, this.layer) ) { const I = v2.normalizeSafe( @@ -2042,13 +2041,13 @@ Player.prototype = { } }, updateFrozenState: function(e) { - if (this.Le.xe) { + if (this.netData.xe) { this.frozenTicker = 0.25; } else { this.frozenTicker -= e; this.updateFrozenImage = true; } - this.bodyEffectSprite.alpha = this.Le.xe + this.bodyEffectSprite.alpha = this.netData.xe ? 1 : math.remap(this.frozenTicker, 0, 0.25, 0, 1); this.bodyEffectSprite.visible = this.frozenTicker > 0; @@ -2095,12 +2094,12 @@ PlayerBarn.prototype = { const y = this.qe(t); const f = this.u(t); this.Jr(t, { - pos: v2.copy(f.Le.ie), + pos: v2.copy(f.netData.ie), health: f.Re.Lr, disconnected: false, - dead: f.Le.he, - downed: f.Le.ue, - role: f.Le.Te, + dead: f.netData.he, + downed: f.netData.ue, + role: f.netData.Te, visible: true }); for ( @@ -2115,15 +2114,15 @@ PlayerBarn.prototype = { const I = this.qe(z); const T = this.u(z); if (T) { - k.posDelta = v2.length(v2.sub(T.Le.ie, k.pos)); - k.posTarget = v2.copy(T.Le.ie); + k.posDelta = v2.length(v2.sub(T.netData.ie, k.pos)); + k.posTarget = v2.copy(T.netData.ie); k.posInterp = math.clamp( k.posInterp + e * 0.2, e / x, 1 ); - k.dead = T.Le.he; - k.downed = T.Le.ue; + k.dead = T.netData.he; + k.downed = T.netData.ue; } else { k.posInterp = e / x; } @@ -2403,5 +2402,5 @@ PlayerBarn.prototype = { } }; export default { - Lt: PlayerBarn + PlayerBarn }; diff --git a/client/src/objects/projectile.js b/client/src/objects/projectile.js index fcdf2640..6a93caaf 100644 --- a/client/src/objects/projectile.js +++ b/client/src/objects/projectile.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { GameConfig } from "../../../shared/gameConfig"; import { collider } from "../../../shared/utils/collider"; import { math } from "../../../shared/utils/math"; @@ -305,5 +304,5 @@ i.prototype = { } }; export default { - Vt: i + ProjectileBarn: i }; diff --git a/client/src/objects/shot.js b/client/src/objects/shot.js index 07d56cca..200af1a6 100644 --- a/client/src/objects/shot.js +++ b/client/src/objects/shot.js @@ -148,16 +148,16 @@ ShotBarn.prototype = { const f = r.u(l.playerId); if ( f && - !f.Le.he && - f.Le.me == l.weaponType && + !f.netData.he && + f.netData.me == l.weaponType && c.caseTiming == "shoot" ) { createCasingParticle( l.weaponType, (Math.PI / 2) * -1, 1, - f.Le.ie, - f.Le.oe, + f.netData.ie, + f.netData.oe, f.renderLayer, f.renderZOrd + 1, i diff --git a/client/src/opponentDisplay.js b/client/src/opponentDisplay.js index 5a8401c9..b73622c6 100644 --- a/client/src/opponentDisplay.js +++ b/client/src/opponentDisplay.js @@ -46,11 +46,11 @@ LoadoutDisplay.prototype = { this.canvasMode = this.pixi.renderer.type == PIXI.RENDERER_TYPE.CANVAS; this.De = new Camera(); - this.Ct = new renderer.At(this, this.canvasMode); + this.Ct = new renderer.Renderer(this, this.canvasMode); this.Ot = new particles.ParticleBarn(this.Ct); this.Dt = new decal.DecalBarn(); - this.Et = new map.Bt(this.Dt); - this.Rt = new Player.Lt(); + this.Et = new map.Map(this.Dt); + this.Rt = new Player.PlayerBarn(); this.Kt = new Smoke.SmokeBarn(); const e = {}; a(e, gameObject.Type.Player, this.Rt.$e); @@ -147,7 +147,7 @@ LoadoutDisplay.prototype = { }, this.Rt ); - this.dr.layer = this.dr.Le.pe; + this.dr.layer = this.dr.netData.pe; this.dr.isLoadoutAvatar = true; this.Ct.setActiveLayer(this.dr.layer); this.ft.activeLayer = this.dr.layer; @@ -207,32 +207,32 @@ LoadoutDisplay.prototype = { this.animIdleTicker = 0; } const r = { - se: this.loadout.outfit, - ne: "backpack02", - le: "helmet01", - ce: "chest03", - me: this.loadout.melee, - pe: 0, - he: false, - ue: false, - ge: e.animType || 0, - ye: e.animSeq || 0, - fe: e.actionSeq || 0, - we: e.actionType || 0, - ze: e.actionItem || "", - _e: false, - be: false, - xe: false, - Se: 0, - ve: 0, - ke: 0, - Ie: 1, - Te: "", - Me: [], + outfit: this.loadout.outfit, + pack: "backpack02", + helmet: "helmet01", + chest: "chest03", + activeWeapon: this.loadout.melee, + layer: 0, + dead: false, + downed: false, + animType: e.animType || 0, + animSeq: e.animSeq || 0, + actionSeq: e.actionSeq || 0, + actionType: e.actionType || 0, + actionItem: e.actionItem || "", + wearingPan: false, + healEffect: false, + frozen: false, + frozenOri: 0, + hasteType: 0, + hasteSeq: 0, + scale: 1, + role: "", + perks: [], $r: false }; - r.ie = v2.create(50, 50); - r.oe = v2.create(0, -1); + r.pos = v2.create(50, 50); + r.dir = v2.create(0, -1); this.mr.updateObjFull(1, 98, r, t); this.Rt.vr({ playerId: 98, diff --git a/client/src/pieTimer.js b/client/src/pieTimer.js index b47b109d..54357a65 100644 --- a/client/src/pieTimer.js +++ b/client/src/pieTimer.js @@ -1,5 +1,4 @@ -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { math } from "../../shared/utils/math"; import device from "./device"; diff --git a/client/src/renderer.js b/client/src/renderer.js index a751e50b..f66de7f1 100644 --- a/client/src/renderer.js +++ b/client/src/renderer.js @@ -75,7 +75,7 @@ class RenderGroup extends PIXI.Container { } Renderer.prototype = { - n: function() { + free: function() { this.layerMask.parent?.removeChild(this.layerMark); this.layerMask.destroy(true); }, @@ -258,5 +258,5 @@ Renderer.prototype = { }; export default { RenderGroup, - At: Renderer + Renderer }; diff --git a/client/src/touch.js b/client/src/touch.js index 06f18e67..8dc47657 100644 --- a/client/src/touch.js +++ b/client/src/touch.js @@ -1,6 +1,5 @@ import $ from "jquery"; -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { collider } from "../../shared/utils/collider"; import { GameConfig } from "../../shared/gameConfig"; import { math } from "../../shared/utils/math"; @@ -661,7 +660,7 @@ class LineSprites { const o = device.touch && e.touchingAim && e.touchAimLine; if (o) { - const s = t.Le.me; + const s = t.netData.me; const g = GameObjectDefs[s]; let y = 30; if (g.type == "gun") { @@ -736,5 +735,5 @@ class LineSprites { } export default { - Pt: Touch + Touch }; diff --git a/client/src/ui.js b/client/src/ui.js index e191bca6..8b3c01c2 100644 --- a/client/src/ui.js +++ b/client/src/ui.js @@ -1,6 +1,5 @@ import $ from "jquery"; -import * as PIXI from "pixi.js" -; +import * as PIXI from "pixi.js"; import { coldet } from "../../shared/utils/coldet"; import { GameConfig } from "../../shared/gameConfig"; import { math } from "../../shared/utils/math"; @@ -370,7 +369,7 @@ function i(e, t, r, a, i, o, c, m, p) { const z = this.getMinimapSize(); this.minimapPos = v2.create( f + z / 2, - e.De.screenHeight - z / 2 - f + e.camera.screenHeight - z / 2 - f ); this.dead = false; this.audioManager = t; @@ -471,7 +470,7 @@ function Color(e, t, r) { } i.prototype = { - n: function() { + free: function() { this.gasRenderer.free(); this.clearUI(); this.roleMenuConfirm.off("click"); @@ -584,7 +583,7 @@ i.prototype = { } this.spectatorCount = t.Re.Be; this.updateSpectatorCountDisplay(false); - if (t.Le.he && !this.dead) { + if (t.netData.he && !this.dead) { this.dead = true; this.Pe.stop(); } @@ -1655,7 +1654,7 @@ i.prototype = { this.bigmapDisplayed ? "block" : "none" ); this.updateSpectatorCountDisplay(true); - this.redraw(this.game.De); + this.redraw(this.game.camera); }, updateSpectatorCountDisplay: function(e) { const t = !this.bigmapDisplayed && this.spectatorCount > 0; diff --git a/client/src/ui2.js b/client/src/ui2.js index 63446d4f..c840660b 100644 --- a/client/src/ui2.js +++ b/client/src/ui2.js @@ -483,7 +483,7 @@ const E = { }; Ui2.prototype = { - n: function() { + free: function() { for (let e = 0; e < this.eventListeners.length; e++) { const t = this.eventListeners[e]; t.elem.removeEventListener(t.event, t.fn); @@ -568,9 +568,9 @@ Ui2.prototype = { O.opacity = E < 6.5 ? 1 : 0; } } - c.health = t.Le.he ? 0 : math.max(t.Re.Lr, 1); + c.health = t.netData.he ? 0 : math.max(t.Re.Lr, 1); c.boost = t.Re.qr; - c.downed = t.Le.ue; + c.downed = t.netData.ue; let B = D.None; let R = null; let L = true; @@ -588,7 +588,7 @@ Ui2.prototype = { if (V) { const U = collider.intersectCircle( H.collider, - t.Le.ie, + t.netData.ie, V.rad + t.rad ); if (U && U.pen >= F) { @@ -604,7 +604,7 @@ Ui2.prototype = { L = true; } const W = i.Er(); - if (W && !t.Le.ue) { + if (W && !t.netData.ue) { const G = GameObjectDefs[W.type]; const X = t.Wr(GameConfig.WeaponSlot.Primary); const K = t.Wr(GameConfig.WeaponSlot.Secondary); @@ -615,10 +615,10 @@ Ui2.prototype = { (c.touch && G.type == "helmet" && t.Nr() == G.level && - W.type != t.Le.le) || + W.type != t.netData.le) || (G.type == "chest" && t.Hr() == G.level && - W.type != t.Le.ce) + W.type != t.netData.ce) ) { J = true; } @@ -636,7 +636,7 @@ Ui2.prototype = { J); } const Q = t.hasPerk("self_revive"); - if (t.action.type == Action.None && (!t.Le.ue || Q)) { + if (t.action.type == Action.None && (!t.netData.ue || Q)) { for ( let $ = a.qe(t.__id).teamId, ee = a.$e.p(), @@ -650,12 +650,12 @@ Ui2.prototype = { if ( (re.__id != t.__id || Q) && $ == ae && - re.Le.ue && - !re.Le.he && + re.netData.ue && + !re.netData.he && re.action.type != Action.Revive ) { const ie = v2.length( - v2.sub(re.Le.ie, t.Le.ie) + v2.sub(re.netData.ie, t.netData.ie) ); if ( ie < GameConfig.player.reviveRange && @@ -669,7 +669,7 @@ Ui2.prototype = { } } } - if (t.action.type == Action.Revive && t.Le.ue && !Q) { + if (t.action.type == Action.Revive && t.netData.ue && !Q) { B = D.None; R = null; L = false; @@ -677,7 +677,7 @@ Ui2.prototype = { if ( (t.action.type == Action.UseItem || (t.action.type == Action.Revive && - (!t.Le.ue || !!Q))) && + (!t.netData.ue || !!Q))) && !r ) { B = D.Cancel; @@ -772,12 +772,12 @@ Ui2.prototype = { const Me = c.gear[Te]; let Pe = ""; if (Me.type == "chest") { - Pe = t.Le.ce; + Pe = t.netData.ce; } else if (Me.type == "helmet") { - Pe = t.Le.le; + Pe = t.netData.le; } else if ( Me.type == "backpack" && - (Pe = t.Le.ne) == "backpack00" + (Pe = t.netData.ne) == "backpack00" ) { Pe = ""; } diff --git a/server/src/game.ts b/server/src/game.ts index b0c77e56..ca8c4b89 100644 --- a/server/src/game.ts +++ b/server/src/game.ts @@ -1,21 +1,17 @@ import { type WebSocket } from "uWebSockets.js"; import { type PlayerContainer } from "./server"; -import { type Msg, MsgStream, MsgType } from "./net/net"; import { Player } from "./objects/player"; import { type Vec2, v2 } from "../../shared/utils/v2"; -import { InputMsg } from "./net/inputMsg"; import { Grid } from "./utils/grid"; -import { JoinMsg } from "./net/joinMsg"; import { ObjectType, type BaseGameObject } from "./objects/gameObject"; import { SpawnMode, type ConfigType } from "./config"; import { GameMap } from "./map"; import { BulletManager } from "./objects/bullet"; -import { type ExplosionData } from "./net/updateMsg"; import { Logger } from "./utils/logger"; import { Loot } from "./objects/loot"; import { GameObjectDefs } from "../../shared/defs/gameObjectDefs"; import { GameConfig } from "../../shared/gameConfig"; -import { DisconnectMsg } from "./net/disconnectMsg"; +import net from "../../shared/net"; export class Game { stopped = false; @@ -37,14 +33,14 @@ export class Game { aliveCountDirty = false; - msgsToSend: Msg[] = []; + msgsToSend: Array<{ type: number, msg: any }> = []; partialObjs = new Set(); fullObjs = new Set(); newPlayers: Player[] = []; - explosions: ExplosionData[] = []; + explosions = []; id: number; @@ -186,23 +182,24 @@ export class Game { } handleMsg(buff: ArrayBuffer, player: Player): void { - const msgStream = new MsgStream(buff); + const msgStream = new net.MsgStream(buff); const type = msgStream.deserializeMsgType(); + const stream = msgStream.stream!; switch (type) { - case MsgType.Input: { - const inputMsg = new InputMsg(); - inputMsg.deserialize(msgStream.stream); + case net.Msg.Input: { + const inputMsg = new net.InputMsg(); + inputMsg.deserialize(stream); player.handleInput(inputMsg); break; } - case MsgType.Join: { - const joinMsg = new JoinMsg(); - joinMsg.deserialize(msgStream.stream); + case net.Msg.Join: { + const joinMsg = new net.JoinMsg(); + joinMsg.deserialize(stream); if (joinMsg.protocol !== GameConfig.protocolVersion) { - const disconnectMsg = new DisconnectMsg(); + const disconnectMsg = new net.DisconnectMsg(); disconnectMsg.reason = "index-invalid-protocol"; - player.sendMsg(disconnectMsg); + player.sendMsg(net.Msg.Disconnect, disconnectMsg); setTimeout(() => { player.socket.close(); }, 1); diff --git a/server/src/map.ts b/server/src/map.ts index 15c8e73d..ecda9a43 100644 --- a/server/src/map.ts +++ b/server/src/map.ts @@ -3,8 +3,6 @@ import { type StructureDef, type BuildingDef, type ObstacleDef } from "../../sha import { type MapDef, MapDefs } from "../../shared/defs/mapDefs"; import { type Game } from "./game"; import { GameConfig } from "../../shared/gameConfig"; -import { MapMsg, type MapRiver } from "./net/mapMsg"; -import { MsgStream } from "./net/net"; import { Building } from "./objects/building"; import { Decal } from "./objects/decal"; import { ObjectType } from "./objects/gameObject"; @@ -16,9 +14,10 @@ import { collider } from "../../shared/utils/collider"; import { mapHelpers } from "../../shared/utils/mapHelpers"; import { math } from "../../shared/utils/math"; import { type River } from "../../shared/utils/river"; -import { generateTerrain } from "../../shared/utils/terrainGen"; +import { type MapRiverData, generateTerrain } from "../../shared/utils/terrainGen"; import { util } from "../../shared/utils/util"; import { type Vec2, v2 } from "../../shared/utils/v2"; +import net from "../../shared/net"; export class GameMap { game: Game; @@ -26,8 +25,8 @@ export class GameMap { width: number; height: number; - msg = new MapMsg(); - mapStream = new MsgStream(new ArrayBuffer(1 << 14)); + msg = new net.MapMsg(); + mapStream = new net.MsgStream(new ArrayBuffer(1 << 14)); seed = util.randomInt(0, 2 ** 31); bounds: AABB; @@ -41,7 +40,7 @@ export class GameMap { mapDef: MapDef; - riverDescs: MapRiver[] = []; + riverDescs: MapRiverData[] = []; constructor(game: Game) { this.game = game; @@ -85,7 +84,7 @@ export class GameMap { this.generateObjects(); - this.mapStream.serializeMsg(this.msg); + this.mapStream.serializeMsg(net.Msg.Map, this.msg); } generateTerrain(): void { diff --git a/server/src/net/KillMsg.ts b/server/src/net/KillMsg.ts deleted file mode 100644 index 13bf3fa2..00000000 --- a/server/src/net/KillMsg.ts +++ /dev/null @@ -1,40 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class KillMsg extends Msg { - override readonly msgType = MsgType.Kill; - itemSourceType = ""; - mapSourceType = ""; - damageType = 0; - targetId = 0; - killerId = 0; - killCreditId = 0; - killerKills = 0; - downed = false; - killed = false; - - deserialize(s: SurvivBitStream) { - this.damageType = s.readUint8(); - this.itemSourceType = s.readGameType(); - this.mapSourceType = s.readMapType(); - this.targetId = s.readUint16(); - this.killerId = s.readUint16(); - this.killCreditId = s.readUint16(); - this.killerKills = s.readUint8(); - this.downed = s.readBoolean(); - this.killed = s.readBoolean(); - s.readAlignToNextByte(); - } - - serialize(s: SurvivBitStream): void { - s.writeUint8(this.damageType); - s.writeGameType(this.itemSourceType); - s.writeMapType(this.mapSourceType); - s.writeUint16(this.targetId); - s.writeUint16(this.killerId); - s.writeUint16(this.killCreditId); - s.writeUint8(this.killerKills); - s.writeBoolean(this.downed); - s.writeBoolean(this.killed); - s.writeAlignToNextByte(); - } -} diff --git a/server/src/net/aliveCountMsg.ts b/server/src/net/aliveCountMsg.ts deleted file mode 100644 index 15774d3d..00000000 --- a/server/src/net/aliveCountMsg.ts +++ /dev/null @@ -1,21 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class AliveCountMsg extends Msg { - override readonly msgType = MsgType.AliveCounts; - - aliveCounts: number[] = []; - - serialize(stream: SurvivBitStream): void { - stream.writeUint8(this.aliveCounts.length); - for (const aliveCount of this.aliveCounts) { - stream.writeUint8(aliveCount); - } - } - - deserialize(stream: SurvivBitStream): void { - const count = stream.readUint8(); - for (let i = 0; i < count; i++) { - this.aliveCounts.push(stream.readUint8()); - } - } -} diff --git a/server/src/net/disconnectMsg.ts b/server/src/net/disconnectMsg.ts deleted file mode 100644 index d158aa32..00000000 --- a/server/src/net/disconnectMsg.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class DisconnectMsg extends Msg { - msgType = MsgType.Disconnect; - - reason = ""; - - serialize(s: SurvivBitStream): void { - s.writeString(this.reason); - } - - deserialize(s: SurvivBitStream): void { - this.reason = s.readString(); - } -} diff --git a/server/src/net/dropItemMsg.ts b/server/src/net/dropItemMsg.ts deleted file mode 100644 index b120d218..00000000 --- a/server/src/net/dropItemMsg.ts +++ /dev/null @@ -1,20 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class DropItemMsg extends Msg { - msgType = MsgType.DropItem; - - item = ""; - weapIdx = 0; - - serialize(s: SurvivBitStream): void { - s.writeGameType(this.item); - s.writeUint8(this.weapIdx); - s.writeBits(0, 6); - } - - deserialize(s: SurvivBitStream): void { - this.item = s.readGameType(); - this.weapIdx = s.readUint8(); - s.readBits(6); - } -} diff --git a/server/src/net/emoteMsg.ts b/server/src/net/emoteMsg.ts deleted file mode 100644 index dc1c2770..00000000 --- a/server/src/net/emoteMsg.ts +++ /dev/null @@ -1,24 +0,0 @@ -import { v2 } from "../../../shared/utils/v2"; -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class EmoteMsg extends Msg { - msgType = MsgType.Emote; - - pos = v2.create(0, 0); - type = ""; - isPing = false; - - serialize(s: SurvivBitStream): void { - s.writeVec(this.pos, 0, 0, 1024, 1024, 16); - s.writeGameType(this.type); - s.writeBoolean(this.isPing); - s.writeBits(0, 5); - } - - deserialize(s: SurvivBitStream): void { - this.pos = s.readVec(0, 0, 1024, 1024, 16); - this.type = s.readGameType(); - this.isPing = s.readBoolean(); - s.readBits(6); - } -} diff --git a/server/src/net/gameOverMsg.ts b/server/src/net/gameOverMsg.ts deleted file mode 100644 index b9781269..00000000 --- a/server/src/net/gameOverMsg.ts +++ /dev/null @@ -1,41 +0,0 @@ -import { PlayerStatsMsg } from "./playerStatsMsg"; -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class GameOverMsg extends Msg { - override readonly msgType = MsgType.GameOver; - - teamId = 1; - teamRank = 0; - gameOver = false; - winningTeamId = 0; - playerStats: Array = []; - - override deserialize(s: SurvivBitStream) { - this.teamId = s.readUint8(); - this.teamRank = s.readUint8(); - this.gameOver = !!s.readUint8(); - this.winningTeamId = s.readUint8(); - - const count = s.readUint8(); - for (let i = 0; i < count; i++) { - const statsMsg = new PlayerStatsMsg(); - statsMsg.deserialize(s); - this.playerStats.push(statsMsg.playerStats); - } - } - - override serialize(s: SurvivBitStream): void { - s.writeUint8(this.teamId); - s.writeUint8(this.teamRank); - s.writeUint8(+this.gameOver); - s.writeUint8(this.winningTeamId); - - s.writeUint8(this.playerStats.length); - for (const stats of this.playerStats) { - const statsMsg = new PlayerStatsMsg(); - statsMsg.playerId = stats.playerId; - statsMsg.playerStats = stats; - statsMsg.serialize(s); - } - } -} diff --git a/server/src/net/inputMsg.ts b/server/src/net/inputMsg.ts deleted file mode 100644 index 8b795402..00000000 --- a/server/src/net/inputMsg.ts +++ /dev/null @@ -1,79 +0,0 @@ -import { v2 } from "../../../shared/utils/v2"; -import { Msg, MsgType, NetConstants, type SurvivBitStream } from "./net"; - -export class InputMsg extends Msg { - override readonly msgType = MsgType.Input; - - seq = 0; - moveLeft = false; - moveRight = false; - moveUp = false; - moveDown = false; - shootStart = false; - shootHold = false; - portrait = false; - touchMoveActive = false; - touchMoveDir = v2.create(1, 0); - touchMoveLen = 255; - toMouseDir = v2.create(1, 0); - toMouseLen = 0; - inputs: number[] = []; - useItem = ""; - - addInput(input: number) { - this.inputs.length < 7 && !this.inputs.includes(input) && this.inputs.push(input); - } - - serialize(s: SurvivBitStream) { - s.writeUint8(this.seq); - s.writeBoolean(this.moveLeft); - s.writeBoolean(this.moveRight); - s.writeBoolean(this.moveUp); - s.writeBoolean(this.moveDown); - - s.writeBoolean(this.shootStart); - s.writeBoolean(this.shootHold); - - s.writeBoolean(this.portrait); - s.writeBoolean(this.touchMoveActive); - if (this.touchMoveActive) { - s.writeUnitVec(this.touchMoveDir, 8); - s.writeUint8(this.touchMoveLen); - } - s.writeUnitVec(this.toMouseDir, 10); - s.writeFloat(this.toMouseLen, 0, NetConstants.MouseMaxDist, 8); - s.writeBits(this.inputs.length, 4); - for (let i = 0; i < this.inputs.length; i++) s.writeUint8(this.inputs[i]); - - s.writeGameType(this.useItem); - - s.writeBits(0, 6); - } - - deserialize(s: SurvivBitStream): void { - this.seq = s.readUint8(); - this.moveLeft = s.readBoolean(); - this.moveRight = s.readBoolean(); - this.moveUp = s.readBoolean(); - this.moveDown = s.readBoolean(); - - this.shootStart = s.readBoolean(); - this.shootHold = s.readBoolean(); - - this.portrait = s.readBoolean(); - this.touchMoveActive = s.readBoolean(); - if (this.touchMoveActive) { - this.touchMoveDir = s.readUnitVec(8); - this.touchMoveLen = s.readUint8(); - } - this.toMouseDir = s.readUnitVec(10); - this.toMouseLen = s.readFloat(0, NetConstants.MouseMaxDist, 8); - - const length = s.readBits(4); - for (let i = 0; i < length; i++) this.inputs.push(s.readUint8()); - - this.useItem = s.readGameType(); - - s.readBits(6); - } -} diff --git a/server/src/net/joinMsg.ts b/server/src/net/joinMsg.ts deleted file mode 100644 index f31b210d..00000000 --- a/server/src/net/joinMsg.ts +++ /dev/null @@ -1,44 +0,0 @@ -import { Msg, MsgType, NetConstants, type SurvivBitStream } from "./net"; - -export class JoinMsg extends Msg { - override readonly msgType = MsgType.Join; - - protocol = 0; - matchPriv = ""; - loadoutPriv = ""; - questPriv = ""; - name = ""; - useTouch = false; - isMobile = false; - proxy = false; - otherProxy = false; - bot = false; - - deserialize(s: SurvivBitStream): void { - this.protocol = s.readUint32(); - this.matchPriv = s.readString(); - this.loadoutPriv = s.readString(); - this.questPriv = s.readString(); - this.name = s.readString(NetConstants.PlayerNameMaxLen); - this.useTouch = s.readBoolean(); - this.isMobile = s.readBoolean(); - this.proxy = s.readBoolean(); - this.otherProxy = s.readBoolean(); - this.bot = s.readBoolean(); - s.readAlignToNextByte(); - } - - serialize(s: SurvivBitStream) { - s.writeUint32(this.protocol); - if (this.matchPriv) s.writeString(this.matchPriv); - if (this.loadoutPriv) s.writeString(this.loadoutPriv); - if (this.questPriv) s.writeString(this.questPriv); - s.writeString(this.name, NetConstants.PlayerNameMaxLen); - s.writeBoolean(this.useTouch); - s.writeBoolean(this.isMobile); - s.writeBoolean(this.proxy); - s.writeBoolean(this.otherProxy); - s.writeBoolean(this.bot); - s.writeAlignToNextByte(); - } -} diff --git a/server/src/net/joinedMsg.ts b/server/src/net/joinedMsg.ts deleted file mode 100644 index c7d4ea7e..00000000 --- a/server/src/net/joinedMsg.ts +++ /dev/null @@ -1,33 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class JoinedMsg extends Msg { - override readonly msgType = MsgType.Joined; - - teamMode = 0; - playerId = 0; - started = false; - emotes: string[] = []; - - serialize(s: SurvivBitStream): void { - s.writeUint8(this.teamMode); - s.writeUint16(this.playerId); - s.writeBoolean(this.started); - - s.writeUint8(this.emotes.length); - for (const emote of this.emotes) { - s.writeGameType(emote); - } - } - - deserialize(s: SurvivBitStream): void { - this.teamMode = s.readUint8(); - this.playerId = s.readUint16(); - this.started = s.readBoolean(); - - const count = s.readUint8(); - for (let i = 0; i < count; i++) { - this.emotes.push(s.readGameType()); - } - s.readAlignToNextByte(); - } -} diff --git a/server/src/net/loadoutMsg.ts b/server/src/net/loadoutMsg.ts deleted file mode 100644 index 96022ac9..00000000 --- a/server/src/net/loadoutMsg.ts +++ /dev/null @@ -1,25 +0,0 @@ -import { GameConfig } from "../../../shared/gameConfig"; -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class LoadoutMsg extends Msg { - msgType = MsgType.Loadout; - - emotes: string[] = []; - custom = 0; - - serialize(s: SurvivBitStream): void { - for (let i = 0; i < GameConfig.EmoteSlot.Count; i++) { - s.writeGameType(this.emotes[i]); - } - s.writeUint8(this.custom); - s.readAlignToNextByte(); - } - - deserialize(s: SurvivBitStream): void { - for (let i = 0; i < GameConfig.EmoteSlot.Count; i++) { - this.emotes.push(s.readGameType()); - } - this.custom = s.readUint8(); - s.writeAlignToNextByte(); - } -} diff --git a/server/src/net/mapMsg.ts b/server/src/net/mapMsg.ts deleted file mode 100644 index a1250d9a..00000000 --- a/server/src/net/mapMsg.ts +++ /dev/null @@ -1,196 +0,0 @@ -import { type Vec2 } from "../../../shared/utils/v2"; -import { Msg, MsgType, NetConstants, type SurvivBitStream } from "./net"; - -export interface MapRiver { - width: number - looped: boolean - points: Vec2[] -} - -function serializeMapRiver(s: SurvivBitStream, data: MapRiver) { - s.writeFloat32(data.width); - s.writeUint8(+data.looped); - s.writeUint8(data.points.length); - - for (const point of data.points) { - s.writeVec(point, 0, 0, 1024, 1024, 16); - } -} - -function deserializeMapRiver(s: SurvivBitStream) { - const x: MapRiver = { - width: s.readFloat32(), - looped: !!s.readUint8(), - points: [] - }; - const count = s.readUint8(); - for (let i = 0; i < count; i++) { - const pos = s.readVec(0, 0, 1024, 1024, 16); - x.points.push(pos); - } - return x; -} - -export interface MapPlace { - name: string - pos: Vec2 -} - -function serializeMapPlace(s: SurvivBitStream, place: MapPlace) { - s.writeString(place.name); - s.writeVec(place.pos, 0, 0, 1024, 1024, 16); -} - -function deserializeMapPlace(s: SurvivBitStream) { - return { - name: s.readString(), - pos: s.readVec(0, 0, 1024, 1024, 16) - }; -} - -export interface MapGroundPatch { - min: Vec2 - max: Vec2 - color: number - roughness: number - offsetDist: number - order: number - useAsMapShape: boolean -} - -function deserializeMapGroundPatch(s: SurvivBitStream): MapGroundPatch { - return { - min: s.readVec(0, 0, 1024, 1024, 16), - max: s.readVec(0, 0, 1024, 1024, 16), - color: s.readUint32(), - roughness: s.readFloat32(), - offsetDist: s.readFloat32(), - order: s.readBits(7), - useAsMapShape: s.readBoolean() - }; -} - -function serializeMapGroundPatch(s: SurvivBitStream, patch: MapGroundPatch) { - s.writeVec(patch.min, 0, 0, 1024, 1024, 16); - s.writeVec(patch.max, 0, 0, 1024, 1024, 16); - s.writeUint32(patch.color); - s.writeFloat32(patch.roughness); - s.writeFloat32(patch.offsetDist); - s.writeBits(patch.order, 7); - s.writeBoolean(patch.useAsMapShape); -} - -export interface MapObj { - pos: Vec2 - scale: number - type: string - ori: number -} - -function serializeMapObj(s: SurvivBitStream, obj: MapObj) { - s.writeVec(obj.pos, 0, 0, 1024, 1024, 16); - s.writeFloat(obj.scale, NetConstants.MapObjectMinScale, NetConstants.MapObjectMaxScale, 8); - s.writeMapType(obj.type); - s.writeBits(obj.ori, 2); - s.writeBits(0, 2); // Padding -} - -function deserializeMapObj(s: SurvivBitStream): MapObj { - const obj: MapObj = { - pos: s.readVec(0.0, 0.0, 1024.0, 1024.0, 16), - scale: s.readFloat(NetConstants.MapObjectMinScale, NetConstants.MapObjectMaxScale, 8), - type: s.readMapType(), - ori: s.readBits(2) - }; - s.readBits(2); // Padding - return obj; -} - -export class MapMsg extends Msg { - override readonly msgType = MsgType.Map; - - mapName = ""; - seed = 0; - width = 0; - height = 0; - shoreInset = 0; - grassInset = 0; - rivers: MapRiver[] = []; - places: MapPlace[] = []; - objects: MapObj[] = []; - groundPatches: MapGroundPatch[] = []; - - serialize(s: SurvivBitStream) { - s.writeString(this.mapName, NetConstants.MapNameMaxLen); - s.writeUint32(this.seed); - s.writeUint16(this.width); - s.writeUint16(this.height); - s.writeUint16(this.shoreInset); - s.writeUint16(this.grassInset); - - // Rivers - s.writeUint8(this.rivers.length); - for (const river of this.rivers) { - serializeMapRiver(s, river); - } - - // Places - s.writeUint8(this.places.length); - for (const place of this.places) { - serializeMapPlace(s, place); - } - - // Objects - s.writeUint16(this.objects.length); - for (const obj of this.objects) { - serializeMapObj(s, obj); - } - - // GroundPatches - s.writeUint8(this.groundPatches.length); - for (const patch of this.groundPatches) { - serializeMapGroundPatch(s, patch); - } - } - - deserialize(s: SurvivBitStream) { - this.mapName = s.readString(NetConstants.MapNameMaxLen); - this.seed = s.readUint32(); - this.width = s.readUint16(); - this.height = s.readUint16(); - this.shoreInset = s.readUint16(); - this.grassInset = s.readUint16(); - - // Rivers - { - const count = s.readUint8(); - for (let i = 0; i < count; i++) { - this.rivers.push(deserializeMapRiver(s)); - } - } - - // Places - { - const count = s.readUint8(); - for (let i = 0; i < count; i++) { - this.places.push(deserializeMapPlace(s)); - } - } - - // Objects - { - const count = s.readUint16(); - for (let i = 0; i < count; i++) { - this.objects.push(deserializeMapObj(s)); - } - } - - // GroundPatches - { - const count = s.readUint8(); - for (let i = 0; i < count; i++) { - this.groundPatches.push(deserializeMapGroundPatch(s)); - } - } - } -} diff --git a/server/src/net/net.ts b/server/src/net/net.ts deleted file mode 100644 index 4cddc7e5..00000000 --- a/server/src/net/net.ts +++ /dev/null @@ -1,215 +0,0 @@ -import { BitStream, type BitView } from "bit-buffer"; -import { MapObjectDefs } from "../../../shared/defs/mapObjectDefs"; -import { GameObjectDefs } from "../../../shared/defs/gameObjectDefs"; - -import { type Vec2 } from "../../../shared/utils/v2"; - -class ConfigTypeMap { - private _typeToId: Record = {}; - private _idToType: Record = {}; - private _nextId = 0; - readonly maxId: number; - - constructor(typeBits: number, types: string[]) { - this.maxId = 2 ** typeBits; - this.addType(""); - - for (const type of types) { - this.addType(type); - } - } - - addType(type: string) { - // assert(this._typeToId[type] === undefined, `Type ${type} has already been defined!`); - // assert(this.nextId < this.maxId); - this._typeToId[type] = this._nextId; - this._idToType[this._nextId] = type; - this._nextId++; - } - - typeToId(type: string) { - const id = this._typeToId[type]; - // assert(id !== undefined, `Invalid type ${type}`); - return id; - } - - idToType(id: number) { - const type = this._idToType[id]; - if (type === undefined) { - console.error("Invalid id given to idToType", id, "max", Object.keys(this._idToType).length); - } - return type; - } -} - -const mapTypeSerialization = new ConfigTypeMap(12, Object.keys(MapObjectDefs)); -const gameTypeSerialization = new ConfigTypeMap(10, Object.keys(GameObjectDefs)); - -export class SurvivBitStream extends BitStream { - constructor(source: ArrayBuffer | BitView, byteOffset = 0, byteLength = 0) { - super(source, byteOffset, byteLength); - } - - writeString(str: string, len?: number): void { this.writeASCIIString(str, len); } - readString(len?: number): string { return this.readASCIIString(len); } - - writeFloat(val: number, min: number, max: number, bitCount: number): void { - const range = (1 << bitCount) - 1; - const x = val < max ? (val > min ? val : min) : max; - const t = (x - min) / (max - min); - this.writeBits(t * range + 0.5, bitCount); - } - - readFloat(min: number, max: number, bitCount: number): number { - const range = (1 << bitCount) - 1; - return min + (max - min) * this.readBits(bitCount) / range; - } - - writeVec(vec: Vec2, minX: number, minY: number, maxX: number, maxY: number, bitCount: number): void { - this.writeFloat(vec.x, minX, maxX, bitCount); - this.writeFloat(vec.y, minY, maxY, bitCount); - } - - readVec(minX: number, minY: number, maxX: number, maxY: number, bitCount: number): Vec2 { - return { - x: this.readFloat(minX, maxX, bitCount), - y: this.readFloat(minY, maxY, bitCount) - }; - } - - writeUnitVec(vec: Vec2, bitCount: number): void { - this.writeVec(vec, -1.0001, -1.0001, 1.0001, 1.0001, bitCount); - } - - readUnitVec(bitCount: number): Vec2 { - return this.readVec(-1.0001, -1.0001, 1.0001, 1.0001, bitCount); - } - - writeVec32(vec: Vec2): void { - this.writeFloat32(vec.x); - this.writeFloat32(vec.y); - } - - readVec32(): Vec2 { - return { - x: this.readFloat32(), - y: this.readFloat32() - }; - } - - // private properties? what is that - declare _view: BitView & { _view: Uint8Array }; - - writeBytes(src: SurvivBitStream, offset: number, length: number) { - // assert(this._index % 8 == 0); - const data = new Uint8Array(src._view._view.buffer, offset, length); - this._view._view.set(data, this.index / 8); - this.index += length * 8; - } - - writeAlignToNextByte(): void { - const offset = 8 - this.index % 8; - if (offset < 8) this.writeBits(0, offset); - } - - readAlignToNextByte(): void { - const offset = 8 - this.index % 8; - if (offset < 8) this.readBits(offset); - } - - writeGameType(type: string): void { - this.writeBits(gameTypeSerialization.typeToId(type), 10); - } - - readGameType(): string { - return gameTypeSerialization.idToType(this.readBits(10)); - } - - writeMapType(type: string): void { - this.writeBits(mapTypeSerialization.typeToId(type), 12); - } - - readMapType(): string { - return mapTypeSerialization.idToType(this.readBits(12)); - } -} - -export const NetConstants = { - MapNameMaxLen: 24, - PlayerNameMaxLen: 16, - MouseMaxDist: 64, - SmokeMaxRad: 10, - ActionMaxDuration: 8.5, - AirstrikeZoneMaxRad: 256, - AirstrikeZoneMaxDuration: 60, - PlayerMinScale: 0.75, - PlayerMaxScale: 2, - MapObjectMinScale: 0.125, - MapObjectMaxScale: 2.5, - MaxPerks: 8, - MaxMapIndicators: 16 -}; - -export enum MsgType { - None, - Join, - Disconnect, - Input, - Edit, - Joined, - Update, - Kill, - GameOver, - Pickup, - Map, - Spectate, - DropItem, - Emote, - PlayerStats, - AdStatus, - Loadout, - RoleAnnouncement, - Stats, - UpdatePass, - AliveCounts, - PerkModeRoleSelect -} - -export abstract class Msg { - abstract msgType: MsgType; - abstract deserialize(s: SurvivBitStream): void; - abstract serialize(s: SurvivBitStream): void; -} - -export class MsgStream { - arrayBuf: ArrayBuffer; - stream: SurvivBitStream; - - constructor(buf: Uint8Array | ArrayBuffer) { - let arrayBuf = buf; - if (buf instanceof Uint8Array) { - arrayBuf = buf.buffer.slice(buf.byteOffset, buf.byteOffset + buf.byteLength); - } - - this.arrayBuf = arrayBuf; - this.stream = new SurvivBitStream(arrayBuf); - } - - getBuffer() { - return new Uint8Array(this.arrayBuf, 0, this.stream.byteIndex); - } - - serializeMsg(msg: Msg) { - // assert(this.stream.index % 8 == 0); - this.stream.writeUint8(msg.msgType); - msg.serialize(this.stream); - // assert(this.stream.index % 8 == 0); - } - - deserializeMsgType(): MsgType { - if (this.stream.length - this.stream.byteIndex * 8 >= 1) { - return this.stream.readUint8(); - } - return MsgType.None; - } -} diff --git a/server/src/net/objectSerialization.ts b/server/src/net/objectSerialization.ts deleted file mode 100644 index d175d963..00000000 --- a/server/src/net/objectSerialization.ts +++ /dev/null @@ -1,383 +0,0 @@ -import { ObjectType } from "../objects/gameObject"; -import { NetConstants, type SurvivBitStream } from "./net"; -import { GameConfig } from "../../../shared/gameConfig"; -import { type Vec2 } from "../../../shared/utils/v2"; - -/* eslint-disable @typescript-eslint/ban-types */ - -export interface ObjectsPartialData { - [ObjectType.Invalid]: {} - [ObjectType.Player]: { - pos: Vec2 - dir: Vec2 - } - [ObjectType.Obstacle]: { - pos: Vec2 - ori: number - scale: number - } - [ObjectType.Loot]: { - pos: Vec2 - } - [ObjectType.LootSpawner]: {} - [ObjectType.DeadBody]: { - pos: Vec2 - } - [ObjectType.Building]: { - ceilingDead: boolean - occupied: boolean - ceilingDamaged: boolean - hasPuzzle: boolean - puzzleSolved: boolean - puzzleErrSeq: number - } - [ObjectType.Structure]: {} - [ObjectType.Decal]: {} - [ObjectType.Projectile]: { - pos: Vec2 - posZ: number - dir: Vec2 - } - [ObjectType.Smoke]: { - pos: Vec2 - rad: number - } - [ObjectType.Airdrop]: { - fallT: number - landed: boolean - } -} - -export interface ObjectsFullData { - [ObjectType.Invalid]: null - [ObjectType.Player]: { - outfit: string - pack: string - helmet: string - chest: string - activeWeapon: string - layer: number - dead: boolean - downed: boolean - - animType: number - animSeq: number - - actionType: number - actionSeq: number - - wearingPan: boolean - healEffect: boolean - - frozen: boolean - frozenOri: number - - hasHaste: boolean - hasteType: number - hasteSeq: number - - actionItem: string - - hasScale: boolean - scale: number - - hasRole: boolean - role: string - - hasPerks: boolean - perks: Array<{ - type: string - droppable: boolean - }> - - } - [ObjectType.Obstacle]: { - healthT: number - type: string - layer: number - dead: boolean - isDoor: boolean - door?: { - open: boolean - canUse: boolean - locked: boolean - seq: number - } - isButton: boolean - button?: { - onOff: boolean - canUse: boolean - seq: number - } - isPuzzlePiece: boolean - parentBuildingId?: number - isSkin: boolean - skinPlayerId?: number - } - [ObjectType.Loot]: { - type: string - layer: number - isOld: boolean - isPreloadedGun: boolean - count: number - ownerId: number - } - [ObjectType.LootSpawner]: null - [ObjectType.DeadBody]: { - layer: number - playerId: number - } - [ObjectType.Building]: { - pos: Vec2 - type: string - ori: number - layer: number - } - [ObjectType.Structure]: { - pos: Vec2 - type: string - ori: number - interiorSoundEnabled: boolean - interiorSoundAlt: boolean - layerObjIds: number[] - } - [ObjectType.Decal]: { - pos: Vec2 - scale: number - type: string - ori: number - layer: number - goreKills: number - } - [ObjectType.Projectile]: { - type: string - layer: number - } - [ObjectType.Smoke]: { - layer: number - interior: number - } - [ObjectType.Airdrop]: { - pos: Vec2 - } -} - -interface ObjectSerialization { - serializedFullSize?: number - serializePart: (s: SurvivBitStream, data: ObjectsPartialData[T]) => void - serializeFull: (s: SurvivBitStream, data: ObjectsFullData[T]) => void - // deserializePart: (s: SurvivBitStream) => ObjectsPartialData[T] - // deserializeFull: (s: SurvivBitStream, data: any) => ObjectsFullData[T] -} - -export const ObjectSerializeFns: { [K in ObjectType]: ObjectSerialization } = { - [ObjectType.Player]: { - serializedFullSize: 32, - serializePart(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - s.writeUnitVec(data.dir, 8); - }, - serializeFull(s, data) { - s.writeGameType(data.outfit); - s.writeGameType(data.pack); - s.writeGameType(data.helmet); - s.writeGameType(data.chest); - s.writeGameType(data.activeWeapon); - - s.writeBits(data.layer, 2); - s.writeBoolean(data.dead); - s.writeBoolean(data.downed); - - s.writeBits(data.animType, 3); - s.writeBits(data.animSeq, 3); - s.writeBits(data.actionType, 3); - s.writeBits(data.actionSeq, 3); - - s.writeBoolean(data.wearingPan); - s.writeBoolean(data.healEffect); - - s.writeBoolean(data.frozen); - s.writeBits(data.frozenOri, 2); - - s.writeBoolean(data.hasHaste); - if (data.hasHaste) { - s.writeBits(data.hasteType, 3); - s.writeBits(data.hasteSeq, 3); - } - - s.writeBoolean(data.actionItem !== ""); - if (data.actionItem !== "") { - s.writeGameType(data.actionItem); - } - - s.writeBoolean(data.hasScale); - if (data.hasScale) { - s.writeFloat(data.scale, NetConstants.PlayerMinScale, NetConstants.PlayerMaxScale, 8); - } - - s.writeBoolean(data.hasRole); - if (data.hasRole) s.writeGameType(data.role); - - s.writeBoolean(data.hasPerks); - if (data.hasPerks) { - s.writeBits(data.perks.length, 3); - for (const perk of data.perks) { - s.writeGameType(perk.type); - s.writeBoolean(perk.droppable); - } - } - - s.writeAlignToNextByte(); - } - }, - [ObjectType.Obstacle]: { - serializePart(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - s.writeBits(data.ori, 2); - s.writeFloat( - data.scale, - NetConstants.MapObjectMinScale, - NetConstants.MapObjectMaxScale, - 8 - ); - s.writeBits(0, 6); - }, - serializeFull(s, data) { - s.writeFloat(data.healthT, 0, 1, 8); - s.writeMapType(data.type); - s.writeBits(data.layer, 2); - s.writeBoolean(data.dead); - s.writeBoolean(data.isDoor); - if (data.isDoor) { - s.writeBoolean(data.door!.open); - s.writeBoolean(data.door!.canUse); - s.writeBoolean(data.door!.locked); - s.writeBits(data.door!.seq, 5); - } - - s.writeBoolean(data.isButton); - if (data.isButton) { - s.writeBoolean(data.button!.onOff); - s.writeBoolean(data.button!.canUse); - s.writeBits(data.button!.seq, 6); - } - - s.writeBoolean(data.isPuzzlePiece); - if (data.isPuzzlePiece) s.writeUint16(data.parentBuildingId!); - - s.writeBoolean(data.isSkin); - if (data.isSkin) s.writeUint16(data.skinPlayerId!); - - s.writeBits(0, 5); // padding - } - }, - [ObjectType.Building]: { - serializePart(s, data) { - s.writeBoolean(data.ceilingDead); - s.writeBoolean(data.occupied); - s.writeBoolean(data.ceilingDamaged); - s.writeBoolean(data.hasPuzzle); - if (data.hasPuzzle) { - s.writeBoolean(data.puzzleSolved); - s.writeBits(data.puzzleErrSeq, 7); - } - s.writeBits(0, 4); // padding - }, - serializeFull(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - s.writeMapType(data.type); - s.writeBits(data.ori, 2); - s.writeBits(data.layer, 2); - } - }, - [ObjectType.Structure]: { - serializePart() { }, - serializeFull(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - s.writeMapType(data.type); - s.writeBits(data.ori, 2); - s.writeBoolean(data.interiorSoundEnabled); - s.writeBoolean(data.interiorSoundAlt); - for (let i = 0; i < GameConfig.structureLayerCount; i++) { - s.writeUint16(data.layerObjIds[i]); - } - } - }, - [ObjectType.Loot]: { - serializedFullSize: 5, - serializePart(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - }, - serializeFull(s, data) { - s.writeGameType(data.type); - s.writeUint8(data.count); - s.writeBits(data.layer, 2); - s.writeBoolean(data.isOld); - s.writeBoolean(data.isPreloadedGun); - s.writeBoolean(data.ownerId !== 0); - if (data.ownerId !== 0) { - s.writeUint16(data.ownerId); - } - s.readBits(1); - } - }, - [ObjectType.DeadBody]: { - serializePart(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - }, - serializeFull(s, data) { - s.writeUint8(data.layer); - s.writeUint16(data.playerId); - } - }, - [ObjectType.Decal]: { - serializePart() { }, - serializeFull(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - s.writeFloat(data.scale, NetConstants.MapObjectMinScale, NetConstants.MapObjectMaxScale, 8); - s.writeMapType(data.type); - s.writeBits(data.ori, 2); - s.writeBits(data.layer, 2); - s.writeUint8(data.goreKills); - } - }, - [ObjectType.Projectile]: { - serializePart(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - s.writeFloat(data.posZ, 0, GameConfig.projectile.maxHeight, 10); - s.writeUnitVec(data.dir, 7); - }, - serializeFull(s, data) { - s.writeGameType(data.type); - s.writeBits(data.layer, 2); - s.writeBits(0, 4); - } - }, - [ObjectType.Smoke]: { - serializePart(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - s.writeFloat(data.rad, 0, NetConstants.SmokeMaxRad, 8); - }, - serializeFull(s, data) { - s.writeBits(data.layer, 2); - s.writeBits(data.interior, 6); - } - }, - [ObjectType.Airdrop]: { - serializePart(s, data) { - s.writeFloat(data.fallT, 0, 1, 7); - s.writeBoolean(data.landed); - }, - serializeFull(s, data) { - s.writeVec(data.pos, 0, 0, 1024, 1024, 16); - } - }, - [ObjectType.Invalid]: { - serializePart() { }, - serializeFull() { } - }, - [ObjectType.LootSpawner]: { - serializePart() { }, - serializeFull() { } - } -}; diff --git a/server/src/net/perkModeRoleSelectMsg.ts b/server/src/net/perkModeRoleSelectMsg.ts deleted file mode 100644 index af9956b4..00000000 --- a/server/src/net/perkModeRoleSelectMsg.ts +++ /dev/null @@ -1,17 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class PerkModeSelectMsg extends Msg { - msgType = MsgType.PerkModeRoleSelect; - - role = ""; - - serialize(s: SurvivBitStream): void { - s.writeGameType(this.role); - s.writeBits(0, 6); - } - - deserialize(s: SurvivBitStream): void { - this.role = s.readGameType(); - s.readBits(6); - } -} diff --git a/server/src/net/pickupMsg.ts b/server/src/net/pickupMsg.ts deleted file mode 100644 index 88ebbe41..00000000 --- a/server/src/net/pickupMsg.ts +++ /dev/null @@ -1,32 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export enum PickupMsgType { - Full, - AlreadyOwned, - AlreadyEquipped, - BetterItemEquipped, - Success, - GunCannotFire -} - -export class PickupMsg extends Msg { - msgType = MsgType.Pickup; - - type = PickupMsgType.Full; - item = ""; - count = 0; - - serialize(s: SurvivBitStream): void { - s.writeUint8(this.type); - s.writeGameType(this.item); - s.writeUint8(this.count); - s.writeBits(0, 6); - } - - deserialize(s: SurvivBitStream): void { - this.type = s.readUint8(); - this.item = s.readGameType(); - this.count = s.readUint8(); - s.readBits(6); - } -} diff --git a/server/src/net/playerStatsMsg.ts b/server/src/net/playerStatsMsg.ts deleted file mode 100644 index 6354c0d4..00000000 --- a/server/src/net/playerStatsMsg.ts +++ /dev/null @@ -1,36 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class PlayerStatsMsg extends Msg { - override readonly msgType = MsgType.PlayerStats; - - playerId = 0; - playerStats = { - playerId: 0, - timeAlive: 0, - kills: 0, - dead: false, - damageDealt: 0, - damageTaken: 0 - }; - - override deserialize(s: SurvivBitStream) { - this.playerId = s.readUint16(); - this.playerStats = { - playerId: this.playerId, - timeAlive: s.readUint16(), - kills: s.readUint8(), - dead: !!s.readUint8(), - damageDealt: s.readUint16(), - damageTaken: s.readUint16() - }; - } - - override serialize(s: SurvivBitStream) { - s.writeUint16(this.playerId); - s.writeUint16(this.playerStats.timeAlive); - s.writeUint8(this.playerStats.kills); - s.writeUint8(+this.playerStats.dead); - s.writeUint16(this.playerStats.damageDealt); - s.writeUint16(this.playerStats.damageTaken); - } -} diff --git a/server/src/net/roleAnnouncementMsg.ts b/server/src/net/roleAnnouncementMsg.ts deleted file mode 100644 index 1e920566..00000000 --- a/server/src/net/roleAnnouncementMsg.ts +++ /dev/null @@ -1,29 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class RoleAnnouncementMsg extends Msg { - msgType = MsgType.RoleAnnouncement; - - playerId = 0; - killerId = 0; - role = ""; - assigned = false; - killed = false; - - serialize(s: SurvivBitStream): void { - s.writeUint16(this.playerId); - s.writeUint16(this.killerId); - s.writeGameType(this.role); - s.writeBoolean(this.assigned); - s.writeBoolean(this.killed); - s.writeAlignToNextByte(); - } - - deserialize(s: SurvivBitStream): void { - this.playerId = s.readUint16(); - this.killerId = s.readUint16(); - this.role = s.readGameType(); - this.assigned = s.readBoolean(); - this.killed = s.readBoolean(); - s.readAlignToNextByte(); - } -} diff --git a/server/src/net/serializationCache.ts b/server/src/net/serializationCache.ts deleted file mode 100644 index 2f757abe..00000000 --- a/server/src/net/serializationCache.ts +++ /dev/null @@ -1,124 +0,0 @@ -import { type Game } from "../game"; -import { SurvivBitStream } from "./net"; -import { ObjectSerializeFns } from "./objectSerialization"; - -const MAX_ID = 2 ** 16; - -// TODO: this doesn't work for now and is unused - -export class SerializationCache { - stream: SurvivBitStream; - buffer: Buffer; - - offsets = new Uint32Array(MAX_ID + 1); - partialOffsets = new Uint32Array(MAX_ID + 1); - lengths = new Uint32Array(MAX_ID + 1); - partialLengths = new Uint32Array(MAX_ID + 1); - - // object id to cache entry - idMap = new Uint32Array(MAX_ID); - - offset = 0; - idCount = 0; - head = 0; - - constructor() { - this.buffer = Buffer.alloc(2 ** 20); - this.stream = new SurvivBitStream(this.buffer); - } - - getOffset(id: number): number { - const i = this.idMap[id]; - if (i === undefined) { - throw new Error("Object not serialized"); - } - return this.offsets[i]!; - } - - getLength(id: number): number { - const i = this.idMap[id]; - if (i === 0) { - throw new Error("Object not serialized"); - } - return this.lengths[i]; - } - - getPartialOffset(id: number): number { - const i = this.idMap[id]; - if (i === undefined) { - throw new Error("Object not serialized"); - } - return this.partialOffsets[i]!; - } - - getPartialLength(id: number): number { - const i = this.idMap[id]; - if (i === 0) { - throw new Error("Object not serialized"); - } - return this.partialLengths[i]; - } - - update(game: Game): void { - this.stream.byteIndex = 0; - - for (const obj of game.partialObjs) { - if (game.fullObjs.has(obj)) { - game.partialObjs.delete(obj); - continue; - } - const objId = obj.id; - const objType = obj.__type; - const index = this.idMap[objId]; - if (index === 0) continue; - - this.stream.byteIndex = this.partialOffsets[index]; - this.stream.writeUint16(objId); - - // @ts-expect-error ... - ObjectSerializeFns[objType].serializePart(this.stream, obj); - } - - for (const obj of game.fullObjs) { - const objId = obj.id; - const objType = obj.__type; - const isNew = this.idMap[objId] === 0; - - if (isNew) { - ++this.idCount; - this.idMap[objId] = this.idCount; - this.offsets[this.idCount] = this.head; - } - - const index = this.idMap[objId]; - this.stream.byteIndex = this.offsets[index]; - this.stream.writeUint8(objType); - - if (isNew) { - this.partialOffsets[this.idCount] = this.stream.byteIndex; - } - - this.stream.writeUint16(objId); - - // @ts-expect-error ... - ObjectSerializeFns[objType].serializePart(this.stream, obj); - - const partialLength = this.stream.byteIndex - this.offsets[index]; - - // @ts-expect-error ... - ObjectSerializeFns[objType].serializeFull(this.stream, obj); - - const length = this.stream.byteIndex - this.offsets[index]; - - if (isNew) { - this.head = this.stream.byteIndex; - this.lengths[index] = length; - this.partialLengths[index] = partialLength; - } else { - if (length !== this.lengths[index] || partialLength !== this.partialLengths[index]) { - throw new Error(`Serialization Cache: Object ${objType} changed length`); - } - } - } - } -} diff --git a/server/src/net/spectateMsg.ts b/server/src/net/spectateMsg.ts deleted file mode 100644 index 70f5e2f2..00000000 --- a/server/src/net/spectateMsg.ts +++ /dev/null @@ -1,26 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class SpectateMsg extends Msg { - msgType = MsgType.Spectate; - - specBegin = false; - specNext = false; - specPrev = false; - specForce = false; - - serialize(s: SurvivBitStream): void { - s.writeBoolean(this.specBegin); - s.writeBoolean(this.specNext); - s.writeBoolean(this.specPrev); - s.writeBoolean(this.specForce); - s.writeBits(0, 4); - } - - deserialize(s: SurvivBitStream): void { - s.writeBoolean(this.specBegin); - s.writeBoolean(this.specNext); - s.writeBoolean(this.specPrev); - s.writeBoolean(this.specForce); - s.writeBits(0, 4); - } -} diff --git a/server/src/net/statsMsg.ts b/server/src/net/statsMsg.ts deleted file mode 100644 index 9c50a6c4..00000000 --- a/server/src/net/statsMsg.ts +++ /dev/null @@ -1,15 +0,0 @@ -import { Msg, MsgType, type SurvivBitStream } from "./net"; - -export class StatsMsg extends Msg { - msgType = MsgType.Stats; - - data = ""; - - serialize(s: SurvivBitStream): void { - s.writeString(this.data); - } - - deserialize(s: SurvivBitStream): void { - this.data = s.readString(); - } -} diff --git a/server/src/net/updateMsg.ts b/server/src/net/updateMsg.ts deleted file mode 100644 index d98e4e4b..00000000 --- a/server/src/net/updateMsg.ts +++ /dev/null @@ -1,487 +0,0 @@ -import { type Vec2 } from "../../../shared/utils/v2"; -import { Msg, MsgType, NetConstants, type SurvivBitStream } from "./net"; -import { ObjectSerializeFns, type ObjectsFullData, type ObjectsPartialData } from "./objectSerialization"; -import { type ObjectType } from "../objects/gameObject"; -import { GameConfig } from "../../../shared/gameConfig"; -import { type SerializationCache } from "./serializationCache"; - -export interface GasData { - mode: number - duration: number - posOld: Vec2 - posNew: Vec2 - radOld: number - radNew: number -} - -function serializeGasData(s: SurvivBitStream, data: GasData) { - s.writeUint8(data.mode); - s.writeFloat32(data.duration); - s.writeVec(data.posNew, 0, 0, 1024, 1024, 16); - s.writeVec(data.posNew, 0, 0, 1024, 1024, 16); - s.writeFloat(data.radOld, 0, 2048, 16); - s.writeFloat(data.radNew, 0, 2048, 16); -} - -export interface ActivePlayerData { - dirty: { - health: boolean - boost: boolean - zoom: boolean - action: boolean - inventory: boolean - weapons: boolean - spectatorCount: boolean - } - - health: number - boost: number - zoom: number - - action: { - time: number - duration: number - targetId: number - } - - scope: string - inventory: Record - - curWeapIdx: number - weapons: Array<{ - type: string - ammo: number - }> - - spectatorCount: number -} - -function serializeActivePlayerData(s: SurvivBitStream, data: ActivePlayerData) { - s.writeBoolean(data.dirty.health); - if (data.dirty.health) s.writeFloat(data.health, 0, 100, 8); - - s.writeBoolean(data.dirty.boost); - if (data.dirty.boost) s.writeFloat(data.boost, 0, 100, 8); - - s.writeBoolean(data.dirty.zoom); - if (data.dirty.zoom) s.writeUint8(data.zoom); - - s.writeBoolean(data.dirty.action); - if (data.dirty.action) { - s.writeFloat(data.action.time, 0, NetConstants.ActionMaxDuration, 8); - s.writeFloat(data.action.duration, 0, NetConstants.ActionMaxDuration, 8); - s.writeUint16(data.action.targetId); - } - - s.writeBoolean(data.dirty.inventory); - if (data.dirty.inventory) { - s.writeGameType(data.scope); - for (const key of Object.keys(GameConfig.bagSizes)) { - const hasItem = data.inventory[key] > 0; - s.writeBoolean(hasItem); - if (hasItem) s.writeBits(data.inventory[key], 9); - } - } - - s.writeBoolean(data.dirty.weapons); - if (data.dirty.weapons) { - s.writeBits(data.curWeapIdx, 2); - for (let i = 0; i < GameConfig.WeaponSlot.Count; i++) { - s.writeGameType(data.weapons[i].type); - s.writeUint8(data.weapons[i].ammo); - } - } - - s.writeBoolean(data.dirty.spectatorCount); - if (data.dirty.spectatorCount) { - s.writeUint8(data.spectatorCount); - } - - s.writeAlignToNextByte(); -} - -export interface PlayerInfo { - id: number - teamId: number - groupId: number - name: string - - loadout: { - heal: string - boost: string - } -} - -function serializePlayerInfo(s: SurvivBitStream, data: PlayerInfo) { - s.writeUint16(data.id); - s.writeUint8(data.teamId); - s.writeUint8(data.groupId); - s.writeString(data.name); - - s.writeGameType(data.loadout.heal); - s.writeGameType(data.loadout.boost); - - s.writeAlignToNextByte(); -} - -export interface PlayerStatus { - hasData: boolean - pos: Vec2 - visible: boolean - dead: boolean - downed: boolean - role: string -} - -function serializePlayerStatus(s: SurvivBitStream, data: PlayerStatus[]) { - s.writeUint8(data.length); - for (const info of data) { - s.writeBoolean(info.hasData); - - if (info.hasData) { - s.writeVec(info.pos, 0, 0, 1024, 1024, 11); - s.writeBoolean(info.visible); - s.writeBoolean(info.dead); - s.writeBoolean(info.downed); - - s.writeBoolean(info.role !== ""); - if (info.role !== "") { - s.writeGameType(info.role); - } - } - } -} - -export interface GroupStatus { - health: number - disconnected: boolean -} - -function serializeGroupStatus(s: SurvivBitStream, data: GroupStatus[]) { - s.writeUint8(data.length); - - for (const status of data) { - s.writeFloat(status.health, 0, 100, 7); - s.writeBoolean(status.disconnected); - } -} - -export interface BulletData { - playerId: number - startPos: Vec2 - dir: Vec2 - bulletType: string - layer: number - varianceT: number - distAdjIdx: number - clipDistance: boolean - distance: number - shotFx: boolean - sourceType: string - shotOffhand: boolean - lastShot: boolean - reflectCount: number - reflectObjId: number - - hasSpecialFx: boolean - shotAlt: boolean - splinter: boolean - trailSaturated: boolean - trailSmall: boolean - trailThick: boolean -} - -export interface ExplosionData { - pos: Vec2 - type: string - layer: number -} - -export interface EmoteData { - playerId: number - type: string - itemType: string - isPing: boolean - pos: Vec2 -} - -export interface PlaneData { - id: number - pos: Vec2 - dir: Vec2 - actionComplete: boolean - action: number -} - -export interface AirStrikeZoneData { - pos: Vec2 - rad: number - duration: number -} - -export interface MapIndicatorData { - id: number - dead: boolean - equipped: boolean - type: string - pos: Vec2 -} - -const UpdateExtFlags = { - DeletedObjects: 1 << 0, - FullObjects: 1 << 1, - ActivePlayerId: 1 << 2, - Gas: 1 << 3, - GasCircle: 1 << 4, - PlayerInfos: 1 << 5, - DeletePlayerIds: 1 << 6, - PlayerStatus: 1 << 7, - GroupStatus: 1 << 8, - Bullets: 1 << 9, - Explosions: 1 << 10, - Emotes: 1 << 11, - Planes: 1 << 12, - AirstrikeZones: 1 << 13, - MapIndicators: 1 << 14, - KillLeader: 1 << 15 -}; - -export class UpdateMsg extends Msg { - override readonly msgType = MsgType.Update; - allocBytes = 1 << 16; - - serializationCache!: SerializationCache; - - delObjIds: number[] = []; - fullObjects: Array< - ObjectsFullData[ObjectType] & ObjectsPartialData[ObjectType] & { - id: number - __type: ObjectType - }> = []; - - partObjects: Array = []; - - activePlayerId = 0; - activePlayerIdDirty = false; - activePlayerData!: ActivePlayerData; - - aliveCounts = []; - aliveDirty = false; - - gas!: GasData; - gasDirty = false; - gasT = 0; - gasTDirty = false; - - playerInfos: PlayerInfo[] = []; - deletedPlayerIds: number[] = []; - - playerStatus: PlayerStatus[] = []; - playerStatusDirty = false; - - groupStatus: GroupStatus[] = []; - groupStatusDirty = false; - - bullets: BulletData[] = []; - explosions: ExplosionData[] = []; - emotes: EmoteData[] = []; - planes: PlaneData[] = []; - airstrikeZones: AirStrikeZoneData[] = []; - mapIndicators: MapIndicatorData[] = []; - - killLeaderId = 0; - killLeaderKills = 0; - killLeaderDirty = false; - ack = 0; - - serialize(s: SurvivBitStream): void { - let flags = 0; - if (this.delObjIds.length) flags += UpdateExtFlags.DeletedObjects; - if (this.fullObjects.length) flags += UpdateExtFlags.FullObjects; - if (this.activePlayerIdDirty) flags += UpdateExtFlags.ActivePlayerId; - if (this.gasDirty) flags += UpdateExtFlags.Gas; - if (this.gasTDirty) flags += UpdateExtFlags.GasCircle; - if (this.playerInfos.length) flags += UpdateExtFlags.PlayerInfos; - if (this.deletedPlayerIds.length) flags += UpdateExtFlags.DeletePlayerIds; - if (this.playerStatusDirty) flags += UpdateExtFlags.PlayerStatus; - if (this.groupStatusDirty) flags += UpdateExtFlags.GroupStatus; - if (this.bullets.length) flags += UpdateExtFlags.Bullets; - if (this.explosions.length) flags += UpdateExtFlags.Explosions; - if (this.emotes.length) flags += UpdateExtFlags.Emotes; - if (this.planes.length) flags += UpdateExtFlags.Planes; - if (this.airstrikeZones.length) flags += UpdateExtFlags.AirstrikeZones; - if (this.mapIndicators.length) flags += UpdateExtFlags.MapIndicators; - if (this.killLeaderDirty) flags += UpdateExtFlags.KillLeader; - - s.writeUint16(flags); - - if ((flags & UpdateExtFlags.DeletedObjects) !== 0) { - s.writeUint16(this.delObjIds.length); - for (const id of this.delObjIds) { - s.writeUint16(id); - } - } - - if ((flags & UpdateExtFlags.FullObjects) !== 0) { - s.writeUint16(this.fullObjects.length); - for (const obj of this.fullObjects) { - s.writeUint8(obj.__type); - s.writeUint16(obj.id); - // @ts-expect-error ... - ObjectSerializeFns[obj.__type].serializePart(s, obj); - // @ts-expect-error ... - ObjectSerializeFns[obj.__type].serializeFull(s, obj); - } - } - - s.writeUint16(this.partObjects.length); - for (const obj of this.partObjects) { - s.writeUint16(obj.id); - // @ts-expect-error ... - ObjectSerializeFns[obj.__type].serializePart(s, obj); - } - - if ((flags & UpdateExtFlags.ActivePlayerId) !== 0) { - s.writeUint16(this.activePlayerId); - } - - serializeActivePlayerData(s, this.activePlayerData); - - if ((flags & UpdateExtFlags.Gas) !== 0) { - serializeGasData(s, this.gas); - } - - if ((flags & UpdateExtFlags.GasCircle) !== 0) { - s.writeFloat(this.gasT, 0, 1, 16); - } - - if ((flags & UpdateExtFlags.PlayerInfos) !== 0) { - s.writeUint8(this.playerInfos.length); - for (const info of this.playerInfos) { - serializePlayerInfo(s, info); - } - } - - if ((flags & UpdateExtFlags.DeletePlayerIds) !== 0) { - s.writeUint8(this.deletedPlayerIds.length); - for (const id of this.deletedPlayerIds) { - s.writeUint16(id); - } - } - - if ((flags & UpdateExtFlags.PlayerInfos) !== 0) { - serializePlayerStatus(s, this.playerStatus); - } - - if ((flags & UpdateExtFlags.GroupStatus) !== 0) { - serializeGroupStatus(s, this.groupStatus); - } - - if ((flags & UpdateExtFlags.Bullets) !== 0) { - s.writeUint8(this.bullets.length); - - for (const bullet of this.bullets) { - s.writeUint16(bullet.playerId); - s.writeVec(bullet.startPos, 0, 0, 1024, 1024, 16); - s.writeUnitVec(bullet.dir, 8); - s.writeGameType(bullet.bulletType); - s.writeBits(bullet.layer, 2); - s.writeFloat(bullet.varianceT, 0, 1, 4); - s.writeBits(bullet.distAdjIdx, 4); - s.writeBoolean(bullet.clipDistance); - if (bullet.clipDistance) { - s.writeFloat(bullet.distance, 0, 1024, 16); - } - s.writeBoolean(bullet.shotFx); - if (bullet.shotFx) { - s.writeGameType(bullet.sourceType); - s.writeBoolean(bullet.shotOffhand); - s.writeBoolean(bullet.lastShot); - } - s.writeBoolean(bullet.reflectCount > 0); - if (bullet.reflectCount > 0) { - s.writeBits(bullet.reflectCount, 2); - s.writeUint16(bullet.reflectObjId); - } - - s.writeBoolean(bullet.hasSpecialFx); - - if (bullet.hasSpecialFx) { - s.writeBoolean(bullet.shotAlt); - s.writeBoolean(bullet.splinter); - s.writeBoolean(bullet.trailSaturated); - s.writeBoolean(bullet.trailSmall); - s.writeBoolean(bullet.trailThick); - } - } - - s.writeAlignToNextByte(); - } - - if ((flags & UpdateExtFlags.Explosions) !== 0) { - s.writeUint8(this.explosions.length); - for (const explosion of this.explosions) { - s.writeVec(explosion.pos, 0, 0, 1024, 1024, 16); - s.writeGameType(explosion.type); - s.writeBits(explosion.layer, 2); - s.writeAlignToNextByte(); - } - } - - if ((flags & UpdateExtFlags.Emotes) !== 0) { - s.writeUint8(this.emotes.length); - for (const emote of this.emotes) { - s.writeUint16(emote.playerId); - s.writeGameType(emote.type); - s.writeBoolean(emote.isPing); - s.writeGameType(emote.itemType); - if (emote.isPing) s.writeVec(emote.pos, 0, 0, 1024, 1024, 16); - s.writeAlignToNextByte(); - } - } - - if ((flags & UpdateExtFlags.Planes) !== 0) { - s.writeUint8(this.planes.length); - for (const plane of this.planes) { - s.writeUint8(plane.id); - s.writeVec(plane.pos, 0, 0, 2048, 2048, 10); - s.writeUnitVec(plane.dir, 8); - s.writeBoolean(plane.actionComplete); - s.writeBits(plane.action, 3); - } - } - - if ((flags & UpdateExtFlags.AirstrikeZones) !== 0) { - s.writeUint8(this.airstrikeZones.length); - for (const zone of this.airstrikeZones) { - s.writeVec(zone.pos, 0, 0, 1024, 1024, 12); - s.writeFloat(zone.rad, 0, NetConstants.AirstrikeZoneMaxRad, 8); - s.writeFloat(zone.duration, 0, NetConstants.AirstrikeZoneMaxDuration, 8); - } - } - - if ((flags & UpdateExtFlags.MapIndicators) !== 0) { - s.writeUint8(this.mapIndicators.length); - for (const indicator of this.mapIndicators) { - s.writeBits(indicator.id, 4); - s.writeBoolean(indicator.dead); - s.writeBoolean(indicator.equipped); - s.writeGameType(indicator.type); - s.writeVec(indicator.pos, 0, 0, 1024, 1024, 16); - } - s.writeAlignToNextByte(); - } - - if ((flags & UpdateExtFlags.KillLeader) !== 0) { - s.writeUint16(this.killLeaderId); - s.writeUint8(this.killLeaderKills); - } - - s.writeUint8(this.ack); - } - - deserialize(): void { } -} diff --git a/server/src/objects/DeadBody.ts b/server/src/objects/DeadBody.ts index 4616fff8..1c8d1079 100644 --- a/server/src/objects/DeadBody.ts +++ b/server/src/objects/DeadBody.ts @@ -1,13 +1,9 @@ import { type Game } from "../game"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { collider } from "../../../shared/utils/collider"; import { v2, type Vec2 } from "../../../shared/utils/v2"; import { BaseGameObject, ObjectType } from "./gameObject"; -type FullDeadBody = ObjectsFullData[ObjectType.DeadBody]; -type PartialDeadBody = ObjectsPartialData[ObjectType.DeadBody]; - -export class DeadBody extends BaseGameObject implements FullDeadBody, PartialDeadBody { +export class DeadBody extends BaseGameObject { bounds = collider.createCircle(v2.create(0, 0), 2); override readonly __type = ObjectType.DeadBody; diff --git a/server/src/objects/airdrop.ts b/server/src/objects/airdrop.ts index b0937cb1..3b27e2b5 100644 --- a/server/src/objects/airdrop.ts +++ b/server/src/objects/airdrop.ts @@ -1,13 +1,9 @@ import { type Game } from "../game"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { collider } from "../../../shared/utils/collider"; import { v2, type Vec2 } from "../../../shared/utils/v2"; import { BaseGameObject, ObjectType } from "./gameObject"; -type FullAirdrop = ObjectsFullData[ObjectType.Airdrop]; -type PartialAirdrop = ObjectsPartialData[ObjectType.Airdrop]; - -export class Airdrop extends BaseGameObject implements FullAirdrop, PartialAirdrop { +export class Airdrop extends BaseGameObject { bounds = collider.createAabbExtents(v2.create(0, 0), v2.create(5, 5)); override readonly __type = ObjectType.Airdrop; diff --git a/server/src/objects/building.ts b/server/src/objects/building.ts index 8256582e..53c05b18 100644 --- a/server/src/objects/building.ts +++ b/server/src/objects/building.ts @@ -2,7 +2,6 @@ import { MapObjectDefs } from "../../../shared/defs/mapObjectDefs"; import { type StructureDef, type BuildingDef } from "../../../shared/defs/mapObjectsTyping"; import { Puzzles } from "../../../shared/defs/puzzles"; import { type Game } from "../game"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { type Collider } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { mapHelpers } from "../../../shared/utils/mapHelpers"; @@ -13,10 +12,7 @@ import { BaseGameObject, ObjectType } from "./gameObject"; import { Obstacle } from "./obstacle"; import { type Structure } from "./structure"; -type FullBuilding = ObjectsFullData[ObjectType.Building]; -type PartialBuilding = ObjectsPartialData[ObjectType.Building]; - -export class Building extends BaseGameObject implements FullBuilding, PartialBuilding { +export class Building extends BaseGameObject { bounds: Collider; mapObstacleBounds: Collider[] = []; diff --git a/server/src/objects/bullet.ts b/server/src/objects/bullet.ts index 8ec12d55..882ba852 100644 --- a/server/src/objects/bullet.ts +++ b/server/src/objects/bullet.ts @@ -4,7 +4,6 @@ import { type ObstacleDef } from "../../../shared/defs/mapObjectsTyping"; import { type GunDef, type BulletDef } from "../../../shared/defs/objectsTypings"; import { type Game } from "../game"; import { GameConfig } from "../../../shared/gameConfig"; -import { type BulletData } from "../net/updateMsg"; import { coldet } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { math } from "../../../shared/utils/math"; @@ -112,7 +111,7 @@ export class BulletManager { } } -export class Bullet implements BulletData { +export class Bullet { collided = false; alive = true; distanceTraveled = 0; diff --git a/server/src/objects/decal.ts b/server/src/objects/decal.ts index 2959c5fe..a63c7377 100644 --- a/server/src/objects/decal.ts +++ b/server/src/objects/decal.ts @@ -1,7 +1,6 @@ import { MapObjectDefs } from "../../../shared/defs/mapObjectDefs"; import { type DecalDef } from "../../../shared/defs/mapObjectsTyping"; import { type Game } from "../game"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { type Circle, type Collider } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { mapHelpers } from "../../../shared/utils/mapHelpers"; @@ -9,10 +8,7 @@ import { math } from "../../../shared/utils/math"; import { v2, type Vec2 } from "../../../shared/utils/v2"; import { BaseGameObject, ObjectType } from "./gameObject"; -type FullDecal = ObjectsFullData[ObjectType.Decal]; -type PartialDecal = ObjectsPartialData[ObjectType.Decal]; - -export class Decal extends BaseGameObject implements FullDecal, PartialDecal { +export class Decal extends BaseGameObject { bounds: Collider; override readonly __type = ObjectType.Decal; diff --git a/server/src/objects/loot.ts b/server/src/objects/loot.ts index 20533793..64e4880e 100644 --- a/server/src/objects/loot.ts +++ b/server/src/objects/loot.ts @@ -2,7 +2,6 @@ import { GameObjectDefs } from "../../../shared/defs/gameObjectDefs"; import { MapDefs } from "../../../shared/defs/mapDefs"; import { type Game } from "../game"; import { GameConfig } from "../../../shared/gameConfig"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { type Circle, coldet } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { util } from "../../../shared/utils/util"; @@ -11,10 +10,7 @@ import { BaseGameObject, ObjectType } from "./gameObject"; import { Obstacle } from "./obstacle"; import { Structure } from "./structure"; -type FullLoot = ObjectsFullData[ObjectType.Loot]; -type PartialLoot = ObjectsPartialData[ObjectType.Loot]; - -export class Loot extends BaseGameObject implements FullLoot, PartialLoot { +export class Loot extends BaseGameObject { bounds = collider.createCircle(v2.create(0.0, 0.0), 3.0); override readonly __type = ObjectType.Loot; diff --git a/server/src/objects/obstacle.ts b/server/src/objects/obstacle.ts index 81eb1536..d226860a 100644 --- a/server/src/objects/obstacle.ts +++ b/server/src/objects/obstacle.ts @@ -2,8 +2,6 @@ import { GameObjectDefs } from "../../../shared/defs/gameObjectDefs"; import { MapObjectDefs } from "../../../shared/defs/mapObjectDefs"; import { type ObstacleDef } from "../../../shared/defs/mapObjectsTyping"; import { type Game } from "../game"; -import { NetConstants } from "../net/net"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { coldet, type Collider } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { mapHelpers } from "../../../shared/utils/mapHelpers"; @@ -14,11 +12,9 @@ import { type Building } from "./building"; import { BaseGameObject, ObjectType } from "./gameObject"; import { getLootTable } from "./loot"; import { type Player } from "./player"; +import net from "../../../shared/net"; -type FullObstacle = ObjectsFullData[ObjectType.Obstacle]; -type PartialObstacle = ObjectsPartialData[ObjectType.Obstacle]; - -export class Obstacle extends BaseGameObject implements FullObstacle, PartialObstacle { +export class Obstacle extends BaseGameObject { override readonly __type = ObjectType.Obstacle; bounds: Collider; @@ -114,7 +110,7 @@ export class Obstacle extends BaseGameObject implements FullObstacle, PartialObs mapHelpers.getBoundingCollider(type), v2.create(0, 0), this.rot, - NetConstants.MapObjectMaxScale + net.Constants.MapObjectMaxScale ); if (def === undefined || def.type !== "obstacle") { diff --git a/server/src/objects/player.ts b/server/src/objects/player.ts index 01303f57..1747c4c8 100644 --- a/server/src/objects/player.ts +++ b/server/src/objects/player.ts @@ -1,33 +1,23 @@ import { type WebSocket } from "uWebSockets.js"; import { type Game } from "../game"; import { GameConfig } from "../../../shared/gameConfig"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; -import { type PlayerInfo, type ActivePlayerData, UpdateMsg } from "../net/updateMsg"; import { collider } from "../../../shared/utils/collider"; import { type Vec2, v2 } from "../../../shared/utils/v2"; import { BaseGameObject, type GameObject, ObjectType } from "./gameObject"; import { type PlayerContainer } from "../server"; -import { type Msg, MsgStream } from "../net/net"; import { coldet } from "../../../shared/utils/coldet"; -import { InputMsg } from "../net/inputMsg"; -import { JoinedMsg } from "../net/joinedMsg"; import { util } from "../../../shared/utils/util"; import { GameObjectDefs } from "../../../shared/defs/gameObjectDefs"; import { Obstacle } from "./obstacle"; import { WeaponManager } from "../utils/weaponManager"; -import { AliveCountMsg } from "../net/aliveCountMsg"; import { math } from "../../../shared/utils/math"; -import { GameOverMsg } from "../net/gameOverMsg"; -import { KillMsg } from "../net/KillMsg"; import { DeadBody } from "./DeadBody"; import { type OutfitDef, type GunDef, type MeleeDef, type ThrowableDef, type HelmetDef, type ChestDef, type BackpackDef } from "../../../shared/defs/objectsTypings"; import { MeleeDefs } from "../../../shared/defs/gameObjects/meleeDefs"; import { Structure } from "./structure"; +import net, { type InputMsg } from "../../../shared/net"; -type PlayerFullData = ObjectsFullData[ObjectType.Player]; -type PlayerPartialData = ObjectsPartialData[ObjectType.Player]; - -export class Player extends BaseGameObject implements PlayerFullData, PlayerPartialData, ActivePlayerData, PlayerInfo { +export class Player extends BaseGameObject { override readonly __type = ObjectType.Player; bounds = collider.toAabb(collider.createCircle(v2.create(0, 0), GameConfig.player.maxVisualRadius)); @@ -224,7 +214,7 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart socket: WebSocket; - msgsToSend: Msg[] = []; + msgsToSend: Array<{ type: number, msg: any }> = []; weaponManager = new WeaponManager(this); recoilTicker = 0; @@ -251,7 +241,7 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart visibleObjects = new Set(); - lastInputMsg = new InputMsg(); + lastInputMsg = new net.InputMsg(); update(): void { if (this.dead) return; @@ -369,27 +359,27 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart private _firstUpdate = true; sendMsgs(): void { - const msgStream = new MsgStream(new ArrayBuffer(65536)); + const msgStream = new net.MsgStream(new ArrayBuffer(65536)); if (this._firstUpdate) { - const joinedMsg = new JoinedMsg(); + const joinedMsg = new net.JoinedMsg(); joinedMsg.teamMode = 1; joinedMsg.playerId = this.id; joinedMsg.emotes = this.loadout.emotes; - this.sendMsg(joinedMsg); + this.sendMsg(net.Msg.Joined, joinedMsg); const mapStream = this.game.map.mapStream.stream; - msgStream.stream.writeBytes(mapStream, 0, mapStream.byteIndex); + msgStream.stream!.writeBytes(mapStream, 0, mapStream!.byteIndex); } if (this.game.aliveCountDirty) { - const aliveMsg = new AliveCountMsg(); - aliveMsg.aliveCounts.push(this.game.aliveCount); - msgStream.serializeMsg(aliveMsg); + const aliveMsg = new net.AliveCountsMsg(); + aliveMsg.teamAliveCounts.push(this.game.aliveCount); + msgStream.serializeMsg(net.Msg.AliveCounts, aliveMsg); } - const updateMsg = new UpdateMsg(); + const updateMsg = new net.UpdateMsg(); // updateMsg.serializationCache = this.game.serializationCache; const radius = this.zoom + 4; @@ -450,16 +440,16 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart updateMsg.bullets = newBullets; updateMsg.explosions = this.game.explosions; - msgStream.serializeMsg(updateMsg); + msgStream.serializeMsg(net.Msg.Update, updateMsg); for (const msg of this.msgsToSend) { - msgStream.serializeMsg(msg); + msgStream.serializeMsg(msg.type, msg.msg); } this.msgsToSend.length = 0; for (const msg of this.game.msgsToSend) { - msgStream.serializeMsg(msg); + msgStream.serializeMsg(msg.type, msg); } this.sendData(msgStream.getBuffer()); @@ -505,7 +495,7 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart this.game.aliveCountDirty = true; this.game.livingPlayers.delete(this); - const killMsg = new KillMsg(); + const killMsg = new net.KillMsg(); killMsg.damageType = damageType; killMsg.itemSourceType = sourceType; killMsg.targetId = this.id; @@ -518,9 +508,9 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart killMsg.killerKills = source.kills; } - this.game.msgsToSend.push(killMsg); + this.game.msgsToSend.push({ type: net.Msg.Kill, msg: killMsg }); - const gameOverMsg = new GameOverMsg(); + const gameOverMsg = new net.GameOverMsg(); gameOverMsg.teamRank = this.game.aliveCount; gameOverMsg.playerStats = [{ @@ -529,7 +519,7 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart }]; gameOverMsg.teamId = this.teamId; gameOverMsg.winningTeamId = -1; - this.msgsToSend.push(gameOverMsg); + this.msgsToSend.push({ type: net.Msg.GameOver, msg: gameOverMsg }); const deadBody = new DeadBody(this.game, this.pos, this.id, this.layer); this.game.grid.addObject(deadBody); @@ -631,9 +621,9 @@ export class Player extends BaseGameObject implements PlayerFullData, PlayerPart } - sendMsg(msg: Msg, bytes = 128): void { - const stream = new MsgStream(new ArrayBuffer(bytes)); - stream.serializeMsg(msg); + sendMsg(type: number, msg: any, bytes = 128): void { + const stream = new net.MsgStream(new ArrayBuffer(bytes)); + stream.serializeMsg(type, msg); this.sendData(stream.getBuffer()); } diff --git a/server/src/objects/projectile.ts b/server/src/objects/projectile.ts index 7bcb52ce..cf40b967 100644 --- a/server/src/objects/projectile.ts +++ b/server/src/objects/projectile.ts @@ -1,16 +1,12 @@ import { GameObjectDefs } from "../../../shared/defs/gameObjectDefs"; import { type ThrowableDef } from "../../../shared/defs/objectsTypings"; import { type Game } from "../game"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { type Collider } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { v2, type Vec2 } from "../../../shared/utils/v2"; import { BaseGameObject, ObjectType } from "./gameObject"; -type FullProjectile = ObjectsFullData[ObjectType.Projectile]; -type PartialProjectile = ObjectsPartialData[ObjectType.Projectile]; - -export class Projectile extends BaseGameObject implements FullProjectile, PartialProjectile { +export class Projectile extends BaseGameObject { bounds: Collider; override readonly __type = ObjectType.Projectile; diff --git a/server/src/objects/smoke.ts b/server/src/objects/smoke.ts index f8a62cea..dfff0ca1 100644 --- a/server/src/objects/smoke.ts +++ b/server/src/objects/smoke.ts @@ -1,13 +1,9 @@ import { type Game } from "../game"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { collider } from "../../../shared/utils/collider"; import { v2, type Vec2 } from "../../../shared/utils/v2"; import { BaseGameObject, ObjectType } from "./gameObject"; -type FullSmoke = ObjectsFullData[ObjectType.Smoke]; -type PartialSmoke = ObjectsPartialData[ObjectType.Smoke]; - -export class Smoke extends BaseGameObject implements FullSmoke, PartialSmoke { +export class Smoke extends BaseGameObject { bounds = collider.createCircle(v2.create(0, 0), 0); override readonly __type = ObjectType.Smoke; diff --git a/server/src/objects/structure.ts b/server/src/objects/structure.ts index d3435d7f..4cc5b9ec 100644 --- a/server/src/objects/structure.ts +++ b/server/src/objects/structure.ts @@ -1,7 +1,6 @@ import { MapObjectDefs } from "../../../shared/defs/mapObjectDefs"; import { type StructureDef } from "../../../shared/defs/mapObjectsTyping"; import { type Game } from "../game"; -import { type ObjectsFullData, type ObjectsPartialData } from "../net/objectSerialization"; import { type AABB, type Circle, coldet, type Collider } from "../../../shared/utils/coldet"; import { collider } from "../../../shared/utils/collider"; import { mapHelpers } from "../../../shared/utils/mapHelpers"; @@ -9,9 +8,6 @@ import { math } from "../../../shared/utils/math"; import { v2, type Vec2 } from "../../../shared/utils/v2"; import { BaseGameObject, ObjectType } from "./gameObject"; -type FullStructure = ObjectsFullData[ObjectType.Structure]; -type PartialStructure = ObjectsPartialData[ObjectType.Structure]; - interface Stair { collision: AABB center: Vec2 @@ -24,7 +20,7 @@ interface Stair { lootOnly: boolean } -export class Structure extends BaseGameObject implements FullStructure, PartialStructure { +export class Structure extends BaseGameObject { bounds: Collider; override readonly __type = ObjectType.Structure; diff --git a/shared/net.js b/shared/net.js index 638c2fc8..b00bbe48 100644 --- a/shared/net.js +++ b/shared/net.js @@ -6,6 +6,45 @@ import { math } from "./utils/math"; import { GameConfig } from "./gameConfig"; import GameObject from "./utils/gameObject"; +const DEV_MODE = false; + +// +// Map type strings to integers for more efficient serialization. +// + +class ConfigTypeMap { + constructor(typeBits) { + this._typeToId = {}; + this._idToType = {}; + this.nextId = 0; + this.maxId = 2 ** typeBits; + + this.addType(""); + } + + addType(type) { + // assert(this._typeToId[type] === undefined, `Type ${type} has already been defined!`); + // assert(this.nextId < this.maxId); + this._typeToId[type] = this.nextId; + this._idToType[this.nextId] = type; + this.nextId++; + } + + typeToId(type) { + const id = this._typeToId[type]; + // assert(id !== undefined, `Invalid type ${type}`); + return id; + } + + idToType(id) { + const type = this._idToType[id]; + if (type === undefined) { + console.error("Invalid id given to idToType", id, "max", Object.keys(this._idToType).length); + } + return type; + } +} + function createTypeSerialization(type, typeList, bitsPerType) { const typeMap = new ConfigTypeMap(bitsPerType); @@ -20,277 +59,108 @@ function createTypeSerialization(type, typeList, bitsPerType) { } // Create serialization functions - bb.BitStream.prototype[`write${type}Type`] = function(v) { + /* bb.BitStream.prototype[`write${type}Type`] = function(v) { this.writeBits(typeMap.typeToId(v), bitsPerType); }; bb.BitStream.prototype[`read${type}Type`] = function() { return typeMap.idToType(this.readBits(bitsPerType)); - }; + }; */ return typeMap; } -function getPlayerStatusUpdateRate(factionMode) { - if (factionMode) { - return 0.5; - } else { - return 0.25; - } -} +const gameTypeSerialization = createTypeSerialization("Game", GameObjectDefs, 10); +const mapTypeSerialization = createTypeSerialization("Map", MapObjectDefs, 12); -function deserializeActivePlayer(e, t) { - t.healthDirty = e.readBoolean(); - if (t.healthDirty) { - t.health = e.readFloat(0, 100, 8); - } - t.boostDirty = e.readBoolean(); - if (t.boostDirty) { - t.boost = e.readFloat(0, 100, 8); - } - t.zoomDirty = e.readBoolean(); - if (t.zoomDirty) { - t.zoom = e.readUint8(); - } - t.actionDirty = e.readBoolean(); - if (t.actionDirty) { - t.action = {}; - t.action.time = e.readFloat(0, Constants.ActionMaxDuration, 8); - t.action.duration = e.readFloat(0, Constants.ActionMaxDuration, 8); - t.action.targetId = e.readUint16(); - } - t.inventoryDirty = e.readBoolean(); - if (t.inventoryDirty) { - t.scope = e.readGameType(); - t.inventory = {}; - for ( - let r = Object.keys(GameConfig.bagSizes), a = 0; - a < r.length; - a++ - ) { - const i = r[a]; - let o = 0; - if (e.readBoolean()) { - o = e.readBits(9); - } - t.inventory[i] = o; - } - } - t.weapsDirty = e.readBoolean(); - if (t.weapsDirty) { - t.curWeapIdx = e.readBits(2); - t.weapons = []; - for (let s = 0; s < GameConfig.WeaponSlot.Count; s++) { - const n = {}; - n.type = e.readGameType(); - n.ammo = e.readUint8(); - t.weapons.push(n); - } - } - t.spectatorCountDirty = e.readBoolean(); - if (t.spectatorCountDirty) { - t.spectatorCount = e.readUint8(); - } - e.readAlignToNextByte(); -} +class BitStream extends bb.BitStream { + writeString(str, len) { this.writeASCIIString(str, len); } + readString(len) { return this.readASCIIString(len); } -function deserializePlayerStatus(e, t) { - t.players = []; - for (let r = e.readUint8(), a = 0; a < r; a++) { - const i = {}; - i.hasData = e.readBoolean(); - if (i.hasData) { - i.pos = e.readVec(0, 0, 1024, 1024, 11); - i.visible = e.readBoolean(); - i.dead = e.readBoolean(); - i.downed = e.readBoolean(); - i.role = ""; - if (e.readBoolean()) { - i.role = e.readGameType(); - } - } - t.players.push(i); + writeFloat(f, min, max, bits) { + // assert(bits > 0 && bits < 31); + // assert(f >= min && f <= max); + const range = (1 << bits) - 1; + const x = math.clamp(f, min, max); + const t = (x - min) / (max - min); + const v = t * range + 0.5; + this.writeBits(v, bits); } - e.readAlignToNextByte(); -} -function deserializeGroupStatus(e, t) { - t.players = []; - for (let r = e.readUint8(), a = 0; a < r; a++) { - const i = {}; - i.health = e.readFloat(0, 100, 7); - i.disconnected = e.readBoolean(); - t.players.push(i); + readFloat(min, max, bits) { + // assert(bits > 0 && bits < 31); + const range = (1 << bits) - 1; + const x = this.readBits(bits); + const t = x / range; + const v = min + t * (max - min); + return v; } -} - -function deserializePlayerInfos(e, t) { - t.playerId = e.readUint16(); - t.teamId = e.readUint8(); - t.groupId = e.readUint8(); - t.name = e.readString(); - t.loadout = {}; - t.loadout.heal = e.readGameType(); - t.loadout.boost = e.readGameType(); - e.readAlignToNextByte(); -} - -function deserializeGasData(s, data) { - data.mode = s.readUint8(); - data.duration = s.readFloat32(); - data.posOld = s.readVec(0, 0, 1024, 1024, 16); - data.posNew = s.readVec(0, 0, 1024, 1024, 16); - data.radOld = s.readFloat(0, 2048, 16); - data.radNew = s.readFloat(0, 2048, 16); -} -function deserializeMapRiver(e, t) { - t.width = e.readFloat32(); - t.looped = e.readUint8(); - t.points = []; - for (let r = e.readUint8(), a = 0; a < r; a++) { - const i = e.readVec(0, 0, 1024, 1024, 16); - t.points.push(i); + writeVec(vec, minX, minY, maxX, maxY, bitCount) { + this.writeFloat(vec.x, minX, maxX, bitCount); + this.writeFloat(vec.y, minY, maxY, bitCount); } -} -function deserializeMapPlaces(e, t) { - t.name = e.readString(); - t.pos = e.readVec(0, 0, 1024, 1024, 16); -} - -function deserializeMapGroundPatch(e, t) { - t.min = e.readVec(0, 0, 1024, 1024, 16); - t.max = e.readVec(0, 0, 1024, 1024, 16); - t.color = e.readUint32(); - t.roughness = e.readFloat32(); - t.offsetDist = e.readFloat32(); - t.order = e.readBits(7); - t.useAsMapShape = e.readBoolean(); -} - -function deserializeMapObj(e, t) { - t.pos = e.readVec(0, 0, 1024, 1024, 16); - t.scale = e.readFloat( - Constants.MapObjectMinScale, - Constants.MapObjectMaxScale, - 8 - ); - t.type = e.readMapType(); - t.ori = e.readBits(2); - e.readBits(2); -} - -const DEV_MODE = false; -bb.BitStream.prototype.writeBytes = function(src, offset, length) { - // assert(this._index % 8 == 0); - const data = new Uint8Array(src._view._view.buffer, offset, length); - this._view._view.set(data, this._index / 8); - this._index += length * 8; -}; - -bb.BitStream.prototype.writeString = bb.BitStream.prototype.writeASCIIString; -bb.BitStream.prototype.readString = bb.BitStream.prototype.readASCIIString; - -bb.BitStream.prototype.writeFloat = function(f, min, max, bits) { - // assert(bits > 0 && bits < 31); - // assert(f >= min && f <= max); - const range = (1 << bits) - 1; - const x = math.clamp(f, min, max); - const t = (x - min) / (max - min); - const v = t * range + 0.5; - this.writeBits(v, bits); -}; - -bb.BitStream.prototype.readFloat = function(min, max, bits) { - // assert(bits > 0 && bits < 31); - const range = (1 << bits) - 1; - const x = this.readBits(bits); - const t = x / range; - const v = min + t * (max - min); - return v; -}; - -bb.BitStream.prototype.writeVec = function(v, minX, minY, maxX, maxY, bits) { - this.writeFloat(v.x, minX, maxX, bits); - this.writeFloat(v.y, minY, maxY, bits); -}; - -bb.BitStream.prototype.readVec = function(minX, minY, maxX, maxY, bits) { - return v2.create(this.readFloat(minX, maxX, bits), this.readFloat(minY, maxY, bits)); -}; - -const kUnitEps = 1.0001; -bb.BitStream.prototype.writeUnitVec = function(v, bits) { - this.writeVec(v, -kUnitEps, -kUnitEps, kUnitEps, kUnitEps, bits); -}; + readVec(minX, minY, maxX, maxY, bitCount) { + return { + x: this.readFloat(minX, maxX, bitCount), + y: this.readFloat(minY, maxY, bitCount) + }; + } -bb.BitStream.prototype.readUnitVec = function(bits) { - return this.readVec(-kUnitEps, -kUnitEps, kUnitEps, kUnitEps, bits); -}; + writeUnitVec(vec, bitCount) { + this.writeVec(vec, -1.0001, -1.0001, 1.0001, 1.0001, bitCount); + } -bb.BitStream.prototype.writeVec32 = function(v) { - this.writeFloat32(v.x); - this.writeFloat32(v.y); -}; + readUnitVec(bitCount) { + return this.readVec(-1.0001, -1.0001, 1.0001, 1.0001, bitCount); + } -bb.BitStream.prototype.readVec32 = function() { - return v2.create(this.readFloat32(), this.readFloat32()); -}; + writeVec32(vec) { + this.writeFloat32(vec.x); + this.writeFloat32(vec.y); + } -bb.BitStream.prototype.writeAlignToNextByte = function() { - const pad = 8 - this.index % 8; - if (pad < 8) { - this.writeBits(0, pad); + readVec32() { + return { + x: this.readFloat32(), + y: this.readFloat32() + }; } -}; -bb.BitStream.prototype.readAlignToNextByte = function() { - const pad = 8 - this.index % 8; - if (pad < 8) { - this.readBits(pad); + writeBytes(src, offset, length) { + // assert(this._index % 8 == 0); + const data = new Uint8Array(src._view._view.buffer, offset, length); + this._view._view.set(data, this.index / 8); + this.index += length * 8; } -}; -// -// Map type strings to integers for more efficient serialization. -// + writeAlignToNextByte() { + const offset = 8 - this.index % 8; + if (offset < 8) this.writeBits(0, offset); + } -class ConfigTypeMap { - constructor(typeBits) { - this._typeToId = {}; - this._idToType = {}; - this.nextId = 0; - this.maxId = 2 ** typeBits; + readAlignToNextByte() { + const offset = 8 - this.index % 8; + if (offset < 8) this.readBits(offset); + } - this.addType(""); + writeGameType(type) { + this.writeBits(gameTypeSerialization.typeToId(type), 10); } - addType(type) { - // assert(this._typeToId[type] === undefined, `Type ${type} has already been defined!`); - // assert(this.nextId < this.maxId); - this._typeToId[type] = this.nextId; - this._idToType[this.nextId] = type; - this.nextId++; + readGameType() { + return gameTypeSerialization.idToType(this.readBits(10)); } - typeToId(type) { - const id = this._typeToId[type]; - // assert(id !== undefined, `Invalid type ${type}`); - return id; + writeMapType(type) { + this.writeBits(mapTypeSerialization.typeToId(type), 12); } - idToType(id) { - const type = this._idToType[id]; - if (type === undefined) { - console.error("Invalid id given to idToType", id, "max", Object.keys(this._idToType).length); - } - return type; + readMapType() { + return mapTypeSerialization.idToType(this.readBits(12)); } } -createTypeSerialization("Game", GameObjectDefs, 10); -createTypeSerialization("Map", MapObjectDefs, 12); - // // MsgStream // @@ -304,7 +174,7 @@ class MsgStream { this.valid = arrayBuf != null; if (this.valid) { this.arrayBuf = arrayBuf; - this.stream = new bb.BitStream(arrayBuf); + this.stream = new BitStream(arrayBuf); } else { console.log("Invalid buf type", typeof buf === "undefined" ? "undefined" : _typeof(buf)); if (typeof buf === "string") { @@ -321,6 +191,9 @@ class MsgStream { return this.stream; } + /** + * @param {Msg} type + **/ serializeMsg(type, msg) { // assert(this.stream.index % 8 == 0); this.stream.writeUint8(type); @@ -338,7 +211,7 @@ class MsgStream { if (this.stream.length - this.stream.byteIndex * 8 >= 1) { return this.stream.readUint8(); } - return MsgType.None; + return Msg.None; } } @@ -373,59 +246,126 @@ function setSerializeFns(type, serializedFullSize, serializePart, serializeFull, setSerializeFns( GameObject.Type.Player, 32, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); - s.writeUnitVec(t.dir, 8); + /** + * @param {BitStream} s + * @param {import("../server/src/objects/player").Player} data + **/ + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); + s.writeUnitVec(data.dir, 8); }, - (s, t) => { }, - (s, t) => { - t.ie = s.readVec(0, 0, 1024, 1024, 16); // position - t.oe = s.readUnitVec(8); // rotation + /** + * @param {BitStream} s + * @param {import("../server/src/objects/player").Player} data + **/ + (s, data) => { + s.writeGameType(data.outfit); + s.writeGameType(data.pack); + s.writeGameType(data.helmet); + s.writeGameType(data.chest); + s.writeGameType(data.activeWeapon); + + s.writeBits(data.layer, 2); + s.writeBoolean(data.dead); + s.writeBoolean(data.downed); + + s.writeBits(data.animType, 3); + s.writeBits(data.animSeq, 3); + s.writeBits(data.actionType, 3); + s.writeBits(data.actionSeq, 3); + + s.writeBoolean(data.wearingPan); + s.writeBoolean(data.healEffect); + + s.writeBoolean(data.frozen); + s.writeBits(data.frozenOri, 2); + + s.writeBoolean(data.hasHaste); + if (data.hasHaste) { + s.writeBits(data.hasteType, 3); + s.writeBits(data.hasteSeq, 3); + } + + s.writeBoolean(data.actionItem !== ""); + if (data.actionItem !== "") { + s.writeGameType(data.actionItem); + } + + s.writeBoolean(data.hasScale); + if (data.hasScale) { + s.writeFloat(data.scale, Constants.PlayerMinScale, Constants.PlayerMaxScale, 8); + } + + s.writeBoolean(data.hasRole); + if (data.hasRole) s.writeGameType(data.role); + + s.writeBoolean(data.hasPerks); + if (data.hasPerks) { + s.writeBits(data.perks.length, 3); + for (const perk of data.perks) { + s.writeGameType(perk.type); + s.writeBoolean(perk.droppable); + } + } + + s.writeAlignToNextByte(); }, - (s, t) => { - t.se = s.readGameType(); // outfit - t.ne = s.readGameType(); // pack - t.le = s.readGameType(); // helmet - t.ce = s.readGameType(); // chest - t.me = s.readGameType(); // active weapon - - t.pe = s.readBits(2); // layer - t.he = s.readBoolean(); // dead - t.ue = s.readBoolean(); // downed - - t.ge = s.readBits(3); // anim type - t.ye = s.readBits(3); // anim seq - t.we = s.readBits(3); // action type - t.fe = s.readBits(3); // action seq - - t._e = s.readBoolean(); // wearing pan - t.be = s.readBoolean(); // heal effect - t.xe = s.readBoolean(); // frozen - t.Se = s.readBits(2); // frozen ori - t.ve = 0; - t.ke = -1; + /** + * @param {BitStream} s + * @param {import("../server/src/objects/player").Player} data + **/ + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); // position + data.dir = s.readUnitVec(8); // rotation + }, + /** + * @param {BitStream} s + * @param {import("../server/src/objects/player").Player} data + **/ + (s, data) => { + data.outfit = s.readGameType(); // outfit + data.pack = s.readGameType(); // pack + data.helmet = s.readGameType(); // helmet + data.chest = s.readGameType(); // chest + data.activeWeapon = s.readGameType(); // active weapon + + data.layer = s.readBits(2); // layer + data.dead = s.readBoolean(); // dead + data.downed = s.readBoolean(); // downed + + data.animType = s.readBits(3); // anim type + data.animSeq = s.readBits(3); // anim seq + data.actionType = s.readBits(3); // action type + data.actionSeq = s.readBits(3); // action seq + + data.wearingPan = s.readBoolean(); // wearing pan + data.healEffect = s.readBoolean(); // heal effect + data.frozen = s.readBoolean(); // frozen + data.frozenOri = s.readBits(2); // frozen ori + data.hasteType = 0; + data.hasteSeq = -1; if (s.readBoolean()) { // has haste - t.ve = s.readBits(3); // haste type - t.ke = s.readBits(3); // haste seq + data.hasteType = s.readBits(3); // haste type + data.hasteSeq = s.readBits(3); // haste seq } const hasActionItem = s.readBoolean(); // has action item - t.ze = hasActionItem ? s.readGameType() : ""; // action item + data.actionItem = hasActionItem ? s.readGameType() : ""; // action item const hasScale = s.readBoolean(); // scale dirty - t.Ie = hasScale + data.scale = hasScale ? s.readFloat(Constants.PlayerMinScale, Constants.PlayerMaxScale, 8) : 1; const hasRole = s.readBoolean(); - t.Te = hasRole ? s.readGameType() : ""; - t.Me = []; + data.role = hasRole ? s.readGameType() : ""; + data.perks = []; const hasPerks = s.readBoolean(); if (hasPerks) { const perkCount = s.readBits(3); for (let i = 0; i < perkCount; i++) { const type = s.readGameType(); const droppable = s.readBoolean(); - t.Me.push({ + data.perks.push({ type, droppable }); @@ -437,55 +377,90 @@ setSerializeFns( setSerializeFns( GameObject.Type.Obstacle, 0, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); - s.writeBits(t.ori, 2); + /** + * @param {BitStream} s + * @param {import("../server/src/objects/obstacle").Obstacle} data + **/ + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); + s.writeBits(data.ori, 2); s.writeFloat( - t.scale, + data.scale, Constants.MapObjectMinScale, Constants.MapObjectMaxScale, 8 ); s.writeBits(0, 6); }, - (s, t) => { }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); - t.ori = s.readBits(2); - t.scale = s.readFloat( + /** + * @param {BitStream} s + * @param {import("../server/src/objects/obstacle").Obstacle} data + **/ + (s, data) => { + s.writeFloat(data.healthT, 0, 1, 8); + s.writeMapType(data.type); + s.writeBits(data.layer, 2); + s.writeBoolean(data.dead); + s.writeBoolean(data.isDoor); + if (data.isDoor) { + s.writeBoolean(data.door.open); + s.writeBoolean(data.door.canUse); + s.writeBoolean(data.door.locked); + s.writeBits(data.door.seq, 5); + } + + s.writeBoolean(data.isButton); + if (data.isButton) { + s.writeBoolean(data.button.onOff); + s.writeBoolean(data.button.canUse); + s.writeBits(data.button.seq, 6); + } + + s.writeBoolean(data.isPuzzlePiece); + if (data.isPuzzlePiece) s.writeUint16(data.parentBuildingId); + + s.writeBoolean(data.isSkin); + if (data.isSkin) s.writeUint16(data.skinPlayerId); + + s.writeBits(0, 5); // padding + }, + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); + data.ori = s.readBits(2); + data.scale = s.readFloat( Constants.MapObjectMinScale, Constants.MapObjectMaxScale, 8 ); s.readBits(6); }, - (s, t) => { - t.healthT = s.readFloat(0, 1, 8); - t.type = s.readMapType(); - t.layer = s.readBits(2); - t.dead = s.readBoolean(); - t.isDoor = s.readBoolean(); - if (t.isDoor) { - t.door = {}; - t.door.open = s.readBoolean(); - t.door.canUse = s.readBoolean(); - t.door.locked = s.readBoolean(); - t.door.seq = s.readBits(5); - } - t.isButton = s.readBoolean(); - if (t.isButton) { - t.button = {}; - t.button.onOff = s.readBoolean(); - t.button.canUse = s.readBoolean(); - t.button.seq = s.readBits(6); - } - t.isPuzzlePiece = s.readBoolean(); - if (t.isPuzzlePiece) { - t.parentBuildingId = s.readUint16(); - } - t.isSkin = s.readBoolean(); - if (t.isSkin) { - t.skinPlayerId = s.readUint16(); + (s, data) => { + data.healthT = s.readFloat(0, 1, 8); + data.type = s.readMapType(); + data.layer = s.readBits(2); + data.dead = s.readBoolean(); + data.isDoor = s.readBoolean(); + if (data.isDoor) { + data.door = {}; + data.door.open = s.readBoolean(); + data.door.canUse = s.readBoolean(); + data.door.locked = s.readBoolean(); + data.door.seq = s.readBits(5); + } + data.isButton = s.readBoolean(); + if (data.isButton) { + data.button = {}; + data.button.onOff = s.readBoolean(); + data.button.canUse = s.readBoolean(); + data.button.seq = s.readBits(6); + } + data.isPuzzlePiece = s.readBoolean(); + if (data.isPuzzlePiece) { + data.parentBuildingId = s.readUint16(); + } + data.isSkin = s.readBoolean(); + if (data.isSkin) { + data.skinPlayerId = s.readUint16(); } s.readBits(5); } @@ -493,30 +468,57 @@ setSerializeFns( setSerializeFns( GameObject.Type.Building, 0, - (s, t) => { }, - (s, t) => { }, - (s, t) => { - t.ceilingDead = s.readBoolean(); - t.occupied = s.readBoolean(); - t.ceilingDamaged = s.readBoolean(); - t.hasPuzzle = s.readBoolean(); - if (t.hasPuzzle) { - t.puzzleSolved = s.readBoolean(); - t.puzzleErrSeq = s.readBits(7); + /** + * @param {BitStream} s + * @param {import("../server/src/objects/building").Building} data + **/ + (s, data) => { + s.writeBoolean(data.ceilingDead); + s.writeBoolean(data.occupied); + s.writeBoolean(data.ceilingDamaged); + s.writeBoolean(data.hasPuzzle); + if (data.hasPuzzle) { + s.writeBoolean(data.puzzleSolved); + s.writeBits(data.puzzleErrSeq, 7); + } + s.writeBits(0, 4); // padding + }, + /** + * @param {BitStream} s + * @param {import("../server/src/objects/building").Building} data + **/ + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); + s.writeMapType(data.type); + s.writeBits(data.ori, 2); + s.writeBits(data.layer, 2); + }, + (s, data) => { + data.ceilingDead = s.readBoolean(); + data.occupied = s.readBoolean(); + data.ceilingDamaged = s.readBoolean(); + data.hasPuzzle = s.readBoolean(); + if (data.hasPuzzle) { + data.puzzleSolved = s.readBoolean(); + data.puzzleErrSeq = s.readBits(7); } s.readBits(4); }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); - t.type = s.readMapType(); - t.ori = s.readBits(2); - t.layer = s.readBits(2); + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); + data.type = s.readMapType(); + data.ori = s.readBits(2); + data.layer = s.readBits(2); } ); setSerializeFns( GameObject.Type.Structure, 0, - (s, t) => { }, + (_s, _t) => { }, + /** + * @param {BitStream} s + * @param {import("../server/src/objects/structure").Structure} data + **/ (s, t) => { s.writeVec(t.pos, 0, 0, 1024, 1024, 16); s.writeMapType(t.type); @@ -527,7 +529,7 @@ setSerializeFns( s.writeUint16(t.layerObjIds[r]); } }, - (s, t) => { }, + (_s, _t) => { }, (s, t) => { t.pos = s.readVec(0, 0, 1024, 1024, 16); t.type = s.readMapType(); @@ -544,51 +546,51 @@ setSerializeFns( setSerializeFns( GameObject.Type.LootSpawner, 0, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); - s.writeMapType(t.type); - s.writeBits(t.layer, 2); + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); + s.writeMapType(data.type); + s.writeBits(data.layer, 2); s.writeBits(0, 2); }, - (s, t) => { }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); - t.type = s.readMapType(); - t.layer = s.readBits(2); + (_s, _data) => { }, + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); + data.type = s.readMapType(); + data.layer = s.readBits(2); s.readBits(2); }, - (s, t) => { } + (_s, _data) => { } ); setSerializeFns( GameObject.Type.Loot, 5, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); }, - (s, t) => { - s.writeGameType(t.type); - s.writeUint8(t.count); - s.writeBits(t.layer, 2); - s.writeBoolean(t.isOld); - s.writeBoolean(t.isPreloadedGun); - s.writeBoolean(t.ownerId != 0); - if (t.ownerId != 0) { - s.writeUint16(t.ownerId); + (s, data) => { + s.writeGameType(data.type); + s.writeUint8(data.count); + s.writeBits(data.layer, 2); + s.writeBoolean(data.isOld); + s.writeBoolean(data.isPreloadedGun); + s.writeBoolean(data.ownerId != 0); + if (data.ownerId != 0) { + s.writeUint16(data.ownerId); } s.writeBits(0, 1); }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); }, - (s, t) => { - t.type = s.readGameType(); - t.count = s.readUint8(); - t.layer = s.readBits(2); - t.isOld = s.readBoolean(); - t.isPreloadedGun = s.readBoolean(); - t.hasOwner = s.readBoolean(); - if (t.hasOwner) { - t.ownerId = s.readUint16(); + (s, data) => { + data.type = s.readGameType(); + data.count = s.readUint8(); + data.layer = s.readBits(2); + data.isOld = s.readBoolean(); + data.isPreloadedGun = s.readBoolean(); + data.hasOwner = s.readBoolean(); + if (data.hasOwner) { + data.ownerId = s.readUint16(); } s.readBits(1); } @@ -596,116 +598,119 @@ setSerializeFns( setSerializeFns( GameObject.Type.DeadBody, 0, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); }, - (s, t) => { - s.writeUint8(t.layer); - s.writeUint16(t.playerId); + (s, data) => { + s.writeUint8(data.layer); + s.writeUint16(data.playerId); }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); }, - (s, t) => { - t.layer = s.readUint8(); - t.playerId = s.readUint16(); + (s, data) => { + data.layer = s.readUint8(); + data.playerId = s.readUint16(); } ); setSerializeFns( GameObject.Type.Decal, 0, - (s, t) => { }, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); + (_s, _data) => { }, + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); s.writeFloat( - t.scale, + data.scale, Constants.MapObjectMinScale, Constants.MapObjectMaxScale, 8 ); - s.writeMapType(t.type); - s.writeBits(t.ori, 2); - s.writeBits(t.layer, 2); - s.writeUint8(t.goreKills); + s.writeMapType(data.type); + s.writeBits(data.ori, 2); + s.writeBits(data.layer, 2); + s.writeUint8(data.goreKills); }, - (s, t) => { }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); - t.scale = s.readFloat( + (_s, _data) => { }, + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); + data.scale = s.readFloat( Constants.MapObjectMinScale, Constants.MapObjectMaxScale, 8 ); - t.type = s.readMapType(); - t.ori = s.readBits(2); - t.layer = s.readBits(2); - t.goreKills = s.readUint8(); + data.type = s.readMapType(); + data.ori = s.readBits(2); + data.layer = s.readBits(2); + data.goreKills = s.readUint8(); } ); setSerializeFns( GameObject.Type.Projectile, 0, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); - s.writeFloat(t.posZ, 0, GameConfig.projectile.maxHeight, 10); - s.writeUnitVec(t.dir, 7); + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); + s.writeFloat(data.posZ, 0, GameConfig.projectile.maxHeight, 10); + s.writeUnitVec(data.dir, 7); }, - (s, t) => { - s.writeGameType(t.type); - s.writeBits(t.layer, 2); + (s, data) => { + s.writeGameType(data.type); + s.writeBits(data.layer, 2); s.writeBits(0, 4); }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); - t.posZ = s.readFloat(0, GameConfig.projectile.maxHeight, 10); - t.dir = s.readUnitVec(7); + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); + data.posZ = s.readFloat(0, GameConfig.projectile.maxHeight, 10); + data.dir = s.readUnitVec(7); }, - (s, t) => { - t.type = s.readGameType(); - t.layer = s.readBits(2); + (s, data) => { + data.type = s.readGameType(); + data.layer = s.readBits(2); s.readBits(4); } ); setSerializeFns( GameObject.Type.Smoke, 0, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); - s.writeFloat(t.rad, 0, Constants.SmokeMaxRad, 8); + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); + s.writeFloat(data.rad, 0, Constants.SmokeMaxRad, 8); }, - (s, t) => { - s.writeBits(t.layer, 2); - s.writeBits(t.interior, 6); + (s, data) => { + s.writeBits(data.layer, 2); + s.writeBits(data.interior, 6); }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); - t.rad = s.readFloat(0, Constants.SmokeMaxRad, 8); + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); + data.rad = s.readFloat(0, Constants.SmokeMaxRad, 8); }, - (s, t) => { - t.layer = s.readBits(2); - t.interior = s.readBits(6); + (s, data) => { + data.layer = s.readBits(2); + data.interior = s.readBits(6); } ); setSerializeFns( GameObject.Type.Airdrop, 0, - (s, t) => { - s.writeFloat(t.fallT, 0, 1, 7); - s.writeBoolean(t.landed); + (s, data) => { + s.writeFloat(data.fallT, 0, 1, 7); + s.writeBoolean(data.landed); }, - (s, t) => { - s.writeVec(t.pos, 0, 0, 1024, 1024, 16); + (s, data) => { + s.writeVec(data.pos, 0, 0, 1024, 1024, 16); }, - (s, t) => { - t.fallT = s.readFloat(0, 1, 7); - t.landed = s.readBoolean(); + (s, data) => { + data.fallT = s.readFloat(0, 1, 7); + data.landed = s.readBoolean(); }, - (s, t) => { - t.pos = s.readVec(0, 0, 1024, 1024, 16); + (s, data) => { + data.pos = s.readVec(0, 0, 1024, 1024, 16); } ); -const MsgType = { +/** + * @enum + */ +const Msg = { None: 0, Join: 1, Disconnect: 2, @@ -744,6 +749,26 @@ class JoinMsg { this.bot = false; } + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.protocol = s.readUint32(); + this.matchPriv = s.readString(); + this.loadoutPriv = s.readString(); + this.questPriv = s.readString(); + this.name = s.readString(Constants.PlayerNameMaxLen); + this.useTouch = s.readBoolean(); + this.isMobile = s.readBoolean(); + this.proxy = s.readBoolean(); + this.otherProxy = s.readBoolean(); + this.bot = s.readBoolean(); + s.readAlignToNextByte(); + } + + /** + * @param {BitStream} s + **/ serialize(s) { s.writeUint32(this.protocol); s.writeString(this.matchPriv); @@ -764,12 +789,22 @@ class DisconnectMsg { this.reason = ""; } + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeString(this.reason); + } + + /** + * @param {BitStream} s + **/ deserialize(s) { this.reason = s.readString(); } } -class InputMsg { +export class InputMsg { constructor() { this.seq = 0; this.moveLeft = false; @@ -788,23 +823,28 @@ class InputMsg { this.useItem = ""; } - addInput(e) { + addInput(input) { if ( this.inputs.length < 7 && - !this.inputs.includes(e) + !this.inputs.includes(input) ) { - this.inputs.push(e); + this.inputs.push(input); } } + /** + * @param {BitStream} s + **/ serialize(s) { s.writeUint8(this.seq); s.writeBoolean(this.moveLeft); s.writeBoolean(this.moveRight); s.writeBoolean(this.moveUp); s.writeBoolean(this.moveDown); + s.writeBoolean(this.shootStart); s.writeBoolean(this.shootHold); + s.writeBoolean(this.portrait); s.writeBoolean(this.touchMoveActive); if (this.touchMoveActive) { @@ -813,13 +853,48 @@ class InputMsg { } s.writeUnitVec(this.toMouseDir, 10); s.writeFloat(this.toMouseLen, 0, Constants.MouseMaxDist, 8); + s.writeBits(this.inputs.length, 4); for (let t = 0; t < this.inputs.length; t++) { s.writeUint8(this.inputs[t]); } + s.writeGameType(this.useItem); + s.writeBits(0, 6); } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.seq = s.readUint8(); + this.moveLeft = s.readBoolean(); + this.moveRight = s.readBoolean(); + this.moveUp = s.readBoolean(); + this.moveDown = s.readBoolean(); + + this.shootStart = s.readBoolean(); + this.shootHold = s.readBoolean(); + + this.portrait = s.readBoolean(); + this.touchMoveActive = s.readBoolean(); + if (this.touchMoveActive) { + this.touchMoveDir = s.readUnitVec(8); + this.touchMoveLen = s.readUint8(); + } + this.toMouseDir = s.readUnitVec(10); + this.toMouseLen = s.readFloat(0, Constants.MouseMaxDist, 8); + + const length = s.readBits(4); + for (let i = 0; i < length; i++) { + this.inputs.push(s.readUint8()); + } + + this.useItem = s.readGameType(); + + s.readBits(6); + } } class DropItemMsg { @@ -828,10 +903,22 @@ class DropItemMsg { this.weapIdx = 0; } - serialize(e) { - e.writeGameType(this.item); - e.writeUint8(this.weapIdx); - e.writeBits(0, 6); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeGameType(this.item); + s.writeUint8(this.weapIdx); + s.writeBits(0, 6); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.item = s.readGameType(); + this.weapIdx = s.readUint8(); + s.readBits(6); } } @@ -840,9 +927,20 @@ class PerkModeRoleSelectMsg { this.role = ""; } - serialize(e) { - e.writeGameType(this.role); - e.writeBits(0, 6); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeGameType(this.role); + s.writeBits(0, 6); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.role = s.readGameType(); + s.readBits(6); } } @@ -853,11 +951,24 @@ class EmoteMsg { this.isPing = false; } - serialize(e) { - e.writeVec(this.pos, 0, 0, 1024, 1024, 16); - e.writeGameType(this.type); - e.writeBoolean(this.isPing); - e.writeBits(0, 5); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeVec(this.pos, 0, 0, 1024, 1024, 16); + s.writeGameType(this.type); + s.writeBoolean(this.isPing); + s.writeBits(0, 5); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.pos = s.readVec(0, 0, 1024, 1024, 16); + this.type = s.readGameType(); + this.isPing = s.readBoolean(); + s.readBits(6); } } @@ -869,18 +980,101 @@ class JoinedMsg { this.emotes = []; } - deserialize(e) { - this.teamMode = e.readUint8(); - this.playerId = e.readUint16(); - this.started = e.readBoolean(); - for (let t = e.readUint8(), r = 0; r < t; r++) { - const a = e.readGameType(); - this.emotes.push(a); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeUint8(this.teamMode); + s.writeUint16(this.playerId); + s.writeBoolean(this.started); + + s.writeUint8(this.emotes.length); + for (const emote of this.emotes) { + s.writeGameType(emote); + } + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.teamMode = s.readUint8(); + this.playerId = s.readUint16(); + this.started = s.readBoolean(); + for (let count = s.readUint8(), i = 0; i < count; i++) { + const emote = s.readGameType(); + this.emotes.push(emote); } - e.readAlignToNextByte(); + s.readAlignToNextByte(); + } +} + +function serializeMapRiver(s, data) { + s.writeFloat32(data.width); + s.writeUint8(data.looped); + s.writeUint8(data.points.length); + + for (const point of data.points) { + s.writeVec(point, 0, 0, 1024, 1024, 16); } } +function deserializeMapRiver(s, data) { + data.width = s.readFloat32(); + data.looped = s.readUint8(); + data.points = []; + for (let r = s.readUint8(), a = 0; a < r; a++) { + const i = s.readVec(0, 0, 1024, 1024, 16); + data.points.push(i); + } +} + +function serializeMapPlace(s, place) { + s.writeString(place.name); + s.writeVec(place.pos, 0, 0, 1024, 1024, 16); +} + +function deserializeMapPlaces(s, place) { + place.name = s.readString(); + place.pos = s.readVec(0, 0, 1024, 1024, 16); +} + +function serializeMapGroundPatch(s, patch) { + s.writeVec(patch.min, 0, 0, 1024, 1024, 16); + s.writeVec(patch.max, 0, 0, 1024, 1024, 16); + s.writeUint32(patch.color); + s.writeFloat32(patch.roughness); + s.writeFloat32(patch.offsetDist); + s.writeBits(patch.order, 7); + s.writeBoolean(patch.useAsMapShape); +} + +function deserializeMapGroundPatch(s, patch) { + patch.min = s.readVec(0, 0, 1024, 1024, 16); + patch.max = s.readVec(0, 0, 1024, 1024, 16); + patch.color = s.readUint32(); + patch.roughness = s.readFloat32(); + patch.offsetDist = s.readFloat32(); + patch.order = s.readBits(7); + patch.useAsMapShape = s.readBoolean(); +} + +function serializeMapObj(s, obj) { + s.writeVec(obj.pos, 0, 0, 1024, 1024, 16); + s.writeFloat(obj.scale, Constants.MapObjectMinScale, Constants.MapObjectMaxScale, 8); + s.writeMapType(obj.type); + s.writeBits(obj.ori, 2); + s.writeBits(0, 2); // Padding +} + +function deserializeMapObj(s, data) { + data.pos = s.readVec(0, 0, 1024, 1024, 16); + data.scale = s.readFloat(Constants.MapObjectMinScale, Constants.MapObjectMaxScale, 8); + data.type = s.readMapType(); + data.ori = s.readBits(2); + s.readBits(2); +} + class MapMsg { constructor() { this.mapName = ""; @@ -895,34 +1089,275 @@ class MapMsg { this.groundPatches = []; } - deserialize(e) { - this.mapName = e.readString(Constants.MapNameMaxLen); - this.seed = e.readUint32(); - this.width = e.readUint16(); - this.height = e.readUint16(); - this.shoreInset = e.readUint16(); - this.grassInset = e.readUint16(); - for (let t = e.readUint8(), r = 0; r < t; r++) { - const a = {}; - deserializeMapRiver(e, a); - this.rivers.push(a); + /** + * @param {BitStream} s + */ + serialize(s) { + s.writeString(this.mapName, Constants.MapNameMaxLen); + s.writeUint32(this.seed); + s.writeUint16(this.width); + s.writeUint16(this.height); + s.writeUint16(this.shoreInset); + s.writeUint16(this.grassInset); + + // Rivers + s.writeUint8(this.rivers.length); + for (const river of this.rivers) { + serializeMapRiver(s, river); } - for (let i = e.readUint8(), o = 0; o < i; o++) { - const s = {}; - deserializeMapPlaces(e, s); - this.places.push(s); + + // Places + s.writeUint8(this.places.length); + for (const place of this.places) { + serializeMapPlace(s, place); } - for (let n = e.readUint16(), l = 0; l < n; l++) { - const c = {}; - deserializeMapObj(e, c); - this.objects.push(c); + + // Objects + s.writeUint16(this.objects.length); + for (const obj of this.objects) { + serializeMapObj(s, obj); } - for (let m = e.readUint8(), p = 0; p < m; p++) { - const y = {}; - deserializeMapGroundPatch(e, y); - this.groundPatches.push(y); + + // GroundPatches + s.writeUint8(this.groundPatches.length); + for (const patch of this.groundPatches) { + serializeMapGroundPatch(s, patch); } } + + /** + * @param {BitStream} s + */ + deserialize(s) { + this.mapName = s.readString(Constants.MapNameMaxLen); + this.seed = s.readUint32(); + this.width = s.readUint16(); + this.height = s.readUint16(); + this.shoreInset = s.readUint16(); + this.grassInset = s.readUint16(); + for (let i = s.readUint8(), r = 0; r < i; r++) { + const river = {}; + deserializeMapRiver(s, river); + this.rivers.push(river); + } + for (let i = s.readUint8(), o = 0; o < i; o++) { + const place = {}; + deserializeMapPlaces(s, place); + this.places.push(place); + } + for (let i = s.readUint16(), l = 0; l < i; l++) { + const obj = {}; + deserializeMapObj(s, obj); + this.objects.push(obj); + } + for (let i = s.readUint8(), p = 0; p < i; p++) { + const patch = {}; + deserializeMapGroundPatch(s, patch); + this.groundPatches.push(patch); + } + } +} + +/** +* @param {BitStream} s +* @param {import("../server/src/objects/player").Player} data +**/ +function serializeActivePlayer(s, data) { + s.writeBoolean(data.dirty.health); + if (data.dirty.health) s.writeFloat(data.health, 0, 100, 8); + + s.writeBoolean(data.dirty.boost); + if (data.dirty.boost) s.writeFloat(data.boost, 0, 100, 8); + + s.writeBoolean(data.dirty.zoom); + if (data.dirty.zoom) s.writeUint8(data.zoom); + + s.writeBoolean(data.dirty.action); + if (data.dirty.action) { + s.writeFloat(data.action.time, 0, Constants.ActionMaxDuration, 8); + s.writeFloat(data.action.duration, 0, Constants.ActionMaxDuration, 8); + s.writeUint16(data.action.targetId); + } + + s.writeBoolean(data.dirty.inventory); + if (data.dirty.inventory) { + s.writeGameType(data.scope); + for (const key of Object.keys(GameConfig.bagSizes)) { + const hasItem = data.inventory[key] > 0; + s.writeBoolean(hasItem); + if (hasItem) s.writeBits(data.inventory[key], 9); + } + } + + s.writeBoolean(data.dirty.weapons); + if (data.dirty.weapons) { + s.writeBits(data.curWeapIdx, 2); + for (let i = 0; i < GameConfig.WeaponSlot.Count; i++) { + s.writeGameType(data.weapons[i].type); + s.writeUint8(data.weapons[i].ammo); + } + } + + s.writeBoolean(data.dirty.spectatorCount); + if (data.dirty.spectatorCount) { + s.writeUint8(data.spectatorCount); + } + + s.writeAlignToNextByte(); +} + +function deserializeActivePlayer(s, data) { + data.healthDirty = s.readBoolean(); + if (data.healthDirty) { + data.health = s.readFloat(0, 100, 8); + } + data.boostDirty = s.readBoolean(); + if (data.boostDirty) { + data.boost = s.readFloat(0, 100, 8); + } + data.zoomDirty = s.readBoolean(); + if (data.zoomDirty) { + data.zoom = s.readUint8(); + } + data.actionDirty = s.readBoolean(); + if (data.actionDirty) { + data.action = {}; + data.action.time = s.readFloat(0, Constants.ActionMaxDuration, 8); + data.action.duration = s.readFloat(0, Constants.ActionMaxDuration, 8); + data.action.targetId = s.readUint16(); + } + data.inventoryDirty = s.readBoolean(); + if (data.inventoryDirty) { + data.scope = s.readGameType(); + data.inventory = {}; + for ( + let r = Object.keys(GameConfig.bagSizes), a = 0; + a < r.length; + a++ + ) { + const i = r[a]; + let o = 0; + if (s.readBoolean()) { + o = s.readBits(9); + } + data.inventory[i] = o; + } + } + data.weapsDirty = s.readBoolean(); + if (data.weapsDirty) { + data.curWeapIdx = s.readBits(2); + data.weapons = []; + for (let i = 0; i < GameConfig.WeaponSlot.Count; i++) { + const n = {}; + n.type = s.readGameType(); + n.ammo = s.readUint8(); + data.weapons.push(n); + } + } + data.spectatorCountDirty = s.readBoolean(); + if (data.spectatorCountDirty) { + data.spectatorCount = s.readUint8(); + } + s.readAlignToNextByte(); +} + +function serializePlayerStatus(s, data) { + s.writeUint8(data.length); + for (const info of data) { + s.writeBoolean(info.hasData); + + if (info.hasData) { + s.writeVec(info.pos, 0, 0, 1024, 1024, 11); + s.writeBoolean(info.visible); + s.writeBoolean(info.dead); + s.writeBoolean(info.downed); + + s.writeBoolean(info.role !== ""); + if (info.role !== "") { + s.writeGameType(info.role); + } + } + } +} + +function deserializePlayerStatus(s, data) { + data.players = []; + for (let r = s.readUint8(), a = 0; a < r; a++) { + const i = {}; + i.hasData = s.readBoolean(); + if (i.hasData) { + i.pos = s.readVec(0, 0, 1024, 1024, 11); + i.visible = s.readBoolean(); + i.dead = s.readBoolean(); + i.downed = s.readBoolean(); + i.role = ""; + if (s.readBoolean()) { + i.role = s.readGameType(); + } + } + data.players.push(i); + } + s.readAlignToNextByte(); +} + +function serializeGroupStatus(s, data) { + s.writeUint8(data.length); + + for (const status of data) { + s.writeFloat(status.health, 0, 100, 7); + s.writeBoolean(status.disconnected); + } +} + +function deserializeGroupStatus(s, data) { + data.players = []; + for (let r = s.readUint8(), a = 0; a < r; a++) { + const i = {}; + i.health = s.readFloat(0, 100, 7); + i.disconnected = s.readBoolean(); + data.players.push(i); + } +} + +function serializePlayerInfo(s, data) { + s.writeUint16(data.id); + s.writeUint8(data.teamId); + s.writeUint8(data.groupId); + s.writeString(data.name); + + s.writeGameType(data.loadout.heal); + s.writeGameType(data.loadout.boost); + + s.writeAlignToNextByte(); +} + +function deserializePlayerInfos(s, data) { + data.playerId = s.readUint16(); + data.teamId = s.readUint8(); + data.groupId = s.readUint8(); + data.name = s.readString(); + data.loadout = {}; + data.loadout.heal = s.readGameType(); + data.loadout.boost = s.readGameType(); + s.readAlignToNextByte(); +} + +function serializeGasData(s, data) { + s.writeUint8(data.mode); + s.writeFloat32(data.duration); + s.writeVec(data.posNew, 0, 0, 1024, 1024, 16); + s.writeVec(data.posNew, 0, 0, 1024, 1024, 16); + s.writeFloat(data.radOld, 0, 2048, 16); + s.writeFloat(data.radNew, 0, 2048, 16); +} + +function deserializeGasData(s, data) { + data.mode = s.readUint8(); + data.duration = s.readFloat32(); + data.posOld = s.readVec(0, 0, 1024, 1024, 16); + data.posNew = s.readVec(0, 0, 1024, 1024, 16); + data.radOld = s.readFloat(0, 2048, 16); + data.radNew = s.readFloat(0, 2048, 16); } const UpdateExtFlags = { @@ -985,6 +1420,196 @@ class UpdateMsg { this.ack = 0; } + /** + * @param {BitStream} s + **/ + serialize(s) { + let flags = 0; + if (this.delObjIds.length) flags += UpdateExtFlags.DeletedObjects; + if (this.fullObjects.length) flags += UpdateExtFlags.FullObjects; + if (this.activePlayerIdDirty) flags += UpdateExtFlags.ActivePlayerId; + if (this.gasDirty) flags += UpdateExtFlags.Gas; + if (this.gasTDirty) flags += UpdateExtFlags.GasCircle; + if (this.playerInfos.length) flags += UpdateExtFlags.PlayerInfos; + if (this.deletedPlayerIds.length) flags += UpdateExtFlags.DeletePlayerIds; + if (this.playerStatusDirty) flags += UpdateExtFlags.PlayerStatus; + if (this.groupStatusDirty) flags += UpdateExtFlags.GroupStatus; + if (this.bullets.length) flags += UpdateExtFlags.Bullets; + if (this.explosions.length) flags += UpdateExtFlags.Explosions; + if (this.emotes.length) flags += UpdateExtFlags.Emotes; + if (this.planes.length) flags += UpdateExtFlags.Planes; + if (this.airstrikeZones.length) flags += UpdateExtFlags.AirstrikeZones; + if (this.mapIndicators.length) flags += UpdateExtFlags.MapIndicators; + if (this.killLeaderDirty) flags += UpdateExtFlags.KillLeader; + + s.writeUint16(flags); + + if ((flags & UpdateExtFlags.DeletedObjects) !== 0) { + s.writeUint16(this.delObjIds.length); + for (const id of this.delObjIds) { + s.writeUint16(id); + } + } + + if ((flags & UpdateExtFlags.FullObjects) !== 0) { + s.writeUint16(this.fullObjects.length); + for (const obj of this.fullObjects) { + s.writeUint8(obj.__type); + s.writeUint16(obj.id); + ObjectSerializeFns[obj.__type].serializePart(s, obj); + ObjectSerializeFns[obj.__type].serializeFull(s, obj); + } + } + + s.writeUint16(this.partObjects.length); + for (const obj of this.partObjects) { + s.writeUint16(obj.id); + ObjectSerializeFns[obj.__type].serializePart(s, obj); + } + + if ((flags & UpdateExtFlags.ActivePlayerId) !== 0) { + s.writeUint16(this.activePlayerId); + } + + serializeActivePlayer(s, this.activePlayerData); + + if ((flags & UpdateExtFlags.Gas) !== 0) { + serializeGasData(s, this.gas); + } + + if ((flags & UpdateExtFlags.GasCircle) !== 0) { + s.writeFloat(this.gasT, 0, 1, 16); + } + + if ((flags & UpdateExtFlags.PlayerInfos) !== 0) { + s.writeUint8(this.playerInfos.length); + for (const info of this.playerInfos) { + serializePlayerInfo(s, info); + } + } + + if ((flags & UpdateExtFlags.DeletePlayerIds) !== 0) { + s.writeUint8(this.deletedPlayerIds.length); + for (const id of this.deletedPlayerIds) { + s.writeUint16(id); + } + } + + if ((flags & UpdateExtFlags.PlayerStatus) !== 0) { + serializePlayerStatus(s, this.playerStatus); + } + + if ((flags & UpdateExtFlags.GroupStatus) !== 0) { + serializeGroupStatus(s, this.groupStatus); + } + + if ((flags & UpdateExtFlags.Bullets) !== 0) { + s.writeUint8(this.bullets.length); + + for (const bullet of this.bullets) { + s.writeUint16(bullet.playerId); + s.writeVec(bullet.startPos, 0, 0, 1024, 1024, 16); + s.writeUnitVec(bullet.dir, 8); + s.writeGameType(bullet.bulletType); + s.writeBits(bullet.layer, 2); + s.writeFloat(bullet.varianceT, 0, 1, 4); + s.writeBits(bullet.distAdjIdx, 4); + s.writeBoolean(bullet.clipDistance); + if (bullet.clipDistance) { + s.writeFloat(bullet.distance, 0, 1024, 16); + } + s.writeBoolean(bullet.shotFx); + if (bullet.shotFx) { + s.writeGameType(bullet.sourceType); + s.writeBoolean(bullet.shotOffhand); + s.writeBoolean(bullet.lastShot); + } + s.writeBoolean(bullet.reflectCount > 0); + if (bullet.reflectCount > 0) { + s.writeBits(bullet.reflectCount, 2); + s.writeUint16(bullet.reflectObjId); + } + + s.writeBoolean(bullet.hasSpecialFx); + + if (bullet.hasSpecialFx) { + s.writeBoolean(bullet.shotAlt); + s.writeBoolean(bullet.splinter); + s.writeBoolean(bullet.trailSaturated); + s.writeBoolean(bullet.trailSmall); + s.writeBoolean(bullet.trailThick); + } + } + + s.writeAlignToNextByte(); + } + + if ((flags & UpdateExtFlags.Explosions) !== 0) { + s.writeUint8(this.explosions.length); + for (const explosion of this.explosions) { + s.writeVec(explosion.pos, 0, 0, 1024, 1024, 16); + s.writeGameType(explosion.type); + s.writeBits(explosion.layer, 2); + s.writeAlignToNextByte(); + } + } + + if ((flags & UpdateExtFlags.Emotes) !== 0) { + s.writeUint8(this.emotes.length); + for (const emote of this.emotes) { + s.writeUint16(emote.playerId); + s.writeGameType(emote.type); + s.writeBoolean(emote.isPing); + s.writeGameType(emote.itemType); + if (emote.isPing) s.writeVec(emote.pos, 0, 0, 1024, 1024, 16); + s.writeAlignToNextByte(); + } + } + + if ((flags & UpdateExtFlags.Planes) !== 0) { + s.writeUint8(this.planes.length); + for (const plane of this.planes) { + s.writeUint8(plane.id); + s.writeVec(plane.pos, 0, 0, 2048, 2048, 10); + s.writeUnitVec(plane.dir, 8); + s.writeBoolean(plane.actionComplete); + s.writeBits(plane.action, 3); + } + } + + if ((flags & UpdateExtFlags.AirstrikeZones) !== 0) { + s.writeUint8(this.airstrikeZones.length); + for (const zone of this.airstrikeZones) { + s.writeVec(zone.pos, 0, 0, 1024, 1024, 12); + s.writeFloat(zone.rad, 0, Constants.AirstrikeZoneMaxRad, 8); + s.writeFloat(zone.duration, 0, Constants.AirstrikeZoneMaxDuration, 8); + } + } + + if ((flags & UpdateExtFlags.MapIndicators) !== 0) { + s.writeUint8(this.mapIndicators.length); + for (const indicator of this.mapIndicators) { + s.writeBits(indicator.id, 4); + s.writeBoolean(indicator.dead); + s.writeBoolean(indicator.equipped); + s.writeGameType(indicator.type); + s.writeVec(indicator.pos, 0, 0, 1024, 1024, 16); + } + s.writeAlignToNextByte(); + } + + if ((flags & UpdateExtFlags.KillLeader) !== 0) { + s.writeUint16(this.killLeaderId); + s.writeUint8(this.killLeaderKills); + } + + s.writeUint8(this.ack); + } + + /** + * @param {BitStream} s + * @param {import("../client/src/objects/objectPool").Creator} objectCreator + **/ deserialize(s, objectCreator) { const flags = s.readUint16(); @@ -1197,35 +1822,76 @@ class KillMsg { this.killed = false; } - deserialize(e) { - this.damageType = e.readUint8(); - this.itemSourceType = e.readGameType(); - this.mapSourceType = e.readMapType(); - this.targetId = e.readUint16(); - this.killerId = e.readUint16(); - this.killCreditId = e.readUint16(); - this.killerKills = e.readUint8(); - this.downed = e.readBoolean(); - this.killed = e.readBoolean(); - e.readAlignToNextByte(); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeUint8(this.damageType); + s.writeGameType(this.itemSourceType); + s.writeMapType(this.mapSourceType); + s.writeUint16(this.targetId); + s.writeUint16(this.killerId); + s.writeUint16(this.killCreditId); + s.writeUint8(this.killerKills); + s.writeBoolean(this.downed); + s.writeBoolean(this.killed); + s.writeAlignToNextByte(); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.damageType = s.readUint8(); + this.itemSourceType = s.readGameType(); + this.mapSourceType = s.readMapType(); + this.targetId = s.readUint16(); + this.killerId = s.readUint16(); + this.killCreditId = s.readUint16(); + this.killerKills = s.readUint8(); + this.downed = s.readBoolean(); + this.killed = s.readBoolean(); + s.readAlignToNextByte(); } } class PlayerStatsMsg { constructor() { this.playerId = 0; - this.playerStats = {}; + this.playerStats = { + playerId: 0, + timeAlive: 0, + kills: 0, + dead: false, + damageDealt: 0, + damageTaken: 0 + }; + } + + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeUint16(this.playerId); + s.writeUint16(this.playerStats.timeAlive); + s.writeUint8(this.playerStats.kills); + s.writeUint8(this.playerStats.dead); + s.writeUint16(this.playerStats.damageDealt); + s.writeUint16(this.playerStats.damageTaken); } - deserialize(e) { - const t = {}; - t.playerId = e.readUint16(); - t.timeAlive = e.readUint16(); - t.kills = e.readUint8(); - t.dead = e.readUint8(); - t.damageDealt = e.readUint16(); - t.damageTaken = e.readUint16(); - this.playerStats = t; + /** + * @param {BitStream} s + **/ + deserialize(s) { + const playerStats = {}; + playerStats.playerId = s.readUint16(); + playerStats.timeAlive = s.readUint16(); + playerStats.kills = s.readUint8(); + playerStats.dead = s.readUint8(); + playerStats.damageDealt = s.readUint16(); + playerStats.damageTaken = s.readUint16(); + this.playerStats = playerStats; } } @@ -1238,15 +1904,36 @@ class GameOverMsg { this.playerStats = []; } - deserialize(e) { - this.teamId = e.readUint8(); - this.teamRank = e.readUint8(); - this.gameOver = e.readUint8(); - this.winningTeamId = e.readUint8(); - for (let t = e.readUint8(), r = 0; r < t; r++) { - const a = new PlayerStatsMsg(); - a.deserialize(e); - this.playerStats.push(a.playerStats); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeUint8(this.teamId); + s.writeUint8(this.teamRank); + s.writeUint8(+this.gameOver); + s.writeUint8(this.winningTeamId); + + s.writeUint8(this.playerStats.length); + for (const stats of this.playerStats) { + const statsMsg = new PlayerStatsMsg(); + statsMsg.playerId = stats.playerId; + statsMsg.playerStats = stats; + statsMsg.serialize(s); + } + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.teamId = s.readUint8(); + this.teamRank = s.readUint8(); + this.gameOver = s.readUint8(); + this.winningTeamId = s.readUint8(); + for (let count = s.readUint8(), i = 0; i < count; i++) { + const statsMsg = new PlayerStatsMsg(); + statsMsg.deserialize(s); + this.playerStats.push(statsMsg.playerStats); } } } @@ -1267,11 +1954,24 @@ class PickupMsg { this.count = 0; } - deserialize(e) { - this.type = e.readUint8(); - this.item = e.readGameType(); - this.count = e.readUint8(); - e.readBits(6); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeUint8(this.type); + s.writeGameType(this.item); + s.writeUint8(this.count); + s.writeBits(0, 6); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.type = s.readUint8(); + this.item = s.readGameType(); + this.count = s.readUint8(); + s.readBits(6); } } @@ -1283,12 +1983,26 @@ class SpectateMsg { this.specForce = false; } - serialize(e) { - e.writeBoolean(this.specBegin); - e.writeBoolean(this.specNext); - e.writeBoolean(this.specPrev); - e.writeBoolean(this.specForce); - e.writeBits(0, 4); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeBoolean(this.specBegin); + s.writeBoolean(this.specNext); + s.writeBoolean(this.specPrev); + s.writeBoolean(this.specForce); + s.writeBits(0, 4); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + s.writeBoolean(this.specBegin); + s.writeBoolean(this.specNext); + s.writeBoolean(this.specPrev); + s.writeBoolean(this.specForce); + s.writeBits(0, 4); } } @@ -1301,13 +2015,28 @@ class RoleAnnouncementMsg { this.killed = false; } - deserialize(e) { - this.playerId = e.readUint16(); - this.killerId = e.readUint16(); - this.role = e.readGameType(); - this.assigned = e.readBoolean(); - this.killed = e.readBoolean(); - e.readAlignToNextByte(); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeUint16(this.playerId); + s.writeUint16(this.killerId); + s.writeGameType(this.role); + s.writeBoolean(this.assigned); + s.writeBoolean(this.killed); + s.writeAlignToNextByte(); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.playerId = s.readUint16(); + this.killerId = s.readUint16(); + this.role = s.readGameType(); + this.assigned = s.readBoolean(); + this.killed = s.readBoolean(); + s.readAlignToNextByte(); } } @@ -1317,12 +2046,26 @@ class LoadoutMsg { this.custom = false; } - serialize(e) { - for (let t = 0; t < GameConfig.EmoteSlot.Count; t++) { - e.writeGameType(this.emotes[t]); + /** + * @param {BitStream} s + **/ + serialize(s) { + for (let i = 0; i < GameConfig.EmoteSlot.Count; i++) { + s.writeGameType(this.emotes[i]); } - e.writeUint8(this.custom); - e.writeAlignToNextByte(); + s.writeUint8(this.custom); + s.readAlignToNextByte(); + } + + /** + * @param {BitStream} s + **/ + deserialize(s) { + for (let i = 0; i < GameConfig.EmoteSlot.Count; i++) { + this.emotes.push(s.readGameType()); + } + this.custom = s.readUint8(); + s.writeAlignToNextByte(); } } @@ -1331,12 +2074,18 @@ class StatsMsg { this.data = ""; } - serialize(e) { - e.writeString(this.data); + /** + * @param {BitStream} s + **/ + serialize(s) { + s.writeString(this.data); } - deserialize(e) { - this.data = e.readString(); + /** + * @param {BitStream} s + **/ + deserialize(s) { + this.data = s.readString(); } } @@ -1345,17 +2094,23 @@ class AliveCountsMsg { this.teamAliveCounts = []; } - serialize(e) { + /** + * @param {BitStream} s + **/ + serialize(s) { const t = this.teamAliveCounts.length; - e.writeUint8(t); + s.writeUint8(t); for (let r = 0; r < t; r++) { - e.writeUint8(this.teamAliveCounts[r]); + s.writeUint8(this.teamAliveCounts[r]); } } - deserialize(e) { - for (let t = e.readUint8(), r = 0; r < t; r++) { - const a = e.readUint8(); + /** + * @param {BitStream} s + **/ + deserialize(s) { + for (let t = s.readUint8(), r = 0; r < t; r++) { + const a = s.readUint8(); this.teamAliveCounts.push(a); } } @@ -1366,12 +2121,20 @@ class UpdatePassMsg { deserialize(_e) { } } +function getPlayerStatusUpdateRate(factionMode) { + if (factionMode) { + return 0.5; + } else { + return 0.25; + } +} + export default { - BitStream: bb.BitStream, + BitStream, Constants, getPlayerStatusUpdateRate, MsgStream, - Msg: MsgType, + Msg, JoinMsg, DisconnectMsg, InputMsg, diff --git a/shared/utils/terrainGen.ts b/shared/utils/terrainGen.ts index caedf4da..f8d7d6a9 100644 --- a/shared/utils/terrainGen.ts +++ b/shared/utils/terrainGen.ts @@ -1,11 +1,16 @@ import { GameConfig } from "../gameConfig"; -import { type MapRiver } from "../../server/src/net/mapMsg"; import { type AABB } from "./coldet"; import { collider } from "./collider"; import { River } from "./river"; import { util } from "./util"; import { type Vec2, v2 } from "./v2"; +export interface MapRiverData { + width: number + looped: boolean + points: Vec2[] +} + export function generateJaggedAabbPoints( aabb: AABB, divisionsX: number, @@ -54,7 +59,7 @@ export function generateTerrain( height: number, shoreInset: number, grassInset: number, - riverDescs: MapRiver[], + riverDescs: MapRiverData[], seed: number) { // Subdivisions along one edge of the shore const shoreDivisions = 64.0;