forked from df-mc/dragonfly
-
Notifications
You must be signed in to change notification settings - Fork 0
/
sign.go
253 lines (227 loc) · 7.96 KB
/
sign.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
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
package block
import (
"github.com/Adrian8115/dragonfly-Amethyst-Protocol/server/block/cube"
"github.com/Adrian8115/dragonfly-Amethyst-Protocol/server/internal/nbtconv"
"github.com/Adrian8115/dragonfly-Amethyst-Protocol/server/item"
"github.com/Adrian8115/dragonfly-Amethyst-Protocol/server/world"
"github.com/Adrian8115/dragonfly-Amethyst-Protocol/server/world/particle"
"github.com/Adrian8115/dragonfly-Amethyst-Protocol/server/world/sound"
"github.com/go-gl/mathgl/mgl64"
"image/color"
"strings"
"time"
)
// Sign is a non-solid block that can display text on the front and back of the block.
type Sign struct {
transparent
empty
bass
sourceWaterDisplacer
// Wood is the type of wood of the sign. This field must have one of the values found in the material
// package.
Wood WoodType
// Attach is the attachment of the Sign. It is either of the type WallAttachment or StandingAttachment.
Attach Attachment
// Waxed specifies if the Sign has been waxed by a player. If set to true, the Sign can no longer be edited by
// anyone and must be destroyed if the text needs to be changed.
Waxed bool
// Front is the text of the front side of the sign. Anyone can edit this unless the sign is Waxed.
Front SignText
// Back is the text of the back side of the sign. Anyone can edit this unless the sign is Waxed.
Back SignText
}
// SignText represents the data for a single side of a sign. The sign can be edited on the front and back side.
type SignText struct {
// Text is the text displayed on this side of the sign. The text is automatically wrapped if it does not fit on a line.
Text string
// BaseColour is the base colour of the text on this side of the sign, changed when using a dye on the sign. The default
// colour is black.
BaseColour color.RGBA
// Glowing specifies if the Sign has glowing text on the current side. If set to true, the text will be visible even
// in the dark, and it will have an outline to improve visibility.
Glowing bool
// Owner holds the XUID of the player that most recently edited this side of the sign.
Owner string
}
// SideClosed ...
func (s Sign) SideClosed(cube.Pos, cube.Pos, *world.World) bool {
return false
}
// MaxCount ...
func (s Sign) MaxCount() int {
return 16
}
// FlammabilityInfo ...
func (s Sign) FlammabilityInfo() FlammabilityInfo {
return newFlammabilityInfo(0, 0, true)
}
// FuelInfo ...
func (Sign) FuelInfo() item.FuelInfo {
return newFuelInfo(time.Second * 10)
}
// EncodeItem ...
func (s Sign) EncodeItem() (name string, meta int16) {
return "minecraft:" + s.Wood.String() + "_sign", 0
}
// BreakInfo ...
func (s Sign) BreakInfo() BreakInfo {
return newBreakInfo(1, alwaysHarvestable, axeEffective, oneOf(Sign{Wood: s.Wood}))
}
// Dye dyes the Sign, changing its base colour to that of the colour passed.
func (s Sign) Dye(pos cube.Pos, userPos mgl64.Vec3, c item.Colour) (world.Block, bool) {
if s.EditingFrontSide(pos, userPos) {
if s.Front.BaseColour == c.RGBA() {
return s, false
}
s.Front.BaseColour = c.RGBA()
} else {
if s.Back.BaseColour == c.RGBA() {
return s, false
}
s.Back.BaseColour = c.RGBA()
}
return s, true
}
// Ink inks the sign either glowing or non-glowing.
func (s Sign) Ink(pos cube.Pos, userPos mgl64.Vec3, glowing bool) (world.Block, bool) {
if s.EditingFrontSide(pos, userPos) {
if s.Front.Glowing == glowing {
return s, false
}
s.Front.Glowing = glowing
} else {
if s.Back.Glowing == glowing {
return s, false
}
s.Back.Glowing = glowing
}
return s, true
}
// Wax waxes a sign to prevent it from further editing.
func (s Sign) Wax(cube.Pos, mgl64.Vec3) (world.Block, bool) {
if s.Waxed {
return s, false
}
s.Waxed = true
return s, true
}
// Activate ...
func (s Sign) Activate(pos cube.Pos, _ cube.Face, w *world.World, user item.User, _ *item.UseContext) bool {
if editor, ok := user.(SignEditor); ok && !s.Waxed {
editor.OpenSign(pos, s.EditingFrontSide(pos, user.Position()))
} else if s.Waxed {
w.PlaySound(pos.Vec3(), sound.WaxedSignFailedInteraction{})
}
return true
}
// EditingFrontSide returns if the user is editing the front side of the sign based on their position relative to the
// position and direction of the sign.
func (s Sign) EditingFrontSide(pos cube.Pos, userPos mgl64.Vec3) bool {
return userPos.Sub(pos.Vec3Centre()).Dot(s.Attach.Rotation().Vec3()) > 0
}
// SignEditor represents something that can edit a sign, typically players.
type SignEditor interface {
OpenSign(pos cube.Pos, frontSide bool)
}
// UseOnBlock ...
func (s Sign) UseOnBlock(pos cube.Pos, face cube.Face, _ mgl64.Vec3, w *world.World, user item.User, ctx *item.UseContext) (used bool) {
pos, face, used = firstReplaceable(w, pos, face, s)
if !used || face == cube.FaceDown {
return false
}
if face == cube.FaceUp {
s.Attach = StandingAttachment(user.Rotation().Orientation().Opposite())
} else {
s.Attach = WallAttachment(face.Direction())
}
place(w, pos, s, user, ctx)
if editor, ok := user.(SignEditor); ok {
editor.OpenSign(pos, true)
}
return placed(ctx)
}
// NeighbourUpdateTick ...
func (s Sign) NeighbourUpdateTick(pos, _ cube.Pos, w *world.World) {
if s.Attach.hanging {
if _, ok := w.Block(pos.Side(s.Attach.facing.Opposite().Face())).(Air); ok {
w.SetBlock(pos, nil, nil)
w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: s})
dropItem(w, item.NewStack(Sign{Wood: s.Wood}, 1), pos.Vec3Centre())
}
return
}
if _, ok := w.Block(pos.Side(cube.FaceDown)).(Air); ok {
w.SetBlock(pos, nil, nil)
w.AddParticle(pos.Vec3Centre(), particle.BlockBreak{Block: s})
dropItem(w, item.NewStack(Sign{Wood: s.Wood}, 1), pos.Vec3Centre())
}
}
// EncodeBlock ...
func (s Sign) EncodeBlock() (name string, properties map[string]any) {
woodType := strings.Replace(s.Wood.String(), "_", "", 1) + "_"
if woodType == "oak_" {
woodType = ""
}
if s.Attach.hanging {
return "minecraft:" + woodType + "wall_sign", map[string]any{"facing_direction": int32(s.Attach.facing + 2)}
}
return "minecraft:" + woodType + "standing_sign", map[string]any{"ground_sign_direction": int32(s.Attach.o)}
}
// DecodeNBT ...
func (s Sign) DecodeNBT(data map[string]any) any {
if nbtconv.String(data, "Text") != "" {
// The NBT format changed in 1.19.80 to have separate data for each side of the sign. The old format must still
// be supported for backwards compatibility.
s.Front.Text = nbtconv.String(data, "Text")
s.Front.BaseColour = nbtconv.RGBAFromInt32(nbtconv.Int32(data, "SignTextColor"))
s.Front.Glowing = nbtconv.Bool(data, "IgnoreLighting") && nbtconv.Bool(data, "TextIgnoreLegacyBugResolved")
return s
}
front, ok := data["FrontText"].(map[string]any)
if ok {
s.Front.BaseColour = nbtconv.RGBAFromInt32(nbtconv.Int32(front, "Color"))
s.Front.Glowing = nbtconv.Bool(front, "GlowingText")
s.Front.Text = nbtconv.String(front, "Text")
s.Front.Owner = nbtconv.String(front, "Owner")
}
back, ok := data["BackText"].(map[string]any)
if ok {
s.Back.BaseColour = nbtconv.RGBAFromInt32(nbtconv.Int32(back, "Color"))
s.Back.Glowing = nbtconv.Bool(back, "GlowingText")
s.Back.Text = nbtconv.String(back, "Text")
s.Back.Owner = nbtconv.String(back, "Owner")
}
return s
}
// EncodeNBT ...
func (s Sign) EncodeNBT() map[string]any {
m := map[string]any{
"id": "Sign",
"IsWaxed": boolByte(s.Waxed),
"FrontText": map[string]any{
"SignTextColor": nbtconv.Int32FromRGBA(s.Front.BaseColour),
"IgnoreLighting": boolByte(s.Front.Glowing),
"Text": s.Front.Text,
"TextOwner": s.Front.Owner,
},
"BackText": map[string]any{
"SignTextColor": nbtconv.Int32FromRGBA(s.Back.BaseColour),
"IgnoreLighting": boolByte(s.Back.Glowing),
"Text": s.Back.Text,
"TextOwner": s.Back.Owner,
},
}
return m
}
// allSigns ...
func allSigns() (signs []world.Block) {
for _, w := range WoodTypes() {
for _, d := range cube.Directions() {
signs = append(signs, Sign{Wood: w, Attach: WallAttachment(d)})
}
for o := cube.Orientation(0); o <= 15; o++ {
signs = append(signs, Sign{Wood: w, Attach: StandingAttachment(o)})
}
}
return
}