// Block Breaking mechanic
    private void BreakBlock()
    {
        if (!current.active)
        {
            return;
        }

        ChunkPos toUpdate  = new ChunkPos(current.chunkX, current.chunkZ);
        ushort   blockCode = loader.chunks[toUpdate].data.GetCell(current.blockX, current.blockY, current.blockZ);

        // If doesn't has special break handling
        if (!loader.blockBook.CheckCustomBreak(blockCode))
        {
            // Actually breaks new block and updates chunk
            loader.chunks[toUpdate].data.SetCell(current.blockX, current.blockY, current.blockZ, 0);
            loader.chunks[toUpdate].metadata.Reset(current.blockX, current.blockY, current.blockZ);

            // Triggers OnBreak
            if (blockCode <= ushort.MaxValue / 2)
            {
                loader.blockBook.blocks[blockCode].OnBreak(toUpdate, current.blockX, current.blockY, current.blockZ, loader);
            }
            else
            {
                loader.blockBook.objects[ushort.MaxValue - blockCode].OnBreak(toUpdate, current.blockX, current.blockY, current.blockZ, loader);
            }

            EmitBlockUpdate("break", current.GetWorldX(), current.GetWorldY(), current.GetWorldZ(), 0, loader);

            loader.budscheduler.ScheduleReload(toUpdate, 0, x: current.blockX, y: current.blockY, z: current.blockZ);
        }
        // If has special break handlings
        else
        {
            if (blockCode <= ushort.MaxValue / 2)
            {
                loader.blockBook.blocks[blockCode].OnBreak(toUpdate, current.blockX, current.blockY, current.blockZ, loader);
            }
            else
            {
                loader.blockBook.objects[ushort.MaxValue - blockCode].OnBreak(toUpdate, current.blockX, current.blockY, current.blockZ, loader);
                loader.regionHandler.SaveChunk(loader.chunks[toUpdate]);
            }
        }
    }
    // Activates OnBreak event -> Emits normal BUD, emits special BUD to breadt-first search leaves
    public override int OnBreak(ChunkPos pos, int blockX, int blockY, int blockZ, ChunkLoader cl)
    {
        CastCoord thisCoord = new CastCoord(pos, blockX, blockY, blockZ);

        EmitBlockUpdate("break", thisCoord.GetWorldX(), thisCoord.GetWorldY(), thisCoord.GetWorldZ(), 0, cl);

        TreeCheck(thisCoord, cl);
        GetSurroundingLeaves(thisCoord, decayDistance, cl);
        RunLeavesRecursion(cl, thisCoord);

        return(0);
    }
    // Does Search for invalid leaves
    private void RunLeavesRecursion(ChunkLoader cl, CastCoord init)
    {
        while (openList.Count > 0)
        {
            GetSurroundingLeaves(openList[0], distances[openList[0]] - 1, cl);
            openList.RemoveAt(0);
        }

        // Applies DECAY BUD to distant leaves
        foreach (CastCoord c in distances.Keys)
        {
            if (distances[c] == 0)
            {
                EmitBUDTo("decay", c.GetWorldX(), c.GetWorldY(), c.GetWorldZ(), 1, cl);
            }
        }

        // Applies DECAY BUD to around blocks if there's no wood around
        EmitDelayedBUD("decay", init.GetWorldX(), init.GetWorldY(), init.GetWorldZ(), 2, 15, cl);

        distances.Clear();
    }
Example #4
0
    // Handles the emittion of BUD to neighboring blocks
    public void EmitBlockUpdate(string type, int x, int y, int z, int tickOffset, ChunkLoader cl)
    {
        CastCoord thisPos = new CastCoord(new Vector3(x, y, z));

        CastCoord[] neighbors =
        {
            thisPos.Add(1,   0, 0),
            thisPos.Add(-1,  0, 0),
            thisPos.Add(0,   1, 0),
            thisPos.Add(0,  -1, 0),
            thisPos.Add(0,   0, 1),
            thisPos.Add(0,   0, -1)
        };

        int[] facings = { 2, 0, 4, 5, 1, 3 };

        int faceCounter = 0;

        foreach (CastCoord c in neighbors)
        {
            cl.budscheduler.ScheduleBUD(new BUDSignal(type, c.GetWorldX(), c.GetWorldY(), c.GetWorldZ(), thisPos.GetWorldX(), thisPos.GetWorldY(), thisPos.GetWorldZ(), facings[faceCounter]), tickOffset);

            faceCounter++;
        }
    }
Example #5
0
    // Handles the emittion of BUD to neighboring blocks
    public void EmitBlockUpdate(BUDCode type, int x, int y, int z, int tickOffset, ChunkLoader_Server cl)
    {
        CastCoord thisPos = new CastCoord(new Vector3(x, y, z));

        CastCoord[] neighbors =
        {
            thisPos.Add(1,   0, 0),
            thisPos.Add(-1,  0, 0),
            thisPos.Add(0,   1, 0),
            thisPos.Add(0,  -1, 0),
            thisPos.Add(0,   0, 1),
            thisPos.Add(0,   0, -1)
        };

        int[] facings = { 2, 0, 4, 5, 1, 3 };

        int blockCode;
        int faceCounter = 0;

        foreach (CastCoord c in neighbors)
        {
            blockCode = cl.chunks[c.GetChunkPos()].data.GetCell(c.blockX, c.blockY, c.blockZ);

            cl.budscheduler.ScheduleBUD(new BUDSignal(type, c.GetWorldX(), c.GetWorldY(), c.GetWorldZ(), thisPos.GetWorldX(), thisPos.GetWorldY(), thisPos.GetWorldZ(), facings[faceCounter]), tickOffset);

            faceCounter++;
        }
    }
    // Handles the emittion of BUD to neighboring blocks
    public void EmitDelayedBUD(string type, int x, int y, int z, int minOffset, int maxOffset, ChunkLoader cl)
    {
        CastCoord thisPos = new CastCoord(new Vector3(x, y, z));

        cache.Clear();

        cache.Add(thisPos.Add(1, 0, 0));
        cache.Add(thisPos.Add(-1, 0, 0));
        cache.Add(thisPos.Add(0, 1, 0));
        cache.Add(thisPos.Add(0, -1, 0));
        cache.Add(thisPos.Add(0, 0, 1));
        cache.Add(thisPos.Add(0, 0, -1));


        foreach (CastCoord c in cache)
        {
            cl.budscheduler.ScheduleBUD(new BUDSignal(type, c.GetWorldX(), c.GetWorldY(), c.GetWorldZ(), thisPos.GetWorldX(), thisPos.GetWorldY(), thisPos.GetWorldZ(), 0), Random.Range(minOffset, maxOffset));
        }
    }
    // Handles the emittion of BUD to neighboring blocks
    public void EmitBlockUpdate(string type, int x, int y, int z, int tickOffset, ChunkLoader cl)
    {
        CastCoord thisPos = GetCoordinates(x, y, z);

        CastCoord[] neighbors =
        {
            thisPos.Add(1,   0, 0),
            thisPos.Add(-1,  0, 0),
            thisPos.Add(0,   1, 0),
            thisPos.Add(0,  -1, 0),
            thisPos.Add(0,   0, 1),
            thisPos.Add(0,   0, -1)
        };

        int[] facings = { 2, 0, 4, 5, 1, 3 };


        int blockCode;
        int faceCounter = 0;

        foreach (CastCoord c in neighbors)
        {
            // Ignores void updates
            if (c.blockY < 0 || c.blockY > Chunk.chunkDepth - 1)
            {
                continue;
            }

            blockCode = cl.chunks[c.GetChunkPos()].data.GetCell(c.blockX, c.blockY, c.blockZ);

            cachedBUD = new BUDSignal(type, c.GetWorldX(), c.GetWorldY(), c.GetWorldZ(), thisPos.GetWorldX(), thisPos.GetWorldY(), thisPos.GetWorldZ(), facings[faceCounter]);
            cl.budscheduler.ScheduleBUD(cachedBUD, tickOffset);

            faceCounter++;
        }
    }
    // Block Placing mechanic
    private void PlaceBlock(ushort blockCode)
    {
        int translatedBlockCode;

        // Encodes for Block Mode
        if (blockCode <= ushort.MaxValue / 2)
        {
            translatedBlockCode = 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;
            }
        }
        // Encodes for Asset Mode
        else
        {
            translatedBlockCode = ushort.MaxValue - 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;
            }
        }

        ChunkPos toUpdate = new ChunkPos(lastCoord.chunkX, lastCoord.chunkZ);

        // Checks if specific block has specific placement rules that may hinder the placement
        if (blockCode <= ushort.MaxValue / 2)
        {
            if (!loader.blockBook.blocks[translatedBlockCode].PlacementRule(toUpdate, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, loader))
            {
                return;
            }
        }
        else
        {
            if (!loader.blockBook.objects[translatedBlockCode].PlacementRule(toUpdate, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, loader))
            {
                return;
            }
        }

        // If doesn't have special place handling
        if (!loader.blockBook.CheckCustomPlace(blockCode))
        {
            // Actually places block/asset into terrain
            loader.chunks[toUpdate].data.SetCell(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, blockCode);
            loader.budscheduler.ScheduleReload(toUpdate, 0);
            EmitBlockUpdate("change", lastCoord.GetWorldX(), lastCoord.GetWorldY(), lastCoord.GetWorldZ(), 0, loader);


            // Applies OnPlace Event
            if (blockCode <= ushort.MaxValue / 2)
            {
                loader.blockBook.blocks[translatedBlockCode].OnPlace(toUpdate, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, loader);
            }
            else
            {
                loader.blockBook.objects[translatedBlockCode].OnPlace(toUpdate, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, loader);
            }
        }

        // If has special handling
        else
        {
            // Actually places block/asset into terrain
            loader.chunks[toUpdate].data.SetCell(lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, blockCode);

            if (blockCode <= ushort.MaxValue / 2)
            {
                loader.blockBook.blocks[blockCode].OnPlace(toUpdate, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, loader);
            }
            else
            {
                loader.blockBook.objects[translatedBlockCode].OnPlace(toUpdate, lastCoord.blockX, lastCoord.blockY, lastCoord.blockZ, facing, loader);
            }
        }
    }
Example #9
0
    // 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;
        }
    }