public void OnPlayerPosition(IMinecraftUser user, IMinecraftPacket packet) { Position destinationPosition = packet.ReadAbsolutePosition(); bool isOnGround = packet.ReadBoolean(); user.Player.Move(destinationPosition, isOnGround); }
/// <summary> /// Creates a new <see cref="HandshakePacket"/> instance. /// </summary> /// <param name="packet">Incoming packet from client.</param> public HandshakePacket(IMinecraftPacket packet) { ProtocolVersion = packet.ReadVarInt32(); ServerAddress = packet.ReadString(); ServerPort = packet.ReadUInt16(); NextState = (MinecraftUserStatus)packet.ReadVarInt32(); }
public void Broadcast(IMinecraftPacket packet) { foreach (IPlayer player in _players.Values) { player.SendPacket(packet); } }
private static void SendPacketToAllPlayers(IWorldMap map, IMinecraftPacket packet) { if (map is not null) { map.Broadcast(packet); } }
private void WriteDimension(Dimension dimension, IMinecraftPacket packet) { var nbtDimension = NbtSerializer.SerializeCompound(dimension.Element, ""); var nbtFile = new NbtFile(nbtDimension); packet.WriteBytes(nbtFile.GetBuffer()); }
public void OnPing(IMinecraftUser user, IMinecraftPacket packet) { var pingPacket = new StatusPingPacket(packet); using var pongPacket = new StatusPongPacket(pingPacket.Payload); user.Send(pongPacket); }
public void OnPlayerDigging(IMinecraftUser user, IMinecraftPacket packet) { var status = (DiggingType)packet.ReadVarInt32(); var position = packet.ReadPosition(); var face = (BlockFaceType)packet.ReadByte(); _logger.LogTrace($"Status={status};Position={position};Face={face}"); if (user.Player.GameMode is ServerGameModeType.Creative) { IBlock previousBlock = user.Player.Map.GetBlock(position); if (previousBlock.IsAir) { throw new InvalidOperationException($"Cannot dig air blocks ({position})"); } using var playerDiggingAck = new AcknowledgePlayerDiggingPacket(position, previousBlock, DiggingType.Started); user.Player.SendPacketToVisibleEntities(playerDiggingAck); using var blockChange = new BlockChangePacket(BlockType.Air, position); user.Player.SendPacketToVisibleEntities(blockChange); IBlock block = user.Player.Map.SetBlock(BlockType.Air, position); using var chunkPacket = new ChunkDataPacket(block.Chunk); user.Player.SendPacketToVisibleEntities(chunkPacket, includeEntity: true); } else { // TODO: other modes } }
public void OnPlayerRotation(IMinecraftUser user, IMinecraftPacket packet) { float yawAngle = packet.ReadSingle(); float pitchAngle = packet.ReadSingle(); bool isOnGround = packet.ReadBoolean(); user.Player.Rotate(yawAngle, pitchAngle); }
public void OnPlayerPositionAndRotation(IMinecraftUser user, IMinecraftPacket packet) { Position destinationPosition = packet.ReadAbsolutePosition(); float yawAngle = packet.ReadSingle(); float pitchAngle = packet.ReadSingle(); bool isOnGround = packet.ReadBoolean(); user.Player.MoveAndRotate(destinationPosition, yawAngle, pitchAngle, isOnGround); }
public void Serialize(IMinecraftPacket packet, bool fullChunk = false) { packet.WriteInt32(X); packet.WriteInt32(Z); packet.WriteBoolean(fullChunk); int mask = 0; // if full chunk using var chunkStream = new MinecraftPacket(); for (int i = 0; i < Sections.Count(); i++) { IChunkSection section = Sections.ElementAt(i); if (fullChunk || section.IsDirty) { mask |= 1 << i; section.Serialize(chunkStream); } } packet.WriteVarInt32(mask); // Heightmap serialization var heightmapCompound = new NbtCompound("") { new NbtLongArray("MOTION_BLOCKING", Heightmap.ToArray()), new NbtLongArray("WORLD_SURFACE", WorldSurfaceHeightmap.ToArray()) }; var nbtFile = new NbtFile(heightmapCompound); packet.WriteBytes(nbtFile.GetBuffer()); // Biomes if (fullChunk) { packet.WriteVarInt32(1024); for (int i = 0; i < 1024; i++) { packet.WriteVarInt32(0); } } chunkStream.Position = 0; packet.WriteVarInt32((int)chunkStream.Length); packet.WriteBytes(chunkStream.BaseBuffer); packet.WriteVarInt32(0); // block count // TODO: foreach block in blocks in chunk as NBT }
public void Send(IMinecraftPacket packet) { if (packet is MinecraftPacket minecraftPacket) { using var stream = new MinecraftStream(); stream.WriteVarInt32(minecraftPacket.PacketLength); stream.WriteVarInt32(minecraftPacket.PacketId); stream.WriteBytes(minecraftPacket.Buffer); base.Send(stream.Buffer); } }
public void OnHeldItemChange(IMinecraftUser user, IMinecraftPacket packet) { short slot = packet.ReadInt16(); if (slot < 0 || slot > 8) { throw new IndexOutOfRangeException($"Slot was out of bounds: {slot}"); } _logger.LogDebug($"Current slot: {slot}"); user.Player.HotBar.SetSlotIndex(slot); _logger.LogDebug($"Selected Item: ItemId = {user.Player.HotBar.SelectedSlot.ItemId}"); }
public void OnPlayerBlockPlacement(IMinecraftUser user, IMinecraftPacket packet) { var handType = (HandType)packet.ReadVarInt32(); Position blockPosition = packet.ReadPosition(); var blockFace = (BlockFaceType)packet.ReadVarInt32(); float cursorX = packet.ReadSingle(); float cursorY = packet.ReadSingle(); float cursorZ = packet.ReadSingle(); bool isInsideBlock = packet.ReadBoolean(); // TODO: check if the current player is interacting with an interactable object. // Like: Chest, anvil, crafting table. IItemSlot currentHeldItem = user.Player.HotBar.SelectedSlot; if (currentHeldItem.HasItem) { BlockData block = _registry.Blocks.FirstOrDefault(x => x.ItemId == currentHeldItem.ItemId); BlockType blockToPlace = block.Type; if (blockToPlace is not BlockType.Air) { Position realBlockPosition = blockFace switch { BlockFaceType.Bottom => new Position(blockPosition.X, blockPosition.Y - 1, blockPosition.Z), BlockFaceType.Top => new Position(blockPosition.X, blockPosition.Y + 1, blockPosition.Z), BlockFaceType.North => new Position(blockPosition.X, blockPosition.Y, blockPosition.Z - 1), BlockFaceType.South => new Position(blockPosition.X, blockPosition.Y, blockPosition.Z + 1), BlockFaceType.West => new Position(blockPosition.X - 1, blockPosition.Y, blockPosition.Z), BlockFaceType.East => new Position(blockPosition.X + 1, blockPosition.Y, blockPosition.Z), _ => throw new InvalidOperationException("Invalid block face type.") }; _logger.LogDebug($"Placing block '{blockToPlace}' at position {realBlockPosition}"); user.Player.Map.SetBlock(blockToPlace, (int)realBlockPosition.X, (int)realBlockPosition.Y, (int)realBlockPosition.Z); using var blockChangePacket = new BlockChangePacket(blockToPlace, blockPosition); user.Player.SendPacketToVisibleEntities(blockChangePacket); using var chunkDataPacket = new ChunkDataPacket(user.Player.Chunk); user.Player.SendPacketToVisibleEntities(chunkDataPacket); } } } }
public void OnChatMessage(IMinecraftUser user, IMinecraftPacket packet) { string message = packet.ReadString(); if (message.Length > 256) { user.Disconnect("Chat message exceeds 256 characters."); } if (message.StartsWith(RedstoneContants.CommandPrefix)) { // TODO: interpret commands } else { user.Player.Speak(message); } }
public void OnCreativeInventoryAction(IMinecraftUser user, IMinecraftPacket packet) { short slot = (short)(packet.ReadInt16() - RedstoneContants.PlayerInventoryHotbarOffset); // item slot structure bool present = packet.ReadBoolean(); if (present) { int itemId = packet.ReadVarInt32(); byte itemCount = packet.ReadByte(); NbtCompound itemExtras = packet.ReadNbtCompound(); _logger.LogInformation($"Item with id: {itemId} (x{itemCount}) set at slot {slot}"); user.Player.HotBar.SetItem(slot, itemId, itemCount); } else { _logger.LogInformation($"Clearing item slot '{slot}'"); user.Player.HotBar.ClearItem(slot); } }
public void OnAnimation(IMinecraftUser user, IMinecraftPacket packet) { var hand = (HandType)packet.ReadVarInt32(); user.Player.SwingHand(hand); }
public void OnLogin(IMinecraftUser user, IMinecraftPacket packet) { string username = packet.ReadString(); _logger.LogInformation($"{user.Username} trying to log-in"); if (_serverConfiguration.Value.Mode == ServerModeType.Offline) { if (_serverConfiguration.Value.AllowMultiplayerDebug) { int count = _server.ConnectedPlayers.Count(x => x.Username.StartsWith(username)); if (count > 0 && _server.ConnectedPlayers.Any(x => x.Username.Equals(username))) { username = $"{username} ({count})"; } } else { if (_server.HasUser(username)) { user.Disconnect($"A player with the same name '{username}' is already connected."); return; } } Guid playerId = GuidUtilities.GenerateGuidFromString($"OfflinePlayer:{username}"); // TODO: initialize current player // TODO: Read player data from storage (DB or file-system) user.LoadPlayer(playerId, username); // DEBUG user.Player.Position.X = 8; user.Player.Position.Y = 2; user.Player.Position.Z = 8; SendLoginSucess(user); user.UpdateStatus(MinecraftUserStatus.Play); _server.Events.OnPlayerJoinGame(new PlayerJoinEventArgs(user.Player)); SendJoinGame(user); SendServerBrand(user); // TODO: held item changed // TODO: declare recipes // TODO: Tags // TODO: Entity status // TODO: declare commands // TODO: Unlock recipes SendPlayerPositionAndLook(user, user.Player.Position); SendPlayerInfo(user, PlayerInfoActionType.Add); SendPlayerInfo(user, PlayerInfoActionType.UpdateLatency); SendUpdateViewPosition(user); // TODO: Update light SendChunkData(user); SendUpdateViewPosition(user); // TODO: World border SendSpawnPosition(user, Position.Zero); SendPlayerPositionAndLook(user, user.Player.Position); user.Player.IsSpawned = true; } else { // TODO: login to Mojang API } }
public void OnHandshake(IMinecraftUser user, IMinecraftPacket packet) { var handshake = new HandshakePacket(packet); user.UpdateStatus(handshake.NextState); }
private void WriteDimensionsAndBiomes(IEnumerable <Dimension> dimensions, IEnumerable <Biome> biomes, IMinecraftPacket packet) { IEnumerable <NbtTag> dimensionsTags = dimensions.Select(x => NbtSerializer.SerializeCompound(x)); IEnumerable <NbtTag> biomesTags = biomes.Select(x => NbtSerializer.SerializeCompound(x)); var nbtCompound = new NbtCompound("") { new NbtCompound("minecraft:dimension_type") { new NbtString("type", "minecraft:dimension_type"), new NbtList("value", dimensionsTags, NbtTagType.Compound) }, new NbtCompound("minecraft:worldgen/biome") { new NbtString("type", "minecraft:worldgen/biome"), new NbtList("value", biomesTags, NbtTagType.Compound) } }; var nbtFile = new NbtFile(nbtCompound); packet.WriteBytes(nbtFile.GetBuffer()); }
public void OnTeleportConfirm(MinecraftUser user, IMinecraftPacket packet) { int teleportId = packet.ReadVarInt32(); _logger.LogInformation($"Teleport ID: {teleportId}"); }
public void OnStatusRequest(IMinecraftUser user, IMinecraftPacket _) { using var responsePacket = new StatusResponsePacket(_server.GetServerStatus()); user.Send(responsePacket); }
public void SendToAll(IMinecraftPacket packet) { SendPacketToAllPlayers(Overworld, packet); SendPacketToAllPlayers(Nether, packet); SendPacketToAllPlayers(End, packet); }
public void SendTo(IEnumerable <IMinecraftUser> users, IMinecraftPacket packet) => SendTo(users.Cast <MinecraftUser>(), (packet as MinecraftPacket).Buffer);
/// <summary> /// Creates a new <see cref="StatusPingPacket"/> instance. /// </summary> /// <param name="packet"></param> public StatusPingPacket(IMinecraftPacket packet) { Payload = packet.ReadInt64(); }
public void OnKeepAlive(MinecraftUser user, IMinecraftPacket packet) { long keepAliveId = packet.ReadInt64(); user.Player.CheckKeepAlive(keepAliveId); }
public override void SendPacket(IMinecraftPacket packet) => _user.Send(packet);