github.com/df-mc/dragonfly@v0.9.13/server/block/lava.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/world" 7 "github.com/df-mc/dragonfly/server/world/sound" 8 "math/rand" 9 "time" 10 ) 11 12 // Lava is a light-emitting fluid block that causes fire damage. 13 type Lava struct { 14 empty 15 replaceable 16 17 // Still makes the lava not spread whenever it is updated. Still lava cannot be acquired in the game 18 // without world editing. 19 Still bool 20 // Depth is the depth of the water. This is a number from 1-8, where 8 is a source block and 1 is the 21 // smallest possible lava block. 22 Depth int 23 // Falling specifies if the lava is falling. Falling lava will always appear as a source block, but its 24 // behaviour differs when it starts spreading. 25 Falling bool 26 } 27 28 // neighboursLavaFlammable returns true if one a block adjacent to the passed position is flammable. 29 func neighboursLavaFlammable(pos cube.Pos, w *world.World) bool { 30 for i := cube.Face(0); i < 6; i++ { 31 if flammable, ok := w.Block(pos.Side(i)).(Flammable); ok && flammable.FlammabilityInfo().LavaFlammable { 32 return true 33 } 34 } 35 return false 36 } 37 38 // EntityInside ... 39 func (l Lava) EntityInside(_ cube.Pos, _ *world.World, e world.Entity) { 40 if fallEntity, ok := e.(fallDistanceEntity); ok { 41 fallEntity.ResetFallDistance() 42 } 43 if flammable, ok := e.(flammableEntity); ok { 44 if l, ok := e.(livingEntity); ok && !l.AttackImmune() { 45 l.Hurt(4, LavaDamageSource{}) 46 } 47 flammable.SetOnFire(15 * time.Second) 48 } 49 } 50 51 // RandomTick ... 52 func (l Lava) RandomTick(pos cube.Pos, w *world.World, r *rand.Rand) { 53 i := r.Intn(3) 54 if i > 0 { 55 for j := 0; j < i; j++ { 56 pos = pos.Add(cube.Pos{r.Intn(3) - 1, 1, r.Intn(3) - 1}) 57 if _, ok := w.Block(pos).(Air); ok { 58 if neighboursLavaFlammable(pos, w) { 59 w.SetBlock(pos, Fire{}, nil) 60 } 61 } 62 } 63 } else { 64 for j := 0; j < 3; j++ { 65 pos = pos.Add(cube.Pos{r.Intn(3) - 1, 0, r.Intn(3) - 1}) 66 if _, ok := w.Block(pos.Side(cube.FaceUp)).(Air); ok { 67 if flammable, ok := w.Block(pos).(Flammable); ok && flammable.FlammabilityInfo().LavaFlammable && flammable.FlammabilityInfo().Encouragement > 0 { 68 w.SetBlock(pos, Fire{}, nil) 69 } 70 } 71 } 72 } 73 } 74 75 // HasLiquidDrops ... 76 func (Lava) HasLiquidDrops() bool { 77 return false 78 } 79 80 // LightDiffusionLevel always returns 2. 81 func (Lava) LightDiffusionLevel() uint8 { 82 return 2 83 } 84 85 // LightEmissionLevel returns 15. 86 func (Lava) LightEmissionLevel() uint8 { 87 return 15 88 } 89 90 // NeighbourUpdateTick ... 91 func (l Lava) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) { 92 if !l.Harden(pos, w, nil) { 93 w.ScheduleBlockUpdate(pos, w.Dimension().LavaSpreadDuration()) 94 } 95 } 96 97 // ScheduledTick ... 98 func (l Lava) ScheduledTick(pos cube.Pos, w *world.World, _ *rand.Rand) { 99 if !l.Harden(pos, w, nil) { 100 tickLiquid(l, pos, w) 101 } 102 } 103 104 // LiquidDepth returns the depth of the lava. 105 func (l Lava) LiquidDepth() int { 106 return l.Depth 107 } 108 109 // SpreadDecay always returns 2. 110 func (Lava) SpreadDecay() int { 111 return 2 112 } 113 114 // WithDepth returns a new Lava block with the depth passed and falling if set to true. 115 func (l Lava) WithDepth(depth int, falling bool) world.Liquid { 116 l.Depth = depth 117 l.Falling = falling 118 l.Still = false 119 return l 120 } 121 122 // LiquidFalling checks if the lava is falling. 123 func (l Lava) LiquidFalling() bool { 124 return l.Falling 125 } 126 127 // BlastResistance always returns 500. 128 func (Lava) BlastResistance() float64 { 129 return 500 130 } 131 132 // LiquidType returns 10 as a unique identifier for the lava liquid. 133 func (Lava) LiquidType() string { 134 return "lava" 135 } 136 137 // Harden handles the hardening logic of lava. 138 func (l Lava) Harden(pos cube.Pos, w *world.World, flownIntoBy *cube.Pos) bool { 139 var ok bool 140 var water, b world.Block 141 142 if flownIntoBy == nil { 143 var water, b world.Block 144 _, soulSoilFound := w.Block(pos.Side(cube.FaceDown)).(SoulSoil) 145 pos.Neighbours(func(neighbour cube.Pos) { 146 if b != nil || neighbour[1] == pos[1]-1 { 147 return 148 } 149 if _, ok := w.Block(neighbour).(BlueIce); ok { 150 if soulSoilFound { 151 b = Basalt{} 152 } 153 return 154 } 155 if waterBlock, ok := w.Block(neighbour).(Water); ok { 156 water = waterBlock 157 if l.Depth == 8 && !l.Falling { 158 b = Obsidian{} 159 return 160 } 161 b = Cobblestone{} 162 } 163 }, w.Range()) 164 if b != nil { 165 ctx := event.C() 166 if w.Handler().HandleLiquidHarden(ctx, pos, l, water, b); ctx.Cancelled() { 167 return false 168 } 169 w.PlaySound(pos.Vec3Centre(), sound.Fizz{}) 170 w.SetBlock(pos, b, nil) 171 return true 172 } 173 return false 174 } 175 water, ok = w.Block(*flownIntoBy).(Water) 176 if !ok { 177 return false 178 } 179 180 if l.Depth == 8 && !l.Falling { 181 b = Obsidian{} 182 } else { 183 b = Cobblestone{} 184 } 185 ctx := event.C() 186 if w.Handler().HandleLiquidHarden(ctx, pos, l, water, b); ctx.Cancelled() { 187 return false 188 } 189 w.SetBlock(pos, b, nil) 190 w.PlaySound(pos.Vec3Centre(), sound.Fizz{}) 191 return true 192 } 193 194 // EncodeBlock ... 195 func (l Lava) EncodeBlock() (name string, properties map[string]any) { 196 if l.Depth < 1 || l.Depth > 8 { 197 panic("invalid lava depth, must be between 1 and 8") 198 } 199 v := 8 - l.Depth 200 if l.Falling { 201 v += 8 202 } 203 if l.Still { 204 return "minecraft:lava", map[string]any{"liquid_depth": int32(v)} 205 } 206 return "minecraft:flowing_lava", map[string]any{"liquid_depth": int32(v)} 207 } 208 209 // allLava returns a list of all lava states. 210 func allLava() (b []world.Block) { 211 f := func(still, falling bool) { 212 b = append(b, Lava{Still: still, Falling: falling, Depth: 8}) 213 b = append(b, Lava{Still: still, Falling: falling, Depth: 7}) 214 b = append(b, Lava{Still: still, Falling: falling, Depth: 6}) 215 b = append(b, Lava{Still: still, Falling: falling, Depth: 5}) 216 b = append(b, Lava{Still: still, Falling: falling, Depth: 4}) 217 b = append(b, Lava{Still: still, Falling: falling, Depth: 3}) 218 b = append(b, Lava{Still: still, Falling: falling, Depth: 2}) 219 b = append(b, Lava{Still: still, Falling: falling, Depth: 1}) 220 } 221 f(true, true) 222 f(true, false) 223 f(false, false) 224 f(false, true) 225 return 226 } 227 228 // LavaDamageSource is used for damage caused by being in lava. 229 type LavaDamageSource struct{} 230 231 func (LavaDamageSource) ReducedByResistance() bool { return true } 232 func (LavaDamageSource) ReducedByArmour() bool { return true } 233 func (LavaDamageSource) Fire() bool { return true }