mirror of
https://github.com/SparklyPower/SparklyPaper.git
synced 2025-12-22 16:39:33 +00:00
Update to Paper 1.21.4 (post hard fork™️ edition)
This commit is contained in:
@@ -0,0 +1,93 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import com.mojang.logging.LogUtils
|
||||
import java.time.LocalDateTime
|
||||
import java.time.Month
|
||||
import java.time.ZoneOffset
|
||||
import java.util.concurrent.*
|
||||
|
||||
class HalloweenManager {
|
||||
companion object {
|
||||
private val LOGGER = LogUtils.getLogger()
|
||||
}
|
||||
private var spookySeasonStartEpoch = 0L
|
||||
private var spookySeasonEndEpoch = 0L
|
||||
private var halloweenStartEpoch = 0L
|
||||
private var halloweenEndEpoch = 0L
|
||||
private var executor = Executors.newSingleThreadScheduledExecutor(object: ThreadFactory {
|
||||
override fun newThread(p0: Runnable): Thread {
|
||||
val thread = Thread(p0)
|
||||
thread.name = "halloween-timer-updater"
|
||||
thread.priority = 1 // Minimum priority
|
||||
return thread
|
||||
}
|
||||
})
|
||||
private var latch = CountDownLatch(1)
|
||||
|
||||
fun startHalloweenEpochTask() {
|
||||
var isFirst = true
|
||||
executor.scheduleAtFixedRate({
|
||||
updateEpoch()
|
||||
if (isFirst)
|
||||
latch.countDown()
|
||||
isFirst = false
|
||||
}, 0L, 90L, TimeUnit.DAYS) // Every 90 days
|
||||
}
|
||||
|
||||
fun waitUntilEpochHasBeenUpdated() {
|
||||
latch.await()
|
||||
}
|
||||
|
||||
fun updateEpoch() {
|
||||
LOGGER.info("Updating Spooky Season and Halloween Time")
|
||||
this.spookySeasonStartEpoch = getEpochMillisAtDate(20, Month.OCTOBER, false)
|
||||
this.spookySeasonEndEpoch = getEpochMillisAtDate(3, Month.NOVEMBER, true)
|
||||
this.halloweenStartEpoch = getEpochMillisAtDate(31, Month.OCTOBER, false)
|
||||
this.halloweenEndEpoch = getEpochMillisAtDate(31, Month.OCTOBER, true)
|
||||
LOGGER.info("Updated Spooky Season and Halloween Time!")
|
||||
}
|
||||
|
||||
fun isSpookySeason() = System.currentTimeMillis() in spookySeasonStartEpoch until spookySeasonEndEpoch
|
||||
fun isHalloween() = System.currentTimeMillis() in halloweenStartEpoch until halloweenEndEpoch
|
||||
|
||||
private fun getEpochMillisAtDate(dayOfMonth: Int, month: Month, isEnd: Boolean): Long {
|
||||
// Get the current year
|
||||
val currentYear = LocalDateTime.now().year
|
||||
|
||||
// Define the target date (20/10/CurrentYear at midnight)
|
||||
val targetDate = LocalDateTime.of(
|
||||
currentYear,
|
||||
month,
|
||||
dayOfMonth,
|
||||
if (isEnd)
|
||||
23
|
||||
else
|
||||
0,
|
||||
if (isEnd)
|
||||
59
|
||||
else
|
||||
0,
|
||||
if (isEnd)
|
||||
59
|
||||
else
|
||||
0,
|
||||
if (isEnd)
|
||||
999_999_999
|
||||
else
|
||||
0,
|
||||
)
|
||||
|
||||
// Check if the target date is in the past
|
||||
val now = LocalDateTime.now()
|
||||
val adjustedDate = if (now.isAfter(targetDate)) {
|
||||
// If in the past, adjust to the same date in the next year
|
||||
targetDate.plusYears(1)
|
||||
} else {
|
||||
// If in the future or today, use the original target date
|
||||
targetDate
|
||||
}
|
||||
|
||||
// Convert the adjusted date to epoch time in milliseconds
|
||||
return adjustedDate.atZone(ZoneOffset.systemDefault()).toInstant().toEpochMilli()
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,95 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import ca.spottedleaf.dataconverter.types.MapType
|
||||
|
||||
object LegacyNBTRemapper {
|
||||
/**
|
||||
* Remaps hacky direct NBT storage used in SparklyPower to proper PersistentDataContainer data
|
||||
*/
|
||||
fun remap(tag: MapType<String>) {
|
||||
val perfectDreamsMap = tag.getMap<String>("PerfectDreams")
|
||||
|
||||
if (perfectDreamsMap != null) {
|
||||
val publicBukkitValuesMap = tag.getOrCreateMap<String>("PublicBukkitValues")
|
||||
|
||||
// The "setBoolean" functions do set bytes behind the scenes, just like how we do the things in SparklyPower
|
||||
perfectDreamsMap.getStringAndRemove("isJetpack")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_jetpack", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("disallowCrafting")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:disallow_crafting", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("poop")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_poop", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("renamedBySeuZe")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_renamed_by_seu_ze", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isMonsterPickaxe")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_monster_tool", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("itemOwner")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:item_owner", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("DreamFusca")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:fusca_info", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isFusca")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_fusca", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("fancyLeatherArmor")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_fancy_leather_armor", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("caixaSecretaLevel")?.let {
|
||||
publicBukkitValuesMap.setInt("sparklypower:caixa_secreta_level", it.toInt())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("caixaSecretaWorld")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:caixa_secreta_world", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isMoveSpawners")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_move_spawners_tool", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("spawnerType")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:spawner_type", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("isMochila")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_mochila", it.toBoolean())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("mochilaId")?.let {
|
||||
publicBukkitValuesMap.setLong("sparklypower:mochila_id", it.toLong())
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("customMapOwner")?.let {
|
||||
publicBukkitValuesMap.setString("sparklypower:map_custom_owner", it)
|
||||
}
|
||||
|
||||
perfectDreamsMap.getStringAndRemove("quickTeleport")?.let {
|
||||
publicBukkitValuesMap.setBoolean("sparklypower:is_quick_resources_teleport", it.toBoolean())
|
||||
}
|
||||
|
||||
// If it is empty, then it means that we have migrated everything and we can remove the old PerfectDreams tag, yay!
|
||||
if (perfectDreamsMap.isEmpty)
|
||||
tag.remove("PerfectDreams")
|
||||
}
|
||||
}
|
||||
|
||||
private fun MapType<String>.getStringAndRemove(key: String): String? {
|
||||
val v = getString(key)
|
||||
remove(key)
|
||||
return v
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import ca.spottedleaf.moonrise.common.util.TickThread
|
||||
import java.util.concurrent.ThreadFactory
|
||||
|
||||
class ServerLevelTickExecutorThreadFactory(private val worldName: String) : ThreadFactory {
|
||||
override fun newThread(p0: Runnable): Thread {
|
||||
val tickThread = TickThread.ServerLevelTickThread(p0, "serverlevel-tick-worker [$worldName]")
|
||||
|
||||
if (tickThread.isDaemon) {
|
||||
tickThread.isDaemon = false
|
||||
}
|
||||
|
||||
if (tickThread.priority != 5) {
|
||||
tickThread.priority = 5
|
||||
}
|
||||
|
||||
return tickThread
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package net.sparklypower.sparklypaper
|
||||
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.sparklypower.sparklypaper.commands.SparklyPaperCommand
|
||||
import org.bukkit.command.Command
|
||||
import org.checkerframework.checker.nullness.qual.NonNull
|
||||
import org.checkerframework.framework.qual.DefaultQualifier
|
||||
|
||||
@DefaultQualifier(NonNull::class)
|
||||
object SparklyPaperCommands {
|
||||
private val COMMANDS = mapOf(
|
||||
"sparklypaper" to SparklyPaperCommand("sparklypaper")
|
||||
)
|
||||
|
||||
fun registerCommands(server: MinecraftServer) {
|
||||
COMMANDS.forEach { (s: String, command: Command) ->
|
||||
server.server.commandMap.register(
|
||||
s, "SparklyPaper", command
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
package net.sparklypower.sparklypaper.configs
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperConfig(
|
||||
@SerialName("config-version")
|
||||
override val configVersion: Int,
|
||||
@SerialName("parallel-world-ticking")
|
||||
val parallelWorldTicking: ParallelWorldTicking,
|
||||
@SerialName("world-settings")
|
||||
val worldSettings: Map<String, SparklyPaperWorldConfig>
|
||||
) : UpgradeableConfig {
|
||||
override fun isNewest() = true
|
||||
|
||||
override fun upgradeToNext() = error("This config is already the newest version!")
|
||||
|
||||
@Serializable
|
||||
class ParallelWorldTicking(
|
||||
val threads: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperWorldConfig(
|
||||
@SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
||||
val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
||||
@SerialName("blazingly-simple-farm-checks")
|
||||
val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks,
|
||||
@SerialName("ticks-per")
|
||||
val ticksPer: TicksPer,
|
||||
) {
|
||||
@Serializable
|
||||
data class BlazinglySimpleFarmChecks(
|
||||
val enabled: Boolean,
|
||||
@SerialName("default-growth-speed")
|
||||
val defaultGrowthSpeed: Float,
|
||||
@SerialName("moist-growth-speed")
|
||||
val moistGrowthSpeed: Float,
|
||||
@SerialName("skip-middle-aging-stages-for-crops")
|
||||
val skipMiddleAgingStagesForCrops: Boolean
|
||||
)
|
||||
|
||||
@Serializable
|
||||
data class TicksPer(
|
||||
@SerialName("hopper-cooldown-when-target-container-is-full")
|
||||
val hopperCooldownWhenTargetContainerIsFull: Int
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,94 @@
|
||||
package net.sparklypower.sparklypaper.configs
|
||||
|
||||
import com.charleskorn.kaml.*
|
||||
import com.google.common.base.Throwables
|
||||
import kotlinx.serialization.SerializationException
|
||||
import kotlinx.serialization.decodeFromString
|
||||
import kotlinx.serialization.encodeToString
|
||||
import net.sparklypower.sparklypaper.configs.previous.SparklyPaperConfigV1
|
||||
import org.bukkit.Bukkit
|
||||
import java.io.File
|
||||
import java.util.logging.Level
|
||||
|
||||
object SparklyPaperConfigUtils {
|
||||
private const val CURRENT_CONFIG_VERSION = 2
|
||||
val yaml = Yaml(
|
||||
configuration = YamlConfiguration(
|
||||
strictMode = false
|
||||
)
|
||||
)
|
||||
val deserializationStrategiesForVersions = mapOf(
|
||||
1 to SparklyPaperConfigV1.serializer(),
|
||||
CURRENT_CONFIG_VERSION to SparklyPaperConfig.serializer()
|
||||
)
|
||||
|
||||
lateinit var config: SparklyPaperConfig
|
||||
val logContainerCreationStacktraces = java.lang.Boolean.getBoolean("sparklypaper.logContainerCreationStacktraces")
|
||||
|
||||
fun init(configFile: File) {
|
||||
// Write default config if the file doesn't exist
|
||||
if (!configFile.exists()) {
|
||||
configFile.writeText(
|
||||
yaml.encodeToString(
|
||||
SparklyPaperConfig(
|
||||
CURRENT_CONFIG_VERSION,
|
||||
SparklyPaperConfig.ParallelWorldTicking(
|
||||
threads = 8
|
||||
),
|
||||
mapOf(
|
||||
"default" to SparklyPaperConfig.SparklyPaperWorldConfig(
|
||||
skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer = true,
|
||||
blazinglySimpleFarmChecks = SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
||||
enabled = false,
|
||||
defaultGrowthSpeed = 1.0f,
|
||||
moistGrowthSpeed = 5.0f,
|
||||
skipMiddleAgingStagesForCrops = true
|
||||
),
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
||||
hopperCooldownWhenTargetContainerIsFull = 0
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
val loadedConfig = try {
|
||||
// Read the version file from the config before attempting to parse
|
||||
val yamlNode = yaml.parseToYamlNode(configFile.readText())
|
||||
var configVersion = yamlNode.yamlMap.getScalar("config-version")?.toInt() ?: 1 // The first config version didn't have the "config-version" key
|
||||
|
||||
if (configVersion != CURRENT_CONFIG_VERSION) {
|
||||
var upgradedVersion: UpgradeableConfig? = null
|
||||
|
||||
while (configVersion != CURRENT_CONFIG_VERSION) {
|
||||
Bukkit.getLogger().log(Level.INFO, "Attempting to upgrade SparklyPaper Config from version $configVersion to the next version...")
|
||||
|
||||
val upgradeableConfig = yaml.decodeFromYamlNode(deserializationStrategiesForVersions[configVersion]!!, yamlNode)
|
||||
if (!upgradeableConfig.isNewest()) {
|
||||
upgradedVersion = upgradeableConfig.upgradeToNext()
|
||||
|
||||
Bukkit.getLogger().log(Level.INFO, "Upgraded SparklyPaper Config from version $configVersion to ${upgradedVersion.configVersion}")
|
||||
configVersion = upgradedVersion.configVersion
|
||||
}
|
||||
}
|
||||
|
||||
upgradedVersion as SparklyPaperConfig
|
||||
} else {
|
||||
yaml.decodeFromYamlNode(SparklyPaperConfig.serializer(), yamlNode)
|
||||
}
|
||||
} catch (e: SerializationException) {
|
||||
Bukkit.getLogger().log(Level.SEVERE, "Could not load sparklypaper.yml, please correct your syntax errors", e)
|
||||
throw Throwables.propagate(e)
|
||||
}
|
||||
// Rewrite the config file to remove old fields and stuff
|
||||
// TODO: Maybe handle this in another way? This feels kinda bad
|
||||
configFile.writeText(yaml.encodeToString(loadedConfig))
|
||||
config = loadedConfig
|
||||
}
|
||||
|
||||
fun getWorldSettings(levelName: String): SparklyPaperConfig.SparklyPaperWorldConfig {
|
||||
return config.worldSettings[levelName] ?: config.worldSettings["default"] ?: error("Missing default world-settings in sparklypaper.yml!")
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package net.sparklypower.sparklypaper.configs
|
||||
|
||||
interface UpgradeableConfig {
|
||||
abstract val configVersion: Int
|
||||
fun isNewest(): Boolean
|
||||
fun upgradeToNext(): UpgradeableConfig
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
package net.sparklypower.sparklypaper.configs.previous
|
||||
|
||||
import kotlinx.serialization.SerialName
|
||||
import kotlinx.serialization.Serializable
|
||||
import net.sparklypower.sparklypaper.configs.SparklyPaperConfig
|
||||
import net.sparklypower.sparklypaper.configs.UpgradeableConfig
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperConfigV1(
|
||||
@SerialName("parallel-world-ticking")
|
||||
val parallelWorldTicking: ParallelWorldTicking,
|
||||
@SerialName("world-settings")
|
||||
val worldSettings: Map<String, SparklyPaperWorldConfig>
|
||||
) : UpgradeableConfig {
|
||||
override val configVersion = 1
|
||||
|
||||
override fun isNewest() = false
|
||||
|
||||
override fun upgradeToNext(): UpgradeableConfig {
|
||||
return SparklyPaperConfig(
|
||||
2,
|
||||
SparklyPaperConfig.ParallelWorldTicking(
|
||||
this.parallelWorldTicking.threads
|
||||
),
|
||||
worldSettings.mapValues {
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig(
|
||||
it.value.skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer,
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig.BlazinglySimpleFarmChecks(
|
||||
it.value.blazinglySimpleFarmChecks.enabled,
|
||||
it.value.blazinglySimpleFarmChecks.defaultGrowthSpeed,
|
||||
it.value.blazinglySimpleFarmChecks.moistGrowthSpeed,
|
||||
it.value.blazinglySimpleFarmChecks.skipMiddleAgingStagesForCrops,
|
||||
),
|
||||
SparklyPaperConfig.SparklyPaperWorldConfig.TicksPer(
|
||||
0
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
@Serializable
|
||||
class ParallelWorldTicking(
|
||||
val threads: Int
|
||||
)
|
||||
|
||||
@Serializable
|
||||
class SparklyPaperWorldConfig(
|
||||
@SerialName("skip-map-item-data-updates-if-map-does-not-have-craftmaprenderer")
|
||||
val skipMapItemDataUpdatesIfMapDoesNotHaveCraftMapRenderer: Boolean,
|
||||
@SerialName("blazingly-simple-farm-checks")
|
||||
val blazinglySimpleFarmChecks: BlazinglySimpleFarmChecks
|
||||
) {
|
||||
@Serializable
|
||||
data class BlazinglySimpleFarmChecks(
|
||||
val enabled: Boolean,
|
||||
@SerialName("default-growth-speed")
|
||||
val defaultGrowthSpeed: Float,
|
||||
@SerialName("moist-growth-speed")
|
||||
val moistGrowthSpeed: Float,
|
||||
@SerialName("skip-middle-aging-stages-for-crops")
|
||||
val skipMiddleAgingStagesForCrops: Boolean
|
||||
)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user