github.com/df-mc/dragonfly@v0.9.13/server/block/sea_pickle.go (about) 1 package block 2 3 import ( 4 "github.com/df-mc/dragonfly/server/block/cube" 5 "github.com/df-mc/dragonfly/server/item" 6 "github.com/df-mc/dragonfly/server/world" 7 "github.com/df-mc/dragonfly/server/world/particle" 8 "github.com/go-gl/mathgl/mgl64" 9 "math" 10 "math/rand" 11 ) 12 13 // SeaPickle is a small stationary underwater block that emits light, and is typically found in colonies of up to 14 // four sea pickles. 15 type SeaPickle struct { 16 empty 17 transparent 18 sourceWaterDisplacer 19 20 // AdditionalCount is the amount of additional sea pickles clustered together. 21 AdditionalCount int 22 // Dead is whether the sea pickles are not alive. Sea pickles are only considered alive when inside of water. While 23 // alive, sea pickles emit light & can be grown with bone meal. 24 Dead bool 25 } 26 27 // canSurvive ... 28 func (SeaPickle) canSurvive(pos cube.Pos, w *world.World) bool { 29 below := w.Block(pos.Side(cube.FaceDown)) 30 if !below.Model().FaceSolid(pos.Side(cube.FaceDown), cube.FaceUp, w) { 31 return false 32 } 33 if emitter, ok := below.(LightDiffuser); ok && emitter.LightDiffusionLevel() != 15 { 34 return false 35 } 36 return true 37 } 38 39 // BoneMeal ... 40 func (s SeaPickle) BoneMeal(pos cube.Pos, w *world.World) bool { 41 if s.Dead { 42 return false 43 } 44 if coral, ok := w.Block(pos.Side(cube.FaceDown)).(CoralBlock); !ok || coral.Dead { 45 return false 46 } 47 48 if s.AdditionalCount != 3 { 49 s.AdditionalCount = 3 50 w.SetBlock(pos, s, nil) 51 } 52 53 for x := -2; x <= 2; x++ { 54 distance := -int(math.Abs(float64(x))) + 2 55 for z := -distance; z <= distance; z++ { 56 for y := -1; y < 1; y++ { 57 if (x == 0 && y == 0 && z == 0) || rand.Intn(6) != 0 { 58 continue 59 } 60 newPos := pos.Add(cube.Pos{x, y, z}) 61 62 if _, ok := w.Block(newPos).(Water); !ok { 63 continue 64 } 65 if coral, ok := w.Block(newPos.Side(cube.FaceDown)).(CoralBlock); !ok || coral.Dead { 66 continue 67 } 68 w.SetBlock(newPos, SeaPickle{AdditionalCount: rand.Intn(3) + 1}, nil) 69 } 70 } 71 } 72 73 return true 74 } 75 76 // UseOnBlock ... 77 func (s SeaPickle) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) bool { 78 if existing, ok := w.Block(pos).(SeaPickle); ok { 79 if existing.AdditionalCount >= 3 { 80 return false 81 } 82 83 existing.AdditionalCount++ 84 place(w, pos, existing, user, ctx) 85 return placed(ctx) 86 } 87 88 pos, _, used := firstReplaceable(w, pos, face, s) 89 if !used { 90 return false 91 } 92 if !s.canSurvive(pos, w) { 93 return false 94 } 95 96 s.Dead = true 97 if liquid, ok := w.Liquid(pos); ok { 98 _, ok = liquid.(Water) 99 s.Dead = !ok 100 } 101 102 place(w, pos, s, user, ctx) 103 return placed(ctx) 104 } 105 106 // NeighbourUpdateTick ... 107 func (s SeaPickle) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) { 108 if !s.canSurvive(pos, w) { 109 w.SetBlock(pos, nil, nil) 110 w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: s}) 111 dropItem(w, item.NewStack(s, s.AdditionalCount+1), pos.Vec3Centre()) 112 return 113 } 114 115 alive := false 116 if liquid, ok := w.Liquid(pos); ok { 117 _, alive = liquid.(Water) 118 } 119 if s.Dead == alive { 120 s.Dead = !alive 121 w.SetBlock(pos, s, nil) 122 } 123 } 124 125 // HasLiquidDrops ... 126 func (SeaPickle) HasLiquidDrops() bool { 127 return true 128 } 129 130 // SideClosed ... 131 func (SeaPickle) SideClosed(cube.Pos, cube.Pos, *world.World) bool { 132 return false 133 } 134 135 // LightEmissionLevel ... 136 func (s SeaPickle) LightEmissionLevel() uint8 { 137 if s.Dead { 138 return 0 139 } 140 return uint8(6 + s.AdditionalCount*3) 141 } 142 143 // BreakInfo ... 144 func (s SeaPickle) BreakInfo() BreakInfo { 145 return newBreakInfo(0, alwaysHarvestable, nothingEffective, simpleDrops(item.NewStack(s, s.AdditionalCount+1))) 146 } 147 148 // FlammabilityInfo ... 149 func (SeaPickle) FlammabilityInfo() FlammabilityInfo { 150 return newFlammabilityInfo(15, 100, true) 151 } 152 153 // SmeltInfo ... 154 func (SeaPickle) SmeltInfo() item.SmeltInfo { 155 return newSmeltInfo(item.NewStack(item.Dye{Colour: item.ColourLime()}, 1), 0.1) 156 } 157 158 // CompostChance ... 159 func (SeaPickle) CompostChance() float64 { 160 return 0.65 161 } 162 163 // EncodeItem ... 164 func (SeaPickle) EncodeItem() (name string, meta int16) { 165 return "minecraft:sea_pickle", 0 166 } 167 168 // EncodeBlock ... 169 func (s SeaPickle) EncodeBlock() (string, map[string]any) { 170 return "minecraft:sea_pickle", map[string]any{"cluster_count": int32(s.AdditionalCount), "dead_bit": s.Dead} 171 } 172 173 // allSeaPickles ... 174 func allSeaPickles() (b []world.Block) { 175 for i := 0; i <= 3; i++ { 176 b = append(b, SeaPickle{AdditionalCount: i}) 177 b = append(b, SeaPickle{AdditionalCount: i, Dead: true}) 178 } 179 return 180 }