/* * Main Callback function for block interactions * (REFER TO THESE CODES WHENEVER ADDING NEW BLOCK INTERACTIONS) * (MAY BE NEEDED IN ORDER TO IMPLEMENT NEW POST HANDLERS FOR NEW BLOCKS) */ private void CallbackHandler(int code, ChunkPos targetChunk, CastCoord thisPos, int facing) { // 0: No further actions necessary if (code == 0) { return; } // 1: Saves chunk and sends a DIRECTBLOCKUPDATE to all connected clients else if (code == 1) { ushort blockCode = this.cl.GetBlock(thisPos); ushort state = this.cl.GetState(thisPos); ushort hp = this.cl.GetHP(thisPos); this.cl.regionHandler.SaveChunk(this.cl.chunks[targetChunk]); NetMessage message = new NetMessage(NetCode.DIRECTBLOCKUPDATE); message.DirectBlockUpdate(BUDCode.CHANGE, targetChunk, thisPos.blockX, thisPos.blockY, thisPos.blockZ, facing, blockCode, state, hp); SendToClients(targetChunk, message); } // 2: Saves Chunk only else if (code == 2) { this.cl.budscheduler.ScheduleSave(targetChunk); } }
// Block Placing mechanic private bool PlaceBlock(ushort blockCode) { // Won't happen if not raycasting something or if block is in player's body or head if (!current.active || (CastCoord.Eq(lastCoord, playerHead) && loader.blockBook.CheckSolid(blockCode)) || (CastCoord.Eq(lastCoord, playerBody) && loader.blockBook.CheckSolid(blockCode))) { return(false); } NetMessage message = new NetMessage(NetCode.DIRECTBLOCKUPDATE); message.DirectBlockUpdate(BUDCode.PLACE, lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, blockCode, ushort.MaxValue, ushort.MaxValue); this.loader.client.Send(message.GetMessage(), message.size); return(true); }
// Breaks Torch if broken public override void OnBlockUpdate(BUDCode type, int x, int y, int z, int budX, int budY, int budZ, int facing, ChunkLoader_Server cl) { if (facing >= 4) { return; } CastCoord aux = new CastCoord(new Vector3(x, y, z)); if (type == BUDCode.LOAD) { this.OnLoad(aux, cl); } ChunkPos thisPos = aux.GetChunkPos(); //new ChunkPos(Mathf.FloorToInt(x/Chunk.chunkWidth), Mathf.FloorToInt(z/Chunk.chunkWidth)); int X = aux.blockX; //x%Chunk.chunkWidth; int Y = aux.blockY; //y%Chunk.chunkDepth; int Z = aux.blockZ; //z%Chunk.chunkWidth; aux = new CastCoord(new Vector3(budX, budY, budZ)); ChunkPos budPos = aux.GetChunkPos(); //new ChunkPos(Mathf.FloorToInt(budX/Chunk.chunkWidth), Mathf.FloorToInt(budZ/Chunk.chunkWidth)); int bX = aux.blockX; //budX%Chunk.chunkWidth; int bY = aux.blockY; //budY%Chunk.chunkDepth; int bZ = aux.blockZ; //budZ%Chunk.chunkWidth; ushort state = cl.chunks[thisPos].metadata.GetState(X, Y, Z); // Breaks Torch if broken attached block if (type == BUDCode.BREAK && (facing == state || facing + 4 == state)) { cl.chunks[thisPos].data.SetCell(X, Y, Z, 0); this.OnBreak(thisPos, X, Y, Z, cl); NetMessage message = new NetMessage(NetCode.DIRECTBLOCKUPDATE); message.DirectBlockUpdate(BUDCode.BREAK, thisPos, X, Y, Z, facing, ushort.MaxValue, state, 0); cl.server.SendToClients(thisPos, message); EraseMetadata(thisPos, X, Y, Z, cl); } // Breaks Torch if changed block is not solid else if (type == BUDCode.CHANGE) { int blockCode = cl.chunks[budPos].data.GetCell(bX, bY, bZ); if (blockCode >= 0) { // If changed block is not solid, break if (!cl.blockBook.blocks[blockCode].solid) { cl.chunks[thisPos].data.SetCell(X, Y, Z, 0); this.OnBreak(thisPos, X, Y, Z, cl); NetMessage message = new NetMessage(NetCode.DIRECTBLOCKUPDATE); message.DirectBlockUpdate(BUDCode.BREAK, thisPos, X, Y, Z, facing, ushort.MaxValue, state, 0); cl.server.SendToClients(thisPos, message); EraseMetadata(thisPos, X, Y, Z, cl); } } else { if (!cl.blockBook.objects[ushort.MaxValue - blockCode].solid) { cl.chunks[thisPos].data.SetCell(X, Y, Z, 0); this.OnBreak(thisPos, X, Y, Z, cl); NetMessage message = new NetMessage(NetCode.DIRECTBLOCKUPDATE); message.DirectBlockUpdate(BUDCode.BREAK, thisPos, X, Y, Z, facing, ushort.MaxValue, state, 0); cl.server.SendToClients(thisPos, message); EraseMetadata(thisPos, X, Y, Z, cl); } } } }
// Sends a direct action BUD to a block // ComesFromMessage flag is used to call this function from within the Server Code and not triggered by any message private void DirectBlockUpdate(byte[] data, ulong id, bool comesFromMessage = true) { ChunkPos pos; int x, y, z, facing; ushort blockCode, state, hp; BUDCode type; NetMessage message; pos = NetDecoder.ReadChunkPos(data, 1); x = NetDecoder.ReadInt(data, 9); y = NetDecoder.ReadInt(data, 13); z = NetDecoder.ReadInt(data, 17); facing = NetDecoder.ReadInt(data, 21); blockCode = NetDecoder.ReadUshort(data, 25); state = 0; hp = 0; if (comesFromMessage) { state = NetDecoder.ReadUshort(data, 27); hp = NetDecoder.ReadUshort(data, 29); type = (BUDCode)NetDecoder.ReadInt(data, 31); } else { type = (BUDCode)NetDecoder.ReadInt(data, 27); } CastCoord lastCoord = new CastCoord(pos, x, y, z); switch (type) { case BUDCode.PLACE: // if chunk is still loaded if (this.cl.chunks.ContainsKey(lastCoord.GetChunkPos())) { // if it's a block if (blockCode <= ushort.MaxValue / 2) { // if placement rules fail if (!cl.blockBook.blocks[blockCode].PlacementRule(lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, cl)) { NetMessage denied = new NetMessage(NetCode.PLACEMENTDENIED); this.Send(denied.GetMessage(), denied.size, id); return; } } // if it's an object else { if (!cl.blockBook.objects[ushort.MaxValue - blockCode].PlacementRule(lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, cl)) { NetMessage denied = new NetMessage(NetCode.PLACEMENTDENIED); this.Send(denied.GetMessage(), denied.size, id); return; } } // Check if is trying to put block on players if (this.playersInChunk.ContainsKey(pos)) { foreach (ulong code in this.playersInChunk[pos]) { if (code == id) { continue; } if (!this.cl.regionHandler.allPlayerData[code].CheckValidPlacement(lastCoord.GetWorldX(), lastCoord.GetWorldY(), lastCoord.GetWorldZ())) { NetMessage denied = new NetMessage(NetCode.PLACEMENTDENIED); this.Send(denied.GetMessage(), denied.size, id); return; } } } // If doesn't have special place handling if (!cl.blockBook.CheckCustomPlace(blockCode)) { // Actually places block/asset into terrain cl.chunks[lastCoord.GetChunkPos()].data.SetCell(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, blockCode); //cl.budscheduler.ScheduleReload(lastCoord.GetChunkPos(), 0); EmitBlockUpdate(BUDCode.CHANGE, lastCoord.GetWorldX(), lastCoord.GetWorldY(), lastCoord.GetWorldZ(), 0, cl); // Applies OnPlace Event if (blockCode <= ushort.MaxValue / 2) { cl.blockBook.blocks[blockCode].OnPlace(lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, cl); } else { cl.blockBook.objects[ushort.MaxValue - blockCode].OnPlace(lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, cl); } // Sends the updated voxel to loaded clients message = new NetMessage(NetCode.DIRECTBLOCKUPDATE); message.DirectBlockUpdate(BUDCode.PLACE, lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, blockCode, this.cl.chunks[lastCoord.GetChunkPos()].metadata.GetState(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ), this.cl.chunks[lastCoord.GetChunkPos()].metadata.GetHP(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ)); SendToClients(lastCoord.GetChunkPos(), message); this.cl.regionHandler.SaveChunk(this.cl.chunks[pos]); } // If has special handling else { // Actually places block/asset into terrain this.cl.chunks[lastCoord.GetChunkPos()].data.SetCell(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, blockCode); if (blockCode <= ushort.MaxValue / 2) { cl.blockBook.blocks[blockCode].OnPlace(lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, cl); } else { cl.blockBook.objects[ushort.MaxValue - blockCode].OnPlace(lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, cl); } } // Make entities in this chunk update their TerrainVision this.entityHandler.SetRefreshVision(EntityType.DROP, lastCoord.GetChunkPos()); } break; case BUDCode.SETSTATE: if (this.cl.chunks.ContainsKey(lastCoord.GetChunkPos())) { this.cl.chunks[lastCoord.GetChunkPos()].metadata.SetState(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, blockCode); this.entityHandler.SetRefreshVision(EntityType.DROP, lastCoord.GetChunkPos()); } break; case BUDCode.BREAK: // If doesn't has special break handling if (!this.cl.blockBook.CheckCustomBreak(blockCode)) { // Actually breaks new block and updates chunk this.cl.chunks[pos].data.SetCell(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, 0); this.cl.chunks[pos].metadata.Reset(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ); // Triggers OnBreak if (blockCode <= ushort.MaxValue / 2) { this.cl.blockBook.blocks[blockCode].OnBreak(pos, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, this.cl); } else { this.cl.blockBook.objects[ushort.MaxValue - blockCode].OnBreak(pos, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, this.cl); } EmitBlockUpdate(BUDCode.BREAK, lastCoord.GetWorldX(), lastCoord.GetWorldY(), lastCoord.GetWorldZ(), 0, this.cl); } // If has special break handlings else { if (blockCode <= ushort.MaxValue / 2) { this.cl.blockBook.blocks[blockCode].OnBreak(pos, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, this.cl); } else { this.cl.blockBook.objects[ushort.MaxValue - blockCode].OnBreak(pos, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, this.cl); } } // Sends the updated voxel to loaded clients this.entityHandler.SetRefreshVision(EntityType.DROP, lastCoord.GetChunkPos()); message = new NetMessage(NetCode.DIRECTBLOCKUPDATE); message.DirectBlockUpdate(BUDCode.BREAK, lastCoord.GetChunkPos(), lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, 0, ushort.MaxValue, ushort.MaxValue); SendToClients(lastCoord.GetChunkPos(), message); this.cl.regionHandler.SaveChunk(this.cl.chunks[pos]); break; case BUDCode.LOAD: // 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); } } break; default: break; } }