summary refs log tree commit diff stats
path: root/src/main/kotlin/space/autistic/radio/entity/DisposableTransmitterEntity.kt
blob: b50849da7cedc6cd29d4627bc66214716613f5af (plain) (blame)
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
    }
}