Update to 1.19.2

This commit is contained in:
Ryan 2022-08-30 18:41:17 -07:00
parent c8cc7a021c
commit 79399c153e
11 changed files with 2681 additions and 1945 deletions

File diff suppressed because it is too large Load diff

709
extracted/packets.json Normal file
View file

@ -0,0 +1,709 @@
{
"serverbound": {
"handshaking": [
{
"name": "HandshakeC2SPacket",
"id": 0
}
],
"play": [
{
"name": "TeleportConfirmC2SPacket",
"id": 0
},
{
"name": "QueryBlockNbtC2SPacket",
"id": 1
},
{
"name": "UpdateDifficultyC2SPacket",
"id": 2
},
{
"name": "MessageAcknowledgmentC2SPacket",
"id": 3
},
{
"name": "CommandExecutionC2SPacket",
"id": 4
},
{
"name": "ChatMessageC2SPacket",
"id": 5
},
{
"name": "RequestChatPreviewC2SPacket",
"id": 6
},
{
"name": "ClientStatusC2SPacket",
"id": 7
},
{
"name": "ClientSettingsC2SPacket",
"id": 8
},
{
"name": "RequestCommandCompletionsC2SPacket",
"id": 9
},
{
"name": "ButtonClickC2SPacket",
"id": 10
},
{
"name": "ClickSlotC2SPacket",
"id": 11
},
{
"name": "CloseHandledScreenC2SPacket",
"id": 12
},
{
"name": "CustomPayloadC2SPacket",
"id": 13
},
{
"name": "BookUpdateC2SPacket",
"id": 14
},
{
"name": "QueryEntityNbtC2SPacket",
"id": 15
},
{
"name": "PlayerInteractEntityC2SPacket",
"id": 16
},
{
"name": "JigsawGeneratingC2SPacket",
"id": 17
},
{
"name": "KeepAliveC2SPacket",
"id": 18
},
{
"name": "UpdateDifficultyLockC2SPacket",
"id": 19
},
{
"name": "PositionAndOnGround",
"id": 20
},
{
"name": "Full",
"id": 21
},
{
"name": "LookAndOnGround",
"id": 22
},
{
"name": "OnGroundOnly",
"id": 23
},
{
"name": "VehicleMoveC2SPacket",
"id": 24
},
{
"name": "BoatPaddleStateC2SPacket",
"id": 25
},
{
"name": "PickFromInventoryC2SPacket",
"id": 26
},
{
"name": "CraftRequestC2SPacket",
"id": 27
},
{
"name": "UpdatePlayerAbilitiesC2SPacket",
"id": 28
},
{
"name": "PlayerActionC2SPacket",
"id": 29
},
{
"name": "ClientCommandC2SPacket",
"id": 30
},
{
"name": "PlayerInputC2SPacket",
"id": 31
},
{
"name": "PlayPongC2SPacket",
"id": 32
},
{
"name": "RecipeCategoryOptionsC2SPacket",
"id": 33
},
{
"name": "RecipeBookDataC2SPacket",
"id": 34
},
{
"name": "RenameItemC2SPacket",
"id": 35
},
{
"name": "ResourcePackStatusC2SPacket",
"id": 36
},
{
"name": "AdvancementTabC2SPacket",
"id": 37
},
{
"name": "SelectMerchantTradeC2SPacket",
"id": 38
},
{
"name": "UpdateBeaconC2SPacket",
"id": 39
},
{
"name": "UpdateSelectedSlotC2SPacket",
"id": 40
},
{
"name": "UpdateCommandBlockC2SPacket",
"id": 41
},
{
"name": "UpdateCommandBlockMinecartC2SPacket",
"id": 42
},
{
"name": "CreativeInventoryActionC2SPacket",
"id": 43
},
{
"name": "UpdateJigsawC2SPacket",
"id": 44
},
{
"name": "UpdateStructureBlockC2SPacket",
"id": 45
},
{
"name": "UpdateSignC2SPacket",
"id": 46
},
{
"name": "HandSwingC2SPacket",
"id": 47
},
{
"name": "SpectatorTeleportC2SPacket",
"id": 48
},
{
"name": "PlayerInteractBlockC2SPacket",
"id": 49
},
{
"name": "PlayerInteractItemC2SPacket",
"id": 50
}
],
"status": [
{
"name": "QueryRequestC2SPacket",
"id": 0
},
{
"name": "QueryPingC2SPacket",
"id": 1
}
],
"login": [
{
"name": "LoginHelloC2SPacket",
"id": 0
},
{
"name": "LoginKeyC2SPacket",
"id": 1
},
{
"name": "LoginQueryResponseC2SPacket",
"id": 2
}
]
},
"clientbound": {
"handshaking": [],
"play": [
{
"name": "EntitySpawnS2CPacket",
"id": 0
},
{
"name": "ExperienceOrbSpawnS2CPacket",
"id": 1
},
{
"name": "PlayerSpawnS2CPacket",
"id": 2
},
{
"name": "EntityAnimationS2CPacket",
"id": 3
},
{
"name": "StatisticsS2CPacket",
"id": 4
},
{
"name": "PlayerActionResponseS2CPacket",
"id": 5
},
{
"name": "BlockBreakingProgressS2CPacket",
"id": 6
},
{
"name": "BlockEntityUpdateS2CPacket",
"id": 7
},
{
"name": "BlockEventS2CPacket",
"id": 8
},
{
"name": "BlockUpdateS2CPacket",
"id": 9
},
{
"name": "BossBarS2CPacket",
"id": 10
},
{
"name": "DifficultyS2CPacket",
"id": 11
},
{
"name": "ChatPreviewS2CPacket",
"id": 12
},
{
"name": "ClearTitleS2CPacket",
"id": 13
},
{
"name": "CommandSuggestionsS2CPacket",
"id": 14
},
{
"name": "CommandTreeS2CPacket",
"id": 15
},
{
"name": "CloseScreenS2CPacket",
"id": 16
},
{
"name": "InventoryS2CPacket",
"id": 17
},
{
"name": "ScreenHandlerPropertyUpdateS2CPacket",
"id": 18
},
{
"name": "ScreenHandlerSlotUpdateS2CPacket",
"id": 19
},
{
"name": "CooldownUpdateS2CPacket",
"id": 20
},
{
"name": "ChatSuggestionsS2CPacket",
"id": 21
},
{
"name": "CustomPayloadS2CPacket",
"id": 22
},
{
"name": "PlaySoundIdS2CPacket",
"id": 23
},
{
"name": "HideMessageS2CPacket",
"id": 24
},
{
"name": "DisconnectS2CPacket",
"id": 25
},
{
"name": "EntityStatusS2CPacket",
"id": 26
},
{
"name": "ExplosionS2CPacket",
"id": 27
},
{
"name": "UnloadChunkS2CPacket",
"id": 28
},
{
"name": "GameStateChangeS2CPacket",
"id": 29
},
{
"name": "OpenHorseScreenS2CPacket",
"id": 30
},
{
"name": "WorldBorderInitializeS2CPacket",
"id": 31
},
{
"name": "KeepAliveS2CPacket",
"id": 32
},
{
"name": "ChunkDataS2CPacket",
"id": 33
},
{
"name": "WorldEventS2CPacket",
"id": 34
},
{
"name": "ParticleS2CPacket",
"id": 35
},
{
"name": "LightUpdateS2CPacket",
"id": 36
},
{
"name": "GameJoinS2CPacket",
"id": 37
},
{
"name": "MapUpdateS2CPacket",
"id": 38
},
{
"name": "SetTradeOffersS2CPacket",
"id": 39
},
{
"name": "MoveRelative",
"id": 40
},
{
"name": "RotateAndMoveRelative",
"id": 41
},
{
"name": "Rotate",
"id": 42
},
{
"name": "VehicleMoveS2CPacket",
"id": 43
},
{
"name": "OpenWrittenBookS2CPacket",
"id": 44
},
{
"name": "OpenScreenS2CPacket",
"id": 45
},
{
"name": "SignEditorOpenS2CPacket",
"id": 46
},
{
"name": "PlayPingS2CPacket",
"id": 47
},
{
"name": "CraftFailedResponseS2CPacket",
"id": 48
},
{
"name": "PlayerAbilitiesS2CPacket",
"id": 49
},
{
"name": "MessageHeaderS2CPacket",
"id": 50
},
{
"name": "ChatMessageS2CPacket",
"id": 51
},
{
"name": "EndCombatS2CPacket",
"id": 52
},
{
"name": "EnterCombatS2CPacket",
"id": 53
},
{
"name": "DeathMessageS2CPacket",
"id": 54
},
{
"name": "PlayerListS2CPacket",
"id": 55
},
{
"name": "LookAtS2CPacket",
"id": 56
},
{
"name": "PlayerPositionLookS2CPacket",
"id": 57
},
{
"name": "UnlockRecipesS2CPacket",
"id": 58
},
{
"name": "EntitiesDestroyS2CPacket",
"id": 59
},
{
"name": "RemoveEntityStatusEffectS2CPacket",
"id": 60
},
{
"name": "ResourcePackSendS2CPacket",
"id": 61
},
{
"name": "PlayerRespawnS2CPacket",
"id": 62
},
{
"name": "EntitySetHeadYawS2CPacket",
"id": 63
},
{
"name": "ChunkDeltaUpdateS2CPacket",
"id": 64
},
{
"name": "SelectAdvancementTabS2CPacket",
"id": 65
},
{
"name": "ServerMetadataS2CPacket",
"id": 66
},
{
"name": "OverlayMessageS2CPacket",
"id": 67
},
{
"name": "WorldBorderCenterChangedS2CPacket",
"id": 68
},
{
"name": "WorldBorderInterpolateSizeS2CPacket",
"id": 69
},
{
"name": "WorldBorderSizeChangedS2CPacket",
"id": 70
},
{
"name": "WorldBorderWarningTimeChangedS2CPacket",
"id": 71
},
{
"name": "WorldBorderWarningBlocksChangedS2CPacket",
"id": 72
},
{
"name": "SetCameraEntityS2CPacket",
"id": 73
},
{
"name": "UpdateSelectedSlotS2CPacket",
"id": 74
},
{
"name": "ChunkRenderDistanceCenterS2CPacket",
"id": 75
},
{
"name": "ChunkLoadDistanceS2CPacket",
"id": 76
},
{
"name": "PlayerSpawnPositionS2CPacket",
"id": 77
},
{
"name": "ChatPreviewStateChangeS2CPacket",
"id": 78
},
{
"name": "ScoreboardDisplayS2CPacket",
"id": 79
},
{
"name": "EntityTrackerUpdateS2CPacket",
"id": 80
},
{
"name": "EntityAttachS2CPacket",
"id": 81
},
{
"name": "EntityVelocityUpdateS2CPacket",
"id": 82
},
{
"name": "EntityEquipmentUpdateS2CPacket",
"id": 83
},
{
"name": "ExperienceBarUpdateS2CPacket",
"id": 84
},
{
"name": "HealthUpdateS2CPacket",
"id": 85
},
{
"name": "ScoreboardObjectiveUpdateS2CPacket",
"id": 86
},
{
"name": "EntityPassengersSetS2CPacket",
"id": 87
},
{
"name": "TeamS2CPacket",
"id": 88
},
{
"name": "ScoreboardPlayerUpdateS2CPacket",
"id": 89
},
{
"name": "SimulationDistanceS2CPacket",
"id": 90
},
{
"name": "SubtitleS2CPacket",
"id": 91
},
{
"name": "WorldTimeUpdateS2CPacket",
"id": 92
},
{
"name": "TitleS2CPacket",
"id": 93
},
{
"name": "TitleFadeS2CPacket",
"id": 94
},
{
"name": "PlaySoundFromEntityS2CPacket",
"id": 95
},
{
"name": "PlaySoundS2CPacket",
"id": 96
},
{
"name": "StopSoundS2CPacket",
"id": 97
},
{
"name": "GameMessageS2CPacket",
"id": 98
},
{
"name": "PlayerListHeaderS2CPacket",
"id": 99
},
{
"name": "NbtQueryResponseS2CPacket",
"id": 100
},
{
"name": "ItemPickupAnimationS2CPacket",
"id": 101
},
{
"name": "EntityPositionS2CPacket",
"id": 102
},
{
"name": "AdvancementUpdateS2CPacket",
"id": 103
},
{
"name": "EntityAttributesS2CPacket",
"id": 104
},
{
"name": "EntityStatusEffectS2CPacket",
"id": 105
},
{
"name": "SynchronizeRecipesS2CPacket",
"id": 106
},
{
"name": "SynchronizeTagsS2CPacket",
"id": 107
}
],
"status": [
{
"name": "QueryResponseS2CPacket",
"id": 0
},
{
"name": "QueryPongS2CPacket",
"id": 1
}
],
"login": [
{
"name": "LoginDisconnectS2CPacket",
"id": 0
},
{
"name": "LoginHelloS2CPacket",
"id": 1
},
{
"name": "LoginSuccessS2CPacket",
"id": 2
},
{
"name": "LoginCompressionS2CPacket",
"id": 3
},
{
"name": "LoginQueryRequestS2CPacket",
"id": 4
}
]
}
}

View file

@ -1,5 +1,5 @@
plugins {
id 'fabric-loom' version '0.12-SNAPSHOT'
id 'fabric-loom' version '1.0-SNAPSHOT'
}
sourceCompatibility = JavaVersion.VERSION_17
@ -35,3 +35,9 @@ tasks.withType(JavaCompile).configureEach {
java {
withSourcesJar()
}
jar {
from("LICENSE") {
rename { "${it}_${project.archivesBaseName}"}
}
}

View file

@ -3,9 +3,9 @@ org.gradle.jvmargs=-Xmx1G
# Fabric Properties
# check these on https://fabricmc.net/develop
minecraft_version=1.19
yarn_mappings=1.19+build.4
loader_version=0.14.8
minecraft_version=1.19.2
yarn_mappings=1.19.2+build.8
loader_version=0.14.9
# Mod Properties
mod_version = 1.0.0
@ -13,4 +13,4 @@ org.gradle.jvmargs=-Xmx1G
archives_base_name = valence-extractor
# Dependencies
fabric_version=0.57.0+1.19
fabric_version=0.60.0+1.19.2

View file

@ -17,7 +17,7 @@ public class Packets implements Main.Extractor {
}
@Override
public JsonElement extract() throws Exception {
public JsonElement extract() {
var packetsJson = new JsonObject();
for (var side : NetworkSide.values()) {

View file

@ -26,10 +26,9 @@ use crate::player_textures::SignedPlayerTextures;
use crate::protocol_inner::packets::c2s::play::{
C2sPlayPacket, DiggingStatus, InteractKind, PlayerCommandId,
};
pub use crate::protocol_inner::packets::s2c::play::TitleAnimationTimes;
pub use crate::protocol_inner::packets::s2c::play::TitleFade;
use crate::protocol_inner::packets::s2c::play::{
BiomeRegistry, ChatType, ChatTypeChat, ChatTypeNarration, ChatTypeRegistry,
ChatTypeRegistryEntry, ChunkLoadDistance, ChunkRenderDistanceCenter, ClearTitles,
BiomeRegistry, ChatTypeRegistry, ChunkLoadDistance, ChunkRenderDistanceCenter, ClearTitles,
DimensionTypeRegistry, DimensionTypeRegistryEntry, Disconnect, EntitiesDestroy,
EntityAnimation, EntityAttributes, EntityAttributesProperty, EntityPosition, EntitySetHeadYaw,
EntityStatus, EntityTrackerUpdate, EntityVelocityUpdate, GameJoin, GameMessage,
@ -450,12 +449,12 @@ impl<C: Config> Client<C> {
/// A title is a large piece of text displayed in the center of the screen
/// which may also include a subtitle underneath it. The title
/// can be configured to fade in and out using the
/// [`TitleAnimationTimes`] struct.
/// [`TitleFade`] struct.
pub fn set_title(
&mut self,
title: impl Into<Text>,
subtitle: impl Into<Text>,
animation: impl Into<Option<TitleAnimationTimes>>,
animation: impl Into<Option<TitleFade>>,
) {
let title = title.into();
let subtitle = subtitle.into();
@ -654,6 +653,7 @@ impl<C: Config> Client<C> {
}
C2sPlayPacket::QueryBlockNbt(_) => {}
C2sPlayPacket::UpdateDifficulty(_) => {}
C2sPlayPacket::MessageAcknowledgment(_) => {}
C2sPlayPacket::CommandExecution(_) => {}
C2sPlayPacket::ChatMessage(p) => self.events.push_back(ClientEvent::ChatMessage {
message: p.message.0,
@ -1411,16 +1411,7 @@ fn make_registry_codec<C: Config>(shared: &SharedServer<C>) -> RegistryCodec {
},
chat_type_registry: ChatTypeRegistry {
kind: ident!("chat_type"),
value: vec![ChatTypeRegistryEntry {
name: ident!("system"),
id: 0,
element: ChatType {
chat: ChatTypeChat {},
narration: ChatTypeNarration {
priority: "system".into(),
},
},
}],
value: Vec::new(),
},
}
}

View file

@ -161,10 +161,10 @@ pub mod protocol {
}
/// The Minecraft protocol version this library currently targets.
pub const PROTOCOL_VERSION: i32 = 759;
pub const PROTOCOL_VERSION: i32 = 760;
/// The name of the Minecraft version this library currently targets, e.g.
/// "1.8.2"
pub const VERSION_NAME: &str = "1.19";
pub const VERSION_NAME: &str = "1.19.2";
/// The namespace for this library used internally for
/// [identifiers](crate::ident::Ident).

View file

@ -380,7 +380,7 @@ def_struct! {
}
def_struct! {
SignatureData {
PublicKeyData {
timestamp: u64,
public_key: Vec<u8>,
signature: Vec<u8>,

View file

@ -55,7 +55,8 @@ pub mod login {
def_struct! {
LoginStart {
username: BoundedString<3, 16>,
sig_data: Option<SignatureData>,
sig_data: Option<PublicKeyData>,
profile_id: Option<Uuid>,
}
}
@ -121,6 +122,19 @@ pub mod play {
}
}
def_struct! {
MessageAcknowledgment {
entry: Option<MessageAcknowledgmentEntry>,
}
}
def_struct! {
MessageAcknowledgmentEntry {
profile_id: Uuid,
signature: Vec<u8>,
}
}
def_struct! {
CommandExecution {
command: String, // TODO: bounded?
@ -668,53 +682,54 @@ pub mod play {
TeleportConfirm = 0,
QueryBlockNbt = 1,
UpdateDifficulty = 2,
CommandExecution = 3,
ChatMessage = 4,
RequestChatPreview = 5,
ClientStatus = 6,
ClientSettings = 7,
RequestCommandCompletion = 8,
ButtonClick = 9,
ClickSlot = 10,
CloseHandledScreen = 11,
CustomPayload = 12,
BookUpdate = 13,
QueryEntityNbt = 14,
PlayerInteractEntity = 15,
JigsawGenerate = 16,
KeepAlive = 17,
UpdateDifficultyLock = 18,
MovePlayerPosition = 19,
MovePlayerPositionAndRotation = 20,
MovePlayerRotation = 21,
MovePlayerOnGround = 22,
MoveVehicle = 23,
BoatPaddleState = 24,
PickFromInventory = 25,
CraftRequest = 26,
UpdatePlayerAbilities = 27,
PlayerAction = 28,
PlayerCommand = 29,
PlayerInput = 30,
PlayPong = 31,
RecipeBookChangeSettings = 32,
RecipeBookSeenRecipe = 33,
RenameItem = 34,
ResourcePackStatus = 35,
AdvancementTab = 36,
SelectMerchantTrade = 37,
UpdateBeacon = 38,
UpdateSelectedSlot = 39,
UpdateCommandBlock = 40,
UpdateCommandBlockMinecart = 41,
UpdateCreativeModeSlot = 42,
UpdateJigsaw = 43,
UpdateStructureBlock = 44,
UpdateSign = 45,
HandSwing = 46,
SpectatorTeleport = 47,
PlayerInteractBlock = 48,
PlayerInteractItem = 49,
MessageAcknowledgment = 3,
CommandExecution = 4,
ChatMessage = 5,
RequestChatPreview = 6,
ClientStatus = 7,
ClientSettings = 8,
RequestCommandCompletion = 9,
ButtonClick = 10,
ClickSlot = 11,
CloseHandledScreen = 12,
CustomPayload = 13,
BookUpdate = 14,
QueryEntityNbt = 15,
PlayerInteractEntity = 16,
JigsawGenerate = 17,
KeepAlive = 18,
UpdateDifficultyLock = 19,
MovePlayerPosition = 20,
MovePlayerPositionAndRotation = 21,
MovePlayerRotation = 22,
MovePlayerOnGround = 23,
MoveVehicle = 24,
BoatPaddleState = 25,
PickFromInventory = 26,
CraftRequest = 27,
UpdatePlayerAbilities = 28,
PlayerAction = 29,
PlayerCommand = 30,
PlayerInput = 31,
PlayPong = 32,
RecipeBookChangeSettings = 33,
RecipeBookSeenRecipe = 34,
RenameItem = 35,
ResourcePackStatus = 36,
AdvancementTab = 37,
SelectMerchantTrade = 38,
UpdateBeacon = 39,
UpdateSelectedSlot = 40,
UpdateCommandBlock = 41,
UpdateCommandBlockMinecart = 42,
UpdateCreativeModeSlot = 43,
UpdateJigsaw = 44,
UpdateStructureBlock = 45,
UpdateSign = 46,
HandSwing = 47,
SpectatorTeleport = 48,
PlayerInteractBlock = 49,
PlayerInteractItem = 50,
}
}
}

View file

@ -543,11 +543,11 @@ pub mod play {
def_struct! {
ChatMessage {
// TODO: more 1.19 stuff.
message: Text,
/// Index into the chat type registry
kind: VarInt,
sender: Uuid,
// TODO more fields
}
}
@ -569,7 +569,7 @@ pub mod play {
game_mode: GameMode,
ping: VarInt,
display_name: Option<Text>,
sig_data: Option<SignatureData>,
sig_data: Option<PublicKeyData>,
}
}
@ -694,7 +694,7 @@ pub mod play {
def_struct! {
#[derive(Copy, PartialEq, Eq)]
TitleAnimationTimes {
TitleFade {
/// Ticks to spend fading in.
fade_in: u32,
/// Ticks to keep the title displayed.
@ -765,37 +765,37 @@ pub mod play {
BlockUpdate = 9,
BossBar = 10,
ClearTitles = 13,
Disconnect = 23,
EntityStatus = 24,
UnloadChunk = 26,
GameStateChange = 27,
KeepAlive = 30,
ChunkData = 31,
GameJoin = 35,
MoveRelative = 38,
RotateAndMoveRelative = 39,
Rotate = 40,
ChatMessage = 48,
UpdatePlayerList = 52,
PlayerPositionLook = 54,
EntitiesDestroy = 56,
PlayerRespawn = 59,
EntitySetHeadYaw = 60,
ChunkSectionUpdate = 61,
UpdateSelectedSlot = 71,
ChunkRenderDistanceCenter = 72,
ChunkLoadDistance = 73,
PlayerSpawnPosition = 74,
EntityTrackerUpdate = 77,
EntityVelocityUpdate = 79,
UpdateSubtitle = 88,
WorldTimeUpdate = 89,
UpdateTitle = 90,
TitleAnimationTimes = 91,
GameMessage = 95,
PlayerListHeaderFooter = 96,
EntityPosition = 99,
EntityAttributes = 101,
Disconnect = 25,
EntityStatus = 26,
UnloadChunk = 28,
GameStateChange = 29,
KeepAlive = 32,
ChunkData = 33,
GameJoin = 37,
MoveRelative = 40,
RotateAndMoveRelative = 41,
Rotate = 42,
ChatMessage = 51,
UpdatePlayerList = 55,
PlayerPositionLook = 57,
EntitiesDestroy = 59,
PlayerRespawn = 62,
EntitySetHeadYaw = 63,
ChunkSectionUpdate = 64,
UpdateSelectedSlot = 74,
ChunkRenderDistanceCenter = 75,
ChunkLoadDistance = 76,
PlayerSpawnPosition = 77,
EntityTrackerUpdate = 80,
EntityVelocityUpdate = 82,
UpdateSubtitle = 91,
WorldTimeUpdate = 92,
UpdateTitle = 93,
TitleFade = 94,
GameMessage = 98,
PlayerListHeaderFooter = 99,
EntityPosition = 102,
EntityAttributes = 104,
}
}
}

View file

@ -76,7 +76,6 @@ pub struct Server<C: Config> {
/// be shared between threads.
///
/// [update]: crate::config::Config::update
pub struct SharedServer<C: Config>(Arc<SharedServerInner<C>>);
impl<C: Config> Clone for SharedServer<C> {
@ -637,6 +636,7 @@ async fn handle_login<C: Config>(
let LoginStart {
username: BoundedString(username),
sig_data: _, // TODO
profile_id: _, // TODO
} = c.dec.read_packet().await?;
ensure!(valid_username(&username), "invalid username '{username}'");