エクストリーム・エクスプロージョン・デモ


私は非常にブロックを爆発Minecraft modを書きます.

package com.nshmura.doromod;

import net.minecraft.client.Minecraft
import net.minecraft.util.ResourceLocation
import net.minecraft.util.math.vector.Vector3d
import net.minecraft.world.Explosion
import net.minecraftforge.common.MinecraftForge
import net.minecraftforge.event.TickEvent
import net.minecraftforge.event.entity.player.PlayerInteractEvent
import net.minecraftforge.eventbus.api.SubscribeEvent
import net.minecraftforge.fml.common.Mod
import net.minecraftforge.fml.network.NetworkEvent
import net.minecraftforge.fml.network.NetworkRegistry
import net.minecraftforge.fml.network.simple.SimpleChannel
import net.minecraftforge.fml.server.ServerLifecycleHooks
import org.apache.logging.log4j.LogManager
import org.apache.logging.log4j.Logger
import java.util.function.Supplier


@Mod(ExampleMod.MOD_ID)
class ExampleMod {
    private val logger: Logger = LogManager.getLogger(MOD_ID)

    private val channel: SimpleChannel = NetworkRegistry.newSimpleChannel(
        ResourceLocation(MOD_ID, "main"),
        { PROTOCOL_VERSION },
        PROTOCOL_VERSION::equals,
        PROTOCOL_VERSION::equals
    )

    private var explosions: List<ContinuousExplosion> = emptyList()

    init {
        channel.registerMessage(
            0,
            ExplosionMessage::class.java,
            ExplosionMessage::encode,
            ExplosionMessage::from,
            this::handle
        )

        MinecraftForge.EVENT_BUS.register(this)
    }

    @SubscribeEvent
    fun on(event: PlayerInteractEvent.LeftClickEmpty) {
        val loc = Minecraft.getInstance().hitResult?.location
            ?: return
        logger.info("[HIT] ${loc.x} ${loc.y} ${loc.z}")

        explosions = explosions.plus(ContinuousExplosion(event, loc))
    }

    @SubscribeEvent
    fun on(event: TickEvent.ClientTickEvent) {
        explosions = explosions.mapNotNull {
            it.tick(event) { message ->
                channel.sendToServer(message)
                logger.info("[POS] ${message.x} ${message.y} ${message.z}")
            }
        }
    }

    private fun handle(message: ExplosionMessage, context: Supplier<NetworkEvent.Context>) {
        logger.info("[EXP] ${message.x} ${message.y}  ${message.z} ")

        ServerLifecycleHooks.getCurrentServer().overworld().explode(
            null,
            message.x,
            message.y,
            message.z,
            message.size,
            Explosion.Mode.BREAK
        )
    }

    companion object {
        const val MOD_ID: String = "doro_mod"
        private const val PROTOCOL_VERSION = "1"
    }
}

class ContinuousExplosion(
    private val event: PlayerInteractEvent.LeftClickEmpty,
    private val location: Vector3d
) {
    private var explodeCount = 0
    private var tickCount = 0

    fun tick(tick: TickEvent, handler: (ExplosionMessage) -> Unit): ContinuousExplosion? {
        if (tick.phase != TickEvent.Phase.START) {
            return this
        }
        tickCount++
        if (tickCount % WAIT_TICK != 0) {
            return this
        }

        val pos = moveTo(location, event.player.lookAngle, explodeCount * EXPLODE_DISTANCE)
        handler(ExplosionMessage(pos.x, pos.y, pos.z, EXPLODE_SIZE))

        explodeCount++
        return if (explodeCount >= EXPLODE_COUNT) {
            null
        } else {
            this
        }
    }

    private fun moveTo(position: Vector3d, angle: Vector3d, multiply: Double) =
        Vector3d(
            position.x + angle.x * multiply,
            position.y + angle.y * multiply,
            position.z + angle.z * multiply
        )

    companion object {
        private const val WAIT_TICK = 5
        private const val EXPLODE_COUNT = 25
        private const val EXPLODE_SIZE = 16F
        private const val EXPLODE_DISTANCE = 5.toDouble()
    }
}