Пример #1
0
        public void CreateTileEntity(int x, int y, int z)
        {
            BlockInfoEx info = BlockInfo.BlockTable[_blocks[x, y, z]] as BlockInfoEx;

            if (info == null)
            {
                throw new InvalidOperationException("The given block is of a type that does not support TileEntities.");
            }

            TileEntity te = TileEntityFactory.Create(info.TileEntityName);

            if (te == null)
            {
                throw new UnknownTileEntityException("The TileEntity type '" + info.TileEntityName + "' has not been registered with the TileEntityFactory.");
            }

            BlockKey key = (TranslateCoordinates != null)
                ? TranslateCoordinates(x, y, z)
                : new BlockKey(x, y, z);

            TagNodeCompound oldte;

            if (_tileEntityTable.TryGetValue(key, out oldte))
            {
                _tileEntities.Remove(oldte);
            }

            te.X = key.x;
            te.Y = key.y;
            te.Z = key.z;

            TagNodeCompound tree = te.BuildTree() as TagNodeCompound;

            _tileEntities.Add(tree);
            _tileEntityTable[key] = tree;
        }
Пример #2
0
        private void DoLava(int x, int y, int z)
        {
            Queue <BlockKey> flowQueue = new Queue <BlockKey>();

            BlockKey prikey = new BlockKey(x, y, z);

            flowQueue.Enqueue(prikey);

            List <BlockKey> outflow = TileOutflow(prikey);

            foreach (BlockKey outkey in outflow)
            {
                flowQueue.Enqueue(outkey);
            }

            while (flowQueue.Count > 0)
            {
                BlockKey key = flowQueue.Dequeue();

                int curflow = 16;
                int inflow  = TileInflow(key);

                BlockCoord tile     = TranslateCoord(key.x, key.y, key.z);
                BlockInfo  tileInfo = tile.chunk.GetInfo(tile.lx, tile.ly, tile.lz);
                if (tileInfo.ID == BlockType.STATIONARY_LAVA || tileInfo.ID == BlockType.LAVA)
                {
                    curflow = tile.chunk.GetData(tile.lx, tile.ly, tile.lz);
                }
                else if (tileInfo.BlocksFluid)
                {
                    continue;
                }

                bool curFall = (curflow & (int)LiquidState.FALLING) != 0;
                bool inFall  = (inflow & (int)LiquidState.FALLING) != 0;

                // We won't update from the following states
                if (curflow == 0 || curflow == inflow || curFall)
                {
                    continue;
                }

                int newflow = curflow;

                // Update from inflow if necessary
                if (inFall)
                {
                    newflow = inflow;
                }
                else if (inflow >= 6)
                {
                    newflow = 16;
                }
                else
                {
                    newflow = inflow + 2;
                }

                // If we haven't changed the flow, don't propagate
                if (newflow == curflow)
                {
                    continue;
                }

                // Update flow, add or remove lava tile as necessary
                if (newflow < 16 && curflow == 16)
                {
                    // If we're overwriting water, replace with appropriate stone type and abort propagation
                    if (tileInfo.ID == BlockType.STATIONARY_WATER || tileInfo.ID == BlockType.WATER)
                    {
                        if ((newflow & (int)LiquidState.FALLING) == 0)
                        {
                            tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.COBBLESTONE);
                            tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                            continue;
                        }
                    }

                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.STATIONARY_LAVA);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }
                else if (newflow == 16)
                {
                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockType.AIR);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                }
                else
                {
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }

                // Process outflows
                outflow = TileOutflow(key);

                foreach (BlockKey nkey in outflow)
                {
                    flowQueue.Enqueue(nkey);
                }
            }
        }
Пример #3
0
        private int TileInflow(BlockKey key)
        {
            // Check if water is falling on us
            if (key.y < _ydim - 1)
            {
                BlockCoord up     = TranslateCoord(key.x, key.y + 1, key.z);
                BlockInfo  upInfo = up.chunk.GetInfo(up.lx, up.ly, up.lz);

                if (upInfo.State == BlockState.FLUID)
                {
                    return(up.chunk.GetData(up.lx, up.ly, up.lz) | (int)LiquidState.FALLING);
                }
            }

            // Otherwise return the min inflow of our neighbors + step
            BlockKey[] keys =
            {
                new BlockKey(key.x - 1, key.y, key.z),
                new BlockKey(key.x + 1, key.y, key.z),
                new BlockKey(key.x,     key.y, key.z - 1),
                new BlockKey(key.x,     key.y, key.z + 1),
            };

            int minFlow = 16;

            // XXX: Might have different neighboring fluids
            for (int i = 0; i < 4; i++)
            {
                BlockCoord neighbor = TranslateCoord(keys[i].x, keys[i].y, keys[i].z);
                if (neighbor.chunk == null)
                {
                    continue;
                }

                BlockInfo neighborInfo = neighbor.chunk.GetInfo(neighbor.lx, neighbor.ly, neighbor.lz);

                if (neighborInfo.State == BlockState.FLUID)
                {
                    int  flow     = neighbor.chunk.GetData(neighbor.lx, neighbor.ly, neighbor.lz);
                    bool flowFall = (flow & (int)LiquidState.FALLING) != 0;

                    if (flowFall)
                    {
                        if (keys[i].y == 0)
                        {
                            continue;
                        }

                        BlockCoord low     = TranslateCoord(keys[i].x, keys[i].y - 1, keys[i].z);
                        BlockInfo  lowinfo = low.chunk.GetInfo(low.lx, low.ly, low.lz);

                        if (lowinfo.BlocksFluid)
                        {
                            return(0);
                        }
                        continue;
                    }
                    if (flow < minFlow)
                    {
                        minFlow = flow;
                    }
                }
            }

            return(minFlow);
        }
Пример #4
0
        // -----

        private List <BlockKey> TileOutflow(BlockKey key, int reach = 5)
        {
            Queue <BlockKey> searchQueue = new Queue <BlockKey>();
            Queue <KeyValuePair <BlockKey, int> > traceQueue = new Queue <KeyValuePair <BlockKey, int> >();
            Dictionary <BlockKey, int>            markTable  = new Dictionary <BlockKey, int>();

            searchQueue.Enqueue(key);
            markTable.Add(key, 0);

            // Identify sinks
            while (searchQueue.Count > 0)
            {
                BlockKey branch   = searchQueue.Dequeue();
                int      distance = markTable[branch];

                // Ignore blocks out of range
                if (distance > reach)
                {
                    continue;
                }

                // Ignore invalid blocks
                BlockCoord branchHigh = TranslateCoord(branch.x, branch.y, branch.z);
                if (branchHigh.chunk == null || branch.y == 0)
                {
                    markTable.Remove(branch);
                    continue;
                }

                // If we're not the magical source block...
                if (distance > 0)
                {
                    // Ignore blocks that block fluid (and thus could not become a fluid)
                    BlockInfo branchHighInfo = branchHigh.chunk.GetInfo(branchHigh.lx, branchHigh.ly, branchHigh.lz);
                    if (branchHighInfo.BlocksFluid)
                    {
                        markTable.Remove(branch);
                        continue;
                    }
                }

                // If we found a hole, add as a sink, mark the sink distance.
                BlockCoord branchLow     = TranslateCoord(branch.x, branch.y - 1, branch.z);
                BlockInfo  branchLowInfo = branchLow.chunk.GetInfo(branchLow.lx, branchLow.ly, branchLow.lz);
                if (!branchLowInfo.BlocksFluid)
                {
                    // If we are our own sink, return the only legal outflow
                    if (key == branch)
                    {
                        List <BlockKey> ret = new List <BlockKey>();
                        ret.Add(new BlockKey(branch.x, branch.y - 1, branch.z));
                        return(ret);
                    }

                    reach = distance;
                    traceQueue.Enqueue(new KeyValuePair <BlockKey, int>(branch, distance));
                    continue;
                }

                // Expand to neighbors
                if (distance < reach)
                {
                    BlockKey[] keys =
                    {
                        new BlockKey(branch.x - 1, branch.y, branch.z),
                        new BlockKey(branch.x + 1, branch.y, branch.z),
                        new BlockKey(branch.x,     branch.y, branch.z - 1),
                        new BlockKey(branch.x,     branch.y, branch.z + 1),
                    };

                    for (int i = 0; i < 4; i++)
                    {
                        if (!markTable.ContainsKey(keys[i]))
                        {
                            searchQueue.Enqueue(keys[i]);
                            markTable.Add(keys[i], distance + 1);
                        }
                    }
                }
            }

            // Candidate outflows are marked
            BlockKey[] neighbors =
            {
                new BlockKey(key.x - 1, key.y, key.z),
                new BlockKey(key.x + 1, key.y, key.z),
                new BlockKey(key.x,     key.y, key.z - 1),
                new BlockKey(key.x,     key.y, key.z + 1),
            };

            List <BlockKey> outflow = new List <BlockKey>();

            foreach (BlockKey n in neighbors)
            {
                if (markTable.ContainsKey(n))
                {
                    outflow.Add(n);
                }
            }

            // If there's no sinks, all neighbors are valid outflows
            if (traceQueue.Count == 0)
            {
                return(outflow);
            }

            // Trace back from each sink eliminating shortest path marks
            while (traceQueue.Count > 0)
            {
                KeyValuePair <BlockKey, int> tilekv = traceQueue.Dequeue();
                BlockKey tile = tilekv.Key;

                int distance = tilekv.Value;
                markTable.Remove(tile);

                BlockKey[] keys =
                {
                    new BlockKey(tile.x - 1, tile.y, tile.z),
                    new BlockKey(tile.x + 1, tile.y, tile.z),
                    new BlockKey(tile.x,     tile.y, tile.z - 1),
                    new BlockKey(tile.x,     tile.y, tile.z + 1),
                };

                for (int i = 0; i < 4; i++)
                {
                    int nval;
                    if (!markTable.TryGetValue(keys[i], out nval))
                    {
                        continue;
                    }

                    if (nval < distance)
                    {
                        markTable.Remove(keys[i]);
                        traceQueue.Enqueue(new KeyValuePair <BlockKey, int>(keys[i], nval));
                    }
                }
            }

            // Remove any candidates that are still marked
            foreach (BlockKey n in neighbors)
            {
                if (markTable.ContainsKey(n))
                {
                    outflow.Remove(n);
                }
            }

            return(outflow);
        }
Пример #5
0
        private void DoWater(int x, int y, int z)
        {
            Queue <BlockKey> flowQueue = new Queue <BlockKey>();

            BlockKey prikey = new BlockKey(x, y, z);

            flowQueue.Enqueue(prikey);

            List <BlockKey> outflow = TileOutflow(prikey);

            foreach (BlockKey outkey in outflow)
            {
                flowQueue.Enqueue(outkey);
            }

            while (flowQueue.Count > 0)
            {
                BlockKey key = flowQueue.Dequeue();

                int curflow = 16;
                int inflow  = TileInflow(key);

                BlockCoord tile     = TranslateCoord(key.x, key.y, key.z);
                BlockInfo  tileInfo = tile.chunk.GetInfo(tile.lx, tile.ly, tile.lz);
                if (tileInfo.ID == BlockInfo.StationaryWater.ID || tileInfo.ID == BlockInfo.Water.ID)
                {
                    curflow = tile.chunk.GetData(tile.lx, tile.ly, tile.lz);
                }
                else if (tileInfo.BlocksFluid)
                {
                    continue;
                }

                bool curFall = (curflow & (int)LiquidState.FALLING) != 0;
                bool inFall  = (inflow & (int)LiquidState.FALLING) != 0;

                // We won't update from the following states
                if (curflow == 0 || curflow == inflow || curFall)
                {
                    continue;
                }

                int newflow = curflow;

                // Update from inflow if necessary
                if (inFall)
                {
                    newflow = inflow;
                }
                else if (inflow >= 7)
                {
                    newflow = 16;
                }
                else
                {
                    newflow = inflow + 1;
                }

                // If we haven't changed the flow, don't propagate
                if (newflow == curflow)
                {
                    continue;
                }

                // Update flow, add or remove water tile as necessary
                if (newflow < 16 && curflow == 16)
                {
                    // If we're overwriting lava, replace with appropriate stone type and abort propagation
                    if (tileInfo.ID == BlockInfo.StationaryLava.ID || tileInfo.ID == BlockInfo.Lava.ID)
                    {
                        if ((newflow & (int)LiquidState.FALLING) != 0)
                        {
                            int odata = tile.chunk.GetData(tile.lx, tile.ly, tile.lz);
                            if (odata == 0)
                            {
                                tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Obsidian.ID);
                            }
                            else
                            {
                                tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Cobblestone.ID);
                            }
                            tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                            continue;
                        }
                    }

                    // Otherwise replace the tile with our water flow
                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.StationaryWater.ID);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }
                else if (newflow == 16)
                {
                    tile.chunk.SetID(tile.lx, tile.ly, tile.lz, BlockInfo.Air.ID);
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, 0);
                }
                else
                {
                    tile.chunk.SetData(tile.lx, tile.ly, tile.lz, newflow);
                }

                // Process outflows
                outflow = TileOutflow(key);

                foreach (BlockKey nkey in outflow)
                {
                    flowQueue.Enqueue(nkey);
                }
            }
        }
Пример #6
0
        private void UpdateBlockSkyLight()
        {
            IBoundedLitBlockCollection[,] chunkMap = LocalBlockLightMap();

            int xdim = _xdim;
            int ydim = _ydim;
            int zdim = _zdim;

            while (_update.Count > 0)
            {
                BlockKey k     = _update.Dequeue();
                int      index = LightBitmapIndex(k);
                _lightbit[index] = false;

                int xi = k.x + xdim;
                int zi = k.z + zdim;

                IBoundedLitBlockCollection cc = chunkMap[xi / xdim, zi / zdim];
                if (cc == null)
                {
                    continue;
                }

                int x = xi % xdim;
                int y = k.y;
                int z = zi % zdim;

                int       lightval = cc.GetSkyLight(x, y, z);
                BlockInfo info     = cc.GetInfo(x, y, z);

                int light = BlockInfo.MIN_LUMINANCE;

                if (cc.GetHeight(x, z) <= y)
                {
                    light = BlockInfo.MAX_LUMINANCE;
                }
                else
                {
                    int lle = NeighborSkyLight(chunkMap, k.x, k.y, k.z - 1);
                    int lln = NeighborSkyLight(chunkMap, k.x - 1, k.y, k.z);
                    int lls = NeighborSkyLight(chunkMap, k.x, k.y, k.z + 1);
                    int llw = NeighborSkyLight(chunkMap, k.x + 1, k.y, k.z);
                    int lld = NeighborSkyLight(chunkMap, k.x, k.y - 1, k.z);
                    int llu = NeighborSkyLight(chunkMap, k.x, k.y + 1, k.z);

                    light = Math.Max(light, lle);
                    light = Math.Max(light, lln);
                    light = Math.Max(light, lls);
                    light = Math.Max(light, llw);
                    light = Math.Max(light, lld);
                    light = Math.Max(light, llu);
                }

                light = Math.Max(light - info.Opacity, 0);

                if (light != lightval)
                {
                    //Console.WriteLine("Block SkyLight: ({0},{1},{2}) " + lightval + " -> " + light, k.x, k.y, k.z);

                    cc.SetSkyLight(x, y, z, light);

                    if (info.TransmitsLight)
                    {
                        if (k.y > 0)
                        {
                            QueueRelight(new BlockKey(k.x, k.y - 1, k.z));
                        }
                        if (k.y < ydim - 1)
                        {
                            QueueRelight(new BlockKey(k.x, k.y + 1, k.z));
                        }

                        QueueRelight(new BlockKey(k.x - 1, k.y, k.z));
                        QueueRelight(new BlockKey(k.x + 1, k.y, k.z));
                        QueueRelight(new BlockKey(k.x, k.y, k.z - 1));
                        QueueRelight(new BlockKey(k.x, k.y, k.z + 1));
                    }
                }
            }
        }