diff --git a/.gitignore b/.gitignore index a94ed0e..ba3cf2a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ .gradle .idea -./build +build/ diff --git a/build.gradle.kts b/build.gradle.kts index e674092..1e9d46d 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -2,7 +2,7 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { kotlin("jvm") version "1.7.20" - id("io.izzel.taboolib") version "1.42" + id("io.izzel.taboolib") version "1.50" } group = "cc.maxmc.blastingcrisis" @@ -20,9 +20,9 @@ repositories { dependencies { implementation(kotlin("stdlib")) + implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") implementation("ink.ptms.core:v10800:10800") implementation("ink.ptms.core:v11200:11200") - implementation("ink.ptms:Adyeshach:1.5.12") } taboolib { @@ -34,10 +34,11 @@ taboolib { } install("common", "common-5") install("platform-bukkit") - install("module-nms", "module-nms-util", "module-chat") + install("module-nms", "module-nms-util") + install("module-chat", "module-lang", "module-configuration") options("skip-kotlin-relocate") - version = "6.0.9-117" + version = "6.0.10-12" } tasks.withType { diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/BlastingCrisis.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/BlastingCrisis.kt index 834a311..7844f4c 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/BlastingCrisis.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/BlastingCrisis.kt @@ -1,11 +1,15 @@ package cc.maxmc.blastingcrisis +import cc.maxmc.blastingcrisis.command.DebugCommand +import taboolib.common.env.RuntimeDependency import taboolib.common.platform.Plugin +@RuntimeDependency( + "org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4", +) object BlastingCrisis: Plugin() { - override fun onEnable() { - + DebugCommand.debug("debugcmd") } } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/command/DebugCommand.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/command/DebugCommand.kt index 5876518..6db1c7a 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/command/DebugCommand.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/command/DebugCommand.kt @@ -1,18 +1,149 @@ package cc.maxmc.blastingcrisis.command +import cc.maxmc.blastingcrisis.game.Game +import cc.maxmc.blastingcrisis.game.GameOreGenerator +import cc.maxmc.blastingcrisis.game.GameState +import cc.maxmc.blastingcrisis.map.GameMap +import cc.maxmc.blastingcrisis.map.MapTeam +import cc.maxmc.blastingcrisis.misc.Area +import cc.maxmc.blastingcrisis.packet.BEntityVillager +import kotlinx.coroutines.cancel import org.bukkit.Bukkit -import org.bukkit.Location -import org.bukkit.entity.Blaze -import org.bukkit.entity.EntityType +import org.bukkit.ChatColor +import org.bukkit.entity.Player +import taboolib.common.platform.ProxyPlayer import taboolib.common.platform.command.command +import taboolib.common.platform.function.adaptCommandSender +import taboolib.common.platform.function.getDataFolder +import taboolib.module.configuration.Configuration +import taboolib.platform.BukkitPlugin +import taboolib.platform.util.sendActionBar +import java.io.File object DebugCommand { + lateinit var game: Game + lateinit var villager: BEntityVillager fun debug(cmd: String) = command(cmd) { literal("game") { + execute { sender, _, _ -> + Bukkit.broadcastMessage(sender.name) + val homeArea = Area(sender.location, sender.location.add(10.0, 10.0, 10.0)) + val area1 = Area(sender.location, sender.location.add(5.0, 5.0, 5.0)) + val area2 = Area(sender.location, sender.location.add(5.0, 5.0, 5.0)) + val area3 = Area(sender.location, sender.location.add(5.0, 5.0, 5.0)) + val team = MapTeam( + "testTeam1", + ChatColor.AQUA, + sender.location, + homeArea, + area1, + area2, + listOf(area3), + area2, + sender.eyeLocation + ) + val map = GameMap( + "test", listOf( + team + ), 4 + ) + game = Game(map) + game.join(sender) + } + literal("state") { + dynamic { + execute { sender, ctx, argument -> + if (!GameState.values().map { it.name } + .contains(argument.uppercase())) return@execute sender.sendMessage("NO STATE") + val state = GameState.valueOf(argument.uppercase()) + game.state = state + sender.sendMessage("changed to $argument") + } + suggestion { _, _ -> + GameState.values().map { it.name } + } + } + } + + literal("timer") { + execute { sender, ctx, argument -> + game.timer.beginCountdown() + } + } } - literal("scoreboard") { + literal("scoreboard") { + execute { sender, context, argument -> + game.scoreboard.sendScoreboardPlayer(sender) + } + } + + literal("title") { + execute { sender, _, _ -> + val adapt = adaptCommandSender(sender) as ProxyPlayer + adapt.sendTitle("Title", "sub", 20, 20, 20) + } + } + + literal("actionBar") { + execute { sender, _, _ -> + sender.sendActionBar("This is an action bar msg") + } + } + + literal("spawnEntity") { + execute { sender, _, _ -> + val loc = sender.location + villager = BEntityVillager(loc) + villager.addViewer(sender) + } + } + +// literal("rename") { +// dynamic { +// execute { _, _, arg -> +// villager.name = arg +// } +// } +// } +// +// literal("destroy") { +// execute { sender, _, _ -> +// villager.removeViewer(sender) +// } +// } +// +// literal("hurt") { +// execute { _, _, _ -> +// villager.hurtAnimate() +// } +// } +// +// literal("die") { +// execute { _, _, _ -> +// villager.dieAnimate() +// } +// } +// +// literal("update") { +// execute { _, _, _ -> +// villager.update() +// } +// } + + literal("genOre") { + execute { sender, _, _ -> + val area = Area(sender.location.block.location, sender.location.block.location.add(20.0, 20.0, 20.0)) + BukkitPlugin.getInstance().saveResource("ore-generators/default.yml", false) + println("saved") + val config = Configuration.loadFromFile(File(getDataFolder(), "ore-generators/default.yml")) + val gen = GameOreGenerator(config) + val job = gen.enable(area) + Bukkit.getScheduler().runTaskLater(BukkitPlugin.getInstance(), { + job.cancel("Stop by hand") + } ,60 * 20) + } } } } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/debug/DListener.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/debug/DListener.kt new file mode 100644 index 0000000..5093c76 --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/debug/DListener.kt @@ -0,0 +1,26 @@ +package cc.maxmc.blastingcrisis.debug + +import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving +import org.bukkit.Bukkit +import taboolib.common.platform.event.SubscribeEvent +import taboolib.library.reflex.Reflex.Companion.getProperty +import taboolib.module.nms.PacketSendEvent +import taboolib.platform.BukkitPlugin +import taboolib.platform.util.broadcast + +object DListener { + @SubscribeEvent + fun onPacket(it: PacketSendEvent) { + Bukkit.getScheduler().runTask(BukkitPlugin.getInstance()) { + if (it.player.name != "TONY_All") return@runTask +// val source = it.packet.source + if (!it.packet.name.lowercase().contains("entity")) return@runTask +// println(it.packet.name) + if( it.packet.source !is PacketPlayOutSpawnEntityLiving ) { + return@runTask + } +// it.packet.source.getProperty("a")!!.broadcast() +// it.packet.source.getProperty("b")!!.broadcast() + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt index 7580019..8ea8e27 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/Game.kt @@ -1,14 +1,65 @@ package cc.maxmc.blastingcrisis.game import cc.maxmc.blastingcrisis.map.GameMap +import cc.maxmc.blastingcrisis.misc.debug import org.bukkit.entity.Player +import taboolib.platform.util.sendLang -class Game(val map: GameMap, val teams: List, val state: GameState, scoreboard: GameScoreboard) { - val players: List - get() { - val all = ArrayList() - teams.map { it.players }.forEach { all.addAll(it) } - return all +class Game( + val map: GameMap, +) { + val teams = map.teams.map { GameTeam(this, it) } + val scoreboard: GameScoreboard = GameScoreboard(this) + val timer: GameTimer = GameTimer(this) + val players = ArrayList() + var state: GameState = GameState.WAITING + + private fun autoJoinTeam() { + players.filter { it.team == null } + .shuffled() + .forEach { + teams.minBy { team -> team.players.size }.join(it) + } + } + + fun join(player: Player) { + players += player + broadcast { + it.sendLang("game_join", player.name) } + scoreboard.sendScoreboard() + } + + fun leave(player: Player) { + if (state == GameState.WAITING || state == GameState.COUNTING_DOWN) { + players.remove(player) + checkStart() + } + val team = + player.team ?: throw IllegalStateException("Player ${player.name} has no team, which shouldn't happen.") + team.checkTeamAlive() + team.players.remove(player) + checkEnd() + } + + fun start() { + debug("game ${map.name} started.") + + } + + private fun checkStart() { + if (players.size > map.maxPlayer * 0.75) { + state = GameState.COUNTING_DOWN + timer.beginCountdown() + } + } + + private fun checkEnd() { + + } + + fun broadcast(action: (Player) -> Unit) { + players.forEach(action) + } } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameOreGenerator.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameOreGenerator.kt new file mode 100644 index 0000000..bab34b3 --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameOreGenerator.kt @@ -0,0 +1,51 @@ +package cc.maxmc.blastingcrisis.game + +import cc.maxmc.blastingcrisis.misc.Area +import cc.maxmc.blastingcrisis.misc.WeightRandom +import cc.maxmc.blastingcrisis.misc.debug +import cc.maxmc.blastingcrisis.misc.pluginScore +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.launch +import org.bukkit.Bukkit +import org.bukkit.Material +import taboolib.common.util.random +import taboolib.library.xseries.XMaterial +import taboolib.module.configuration.Configuration +import taboolib.platform.BukkitPlugin + +class GameOreGenerator(config: Configuration) { + private val rate: Int = config.getInt("rate") + private val ores: MutableMap = HashMap().also { + config.getConfigurationSection("ores")!!.getKeys(false).forEach { key -> + it += XMaterial.valueOf(key) to (config["ores.$key"]!! as Int) + } + } + private val random = WeightRandom(ores.map { it.key to it.value }) + + fun enable(area: Area): Job { + return pluginScore.launch { + while (true) { + generate(area) + delay(rate * 50L) + } + } + } + + private tailrec fun generate(area: Area) { + val x = random(area.locMin.blockX, area.locTop.blockX) + val y = random(area.locMin.blockY, area.locTop.blockY) + val z = random(area.locMin.blockZ, area.locTop.blockZ) + val block = area.locMin.world.getBlockAt(x, y, z) + debug("trying generate at ($x, $y, $z) - ${block.type}") + + if (block.type == Material.AIR) { + Bukkit.getScheduler().runTask(BukkitPlugin.getInstance()) { + block.type = random.random().parseMaterial() + debug("generating ${block.type} at ($x, $y, $z)") + } + } else { + return generate(area) + } + } +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GamePlayer.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GamePlayer.kt index 8b3e540..bc8d9fd 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GamePlayer.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GamePlayer.kt @@ -1,2 +1,9 @@ package cc.maxmc.blastingcrisis.game +import cc.maxmc.blastingcrisis.misc.GameManager +import org.bukkit.entity.Player + +val Player.team: GameTeam? + get() = GameManager.currentGame.teams.findLast { + it.players.contains(this) + } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameScoreboard.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameScoreboard.kt index e43a455..4ca4a6d 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameScoreboard.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameScoreboard.kt @@ -1,28 +1,27 @@ package cc.maxmc.blastingcrisis.game import cc.maxmc.blastingcrisis.game.GameState.* +import cc.maxmc.blastingcrisis.misc.debug import org.bukkit.entity.Player import taboolib.module.nms.sendScoreboard import taboolib.platform.util.asLangText class GameScoreboard(val game: Game) { fun sendScoreboard() { - game.teams.forEach { g -> - g.players.forEach { - sendScoreboardPlayer(it) - } + game.broadcast { + sendScoreboardPlayer(it) } } fun sendScoreboardPlayer(player: Player) { - + debug("sending Scoreboard to ${player.name}") val scoreboardText = when (game.state) { WAITING -> { player.asLangText("scoreboard_waiting", game.players.size, game.map.maxPlayer) } COUNTING_DOWN -> { - player.asLangText("scoreboard_counting_down", game.players.size, game.map.maxPlayer) + player.asLangText("scoreboard_counting_down", game.players.size, game.map.maxPlayer, game.timer.current) } START -> TODO() WALL_FALL -> TODO() diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt index 653d189..394d059 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTeam.kt @@ -3,6 +3,16 @@ package cc.maxmc.blastingcrisis.game import cc.maxmc.blastingcrisis.map.MapTeam import org.bukkit.entity.Player -class GameTeam(val team: MapTeam, val players: List) { +class GameTeam(val game: Game, val team: MapTeam) { + val players = ArrayList() + + fun join(player: Player) { + players += player + + + } + fun checkTeamAlive() { + + } } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTimer.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTimer.kt index f546bea..f1600b6 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTimer.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/game/GameTimer.kt @@ -1,10 +1,49 @@ package cc.maxmc.blastingcrisis.game -class GameTimer(val game: Game) { - val time2Start = 2 +import cc.maxmc.blastingcrisis.misc.pluginScore +import kotlinx.coroutines.Job +import kotlinx.coroutines.delay +import kotlinx.coroutines.isActive +import kotlinx.coroutines.launch +import taboolib.common.platform.function.adaptCommandSender +import taboolib.module.lang.getLocaleFile +import taboolib.platform.util.asLangTextOrNull +import taboolib.platform.util.sendLang + +class GameTimer(private val game: Game) { + val timeToStart = 15 + lateinit var countdownJob: Job + var current = timeToStart fun beginCountdown() { + countdownJob = pluginScore.launch { + while (current > 0) { + if (!isActive) { + return@launch + } + countdown() + current-- + delay(1000) + } + game.start() + } + } + private fun countdown() { + game.scoreboard.sendScoreboard() + game.broadcast { + val locale = adaptCommandSender(it).getLocaleFile()!! + if (locale.nodes.containsKey("game_countdown_${current}")) { + it.sendLang("game_countdown_${current}") + } + } + } + + fun resetCountdown() { + game.broadcast { + it.sendLang("time_reset") + } + current = timeToStart } fun startTimer() { diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Coroutines.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Coroutines.kt new file mode 100644 index 0000000..0240d2b --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Coroutines.kt @@ -0,0 +1,9 @@ +package cc.maxmc.blastingcrisis.misc + +import kotlinx.coroutines.CoroutineExceptionHandler +import kotlinx.coroutines.CoroutineScope +import kotlinx.coroutines.SupervisorJob + +val pluginScore = CoroutineScope(SupervisorJob() + CoroutineExceptionHandler { job, exception -> + IllegalStateException("在执行 Job $job 时出线异常", exception).printStackTrace() +}) \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/misc/DebugMessage.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/DebugMessage.kt new file mode 100644 index 0000000..63e4fa1 --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/DebugMessage.kt @@ -0,0 +1,7 @@ +package cc.maxmc.blastingcrisis.misc + +import taboolib.common.platform.function.console + +fun debug(message: String) { + console().sendMessage("§1DEBUG| §7$message") +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/misc/GameManager.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/GameManager.kt index 99efdc4..b427686 100644 --- a/src/main/kotlin/cc/maxmc/blastingcrisis/misc/GameManager.kt +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/GameManager.kt @@ -1,5 +1,7 @@ package cc.maxmc.blastingcrisis.misc -object GameManager { +import cc.maxmc.blastingcrisis.game.Game +object GameManager { + lateinit var currentGame : Game } \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Math.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Math.kt new file mode 100644 index 0000000..64511ca --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/misc/Math.kt @@ -0,0 +1,24 @@ +package cc.maxmc.blastingcrisis.misc + +import com.google.common.base.Preconditions +import java.util.* + + +class WeightRandom(list: List>) { + private val weightMap = TreeMap() + + init { + Preconditions.checkNotNull(list, "list can NOT be null!") + for (pair in list) { + Preconditions.checkArgument(pair.second.toDouble() > 0, "非法权重值:pair=$pair") + val lastWeight: Double = if (weightMap.size == 0) 0.0 else weightMap.lastKey().toDouble() //统一转为double + weightMap[pair.second.toDouble() + lastWeight] = pair.first //权重累加 + } + } + + fun random(): K { + val randomWeight = weightMap.lastKey() * Math.random() + val tailMap: SortedMap = weightMap.tailMap(randomWeight, false) + return weightMap[tailMap.firstKey()]!! + } +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntity.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntity.kt new file mode 100644 index 0000000..12aeeb5 --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntity.kt @@ -0,0 +1,101 @@ +package cc.maxmc.blastingcrisis.packet + +import gnu.trove.TDecorators +import gnu.trove.map.hash.TIntObjectHashMap +import net.minecraft.server.v1_8_R3.* +import org.bukkit.Location +import org.bukkit.entity.Player +import taboolib.common.util.random +import taboolib.library.reflex.Reflex.Companion.getProperty +import taboolib.library.reflex.Reflex.Companion.setProperty +import taboolib.library.reflex.Reflex.Companion.unsafeInstance +import taboolib.module.nms.sendPacket +import java.util.concurrent.atomic.AtomicInteger +import java.util.concurrent.locks.ReentrantReadWriteLock + +abstract class BEntity(var loc: Location, val entityType: Int) { + private val dataWatcher = (DataWatcher::class.java.unsafeInstance() as DataWatcher).apply { + setProperty("b", true) + setProperty("dataValues", TIntObjectHashMap(10, 0.5f, -1)) + setProperty("d", TDecorators.wrap(getProperty>("dataValues")!!)) + setProperty("f", ReentrantReadWriteLock()) + }.apply { + /* + 0x01 On Fire + 0x02 Crouched + 0x08 Sprinting + 0x10 Eating/Drinking/Blocking + 0x20 Invisible + */ + a(0, 0.toByte()) + a(1, 300.toShort()) // Air + a(2, "") // Name Tag + a(3, 0.toByte()) // Always Show Name Tag + a(4, 0.toByte()) // Silent + initEntity() + } + val entityID: Int = getEID() + val viewers = ArrayList() + + abstract fun DataWatcher.initEntity() + + open fun spawnForPlayer(player: Player) { + val packet = PacketPlayOutSpawnEntityLiving() + packet.apply { + setProperty("a", entityID) + setProperty("b", entityType) + setProperty("c", MathHelper.floor(loc.x * 32.0)) + setProperty("d", MathHelper.floor(loc.y * 32.0)) + setProperty("e", MathHelper.floor(loc.z * 32.0)) + setProperty("f", 0.toShort()) + setProperty("g", 0.toShort()) + setProperty("h", 0.toShort()) + setProperty("i", (loc.yaw * 256.0f / 360.0f).toInt().toByte()) + setProperty("j", (loc.pitch * 256.0f / 360.0f).toInt().toByte()) + setProperty("k", (loc.yaw * 256.0f / 360.0f).toInt().toByte()) + } + packet.setProperty("l", dataWatcher) + + viewers.forEach { it.sendPacket(packet) } + } + + open fun addViewer(viewer: Player) { + viewers.add(viewer) + spawnForPlayer(viewer) + } + + open fun removeViewer(viewer: Player) { + viewer.sendPacket(PacketPlayOutEntityDestroy(entityID)) + viewers.remove(viewer) + } + + fun update() { + val packet = PacketPlayOutEntityMetadata(entityID, dataWatcher, true) + viewers.forEach { it.sendPacket(packet) } + } + + fun updateData(toDo: DataWatcher.() -> Unit) { + toDo(dataWatcher) + update() + } + + fun hurtAnimate() { + PacketPlayOutEntityStatus().apply { + setProperty("a", entityID) + setProperty("b", 2.toByte()) + }.let { viewers.forEach { p -> p.sendPacket(it) } } + } + + fun dieAnimate() { + PacketPlayOutEntityStatus().apply { + setProperty("a", entityID) + setProperty("b", 3.toByte()) + }.let { viewers.forEach { p -> p.sendPacket(it) } } + } + + companion object { + private val incrementEntityID = AtomicInteger(197827 + random(0, 549)) + + fun getEID() = incrementEntityID.addAndGet(1) + } +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntityNameTag.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntityNameTag.kt new file mode 100644 index 0000000..9f99b46 --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntityNameTag.kt @@ -0,0 +1,46 @@ +package cc.maxmc.blastingcrisis.packet + +import net.minecraft.server.v1_8_R3.DataWatcher +import net.minecraft.server.v1_8_R3.MathHelper +import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntity +import org.bukkit.Location +import org.bukkit.entity.Player +import taboolib.library.reflex.Reflex.Companion.setProperty +import taboolib.module.nms.sendPacket +import kotlin.experimental.or + +class BEntityNameTag(loc: Location) : BEntity(loc, 78) { + var name: String = "" + set(name) { + updateData { + getWatchableObject(2).a(name) + } + } + + override fun DataWatcher.initEntity() { + getWatchableObject(0).a(getByte(0) or 0x20) + getWatchableObject(2).a("") + getWatchableObject(3).a(1.toByte()) + } + + override fun spawnForPlayer(player: Player) { + val packet = PacketPlayOutSpawnEntity() + packet.apply { + setProperty("a", entityID) + setProperty("b", MathHelper.floor(loc.x * 32.0)) + setProperty("c", MathHelper.floor(loc.y * 32.0)) + setProperty("d", MathHelper.floor(loc.z * 32.0)) + setProperty("e", 0) + setProperty("f", 0) + setProperty("g", 0) + setProperty("h", 0) + setProperty("i", 0) + setProperty("j", entityType) + setProperty("k", 0) + } + + player.sendPacket(packet) + update() + } + +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntityVillager.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntityVillager.kt new file mode 100644 index 0000000..ee1a492 --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/BEntityVillager.kt @@ -0,0 +1,49 @@ +package cc.maxmc.blastingcrisis.packet + +import net.minecraft.server.v1_8_R3.DataWatcher +import net.minecraft.server.v1_8_R3.PacketPlayOutEntityStatus +import org.bukkit.Location +import org.bukkit.entity.Player +import taboolib.library.reflex.Reflex.Companion.setProperty + +class BEntityVillager(loc: Location) : BEntity(loc, 120) { + var name: String + get() = nameTag.name + set(name) { + nameTag.name = name + } + + private val nameTag = BEntityNameTag(loc) + + override fun addViewer(viewer: Player) { + super.addViewer(viewer) + nameTag.addViewer(viewer) + } + + override fun spawnForPlayer(player: Player) { + super.spawnForPlayer(player) + nameTag.spawnForPlayer(player) + } + + override fun removeViewer(viewer: Player) { + super.removeViewer(viewer) + nameTag.removeViewer(viewer) + } + + override fun DataWatcher.initEntity() { + a(6, 1.0f) // Health + a(7, 0) // Potion Effect Color + a(8, 0.toByte()) // Is Potion Effect Ambient + a(9, 0.toByte()) // Number of Arrows in Entity + a(12, 1.toByte()) // Age (0 - child, 1 - adult) + a(15, 0.toByte()) // AI + /* + 0 Farmer + 1 Librarian + 2 Priest + 3 Blacksmith + 4 Butcher + */ + a(16, 0) // Villager Type + } +} \ No newline at end of file diff --git a/src/main/kotlin/cc/maxmc/blastingcrisis/packet/ExternalDataWatcher.kt b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/ExternalDataWatcher.kt new file mode 100644 index 0000000..274ebbc --- /dev/null +++ b/src/main/kotlin/cc/maxmc/blastingcrisis/packet/ExternalDataWatcher.kt @@ -0,0 +1,8 @@ +package cc.maxmc.blastingcrisis.packet + +import net.minecraft.server.v1_8_R3.DataWatcher +import taboolib.library.reflex.Reflex.Companion.invokeMethod +import java.lang.IllegalStateException + +fun DataWatcher.getWatchableObject(id: Int): DataWatcher.WatchableObject = this.invokeMethod("j", id) ?: throw IllegalStateException("Object not exists.") + diff --git a/src/main/resources/lang/zh_CN.yml b/src/main/resources/lang/zh_CN.yml index 08a3d5b..1d64277 100644 --- a/src/main/resources/lang/zh_CN.yml +++ b/src/main/resources/lang/zh_CN.yml @@ -5,4 +5,39 @@ scoreboard_waiting: |- §a| §7等待中... - §aplay.maxmc.cc \ No newline at end of file + §6Play.MaxMC.cc +scoreboard_counting_down: |- + §6Blasting§7Crisis + + §a| §7当前玩家: §a{0}/{1} + + §a| §7游戏还有 §a{2} §7秒开始. + + §6Play.MaxMC.cc +game_countdown_15: + - "§e| §7游戏还有 §e15 §7秒开始." +game_countdown_10: + - type: title + title: "§c10" + - "§e| §7游戏还有 §e10 §7秒开始." +game_countdown_5: + - type: title + title: "§c5" + - "§e| §7游戏还有 §e5 §7秒开始." +game_countdown_3: + - type: title + title: "§c3" + - "§e| §7游戏还有 §e3 §7秒开始." +game_countdown_2: + - type: title + title: "§e2" + - "§e| §7游戏还有 §e2 §7秒开始." +game_countdown_1: + - type: title + title: "§a1" + - "§e| §7游戏还有 §e1 §7秒开始." +game_countdown_reset: + - type: title + text: "§c人数不足" + - "§c| §7由于人数不足, 无法开始游戏." +game_join: "§a| §7玩家 §a{0} §7加入了游戏" \ No newline at end of file diff --git a/src/main/resources/ore-generators/default.yml b/src/main/resources/ore-generators/default.yml new file mode 100644 index 0000000..c565442 --- /dev/null +++ b/src/main/resources/ore-generators/default.yml @@ -0,0 +1,8 @@ +rate: 20 # tick per generate +ores: + # ORE: weight + COAL_ORE: 50 + IRON_ORE: 25 + REDSTONE_ORE: 15 + DIAMOND_ORE: 10 + EMERALD_ORE: 5 \ No newline at end of file