Port to 1.20 and update CI/CD
parent
247159970c
commit
8dca36983c
|
@ -0,0 +1,33 @@
|
||||||
|
name: "Build and publish releases"
|
||||||
|
|
||||||
|
on:
|
||||||
|
push:
|
||||||
|
tag: "v*"
|
||||||
|
|
||||||
|
jobs:
|
||||||
|
release:
|
||||||
|
if: github.repository_owner == 'mc'
|
||||||
|
runs-on: ubuntu-latest
|
||||||
|
steps:
|
||||||
|
- uses: actions/checkout@v3
|
||||||
|
- name: Set up JDK 17
|
||||||
|
uses: github.com/actions/setup-java@v3
|
||||||
|
with:
|
||||||
|
java-version: '17'
|
||||||
|
distribution: 'temurin'
|
||||||
|
|
||||||
|
- name: "build"
|
||||||
|
run: |
|
||||||
|
./gradlew build
|
||||||
|
|
||||||
|
- name: "move releases"
|
||||||
|
run: |
|
||||||
|
mkdir release
|
||||||
|
mv build/libs/*.jar release
|
||||||
|
|
||||||
|
- name: "publish release"
|
||||||
|
uses: https://code.forgejo.org/actions/forgejo-release@v1
|
||||||
|
with:
|
||||||
|
direction: upload
|
||||||
|
release-dir: release
|
||||||
|
token: ${{ secrets.TOKEN }}
|
|
@ -1,14 +1,14 @@
|
||||||
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
kotlin("jvm") version "1.7.0-RC"
|
kotlin("jvm") version "1.8.22"
|
||||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
id("com.github.johnrengelman.shadow") version "8.1.1"
|
||||||
id("xyz.jpenilla.run-paper") version "1.0.6" // Adds runServer and runMojangMappedServer tasks for testing
|
id("xyz.jpenilla.run-paper") version "2.1.0" // Adds runServer and runMojangMappedServer tasks for testing
|
||||||
id("io.papermc.paperweight.userdev") version "1.3.7"
|
id("io.papermc.paperweight.userdev") version "1.5.5"
|
||||||
}
|
}
|
||||||
|
|
||||||
group = "nl.kallestruik"
|
group = "nl.kallestruik"
|
||||||
version = "1.0"
|
version = "1.1"
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
|
@ -17,16 +17,16 @@ repositories {
|
||||||
maven("https://papermc.io/repo/repository/maven-public/")
|
maven("https://papermc.io/repo/repository/maven-public/")
|
||||||
maven("https://repo.aikar.co/content/groups/aikar/")
|
maven("https://repo.aikar.co/content/groups/aikar/")
|
||||||
maven("https://repo.dmulloy2.net/repository/public/")
|
maven("https://repo.dmulloy2.net/repository/public/")
|
||||||
|
maven("https://git.kallestruik.nl/api/packages/mc/maven/")
|
||||||
}
|
}
|
||||||
|
|
||||||
dependencies {
|
dependencies {
|
||||||
paperDevBundle("1.19-R0.1-SNAPSHOT")
|
paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT")
|
||||||
|
|
||||||
implementation("co.aikar:acf-paper:0.5.0-SNAPSHOT")
|
implementation("co.aikar:acf-paper:0.5.1-SNAPSHOT")
|
||||||
compileOnly("com.comphenix.protocol:ProtocolLib:4.6.0")
|
compileOnly("com.comphenix.protocol:ProtocolLib:5.0.0")
|
||||||
compileOnly(kotlin("stdlib-jdk8"))
|
|
||||||
|
|
||||||
compileOnly("nl.kallestruik:DLib:1.4.4")
|
compileOnly("nl.kallestruik:DLib:1.5.1")
|
||||||
|
|
||||||
testImplementation(kotlin("test-junit5"))
|
testImplementation(kotlin("test-junit5"))
|
||||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
|
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
|
||||||
|
@ -58,7 +58,7 @@ tasks {
|
||||||
kotlinOptions.javaParameters = true
|
kotlinOptions.javaParameters = true
|
||||||
}
|
}
|
||||||
withType<KotlinCompile> {
|
withType<KotlinCompile> {
|
||||||
kotlinOptions.jvmTarget = "16"
|
kotlinOptions.jvmTarget = "17"
|
||||||
}
|
}
|
||||||
|
|
||||||
processResources {
|
processResources {
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
distributionBase=GRADLE_USER_HOME
|
distributionBase=GRADLE_USER_HOME
|
||||||
distributionPath=wrapper/dists
|
distributionPath=wrapper/dists
|
||||||
distributionUrl=https\://services.gradle.org/distributions/gradle-7.3-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
zipStorePath=wrapper/dists
|
zipStorePath=wrapper/dists
|
||||||
|
|
|
@ -1,25 +0,0 @@
|
||||||
package nl.kallestruik.dtweaks
|
|
||||||
|
|
||||||
import org.bukkit.Material
|
|
||||||
|
|
||||||
enum class BundleColor(
|
|
||||||
val modelData: Int,
|
|
||||||
val dye: Material,
|
|
||||||
) {
|
|
||||||
BLACK(0, Material.BLACK_DYE),
|
|
||||||
BLUE(1, Material.BLUE_DYE),
|
|
||||||
BROWN(2, Material.BROWN_DYE),
|
|
||||||
CYAN(3, Material.CYAN_DYE),
|
|
||||||
GRAY(4, Material.GRAY_DYE),
|
|
||||||
GREEN(5, Material.GREEN_DYE),
|
|
||||||
LIGHT_BLUE(6, Material.LIGHT_BLUE_DYE),
|
|
||||||
LIGHT_GRAY(7, Material.LIGHT_GRAY_DYE),
|
|
||||||
LIME(8, Material.LIME_DYE),
|
|
||||||
MAGENTA(9, Material.MAGENTA_DYE),
|
|
||||||
ORANGE(10, Material.ORANGE_DYE),
|
|
||||||
PINK(11, Material.PINK_DYE),
|
|
||||||
PURPLE(12, Material.PURPLE_DYE),
|
|
||||||
RED(13, Material.RED_DYE),
|
|
||||||
WHITE(14, Material.WHITE_DYE),
|
|
||||||
YELLOW(15, Material.YELLOW_DYE)
|
|
||||||
}
|
|
|
@ -1,15 +0,0 @@
|
||||||
package nl.kallestruik.dtweaks
|
|
||||||
|
|
||||||
import org.bukkit.Material
|
|
||||||
|
|
||||||
enum class BundleVariant(
|
|
||||||
val modelDataStart: Int,
|
|
||||||
val maxWeight: Int,
|
|
||||||
val material: Material?,
|
|
||||||
) {
|
|
||||||
NORMAL(0, 1 * 64, null),
|
|
||||||
IRON(100, 2 * 64, Material.IRON_INGOT),
|
|
||||||
GOLD(200, 4 * 64, Material.GOLD_INGOT),
|
|
||||||
DIAMOND(300, 6 * 64, Material.DIAMOND),
|
|
||||||
NETHERITE(400, 8 * 64, Material.NETHERITE_INGOT)
|
|
||||||
}
|
|
|
@ -5,7 +5,6 @@ import co.aikar.commands.PaperCommandManager
|
||||||
import nl.kallestruik.dlib.DUtil
|
import nl.kallestruik.dlib.DUtil
|
||||||
import nl.kallestruik.dlib.MathHelper
|
import nl.kallestruik.dlib.MathHelper
|
||||||
import nl.kallestruik.dlib.ReflectionUtil
|
import nl.kallestruik.dlib.ReflectionUtil
|
||||||
import nl.kallestruik.dtweaks.commands.CommandBundle
|
|
||||||
import nl.kallestruik.dtweaks.commands.CommandPlayer
|
import nl.kallestruik.dtweaks.commands.CommandPlayer
|
||||||
import nl.kallestruik.dtweaks.commands.CommandSpawnzones
|
import nl.kallestruik.dtweaks.commands.CommandSpawnzones
|
||||||
import nl.kallestruik.dtweaks.commands.CommandToggletrample
|
import nl.kallestruik.dtweaks.commands.CommandToggletrample
|
||||||
|
@ -25,6 +24,7 @@ import java.util.*
|
||||||
|
|
||||||
class DTweaks: JavaPlugin() {
|
class DTweaks: JavaPlugin() {
|
||||||
companion object {
|
companion object {
|
||||||
|
lateinit var plugin: DTweaks
|
||||||
private lateinit var random: Random
|
private lateinit var random: Random
|
||||||
private lateinit var tweakManager: TweakManager
|
private lateinit var tweakManager: TweakManager
|
||||||
private lateinit var util: DUtil
|
private lateinit var util: DUtil
|
||||||
|
@ -34,13 +34,13 @@ class DTweaks: JavaPlugin() {
|
||||||
private lateinit var commandManager: PaperCommandManager
|
private lateinit var commandManager: PaperCommandManager
|
||||||
private lateinit var fakePlayerManager: FakePlayerManager
|
private lateinit var fakePlayerManager: FakePlayerManager
|
||||||
private lateinit var noSpawnZoneManager: NoSpawnZoneManager
|
private lateinit var noSpawnZoneManager: NoSpawnZoneManager
|
||||||
// private lateinit var pocketDimensionManager: PocketDimensionManager
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun onEnable() {
|
override fun onEnable() {
|
||||||
/*
|
/*
|
||||||
* Initialize stuff
|
* Initialize stuff
|
||||||
*/
|
*/
|
||||||
|
plugin = this
|
||||||
random = Random()
|
random = Random()
|
||||||
tweakManager = TweakManager(this)
|
tweakManager = TweakManager(this)
|
||||||
util = DUtil(random)
|
util = DUtil(random)
|
||||||
|
@ -50,23 +50,18 @@ class DTweaks: JavaPlugin() {
|
||||||
commandManager = PaperCommandManager(this)
|
commandManager = PaperCommandManager(this)
|
||||||
fakePlayerManager = FakePlayerManager(this)
|
fakePlayerManager = FakePlayerManager(this)
|
||||||
noSpawnZoneManager = NoSpawnZoneManager()
|
noSpawnZoneManager = NoSpawnZoneManager()
|
||||||
// pocketDimensionManager = PocketDimensionManager(mathHelper)
|
|
||||||
|
|
||||||
// Enable brigadier support on ACF
|
// Enable brigadier support on ACF
|
||||||
commandManager.enableUnstableAPI("brigadier")
|
commandManager.enableUnstableAPI("brigadier")
|
||||||
|
|
||||||
registerCommandConditions()
|
registerCommandConditions()
|
||||||
|
|
||||||
val betterBundles = BetterBundles(this)
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Commands
|
* Commands
|
||||||
*/
|
*/
|
||||||
// commandManager.registerCommand(CommandMobcaps(reflectionUtil))
|
// commandManager.registerCommand(CommandMobcaps(reflectionUtil))
|
||||||
commandManager.registerCommand(CommandPlayer(fakePlayerManager))
|
commandManager.registerCommand(CommandPlayer(fakePlayerManager))
|
||||||
// commandManager.registerCommand(CommandPocketdim(pocketDimensionManager))
|
|
||||||
commandManager.registerCommand(CommandToggletrample(trampleManager))
|
commandManager.registerCommand(CommandToggletrample(trampleManager))
|
||||||
commandManager.registerCommand(CommandBundle(betterBundles))
|
|
||||||
commandManager.registerCommand(CommandSpawnzones(noSpawnZoneManager))
|
commandManager.registerCommand(CommandSpawnzones(noSpawnZoneManager))
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -75,7 +70,6 @@ class DTweaks: JavaPlugin() {
|
||||||
tweakManager.loadFromFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
|
tweakManager.loadFromFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
|
||||||
trampleManager.loadFromFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
|
trampleManager.loadFromFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
|
||||||
noSpawnZoneManager.loadFromFile(File(dataFolder, Const.NO_SPAWN_ZONE_FILE_NAME))
|
noSpawnZoneManager.loadFromFile(File(dataFolder, Const.NO_SPAWN_ZONE_FILE_NAME))
|
||||||
// pocketDimensionManager.loadData()
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Crafting tweaks
|
* Crafting tweaks
|
||||||
|
@ -113,12 +107,8 @@ class DTweaks: JavaPlugin() {
|
||||||
*/
|
*/
|
||||||
tweakManager.registerTweak(ArmorStandArmorSwapping(this))
|
tweakManager.registerTweak(ArmorStandArmorSwapping(this))
|
||||||
// tweakManager.registerTweak(CarpetBlockPlacingProtocol(this, mathHelper))
|
// tweakManager.registerTweak(CarpetBlockPlacingProtocol(this, mathHelper))
|
||||||
tweakManager.registerTweak(betterBundles)
|
|
||||||
// tweakManager.registerTweak(DyeableNetherite(this))
|
|
||||||
tweakManager.registerTweak(FakePlayers(fakePlayerManager, this))
|
tweakManager.registerTweak(FakePlayers(fakePlayerManager, this))
|
||||||
tweakManager.registerTweak(Hammers(this))
|
|
||||||
tweakManager.registerTweak(NoMelting(this))
|
tweakManager.registerTweak(NoMelting(this))
|
||||||
// tweakManager.registerTweak(SpaceTimePockets(this, pocketDimensionManager))
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* Mob Tweaks
|
* Mob Tweaks
|
||||||
|
@ -126,7 +116,6 @@ class DTweaks: JavaPlugin() {
|
||||||
tweakManager.registerTweak(NoCreeperGrief(this))
|
tweakManager.registerTweak(NoCreeperGrief(this))
|
||||||
tweakManager.registerTweak(NoDoorBreaking(this))
|
tweakManager.registerTweak(NoDoorBreaking(this))
|
||||||
tweakManager.registerTweak(NoEndermanGrief(this))
|
tweakManager.registerTweak(NoEndermanGrief(this))
|
||||||
tweakManager.registerTweak(VillagerInfo(this))
|
|
||||||
tweakManager.registerTweak(NoSpawnZones(this, noSpawnZoneManager))
|
tweakManager.registerTweak(NoSpawnZones(this, noSpawnZoneManager))
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -137,7 +126,6 @@ class DTweaks: JavaPlugin() {
|
||||||
tweakManager.saveToFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
|
tweakManager.saveToFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
|
||||||
trampleManager.saveToFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
|
trampleManager.saveToFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
|
||||||
noSpawnZoneManager.saveToFile()
|
noSpawnZoneManager.saveToFile()
|
||||||
// pocketDimensionManager.saveData()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun registerCommandConditions() {
|
private fun registerCommandConditions() {
|
||||||
|
|
|
@ -1,40 +0,0 @@
|
||||||
package nl.kallestruik.dtweaks.commands
|
|
||||||
|
|
||||||
import co.aikar.commands.BaseCommand
|
|
||||||
import co.aikar.commands.annotation.*
|
|
||||||
import nl.kallestruik.dtweaks.BundleColor
|
|
||||||
import nl.kallestruik.dtweaks.BundleVariant
|
|
||||||
import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.BetterBundles
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.bukkit.persistence.PersistentDataType
|
|
||||||
|
|
||||||
@CommandAlias("bundle")
|
|
||||||
@Conditions("tweakEnabled:tweak=BetterBundles")
|
|
||||||
class CommandBundle(
|
|
||||||
private val betterBundles: BetterBundles,
|
|
||||||
): BaseCommand() {
|
|
||||||
@Subcommand("variant")
|
|
||||||
fun onVariant(sender: Player, variant: BundleVariant) {
|
|
||||||
val bundle = sender.inventory.itemInMainHand
|
|
||||||
if (bundle.type != Material.BUNDLE)
|
|
||||||
return
|
|
||||||
|
|
||||||
val bundleMeta = bundle.itemMeta
|
|
||||||
bundleMeta.persistentDataContainer.set(betterBundles.VARIANT_KEY, PersistentDataType.STRING, variant.toString())
|
|
||||||
bundle.itemMeta = bundleMeta
|
|
||||||
betterBundles.updateBundle(bundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
@Subcommand("color")
|
|
||||||
fun onVariant(sender: Player, color: BundleColor) {
|
|
||||||
val bundle = sender.inventory.itemInMainHand
|
|
||||||
if (bundle.type != Material.BUNDLE)
|
|
||||||
return
|
|
||||||
|
|
||||||
val bundleMeta = bundle.itemMeta
|
|
||||||
bundleMeta.persistentDataContainer.set(betterBundles.COLOR_KEY, PersistentDataType.STRING, color.toString())
|
|
||||||
bundle.itemMeta = bundleMeta
|
|
||||||
betterBundles.updateBundle(bundle)
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,25 +0,0 @@
|
||||||
//package nl.kallestruik.dtweaks.commands
|
|
||||||
//
|
|
||||||
//import co.aikar.commands.BaseCommand
|
|
||||||
//import co.aikar.commands.annotation.CommandAlias
|
|
||||||
//import co.aikar.commands.annotation.Conditions
|
|
||||||
//import co.aikar.commands.annotation.Subcommand
|
|
||||||
//import nl.kallestruik.dtweaks.managers.PocketDimensionManager
|
|
||||||
//import org.bukkit.entity.Player
|
|
||||||
//
|
|
||||||
//@CommandAlias("pocketdim")
|
|
||||||
//@Conditions("tweakEnabled:tweak=SpaceTimePockets")
|
|
||||||
//class CommandPocketdim(
|
|
||||||
// private val pocketDimensionManager: PocketDimensionManager
|
|
||||||
//): BaseCommand() {
|
|
||||||
//
|
|
||||||
// @Subcommand("create")
|
|
||||||
// fun onCreate(sender: Player) {
|
|
||||||
// pocketDimensionManager.createPocketForPlayer(sender)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @Subcommand("tp")
|
|
||||||
// fun onTp(sender: Player) {
|
|
||||||
// pocketDimensionManager.teleportPlayerIntoPocket(sender, sender.uniqueId)
|
|
||||||
// }
|
|
||||||
//}
|
|
|
@ -1,5 +1,8 @@
|
||||||
package nl.kallestruik.dtweaks.fakeplayer
|
package nl.kallestruik.dtweaks.fakeplayer
|
||||||
|
|
||||||
|
import io.netty.channel.ChannelHandler
|
||||||
|
import io.netty.channel.ChannelHandlerContext
|
||||||
|
import io.netty.channel.ChannelPipeline
|
||||||
import io.netty.channel.embedded.EmbeddedChannel
|
import io.netty.channel.embedded.EmbeddedChannel
|
||||||
import net.minecraft.network.Connection
|
import net.minecraft.network.Connection
|
||||||
import net.minecraft.network.protocol.PacketFlow
|
import net.minecraft.network.protocol.PacketFlow
|
||||||
|
@ -10,10 +13,31 @@ class FakeConnection(
|
||||||
): Connection(packetFlow) {
|
): Connection(packetFlow) {
|
||||||
|
|
||||||
init {
|
init {
|
||||||
this.channel = EmbeddedChannel()
|
this.channel = FakeChannel()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun setReadOnly() {}
|
override fun setReadOnly() {}
|
||||||
|
|
||||||
override fun handleDisconnection() {}
|
override fun handleDisconnection() {}
|
||||||
|
|
||||||
|
// We need protocol lib to not get very confused with our fake connection,
|
||||||
|
// so we need to create a fake netty pipeline.
|
||||||
|
class FakeChannel: EmbeddedChannel() {
|
||||||
|
override fun pipeline(): ChannelPipeline {
|
||||||
|
val pipeline = newChannelPipeline()
|
||||||
|
return pipeline
|
||||||
|
.addFirst("encoder", NoopChannelHandler())
|
||||||
|
.addFirst("decoder", NoopChannelHandler())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
class NoopChannelHandler : ChannelHandler {
|
||||||
|
override fun handlerAdded(ctx: ChannelHandlerContext?) {}
|
||||||
|
|
||||||
|
override fun handlerRemoved(ctx: ChannelHandlerContext?) {}
|
||||||
|
|
||||||
|
@Deprecated("Deprecated in Java")
|
||||||
|
override fun exceptionCaught(ctx: ChannelHandlerContext?, cause: Throwable?) {}
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
|
@ -12,16 +12,17 @@ import net.minecraft.server.level.ServerPlayer
|
||||||
import net.minecraft.world.damagesource.DamageSource
|
import net.minecraft.world.damagesource.DamageSource
|
||||||
import net.minecraft.world.food.FoodData
|
import net.minecraft.world.food.FoodData
|
||||||
import net.minecraft.world.level.block.entity.SkullBlockEntity
|
import net.minecraft.world.level.block.entity.SkullBlockEntity
|
||||||
import nl.kallestruik.dtweaks.fakeplayer.FakePlayerList.placeFakePlayer
|
import nl.kallestruik.dtweaks.DTweaks
|
||||||
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld
|
import org.bukkit.craftbukkit.v1_20_R1.CraftWorld
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
import java.util.concurrent.atomic.AtomicReference
|
||||||
|
|
||||||
class FakePlayer(
|
class FakePlayer(
|
||||||
server: MinecraftServer,
|
server: MinecraftServer,
|
||||||
private val serverLevel: ServerLevel,
|
private val serverLevel: ServerLevel,
|
||||||
gameProfile: GameProfile
|
gameProfile: GameProfile
|
||||||
): ServerPlayer(server, serverLevel, gameProfile, null) {
|
): ServerPlayer(server, serverLevel, gameProfile) {
|
||||||
val locale = "en_US"
|
val locale = "en_US"
|
||||||
|
|
||||||
companion object {
|
companion object {
|
||||||
|
@ -31,7 +32,7 @@ class FakePlayer(
|
||||||
// Get the world
|
// Get the world
|
||||||
val serverLevel = (location.world as CraftWorld).handle
|
val serverLevel = (location.world as CraftWorld).handle
|
||||||
// Get the game profile from the cache (or retrieve it if it is not cached)
|
// Get the game profile from the cache (or retrieve it if it is not cached)
|
||||||
var gameProfile = minecraftServer.profileCache.get(name).takeIf { it.isPresent }?.get() ?: return null
|
var gameProfile = minecraftServer.profileCache?.get(name).takeIf { it?.isPresent == true }?.get() ?: return null
|
||||||
if (gameProfile.properties.containsKey("textures")) {
|
if (gameProfile.properties.containsKey("textures")) {
|
||||||
val result = AtomicReference<GameProfile>()
|
val result = AtomicReference<GameProfile>()
|
||||||
SkullBlockEntity.updateGameprofile(gameProfile, result::set)
|
SkullBlockEntity.updateGameprofile(gameProfile, result::set)
|
||||||
|
@ -43,14 +44,15 @@ class FakePlayer(
|
||||||
|
|
||||||
// Create a fake connection for our fake player.
|
// Create a fake connection for our fake player.
|
||||||
val connection = FakeConnection(PacketFlow.SERVERBOUND)
|
val connection = FakeConnection(PacketFlow.SERVERBOUND)
|
||||||
minecraftServer.playerList.placeFakePlayer(connection, instance)
|
|
||||||
|
|
||||||
instance.respawn()
|
val bukkitPlayer = instance.bukkitEntity
|
||||||
instance.teleportTo(serverLevel, location.x, location.y, location.z, location.yaw, location.pitch)
|
|
||||||
instance.dead = false
|
Bukkit.getScheduler().runTaskLater(DTweaks.plugin, Runnable {
|
||||||
instance.heal(instance.maxHealth)
|
bukkitPlayer.spigot().respawn()
|
||||||
instance.unsetRemoved()
|
bukkitPlayer.teleport(location)
|
||||||
instance.maxUpStep = 0.6F
|
}, 0)
|
||||||
|
|
||||||
|
minecraftServer.playerList.placeNewPlayer(connection, instance)
|
||||||
|
|
||||||
minecraftServer.playerList.broadcastAll(
|
minecraftServer.playerList.broadcastAll(
|
||||||
ClientboundRotateHeadPacket(
|
ClientboundRotateHeadPacket(
|
||||||
|
@ -62,59 +64,6 @@ class FakePlayer(
|
||||||
|
|
||||||
instance.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, 0x7f)
|
instance.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, 0x7f)
|
||||||
return instance
|
return instance
|
||||||
|
|
||||||
// (DTweaks.reflectionUtil.getValueFromField(
|
|
||||||
// serverConnection!!,
|
|
||||||
// "connectedChannels"
|
|
||||||
// ) as MutableList<NetworkManager?>).add(connection)
|
|
||||||
//
|
|
||||||
// // Connect the fake player to the server using the fake connection.
|
|
||||||
// FakePlayerList.a(minecraftServer.playerList, connection, instance)
|
|
||||||
//
|
|
||||||
// // Check if the fake player is not yet in the correct world.
|
|
||||||
// if (instance.world.dimensionKey != worldServer.dimensionKey) {
|
|
||||||
// // Store the old world of the fake player.
|
|
||||||
// val old_world = instance.world as WorldServer
|
|
||||||
// // Remove the fake player from the old world.
|
|
||||||
// old_world.removePlayer(instance)
|
|
||||||
// // Make the fake player not be dead.
|
|
||||||
// instance.dead = false
|
|
||||||
// // Create the fake player in the new world.
|
|
||||||
// worldServer.addEntity(instance)
|
|
||||||
// // Spawn the fake player in the new world.
|
|
||||||
// instance.spawnIn(worldServer)
|
|
||||||
// // Move the fake player to the new world for the server.
|
|
||||||
// minecraftServer.playerList.moveToWorld(instance, old_world, true, null, false)
|
|
||||||
// // requestTeleport(x, y, z, yaw, pitch)
|
|
||||||
// // Request the teleport from the fake player.
|
|
||||||
// instance.playerConnection.a(x, y, z, yaw.toFloat(), pitch.toFloat())
|
|
||||||
// // Set the fake player's world to the new world.
|
|
||||||
// instance.playerInteractManager.world = worldServer
|
|
||||||
// instance.teleportTo(worldServer, BlockPosition(x, y, z))
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// /// Set the fake players health to max.
|
|
||||||
// instance.health = 20.0f
|
|
||||||
// // Make the fake player not be dead.
|
|
||||||
// instance.dead = false
|
|
||||||
// // a == requestTeleport
|
|
||||||
// // Request the teleport from the fake player.
|
|
||||||
// instance.playerConnection.a(x, y, z, yaw.toFloat(), pitch.toFloat())
|
|
||||||
// // G == stepHeight
|
|
||||||
// // Set the fake players step height to 0.6 (The normal value).
|
|
||||||
// instance.G = 0.6f
|
|
||||||
// // Set the fake players gamemode to survival.
|
|
||||||
// playerInteractManager.gameMode = EnumGamemode.SURVIVAL
|
|
||||||
// // Tell everyone in the world about the fake player and where he is.
|
|
||||||
// minecraftServer.playerList.a(
|
|
||||||
// PacketPlayOutEntityHeadRotation(instance, (instance.yaw * 256 / 360).toByte()),
|
|
||||||
// instance.world.dimensionKey
|
|
||||||
// )
|
|
||||||
// minecraftServer.playerList.a(PacketPlayOutEntityTeleport(instance), instance.world.dimensionKey)
|
|
||||||
// // Move the fake player for the worlds chunk provider.
|
|
||||||
// instance.worldServer.getChunkProvider().movePlayer(instance)
|
|
||||||
// // bp == PLAYER_MODEL_PARTS
|
|
||||||
// instance.datawatcher.set<Byte>(bj, 0x7f.toByte()) // show all model layers (incl. capes)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -2,6 +2,7 @@ package nl.kallestruik.dtweaks.fakeplayer
|
||||||
|
|
||||||
import io.netty.util.concurrent.Future
|
import io.netty.util.concurrent.Future
|
||||||
import io.netty.util.concurrent.GenericFutureListener
|
import io.netty.util.concurrent.GenericFutureListener
|
||||||
|
import net.minecraft.network.PacketSendListener
|
||||||
import net.minecraft.network.chat.Component
|
import net.minecraft.network.chat.Component
|
||||||
import net.minecraft.network.protocol.Packet
|
import net.minecraft.network.protocol.Packet
|
||||||
import net.minecraft.server.MinecraftServer
|
import net.minecraft.server.MinecraftServer
|
||||||
|
@ -13,15 +14,10 @@ class FakePlayerConnection(
|
||||||
connection: FakeConnection,
|
connection: FakeConnection,
|
||||||
player: FakePlayer
|
player: FakePlayer
|
||||||
): ServerGamePacketListenerImpl(minecraftServer, connection, player) {
|
): ServerGamePacketListenerImpl(minecraftServer, connection, player) {
|
||||||
override fun send(packetIn: Packet<*>?) {}
|
override fun send(packetIn: Packet<*>) {}
|
||||||
override fun send(packet: Packet<*>, listener: GenericFutureListener<out Future<in Void>>?) {}
|
override fun send(packet: Packet<*>, callbacks: PacketSendListener?) {}
|
||||||
|
|
||||||
override fun disconnect(message: Component) {
|
override fun disconnect(message: Component) {
|
||||||
player.kill()
|
player.kill()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun tick() {
|
|
||||||
println("Tick for ${player.name}")
|
|
||||||
super.tick()
|
|
||||||
}
|
|
||||||
}
|
}
|
|
@ -1,338 +1,12 @@
|
||||||
package nl.kallestruik.dtweaks.fakeplayer
|
package nl.kallestruik.dtweaks.fakeplayer
|
||||||
|
|
||||||
import com.destroystokyo.paper.event.player.PlayerInitialSpawnEvent
|
|
||||||
import com.mojang.authlib.GameProfile
|
|
||||||
import com.mojang.datafixers.util.Either
|
|
||||||
import com.mojang.serialization.Dynamic
|
|
||||||
import io.netty.buffer.Unpooled
|
|
||||||
import io.papermc.paper.configuration.GlobalConfiguration
|
|
||||||
import net.minecraft.core.RegistryAccess
|
|
||||||
import net.minecraft.nbt.CompoundTag
|
|
||||||
import net.minecraft.nbt.NbtOps
|
|
||||||
import net.minecraft.nbt.Tag
|
|
||||||
import net.minecraft.network.Connection
|
import net.minecraft.network.Connection
|
||||||
import net.minecraft.network.FriendlyByteBuf
|
|
||||||
import net.minecraft.network.protocol.game.*
|
|
||||||
import net.minecraft.resources.ResourceKey
|
|
||||||
import net.minecraft.server.MinecraftServer
|
|
||||||
import net.minecraft.server.level.ChunkHolder.ChunkLoadingFailure
|
|
||||||
import net.minecraft.server.level.DistanceManager
|
|
||||||
import net.minecraft.server.level.ServerLevel
|
|
||||||
import net.minecraft.server.level.ServerPlayer
|
import net.minecraft.server.level.ServerPlayer
|
||||||
import net.minecraft.server.level.TicketType
|
|
||||||
import net.minecraft.server.network.ServerGamePacketListenerImpl
|
|
||||||
import net.minecraft.server.players.GameProfileCache
|
|
||||||
import net.minecraft.server.players.PlayerList
|
import net.minecraft.server.players.PlayerList
|
||||||
import net.minecraft.tags.TagNetworkSerialization
|
|
||||||
import net.minecraft.world.level.ChunkPos
|
|
||||||
import net.minecraft.world.level.GameRules
|
|
||||||
import net.minecraft.world.level.Level
|
|
||||||
import net.minecraft.world.level.biome.BiomeManager
|
|
||||||
import net.minecraft.world.level.chunk.ChunkAccess
|
|
||||||
import net.minecraft.world.level.dimension.DimensionType
|
|
||||||
import nl.kallestruik.dlib.ReflectionUtil
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.CraftServer
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.CraftWorld
|
|
||||||
import org.bukkit.entity.Player
|
|
||||||
import org.spigotmc.event.player.PlayerSpawnLocationEvent
|
|
||||||
import java.util.*
|
|
||||||
import java.util.concurrent.CompletableFuture
|
|
||||||
|
|
||||||
object FakePlayerList {
|
object FakePlayerList {
|
||||||
|
|
||||||
fun PlayerList.placeFakePlayer(connection: Connection, player: ServerPlayer) {
|
fun PlayerList.placeFakePlayer(connection: Connection, player: ServerPlayer) {
|
||||||
player.isRealPlayer = true // Paper - Chunk priority
|
|
||||||
player.networkManager = connection // Paper
|
|
||||||
player.loginTime = System.currentTimeMillis() // Paper
|
|
||||||
|
|
||||||
val gameprofile = player.getGameProfile()
|
|
||||||
val usercache = server.profileCache
|
|
||||||
val optional = usercache[gameprofile.id]
|
|
||||||
var s: String? = optional.map { obj: GameProfile -> obj.name }.orElse(gameprofile.name)
|
|
||||||
|
|
||||||
usercache.add(gameprofile)
|
|
||||||
val nbttagcompound = load(player)
|
|
||||||
// CraftBukkit start - Better rename detection
|
|
||||||
// CraftBukkit start - Better rename detection
|
|
||||||
if (nbttagcompound != null && nbttagcompound.contains("bukkit")) {
|
|
||||||
val bukkit = nbttagcompound.getCompound("bukkit")
|
|
||||||
s = if (bukkit.contains("lastKnownName", 8)) bukkit.getString("lastKnownName") else s
|
|
||||||
}
|
|
||||||
val lastKnownName = s // Paper
|
|
||||||
|
|
||||||
// CraftBukkit end
|
|
||||||
|
|
||||||
// Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
|
|
||||||
// CraftBukkit end
|
|
||||||
|
|
||||||
// Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
|
|
||||||
val resourcekey =
|
|
||||||
if (nbttagcompound != null && nbttagcompound.contains("WorldUUIDMost") && nbttagcompound.contains("WorldUUIDLeast")) {
|
|
||||||
val uid = UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast"))
|
|
||||||
val bWorld = Bukkit.getServer().getWorld(uid)
|
|
||||||
if (bWorld != null) {
|
|
||||||
(bWorld as CraftWorld).handle.dimension()
|
|
||||||
} else {
|
|
||||||
Level.OVERWORLD
|
|
||||||
}
|
|
||||||
} else if (nbttagcompound != null) {
|
|
||||||
// Vanilla migration support
|
|
||||||
// Paper end
|
|
||||||
val dataresult = DimensionType.parseLegacy(
|
|
||||||
Dynamic(
|
|
||||||
NbtOps.INSTANCE,
|
|
||||||
nbttagcompound["Dimension"]
|
|
||||||
)
|
|
||||||
) // CraftBukkit - decompile error
|
|
||||||
dataresult.resultOrPartial { msg: String? ->
|
|
||||||
|
|
||||||
}.orElse(Level.OVERWORLD)
|
|
||||||
} else {
|
|
||||||
Level.OVERWORLD
|
|
||||||
}
|
|
||||||
|
|
||||||
val resourcekey1: ResourceKey<Level> = resourcekey
|
|
||||||
val worldserver = server.getLevel(resourcekey1)
|
|
||||||
var worldserver1: ServerLevel
|
|
||||||
|
|
||||||
worldserver1 = if (worldserver == null) {
|
|
||||||
server.overworld()
|
|
||||||
} else {
|
|
||||||
worldserver
|
|
||||||
}
|
|
||||||
|
|
||||||
if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1) // Paper - only move to spawn on first login, otherwise, stay where you are....
|
|
||||||
|
|
||||||
|
|
||||||
player.setLevel(worldserver1)
|
|
||||||
// Paper start - make s1 final
|
|
||||||
// Paper start - make s1 final
|
|
||||||
val s1: String
|
|
||||||
|
|
||||||
s1 = if (connection.remoteAddress != null) {
|
|
||||||
if (GlobalConfiguration.get().logging.logPlayerIpAddresses) connection.remoteAddress.toString() else "<ip address withheld>" // Paper
|
|
||||||
} else {
|
|
||||||
"local"
|
|
||||||
}
|
|
||||||
// Paper end
|
|
||||||
|
|
||||||
// Spigot start - spawn location event
|
|
||||||
// Paper end
|
|
||||||
|
|
||||||
// Spigot start - spawn location event
|
|
||||||
val spawnPlayer: Player = player.bukkitEntity
|
|
||||||
val ev: PlayerSpawnLocationEvent =
|
|
||||||
PlayerInitialSpawnEvent(spawnPlayer, spawnPlayer.location) // Paper use our duplicate event
|
|
||||||
|
|
||||||
val cserver = ReflectionUtil().getValueFromField(this, "cserver") as CraftServer
|
|
||||||
|
|
||||||
cserver.pluginManager.callEvent(ev)
|
|
||||||
|
|
||||||
val loc = ev.spawnLocation
|
|
||||||
worldserver1 = (loc.world as CraftWorld).handle
|
|
||||||
|
|
||||||
player.spawnIn(worldserver1)
|
|
||||||
player.gameMode.setLevel(player.level as ServerLevel)
|
|
||||||
player.setPosRaw(loc.x, loc.y, loc.z)
|
|
||||||
player.setRot(loc.yaw, loc.pitch)
|
|
||||||
|
|
||||||
val worlddata = worldserver1.getLevelData()
|
|
||||||
|
|
||||||
player.loadGameTypes(nbttagcompound)
|
|
||||||
val playerconnection = ServerGamePacketListenerImpl(server, connection, player)
|
|
||||||
val gamerules = worldserver1.gameRules
|
|
||||||
val flag = gamerules.getBoolean(GameRules.RULE_DO_IMMEDIATE_RESPAWN)
|
|
||||||
val flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO)
|
|
||||||
|
|
||||||
val registryHolder = ReflectionUtil().getValueFromField(this, "t" /* registryHolder -> t */) as RegistryAccess.Frozen
|
|
||||||
|
|
||||||
playerconnection.send(
|
|
||||||
ClientboundLoginPacket(
|
|
||||||
player.id,
|
|
||||||
worlddata.isHardcore,
|
|
||||||
player.gameMode.gameModeForPlayer,
|
|
||||||
player.gameMode.previousGameModeForPlayer,
|
|
||||||
server.levelKeys(),
|
|
||||||
registryHolder,
|
|
||||||
worldserver1.dimensionTypeId(),
|
|
||||||
worldserver1.dimension(),
|
|
||||||
BiomeManager.obfuscateSeed(worldserver1.seed),
|
|
||||||
maxPlayers,
|
|
||||||
worldserver1.getChunkSource().chunkMap.playerChunkManager.targetSendDistance,
|
|
||||||
worldserver1.getChunkSource().chunkMap.playerChunkManager.targetTickViewDistance,
|
|
||||||
flag1,
|
|
||||||
!flag,
|
|
||||||
worldserver1.isDebug,
|
|
||||||
worldserver1.isFlat,
|
|
||||||
player.lastDeathLocation
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
player.bukkitEntity.sendSupportedChannels() // CraftBukkit
|
|
||||||
|
|
||||||
playerconnection.send(
|
|
||||||
ClientboundCustomPayloadPacket(
|
|
||||||
ClientboundCustomPayloadPacket.BRAND, FriendlyByteBuf(Unpooled.buffer()).writeUtf(
|
|
||||||
server.serverModName
|
|
||||||
)
|
|
||||||
)
|
|
||||||
)
|
|
||||||
playerconnection.send(ClientboundChangeDifficultyPacket(worlddata.difficulty, worlddata.isDifficultyLocked))
|
|
||||||
playerconnection.send(ClientboundPlayerAbilitiesPacket(player.abilities))
|
|
||||||
playerconnection.send(ClientboundSetCarriedItemPacket(player.inventory.selected))
|
|
||||||
playerconnection.send(ClientboundUpdateRecipesPacket(server.recipeManager.getRecipes()))
|
|
||||||
playerconnection.send(ClientboundUpdateTagsPacket(TagNetworkSerialization.serializeTagsToNetwork(registryHolder)))
|
|
||||||
this.sendPlayerPermissionLevel(player)
|
|
||||||
player.stats.markAllDirty()
|
|
||||||
player.recipeBook.sendInitialRecipeBook(player)
|
|
||||||
updateEntireScoreboard(worldserver1.scoreboard, player)
|
|
||||||
server.invalidateStatus()
|
|
||||||
// Paper start - async load spawn in chunk
|
|
||||||
// Paper start - async load spawn in chunk
|
|
||||||
val finalWorldserver = worldserver1
|
|
||||||
val chunkX = loc.blockX shr 4
|
|
||||||
val chunkZ = loc.blockZ shr 4
|
|
||||||
val pos = ChunkPos(chunkX, chunkZ)
|
|
||||||
val playerChunkMap = worldserver1.getChunkSource().chunkMap
|
|
||||||
val distanceManager: DistanceManager = playerChunkMap.distanceManager
|
|
||||||
distanceManager.addTicket(TicketType.LOGIN, pos, 31, pos.toLong())
|
|
||||||
worldserver1.getChunkSource().markAreaHighPriority(pos, 28, 3) // Paper - Chunk priority
|
|
||||||
|
|
||||||
val postChunkLoadJoin = this::class.java.superclass.getDeclaredMethod("postChunkLoadJoin", ServerPlayer::class.java, ServerLevel::class.java, Connection::class.java, ServerGamePacketListenerImpl::class.java, CompoundTag::class.java, String::class.java, String::class.java)
|
|
||||||
postChunkLoadJoin.isAccessible = true
|
|
||||||
postChunkLoadJoin.invoke(this, player, finalWorldserver, connection, playerconnection,
|
|
||||||
nbttagcompound, "127.0.0.1", lastKnownName)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun placeNewPlayer(playerList: PlayerList, server: MinecraftServer, connection: FakeConnection, player: FakePlayer) {
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
fun placeNewPlayerOld(playerList: PlayerList, server: MinecraftServer, connection: FakeConnection, player: FakePlayer) {
|
|
||||||
player.isRealPlayer = true // Paper - Chunk priority
|
|
||||||
|
|
||||||
player.networkManager = connection // Paper
|
|
||||||
|
|
||||||
player.loginTime = System.currentTimeMillis() // Paper
|
|
||||||
|
|
||||||
val gameProfile: GameProfile = player.getGameProfile()
|
|
||||||
val userCache: GameProfileCache = server.getProfileCache()
|
|
||||||
val optional = userCache[gameProfile.id]
|
|
||||||
var s: String? = optional.map { obj: GameProfile -> obj.name }.orElse(gameProfile.name)
|
|
||||||
|
|
||||||
userCache.add(gameProfile)
|
|
||||||
val nbtTagCompound: CompoundTag? = playerList.load(player)
|
|
||||||
// CraftBukkit start - Better rename detection
|
|
||||||
// CraftBukkit start - Better rename detection
|
|
||||||
if (nbtTagCompound != null && nbtTagCompound.contains("bukkit")) {
|
|
||||||
val bukkit = nbtTagCompound.getCompound("bukkit")
|
|
||||||
s = if (bukkit.contains("lastKnownName", 8)) bukkit.getString("lastKnownName") else s
|
|
||||||
}
|
|
||||||
val lastKnownName = s // Paper
|
|
||||||
|
|
||||||
// CraftBukkit end
|
|
||||||
|
|
||||||
// Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
|
|
||||||
// CraftBukkit end
|
|
||||||
|
|
||||||
// Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
|
|
||||||
val resourceKey: ResourceKey<Level> = if (nbtTagCompound != null && nbtTagCompound.contains("WorldUUIDMost") && nbtTagCompound.contains("WorldUUIDLeast")) {
|
|
||||||
val uid = UUID(nbtTagCompound.getLong("WorldUUIDMost"), nbtTagCompound.getLong("WorldUUIDLeast"))
|
|
||||||
val bWorld = Bukkit.getServer().getWorld(uid)
|
|
||||||
if (bWorld != null) {
|
|
||||||
(bWorld as CraftWorld).handle.dimension()
|
|
||||||
} else {
|
|
||||||
Level.OVERWORLD
|
|
||||||
}
|
|
||||||
} else if (nbtTagCompound != null) {
|
|
||||||
// Vanilla migration support
|
|
||||||
// Paper end
|
|
||||||
val dataResult = DimensionType.parseLegacy(
|
|
||||||
Dynamic(
|
|
||||||
NbtOps.INSTANCE,
|
|
||||||
nbtTagCompound["Dimension"]
|
|
||||||
)
|
|
||||||
)
|
|
||||||
dataResult.result().orElse(Level.OVERWORLD)
|
|
||||||
} else {
|
|
||||||
Level.OVERWORLD
|
|
||||||
}
|
|
||||||
|
|
||||||
var worldServer: ServerLevel = server.getLevel(resourceKey) ?: server.overworld()
|
|
||||||
|
|
||||||
if (nbtTagCompound == null) player.fudgeSpawnLocation(worldServer) // Paper - only move to spawn on first login, otherwise, stay where you are....
|
|
||||||
|
|
||||||
player.setLevel(worldServer)
|
|
||||||
|
|
||||||
|
|
||||||
// Spigot start - spawn location event
|
|
||||||
val spawnPlayer: Player = player.bukkitEntity
|
|
||||||
val ev: PlayerSpawnLocationEvent =
|
|
||||||
PlayerInitialSpawnEvent(spawnPlayer, spawnPlayer.location) // Paper use our duplicate event
|
|
||||||
|
|
||||||
Bukkit.getServer().pluginManager.callEvent(ev)
|
|
||||||
|
|
||||||
val loc = ev.spawnLocation
|
|
||||||
worldServer = (loc.world as CraftWorld).handle
|
|
||||||
|
|
||||||
player.spawnIn(worldServer)
|
|
||||||
player.gameMode.setLevel(player.level as ServerLevel)
|
|
||||||
// Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
|
|
||||||
// Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
|
|
||||||
player.setPosRaw(loc.x, loc.y, loc.z)
|
|
||||||
player.setRot(loc.yaw, loc.pitch)
|
|
||||||
// Paper end
|
|
||||||
// Spigot end
|
|
||||||
|
|
||||||
// CraftBukkit - Moved message to after join
|
|
||||||
// PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ({}, {}, {})", entityplayer.getName().getString(), s1, entityplayer.getId(), entityplayer.getX(), entityplayer.getY(), entityplayer.getZ());
|
|
||||||
// Paper end
|
|
||||||
// Spigot end
|
|
||||||
|
|
||||||
// CraftBukkit - Moved message to after join
|
|
||||||
// PlayerList.LOGGER.info("{}[{}] logged in with entity id {} at ({}, {}, {})", entityplayer.getName().getString(), s1, entityplayer.getId(), entityplayer.getX(), entityplayer.getY(), entityplayer.getZ());
|
|
||||||
val worlddata = worldServer.getLevelData()
|
|
||||||
|
|
||||||
player.loadGameTypes(nbtTagCompound)
|
|
||||||
val playerconnection = FakePlayerConnection(server, connection, player)
|
|
||||||
val gamerules = worldServer.gameRules
|
|
||||||
|
|
||||||
player.bukkitEntity.sendSupportedChannels() // CraftBukkit
|
|
||||||
|
|
||||||
player.stats.markAllDirty()
|
|
||||||
player.recipeBook.sendInitialRecipeBook(player)
|
|
||||||
playerList.updateEntireScoreboard(worldServer.scoreboard, player)
|
|
||||||
server.invalidateStatus()
|
|
||||||
// Paper start - async load spawn in chunk
|
|
||||||
// Paper start - async load spawn in chunk
|
|
||||||
val finalWorldserver = worldServer
|
|
||||||
val chunkX = loc.blockX shr 4
|
|
||||||
val chunkZ = loc.blockZ shr 4
|
|
||||||
val pos = ChunkPos(chunkX, chunkZ)
|
|
||||||
val playerChunkMap = worldServer.getChunkSource().chunkMap
|
|
||||||
val distanceManager: DistanceManager = playerChunkMap.distanceManager
|
|
||||||
// distanceManager.addTicket(TicketType.LOGIN, pos, 31, pos.toLong())
|
|
||||||
worldServer.getChunkSource().markAreaHighPriority(pos, 28, 3) // Paper - Chunk priority
|
|
||||||
|
|
||||||
val postChunkLoadJoin = playerList::class.java.superclass.getDeclaredMethod("postChunkLoadJoin", ServerPlayer::class.java, ServerLevel::class.java, Connection::class.java, ServerGamePacketListenerImpl::class.java, CompoundTag::class.java, String::class.java, String::class.java)
|
|
||||||
postChunkLoadJoin.isAccessible = true
|
|
||||||
postChunkLoadJoin.invoke(playerList, player, finalWorldserver, connection, playerconnection,
|
|
||||||
nbtTagCompound, "127.0.0.1", lastKnownName)
|
|
||||||
|
|
||||||
|
|
||||||
// worldServer.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, false)
|
|
||||||
// .thenApply { chunk: Either<ChunkAccess, ChunkLoadingFailure> -> // Paper - Chunk priority
|
|
||||||
// val updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong())
|
|
||||||
// if (updatingChunk != null) {
|
|
||||||
// return@thenApply updatingChunk.entityTickingChunkFuture
|
|
||||||
// } else {
|
|
||||||
// return@thenApply CompletableFuture.completedFuture(
|
|
||||||
// chunk
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
// }.thenAccept {
|
|
||||||
//
|
|
||||||
// }
|
|
||||||
}
|
}
|
||||||
}
|
}
|
|
@ -4,8 +4,8 @@ import nl.kallestruik.dtweaks.DTweaks
|
||||||
import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
|
import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
|
||||||
import org.bukkit.Bukkit
|
import org.bukkit.Bukkit
|
||||||
import org.bukkit.Location
|
import org.bukkit.Location
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftEntity
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
|
|
@ -1,108 +0,0 @@
|
||||||
//package nl.kallestruik.dtweaks.managers
|
|
||||||
//
|
|
||||||
//import nl.kallestruik.dlib.MathHelper
|
|
||||||
//import nl.kallestruik.dtweaks.spacetimepockets.SpaceTimePocketChunkGenerator
|
|
||||||
//import org.bukkit.*
|
|
||||||
//import org.bukkit.entity.Player
|
|
||||||
//import java.util.*
|
|
||||||
//
|
|
||||||
//class PocketDimensionManager(
|
|
||||||
// private val mathHelper: MathHelper
|
|
||||||
//) {
|
|
||||||
// val pocketDimension: World = WorldCreator.name("space-time-pockets").generator(SpaceTimePocketChunkGenerator()).createWorld()!!
|
|
||||||
// private val data = HashMap<UUID, PocketData>()
|
|
||||||
// private var lastCreatedPocket = -1
|
|
||||||
//
|
|
||||||
// fun loadData() {
|
|
||||||
// //TODO: Load data from data file on disk.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun saveData() {
|
|
||||||
// //TODO: Save data to file on disk.
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun teleportPlayerIntoPocket(player: Player, pocketOwner: UUID) {
|
|
||||||
// var pocketData = data[pocketOwner]
|
|
||||||
// if (pocketData == null) pocketData = if (player.uniqueId == pocketOwner) {
|
|
||||||
// createPocketForPlayer(player)
|
|
||||||
// } else return
|
|
||||||
// player.teleport(
|
|
||||||
// Location(
|
|
||||||
// pocketDimension, (pocketData.startX + 9).toDouble(), 128.0,
|
|
||||||
// (pocketData.startZ + 9).toDouble()
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// fun createPocketForPlayer(player: Player): PocketData {
|
|
||||||
// // Find a spot
|
|
||||||
// val point = findNextFree()
|
|
||||||
//
|
|
||||||
// // Load the chunks
|
|
||||||
// for (x in 0..2) {
|
|
||||||
// for (y in 0..2) {
|
|
||||||
// pocketDimension.loadChunk(point.x / 16 + x, point.z / 16 + y)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Build the box
|
|
||||||
// for (x in 0..17) {
|
|
||||||
// for (z in 0..17) {
|
|
||||||
// for (y in 0..255) {
|
|
||||||
// if (x == 0 || y == 0 || z == 0 || x == 17 || y == 255 || z == 17) {
|
|
||||||
// pocketDimension.getBlockAt(point.x + x, y, point.z + z).type = Material.BLACK_CONCRETE
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// // Create the spawning platform
|
|
||||||
// pocketDimension.getBlockAt(point.x + 8, 127, point.z + 8).type = Material.STONE
|
|
||||||
// pocketDimension.getBlockAt(point.x + 8, 127, point.z + 9).type = Material.STONE
|
|
||||||
// pocketDimension.getBlockAt(point.x + 9, 127, point.z + 8).type = Material.STONE
|
|
||||||
// pocketDimension.getBlockAt(point.x + 9, 127, point.z + 9).type = Material.STONE
|
|
||||||
//
|
|
||||||
// // Unload the chunks
|
|
||||||
// for (x in 0..2) {
|
|
||||||
// for (y in 0..2) {
|
|
||||||
// pocketDimension.unloadChunk(point.x / 16 + x, point.z / 16 + y)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// val pocketData = PocketData(player.uniqueId, point.x, point.z, ArrayList())
|
|
||||||
// data[player.uniqueId] = pocketData
|
|
||||||
// return pocketData
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private fun findNextFree(): Point {
|
|
||||||
// while (true) {
|
|
||||||
// lastCreatedPocket++
|
|
||||||
// val toCheck = getXYForIndex(lastCreatedPocket)
|
|
||||||
// val chunk = pocketDimension.getChunkAt(
|
|
||||||
// Location(
|
|
||||||
// pocketDimension,
|
|
||||||
// toCheck.x.toDouble(), 0.0, toCheck.z.toDouble()
|
|
||||||
// )
|
|
||||||
// )
|
|
||||||
// val corner = chunk.getBlock(mathHelper.chunkAbs(toCheck.x % 16), 0, mathHelper.chunkAbs(toCheck.z % 16))
|
|
||||||
// if (corner.type == Material.AIR) {
|
|
||||||
// return toCheck
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// private fun getXYForIndex(index: Int): Point {
|
|
||||||
// // Space the pockets 256 blocks (16 chunks) from each other with each pocket being 16 blocks (and two for walls)
|
|
||||||
// // Also subtract 1 from each point so the interior is chunk aligned.
|
|
||||||
// val x = (256 + 16) * (index % 1000) - 1
|
|
||||||
// val z = (256 + 16) * (index / 1000) - 1
|
|
||||||
// return Point(x, z)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// class PocketData(var owner: UUID, var startX: Int, var startZ: Int, var queuedGateways: ArrayList<GatewayData?>)
|
|
||||||
//
|
|
||||||
// class GatewayData
|
|
||||||
//
|
|
||||||
// class Point(var x: Int, var y: Int, var z: Int) {
|
|
||||||
// constructor(x: Int, z: Int) : this(x, 0, z) {}
|
|
||||||
// }
|
|
||||||
//}
|
|
|
@ -1,27 +0,0 @@
|
||||||
//package nl.kallestruik.dtweaks.spacetimepockets
|
|
||||||
//
|
|
||||||
//import org.bukkit.World
|
|
||||||
//import org.bukkit.block.Biome
|
|
||||||
//import org.bukkit.craftbukkit.v1_18_R1.generator.CraftChunkData
|
|
||||||
//import org.bukkit.generator.ChunkGenerator
|
|
||||||
//import java.util.*
|
|
||||||
//
|
|
||||||
//class SpaceTimePocketChunkGenerator: ChunkGenerator() {
|
|
||||||
//
|
|
||||||
// override fun generateChunkData(
|
|
||||||
// world: World,
|
|
||||||
// random: Random,
|
|
||||||
// x: Int,
|
|
||||||
// z: Int,
|
|
||||||
// biome: BiomeGrid
|
|
||||||
// ): ChunkData {
|
|
||||||
// for (cx in 0..15) {
|
|
||||||
// for (cz in 0..15) {
|
|
||||||
// for (cy in 0..264) {
|
|
||||||
// biome.setBiome(cx, cy, cz, Biome.THE_VOID)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
// return CraftChunkData(world)
|
|
||||||
// }
|
|
||||||
//}
|
|
|
@ -1,345 +0,0 @@
|
||||||
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
|
|
||||||
|
|
||||||
import com.google.common.base.Preconditions
|
|
||||||
import net.kyori.adventure.text.Component
|
|
||||||
import net.kyori.adventure.text.format.NamedTextColor
|
|
||||||
import net.kyori.adventure.text.format.TextDecoration
|
|
||||||
import nl.kallestruik.dtweaks.BundleColor
|
|
||||||
import nl.kallestruik.dtweaks.BundleVariant
|
|
||||||
import nl.kallestruik.dtweaks.DTweaks
|
|
||||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
|
||||||
import org.bukkit.Bukkit
|
|
||||||
import org.bukkit.Keyed
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.NamespacedKey
|
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.HandlerList
|
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.inventory.InventoryClickEvent
|
|
||||||
import org.bukkit.event.inventory.PrepareItemCraftEvent
|
|
||||||
import org.bukkit.inventory.*
|
|
||||||
import org.bukkit.inventory.meta.BundleMeta
|
|
||||||
import org.bukkit.persistence.PersistentDataType
|
|
||||||
|
|
||||||
|
|
||||||
class BetterBundles(
|
|
||||||
private val plugin: DTweaks
|
|
||||||
): ITweak, Listener {
|
|
||||||
override fun getIdentifier(): String = "BetterBundles"
|
|
||||||
override fun getCategories(): List<String> = listOf("miscellaneous", "survival")
|
|
||||||
|
|
||||||
private val recipeKeys = mutableListOf<NamespacedKey>()
|
|
||||||
|
|
||||||
override fun onEnable() {
|
|
||||||
plugin.server.pluginManager.registerEvents(this, plugin)
|
|
||||||
|
|
||||||
for (color in BundleColor.values()) {
|
|
||||||
val result = ItemStack(Material.BUNDLE)
|
|
||||||
val resultMeta = result.itemMeta
|
|
||||||
resultMeta.setCustomModelData(BundleVariant.NORMAL.modelDataStart + color.modelData)
|
|
||||||
resultMeta.persistentDataContainer.set(COLOR_KEY, PersistentDataType.STRING, color.toString())
|
|
||||||
result.itemMeta = resultMeta
|
|
||||||
|
|
||||||
val key = NamespacedKey(plugin, "${color.name.lowercase()}_color_bundle")
|
|
||||||
recipeKeys.add(key)
|
|
||||||
|
|
||||||
addDyeRecipe(key, color.dye, result)
|
|
||||||
}
|
|
||||||
|
|
||||||
for (variant in BundleVariant.values()) {
|
|
||||||
if (variant.material == null)
|
|
||||||
continue
|
|
||||||
|
|
||||||
val result = ItemStack(Material.BUNDLE)
|
|
||||||
val resultMeta = result.itemMeta
|
|
||||||
resultMeta.setCustomModelData(variant.modelDataStart + BundleColor.BROWN.modelData)
|
|
||||||
resultMeta.persistentDataContainer.set(VARIANT_KEY, PersistentDataType.STRING, variant.toString())
|
|
||||||
|
|
||||||
result.itemMeta = resultMeta
|
|
||||||
|
|
||||||
val key = NamespacedKey(plugin, "${variant.name.lowercase()}_variant_bundle")
|
|
||||||
recipeKeys.add(key)
|
|
||||||
|
|
||||||
addUpgradeRecipe(key, variant.material, result)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisable() {
|
|
||||||
HandlerList.unregisterAll(this)
|
|
||||||
for (key in recipeKeys) {
|
|
||||||
plugin.server.removeRecipe(key)
|
|
||||||
}
|
|
||||||
|
|
||||||
recipeKeys.clear()
|
|
||||||
}
|
|
||||||
|
|
||||||
val VARIANT_KEY = NamespacedKey(plugin, "variant")
|
|
||||||
val COLOR_KEY = NamespacedKey(plugin, "color")
|
|
||||||
|
|
||||||
private fun addDyeRecipe(key: NamespacedKey, dye: Material, result: ItemStack) {
|
|
||||||
val recipe = ShapelessRecipe(key, result)
|
|
||||||
recipe.addIngredient(dye)
|
|
||||||
recipe.addIngredient(Material.BUNDLE)
|
|
||||||
|
|
||||||
plugin.server.addRecipe(recipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addUpgradeRecipe(key: NamespacedKey, material: Material, result: ItemStack) {
|
|
||||||
val recipe = ShapedRecipe(key, result)
|
|
||||||
recipe.shape("MMM", "MBM", "MMM")
|
|
||||||
recipe.setIngredient('M', material)
|
|
||||||
recipe.setIngredient('B', Material.BUNDLE)
|
|
||||||
|
|
||||||
plugin.server.addRecipe(recipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isBundleRecipe(recipe: Recipe): Boolean {
|
|
||||||
return isDyeRecipe(recipe) || isVariantRecipe(recipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isDyeRecipe(recipe: Recipe): Boolean {
|
|
||||||
if (recipe !is Keyed)
|
|
||||||
return false
|
|
||||||
|
|
||||||
val key = recipe.key
|
|
||||||
if (key.namespace != plugin.getNamespace())
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (!key.key.endsWith("_color_bundle"))
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isVariantRecipe(recipe: Recipe): Boolean {
|
|
||||||
if (recipe !is Keyed)
|
|
||||||
return false
|
|
||||||
|
|
||||||
val key = recipe.key
|
|
||||||
if (key.namespace != plugin.getNamespace())
|
|
||||||
return false
|
|
||||||
|
|
||||||
if (!key.key.endsWith("_variant_bundle"))
|
|
||||||
return false
|
|
||||||
|
|
||||||
return true
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onCraft(event: PrepareItemCraftEvent) {
|
|
||||||
val recipe = event.recipe ?: return
|
|
||||||
|
|
||||||
if (!isBundleRecipe(recipe))
|
|
||||||
return
|
|
||||||
|
|
||||||
|
|
||||||
val inventory = event.inventory
|
|
||||||
Bukkit.getScheduler().runTask(
|
|
||||||
plugin,
|
|
||||||
Runnable {
|
|
||||||
inventory.result =
|
|
||||||
if (isDyeRecipe(recipe)) getDyeResult(recipe, inventory)
|
|
||||||
else if (isVariantRecipe(recipe)) getVariantResult(recipe, inventory)
|
|
||||||
else null
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getDyeResult(recipe: Recipe, inventory: CraftingInventory): ItemStack? {
|
|
||||||
val bundle = inventory.matrix?.filter { it?.type == Material.BUNDLE }?.get(0) ?: return null
|
|
||||||
val recipeResult = recipe.result
|
|
||||||
|
|
||||||
val result = bundle.clone()
|
|
||||||
val resultMeta = result.itemMeta
|
|
||||||
resultMeta.persistentDataContainer.set(
|
|
||||||
COLOR_KEY,
|
|
||||||
PersistentDataType.STRING,
|
|
||||||
recipeResult.itemMeta.persistentDataContainer.get(
|
|
||||||
COLOR_KEY,
|
|
||||||
PersistentDataType.STRING
|
|
||||||
) ?: BundleColor.BROWN.name
|
|
||||||
)
|
|
||||||
|
|
||||||
result.itemMeta = resultMeta
|
|
||||||
updateBundle(result)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getVariantResult(recipe: Recipe, inventory: CraftingInventory): ItemStack? {
|
|
||||||
val bundle = inventory.matrix?.filter { it?.type == Material.BUNDLE }?.get(0) ?: return null
|
|
||||||
val recipeResult = recipe.result
|
|
||||||
|
|
||||||
val result = bundle.clone()
|
|
||||||
val resultMeta = result.itemMeta
|
|
||||||
resultMeta.persistentDataContainer.set(
|
|
||||||
VARIANT_KEY,
|
|
||||||
PersistentDataType.STRING,
|
|
||||||
recipeResult.itemMeta.persistentDataContainer.get(
|
|
||||||
VARIANT_KEY,
|
|
||||||
PersistentDataType.STRING
|
|
||||||
) ?: BundleVariant.NORMAL.name
|
|
||||||
)
|
|
||||||
|
|
||||||
result.itemMeta = resultMeta
|
|
||||||
updateBundle(result)
|
|
||||||
|
|
||||||
return result
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onInventoryClick(event: InventoryClickEvent) {
|
|
||||||
if (!event.isRightClick)
|
|
||||||
return
|
|
||||||
|
|
||||||
val cursor = event.cursor ?: return
|
|
||||||
val clicked = event.currentItem ?: return
|
|
||||||
|
|
||||||
val bundle: ItemStack
|
|
||||||
val item: ItemStack
|
|
||||||
var itemIsCursor = true
|
|
||||||
|
|
||||||
if (cursor.type == Material.BUNDLE) {
|
|
||||||
bundle = cursor
|
|
||||||
item = clicked
|
|
||||||
itemIsCursor = false
|
|
||||||
} else if (clicked.type == Material.BUNDLE) {
|
|
||||||
bundle = clicked
|
|
||||||
item = cursor
|
|
||||||
} else
|
|
||||||
return
|
|
||||||
|
|
||||||
if (item.type.isAir || item.amount == 0) {
|
|
||||||
val itemStack = removeItemFromBundle(bundle) ?: return
|
|
||||||
|
|
||||||
if (itemIsCursor)
|
|
||||||
event.cursor = itemStack
|
|
||||||
else
|
|
||||||
event.currentItem = itemStack
|
|
||||||
} else
|
|
||||||
addItemToBundle(bundle, item)
|
|
||||||
|
|
||||||
event.isCancelled = true
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun removeItemFromBundle(bundle: ItemStack): ItemStack? {
|
|
||||||
val meta = bundle.itemMeta as BundleMeta
|
|
||||||
if (!meta.hasItems())
|
|
||||||
return null
|
|
||||||
|
|
||||||
val itemsInBundle = mutableListOf<ItemStack>()
|
|
||||||
itemsInBundle.addAll(meta.items)
|
|
||||||
val toReturn = itemsInBundle.removeFirst()
|
|
||||||
|
|
||||||
meta.setItems(itemsInBundle)
|
|
||||||
bundle.itemMeta = meta
|
|
||||||
|
|
||||||
updateBundle(bundle)
|
|
||||||
|
|
||||||
return toReturn
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addItemToBundle(bundle: ItemStack, item: ItemStack) {
|
|
||||||
var meta = bundle.itemMeta as BundleMeta
|
|
||||||
val persistentContainer = bundle.itemMeta.persistentDataContainer
|
|
||||||
val variant = BundleVariant.valueOf(persistentContainer.get(VARIANT_KEY, PersistentDataType.STRING) ?: "NORMAL")
|
|
||||||
|
|
||||||
val currentWeight = computeWeight(meta.items)
|
|
||||||
val availableWeight = variant.maxWeight - currentWeight
|
|
||||||
|
|
||||||
val weightPerItem = getWeightPerItem(item)
|
|
||||||
val totalStackWeight = weightPerItem * item.amount
|
|
||||||
if (totalStackWeight > availableWeight) {
|
|
||||||
val toStoreAmount = availableWeight / weightPerItem
|
|
||||||
if (toStoreAmount <= 0)
|
|
||||||
return
|
|
||||||
|
|
||||||
meta = addItemToBundleProper(meta, item.asQuantity(toStoreAmount))
|
|
||||||
item.amount -= toStoreAmount
|
|
||||||
} else {
|
|
||||||
meta = addItemToBundleProper(meta, item.clone())
|
|
||||||
item.amount = 0
|
|
||||||
}
|
|
||||||
|
|
||||||
bundle.itemMeta = meta
|
|
||||||
|
|
||||||
updateBundle(bundle)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateBundle(bundle: ItemStack) {
|
|
||||||
val meta = bundle.itemMeta as BundleMeta
|
|
||||||
val persistentContainer = meta.persistentDataContainer
|
|
||||||
|
|
||||||
val variant = BundleVariant.valueOf(persistentContainer.get(VARIANT_KEY, PersistentDataType.STRING) ?: "NORMAL")
|
|
||||||
val color = BundleColor.valueOf(persistentContainer.get(COLOR_KEY, PersistentDataType.STRING) ?: "BROWN")
|
|
||||||
|
|
||||||
val customModelData = variant.modelDataStart + color.modelData
|
|
||||||
|
|
||||||
meta.setCustomModelData(customModelData)
|
|
||||||
meta.addItemFlags(ItemFlag.HIDE_POTION_EFFECTS)
|
|
||||||
meta.lore(listOf(Component
|
|
||||||
.text("${computeWeight(meta.items)}/${variant.maxWeight}")
|
|
||||||
.color(NamedTextColor.GRAY)
|
|
||||||
.decoration(TextDecoration.ITALIC, false)))
|
|
||||||
|
|
||||||
bundle.itemMeta = meta
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun computeWeight(items: List<ItemStack>): Int {
|
|
||||||
return items.sumOf { getWeight(it) }
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getWeight(item: ItemStack): Int {
|
|
||||||
return item.amount * getWeightPerItem(item)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun getWeightPerItem(item: ItemStack): Int {
|
|
||||||
// Special case for bundle nesting.
|
|
||||||
if (item.type == Material.BUNDLE) {
|
|
||||||
val meta = item.itemMeta as BundleMeta
|
|
||||||
return if (meta.hasItems())
|
|
||||||
64
|
|
||||||
else
|
|
||||||
4
|
|
||||||
}
|
|
||||||
|
|
||||||
// Calculate the right weight.
|
|
||||||
return (64 / item.maxStackSize)
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun addItemToBundleProper(itemMeta: BundleMeta, itemStack: ItemStack): BundleMeta {
|
|
||||||
Preconditions.checkArgument(!itemStack.type.isAir, "item is null or air")
|
|
||||||
|
|
||||||
var leftOver = true
|
|
||||||
val items = mutableListOf<ItemStack>()
|
|
||||||
items.addAll(itemMeta.items)
|
|
||||||
|
|
||||||
for (item in itemMeta.items) {
|
|
||||||
if (item.isSimilar(itemStack)) {
|
|
||||||
if (item.amount >= item.maxStackSize)
|
|
||||||
continue
|
|
||||||
|
|
||||||
items.remove(item)
|
|
||||||
val spaceLeft = item.maxStackSize - item.amount
|
|
||||||
if (spaceLeft >= itemStack.amount) {
|
|
||||||
item.amount += itemStack.amount
|
|
||||||
itemStack.amount = 0
|
|
||||||
items.add(0, item)
|
|
||||||
leftOver = false
|
|
||||||
break
|
|
||||||
} else {
|
|
||||||
item.amount = item.maxStackSize
|
|
||||||
itemStack.amount -= spaceLeft
|
|
||||||
items.add(0, item)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
if (leftOver)
|
|
||||||
items.add(0, itemStack)
|
|
||||||
|
|
||||||
itemMeta.setItems(items)
|
|
||||||
|
|
||||||
return itemMeta
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -4,7 +4,7 @@ import nl.kallestruik.dtweaks.DTweaks
|
||||||
import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
|
import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
|
||||||
import nl.kallestruik.dtweaks.managers.FakePlayerManager
|
import nl.kallestruik.dtweaks.managers.FakePlayerManager
|
||||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer
|
import org.bukkit.craftbukkit.v1_20_R1.entity.CraftPlayer
|
||||||
import org.bukkit.entity.Player
|
import org.bukkit.entity.Player
|
||||||
import org.bukkit.event.EventHandler
|
import org.bukkit.event.EventHandler
|
||||||
import org.bukkit.event.HandlerList
|
import org.bukkit.event.HandlerList
|
||||||
|
|
|
@ -1,134 +0,0 @@
|
||||||
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
|
|
||||||
|
|
||||||
import nl.kallestruik.dtweaks.DTweaks
|
|
||||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
|
||||||
import org.bukkit.Material
|
|
||||||
import org.bukkit.NamespacedKey
|
|
||||||
import org.bukkit.block.Block
|
|
||||||
import org.bukkit.block.BlockFace
|
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.HandlerList
|
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.block.BlockBreakEvent
|
|
||||||
import org.bukkit.inventory.*
|
|
||||||
import org.bukkit.inventory.meta.Damageable
|
|
||||||
import org.bukkit.persistence.PersistentDataType
|
|
||||||
|
|
||||||
|
|
||||||
class Hammers(
|
|
||||||
private val plugin: DTweaks
|
|
||||||
): ITweak, Listener {
|
|
||||||
override fun getIdentifier(): String = "Hammers"
|
|
||||||
override fun getCategories(): List<String> = listOf("miscellaneous", "survival")
|
|
||||||
|
|
||||||
val HAMMER_KEY = NamespacedKey(plugin, "hammer")
|
|
||||||
val diamondHammerRecipeKey = NamespacedKey(plugin, "diamond_hammer")
|
|
||||||
|
|
||||||
override fun onEnable() {
|
|
||||||
plugin.server.pluginManager.registerEvents(this, plugin)
|
|
||||||
|
|
||||||
val diamondHammer = ItemStack(Material.DIAMOND_PICKAXE)
|
|
||||||
val diamondHammerMeta = diamondHammer.itemMeta
|
|
||||||
diamondHammerMeta.persistentDataContainer.set(HAMMER_KEY, PersistentDataType.SHORT, 1)
|
|
||||||
diamondHammer.itemMeta = diamondHammerMeta
|
|
||||||
updateHammer(diamondHammer)
|
|
||||||
|
|
||||||
val recipe = ShapedRecipe(diamondHammerRecipeKey, diamondHammer)
|
|
||||||
recipe.shape(
|
|
||||||
" BD",
|
|
||||||
" SB",
|
|
||||||
"S ")
|
|
||||||
recipe.setIngredient('B', Material.DIAMOND_BLOCK)
|
|
||||||
recipe.setIngredient('D', Material.DIAMOND)
|
|
||||||
recipe.setIngredient('S', Material.STICK)
|
|
||||||
|
|
||||||
plugin.server.addRecipe(recipe)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisable() {
|
|
||||||
HandlerList.unregisterAll(this)
|
|
||||||
plugin.server.removeRecipe(diamondHammerRecipeKey)
|
|
||||||
}
|
|
||||||
|
|
||||||
fun updateHammer(hammer: ItemStack) {
|
|
||||||
if (!isHammer(hammer))
|
|
||||||
return
|
|
||||||
val meta = hammer.itemMeta
|
|
||||||
|
|
||||||
meta.setCustomModelData(1)
|
|
||||||
|
|
||||||
hammer.itemMeta = meta
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun isHammer(itemStack: ItemStack): Boolean {
|
|
||||||
val meta = itemStack.itemMeta ?: return false
|
|
||||||
|
|
||||||
val persistentContainer = meta.persistentDataContainer
|
|
||||||
|
|
||||||
return persistentContainer.get(HAMMER_KEY, PersistentDataType.SHORT) == 1.toShort()
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onBlockBreak(event: BlockBreakEvent) {
|
|
||||||
val hammer = event.player.inventory.itemInMainHand
|
|
||||||
if (!isHammer(hammer))
|
|
||||||
return
|
|
||||||
|
|
||||||
val player = event.player
|
|
||||||
|
|
||||||
val lastTwoTargetBlocks: List<Block> = player.getLastTwoTargetBlocks(null, 100)
|
|
||||||
if (lastTwoTargetBlocks.size != 2 || !lastTwoTargetBlocks[1].type.isOccluding) return
|
|
||||||
|
|
||||||
val targetBlock: Block = lastTwoTargetBlocks[1]
|
|
||||||
val adjacentBlock: Block = lastTwoTargetBlocks[0]
|
|
||||||
|
|
||||||
val targetFace = targetBlock.getFace(adjacentBlock)
|
|
||||||
|
|
||||||
val toBreak: MutableList<Block> = mutableListOf()
|
|
||||||
|
|
||||||
when (targetFace) {
|
|
||||||
BlockFace.NORTH, BlockFace.SOUTH -> {
|
|
||||||
toBreak.add(targetBlock.getRelative(1, 0, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(-1, 0, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 1, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, -1, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(1, 1, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(-1, 1, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(1, -1, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(-1, -1, 0))
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockFace.EAST, BlockFace.WEST -> {
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 1, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, -1, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 0, 1))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 0, -1))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 1, 1))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, -1, 1))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 1, -1))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, -1, -1))
|
|
||||||
}
|
|
||||||
|
|
||||||
BlockFace.UP, BlockFace.DOWN -> {
|
|
||||||
toBreak.add(targetBlock.getRelative(1, 0, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(-1, 0, 0))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 0, 1))
|
|
||||||
toBreak.add(targetBlock.getRelative(0, 0, -1))
|
|
||||||
toBreak.add(targetBlock.getRelative(1, 0, 1))
|
|
||||||
toBreak.add(targetBlock.getRelative(-1, 0, 1))
|
|
||||||
toBreak.add(targetBlock.getRelative(1, 0, -1))
|
|
||||||
toBreak.add(targetBlock.getRelative(-1, 0, -1))
|
|
||||||
}
|
|
||||||
else -> return
|
|
||||||
}
|
|
||||||
|
|
||||||
val maxHardness = targetBlock.type.hardness
|
|
||||||
|
|
||||||
for (block in toBreak) {
|
|
||||||
if (block.type.hardness > maxHardness)
|
|
||||||
continue
|
|
||||||
|
|
||||||
block.breakNaturally(hammer)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,70 +0,0 @@
|
||||||
//package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
|
|
||||||
//
|
|
||||||
//import nl.kallestruik.dtweaks.managers.PocketDimensionManager
|
|
||||||
//import nl.kallestruik.dtweaks.tweaks.ITweak
|
|
||||||
//import org.bukkit.entity.Player
|
|
||||||
//import org.bukkit.event.EventHandler
|
|
||||||
//import org.bukkit.event.HandlerList
|
|
||||||
//import org.bukkit.event.Listener
|
|
||||||
//import org.bukkit.event.block.BlockBreakEvent
|
|
||||||
//import org.bukkit.event.entity.CreatureSpawnEvent
|
|
||||||
//import org.bukkit.event.entity.EntityDamageEvent
|
|
||||||
//import org.bukkit.event.player.PlayerMoveEvent
|
|
||||||
//import org.bukkit.plugin.java.JavaPlugin
|
|
||||||
//
|
|
||||||
//class SpaceTimePockets(
|
|
||||||
// private val plugin: JavaPlugin,
|
|
||||||
// private val pocketDimensionManager: PocketDimensionManager
|
|
||||||
//): ITweak, Listener {
|
|
||||||
// override fun getIdentifier(): String = "SpaceTimePockets"
|
|
||||||
// override fun getCategories(): List<String> = listOf("miscellaneous", "survival")
|
|
||||||
//
|
|
||||||
// override fun onRegister() {
|
|
||||||
// plugin.server.pluginManager.registerEvents(this, plugin)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// override fun onUnRegister() {
|
|
||||||
// HandlerList.unregisterAll(this)
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
//
|
|
||||||
// @EventHandler
|
|
||||||
// fun onBlockBreak(event: BlockBreakEvent) {
|
|
||||||
// if (event.player.world != pocketDimensionManager.pocketDimension) {
|
|
||||||
// return
|
|
||||||
// }
|
|
||||||
// if (event.block.location.chunk == event.player.location.chunk && event.block.y != 0 && event.block.y != 255) return
|
|
||||||
// event.isCancelled = true
|
|
||||||
// event.player.sendMessage("It seems like a bad idea to break the only thing keeping you from getting lost into the endlessness around you.")
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @EventHandler
|
|
||||||
// fun onMobSpawn(event: CreatureSpawnEvent) {
|
|
||||||
// if (pocketDimensionManager.pocketDimension != event.location.world) return
|
|
||||||
// event.isCancelled = true
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @EventHandler
|
|
||||||
// fun onPlayerDamage(event: EntityDamageEvent) {
|
|
||||||
// if (event.entity !is Player) return
|
|
||||||
// if (pocketDimensionManager.pocketDimension != event.entity.world) return
|
|
||||||
// event.isCancelled = true
|
|
||||||
// }
|
|
||||||
//
|
|
||||||
// @EventHandler
|
|
||||||
// fun onPlayerFall(event: PlayerMoveEvent) {
|
|
||||||
// if (pocketDimensionManager.pocketDimension != event.from.world
|
|
||||||
// || pocketDimensionManager.pocketDimension != event.to.world
|
|
||||||
// ) return
|
|
||||||
// if (event.from.chunk != event.to.chunk) {
|
|
||||||
// event.player.sendMessage("Something pulls you back from the darkness.")
|
|
||||||
// event.isCancelled = true
|
|
||||||
// }
|
|
||||||
// if (event.to.blockY < 0 || event.to.blockY > 256) {
|
|
||||||
// event.player.sendMessage("Something pulls you back from the darkness.")
|
|
||||||
// val safeLocation = event.player.location
|
|
||||||
// safeLocation.y = 128.0
|
|
||||||
// event.player.teleport(safeLocation)
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//}
|
|
|
@ -1,111 +0,0 @@
|
||||||
package nl.kallestruik.dtweaks.tweaks.mobtweaks
|
|
||||||
|
|
||||||
import net.minecraft.core.GlobalPos
|
|
||||||
import net.minecraft.world.entity.ai.memory.MemoryModuleType
|
|
||||||
import net.minecraft.world.entity.schedule.Activity
|
|
||||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
|
||||||
import org.bukkit.craftbukkit.v1_19_R1.entity.CraftVillager
|
|
||||||
import org.bukkit.entity.Villager
|
|
||||||
import org.bukkit.event.EventHandler
|
|
||||||
import org.bukkit.event.HandlerList
|
|
||||||
import org.bukkit.event.Listener
|
|
||||||
import org.bukkit.event.player.PlayerInteractEntityEvent
|
|
||||||
import org.bukkit.plugin.java.JavaPlugin
|
|
||||||
import java.util.concurrent.atomic.AtomicReference
|
|
||||||
|
|
||||||
class VillagerInfo(
|
|
||||||
private val plugin: JavaPlugin
|
|
||||||
): ITweak, Listener {
|
|
||||||
override fun getIdentifier(): String = "VillagerInfo"
|
|
||||||
override fun getCategories(): List<String> = listOf("mobs")
|
|
||||||
|
|
||||||
override fun onEnable() {
|
|
||||||
plugin.server.pluginManager.registerEvents(this, plugin)
|
|
||||||
}
|
|
||||||
|
|
||||||
override fun onDisable() {
|
|
||||||
HandlerList.unregisterAll(this)
|
|
||||||
}
|
|
||||||
|
|
||||||
@EventHandler
|
|
||||||
fun onInteractEvent(event: PlayerInteractEntityEvent) {
|
|
||||||
if (!event.player.isSneaking) return
|
|
||||||
val clicked = event.rightClicked as? Villager ?: return
|
|
||||||
val eVillager: net.minecraft.world.entity.npc.Villager = (clicked as CraftVillager).handle
|
|
||||||
val homePos: AtomicReference<GlobalPos?> = AtomicReference(null)
|
|
||||||
eVillager.brain.getMemory(MemoryModuleType.HOME)
|
|
||||||
.ifPresent { newValue -> homePos.set(newValue) }
|
|
||||||
val workPos: AtomicReference<GlobalPos?> = AtomicReference(null)
|
|
||||||
eVillager.brain.getMemory(MemoryModuleType.JOB_SITE).ifPresent { newValue ->
|
|
||||||
workPos.set(
|
|
||||||
newValue
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val meetingPos: AtomicReference<GlobalPos?> = AtomicReference(null)
|
|
||||||
eVillager.brain.getMemory(MemoryModuleType.MEETING_POINT).ifPresent { newValue ->
|
|
||||||
meetingPos.set(
|
|
||||||
newValue
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val lastWork: AtomicReference<Long?> = AtomicReference(null)
|
|
||||||
eVillager.brain.getMemory(MemoryModuleType.LAST_WORKED_AT_POI).ifPresent { newValue ->
|
|
||||||
lastWork.set(
|
|
||||||
newValue
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val lastSleep: AtomicReference<Long?> = AtomicReference(null)
|
|
||||||
eVillager.brain.getMemory(MemoryModuleType.LAST_SLEPT).ifPresent { newValue ->
|
|
||||||
lastSleep.set(
|
|
||||||
newValue
|
|
||||||
)
|
|
||||||
}
|
|
||||||
val seenIGRecently: AtomicReference<Boolean?> = AtomicReference(null)
|
|
||||||
eVillager.brain.getMemory(MemoryModuleType.GOLEM_DETECTED_RECENTLY).ifPresent { newValue ->
|
|
||||||
seenIGRecently.set(
|
|
||||||
newValue
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
val isPanicking: Boolean = eVillager.brain.isActive(Activity.PANIC)
|
|
||||||
val player = event.player
|
|
||||||
|
|
||||||
player.sendMessage("=====Villager Info=====")
|
|
||||||
player.sendMessage("Type: " + clicked.villagerType)
|
|
||||||
player.sendMessage("Profession: " + clicked.profession)
|
|
||||||
player.sendMessage("Level: " + clicked.villagerLevel + "(" + clicked.villagerExperience + " xp)")
|
|
||||||
player.sendMessage("Panic: $isPanicking")
|
|
||||||
|
|
||||||
if (homePos.get() != null) player.sendMessage(
|
|
||||||
java.lang.String.format(
|
|
||||||
"Home: %s, %s, %s",
|
|
||||||
homePos.get()?.pos()?.x,
|
|
||||||
homePos.get()?.pos()?.y,
|
|
||||||
homePos.get()?.pos()?.z
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (workPos.get() != null) player.sendMessage(
|
|
||||||
java.lang.String.format(
|
|
||||||
"Work: %s, %s, %s",
|
|
||||||
workPos.get()?.pos()?.x,
|
|
||||||
workPos.get()?.pos()?.y,
|
|
||||||
workPos.get()?.pos()?.z
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (homePos.get() != null) player.sendMessage(
|
|
||||||
java.lang.String.format(
|
|
||||||
"Meeting point: %s, %s, %s",
|
|
||||||
meetingPos.get()?.pos()?.x,
|
|
||||||
meetingPos.get()?.pos()?.y,
|
|
||||||
meetingPos.get()?.pos()?.z
|
|
||||||
)
|
|
||||||
)
|
|
||||||
|
|
||||||
if (lastSleep.get() != null)
|
|
||||||
player.sendMessage("Last slept: ${lastSleep.get()}")
|
|
||||||
|
|
||||||
if (seenIGRecently.get() != null)
|
|
||||||
player.sendMessage("Seen iron golem Recently: ${seenIGRecently.get()}")
|
|
||||||
}
|
|
||||||
}
|
|
|
@ -1,22 +1,25 @@
|
||||||
name: DTweaks
|
name: DTweaks
|
||||||
version: ${version}
|
version: ${version}
|
||||||
main: nl.kallestruik.dtweaks.DTweaks
|
main: nl.kallestruik.dtweaks.DTweaks
|
||||||
api-version: 1.16
|
api-version: "1.20"
|
||||||
depend:
|
dependencies:
|
||||||
- "ProtocolLib"
|
- name: "ProtocolLib"
|
||||||
- "DLib"
|
required: true
|
||||||
|
- name: "DLib"
|
||||||
|
required: true
|
||||||
|
bootstrap: true
|
||||||
|
has-open-classloader: true
|
||||||
|
load-after:
|
||||||
|
- name: "DLib"
|
||||||
|
bootstrap: true
|
||||||
|
|
||||||
commands:
|
commands:
|
||||||
toggletrample:
|
toggletrample:
|
||||||
description: "Toggles whether you can trample crops."
|
description: "Toggles whether you can trample crops."
|
||||||
player:
|
player:
|
||||||
description: "Interact with fake players."
|
description: "Interact with fake players."
|
||||||
permission: op
|
permission: op
|
||||||
bundle:
|
|
||||||
description: "Admin command for managing custom bundles."
|
|
||||||
permission: op
|
|
||||||
mobcaps:
|
mobcaps:
|
||||||
description: "Display mobcap information from your current dimension."
|
description: "Display mobcap information from your current dimension."
|
||||||
pocketdim:
|
|
||||||
description: "Interact with pocket dimensions. Testing command."
|
|
||||||
spawnzones:
|
spawnzones:
|
||||||
description: "Manage no spawn zones"
|
description: "Manage no spawn zones"
|
|
@ -20,7 +20,6 @@ NoDoorBreaking: true
|
||||||
NoCreeperGrief: false
|
NoCreeperGrief: false
|
||||||
NoEndermanGrief: true
|
NoEndermanGrief: true
|
||||||
SugarcaneBonemealing: true
|
SugarcaneBonemealing: true
|
||||||
SpaceTimePockets: true
|
|
||||||
VillagerInfo: true
|
VillagerInfo: true
|
||||||
BetterBundles: true
|
BetterBundles: true
|
||||||
RedyeTerracotta: true
|
RedyeTerracotta: true
|
||||||
|
|
Loading…
Reference in New Issue