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
|
package space.autistic.radio.entity
import net.minecraft.entity.Entity
import net.minecraft.entity.EntityType
import net.minecraft.entity.data.DataTracker
import net.minecraft.entity.data.TrackedDataHandlerRegistry
import net.minecraft.entity.decoration.AbstractDecorationEntity
import net.minecraft.entity.player.PlayerEntity
import net.minecraft.nbt.NbtCompound
import net.minecraft.network.listener.ClientPlayPacketListener
import net.minecraft.network.packet.Packet
import net.minecraft.network.packet.s2c.play.EntitySpawnS2CPacket
import net.minecraft.server.network.EntityTrackerEntry
import net.minecraft.util.ActionResult
import net.minecraft.util.Hand
import net.minecraft.util.math.*
import net.minecraft.world.World
import net.minecraft.world.event.GameEvent
import space.autistic.radio.PirateRadioComponents
import space.autistic.radio.PirateRadioEntityTypes
import space.autistic.radio.PirateRadioItems
import kotlin.math.max
import kotlin.math.min
class DisposableTransmitterEntity : AbstractDecorationEntity {
var despawnDelay = 60 * 60 * 20
constructor(type: EntityType<out DisposableTransmitterEntity>?, world: World?) : super(type, world)
constructor(
type: EntityType<out DisposableTransmitterEntity>?,
world: World?,
pos: BlockPos,
facing: Direction
) : super(
type, world, pos
) {
this.setFacing(facing)
}
constructor(
world: World,
blockPos2: BlockPos,
direction: Direction
) : this(PirateRadioEntityTypes.DISPOSABLE_TRANSMITTER, world, blockPos2, direction)
override fun initDataTracker(builder: DataTracker.Builder) {
builder.add(TEXT, "")
builder.add(FREQUENCY, 768)
}
override fun tick() {
super.tick()
if (!world.isClient) {
this.tickDespawnDelay();
}
}
private fun tickDespawnDelay() {
if (this.despawnDelay > 0 && --this.despawnDelay == 0) {
this.discard()
}
}
override fun setFacing(facing: Direction) {
this.facing = facing
if (facing.axis.isHorizontal) {
this.pitch = 0.0f
this.yaw = (this.facing.horizontal * 90).toFloat()
} else {
this.pitch = (-90 * facing.direction.offset()).toFloat()
this.yaw = 0.0f
}
this.prevPitch = this.pitch
this.prevYaw = this.yaw
this.updateAttachmentPosition()
}
override fun calculateBoundingBox(pos: BlockPos, side: Direction): Box {
val center = Vec3d.ofCenter(pos).offset(side, -(1.0 - DEPTH) / 2.0)
val axis = side.axis
val dx = if (axis === Direction.Axis.X) DEPTH else WIDTH
val dy = if (axis === Direction.Axis.Y) DEPTH else HEIGHT
val dz = if (axis === Direction.Axis.Z) DEPTH else WIDTH
return Box.of(center, dx, dy, dz)
}
// leave this true for performance
override fun canStayAttached(): Boolean = true
override fun onBreak(breaker: Entity?) {
// hmm, what to do here...
}
override fun onPlace() {
// hmm, what to do here...
}
var text: String
get() {
return this.dataTracker[TEXT]
}
set(value) {
this.dataTracker[TEXT] = value
}
var frequency: Int
get() {
return this.dataTracker[FREQUENCY]
}
set(value) {
this.dataTracker[FREQUENCY] = value
}
override fun writeCustomDataToNbt(nbt: NbtCompound) {
super.writeCustomDataToNbt(nbt)
nbt.putByte("Facing", this.facing.id.toByte())
nbt.putInt("DespawnDelay", this.despawnDelay)
nbt.putString("Text", this.text)
nbt.putBoolean("Invisible", this.isInvisible)
nbt.putInt("Frequency", this.frequency)
}
override fun readCustomDataFromNbt(nbt: NbtCompound) {
super.readCustomDataFromNbt(nbt)
this.despawnDelay = nbt.getInt("DespawnDelay")
this.setFacing(Direction.byId(nbt.getByte("Facing").toInt()))
this.text = nbt.getString("Text")
this.isInvisible = nbt.getBoolean("Invisible")
this.frequency = min(1080, max(768, nbt.getInt("Frequency")))
}
override fun createSpawnPacket(entityTrackerEntry: EntityTrackerEntry): Packet<ClientPlayPacketListener> {
return EntitySpawnS2CPacket(this, facing.id, this.getAttachedBlockPos())
}
override fun onSpawnPacket(packet: EntitySpawnS2CPacket) {
super.onSpawnPacket(packet)
this.setFacing(Direction.byId(packet.entityData))
}
override fun getBodyYaw(): Float {
val direction = this.horizontalFacing
val i = if (direction.axis.isVertical) 90 * direction.direction.offset() else 0
return MathHelper.wrapDegrees(180 + direction.horizontal * 90 + i).toFloat()
}
override fun interact(player: PlayerEntity, hand: Hand): ActionResult {
val itemStack = player.getStackInHand(hand)
val noTextInTransmitter = this.text.isEmpty()
val isCard = itemStack.isOf(PirateRadioItems.STORAGE_CARD)
val holdingMessage = isCard && (itemStack.get(PirateRadioComponents.MESSAGE)?.literalString ?: "").isNotEmpty()
if (!world.isClient) {
if (noTextInTransmitter) {
if (holdingMessage && !this.isRemoved) {
this.frequency = itemStack.getOrDefault(PirateRadioComponents.FREQUENCY, 768)
this.text = itemStack.get(PirateRadioComponents.MESSAGE)?.literalString ?: ""
this.emitGameEvent(GameEvent.BLOCK_CHANGE, player)
itemStack.decrementUnlessCreative(1, player)
}
}
return ActionResult.CONSUME
} else {
return if (noTextInTransmitter && holdingMessage) ActionResult.SUCCESS else ActionResult.PASS
}
}
companion object {
private val TEXT =
DataTracker.registerData(DisposableTransmitterEntity::class.java, TrackedDataHandlerRegistry.STRING)
private val FREQUENCY =
DataTracker.registerData(DisposableTransmitterEntity::class.java, TrackedDataHandlerRegistry.INTEGER)
const val DEPTH = 0.0625
private const val WIDTH = 0.75
private const val HEIGHT = 0.75
}
}
|