github.com/df-mc/dragonfly@v0.9.13/server/block/water.go (about)

     1  package block
     2  
     3  import (
     4  	"github.com/df-mc/dragonfly/server/block/cube"
     5  	"github.com/df-mc/dragonfly/server/event"
     6  	"github.com/df-mc/dragonfly/server/item"
     7  	"github.com/df-mc/dragonfly/server/item/potion"
     8  	"github.com/df-mc/dragonfly/server/world"
     9  	"github.com/df-mc/dragonfly/server/world/sound"
    10  	"math/rand"
    11  	"time"
    12  )
    13  
    14  // Water is a natural fluid that generates abundantly in the world.
    15  type Water struct {
    16  	empty
    17  	replaceable
    18  
    19  	// Still makes the water appear as if it is not flowing.
    20  	Still bool
    21  	// Depth is the depth of the water. This is a number from 1-8, where 8 is a source block and 1 is the
    22  	// smallest possible water block.
    23  	Depth int
    24  	// Falling specifies if the water is falling. Falling water will always appear as a source block, but its
    25  	// behaviour differs when it starts spreading.
    26  	Falling bool
    27  }
    28  
    29  // EntityInside ...
    30  func (w Water) EntityInside(_ cube.Pos, _ *world.World, e world.Entity) {
    31  	if fallEntity, ok := e.(fallDistanceEntity); ok {
    32  		fallEntity.ResetFallDistance()
    33  	}
    34  	if flammable, ok := e.(flammableEntity); ok {
    35  		flammable.Extinguish()
    36  	}
    37  }
    38  
    39  // FillBottle ...
    40  func (w Water) FillBottle() (world.Block, item.Stack, bool) {
    41  	if w.Depth == 8 {
    42  		return w, item.NewStack(item.Potion{Type: potion.Water()}, 1), true
    43  	}
    44  	return nil, item.Stack{}, false
    45  }
    46  
    47  // LiquidDepth returns the depth of the water.
    48  func (w Water) LiquidDepth() int {
    49  	return w.Depth
    50  }
    51  
    52  // SpreadDecay returns 1 - The amount of levels decreased upon spreading.
    53  func (Water) SpreadDecay() int {
    54  	return 1
    55  }
    56  
    57  // WithDepth returns the water with the depth passed.
    58  func (w Water) WithDepth(depth int, falling bool) world.Liquid {
    59  	w.Depth = depth
    60  	w.Falling = falling
    61  	w.Still = false
    62  	return w
    63  }
    64  
    65  // LiquidFalling returns Water.Falling.
    66  func (w Water) LiquidFalling() bool {
    67  	return w.Falling
    68  }
    69  
    70  // BlastResistance always returns 500.
    71  func (Water) BlastResistance() float64 {
    72  	return 500
    73  }
    74  
    75  // HasLiquidDrops ...
    76  func (Water) HasLiquidDrops() bool {
    77  	return false
    78  }
    79  
    80  // LightDiffusionLevel ...
    81  func (Water) LightDiffusionLevel() uint8 {
    82  	return 2
    83  }
    84  
    85  // ScheduledTick ...
    86  func (w Water) ScheduledTick(pos cube.Pos, wo *world.World, _ *rand.Rand) {
    87  	if w.Depth == 7 {
    88  		// Attempt to form new water source blocks.
    89  		count := 0
    90  		pos.Neighbours(func(neighbour cube.Pos) {
    91  			if neighbour[1] == pos[1] {
    92  				if liquid, ok := wo.Liquid(neighbour); ok {
    93  					if water, ok := liquid.(Water); ok && water.Depth == 8 && !water.Falling {
    94  						count++
    95  					}
    96  				}
    97  			}
    98  		}, wo.Range())
    99  		if count >= 2 {
   100  			if !canFlowInto(w, wo, pos.Side(cube.FaceDown), true) {
   101  				// Only form a new source block if there either is no water below this block, or if the water
   102  				// below this is not falling (full source block).
   103  				res := Water{Depth: 8, Still: true}
   104  				ctx := event.C()
   105  				if wo.Handler().HandleLiquidFlow(ctx, pos, pos, res, w); ctx.Cancelled() {
   106  					return
   107  				}
   108  				wo.SetLiquid(pos, res)
   109  			}
   110  		}
   111  	}
   112  	tickLiquid(w, pos, wo)
   113  }
   114  
   115  // NeighbourUpdateTick ...
   116  func (Water) NeighbourUpdateTick(pos, _ cube.Pos, wo *world.World) {
   117  	if wo.Dimension().WaterEvaporates() {
   118  		// Particles are spawned client-side.
   119  		wo.SetLiquid(pos, nil)
   120  		return
   121  	}
   122  	wo.ScheduleBlockUpdate(pos, time.Second/4)
   123  }
   124  
   125  // LiquidType ...
   126  func (Water) LiquidType() string {
   127  	return "water"
   128  }
   129  
   130  // Harden hardens the water if lava flows into it.
   131  func (w Water) Harden(pos cube.Pos, wo *world.World, flownIntoBy *cube.Pos) bool {
   132  	if flownIntoBy == nil {
   133  		return false
   134  	}
   135  	if lava, ok := wo.Block(pos.Side(cube.FaceUp)).(Lava); ok {
   136  		ctx := event.C()
   137  		if wo.Handler().HandleLiquidHarden(ctx, pos, w, lava, Stone{}); ctx.Cancelled() {
   138  			return false
   139  		}
   140  		wo.SetBlock(pos, Stone{}, nil)
   141  		wo.PlaySound(pos.Vec3Centre(), sound.Fizz{})
   142  		return true
   143  	} else if lava, ok := wo.Block(*flownIntoBy).(Lava); ok {
   144  		ctx := event.C()
   145  		if wo.Handler().HandleLiquidHarden(ctx, pos, w, lava, Cobblestone{}); ctx.Cancelled() {
   146  			return false
   147  		}
   148  		wo.SetBlock(*flownIntoBy, Cobblestone{}, nil)
   149  		wo.PlaySound(pos.Vec3Centre(), sound.Fizz{})
   150  		return true
   151  	}
   152  	return false
   153  }
   154  
   155  // EncodeBlock ...
   156  func (w Water) EncodeBlock() (name string, properties map[string]any) {
   157  	if w.Depth < 1 || w.Depth > 8 {
   158  		panic("invalid water depth, must be between 1 and 8")
   159  	}
   160  	v := 8 - w.Depth
   161  	if w.Falling {
   162  		v += 8
   163  	}
   164  	if w.Still {
   165  		return "minecraft:water", map[string]any{"liquid_depth": int32(v)}
   166  	}
   167  	return "minecraft:flowing_water", map[string]any{"liquid_depth": int32(v)}
   168  }
   169  
   170  // allWater returns a list of all water states.
   171  func allWater() (b []world.Block) {
   172  	f := func(still, falling bool) {
   173  		b = append(b, Water{Still: still, Falling: falling, Depth: 8})
   174  		b = append(b, Water{Still: still, Falling: falling, Depth: 7})
   175  		b = append(b, Water{Still: still, Falling: falling, Depth: 6})
   176  		b = append(b, Water{Still: still, Falling: falling, Depth: 5})
   177  		b = append(b, Water{Still: still, Falling: falling, Depth: 4})
   178  		b = append(b, Water{Still: still, Falling: falling, Depth: 3})
   179  		b = append(b, Water{Still: still, Falling: falling, Depth: 2})
   180  		b = append(b, Water{Still: still, Falling: falling, Depth: 1})
   181  	}
   182  	f(true, true)
   183  	f(true, false)
   184  	f(false, false)
   185  	f(false, true)
   186  	return
   187  }