New Among Us version support and bug fix#102
Open
FangkuaiYa wants to merge 17 commits into
Open
Conversation
…events, matchmaker improvements, and config updates
=== Game Options Validation (src/game/GameOptions.ts) [NEW] ===
+ GameOptionsValidator.validateGameSettings() — validates all game settings
+ Numeric range checks: playerSpeed, killCooldown, vision, tasks, timers
+ Enum checks: GameMap, GameKeyword, KillDistance, TaskBarMode, GameMode,
RulesPreset
+ Dependency check: numEmergencies <= maxPlayers
+ Role settings validation for all 9 roles
+ Used in WaterwayServer.handleHostGameMessage() on room creation
+ Used in Room constructor on player.syncsettings RPC
=== Hide & Seek Game Mode Manager (src/game/modes/HideAndSeekManager.ts) [NEW] ===
+ Full lifecycle: Hiding -> Seeking -> FinalHide -> Ended
+ Automatic seeker selection (configured playerId or random)
+ Hider tracking with task-completion win condition
+ Body reports and meetings disabled during gameplay
+ Final hide phase: seeker speed boost, position ping mechanic
+ Player disconnect handling:
- Seeker leaves -> hiders win
- All hiders leave -> seeker wins
+ Integrated into Room.handleStartGame() and Room.handleRpcMessage()
+ Clean teardown on destroy / game end
=== Role System (src/game/roles/) [NEW] ===
[NEW] BaseRole.ts — server-side role base class
+ Cooldown management (startCooldown, canUseAbility, isOnCooldown)
+ Hooks: onGameStart, onKill, onTaskComplete, onDeath, onMeetingStart,
onAbilityUse, onFixedUpdate, onGameEnd
+ roleType, teamType, isActive, currentCooldown, lastAbilityUse
[NEW] NoisemakerRole.ts — crewmate, emits alert on task completion
+ onTaskComplete(): broadcasts position reveal to nearby players
+ Configurable alert duration and impostor visibility
[NEW] PhantomRole.ts — impostor, vanishes on death
+ onDeath(): enters invisible ghost state instead of dying
+ Vanish duration + cooldown from role settings
+ Auto-dies after vanish expires
[NEW] TrackerRole.ts — crewmate, tracks a target
+ onAbilityUse(target): starts periodic position updates
+ Tracking duration, cooldown, and update delay from role settings
+ Auto-stops after duration
[NEW] DetectiveRole.ts — crewmate, inspects suspects
+ onAbilityUse(target): checks kill count, reports suspicion level
+ suspectLimit from role settings
+ Tracks murder records during game
[NEW] ViperRole.ts — impostor, delayed poison kills
+ onKill(target): applies poison instead of instant kill
+ Target dies after viperDissolveTime seconds
+ All poisons cleared on Viper death or game end
[NEW] RoleManager.ts — role assignment and lifecycle
+ assignRoles(): reads roleChances from settings, rolls dice per player
+ Respects maxPlayers limits and team constraints
+ Routes game events (kill, task, death, meeting) to correct role
+ Plugin-extensible via static registerRole()
=== New API Events (src/api/events/) [NEW] ===
[NEW] room/HideAndSeekStart.ts — room.hideandseekstart
Fields: room, seekerPlayer, hiderPlayers, hideDuration
[NEW] room/HiderCaught.ts — room.hidercaught
Fields: room, hiderPlayer, seekerPlayer, remainingHiders
[NEW] room/HideAndSeekEnd.ts — room.hideandseekend
Fields: room, winner ("seekers"|"hiders"|"none"), reason
[NEW] player/TaskStarted.ts — player.taskstarted
Fields: room, player, taskType, taskId
[NEW] player/TaskProgress.ts — player.taskprogress
Fields: room, player, taskId, progress
[NEW] player/TaskCompleted.ts — player.taskcompleted
Fields: room, player, taskType, taskId, isLongTask
[NEW] player/LevelChanged.ts — player.levelchanged
Fields: room, player, oldLevel, newLevel
Emitted in Room.on("player.setlevel") handler
[NEW] player/MurderFail.ts — player.murderfail
Fields: room, player (killer), target, reason, details?
Emitted from Room.on("player.checkmurder") when murder is invalid
[MODIFY] events/room/index.ts — export HideAndSeekStart, HideAndSeekEnd,
HiderCaught
[NEW] events/player/index.ts — export all new player events
[MODIFY] events/index.ts — export player module
=== HTTP Matchmaker (src/Matchmaker.ts) [MODIFY] ===
[NEW] GET / — server dashboard HTML page
Shows: room/player/connection/plugin counts, public room list table,
API endpoint reference. Dark theme, zero external CSS.
[ENHANCE] GET /api/games/:id — now returns full room info
+ Players array: clientId, username, color, hat, skin, visor,
isHost, isDead
+ GameState, GameMode, Privacy strings
[FIX] GET /api/filtertags — was stub returning [], now dynamic
+ Scans active rooms for maps, languages, game modes
+ Merges with configurable static filterTags from server config
+ Returns FilterTagJson[] with Name, DisplayName, Type, Count
[NEW] POST /api/games/:id/refresh — room metadata refresh
+ Host can update privacy and room name
+ Returns updated GameListingJson
=== Config Updates (src/WaterwayServer.ts, bin/createDefaultConfig.ts) [MODIFY] ===
[ADD] GameListingConfig.filterTags
Type: { name: string; displayName: string; icon?: string }[]
Served by GET /api/filtertags as static filter buttons
[ADD] RoomsConfig.allowedGameModes
Type: number[] — restrict which game modes rooms can use
Empty array = all modes allowed
[ADD] RoomsConfig.defaultGameMode
Type: number — game mode for new rooms (default 1 = Normal)
[ENHANCE] Room constructor applies enforceSettings from config on creation
Settings in enforceSettings cannot be overridden by host
[MODIFY] bin/createDefaultConfig.ts — all new fields with defaults
=== Room Integration (src/Room.ts) [MODIFY] ===
+ gameModeManager property — active game mode handler (HideAndSeekManager)
+ roleManager property — role assignment and lifecycle
+ Validates game options on player.syncsettings (rejects invalid)
+ Emits PlayerLevelChangedEvent on player.setlevel
+ Emits PlayerTaskCompletedEvent on player.completetask
+ Emits PlayerMurderFailEvent on player.checkmurder (when !isValid)
+ Routes kill/task/death through roleManager
+ Routes RPCs through gameModeManager
+ Cleanup in _reset() and destroy()
=== Verification ===
- TypeScript compilation passes cleanly (tsc --noEmit exits 0)
- All events follow existing Waterway event patterns
- Role classes extend Waterway BaseRole (server-side), not SkeldJS BaseRole
Updated Dockerfile to allow branch specification for cloning SkeldJS.
…ting
2 +
3 +=== [FIX] Room Privacy Inverted (src/Room.ts) ===
4 + - finishJoiningGame() sent AlterGame(ChangePrivacy, 1) when room was Private
5 + because the ternary mapped RoomPrivacy.Private(=1) -> value 1, but in the
6 + Among Us protocol, value 1 means Public.
7 + - Result: every newly-joined player received an initial AlterGame telling them
8 + the room was public when it was actually private. Manual toggle by host
9 + fixed it because handleAlterGameMessage() (correct path) was then used.
10 + - Fix: change ternary from "RoomPrivacy.Private ? 1 : 0" to
11 + "RoomPrivacy.Public ? 1 : 0"
12 +
13 +=== [FIX] Missing QuickChat in HTTP Matchmaker (src/Matchmaker.ts) ===
14 + - GameListingJson type was missing the QuickChat field that Among Us clients
15 + read from the HTTP /api/games response to determine chat mode.
16 + - getGameListing() now sets QuickChat from the host connection's chatMode.
17 + - Without this, joining clients defaulted to QuickChatOnly display.
18 +
19 +=== [FIX] Missing Language field in UDP GameListing (src/WaterwayServer.ts) ===
20 + - UDP game listing now passes room.settings.keywords as Language to the
21 + GameListing constructor (11th arg, cast to any for npm compat until
22 + SkeldJS protocol update is published).
…t system, role completion, and RPC fixes. - handleRpcMessage(): In SaaH mode, block the original message broadcast after receiving ReportDeadBody - The server has already initiated StartMeeting + MeetingHud spawn via startMeetingWithAuth - Prevent the client from receiving duplicate ReportDeadBody + StartMeeting, eliminating double report UI - Fix the issue where non-host players cannot enter the meeting - handleRpcMessage(): Add import for ReportDeadBodyMessage - processFixedUpdate(): Call roleManager.handleFixedUpdate() to drive role timers - processFixedUpdate(): Call gameModeManager's fixed update (type-safe check) - player.startmeeting event: Add roleManager.handleMeetingStart() call - Add ReportDeadBodyMessage to @skeldjs/au-protocol imports - Three-level cache matching strategy: (IP + username) → username only → IP only - Support expiration cleanup, manual removal, on-demand lookup - Default TTL: 10 minutes - Storage: puid, friendCode, username, ip, clientVersion, expiresAt - New fields: puid: string, friendCode: string, isAuthenticated: boolean - Constructor initializes them as empty - disconnect() cleanup resets all authentication fields - Parse JWT from Authorization: Bearer <eosToken> header - extractPuidFromJwt(): Base64URL-decode JWT payload, extract sub claim - Call Innersloth backend to obtain FriendCode - fetchFriendCodeFromBackend(): HTTPS GET backend.innersloth.com/api/user/username - Support both JSON:API and flat response formats - 15-second timeout - generateFallbackFriendCode(): Generate stable fallback code based on SHA-256 hash of PUID - Store in AuthCache for UDP handshake matching - Support X-Real-IP / X-Forwarded-For reverse proxy headers - Preserve body.Puid fallback path (legacy) - New imports: https, AuthCache - handleHello(): After client authentication, look up AuthCache by (remoteIP, username) - On match: set connection.puid, connection.friendCode, connection.isAuthenticated - Remove from cache after match (single-use) - Three-tier fallback: IP+username → username → IP - handleJoin(): Pass friendCode and puid parameters when constructing Player - handleRemoteJoin(): PlayerJoinData includes puid and friendCode - Crewmate role, passive ability - Client automatically displays Vitals UI after recognizing via SetRole RPC - No special server-side logic - Crewmate role, can use vents - Track ventUsesRemaining (from roleSettings.engineerVentUses / crewmateVentUses) - onVentUse(): Check and decrement usage count - Crewmate role, can shield alive players - Shield duration from guardianAngelProtectionDuration setting - Cooldown from guardianAngelCooldown setting - onAbilityUse(): Set protection state via PlayerControl - onFixedUpdate(): Drive cooldown timer - onDeath(): Remove current protection - Impostor role, can shapeshift into other players' appearances - Shift duration from shapeshifterDuration setting - Cooldown from shapeshifterCooldown setting - onAbilityUse(): Save original appearance → apply target appearance - revertTransform(): Restore original appearance → push PlayerInfo update - onFixedUpdate(): Drive shapeshift timer and cooldown - Add Scientist, Engineer, GuardianAngel, Shapeshifter to ROLE_CONSTRUCTORS - Add Crewmate to isCrewmateRole - Add Impostor to isImpostorRole - Add ScientistRole, EngineerRole, GuardianAngelRole, ShapeshifterRole exports - onDeath(): Trigger vanishWithAuth() RPC instead of just sending chat message - endVanish(): Trigger appearWithAuth() RPC + causeToDie for official death - onFixedUpdate(): Drive vanish timer and cooldown - Remove all setTimeout, use fixed update timers instead - onKill(): Poison delay, track poisoned players and remaining time via Map - onFixedUpdate(): Countdown dissolution, call causeToDie - dissolveTarget(): Execute dissolution kill - Remove setTimeout, use fixed update timers instead - onFixedUpdate(): Drive tracking duration, position update interval, cooldown - sendPositionUpdate(): Read target CustomNetworkTransform to get position - Remove setInterval, use fixed update instead - onFixedUpdate(): Drive alarm effect timer and cooldown - Remove setTimeout dependency - onFixedUpdate(): Drive cooldown timer - onGameStart(): Register player.murder listener to track kill records - Remove setInterval dependency - Among Us native /cmd chat command handler - Built-in commands: - /cmd help — Show available commands - /cmd list — List room players (with FriendCode) - /cmd kick <player> — Kick a player - /cmd ban <player> — Ban a player - /cmd room <name> — Set room name - /cmd public — Make room public - /cmd private — Make room private - CmdContext: Supports reply (visible only to sender) and broadcast (entire room) - Player lookup: Supports fuzzy username matching and exact ClientID matching - Authentication requirement: kick/ban/room/public/private require isAuthenticated - Extensible: register() method for plugins to register custom commands - Add cmdHandler: CmdHandler field and instantiate it - handleRpcMessage(): Detect /cmd messages from non-authority players - Call cmdHandler.handleMessage() to process the command - Suppress broadcast (aligns with Impostor /cmd being host-only visible) - player.chat event: Skip /cmd messages (avoid duplicate processing with CmdHandler)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Support lastest Among Us version
Fix a lot of bug(still have some)