public void MinecraftPacketReadVarInt64Test(long expectedValue, byte[] packetContent) { using var packet = new MinecraftPacket(0, packetContent); long value = packet.ReadVarInt64(); Assert.Equal(expectedValue, value); }
public void SendPacketViewers(MinecraftPacket packet) { Player[] players = this.Viewers; for (int i = 0; i < players.Length; ++i) { players[i].SendPacket(packet); } }
public void MinecraftPacketWriteVarInt64Test(long valueToWrite, byte[] expectedContent) { using var packet = new MinecraftPacket(0); packet.WriteVarInt64(valueToWrite); Assert.Equal(expectedContent, packet.BaseBuffer); }
private void SendLoginSucess(IMinecraftUser user) { using var p = new MinecraftPacket(ClientLoginPacketType.LoginSuccess); p.WriteUUID(user.Id); p.WriteString(user.Username); user.Send(p); }
public void SendPacket(MinecraftPacket packet, int reliability = RakNetPacketReliability.RELIABLE, int flag = RakNetProtocol.FlagNormal) { NetworkSession session = this.GetSession(); if (session == null) { return; } session.AddPacketBatchQueue(packet, reliability, flag); }
public void BroadcastSendPacket(MinecraftPacket packet, Player[] players = null) { if (players == null) { players = Instance.GetPlayers(); } for (int i = 0; i < players.Length; ++i) { players[i].SendPacket(packet); } }
public override void AddVisibleEntity(IEntity entity) { base.AddVisibleEntity(entity); using MinecraftPacket packet = entity switch { IPlayer playerEntity => new SpawnPlayerPacket(playerEntity), // TODO: add other entity types _ => throw new NotImplementedException() }; SendPacket(packet); }
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 MinecraftPacketWriteJsonTest() { const string json = "{\"text\":\"Hello world!\"}"; byte[] jsonBytes = Encoding.UTF8.GetBytes(json); var jsonObject = new JsonPacketClass("Hello world!"); using var packet = new MinecraftPacket(0); packet.WriteJson(jsonObject); byte[] packetBytes = packet.BaseBuffer.Skip(1).ToArray(); Assert.Equal(jsonBytes, packetBytes); }
public MinecraftPacket GetMinecraftPacket(int msgId, byte[] buffer = null) { MinecraftPacket pk = null; MineNET_Registries.MinecraftPacket.TryGetValue(msgId, out pk); pk = pk?.Clone(); if (pk != null && buffer != null) { pk.SetBuffer(buffer); pk.Decode(); } return(pk); }
public void AddPacketBatchQueue(MinecraftPacket packet, int reliability, int flags = RakNetProtocol.FlagNormal) { packet.Encode(); byte[] buffer = packet.ToArray(); BinaryStream st = new BinaryStream(); st.WriteVarInt((int)buffer.Length); st.WriteBytes(buffer); if (Server.Instance.Config.PacketDebug) { Logger.Debug("%server.network.minecraft.sendPacket", packet.PacketID.ToString("X"), packet.Length); } BatchPacket pk = new BatchPacket(); if (packet is FullChunkDataPacket) { pk.CompressionLevel = CompressionLevel.Optimal; } pk.Payload = st.ToArray(); string endPointStr = this.EndPoint.ToString(); Player player = null; Server.Instance.Network.Players.TryGetValue(endPointStr, out player); if (player == null) { return; } RakNetBatchPacketSendEventArgs ev = new RakNetBatchPacketSendEventArgs(this, player, pk); Server.Instance.Event.Network.OnRakNetBatchPacketSend(this, ev); if (ev.IsCancel) { return; } pk = ev.Packet; this.QueueConnectedPacket(pk, reliability, packet.OrderChannel, flags); }
public void MinecraftPacketReadUUIDTest(Guid expectedValue, byte[] packetContent) { // FIX: little/big Endian if (BitConverter.IsLittleEndian) { byte[] firstLong = packetContent.Take(8).Reverse().ToArray(); byte[] secondLong = packetContent.Skip(8).Reverse().ToArray(); packetContent = firstLong.Concat(secondLong).ToArray(); } using var packet = new MinecraftPacket(0, packetContent); Guid value = packet.ReadUUID(); Assert.Equal(expectedValue, value); }
public void MinecraftPacketWriteUUIDTest(Guid valueToWrite, byte[] expectedContent) { using var packet = new MinecraftPacket(0); packet.WriteUUID(valueToWrite); // FIX: little/big Endian if (BitConverter.IsLittleEndian) { byte[] firstLong = expectedContent.Take(8).Reverse().ToArray(); byte[] secondLong = expectedContent.Skip(8).Reverse().ToArray(); expectedContent = firstLong.Concat(secondLong).ToArray(); } Assert.Equal(expectedContent, packet.BaseBuffer); }
public void Write(MinecraftPacket stream) { stream.WriteSVarInt(this.ID); stream.WriteUVarInt((uint)this.RecipeItems.Length); for (int i = 0; i < this.RecipeItems.Length; ++i) { stream.WriteItem(this.RecipeItems[i]); } stream.WriteUVarInt((uint)this.Output.Length); for (int i = 0; i < this.Output.Length; ++i) { stream.WriteItem(this.Output[i]); } stream.WriteUUID(this.UUID); }
public void MulticastAsync(MinecraftPacket packet, TcpSession excludeSession = null, params TcpSession[] sessions) { Task.Run(() => { if (!IsStarted) { return; } if (packet == null) { return; } foreach (TcpSession session in sessions) { if (session is MinecraftClient client) { if (client.GameState != MinecraftClient.State.Playing) { continue; } if (excludeSession != null) { if (session != excludeSession) { client.Send(new MinecraftPacket(client, packet)); } } else { client.Send(new MinecraftPacket(client, packet)); } } } packet.Dispose(); }); }
public void HandleInventoryAction(MinecraftPacket packet) { switch (packet) { case CP25HeldItemChange heldItemChange: Inventory.HeldSlot = heldItemChange.Slot + 36; // mojang moment break; case CP28CreativeInventoryAction creativeInventoryAction: if (creativeInventoryAction.Slot == -1) { // TODO spawn item entity here } else { Inventory.Slots[creativeInventoryAction.Slot] = creativeInventoryAction.ClickedItem.IsEmpty() ? Inventories.Inventory.Slot.Empty : creativeInventoryAction.ClickedItem; } break; } }
public void HandleMinecraftPacket(BatchPacket pk, Player player) { using (BinaryStream stream = new BinaryStream(pk.Payload)) { while (!stream.EndOfStream) { int len = stream.ReadVarInt(); byte[] buffer = stream.ReadBytes(len); MinecraftPacket packet = this.Manager.GetMinecraftPacket(buffer[0], buffer); if (packet != null) { /*DataPacketReceiveArgs args = new DataPacketReceiveArgs(player, pk); * ServerEvents.OnPacketReceive(args); * * if (args.IsCancel) * { * return; * }*/ if (Server.Instance.Config.PacketDebug) { Logger.Debug("%server.network.minecraft.receivePacket", buffer[0].ToString("X"), buffer.Length); } Server.Instance.Invoke(() => player.OnPacketHandle(packet.Clone())); } else { if (Server.Instance.Config.PacketDebug) { Logger.Debug("%server.network.minecraft.notHandle", buffer[0].ToString("X")); } } } } }
public static void Run(string[] args) { Directory.CreateDirectory(WORLDS_DIRECTORY); Logger.Out = Console.Out; #if DEBUG Logger.MinimumLevel = LogLevel.Debug; #else Logger.MinimumLevel = LogLevel.Info; #endif AppDomain.CurrentDomain.UnhandledException += ShutdownHook; AppDomain.CurrentDomain.ProcessExit += ShutdownHook; MinecraftPacket.Initialize(); BaseEntity.Initialize(); BlockRepository.Initialize(); ItemRepository.Initialize(); Tag.Initialize(); Server = new MinecraftServer(IPAddress.Any, args.Length > 0 ? int.Parse(args[0]) : 25565); Server.Start(); }
private void WriteChunkSection(ChunkSection section, ref MemoryStream stream) { #region Section byte bitsPerBlock = FULL_SIZE_BITS_PER_BLOCK; MinecraftPacket.WriteToStream(stream, bitsPerBlock); //0: disabled? //MinecraftPacket.WriteToStream(stream, (VarInt)0); //up to 4: Blocks are encoded as 4 bits. The palette is used and sent. //5 to 8: Blocks are encoded with the given number of bits.The palette is used and sent. //9 and above: The palette is not sent. Blocks are encoded by their whole ID in the global palette, with bits per block being set as the base 2 logarithm of the number of block states, rounded up. For the current vanilla release, this is 14 bits per block. // A bitmask that contains bitsPerBlock set bits uint individualValueMask = (uint)((1 << bitsPerBlock) - 1); int dataLength = (Constants.SECTION_HEIGHT * Constants.SECTION_WIDTH * Constants.SECTION_DEPTH) * bitsPerBlock / 64; UInt64[] DataArray = new UInt64[dataLength]; for (int y = 0; y < Constants.SECTION_HEIGHT; y++) { for (int z = 0; z < Constants.SECTION_WIDTH; z++) { for (int x = 0; x < Constants.SECTION_WIDTH; x++) { var blockPos = new Vector3(x, y, z); int blockNumber = ((((int)blockPos.Y * Constants.SECTION_HEIGHT) + (int)blockPos.Z) * Constants.SECTION_WIDTH) + (int)blockPos.X; int startLong = (blockNumber * bitsPerBlock) / 64; int startOffset = (blockNumber * bitsPerBlock) % 64; int endLong = ((blockNumber + 1) * bitsPerBlock - 1) / 64; Block state = section.blocks[blockPos]; //C# Still limits the Byte Size to uint if this is a uint, //even after byteshifting into a ulong ulong value = (ulong)state.GetGlobalPaletteIDFromState(); value &= individualValueMask; DataArray[startLong] |= (value << startOffset); if (startLong != endLong) { DataArray[endLong] = (value >> (64 - startOffset)); } } } } Console.WriteLine($"Data Array was {DataArray.Length} long"); MinecraftPacket.WriteToStream(stream, (VarInt)dataLength); MinecraftPacket.WriteArrayToStream(stream, DataArray); List <byte> BlockLightData = new List <byte>(); for (int y = 0; y < Constants.SECTION_HEIGHT; y++) { for (int z = 0; z < Constants.SECTION_WIDTH; z++) { for (int x = 0; x < Constants.SECTION_WIDTH; x += 2) { // Note: x += 2 above; we read 2 values along x each time byte blocklight1 = (byte)(section.blocks[new Vector3(x, y, z)].BlockLight); //this only works because 16 is even byte blocklight2 = (byte)(section.blocks[new Vector3(x + 1, y, z)].BlockLight << 4); byte value = (byte)(blocklight1 | blocklight2); BlockLightData.Add(value); } } } Console.WriteLine($"BlockLight was {BlockLightData.Count} Long"); MinecraftPacket.WriteArrayToStream(stream, BlockLightData.ToArray()); List <byte> SkyLightData = new List <byte>(); if (section.HasSkylight) { // => current dimension is overworld / 0 for (int y = 0; y < Constants.SECTION_HEIGHT; y++) { for (int z = 0; z < Constants.SECTION_WIDTH; z++) { for (int x = 0; x < Constants.SECTION_WIDTH; x += 2) { // Note: x += 2 above; we read 2 values along x each time byte blocklight1 = (byte)(section.blocks[new Vector3(x, y, z)].SkyLight); //this only works because 16 is even byte blocklight2 = (byte)(section.blocks[new Vector3(x + 1, y, z)].SkyLight << 4); byte value = (byte)(blocklight1 | blocklight2); SkyLightData.Add(value); } } } } Console.WriteLine($"SkyLight was {SkyLightData.Count} Long"); MinecraftPacket.WriteArrayToStream(stream, SkyLightData.ToArray()); #endregion }
public void HandleWorldAction(MinecraftPacket packet) { switch (packet) { case CP1BPlayerDigging digging: bool IsLegal(double x1, double y1, double z1, double x2, double y2, double z2) { return(Math.Sqrt(Math.Pow(x2 - x1, 2) + Math.Pow(y2 - y1, 2) + Math.Pow(z2 - z1, 2)) <= 6.0); } BlockBase block = Parent.GetBlock(digging.Location.X, digging.Location.Y, digging.Location.Z); SP07AcknowledgePlayerDigging acknowledgePlayerDigging; if (block == null) { acknowledgePlayerDigging = new SP07AcknowledgePlayerDigging(Client, digging.Location, 0, (SP07AcknowledgePlayerDigging.ActionType)digging.Status, false); Client.Send(acknowledgePlayerDigging); break; } if (!IsLegal(X, Y + 1.5, Z, digging.Location.X, digging.Location.Y, digging.Location.Z)) { acknowledgePlayerDigging = new SP07AcknowledgePlayerDigging(Client, digging.Location, block.State, (SP07AcknowledgePlayerDigging.ActionType)digging.Status, false); Client.Send(acknowledgePlayerDigging); break; } acknowledgePlayerDigging = new SP07AcknowledgePlayerDigging(Client, digging.Location, block.State, (SP07AcknowledgePlayerDigging.ActionType)digging.Status, true); Client.Send(acknowledgePlayerDigging); // TODO block break animation CP1BPlayerDigging.ActionType requiredAction; if (Gamemode == Gamemode.Creative) { requiredAction = CP1BPlayerDigging.ActionType.StartedDigging; } else { requiredAction = CP1BPlayerDigging.ActionType.FinishedDigging; } if (digging.Status == requiredAction) { BlockBase air = new BlockAir(); Parent.SetBlock(air, digging.Location.X, digging.Location.Y, digging.Location.Z); SP0BBlockChange blockChange = new(null, digging.Location, air.State); Client.Server.MulticastAsync(blockChange, Client, Parent.GetClientsWithChunkLoaded( (int)Math.Floor((double)digging.Location.X / Chunk.X_SIZE), (int)Math.Floor((double)digging.Location.Z / Chunk.Z_SIZE)).ToArray()); } break; case CP2EPlayerBlockPlacement playerBlockPlacement: Position.Int pos = new(playerBlockPlacement.Location); switch (playerBlockPlacement.Face) { case Face.Top: pos.Y++; break; case Face.Bottom: pos.Y--; break; case Face.North: pos.Z--; break; case Face.East: pos.X++; break; case Face.South: pos.Z++; break; case Face.West: pos.X--; break; } // TODO check for collisions here if (Parent.GetBlock(pos.X, pos.Y, pos.Z) == null) { Inventory.Slot held = Inventory.Slots[Inventory.HeldSlot]; if (!held.IsEmpty() && held.Item is BlockItem item) { block = BlockRepository.Create(item.BlockProtocolId); if (block == null || block.State == 0) { break; } if (pos.Y < 0 || pos.Y >= Chunk.Y_SIZE) { return; } Parent.SetBlock(block, pos.X, pos.Y, pos.Z); SP0BBlockChange _blockChange = new(null, pos, block.State); Client.Server.MulticastAsync(_blockChange, Client, Parent.GetClientsWithChunkLoaded( (int)Math.Floor((double)pos.X / Chunk.X_SIZE), (int)Math.Floor((double)pos.Z / Chunk.Z_SIZE)).ToArray()); } } break; case CP1CEntityAction: break; } }
public void HandleMovement(MinecraftPacket packet) { LastX = X; LastY = Y; LastZ = Z; LastOnGround = OnGround; double newX = X; double newY = Y; double newZ = Z; float newYaw = Yaw; float newPitch = Pitch; bool newOnGround = OnGround; switch (packet) { case CP12PlayerPosition p: newX = p.X; newY = p.FeetY; newZ = p.Z; newOnGround = p.OnGround; break; case CP13PlayerPositionAndRotation _p: newX = _p.X; newY = _p.FeetY; newZ = _p.Z; newYaw = _p.Yaw; newPitch = _p.Pitch; newOnGround = _p.OnGround; break; case CP14PlayerRotation __p: newYaw = __p.Yaw; newPitch = __p.Pitch; newOnGround = __p.OnGround; break; case CP15PlayerMovement: SP2AEntityMovement entityMovement = new(Client, EntityId); Client.Server.MulticastAsync(entityMovement, Client); return; } if (newX != LastX || newY != LastY || newZ != LastZ) { if (double.IsInfinity(newX) || double.IsInfinity(newY) || double.IsInfinity(newZ) || newX > 3.2 * Math.Pow(10, 7) || newZ > 3.2 * Math.Pow(10, 7)) { SP19Disconnect disconnect = new(Client, new { text = "Invalid move packet received" }); Client.Send(disconnect); Client.Disconnect(); } double deltaX = newX - LastX; double deltaY = newY - LastY; double deltaZ = newZ - LastZ; double total = Math.Pow(deltaX, 2) + Math.Pow(deltaY, 2) + Math.Pow(deltaZ, 2); double expected = Math.Pow(LastX, 2) + Math.Pow(LastY, 2) + Math.Pow(LastZ, 2); // TODO 300 if elytra if (total - expected > 100) { Logger.Info($"Player [{Username}] moved too fast!"); SP56EntityTeleport teleport = new(Client, EntityId, LastX, LastY, LastZ, Yaw, Pitch, LastOnGround); Client.Send(teleport); } X = newX; Y = newY; Z = newZ; OnGround = newOnGround; SP27EntityPosition entityPosition = new(Client, EntityId, (short)(((X * 32) - (LastX * 32)) * 128), (short)(((Y * 32) - (LastY * 32)) * 128), (short)(((Z * 32) - (LastZ * 32)) * 128), OnGround); Client.Server.MulticastAsync(entityPosition, Client); // player changed chunk if (ChunkX != (int)Math.Floor(LastX / Chunk.X_SIZE) || ChunkZ != (int)Math.Floor(LastZ / Chunk.Z_SIZE)) { SP40UpdateViewPosition updateViewPosition = new(Client, ChunkX, ChunkZ); Client.Send(updateViewPosition); Chunk[] chunks = Parent.GetChunksInViewDistance(ChunkX, ChunkZ, Client.Configuration.ViewDistance); IEnumerable <Chunk> toUnload = Client.LoadedChunks.Except(chunks); IEnumerable <Chunk> toLoad = chunks.Except(Client.LoadedChunks); Client.UnloadChunks(toUnload.ToArray()); Client.LoadChunks(toLoad.ToArray()); } } // TODO fix this somehow if (newYaw != Yaw || newPitch != Pitch) { double x = -Math.Cos(newPitch) * Math.Sin(newYaw); double y = -Math.Sin(newPitch); double z = Math.Cos(newPitch) * Math.Cos(newYaw); double dx = x - X; double dy = y - Y; double dz = z - Z; double r = Math.Sqrt((dx * dx) + (dy * dy) + (dz * dz)); double yaw = (-Math.Atan2(dx, dz) / Math.PI) * 180; if (yaw < 0) { yaw = 360 + yaw; } double pitch = (-Math.Asin(dy / r) / Math.PI) * 180; Yaw = (float)yaw; Pitch = (float)pitch; OnGround = newOnGround; SP29EntityRotation entityRotation = new(Client, EntityId, Yaw, Pitch, OnGround); Client.Server.MulticastAsync(entityRotation, Client); } }
public void Write(MinecraftPacket stream) { throw new System.NotImplementedException(); }