diff --git a/client/src/emote.js b/client/src/emote.js index cbd8642a..3c7038f8 100644 --- a/client/src/emote.js +++ b/client/src/emote.js @@ -2,6 +2,7 @@ import $ from "jquery"; import { GameConfig } from "../../shared/gameConfig"; import * as PIXI from "pixi.js"; import { coldet } from "../../shared/utils/coldet"; +import { util } from "../../shared/utils/util"; import { v2 } from "../../shared/utils/v2"; import { math } from "../../shared/utils/math"; import { device } from "./device"; diff --git a/client/src/game.js b/client/src/game.js index 3731a608..1c02d8c3 100644 --- a/client/src/game.js +++ b/client/src/game.js @@ -97,6 +97,8 @@ export class Game { joinMessage.proxy = false; //* !/.*surviv\.io$/.test(window.location.hostname); joinMessage.otherProxy = false; //* !proxy.authLocation(); joinMessage.bot = false; + joinMessage.emotes = _this.config.get("loadout").emotes; + _this.sendMessage(net.MsgType.Join, joinMessage, 8192); }; this.ws.onmessage = function(e) { diff --git a/server/src/game.ts b/server/src/game.ts index bf642f55..103d2aee 100644 --- a/server/src/game.ts +++ b/server/src/game.ts @@ -14,7 +14,21 @@ import { GameConfig } from "../../shared/gameConfig"; import net from "../../shared/net"; import { type Explosion } from "./objects/explosion"; import { type Msg } from "../../shared/netTypings"; - +import { EmotesDefs } from "../../shared/defs/gameObjects/emoteDefs"; + +export class Emote { + playerId: number; + pos: Vec2; + type: string; + isPing: boolean; + + constructor(playerId: number, pos: Vec2, type: string, isPing: boolean) { + this.playerId = playerId; + this.pos = pos; + this.type = type; + this.isPing = isPing; + } +} export class Game { stopped = false; allowJoin = true; @@ -68,6 +82,8 @@ export class Game { logger: Logger; + emotes = new Set(); + constructor(id: number, config: ConfigType) { this.id = id; this.logger = new Logger(`Game #${this.id}`); @@ -107,6 +123,14 @@ export class Game { // this.serializationCache.update(this); for (const player of this.connectedPlayers) { + if (this.emotes.size) { + for (const emote of this.emotes) { + if (emote.playerId === player.id || !emote.isPing) { + player.emotes.add(emote); + } + } + } + player.sendMsgs(); } @@ -127,6 +151,8 @@ export class Game { this.explosions.length = 0; this.aliveCountDirty = false; + this.emotes.clear(); + // Record performance and start the next tick // THIS TICK COUNTER IS WORKING CORRECTLY! // It measures the time it takes to calculate a tick, not the time between ticks. @@ -217,6 +243,20 @@ export class Game { player.name = name; player.joinedTime = Date.now(); + const emotes = joinMsg.emotes; + for (let i = 0; i < emotes.length; i++) { + const emote = emotes[i]; + if ((i < 4 && emote === "")) { + player.loadout.emotes.push("emote_logoswine"); + continue; + } + + if (EmotesDefs[emote as keyof typeof EmotesDefs] === undefined && + emote != "") { + player.loadout.emotes.push("emote_logoswine"); + } else player.loadout.emotes.push(emote); + } + this.newPlayers.push(player); this.grid.addObject(player); this.connectedPlayers.add(player); @@ -225,6 +265,12 @@ export class Game { this.aliveCountDirty = true; break; } + case net.MsgType.Emote: { + const emoteMsg = new net.EmoteMsg(); + emoteMsg.deserialize(stream); + + this.emotes.add(new Emote(player.id, emoteMsg.pos, emoteMsg.type, emoteMsg.isPing)); + } } } diff --git a/server/src/objects/player.ts b/server/src/objects/player.ts index 91a17d21..6f6d4ab1 100644 --- a/server/src/objects/player.ts +++ b/server/src/objects/player.ts @@ -1,5 +1,5 @@ import { type WebSocket } from "uWebSockets.js"; -import { type Game } from "../game"; +import { Emote, type Game } from "../game"; import { GameConfig } from "../../../shared/gameConfig"; import { collider } from "../../../shared/utils/collider"; import { type Vec2, v2 } from "../../../shared/utils/v2"; @@ -201,9 +201,11 @@ export class Player extends BaseGameObject { loadout = { heal: "heal_basic", boost: "boost_basic", - emotes: [...GameConfig.defaultEmoteLoadout] + emotes: [] as string[] }; + emotes = new Set(); + damageTaken = 0; damageDealt = 0; joinedTime = 0; @@ -418,6 +420,11 @@ export class Player extends BaseGameObject { updateMsg.activePlayerData = this; updateMsg.playerInfos = this._firstUpdate ? [...this.game.players] : this.game.newPlayers; + for (const emote of this.emotes) { + updateMsg.emotes.push(emote); + } + this.emotes.clear(); + let newBullets = []; const extendedRadius = 1.1 * radius; const radiusSquared = extendedRadius * extendedRadius; @@ -556,6 +563,12 @@ export class Player extends BaseGameObject { this.game.addLoot(this.outfit, this.pos, this.layer, 1); } } + + // death emote + + if (this.loadout.emotes[5] != "") { + this.game.emotes.add(new Emote(this.id, this.pos, this.loadout.emotes[5], false)); + } } toMouseLen = 0; diff --git a/shared/net.js b/shared/net.js index 86bd4251..4107bacb 100644 --- a/shared/net.js +++ b/shared/net.js @@ -888,6 +888,10 @@ class JoinMsg { * @type {boolean} */ this.bot = false; + /** + * @type {string[]} + */ + this.emotes = []; } /** @@ -904,6 +908,13 @@ class JoinMsg { this.proxy = s.readBoolean(); this.otherProxy = s.readBoolean(); this.bot = s.readBoolean(); + this.emotes = []; + const count = s.readUint8(); + + for (let i = 0; i < count; i++) { + const emote = s.readGameType(); + this.emotes.push(emote); + } s.readAlignToNextByte(); } @@ -921,6 +932,11 @@ class JoinMsg { s.writeBoolean(this.proxy); s.writeBoolean(this.otherProxy); s.writeBoolean(this.bot); + + s.writeUint8(this.emotes.length); + for (const emote of this.emotes) { + s.writeGameType(emote); + } s.writeAlignToNextByte(); } } @@ -1140,7 +1156,7 @@ class EmoteMsg { this.pos = s.readVec(0, 0, 1024, 1024, 16); this.type = s.readGameType(); this.isPing = s.readBoolean(); - s.readBits(6); + s.readBits(5); } } @@ -1163,7 +1179,6 @@ class JoinedMsg { 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); @@ -1177,7 +1192,8 @@ class JoinedMsg { this.teamMode = s.readUint8(); this.playerId = s.readUint16(); this.started = s.readBoolean(); - for (let count = s.readUint8(), i = 0; i < count; i++) { + const count = s.readUint8(); + for (let i = 0; i < count; i++) { const emote = s.readGameType(); this.emotes.push(emote); } @@ -1612,6 +1628,9 @@ class UpdateMsg { this.groupStatusDirty = false; this.bullets = []; this.explosions = []; + /** + * @type {Emote[]} + */ this.emotes = []; this.planes = []; this.airstrikeZones = []; @@ -1761,8 +1780,9 @@ class UpdateMsg { for (const emote of this.emotes) { s.writeUint16(emote.playerId); s.writeGameType(emote.type); - s.writeBoolean(emote.isPing); s.writeGameType(emote.itemType); + s.writeBoolean(emote.isPing); + if (emote.isPing) s.writeVec(emote.pos, 0, 0, 1024, 1024, 16); s.writeAlignToNextByte(); } @@ -1950,6 +1970,7 @@ class UpdateMsg { emote.type = s.readGameType(); emote.itemType = s.readGameType(); emote.isPing = s.readBoolean(); + if (emote.isPing) { emote.pos = s.readVec(0, 0, 1024, 1024, 16); }