mirror of
https://github.com/djdevin/recflare.git
synced 2026-09-09 15:11:29 -07:00
[notify] add documentation on push shapes
This commit is contained in:
@@ -0,0 +1,581 @@
|
|||||||
|
/**
|
||||||
|
* The `Msg` bodies the client expects behind each {@link NotificationType}.
|
||||||
|
*
|
||||||
|
* Recovered from the client's Utf8Json generated formatters (see `recnet-patcher`,
|
||||||
|
* `il2cpp-tools/dtoshape.py`), not from a spec. Three properties of that decoder decide how
|
||||||
|
* much these matter:
|
||||||
|
*
|
||||||
|
* - **Every key is accepted in three casings** — Original, camelCase and all-lowercase. So
|
||||||
|
* `RoomId`, `roomId` and `roomid` are the same field. The spelling used below is the
|
||||||
|
* client's own canonical one.
|
||||||
|
* - **Unknown members are dropped in silence.** A typo'd key behaves exactly like an omitted
|
||||||
|
* one, which is why a wrong payload shows up as a blank UI rather than an error.
|
||||||
|
* - **A missing nested object is worse than a missing scalar.** Several handlers dereference
|
||||||
|
* one level down with no null guard, so omitting a nested field surfaces as a bare
|
||||||
|
* `NullReferenceException` in the client. Send a stub rather than nothing.
|
||||||
|
*
|
||||||
|
* Field *names* below are verified. Where a payload's type mapping could not be pinned down
|
||||||
|
* as confidently as its key list, the interface says so on the member.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/** How a balance came to change. Log/telemetry only on the purchase frame — see below. */
|
||||||
|
export enum BalanceAddType {
|
||||||
|
Invalid = 0,
|
||||||
|
DirectBalanceWithMultiplier = 1,
|
||||||
|
FromGiftBox = 2,
|
||||||
|
NUXChallenge = 10,
|
||||||
|
AllNUXChallenges = 11,
|
||||||
|
DailyChallenge = 100,
|
||||||
|
AllDailyChallenges = 101,
|
||||||
|
FinishActivity = 200,
|
||||||
|
RecRoyaleMatchFinished = 250,
|
||||||
|
ChecklistCredit = 303,
|
||||||
|
WonGame = 1000,
|
||||||
|
LostGame = 1001,
|
||||||
|
WonGameRateLimited = 1002,
|
||||||
|
WonGamePartial = 1003,
|
||||||
|
LevelUp = 1100,
|
||||||
|
Registered = 1200,
|
||||||
|
CreatorReward = 1300,
|
||||||
|
CommercePurchase = 1400,
|
||||||
|
CommercePurchaseRevoked = 1401,
|
||||||
|
ManualRefund = 2000,
|
||||||
|
ManualThanks = 2010,
|
||||||
|
ManualApology = 2020,
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Which store a balance belongs to. Note the **wire key is `Platform`, not `BalanceType`** —
|
||||||
|
* the client's property is called `BalanceType` but carries a `[DataMember]` rename, so
|
||||||
|
* `balanceType` on the wire is dropped and the balance silently reads as `SteamPurchased`.
|
||||||
|
*
|
||||||
|
* Balances are held per `(CurrencyType, Platform)` pair, so this also selects which bucket a
|
||||||
|
* balance frame updates. `RecNetPurchased` is the one to use for a self-hosted store.
|
||||||
|
*/
|
||||||
|
export enum BalancePlatform {
|
||||||
|
NonPurchasedNotUsableInP2P = -2,
|
||||||
|
NonPurchasedDefault = -1,
|
||||||
|
SteamPurchased = 0,
|
||||||
|
OculusPurchased = 1,
|
||||||
|
PlayStationPurchased = 2,
|
||||||
|
MicrosoftPurchased = 3,
|
||||||
|
RecNetPurchased = 4,
|
||||||
|
IOSPurchased = 5,
|
||||||
|
GooglePlayPurchased = 6,
|
||||||
|
PicoPurchased = 8,
|
||||||
|
PlayStationNonPurchasedP2P = 100,
|
||||||
|
NonPlayStationNonPurchasedP2P = 101,
|
||||||
|
NonPurchasedEarnedByP2P = 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum CurrencyType {
|
||||||
|
Invalid = 0,
|
||||||
|
LaserTagTickets = 1,
|
||||||
|
RecCenterTokens = 2,
|
||||||
|
LostSkullsGold = 100,
|
||||||
|
DraculaSilver = 101,
|
||||||
|
RecRoyaleSeason1 = 200,
|
||||||
|
RoomCurrency = 300,
|
||||||
|
ProgressionEvent = 400,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Why a player was kicked/banned/warned. Shared by ModerationKick and ModerationUnkick. */
|
||||||
|
export enum KickReportCategory {
|
||||||
|
Moderator = -1,
|
||||||
|
Unknown = 0,
|
||||||
|
DeprecatedMicrophoneAbuse = 1,
|
||||||
|
Harassment = 2,
|
||||||
|
Cheating = 3,
|
||||||
|
DeprecatedImmatureBehavior = 4,
|
||||||
|
AFK = 5,
|
||||||
|
Misc = 6,
|
||||||
|
Underage = 7,
|
||||||
|
VoteKick = 10,
|
||||||
|
MisleadingPurchases = 11,
|
||||||
|
CoCUnderage = 100,
|
||||||
|
CoCSexual = 101,
|
||||||
|
CoCDiscrimination = 102,
|
||||||
|
CoCTrolling = 103,
|
||||||
|
CoCNameOrProfile = 104,
|
||||||
|
InappropriateClothing = 200,
|
||||||
|
IssuingInaccurateReports = 1000,
|
||||||
|
}
|
||||||
|
|
||||||
|
export enum LogoutReason {
|
||||||
|
Unknown = 0,
|
||||||
|
UserInitiated = 1,
|
||||||
|
SessionTakeover = 2,
|
||||||
|
ForciblyLoggedOut = 3,
|
||||||
|
Banned = 4,
|
||||||
|
}
|
||||||
|
|
||||||
|
/** The error the client renders when a `GoTo` fails. */
|
||||||
|
export enum GoToFailureError {
|
||||||
|
UnknownError = -1,
|
||||||
|
Success = 0,
|
||||||
|
NoSuchGame = 1,
|
||||||
|
PlayerNotOnline = 2,
|
||||||
|
InsufficientSpace = 3,
|
||||||
|
EventNotStarted = 4,
|
||||||
|
EventAlreadyFinished = 5,
|
||||||
|
BlockedFromRoom = 7,
|
||||||
|
JuniorNotAllowed = 11,
|
||||||
|
Banned = 12,
|
||||||
|
AlreadyInBestInstance = 13,
|
||||||
|
InsufficientRelationship = 14,
|
||||||
|
UpdateRequired = 16,
|
||||||
|
AlreadyInTargetInstance = 17,
|
||||||
|
UGCNotAllowed = 19,
|
||||||
|
NoSuchRoom = 20,
|
||||||
|
RoomIsNotActive = 22,
|
||||||
|
RoomBlockedByCreator = 23,
|
||||||
|
RoomIsPrivate = 25,
|
||||||
|
RoomInstanceIsPrivate = 26,
|
||||||
|
DeviceClassNotSupported = 30,
|
||||||
|
DeviceClassNotSupportedByRoomOwner = 31,
|
||||||
|
MovementModeNotSupportedByRoomOwner = 32,
|
||||||
|
EventIsPrivate = 35,
|
||||||
|
EventIsFull = 36,
|
||||||
|
RoomInviteExpired = 40,
|
||||||
|
NoAvailableRegion = 45,
|
||||||
|
}
|
||||||
|
|
||||||
|
// ---- Payloads ------------------------------------------------------------------
|
||||||
|
|
||||||
|
/** `StorefrontBalancePurchase` (62). */
|
||||||
|
export interface PurchaseBalanceModificationPayload {
|
||||||
|
BalanceAddType: BalanceAddType
|
||||||
|
/**
|
||||||
|
* The change, **for display only** — the client does not apply it. Its handler logs a
|
||||||
|
* line and then stores {@link Balance} outright, so a correct `Delta` with a stale
|
||||||
|
* `Balance` leaves the player's balance wrong.
|
||||||
|
*/
|
||||||
|
Delta: number
|
||||||
|
/** The post-transaction total. Absolute, and the only field that changes client state. */
|
||||||
|
Balance: number
|
||||||
|
Platform: BalancePlatform
|
||||||
|
CurrencyType: CurrencyType
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `StorefrontBalanceUpdate` (61) — a bare set of one bucket to an absolute value. */
|
||||||
|
export interface BalanceResponsePayload {
|
||||||
|
Balance: number
|
||||||
|
CurrencyType: CurrencyType
|
||||||
|
Platform: BalancePlatform
|
||||||
|
}
|
||||||
|
|
||||||
|
/** One element of the `StorefrontBalanceAdd` (60) batch. */
|
||||||
|
export interface RewardBalanceModificationPayload {
|
||||||
|
BalanceAddType: BalanceAddType
|
||||||
|
BaseAward: number
|
||||||
|
BonusAward: number
|
||||||
|
RateLimit: number
|
||||||
|
CurrentCount: number
|
||||||
|
Total: number
|
||||||
|
Platform: BalancePlatform
|
||||||
|
BalanceInGiftBox: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ConsumableMappingAdded` (70) / `ConsumableMappingRemoved` (71). */
|
||||||
|
export interface ConsumableMappingPayload {
|
||||||
|
Id: number
|
||||||
|
ConsumableItemDesc: string
|
||||||
|
Count: number
|
||||||
|
InitialCount: number
|
||||||
|
/** ISO-8601. */
|
||||||
|
CreatedAt: string
|
||||||
|
ActiveDurationMinutes: number | null
|
||||||
|
IsActive: boolean
|
||||||
|
IsTransferable: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ModerationKick` (22) and `ModerationUnkick`. Room bans go out as this with `IsBan`. */
|
||||||
|
export interface ModerationKickPayload {
|
||||||
|
ReportCategory: KickReportCategory
|
||||||
|
/** Seconds. */
|
||||||
|
Duration: number
|
||||||
|
GameSessionId: number
|
||||||
|
IsHostKick: boolean
|
||||||
|
Message: string
|
||||||
|
PlayerIdReporter: number | null
|
||||||
|
IsBan: boolean
|
||||||
|
IsVoiceModAutoban: boolean
|
||||||
|
IsWarning: boolean
|
||||||
|
VoteKickReason: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
TimeoutStartedAt: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ModerationKickAttemptFailed` (23) — a vote-kick that didn't carry. */
|
||||||
|
export interface ModerationKickFailedPayload {
|
||||||
|
ReportCategory: KickReportCategory
|
||||||
|
YesVotes: number
|
||||||
|
NoVotes: number
|
||||||
|
PlayerIdReported: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ServerMaintenance` (25). */
|
||||||
|
export interface ServerMaintenancePayload {
|
||||||
|
StartsInMinutes: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `Logout` (6). */
|
||||||
|
export interface LogoutPayload {
|
||||||
|
Reason: LogoutReason
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `MessageDeleted` (3) — the id of the message to drop. */
|
||||||
|
export interface MessageDeletedPayload {
|
||||||
|
Id: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `MessageReceived` (2). */
|
||||||
|
export interface MessageReceivedPayload {
|
||||||
|
Id: number
|
||||||
|
FromPlayerId: number
|
||||||
|
/** ISO-8601. */
|
||||||
|
SentTime: string
|
||||||
|
Type: number
|
||||||
|
Data: string
|
||||||
|
RoomId: number | null
|
||||||
|
PlayerEventId: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `RelationshipChanged` (1). */
|
||||||
|
export interface RelationshipChangedPayload {
|
||||||
|
/** Note the spelling — capital `ID`, unlike every other id key on the wire. */
|
||||||
|
PlayerID: number
|
||||||
|
RelationshipType: number
|
||||||
|
Muted: boolean
|
||||||
|
Ignored: boolean
|
||||||
|
Favorited: boolean
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `PlayerEventDeleted` (82) / `PlayerEventResponseDeleted` (84). */
|
||||||
|
export interface PlayerEventIdPayload {
|
||||||
|
PlayerEventId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `PlayerEventResponseChanged` (83). */
|
||||||
|
export interface PlayerEventResponsePayload {
|
||||||
|
PlayerEvent: Record<string, unknown>
|
||||||
|
PlayerEventResponse: Record<string, unknown>
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `PlayerEventCreated` (80) / `PlayerEventUpdated` (81). */
|
||||||
|
export interface PlayerEventPayload {
|
||||||
|
Tags: unknown[]
|
||||||
|
PlayerEventId: number
|
||||||
|
CreatorPlayerId: number
|
||||||
|
RoomId: number
|
||||||
|
SubRoomId: number | null
|
||||||
|
ClubId: number | null
|
||||||
|
Name: string
|
||||||
|
Description: string
|
||||||
|
ImageName: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
StartTime: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
EndTime: string
|
||||||
|
AttendeeCount: number
|
||||||
|
Accessibility: number
|
||||||
|
IsMultiInstance: boolean
|
||||||
|
SupportMultiInstanceRoomChat: boolean
|
||||||
|
DefaultBroadcastPermissions: number
|
||||||
|
CanRequestBroadcastPermissions: number
|
||||||
|
BroadcastingRoomInstanceId: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `PlayerProgressionLevelUpdate`. `XP` is progress into the level, not a lifetime total. */
|
||||||
|
export interface PlayerProgressionLevelPayload {
|
||||||
|
PlayerId: number
|
||||||
|
Level: number
|
||||||
|
XP: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ProgressionEventsRecordUpdate`. */
|
||||||
|
export interface ProgressionEventRecordPayload {
|
||||||
|
AccountId: number
|
||||||
|
Xp: number
|
||||||
|
GameMinutesToday: number
|
||||||
|
RewardsCollected: number
|
||||||
|
BonusRewardsCollected: number
|
||||||
|
/** ISO-8601. */
|
||||||
|
XpBoostLastPurchasedAt: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `SubscriptionUpdateProfile` (`"AccountUpdate"`) — the public projection of an account.
|
||||||
|
* The `Obscured*` CodeStage wrappers on the client side serialise as their plain underlying
|
||||||
|
* value, so nothing special is needed on the wire.
|
||||||
|
*/
|
||||||
|
export interface AccountUpdatePayload {
|
||||||
|
AccountId: number
|
||||||
|
UserName: string
|
||||||
|
DisplayName: string
|
||||||
|
DisplayEmoji: string
|
||||||
|
ProfileImage: string
|
||||||
|
BannerImage: string
|
||||||
|
TreatAsJunior: boolean
|
||||||
|
HasBirthday: boolean
|
||||||
|
PersonalPronouns: number
|
||||||
|
IdentityFlags: number
|
||||||
|
/** Lowercase-camel on the client's canonical spelling, unlike its neighbours. */
|
||||||
|
createdAt: string
|
||||||
|
IsJunior: boolean | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `SubscriptionUpdateSelfProfile` (`"SelfAccountUpdate"`) — the owner-only projection: the
|
||||||
|
* six private fields **first**, then every field of {@link AccountUpdatePayload}. That order
|
||||||
|
* is not cosmetic; the client's decoder emits a derived DTO's own members before its base's.
|
||||||
|
*/
|
||||||
|
export interface SelfAccountUpdatePayload extends AccountUpdatePayload {
|
||||||
|
Email: string
|
||||||
|
Phone: string
|
||||||
|
/** ISO-8601. Its absence is what caused the under-13 junior crash. */
|
||||||
|
Birthday: string | null
|
||||||
|
JuniorState: number
|
||||||
|
ParentAccountId: number | null
|
||||||
|
AvailableUsernameChanges: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ChatMessageReceived` and `PlayerLeftChat` — same shape. */
|
||||||
|
export interface ChatMessagePayload {
|
||||||
|
ChatMessageId: number
|
||||||
|
ChatThreadId: number
|
||||||
|
SenderPlayerId: number
|
||||||
|
/** ISO-8601. */
|
||||||
|
TimeSent: string
|
||||||
|
Contents: string
|
||||||
|
ModerationState: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ClubMembershipUpdate`. */
|
||||||
|
export interface ClubMembershipPayload {
|
||||||
|
ClubId: number
|
||||||
|
MembershipType: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `CreatorClubSubscriptionUpdate`. */
|
||||||
|
export interface CreatorClubSubscriptionPayload {
|
||||||
|
CreatorAccountId: number
|
||||||
|
ClubId: number
|
||||||
|
MembershipType: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `RoomCurrencyCreated` / `RoomCurrencyModified`. */
|
||||||
|
export interface RoomCurrencyPayload {
|
||||||
|
CurrencyId: string
|
||||||
|
RoomId: number | null
|
||||||
|
Name: string
|
||||||
|
Description: string
|
||||||
|
CurrencyType: CurrencyType
|
||||||
|
Limit: number
|
||||||
|
ImageName: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
CreatedAt: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
ModifiedAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `RoomCurrencyDeleted`. */
|
||||||
|
export interface RoomCurrencyDeletedPayload {
|
||||||
|
CurrencyId: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `LocalRoomKeyCreated` (120). */
|
||||||
|
export interface LocalRoomKeyPayload {
|
||||||
|
RoomKeyId: number
|
||||||
|
ReplicationId: string
|
||||||
|
RoomId: number
|
||||||
|
Name: string
|
||||||
|
Description: string
|
||||||
|
Price: number
|
||||||
|
PurchaseCurrencyId: string | null
|
||||||
|
/** ISO-8601. */
|
||||||
|
CreatedAt: string
|
||||||
|
ImageName: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `LocalRoomKeyDeleted` (121). */
|
||||||
|
export interface LocalRoomKeyDeletedPayload {
|
||||||
|
RoomKeyId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `AnnouncementUpdate`. */
|
||||||
|
export interface AnnouncementPayload {
|
||||||
|
AnnouncementId: number
|
||||||
|
AnnouncementType: number
|
||||||
|
Title: string
|
||||||
|
Body: string
|
||||||
|
ImageName: string
|
||||||
|
LinkType: number
|
||||||
|
LinkName: string
|
||||||
|
LinkButtonLabel: string
|
||||||
|
LinkUri: string
|
||||||
|
Platform: number
|
||||||
|
/** ISO-8601. */
|
||||||
|
CreatedAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `AnnouncementDelete`. */
|
||||||
|
export interface AnnouncementDeletePayload {
|
||||||
|
AnnouncementId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `CommunityBoardAnnouncementUpdate` (96) — the board's single current announcement. */
|
||||||
|
export interface CommunityBoardAnnouncementPayload {
|
||||||
|
Message: string
|
||||||
|
MoreInfoUrl: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `ReputationUpdate`. */
|
||||||
|
export interface ReputationPayload {
|
||||||
|
AccountId: number
|
||||||
|
IsCheerful: boolean
|
||||||
|
SelectedCheer: number | null
|
||||||
|
CheerCredit: number
|
||||||
|
CheerGeneral: number
|
||||||
|
CheerHelpful: number
|
||||||
|
CheerCreative: number
|
||||||
|
CheerGreatHost: number
|
||||||
|
CheerSportsman: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `PhotonAccessToken`. */
|
||||||
|
export interface PhotonAccessTokenPayload {
|
||||||
|
RoomInstanceId: number
|
||||||
|
PhotonAccessToken: string
|
||||||
|
Permissions: unknown[]
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `KeepsakeInstanceAdded` / `KeepsakeInstanceRemoved`. */
|
||||||
|
export interface KeepsakeInstancePayload {
|
||||||
|
KeepsakeInstanceId: string
|
||||||
|
KeepsakeCategoryConfigId: number
|
||||||
|
PlacedByAccountId: number
|
||||||
|
RoomId: number
|
||||||
|
SubRoomId: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `PlayerCustomAvatarItemModerated`. */
|
||||||
|
export interface CustomAvatarItemPayload {
|
||||||
|
CustomAvatarItemId: string
|
||||||
|
CreatorAccountId: number
|
||||||
|
Name: string
|
||||||
|
Description: string
|
||||||
|
Price: number
|
||||||
|
Accessibility: number
|
||||||
|
IsFeatured: boolean
|
||||||
|
BaseAvatarItemId: number | null
|
||||||
|
BaseAvatarItemColor: string
|
||||||
|
DesignFilename: string
|
||||||
|
ThumbnailImageFilename: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
CreatedAt: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
ModifiedAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `GoToFailure`. */
|
||||||
|
export interface GoToFailurePayload {
|
||||||
|
Error: GoToFailureError
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `AppVersionUpdate` — the live replacement for the dead `ModerationUpdateRequired` (21). */
|
||||||
|
export interface AppVersionUpdatePayload {
|
||||||
|
ActivePlatforms: unknown
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `IncentivizedReferralUpdate`. */
|
||||||
|
export interface IncentivizedReferralPayload {
|
||||||
|
InviteeAccountId: number
|
||||||
|
/** ISO-8601. */
|
||||||
|
CreatedAt: string
|
||||||
|
/** ISO-8601. */
|
||||||
|
VerifiedAt: string | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `InfluencerSupportedUpdate`. */
|
||||||
|
export interface InfluencerSupportedPayload {
|
||||||
|
SupportedInfluencerId: number | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `StringAutoLocalizationJob`. */
|
||||||
|
export interface StringAutoLocalizationJobPayload {
|
||||||
|
Scope: string
|
||||||
|
Status: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `SubscriptionUpdateGameSession` (`"RoomInstanceUpdate"`). */
|
||||||
|
export interface RoomInstanceUpdatePayload {
|
||||||
|
RoomInstanceId: number
|
||||||
|
RoomId: number
|
||||||
|
SubRoomId: number
|
||||||
|
Location: string
|
||||||
|
EventId: number
|
||||||
|
ClubId: number
|
||||||
|
RoomCode: string
|
||||||
|
/** Canonical spelling is lower-camel here, unlike its neighbours. */
|
||||||
|
photonRegionId: string
|
||||||
|
PhotonRoomId: string
|
||||||
|
Name: string
|
||||||
|
MaxCapacity: number
|
||||||
|
IsFull: boolean
|
||||||
|
IsPrivate: boolean
|
||||||
|
IsInProgress: boolean
|
||||||
|
EncryptVoiceChat: boolean
|
||||||
|
RoomInstanceType: number
|
||||||
|
MatchmakingPolicy: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* `GiftPackageReceived` (30), `GiftPackageReceivedImmediate` (31) and
|
||||||
|
* `GiftPackageRewardSelectionReceived` (32) all carry this. Note `BalanceType` here is NOT
|
||||||
|
* the renamed-to-`Platform` field seen on the balance payloads — it is its own member and
|
||||||
|
* keeps its name; `Platform` is a separate key on the same object.
|
||||||
|
*/
|
||||||
|
export interface GiftPackagePayload {
|
||||||
|
Id: number | null
|
||||||
|
FromPlayerId: number | null
|
||||||
|
ConsumableItemDesc: string
|
||||||
|
AvatarItemType: number | null
|
||||||
|
AvatarItemDesc: string
|
||||||
|
EquipmentPrefabName: string
|
||||||
|
EquipmentModificationGuid: string
|
||||||
|
CurrencyType: CurrencyType
|
||||||
|
Currency: number
|
||||||
|
Xp: number
|
||||||
|
GiftContext: number
|
||||||
|
GiftRarity: number
|
||||||
|
Message: string
|
||||||
|
Platform: number
|
||||||
|
PlatformsToSpawnOn: unknown
|
||||||
|
BalanceType: BalancePlatform | null
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `gift.manualconsumed`. */
|
||||||
|
export interface GiftManualConsumedPayload {
|
||||||
|
GiftPackageId: number
|
||||||
|
}
|
||||||
|
|
||||||
|
/** `RewardSelectionReceived` — distinct from the gift-package frames above. */
|
||||||
|
export interface RewardSelectionPayload {
|
||||||
|
RewardSelectionId: number
|
||||||
|
RewardType: number
|
||||||
|
Message: string
|
||||||
|
GiftContext: number
|
||||||
|
GiftDrop1: unknown
|
||||||
|
GiftDrop2: unknown
|
||||||
|
GiftDrop3: unknown
|
||||||
|
Subscriber_GiftDrop3: unknown
|
||||||
|
/** ISO-8601. */
|
||||||
|
CreatedAt: string
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Channels whose handler takes no argument at all — the client refetches rather than reading
|
||||||
|
* the frame. Send `{}`; anything else is ignored.
|
||||||
|
*/
|
||||||
|
export type NoPayload = Record<string, never>
|
||||||
@@ -13,12 +13,32 @@
|
|||||||
* Lives in the `notify` worker (the hub owner); other workers import it to send a
|
* Lives in the `notify` worker (the hub owner); other workers import it to send a
|
||||||
* typed notification instead of a magic number. No runtime dependencies, so it's safe
|
* typed notification instead of a magic number. No runtime dependencies, so it's safe
|
||||||
* to import as a value from another worker's bundle.
|
* to import as a value from another worker's bundle.
|
||||||
|
*
|
||||||
|
* ## How this was verified
|
||||||
|
*
|
||||||
|
* Every member below was checked against the client's own subscription table, recovered by
|
||||||
|
* static analysis of `GameAssembly.dll` (see `recnet-patcher`, `il2cpp-tools/regall.py`).
|
||||||
|
* The client registers each channel by key — a decimal string for numeric ids, a name for
|
||||||
|
* the rest — and **a key with no subscriber is dropped in silence**: the frame parses, no
|
||||||
|
* handler runs, nothing is logged. So "the client ignores this" is indistinguishable from
|
||||||
|
* "the server never sent it" at runtime, which is why the status is recorded here instead.
|
||||||
|
*
|
||||||
|
* Members marked `@deadOnClient` have no subscriber in the build this was taken from
|
||||||
|
* (20230414-era, `GameAssembly.dll` 156,069,888 bytes). They are kept because they name a
|
||||||
|
* real client enum member and may come back in another build — but sending one today is a
|
||||||
|
* no-op. Everything not so marked was confirmed to have a live handler.
|
||||||
*/
|
*/
|
||||||
export enum NotificationType {
|
export enum NotificationType {
|
||||||
RelationshipChanged = 1,
|
RelationshipChanged = 1,
|
||||||
MessageReceived = 2,
|
MessageReceived = 2,
|
||||||
MessageDeleted = 3,
|
MessageDeleted = 3,
|
||||||
|
/**
|
||||||
|
* @deadOnClient No subscriber, and unlike its neighbours it has no wire-name twin either —
|
||||||
|
* the string `PresenceHeartbeat…` does not appear anywhere in the client's metadata. The
|
||||||
|
* heartbeat response has nowhere to land in this build.
|
||||||
|
*/
|
||||||
PresenceHeartbeatResponse = 4,
|
PresenceHeartbeatResponse = 4,
|
||||||
|
/** Also reachable as the wire name `"PlayerPrivileges.Refresh"` — same handler. */
|
||||||
RefreshLogin = 5,
|
RefreshLogin = 5,
|
||||||
Logout = 6,
|
Logout = 6,
|
||||||
SubscriptionUpdateProfile = 'AccountUpdate',
|
SubscriptionUpdateProfile = 'AccountUpdate',
|
||||||
@@ -28,6 +48,9 @@ export enum NotificationType {
|
|||||||
* sends both on connect and after a profile mutation — everyone gets the public frame,
|
* sends both on connect and after a profile mutation — everyone gets the public frame,
|
||||||
* the owner additionally gets this one. Named after its twin rather than after a client
|
* the owner additionally gets this one. Named after its twin rather than after a client
|
||||||
* enum member, since the client's enum doesn't list it; the WIRE name is what matters.
|
* enum member, since the client's enum doesn't list it; the WIRE name is what matters.
|
||||||
|
*
|
||||||
|
* Confirmed live: the client subscribes `"SelfAccountUpdate"` and the payload is the
|
||||||
|
* public account DTO plus six owner-only fields. See `SelfAccountUpdatePayload`.
|
||||||
*/
|
*/
|
||||||
SubscriptionUpdateSelfProfile = 'SelfAccountUpdate',
|
SubscriptionUpdateSelfProfile = 'SelfAccountUpdate',
|
||||||
SubscriptionUpdatePresence = 'PresenceUpdate',
|
SubscriptionUpdatePresence = 'PresenceUpdate',
|
||||||
@@ -39,16 +62,29 @@ export enum NotificationType {
|
|||||||
* stringifies whatever it is given, so `15` would go out as the unrelated `"15"`.
|
* stringifies whatever it is given, so `15` would go out as the unrelated `"15"`.
|
||||||
*/
|
*/
|
||||||
SubscriptionUpdateRoom = 'RoomUpdate',
|
SubscriptionUpdateRoom = 'RoomUpdate',
|
||||||
/** Unverified: nothing sends it here, and the reference's hub never puts it on the wire. */
|
/** @deadOnClient No subscriber under `16` and no wire-name twin. */
|
||||||
SubscriptionUpdateRoomPlaylist = 16,
|
SubscriptionUpdateRoomPlaylist = 16,
|
||||||
ModerationQuitGame = 20,
|
ModerationQuitGame = 20,
|
||||||
|
/**
|
||||||
|
* @deadOnClient Nothing listens on `21`. {@link AppVersionUpdate} is the live channel
|
||||||
|
* that does this job — same handler class, addressed by name.
|
||||||
|
*/
|
||||||
ModerationUpdateRequired = 21,
|
ModerationUpdateRequired = 21,
|
||||||
ModerationKick = 22,
|
ModerationKick = 22,
|
||||||
ModerationKickAttemptFailed = 23,
|
ModerationKickAttemptFailed = 23,
|
||||||
|
/**
|
||||||
|
* @deadOnClient Not present in this build at all: no subscriber on `24`, and the string
|
||||||
|
* `"ModerationRoomBan"` does not exist in the client's metadata, so neither spelling can
|
||||||
|
* be dispatched. To ban from a room, use {@link ModerationKick} with `IsBan: true`.
|
||||||
|
*/
|
||||||
ModerationRoomBan = 'ModerationRoomBan',
|
ModerationRoomBan = 'ModerationRoomBan',
|
||||||
ServerMaintenance = 25,
|
ServerMaintenance = 25,
|
||||||
GiftPackageReceived = 30,
|
GiftPackageReceived = 30,
|
||||||
GiftPackageReceivedImmediate = 31,
|
GiftPackageReceivedImmediate = 31,
|
||||||
|
/**
|
||||||
|
* Carries a gift package like its two neighbours. Distinct from
|
||||||
|
* {@link RewardSelectionReceived}, which is a different channel with a different payload.
|
||||||
|
*/
|
||||||
GiftPackageRewardSelectionReceived = 32,
|
GiftPackageRewardSelectionReceived = 32,
|
||||||
/**
|
/**
|
||||||
* A player's level/XP changed — `{ PlayerId, Level, XP }`, where XP is the progress into
|
* A player's level/XP changed — `{ PlayerId, Level, XP }`, where XP is the progress into
|
||||||
@@ -56,9 +92,13 @@ export enum NotificationType {
|
|||||||
* wire name and its enum has no number for this one at all. It pushes the frame both when
|
* wire name and its enum has no number for this one at all. It pushes the frame both when
|
||||||
* progression changes and when the player reads it back, which is how a client that just
|
* progression changes and when the player reads it back, which is how a client that just
|
||||||
* connected gets its bar right.
|
* connected gets its bar right.
|
||||||
|
*
|
||||||
|
* Confirmed live, and the three-field payload confirmed against the client's formatter.
|
||||||
*/
|
*/
|
||||||
PlayerProgressionLevelUpdate = 'PlayerProgressionLevelUpdate',
|
PlayerProgressionLevelUpdate = 'PlayerProgressionLevelUpdate',
|
||||||
|
/** @deadOnClient No subscriber under `40` and no wire-name twin. */
|
||||||
ProfileJuniorStatusUpdate = 40,
|
ProfileJuniorStatusUpdate = 40,
|
||||||
|
/** Takes no payload — the client refetches. */
|
||||||
RelationshipsInvalid = 50,
|
RelationshipsInvalid = 50,
|
||||||
StorefrontBalanceAdd = 60,
|
StorefrontBalanceAdd = 60,
|
||||||
StorefrontBalanceUpdate = 61,
|
StorefrontBalanceUpdate = 61,
|
||||||
@@ -70,12 +110,67 @@ export enum NotificationType {
|
|||||||
PlayerEventDeleted = 82,
|
PlayerEventDeleted = 82,
|
||||||
PlayerEventResponseChanged = 83,
|
PlayerEventResponseChanged = 83,
|
||||||
PlayerEventResponseDeleted = 84,
|
PlayerEventResponseDeleted = 84,
|
||||||
|
/** @deadOnClient No subscriber under `85` and no wire-name twin. */
|
||||||
PlayerEventStateChanged = 85,
|
PlayerEventStateChanged = 85,
|
||||||
ChatMessageReceived = 'ChatMessageReceived',
|
ChatMessageReceived = 'ChatMessageReceived',
|
||||||
CommunityBoardUpdate = 95,
|
/**
|
||||||
|
* STRING-valued, and this one is easy to get wrong: the client's enum *does* have a
|
||||||
|
* member numbered `95`, but nothing subscribes to `"95"` — the live subscription is on
|
||||||
|
* the name. Sending the number is a silent no-op.
|
||||||
|
*/
|
||||||
|
CommunityBoardUpdate = 'CommunityBoardUpdate',
|
||||||
|
/**
|
||||||
|
* Numeric, unlike its `CommunityBoard` sibling above — `96` genuinely has a subscriber.
|
||||||
|
* Do not "unify" these two; they were checked separately. Note the *announcement list*
|
||||||
|
* has its own name-addressed channels ({@link AnnouncementUpdate} /
|
||||||
|
* {@link AnnouncementDelete}); this one is the board's single current announcement.
|
||||||
|
*/
|
||||||
CommunityBoardAnnouncementUpdate = 96,
|
CommunityBoardAnnouncementUpdate = 96,
|
||||||
|
/** Takes no payload — the client refetches. */
|
||||||
InventionModerationStateChanged = 100,
|
InventionModerationStateChanged = 100,
|
||||||
|
/** Takes no payload — the client refetches. */
|
||||||
FreeGiftButtonItemsAdded = 110,
|
FreeGiftButtonItemsAdded = 110,
|
||||||
LocalRoomKeyCreated = 120,
|
LocalRoomKeyCreated = 120,
|
||||||
LocalRoomKeyDeleted = 121,
|
LocalRoomKeyDeleted = 121,
|
||||||
|
|
||||||
|
// ---- Name-addressed channels with no client enum member ------------------
|
||||||
|
// These have no number at all: the client subscribes them purely by name. Grouped
|
||||||
|
// separately so the numeric block above stays a faithful mirror of the client enum.
|
||||||
|
|
||||||
|
/** Client version gate. The live replacement for {@link ModerationUpdateRequired}. */
|
||||||
|
AppVersionUpdate = 'AppVersionUpdate',
|
||||||
|
AnnouncementUpdate = 'AnnouncementUpdate',
|
||||||
|
AnnouncementDelete = 'AnnouncementDelete',
|
||||||
|
ClubMembershipUpdate = 'ClubMembershipUpdate',
|
||||||
|
CreatorClubSubscriptionUpdate = 'CreatorClubSubscriptionUpdate',
|
||||||
|
CommerceSubscriptionUpdate = 'CommerceSubscriptionUpdate',
|
||||||
|
/** Takes no payload — the client refetches `api/config/v2`. */
|
||||||
|
GameConfigRefresh = 'GameConfig.Refresh',
|
||||||
|
/** Takes no payload — the client refetches. */
|
||||||
|
PlayerSettingsRefresh = 'PlayerSettings.Refresh',
|
||||||
|
/** Matchmaking told the client its `GoTo` failed; payload is a single error code. */
|
||||||
|
GoToFailure = 'GoToFailure',
|
||||||
|
IncentivizedReferralUpdate = 'IncentivizedReferralUpdate',
|
||||||
|
InfluencerSupportedUpdate = 'InfluencerSupportedUpdate',
|
||||||
|
KeepsakeInstanceAdded = 'KeepsakeInstanceAdded',
|
||||||
|
KeepsakeInstanceRemoved = 'KeepsakeInstanceRemoved',
|
||||||
|
/** The un-kick; same payload type as {@link ModerationKick}. */
|
||||||
|
ModerationUnkick = 'ModerationUnkick',
|
||||||
|
/** Hands the client a Photon token for a room instance. */
|
||||||
|
PhotonAccessToken = 'PhotonAccessToken',
|
||||||
|
PlayerCustomAvatarItemModerated = 'PlayerCustomAvatarItemModerated',
|
||||||
|
/** Same payload type as {@link ChatMessageReceived}. */
|
||||||
|
PlayerLeftChat = 'PlayerLeftChat',
|
||||||
|
ProgressionEventsRecordUpdate = 'ProgressionEventsRecordUpdate',
|
||||||
|
ReputationUpdate = 'ReputationUpdate',
|
||||||
|
/** Distinct from {@link GiftPackageRewardSelectionReceived} — different payload. */
|
||||||
|
RewardSelectionReceived = 'RewardSelectionReceived',
|
||||||
|
RoomCommentDeleted = 'RoomCommentDeleted',
|
||||||
|
RoomCurrencyCreated = 'RoomCurrencyCreated',
|
||||||
|
RoomCurrencyModified = 'RoomCurrencyModified',
|
||||||
|
RoomCurrencyDeleted = 'RoomCurrencyDeleted',
|
||||||
|
StringAutoLocalizationJob = 'StringAutoLocalizationJob',
|
||||||
|
WebsiteInventionPurchase = 'WebsiteInventionPurchase',
|
||||||
|
GiftManualConsumed = 'gift.manualconsumed',
|
||||||
|
PushToDevice = 'rrs.pushtodevice',
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user