sync code

This commit is contained in:
TONY_All 2022-10-28 16:30:46 +08:00
parent b19752154e
commit 3145fc1586
24 changed files with 278 additions and 80 deletions

View File

@ -22,7 +22,7 @@ dependencies {
implementation(kotlin("stdlib")) implementation(kotlin("stdlib"))
implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4") implementation("org.jetbrains.kotlinx:kotlinx-coroutines-core:1.6.4")
implementation("ink.ptms.core:v10800:10800") implementation("ink.ptms.core:v10800:10800")
implementation("ink.ptms.core:v11200:11200") // implementation("ink.ptms.core:v11200:11200")
} }
taboolib { taboolib {

View File

@ -1,6 +1,8 @@
package cc.maxmc.blastingcrisis package cc.maxmc.blastingcrisis
import cc.maxmc.blastingcrisis.command.DebugCommand import cc.maxmc.blastingcrisis.command.DebugCommand
import cc.maxmc.blastingcrisis.misc.pluginScope
import kotlinx.coroutines.cancel
import taboolib.common.env.RuntimeDependency import taboolib.common.env.RuntimeDependency
import taboolib.common.platform.Plugin import taboolib.common.platform.Plugin
@ -12,4 +14,7 @@ object BlastingCrisis: Plugin() {
DebugCommand.debug("debugcmd") DebugCommand.debug("debugcmd")
} }
override fun onDisable() {
pluginScope.cancel()
}
} }

View File

@ -1,5 +1,6 @@
package cc.maxmc.blastingcrisis.command package cc.maxmc.blastingcrisis.command
import cc.maxmc.blastingcrisis.factory.BEntityFactory
import cc.maxmc.blastingcrisis.game.Game import cc.maxmc.blastingcrisis.game.Game
import cc.maxmc.blastingcrisis.game.GameOreGenerator import cc.maxmc.blastingcrisis.game.GameOreGenerator
import cc.maxmc.blastingcrisis.game.GameState import cc.maxmc.blastingcrisis.game.GameState
@ -35,25 +36,33 @@ object DebugCommand {
"testTeam1", "testTeam1",
ChatColor.AQUA, ChatColor.AQUA,
sender.location, sender.location,
sender.location,
sender.eyeLocation,
homeArea, homeArea,
area1, area1,
area2, area2,
listOf(area3),
area2, area2,
sender.eyeLocation listOf(area3),
) )
val map = GameMap( val map = GameMap(
"test", listOf( "test",
homeArea,
listOf(
team team
), 4 ), 4
) )
game = Game(map) game = Game(map)
game.join(sender) }
literal("join") {
execute<Player> { sender, _, _ ->
game.join(sender)
}
} }
literal("state") { literal("state") {
dynamic { dynamic {
execute<Player> { sender, ctx, argument -> execute<Player> { sender, _, argument ->
if (!GameState.values().map { it.name } if (!GameState.values().map { it.name }
.contains(argument.uppercase())) return@execute sender.sendMessage("NO STATE") .contains(argument.uppercase())) return@execute sender.sendMessage("NO STATE")
val state = GameState.valueOf(argument.uppercase()) val state = GameState.valueOf(argument.uppercase())
@ -67,14 +76,14 @@ object DebugCommand {
} }
literal("timer") { literal("timer") {
execute<Player> { sender, ctx, argument -> execute<Player> { _, _, _ ->
game.timer.beginCountdown() game.timer.beginCountdown()
} }
} }
} }
literal("scoreboard") { literal("scoreboard") {
execute { sender, context, argument -> execute { sender, _, _ ->
game.scoreboard.sendScoreboardPlayer(sender) game.scoreboard.sendScoreboardPlayer(sender)
} }
} }
@ -95,42 +104,42 @@ object DebugCommand {
literal("spawnEntity") { literal("spawnEntity") {
execute<Player> { sender, _, _ -> execute<Player> { sender, _, _ ->
val loc = sender.location val loc = sender.location
villager = BEntityVillager(loc) villager = BEntityFactory.createVillager(loc)
villager.addViewer(sender) villager.addViewer(sender)
} }
} }
// literal("rename") { literal("rename") {
// dynamic { dynamic {
// execute<Player> { _, _, arg -> execute<Player> { _, _, arg ->
// villager.name = arg villager.name = { it.name + ":" + arg }
// } }
// } }
// } }
//
// literal("destroy") { literal("destroy") {
// execute { sender, _, _ -> execute { sender, _, _ ->
// villager.removeViewer(sender) villager.removeViewer(sender)
// } }
// } }
//
// literal("hurt") { literal("hurt") {
// execute<Player> { _, _, _ -> execute<Player> { _, _, _ ->
// villager.hurtAnimate() villager.hurtAnimate()
// } }
// } }
//
// literal("die") { literal("die") {
// execute<Player> { _, _, _ -> execute<Player> { _, _, _ ->
// villager.dieAnimate() villager.dieAnimate()
// } }
// } }
//
// literal("update") { literal("update") {
// execute<Player> { _, _, _ -> execute<Player> { _, _, _ ->
// villager.update() villager.update()
// } }
// } }
literal("genOre") { literal("genOre") {
execute<Player> { sender, _, _ -> execute<Player> { sender, _, _ ->
@ -142,7 +151,7 @@ object DebugCommand {
val job = gen.enable(area) val job = gen.enable(area)
Bukkit.getScheduler().runTaskLater(BukkitPlugin.getInstance(), { Bukkit.getScheduler().runTaskLater(BukkitPlugin.getInstance(), {
job.cancel("Stop by hand") job.cancel("Stop by hand")
} ,60 * 20) }, 60 * 20)
} }
} }
} }

View File

@ -0,0 +1,13 @@
package cc.maxmc.blastingcrisis.configuration
import taboolib.module.configuration.Config
import taboolib.module.configuration.Configuration
object GlobalSettings {
@Config("settings.yml")
lateinit var settings: Configuration
val timeToStart
get() = settings.getInt("time-to-start")
}

View File

@ -3,10 +3,8 @@ package cc.maxmc.blastingcrisis.debug
import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving import net.minecraft.server.v1_8_R3.PacketPlayOutSpawnEntityLiving
import org.bukkit.Bukkit import org.bukkit.Bukkit
import taboolib.common.platform.event.SubscribeEvent import taboolib.common.platform.event.SubscribeEvent
import taboolib.library.reflex.Reflex.Companion.getProperty
import taboolib.module.nms.PacketSendEvent import taboolib.module.nms.PacketSendEvent
import taboolib.platform.BukkitPlugin import taboolib.platform.BukkitPlugin
import taboolib.platform.util.broadcast
object DListener { object DListener {
@SubscribeEvent @SubscribeEvent
@ -16,7 +14,7 @@ object DListener {
// val source = it.packet.source // val source = it.packet.source
if (!it.packet.name.lowercase().contains("entity")) return@runTask if (!it.packet.name.lowercase().contains("entity")) return@runTask
// println(it.packet.name) // println(it.packet.name)
if( it.packet.source !is PacketPlayOutSpawnEntityLiving ) { if (it.packet.source !is PacketPlayOutSpawnEntityLiving) {
return@runTask return@runTask
} }
// it.packet.source.getProperty<Int>("a")!!.broadcast() // it.packet.source.getProperty<Int>("a")!!.broadcast()

View File

@ -0,0 +1,19 @@
package cc.maxmc.blastingcrisis.factory
import cc.maxmc.blastingcrisis.misc.PacketEntityManager
import cc.maxmc.blastingcrisis.misc.debug
import cc.maxmc.blastingcrisis.packet.BEntityVillager
import org.bukkit.Location
object BEntityFactory {
fun createVillager(loc: Location): BEntityVillager {
val entity = BEntityVillager(loc)
PacketEntityManager.register(entity.entityID, entity)
entity.handleInteract {
debug("Interacting with entity: ${entity.entityID}")
debug("type: ${it.type}")
it.vector?.let { vec -> debug("vector: $vec") }
}
return entity
}
}

View File

@ -33,21 +33,29 @@ class Game(
fun leave(player: Player) { fun leave(player: Player) {
if (state == GameState.WAITING || state == GameState.COUNTING_DOWN) { if (state == GameState.WAITING || state == GameState.COUNTING_DOWN) {
players.remove(player) players.remove(player)
player.team?.removePlayer(player)
broadcast { it.sendLang("game_leave", player.name) }
checkStart() checkStart()
} }
val team = val team =
player.team ?: throw IllegalStateException("Player ${player.name} has no team, which shouldn't happen.") player.team ?: throw IllegalStateException("Player ${player.name} has no team, which shouldn't happen.")
team.checkTeamAlive() team.removePlayer(player)
team.players.remove(player)
checkEnd() checkEnd()
} }
fun start() { fun start() {
debug("game ${map.name} started.") debug("game ${map.name} started.")
timer.startTimer()
} }
private fun checkStart() { private fun checkStart() {
if (players.size < map.maxPlayer * 0.5 && state == GameState.COUNTING_DOWN) {
state = GameState.WAITING
timer.resetCountdown()
}
if (players.size > map.maxPlayer * 0.75) { if (players.size > map.maxPlayer * 0.75) {
state = GameState.COUNTING_DOWN state = GameState.COUNTING_DOWN
timer.beginCountdown() timer.beginCountdown()

View File

@ -3,7 +3,7 @@ package cc.maxmc.blastingcrisis.game
import cc.maxmc.blastingcrisis.misc.Area import cc.maxmc.blastingcrisis.misc.Area
import cc.maxmc.blastingcrisis.misc.WeightRandom import cc.maxmc.blastingcrisis.misc.WeightRandom
import cc.maxmc.blastingcrisis.misc.debug import cc.maxmc.blastingcrisis.misc.debug
import cc.maxmc.blastingcrisis.misc.pluginScore import cc.maxmc.blastingcrisis.misc.pluginScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
@ -16,6 +16,7 @@ import taboolib.platform.BukkitPlugin
class GameOreGenerator(config: Configuration) { class GameOreGenerator(config: Configuration) {
private val rate: Int = config.getInt("rate") private val rate: Int = config.getInt("rate")
private val maxTry: Int = config.getInt("try")
private val ores: MutableMap<XMaterial, Int> = HashMap<XMaterial, Int>().also { private val ores: MutableMap<XMaterial, Int> = HashMap<XMaterial, Int>().also {
config.getConfigurationSection("ores")!!.getKeys(false).forEach { key -> config.getConfigurationSection("ores")!!.getKeys(false).forEach { key ->
it += XMaterial.valueOf(key) to (config["ores.$key"]!! as Int) it += XMaterial.valueOf(key) to (config["ores.$key"]!! as Int)
@ -24,7 +25,7 @@ class GameOreGenerator(config: Configuration) {
private val random = WeightRandom(ores.map { it.key to it.value }) private val random = WeightRandom(ores.map { it.key to it.value })
fun enable(area: Area): Job { fun enable(area: Area): Job {
return pluginScore.launch { return pluginScope.launch {
while (true) { while (true) {
generate(area) generate(area)
delay(rate * 50L) delay(rate * 50L)
@ -32,7 +33,8 @@ class GameOreGenerator(config: Configuration) {
} }
} }
private tailrec fun generate(area: Area) { private tailrec fun generate(area: Area, times: Int = 0) {
if (times > maxTry) return
val x = random(area.locMin.blockX, area.locTop.blockX) val x = random(area.locMin.blockX, area.locTop.blockX)
val y = random(area.locMin.blockY, area.locTop.blockY) val y = random(area.locMin.blockY, area.locTop.blockY)
val z = random(area.locMin.blockZ, area.locTop.blockZ) val z = random(area.locMin.blockZ, area.locTop.blockZ)
@ -45,7 +47,7 @@ class GameOreGenerator(config: Configuration) {
debug("generating ${block.type} at ($x, $y, $z)") debug("generating ${block.type} at ($x, $y, $z)")
} }
} else { } else {
return generate(area) return generate(area, times + 1)
} }
} }
} }

View File

@ -6,4 +6,6 @@ enum class GameState {
START, START,
WALL_FALL, WALL_FALL,
FINISH; FINISH;
fun isStarted(): Boolean = this == START || this == WALL_FALL
} }

View File

@ -2,17 +2,35 @@ package cc.maxmc.blastingcrisis.game
import cc.maxmc.blastingcrisis.map.MapTeam import cc.maxmc.blastingcrisis.map.MapTeam
import org.bukkit.entity.Player import org.bukkit.entity.Player
import taboolib.platform.util.sendLang
class GameTeam(val game: Game, val team: MapTeam) { class GameTeam(val game: Game, val teamInfo: MapTeam) {
val players = ArrayList<Player>() val players = ArrayList<Player>()
val villager = TeamVillager(this)
var teamSurvive = true
private set
fun join(player: Player) { fun join(player: Player) {
players += player players += player
if (game.state == GameState.COUNTING_DOWN || game.state == GameState.WAITING) {
player.sendLang("team_join", teamInfo.name)
}
} }
fun checkTeamAlive() {
fun removePlayer(player: Player) {
players -= player
if (game.state.isStarted()) {
checkTeamAlive()
}
}
private fun checkTeamAlive() {
if (players.size != 0) return
game.broadcast {
it.sendLang("team_death", teamInfo.name)
}
teamSurvive = false
} }
} }

View File

@ -1,22 +1,21 @@
package cc.maxmc.blastingcrisis.game package cc.maxmc.blastingcrisis.game
import cc.maxmc.blastingcrisis.misc.pluginScore import cc.maxmc.blastingcrisis.configuration.GlobalSettings
import cc.maxmc.blastingcrisis.misc.pluginScope
import kotlinx.coroutines.Job import kotlinx.coroutines.Job
import kotlinx.coroutines.delay import kotlinx.coroutines.delay
import kotlinx.coroutines.isActive import kotlinx.coroutines.isActive
import kotlinx.coroutines.launch import kotlinx.coroutines.launch
import taboolib.common.platform.function.adaptCommandSender import taboolib.common.platform.function.adaptCommandSender
import taboolib.module.lang.getLocaleFile import taboolib.module.lang.getLocaleFile
import taboolib.platform.util.asLangTextOrNull
import taboolib.platform.util.sendLang import taboolib.platform.util.sendLang
class GameTimer(private val game: Game) { class GameTimer(private val game: Game) {
val timeToStart = 15
lateinit var countdownJob: Job lateinit var countdownJob: Job
var current = timeToStart var current = GlobalSettings.timeToStart
fun beginCountdown() { fun beginCountdown() {
countdownJob = pluginScore.launch { countdownJob = pluginScope.launch {
while (current > 0) { while (current > 0) {
if (!isActive) { if (!isActive) {
return@launch return@launch
@ -43,7 +42,7 @@ class GameTimer(private val game: Game) {
game.broadcast { game.broadcast {
it.sendLang("time_reset") it.sendLang("time_reset")
} }
current = timeToStart current = GlobalSettings.timeToStart
} }
fun startTimer() { fun startTimer() {

View File

@ -0,0 +1,38 @@
package cc.maxmc.blastingcrisis.game
import cc.maxmc.blastingcrisis.factory.BEntityFactory
import org.bukkit.Bukkit
import taboolib.platform.BukkitPlugin
import taboolib.platform.util.asLangText
class TeamVillager(private val team: GameTeam) {
private val packetVillager = BEntityFactory.createVillager(team.teamInfo.villager)
private var health: Int = 150
init {
packetVillager.name = {
if (it.team == team) {
it.asLangText("team_villager_name_internal")
} else {
it.asLangText("team_villager_name_outer")
}
}
}
fun spawn() {
team.game.broadcast(packetVillager::addViewer)
}
fun damage() {
health -= 10
if (health <= 0) {
packetVillager.dieAnimate()
Bukkit.getScheduler().runTaskLater(BukkitPlugin.getInstance(), {
packetVillager.destroy()
}, 20 * 3)
}
packetVillager.hurtAnimate()
}
}

View File

@ -0,0 +1,30 @@
package cc.maxmc.blastingcrisis.listener
import cc.maxmc.blastingcrisis.misc.PacketEntityManager
import net.minecraft.server.v1_8_R3.PacketPlayInUseEntity
import org.bukkit.util.Vector
import taboolib.common.platform.event.SubscribeEvent
import taboolib.library.reflex.Reflex.Companion.getProperty
import taboolib.module.nms.PacketReceiveEvent
object PacketEntityListener {
@SubscribeEvent
fun onClick(e: PacketReceiveEvent) {
if (e.packet.name != "PacketPlayInUseEntity") return
val packet = e.packet.source as PacketPlayInUseEntity
val id = packet.getProperty<Int>("a")!!
val bEntity = PacketEntityManager.getEntity(id) ?: return
val direction = packet.b()
bEntity.onInteract(BEntityInteract(map(packet.a()), direction?.let { Vector(it.a, it.b, it.c) }))
e.isCancelled = true
}
private fun map(action: PacketPlayInUseEntity.EnumEntityUseAction) = EntityUseAction.values()[action.ordinal]
enum class EntityUseAction {
INTERACT, ATTACK, INTERACT_AT;
}
}
data class BEntityInteract(val type: PacketEntityListener.EntityUseAction, val vector: Vector?)

View File

@ -1,6 +1,8 @@
package cc.maxmc.blastingcrisis.map package cc.maxmc.blastingcrisis.map
class GameMap(val name: String, val teams: List<MapTeam>, val maxPlayersPerTeam: Int) { import cc.maxmc.blastingcrisis.misc.Area
class GameMap(val name: String, val area: Area, val teams: List<MapTeam>, val maxPlayersPerTeam: Int) {
val maxPlayer: Int val maxPlayer: Int
get() = maxPlayersPerTeam * teams.size get() = maxPlayersPerTeam * teams.size
} }

View File

@ -8,10 +8,11 @@ data class MapTeam(
val name: String, val name: String,
val color: ChatColor, val color: ChatColor,
val spawn: Location, val spawn: Location,
val villager: Location,
val upgrade: Location,
val home: Area, val home: Area,
val wall: Area, val wall: Area,
val mine: Area, val mine: Area,
val sides: List<Area>,
val teleport: Area, val teleport: Area,
val upgrade: Location, val sides: List<Area>,
) )

View File

@ -53,9 +53,9 @@ class Area(loc1: Location, loc2: Location) : ConfigurationSerializable {
} }
/** /**
* get all locations of the non air blocks in this area * get all locations of the non-air blocks in this area
* *
* @return all locations of the non air blocks in this area * @return all locations of the non-air blocks in this area
*/ */
fun forBlocksWithoutAir(): List<Location> { fun forBlocksWithoutAir(): List<Location> {
return forBlocksInArea().filter { it.block.type != Material.AIR } return forBlocksInArea().filter { it.block.type != Material.AIR }

View File

@ -4,6 +4,6 @@ import kotlinx.coroutines.CoroutineExceptionHandler
import kotlinx.coroutines.CoroutineScope import kotlinx.coroutines.CoroutineScope
import kotlinx.coroutines.SupervisorJob import kotlinx.coroutines.SupervisorJob
val pluginScore = CoroutineScope(SupervisorJob() + CoroutineExceptionHandler { job, exception -> val pluginScope = CoroutineScope(SupervisorJob() + CoroutineExceptionHandler { job, exception ->
IllegalStateException("在执行 Job $job 时出线异常", exception).printStackTrace() IllegalStateException("在执行 Job $job 时出线异常", exception).printStackTrace()
}) })

View File

@ -0,0 +1,14 @@
package cc.maxmc.blastingcrisis.misc
import cc.maxmc.blastingcrisis.packet.BEntity
object PacketEntityManager {
private val entities = HashMap<Int, BEntity>()
fun register(id: Int, entity: BEntity) {
entities[id] = entity
}
fun getEntity(id: Int): BEntity? = entities[id]
}

View File

@ -1,5 +1,6 @@
package cc.maxmc.blastingcrisis.packet package cc.maxmc.blastingcrisis.packet
import cc.maxmc.blastingcrisis.listener.BEntityInteract
import gnu.trove.TDecorators import gnu.trove.TDecorators
import gnu.trove.map.hash.TIntObjectHashMap import gnu.trove.map.hash.TIntObjectHashMap
import net.minecraft.server.v1_8_R3.* import net.minecraft.server.v1_8_R3.*
@ -36,6 +37,7 @@ abstract class BEntity(var loc: Location, val entityType: Int) {
} }
val entityID: Int = getEID() val entityID: Int = getEID()
val viewers = ArrayList<Player>() val viewers = ArrayList<Player>()
val interactHandlers = ArrayList<(BEntityInteract) -> Unit>()
abstract fun DataWatcher.initEntity() abstract fun DataWatcher.initEntity()
@ -69,14 +71,26 @@ abstract class BEntity(var loc: Location, val entityType: Int) {
viewers.remove(viewer) viewers.remove(viewer)
} }
fun update() { fun destroy() {
val packet = PacketPlayOutEntityMetadata(entityID, dataWatcher, true) ArrayList(viewers).forEach { removeViewer(it) }
viewers.forEach { it.sendPacket(packet) }
} }
fun updateData(toDo: DataWatcher.() -> Unit) { fun update() {
toDo(dataWatcher) viewers.forEach {
update() updateFor(it)
}
}
fun updateFor(player: Player) {
val packet = PacketPlayOutEntityMetadata(entityID, dataWatcher, true)
player.sendPacket(packet)
}
fun updateData(toDo: DataWatcher.(Player) -> Unit) {
viewers.forEach {
toDo(dataWatcher, it)
updateFor(it)
}
} }
fun hurtAnimate() { fun hurtAnimate() {
@ -93,6 +107,14 @@ abstract class BEntity(var loc: Location, val entityType: Int) {
}.let { viewers.forEach { p -> p.sendPacket(it) } } }.let { viewers.forEach { p -> p.sendPacket(it) } }
} }
fun handleInteract(handler: (BEntityInteract) -> Unit) {
interactHandlers.add(handler)
}
fun onInteract(interact: BEntityInteract) {
interactHandlers.forEach { it(interact) }
}
companion object { companion object {
private val incrementEntityID = AtomicInteger(197827 + random(0, 549)) private val incrementEntityID = AtomicInteger(197827 + random(0, 549))

View File

@ -10,10 +10,11 @@ import taboolib.module.nms.sendPacket
import kotlin.experimental.or import kotlin.experimental.or
class BEntityNameTag(loc: Location) : BEntity(loc, 78) { class BEntityNameTag(loc: Location) : BEntity(loc, 78) {
var name: String = "" var name: (Player) -> String = { "" }
set(name) { set(name) {
field = name
updateData { updateData {
getWatchableObject(2).a(name) getWatchableObject(2).a(name(it))
} }
} }
@ -40,7 +41,7 @@ class BEntityNameTag(loc: Location) : BEntity(loc, 78) {
} }
player.sendPacket(packet) player.sendPacket(packet)
update() updateFor(player)
} }
} }

View File

@ -7,7 +7,7 @@ import org.bukkit.entity.Player
import taboolib.library.reflex.Reflex.Companion.setProperty import taboolib.library.reflex.Reflex.Companion.setProperty
class BEntityVillager(loc: Location) : BEntity(loc, 120) { class BEntityVillager(loc: Location) : BEntity(loc, 120) {
var name: String var name: (Player) -> String
get() = nameTag.name get() = nameTag.name
set(name) { set(name) {
nameTag.name = name nameTag.name = name

View File

@ -5,4 +5,3 @@ import taboolib.library.reflex.Reflex.Companion.invokeMethod
import java.lang.IllegalStateException import java.lang.IllegalStateException
fun DataWatcher.getWatchableObject(id: Int): DataWatcher.WatchableObject = this.invokeMethod<DataWatcher.WatchableObject>("j", id) ?: throw IllegalStateException("Object not exists.") fun DataWatcher.getWatchableObject(id: Int): DataWatcher.WatchableObject = this.invokeMethod<DataWatcher.WatchableObject>("j", id) ?: throw IllegalStateException("Object not exists.")

View File

@ -1,3 +1,4 @@
## part scoreboard
scoreboard_waiting: |- scoreboard_waiting: |-
§6Blasting§7Crisis §6Blasting§7Crisis
@ -14,6 +15,10 @@ scoreboard_counting_down: |-
§a| §7游戏还有 §a{2} §7秒开始. §a| §7游戏还有 §a{2} §7秒开始.
§6Play.MaxMC.cc §6Play.MaxMC.cc
## end part scoreboard
## part game
game_countdown_15: game_countdown_15:
- "§e| §7游戏还有 §e15 §7秒开始." - "§e| §7游戏还有 §e15 §7秒开始."
game_countdown_10: game_countdown_10:
@ -40,4 +45,13 @@ game_countdown_reset:
- type: title - type: title
text: "§c人数不足" text: "§c人数不足"
- "§c| §7由于人数不足, 无法开始游戏." - "§c| §7由于人数不足, 无法开始游戏."
game_join: "§a| §7玩家 §a{0} §7加入了游戏" game_join: "§a| §7玩家 §a{0} §7加入了游戏."
game_leave: "§e| §7玩家 §e{0} §7离开了游戏."
## end part game
## part team
team_join: "§a| §7你加入了 §a{0}"
team_death: "§e| §7队伍 §e{0} §7已淘汰."
team_villager_name_internal: "本队村民 {0}"
team_villager_name_outer: "{0}队村民 {1}"
## end part team

View File

@ -0,0 +1,4 @@
# Time before game start
# Unit: second
time-to-start: 15