-
Notifications
You must be signed in to change notification settings - Fork 140
/
block.go
233 lines (197 loc) · 8.19 KB
/
block.go
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
package block
import (
"github.com/df-mc/dragonfly/server/block/cube"
"github.com/df-mc/dragonfly/server/block/instrument"
"github.com/df-mc/dragonfly/server/entity"
"github.com/df-mc/dragonfly/server/entity/effect"
"github.com/df-mc/dragonfly/server/item"
"github.com/df-mc/dragonfly/server/world"
"github.com/df-mc/dragonfly/server/world/sound"
)
// Activatable represents a block that may be activated by a viewer of the world. When activated, the block
// will execute some specific logic.
type Activatable interface {
// Activate activates the block at a specific block position. The face clicked is passed, as well as the
// world in which the block was activated and the viewer that activated it.
Activate(pos cube.Pos, clickedFace cube.Face, w *world.World, u item.User)
}
// Punchable represents a block that may be punched by a viewer of the world. When punched, the block
// will execute some specific logic.
type Punchable interface {
// Punch punches the block at a specific block position. The face clicked is passed, as well as the
// world in which the block was punched and the viewer that punched it.
Punch(pos cube.Pos, clickedFace cube.Face, w *world.World, u item.User)
}
// LightEmitter represents a block that emits light when placed. Blocks such as torches or lanterns implement
// this interface.
type LightEmitter interface {
// LightEmissionLevel returns the light emission level of the block, a number from 0-15 where 15 is the
// brightest and 0 means it doesn't emit light at all.
LightEmissionLevel() uint8
}
// LightDiffuser represents a block that diffuses light. This means that a specific amount of light levels
// will be subtracted when light passes through the block.
// Blocks that do not implement LightDiffuser will be assumed to be solid: Light will not be able to pass
// through these blocks.
type LightDiffuser interface {
// LightDiffusionLevel returns the amount of light levels that is subtracted when light passes through
// this block. Some blocks, such as leaves, have this behaviour. A diffusion level of 15 means that all
// light will be completely blocked when it passes through the block.
LightDiffusionLevel() uint8
}
// Replaceable represents a block that may be replaced by another block automatically. An example is grass,
// which may be replaced by clicking it with another block.
type Replaceable interface {
// ReplaceableBy returns a bool which indicates if the block is replaceableWith by another block.
ReplaceableBy(b world.Block) bool
}
// BeaconSource represents a block which is capable of contributing to powering a beacon pyramid.
type BeaconSource interface {
// PowersBeacon returns a bool which indicates whether this block can contribute to powering up a
// beacon pyramid.
PowersBeacon() bool
}
// beaconAffected represents an entity that can be powered by a beacon. Only players will implement this.
type beaconAffected interface {
// AddEffect adds a specific effect to the entity that implements this interface.
AddEffect(e effect.Effect)
// BeaconAffected returns whether this entity can be powered by a beacon.
BeaconAffected() bool
}
// replaceableWith checks if the block at the position passed is replaceable with the block passed.
func replaceableWith(w *world.World, pos cube.Pos, with world.Block) bool {
if pos.OutOfBounds() {
return false
}
b := w.Block(pos)
if replaceable, ok := b.(Replaceable); ok {
return replaceable.ReplaceableBy(with)
}
return false
}
// firstReplaceable finds the first replaceable block position eligible to have a block placed on it after
// clicking on the position and face passed.
// If none can be found, the bool returned is false.
func firstReplaceable(w *world.World, pos cube.Pos, face cube.Face, with world.Block) (cube.Pos, cube.Face, bool) {
if replaceableWith(w, pos, with) {
// A replaceableWith block was clicked, so we can replace it. This will then be assumed to be placed on
// the top face. (Torches, for example, will get attached to the floor when clicking tall grass.)
return pos, cube.FaceUp, true
}
side := pos.Side(face)
if replaceableWith(w, side, with) {
return side, face, true
}
return pos, face, false
}
// place places the block passed at the position passed. If the user implements the block.Placer interface, it
// will use its PlaceBlock method. If not, the block is placed without interaction from the user.
func place(w *world.World, pos cube.Pos, b world.Block, user item.User, ctx *item.UseContext) {
if placer, ok := user.(Placer); ok {
placer.PlaceBlock(pos, b, ctx)
return
}
w.PlaceBlock(pos, b)
w.PlaySound(pos.Vec3(), sound.BlockPlace{Block: b})
}
// placed checks if an item was placed with the use context passed.
func placed(ctx *item.UseContext) bool {
return ctx.CountSub > 0
}
// boolByte returns 1 if the bool passed is true, or 0 if it is false.
func boolByte(b bool) uint8 {
if b {
return 1
}
return 0
}
// replaceable is a struct that may be embedded to make a block replaceable by any other block.
type replaceable struct{}
// ReplaceableBy ...
func (replaceable) ReplaceableBy(world.Block) bool {
return true
}
// transparent is a struct that may be embedded to make a block transparent to light. Light will be able to
// pass through this block freely.
type transparent struct{}
// LightDiffusionLevel ...
func (transparent) LightDiffusionLevel() uint8 {
return 0
}
// gravityAffected is a struct that may be embedded for blocks affected by gravity.
type gravityAffected struct{}
// Solidifies ...
func (g gravityAffected) Solidifies(cube.Pos, *world.World) bool {
return false
}
// fall spawns a falling block entity at the given position.
func (g gravityAffected) fall(b world.Block, pos cube.Pos, w *world.World) {
_, air := w.Block(pos.Side(cube.FaceDown)).(Air)
_, liquid := w.Liquid(pos.Side(cube.FaceDown))
if air || liquid {
w.BreakBlockWithoutParticles(pos)
e := entity.NewFallingBlock(b, pos.Vec3Middle())
w.AddEntity(e)
}
}
// Flammable is an interface for blocks that can catch on fire.
type Flammable interface {
// FlammabilityInfo returns information about a blocks behavior involving fire.
FlammabilityInfo() FlammabilityInfo
}
// FlammabilityInfo contains values related to block behaviors involving fire.
type FlammabilityInfo struct {
// Encouragement is the chance a block will catch on fire during attempted fire spread.
Encouragement,
// Flammability is the chance a block will burn away during a fire block tick.
Flammability int
// LavaFlammable returns whether it can catch on fire from lava.
LavaFlammable bool
}
// newFlammabilityInfo creates a FlammabilityInfo struct with the properties passed.
func newFlammabilityInfo(encouragement, flammability int, lavaFlammable bool) FlammabilityInfo {
return FlammabilityInfo{
Encouragement: encouragement,
Flammability: flammability,
LavaFlammable: lavaFlammable,
}
}
// EntityCollider is an interface for blocks with special behaviors on entity collision.
type EntityCollider interface {
// EntityCollide is called on entity collision.
EntityCollide(e world.Entity)
}
// FallDistanceEntity is an entity that has a fall distance.
type FallDistanceEntity interface {
// ResetFallDistance resets the entities fall distance.
ResetFallDistance()
}
// InstrumentBlock represents a block that creates a note block sound other than the piano.
type InstrumentBlock interface {
// Instrument returns the instrument used.
Instrument() instrument.Instrument
}
// bass is a struct that may be embedded for blocks that create a bass sound.
type bass struct{}
// Instrument ...
func (bass) Instrument() instrument.Instrument {
return instrument.Bass()
}
// snare is a struct that may be embedded for blocks that create a snare drum sound.
type snare struct{}
// Instrument ...
func (snare) Instrument() instrument.Instrument {
return instrument.Snare()
}
// clicksAndSticks is a struct that may be embedded for blocks that create a clicks and sticks sound.
type clicksAndSticks struct{}
// Instrument ...
func (clicksAndSticks) Instrument() instrument.Instrument {
return instrument.ClicksAndSticks()
}
// bassDrum is a struct that may be embedded for blocks that create a bass drum sound.
type bassDrum struct{}
// Instrument ...
func (bassDrum) Instrument() instrument.Instrument {
return instrument.BassDrum()
}