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?, world: World?) : super(type, world) constructor( type: EntityType?, 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 { 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 } }