Esempio n. 1
0
        private void SetContent(Block block, uint data, Liquid liquid, LiquidLevel level, bool isStatic,
            Vector3i position, bool tickLiquid)
        {
            Chunk? chunk = GetChunkWithPosition(position);

            if (chunk == null) return;

            uint val = Section.Encode(block, data, liquid, level, isStatic);

            chunk.GetSection(position.Y >> Section.SectionSizeExp).SetContent(position, val);

            if (tickLiquid) liquid.TickNow(this, position, level, isStatic);

            // Block updates - Side is passed out of the perspective of the block receiving the block update.

            foreach (BlockSide side in BlockSide.All.Sides())
            {
                Vector3i neighborPosition = side.Offset(position);

                (BlockInstance? blockNeighbor, LiquidInstance? liquidNeighbor) = GetContent(neighborPosition);

                blockNeighbor?.Block.BlockUpdate(this, neighborPosition, blockNeighbor.Data, side.Opposite());
                liquidNeighbor?.Liquid.TickSoon(this, neighborPosition, liquidNeighbor.IsStatic);
            }

            ProcessChangedSection(chunk, position);
        }
Esempio n. 2
0
 /// <inheritdoc />
 public void LiquidChange(World world, Vector3i position, Liquid liquid, LiquidLevel level)
 {
     if (liquid.IsLiquid && level > LiquidLevel.Three)
     {
         ScheduleDestroy(world, position);
     }
 }
Esempio n. 3
0
        private void InvalidLocationFlow(World world, Vector3i position, LiquidLevel level)
        {
            if (FlowVertical(
                    world,
                    position,
                    currentFillable: null,
                    level,
                    Direction,
                    handleContact: false,
                    out int remaining) && remaining == -1 ||
                FlowVertical(
                    world,
                    position,
                    currentFillable: null,
                    (LiquidLevel)remaining,
                    Direction.Opposite(),
                    handleContact: false,
                    out remaining) &&
                remaining == -1)
            {
                return;
            }

            SpreadOrDestroyLiquid(world, position, (LiquidLevel)remaining);
        }
 /// <summary>
 ///     Try to place a concrete block at the given position.
 ///     The block will only be actually placed if the placement conditions are met, e.g. the position is replaceable.
 /// </summary>
 /// <param name="world">The world in which the block will be placed.</param>
 /// <param name="level">The height of the block, given in liquid levels.</param>
 /// <param name="position">The position where the block will be placed.</param>
 public void Place(World world, LiquidLevel level, Vector3i position)
 {
     if (base.Place(world, position))
     {
         world.SetBlock(this.AsInstance(Encode(BlockColor.Default, level.GetBlockHeight())), position);
     }
 }
 /// <inheritdoc />
 public void LiquidChange(World world, Vector3i position, Liquid liquid, LiquidLevel level)
 {
     if (liquid.IsLiquid)
     {
         world.SetBlock(Dirt.AsInstance(), position);
     }
 }
        /// <summary>
        ///     Will schedule a tick for a liquid in the next possible update.
        /// </summary>
        internal void TickNow(World world, Vector3i position, LiquidLevel level, bool isStatic)
        {
            if (this == None)
            {
                return;
            }

            ScheduledUpdate(world, position, level, isStatic);
        }
Esempio n. 7
0
        /// <inheritdoc />
        internal override void RandomUpdate(World world, Vector3i position, LiquidLevel level, bool isStatic)
        {
            if (!isStatic)
            {
                return;
            }

            world.SetDefaultLiquid(position);
            Block.Specials.Concrete.Place(world, level, position);
        }
Esempio n. 8
0
        /// <inheritdoc />
        protected override void ScheduledUpdate(World world, Vector3i position, LiquidLevel level, bool isStatic)
        {
            if (world.GetBlock(position)?.Block is IFlammable block)
            {
                block.Burn(world, position, Block.Fire);
            }

            BurnAround(world, position);

            base.ScheduledUpdate(world, position, level, isStatic);
        }
Esempio n. 9
0
        /// <inheritdoc />
        protected override void ScheduledUpdate(World world, Vector3i position, LiquidLevel level, bool isStatic)
        {
            if (CheckVerticalWorldBounds(world, position))
            {
                return;
            }

            Block block = world.GetBlock(position)?.Block ?? Block.Air;

            if (block is IFillable fillable)
            {
                ValidLocationFlow(world, position, level, fillable);
            }
            else
            {
                InvalidLocationFlow(world, position, level);
            }
        }
Esempio n. 10
0
        private void RetrieveContent(Vector3i position,
            out Block? block, out uint data,
            out Liquid? liquid, out LiquidLevel level, out bool isStatic)
        {
            Chunk? chunk = GetChunkWithPosition(position);

            if (chunk != null)
            {
                uint val = chunk.GetSection(position.Y >> Section.SectionSizeExp).GetContent(position);
                Section.Decode(val, out block, out data, out liquid, out level, out isStatic);

                return;
            }

            block = null;
            data = 0;
            liquid = null;
            level = 0;
            isStatic = false;
        }
Esempio n. 11
0
        private void ValidLocationFlow(World world, Vector3i position, LiquidLevel level, IFillable current)
        {
            if (FlowVertical(
                    world,
                    position,
                    current,
                    level,
                    Direction,
                    handleContact: true,
                    out _))
            {
                return;
            }

            if (level != LiquidLevel.One
                ? FlowHorizontal(world, position, level, current) || FarFlowHorizontal(world, position, level, current)
                : TryPuddleFlow(world, position, current))
            {
                return;
            }

            world.ModifyLiquid(isStatic: true, position);
        }
Esempio n. 12
0
        private bool FlowHorizontal(World world, Vector3i position, LiquidLevel level, IFillable currentFillable)
        {
            Vector3i  horizontalPosition = position;
            var       isHorStatic        = false;
            var       levelHorizontal    = LiquidLevel.Eight;
            IFillable?horizontalFillable = null;

            foreach (Orientation orientation in Orientations.ShuffledStart(position))
            {
                if (CheckNeighbor(
                        currentFillable.AllowOutflow(world, position, orientation.ToBlockSide()),
                        orientation.Offset(position),
                        orientation.Opposite().ToBlockSide()))
                {
                    return(true);
                }
            }

            if (horizontalPosition == position)
            {
                return(false);
            }

            SetLiquid(world, this, levelHorizontal + 1, isStatic: false, horizontalFillable, horizontalPosition);

            if (isHorStatic)
            {
                ScheduleTick(world, horizontalPosition);
            }

            bool hasRemaining = level != LiquidLevel.One;

            SetLiquid(
                world,
                hasRemaining ? this : None,
                hasRemaining ? level - 1 : LiquidLevel.Eight,
                !hasRemaining,
                currentFillable,
                position);

            if (hasRemaining)
            {
                ScheduleTick(world, position);
            }

            return(true);

            bool CheckNeighbor(bool outflowAllowed, Vector3i neighborPosition, BlockSide side)
            {
                (BlockInstance? blockNeighbor, LiquidInstance? liquidNeighbor) = world.GetContent(neighborPosition);

                if (!outflowAllowed || blockNeighbor?.Block is not IFillable neighborFillable ||
                    !neighborFillable.AllowInflow(world, neighborPosition, side, this))
                {
                    return(false);
                }

                bool isStatic = liquidNeighbor?.IsStatic ?? false;

                if (liquidNeighbor?.Liquid == None)
                {
                    isStatic = true;

                    Vector3i belowNeighborPosition = neighborPosition + FlowDirection;

                    (BlockInstance? belowNeighborBlock, LiquidInstance? belowNeighborLiquid) = world.GetContent(
                        belowNeighborPosition);

                    if (belowNeighborLiquid?.Liquid == None &&
                        belowNeighborBlock?.Block is IFillable belowFillable &&
                        belowFillable.AllowInflow(
                            world,
                            belowNeighborPosition,
                            Direction.EntrySide(),
                            this) &&
                        neighborFillable.AllowOutflow(
                            world,
                            neighborPosition,
                            Direction.ExitSide()))
                    {
                        SetLiquid(world, this, level, isStatic: false, belowFillable, belowNeighborPosition);

                        ScheduleTick(world, belowNeighborPosition);

                        SetLiquid(world, None, LiquidLevel.Eight, isStatic: true, currentFillable, position);
                    }
                    else
                    {
                        SetLiquid(world, this, LiquidLevel.One, isStatic: false, neighborFillable, neighborPosition);

                        if (isStatic)
                        {
                            ScheduleTick(world, neighborPosition);
                        }

                        bool remaining = level != LiquidLevel.One;

                        SetLiquid(
                            world,
                            remaining ? this : None,
                            remaining ? level - 1 : LiquidLevel.Eight,
                            !remaining,
                            currentFillable,
                            position);

                        if (remaining)
                        {
                            ScheduleTick(world, position);
                        }
                    }

                    return(true);
                }

                if (liquidNeighbor != null && liquidNeighbor.Liquid != this)
                {
                    if (ContactManager.HandleContact(
                            world,
                            this.AsInstance(level),
                            position,
                            liquidNeighbor,
                            neighborPosition))
                    {
                        return(true);
                    }
                }
                else if (liquidNeighbor?.Liquid == this && level > liquidNeighbor.Level &&
                         liquidNeighbor.Level < levelHorizontal)
                {
                    bool allowsFlow = liquidNeighbor.Level != level - 1 ||
                                      level == LiquidLevel.Eight && !IsAtSurface(world, position) &&
                                      IsAtSurface(world, neighborPosition) ||
                                      HasNeighborWithLevel(world, level - 2, neighborPosition) ||
                                      HasNeighborWithEmpty(world, neighborPosition);

                    if (!allowsFlow)
                    {
                        return(false);
                    }

                    levelHorizontal    = liquidNeighbor.Level;
                    horizontalPosition = neighborPosition;
                    isHorStatic        = isStatic;

                    horizontalFillable = neighborFillable;
                }

                return(false);
            }
Esempio n. 13
0
 /// <summary>
 ///     Get a liquid as instance.
 /// </summary>
 public static LiquidInstance AsInstance(this Liquid?liquid, LiquidLevel level = LiquidLevel.Eight,
                                         bool isStatic = true)
 {
     return(liquid is null ? LiquidInstance.Default : new LiquidInstance(liquid, level, isStatic));
 }
 private LiquidMeshInfo(LiquidLevel level, BlockSide side, bool isStatic)
 {
     Level    = level;
     Side     = side;
     IsStatic = isStatic;
 }
 /// <summary>
 ///     Create liquid meshing information.
 /// </summary>
 public static LiquidMeshInfo Liquid(LiquidLevel level, BlockSide side, bool isStatic)
 {
     return(new(level, side, isStatic));
 }
Esempio n. 16
0
 /// <summary>
 ///     Get the liquid level as block height.
 /// </summary>
 public static int GetBlockHeight(this LiquidLevel level)
 {
     return(((int)level * 2) + 1);
 }
Esempio n. 17
0
 /// <inheritdoc />
 protected override void ScheduledUpdate(World world, Vector3i position, LiquidLevel level, bool isStatic)
 {
 }
Esempio n. 18
0
 public void SetPosition(Block block, uint data, Liquid liquid, LiquidLevel level, bool isStatic,
     Vector3i position)
 {
     SetContent(block, data, liquid, level, isStatic, position, tickLiquid: true);
 }
Esempio n. 19
0
 /// <inheritdoc />
 internal override void RandomUpdate(World world, Vector3i position, LiquidLevel level, bool isStatic)
 {
     BurnAround(world, position);
 }
Esempio n. 20
0
        private bool FlowVertical(World world, Vector3i position, IFillable?currentFillable, LiquidLevel level,
                                  VerticalFlow flow, bool handleContact, out int remaining)
        {
            (BlockInstance? blockVertical, LiquidInstance? liquidVertical) = world.GetContent(
                position + flow.Direction());

            if (blockVertical?.Block is IFillable verticalFillable &&
                verticalFillable.AllowInflow(
                    world,
                    position + flow.Direction(),
                    flow.EntrySide(),
                    this) &&
                (currentFillable?.AllowOutflow(world, position, flow.ExitSide()) ??
                 true))
            {
                if (liquidVertical?.Liquid == None)
                {
                    SetLiquid(world, this, level, isStatic: false, verticalFillable, position + flow.Direction());
                    SetLiquid(world, None, LiquidLevel.Eight, isStatic: true, currentFillable, position);

                    ScheduleTick(world, position + flow.Direction());

                    remaining = -1;

                    return(true);
                }

                if (liquidVertical?.Liquid == this)
                {
                    if (liquidVertical.Level == LiquidLevel.Eight)
                    {
                        remaining = (int)level;

                        return(false);
                    }

                    int volume = LiquidLevel.Eight - liquidVertical.Level - 1;

                    if (volume >= (int)level)
                    {
                        SetLiquid(
                            world,
                            this,
                            liquidVertical.Level + (int)level + 1,
                            isStatic: false,
                            verticalFillable,
                            position + flow.Direction());

                        SetLiquid(world, None, LiquidLevel.Eight, isStatic: true, currentFillable, position);

                        remaining = -1;
                    }
                    else
                    {
                        SetLiquid(
                            world,
                            this,
                            LiquidLevel.Eight,
                            isStatic: false,
                            verticalFillable,
                            position + flow.Direction());

                        SetLiquid(world, this, level - volume - 1, isStatic: false, currentFillable, position);

                        remaining = (int)(level - volume - 1);

                        ScheduleTick(world, position);
                    }

                    if (liquidVertical.IsStatic)
                    {
                        ScheduleTick(world, position + flow.Direction());
                    }

                    return(true);
                }

                if (handleContact && liquidVertical != null)
                {
                    remaining = (int)level;

                    return(ContactManager.HandleContact(
                               world,
                               this.AsInstance(level),
                               position,
                               liquidVertical,
                               position + flow.Direction()));
                }
            }

            remaining = (int)level;

            return(false);
        }