// Server sends entity data to Client public void PlayerData(ulong code, float posX, float posY, float posZ, float dirX, float dirY, float dirZ) { NetDecoder.WriteLong(code, NetMessage.buffer, 1); NetDecoder.WriteFloat3(posX, posY, posZ, NetMessage.buffer, 9); NetDecoder.WriteFloat3(dirX, dirY, dirZ, NetMessage.buffer, 21); this.size = 33; }
// Receives a Chunk private void SendChunk(byte[] data) { ChunkPos pos = NetDecoder.ReadChunkPos(data, 1); this.cl.toLoad.Add(data); this.cl.toLoadChunk.Add(pos); }
// Receives Player Information saved on server on startup private void SendServerInfo(byte[] data) { float x, y, z, xDir, yDir, zDir; CastCoord initialCoord; x = NetDecoder.ReadFloat(data, 1); y = NetDecoder.ReadFloat(data, 5); z = NetDecoder.ReadFloat(data, 9); xDir = NetDecoder.ReadFloat(data, 13); yDir = NetDecoder.ReadFloat(data, 17); zDir = NetDecoder.ReadFloat(data, 21); this.cl.PLAYERSPAWNED = true; this.cl.playerX = x; this.cl.playerY = y; this.cl.playerZ = z; this.cl.playerDirX = xDir; this.cl.playerDirY = yDir; this.cl.playerDirZ = zDir; // Finds current Chunk and sends position data initialCoord = new CastCoord(x, y, z); this.cl.time.SetCurrentChunkPos(initialCoord.GetChunkPos()); this.cl.time.SendChunkPosMessage(); }
// Loads the chunk into the Chunkloader private void LoadChunk() { if (toLoad.Count > 0) { int min; // Sets the current iteration amount if (3 <= toLoad.Count) { min = 3; } else { min = toLoad.Count; } for (int i = 0; i < min; i++) { byte[] data = toLoad[0]; int headerSize = RegionFileHandler.chunkHeaderSize; ChunkPos cp = NetDecoder.ReadChunkPos(data, 1); // Prevention if (this.chunks.ContainsKey(cp)) { this.chunks[cp].Destroy(); this.chunks.Remove(cp); } int blockDataSize = NetDecoder.ReadInt(data, 9); int hpDataSize = NetDecoder.ReadInt(data, 13); int stateDataSize = NetDecoder.ReadInt(data, 17); this.chunks[cp] = new Chunk(cp, this.rend, this.blockBook, this); this.chunks[cp].biomeName = BiomeHandler.ByteToBiome(data[21]); Compression.DecompressBlocksClient(this.chunks[cp], data, initialPos: 21 + headerSize); Compression.DecompressMetadataHPClient(this.chunks[cp], data, initialPos: 21 + headerSize + blockDataSize); Compression.DecompressMetadataStateClient(this.chunks[cp], data, initialPos: 21 + headerSize + blockDataSize + hpDataSize); if (this.vfx.data.ContainsKey(cp)) { this.vfx.RemoveChunk(cp); } this.vfx.NewChunk(cp); if (!this.toDraw.Contains(cp)) { this.toDraw.Add(cp); } toLoad.RemoveAt(0); toLoadChunk.RemoveAt(0); } } }
// Receives block damage information from server private void BlockDamage(byte[] data) { ChunkPos pos; int x, y, z; ushort newHP; bool shouldRedraw; Chunk c; pos = NetDecoder.ReadChunkPos(data, 1); x = NetDecoder.ReadInt(data, 9); y = NetDecoder.ReadInt(data, 13); z = NetDecoder.ReadInt(data, 17); newHP = NetDecoder.ReadUshort(data, 21); shouldRedraw = NetDecoder.ReadBool(data, 23); if (this.cl.chunks.ContainsKey(pos)) { c = this.cl.chunks[pos]; c.metadata.SetHP(x, y, z, newHP); if (shouldRedraw) { this.cl.AddToUpdate(pos); CheckReload(pos, x, y, z); } } }
// Receives an Interaction command from client private void Interact(byte[] data) { ChunkPos pos = NetDecoder.ReadChunkPos(data, 1); int x = NetDecoder.ReadInt(data, 9); int y = NetDecoder.ReadInt(data, 13); int z = NetDecoder.ReadInt(data, 17); int facing = NetDecoder.ReadInt(data, 21); int callback; CastCoord current = new CastCoord(pos, x, y, z); ushort blockCode = this.cl.GetBlock(current); if (blockCode <= ushort.MaxValue / 2) { callback = this.cl.blockBook.blocks[blockCode].OnInteract(pos, current.blockX, current.blockY, current.blockZ, this.cl); } else { callback = this.cl.blockBook.objects[ushort.MaxValue - blockCode].OnInteract(pos, current.blockX, current.blockY, current.blockZ, this.cl); } // Actual handling of message CallbackHandler(callback, pos, current, facing); }
// Receives player position and adds it to PlayerPositions Dict private void ClientPlayerPosition(byte[] data, ulong id) { float3 pos, dir; ChunkPos cp; NetMessage graphMessage = new NetMessage(NetCode.PLAYERDATA); pos = NetDecoder.ReadFloat3(data, 1); dir = NetDecoder.ReadFloat3(data, 13); this.cl.regionHandler.allPlayerData[id].SetPosition(pos.x, pos.y, pos.z); this.cl.regionHandler.allPlayerData[id].SetDirection(dir.x, dir.y, dir.z); cp = this.cl.regionHandler.allPlayerData[id].GetChunkPos(); if (!this.entityHandler.Contains(EntityType.PLAYER, cp, id)) { this.entityHandler.AddPlayer(cp, id, pos, dir); } this.entityHandler.SetPosition(EntityType.PLAYER, id, cp, pos); this.entityHandler.SetRotation(EntityType.PLAYER, id, cp, dir); // Propagates data to all network foreach (ulong code in this.connectionGraph[id]) { graphMessage.PlayerData(this.cl.regionHandler.allPlayerData[id]); this.Send(graphMessage.GetMessage(), graphMessage.size, code); } }
// Deletes the connection between a client and a chunk private void RequestChunkUnload(byte[] data, ulong id) { ChunkPos pos = NetDecoder.ReadChunkPos(data, 1); NetMessage killMessage = new NetMessage(NetCode.ENTITYDELETE); if (this.playersInChunk.ContainsKey(pos)) { foreach (ulong code in this.playersInChunk[pos]) { if (code == id) { continue; } this.connectionGraph[code].Remove(id); killMessage.EntityDelete(EntityType.PLAYER, code); this.Send(killMessage.GetMessage(), killMessage.size, id); } } if (this.entityHandler.Contains(EntityType.DROP, pos)) { foreach (ulong itemCode in this.entityHandler.dropObject[pos].Keys) { killMessage.EntityDelete(EntityType.DROP, itemCode); this.Send(killMessage.GetMessage(), killMessage.size, id); } } this.cl.UnloadChunk(pos, id); }
// Sends time data to Client public void SendGameTime(uint day, byte hour, byte minute) { NetDecoder.WriteUint(day, NetMessage.buffer, 1); NetDecoder.WriteByte(hour, NetMessage.buffer, 5); NetDecoder.WriteByte(minute, NetMessage.buffer, 6); this.size = 7; }
// Receives dd:hh:mm from server private void SendGameTime(byte[] data) { uint days = NetDecoder.ReadUint(data, 1); byte hours = data[5]; byte minutes = data[6]; this.cl.time.SetTime(days, hours, minutes); }
// Receives entity deletion command private void EntityDelete(byte[] data) { EntityType type = (EntityType)data[1]; ulong code = NetDecoder.ReadUlong(data, 2); this.entityHandler.Remove(type, code); this.smoothMovement.Remove(type, code); }
// Captures client info private void SendClientInfo(byte[] data, ulong id) { NetMessage message = new NetMessage(NetCode.SENDSERVERINFO); ulong accountID = NetDecoder.ReadUlong(data, 1); int renderDistance = NetDecoder.ReadInt(data, 9); int seed = NetDecoder.ReadInt(data, 13); int stringSize = NetDecoder.ReadInt(data, 17); string worldName = NetDecoder.ReadString(data, 21, stringSize); playerRenderDistances[accountID] = renderDistance; if (this.isLocal) { World.worldName = worldName; World.worldSeed = seed; } // Sends Player Info if (this.cl.RECEIVEDWORLDDATA) { PlayerData pdat = this.cl.regionHandler.LoadPlayer(accountID); pdat.SetOnline(true); Vector3 playerPos = pdat.GetPosition(); Vector3 playerDir = pdat.GetDirection(); message.SendServerInfo(playerPos.x, playerPos.y, playerPos.z, playerDir.x, playerDir.y, playerDir.z); this.Send(message.GetMessage(), message.size, id, temporary: true); } // If AccountID is already online, erase all memory from that connection if (this.connections.ContainsKey(accountID)) { Disconnect(accountID, DisconnectType.LOGINOVERWRITE); } // Assigns a fixed ID this.connections.Add(accountID, this.temporaryConnections[id]); this.temporaryConnections.Remove(id); this.lengthPacket[accountID] = true; this.packetIndex[accountID] = 0; this.connectionGraph.Add(accountID, new HashSet <ulong>()); this.receiveBuffer.Add(accountID, new byte[receiveBufferSize]); this.receiveBuffer.Remove(id); this.cl.RECEIVEDWORLDDATA = true; if (this.firstConnectedID == ulong.MaxValue) { this.firstConnectedID = accountID; } this.timeoutTimers.Add(accountID, DateTime.Now); Debug.Log("Temporary ID: " + id + " was assigned to ID: " + accountID); this.connections[accountID].BeginReceive(this.receiveBuffer[accountID], 0, 4, 0, out this.err, new AsyncCallback(ReceiveCallback), accountID); }
// Client sends a voxel coordinate to trigger OnInteraction in server public void Interact(ChunkPos pos, int x, int y, int z, int facing) { NetDecoder.WriteChunkPos(pos, NetMessage.buffer, 1); NetDecoder.WriteInt(x, NetMessage.buffer, 9); NetDecoder.WriteInt(y, NetMessage.buffer, 13); NetDecoder.WriteInt(z, NetMessage.buffer, 17); NetDecoder.WriteInt(facing, NetMessage.buffer, 21); this.size = 25; }
// Receives a failed request notification from server and immediately re-tries private void FailedChunkRequest(byte[] data) { ChunkPos pos = NetDecoder.ReadChunkPos(data, 1); NetMessage message = new NetMessage(NetCode.REQUESTCHUNKLOAD); message.RequestChunkLoad(pos); this.Send(message.GetMessage(), message.size); }
// Item Entity Data public void ItemEntityData(float posX, float posY, float posZ, float rotX, float rotY, float rotZ, ushort itemCode, byte amount, ulong entityCode) { NetDecoder.WriteFloat3(posX, posY, posZ, NetMessage.buffer, 1); NetDecoder.WriteFloat3(rotX, rotY, rotZ, NetMessage.buffer, 13); NetDecoder.WriteUshort(itemCode, NetMessage.buffer, 25); NetDecoder.WriteByte(amount, NetMessage.buffer, 27); NetDecoder.WriteLong(entityCode, NetMessage.buffer, 28); this.size = 36; }
// Receives a Direct Block Update from server private void DirectBlockUpdate(byte[] data) { ChunkPos pos; int x, y, z; ushort blockCode, state, hp; BUDCode type; pos = NetDecoder.ReadChunkPos(data, 1); x = NetDecoder.ReadInt(data, 9); y = NetDecoder.ReadInt(data, 13); z = NetDecoder.ReadInt(data, 17); int facing = NetDecoder.ReadInt(data, 21); blockCode = NetDecoder.ReadUshort(data, 25); state = NetDecoder.ReadUshort(data, 27); hp = NetDecoder.ReadUshort(data, 29); type = (BUDCode)NetDecoder.ReadInt(data, 31); switch (type) { case BUDCode.PLACE: if (this.cl.chunks.ContainsKey(pos)) { this.cl.chunks[pos].data.SetCell(x, y, z, blockCode); this.cl.chunks[pos].metadata.SetState(x, y, z, state); this.cl.chunks[pos].metadata.SetHP(x, y, z, hp); this.cl.chunks[pos].data.CalculateHeightMap(x, z); this.cl.AddToUpdate(pos); CheckReload(pos, x, y, z); } break; case BUDCode.BREAK: if (this.cl.chunks.ContainsKey(pos)) { this.cl.chunks[pos].data.SetCell(x, y, z, 0); this.cl.chunks[pos].metadata.Reset(x, y, z); this.cl.chunks[pos].data.CalculateHeightMap(x, z); this.cl.AddToUpdate(pos); CheckReload(pos, x, y, z); } break; case BUDCode.CHANGE: if (this.cl.chunks.ContainsKey(pos)) { this.cl.chunks[pos].data.SetCell(x, y, z, blockCode); this.cl.chunks[pos].metadata.SetState(x, y, z, state); this.cl.chunks[pos].metadata.SetHP(x, y, z, hp); this.cl.AddToUpdate(pos); } break; default: break; } }
// Client sends item information for server to create a Dropped Item Entity public void DropItem(float posX, float posY, float posZ, float rotX, float rotY, float rotZ, float moveX, float moveY, float moveZ, ushort itemCode, byte amount) { NetDecoder.WriteFloat3(posX, posY, posZ, NetMessage.buffer, 1); NetDecoder.WriteFloat3(rotX, rotY, rotZ, NetMessage.buffer, 13); NetDecoder.WriteFloat3(moveX, moveY, moveZ, NetMessage.buffer, 25); NetDecoder.WriteUshort(itemCode, NetMessage.buffer, 37); NetDecoder.WriteByte(amount, NetMessage.buffer, 39); this.size = 40; }
// Server sending player character position public void SendServerInfo(float xPos, float yPos, float zPos, float xDir, float yDir, float zDir) { NetDecoder.WriteFloat(xPos, NetMessage.buffer, 1); NetDecoder.WriteFloat(yPos, NetMessage.buffer, 5); NetDecoder.WriteFloat(zPos, NetMessage.buffer, 9); NetDecoder.WriteFloat(xDir, NetMessage.buffer, 13); NetDecoder.WriteFloat(yDir, NetMessage.buffer, 17); NetDecoder.WriteFloat(zDir, NetMessage.buffer, 21); this.size = 25; }
// Client or server sends a block damage operation to server // TODO: Add Damage Type public void BlockDamage(ChunkPos pos, int x, int y, int z, ushort newHPOrDamage, bool shouldRedrawChunk) { NetDecoder.WriteChunkPos(pos, NetMessage.buffer, 1); NetDecoder.WriteInt(x, NetMessage.buffer, 9); NetDecoder.WriteInt(y, NetMessage.buffer, 13); NetDecoder.WriteInt(z, NetMessage.buffer, 17); NetDecoder.WriteUshort(newHPOrDamage, NetMessage.buffer, 21); NetDecoder.WriteBool(shouldRedrawChunk, NetMessage.buffer, 23); this.size = 24; }
// Clients sends their position to Server public void ClientPlayerPosition(float x, float y, float z, float rotX, float rotY, float rotZ) { NetDecoder.WriteFloat(x, NetMessage.buffer, 1); NetDecoder.WriteFloat(y, NetMessage.buffer, 5); NetDecoder.WriteFloat(z, NetMessage.buffer, 9); NetDecoder.WriteFloat(rotX, NetMessage.buffer, 13); NetDecoder.WriteFloat(rotY, NetMessage.buffer, 17); NetDecoder.WriteFloat(rotZ, NetMessage.buffer, 21); this.size = 25; }
// Server sends VFX deletion information to Client public void VFXBreak(ChunkPos pos, int x, int y, int z, ushort blockCode, ushort state) { NetDecoder.WriteChunkPos(pos, NetMessage.buffer, 1); NetDecoder.WriteInt(x, NetMessage.buffer, 9); NetDecoder.WriteInt(y, NetMessage.buffer, 13); NetDecoder.WriteInt(z, NetMessage.buffer, 17); NetDecoder.WriteUshort(blockCode, NetMessage.buffer, 21); NetDecoder.WriteUshort(state, NetMessage.buffer, 23); this.size = 25; }
// Receive call handling private void ReceiveCallback(IAsyncResult result) { try{ // Resets timeout timer this.lastMessageTime = DateTime.Now; int bytesReceived = this.socket.EndReceive(result); // If has received a length Packet if (this.lengthPacket) { int size = NetDecoder.ReadInt(receiveBuffer, 0); // Ignores packets that are way too big if (size > Client.maxBufferSize) { this.socket.BeginReceive(receiveBuffer, 0, size, 0, out this.err, new AsyncCallback(ReceiveCallback), null); return; } this.dataBuffer = new byte[size]; this.packetSize = size; this.packetIndex = 0; this.lengthPacket = false; this.socket.BeginReceive(receiveBuffer, 0, size, 0, out this.err, new AsyncCallback(ReceiveCallback), null); return; } // If has received a segmented packet if (bytesReceived + this.packetIndex < this.packetSize) { Array.Copy(receiveBuffer, 0, this.dataBuffer, this.packetIndex, bytesReceived); this.packetIndex = this.packetIndex + bytesReceived; this.socket.BeginReceive(receiveBuffer, 0, this.packetSize - this.packetIndex, 0, out this.err, new AsyncCallback(ReceiveCallback), null); return; } Array.Copy(receiveBuffer, 0, this.dataBuffer, this.packetIndex, bytesReceived); NetMessage.Broadcast(NetBroadcast.RECEIVED, dataBuffer[0], 0, this.packetSize); NetMessage receivedMessage = new NetMessage(this.dataBuffer, 0); this.queue.Add(receivedMessage); this.lengthPacket = true; this.packetSize = 0; this.packetIndex = 0; this.socket.BeginReceive(receiveBuffer, 0, 4, 0, out this.err, new AsyncCallback(ReceiveCallback), null); } catch (Exception e) { Debug.Log(e.ToString()); } }
// Adds a new block information to BatchLoadBUD message public void AddBatchLoad(int x, int y, int z, int facing, ushort blockCode, ushort state, ushort hp) { NetDecoder.WriteInt(x, NetMessage.buffer, this.size); NetDecoder.WriteInt(y, NetMessage.buffer, this.size + 4); NetDecoder.WriteInt(z, NetMessage.buffer, this.size + 8); NetDecoder.WriteInt(facing, NetMessage.buffer, this.size + 12); NetDecoder.WriteUshort(blockCode, NetMessage.buffer, this.size + 16); NetDecoder.WriteUshort(state, NetMessage.buffer, this.size + 18); NetDecoder.WriteUshort(hp, NetMessage.buffer, this.size + 20); this.size += 22; }
// Server sends VFX change of state to Client public void VFXChange(ChunkPos pos, int x, int y, int z, int facing, ushort blockCode, ushort state) { NetDecoder.WriteChunkPos(pos, NetMessage.buffer, 1); NetDecoder.WriteInt(x, NetMessage.buffer, 9); NetDecoder.WriteInt(y, NetMessage.buffer, 13); NetDecoder.WriteInt(z, NetMessage.buffer, 17); NetDecoder.WriteInt(facing, NetMessage.buffer, 21); NetDecoder.WriteUshort(blockCode, NetMessage.buffer, 25); NetDecoder.WriteUshort(state, NetMessage.buffer, 27); this.size = 29; }
// Loads PlayerData from pdat file // Used when loading non-online players public PlayerData(byte[] data) { this.ID = NetDecoder.ReadUlong(data, 0); this.posX = NetDecoder.ReadFloat(data, 8); this.posY = NetDecoder.ReadFloat(data, 12); this.posZ = NetDecoder.ReadFloat(data, 16); this.dirX = NetDecoder.ReadFloat(data, 20); this.dirY = NetDecoder.ReadFloat(data, 24); this.dirZ = NetDecoder.ReadFloat(data, 28); this.isOnline = false; this.pos = this.GetChunkPos(); }
// Sends a BUD packet to the server public void SendBUD(BUDSignal bud, int timeOffset) { NetDecoder.WriteInt((int)bud.type, NetMessage.buffer, 1); NetDecoder.WriteInt(bud.x, NetMessage.buffer, 5); NetDecoder.WriteInt(bud.y, NetMessage.buffer, 9); NetDecoder.WriteInt(bud.z, NetMessage.buffer, 13); NetDecoder.WriteInt(bud.budX, NetMessage.buffer, 17); NetDecoder.WriteInt(bud.budY, NetMessage.buffer, 21); NetDecoder.WriteInt(bud.budZ, NetMessage.buffer, 25); NetDecoder.WriteInt(bud.facing, NetMessage.buffer, 29); NetDecoder.WriteInt(timeOffset, NetMessage.buffer, 33); this.size = 37; }
// Client or Server send a single voxel data to each other public void DirectBlockUpdate(BUDCode type, ChunkPos pos, int x, int y, int z, int facing, ushort blockCode, ushort state, ushort hp) { NetDecoder.WriteChunkPos(pos, NetMessage.buffer, 1); NetDecoder.WriteInt(x, NetMessage.buffer, 9); NetDecoder.WriteInt(y, NetMessage.buffer, 13); NetDecoder.WriteInt(z, NetMessage.buffer, 17); NetDecoder.WriteInt(facing, NetMessage.buffer, 21); NetDecoder.WriteUshort(blockCode, NetMessage.buffer, 25); NetDecoder.WriteUshort(state, NetMessage.buffer, 27); NetDecoder.WriteUshort(hp, NetMessage.buffer, 29); NetDecoder.WriteInt((int)type, NetMessage.buffer, 31); this.size = 35; }
public byte[] ToByteArray() { byte[] data = new byte[RegionFileHandler.pdatEntrySize]; NetDecoder.WriteLong(this.ID, data, 0); NetDecoder.WriteFloat(this.posX, data, 8); NetDecoder.WriteFloat(this.posY, data, 12); NetDecoder.WriteFloat(this.posZ, data, 16); NetDecoder.WriteFloat(this.dirX, data, 20); NetDecoder.WriteFloat(this.dirY, data, 24); NetDecoder.WriteFloat(this.dirZ, data, 28); return(data); }
// Receives a BatchLoadBUD request from client, with plenty of block coordinates in a chunk private void BatchLoadBUD(byte[] data, ulong id) { ChunkPos pos; int x, y, z, facing; ushort blockCode, state, hp; int currentByte = 9; CastCoord lastCoord; pos = NetDecoder.ReadChunkPos(data, 1); while (data.Length > currentByte) { x = NetDecoder.ReadInt(data, currentByte); y = NetDecoder.ReadInt(data, currentByte + 4); z = NetDecoder.ReadInt(data, currentByte + 8); facing = NetDecoder.ReadInt(data, currentByte + 12); blockCode = NetDecoder.ReadUshort(data, currentByte + 16); state = NetDecoder.ReadUshort(data, currentByte + 18); hp = NetDecoder.ReadUshort(data, currentByte + 20); currentByte += 22; lastCoord = new CastCoord(pos, x, y, z); // HP is set as the Chunk Coordinates vs World Coordinates flag if (hp == ushort.MaxValue) { lastCoord = new CastCoord(new Vector3(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ)); } blockCode = this.cl.GetBlock(lastCoord); if (this.cl.chunks.ContainsKey(lastCoord.GetChunkPos())) { if (blockCode <= ushort.MaxValue / 2) { this.cl.blockBook.blocks[blockCode].OnLoad(lastCoord, this.cl); } else { this.cl.blockBook.objects[ushort.MaxValue - blockCode].OnLoad(lastCoord, this.cl); } } } }
// Receives data regarding an entity private void PlayerData(byte[] data) { ulong code = NetDecoder.ReadUlong(data, 1); float3 pos = NetDecoder.ReadFloat3(data, 9); float3 dir = NetDecoder.ReadFloat3(data, 21); if (this.entityHandler.Contains(EntityType.PLAYER, code)) { this.entityHandler.NudgeLastPos(EntityType.PLAYER, code, pos, dir); this.smoothMovement.DefineMovement(EntityType.PLAYER, code, pos, dir); } else { this.entityHandler.AddPlayer(code, pos, dir); this.smoothMovement.AddPlayer(code); } }