feat: Add Better Bundles, Hammers, No Spawn Zones, No Melting, and More Sandstone tweaks
|
@ -0,0 +1,5 @@
|
|||
/.gradle/
|
||||
/.idea/
|
||||
/build/
|
||||
/run/
|
||||
/textures/out/
|
|
@ -2,7 +2,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
|
|||
|
||||
plugins {
|
||||
kotlin("jvm") version "1.5.31"
|
||||
id("com.github.johnrengelman.shadow") version "5.2.0"
|
||||
id("com.github.johnrengelman.shadow") version "7.1.2"
|
||||
id("xyz.jpenilla.run-paper") version "1.0.6" // Adds runServer and runMojangMappedServer tasks for testing
|
||||
id("io.papermc.paperweight.userdev") version "1.3.4"
|
||||
}
|
||||
|
||||
|
@ -24,18 +25,13 @@ dependencies {
|
|||
compileOnly("com.comphenix.protocol:ProtocolLib:4.6.0")
|
||||
compileOnly(kotlin("stdlib-jdk8"))
|
||||
|
||||
compileOnly("nl.kallestruik:DLib:1.3.5")
|
||||
compileOnly("nl.kallestruik:DLib:1.3.6")
|
||||
|
||||
testImplementation(kotlin("test-junit5"))
|
||||
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
|
||||
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine:5.6.0")
|
||||
}
|
||||
|
||||
tasks.shadowJar {
|
||||
relocate("co.aikar.commands", "nl.kallestruik.dtweaks.acf")
|
||||
relocate("co.aikar.locales", "nl.kallestruik.dtweaks.locales")
|
||||
}
|
||||
|
||||
tasks.build {
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
|
@ -49,6 +45,11 @@ tasks {
|
|||
useJUnitPlatform()
|
||||
}
|
||||
|
||||
shadowJar {
|
||||
relocate("co.aikar.commands", "nl.kallestruik.dtweaks.acf")
|
||||
relocate("co.aikar.locales", "nl.kallestruik.dtweaks.locales")
|
||||
}
|
||||
|
||||
compileJava {
|
||||
options.compilerArgs.add("-parameters")
|
||||
}
|
||||
|
@ -56,7 +57,7 @@ tasks {
|
|||
kotlinOptions.javaParameters = true
|
||||
}
|
||||
withType<KotlinCompile> {
|
||||
kotlinOptions.jvmTarget = "11"
|
||||
kotlinOptions.jvmTarget = "16"
|
||||
}
|
||||
|
||||
processResources {
|
||||
|
|
|
@ -0,0 +1,25 @@
|
|||
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)
|
||||
}
|
|
@ -0,0 +1,15 @@
|
|||
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)
|
||||
}
|
|
@ -3,4 +3,5 @@ package nl.kallestruik.dtweaks
|
|||
object Const {
|
||||
const val TRAMPLE_ENABLED_FILE_NAME = "tramplestore.yml"
|
||||
const val TWEAK_STATE_FILE_NAME = "tweak_states.yml"
|
||||
const val NO_SPAWN_ZONE_FILE_NAME = "no_spawn_store.yml"
|
||||
}
|
|
@ -5,18 +5,19 @@ import co.aikar.commands.PaperCommandManager
|
|||
import nl.kallestruik.dlib.DUtil
|
||||
import nl.kallestruik.dlib.MathHelper
|
||||
import nl.kallestruik.dlib.ReflectionUtil
|
||||
import nl.kallestruik.dtweaks.commands.CommandBundle
|
||||
import nl.kallestruik.dtweaks.commands.CommandPlayer
|
||||
import nl.kallestruik.dtweaks.commands.CommandSpawnzones
|
||||
import nl.kallestruik.dtweaks.commands.CommandToggletrample
|
||||
import nl.kallestruik.dtweaks.managers.FakePlayerManager
|
||||
import nl.kallestruik.dtweaks.managers.NoSpawnZoneManager
|
||||
import nl.kallestruik.dtweaks.managers.TrampleManager
|
||||
import nl.kallestruik.dtweaks.managers.TweakManager
|
||||
import nl.kallestruik.dtweaks.tweaks.craftingtweaks.*
|
||||
import nl.kallestruik.dtweaks.tweaks.croptweaks.*
|
||||
import nl.kallestruik.dtweaks.tweaks.dispsensertweaks.DispensersCanPlantSaplings
|
||||
import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.ArmorStandArmorSwapping
|
||||
import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.CarpetBlockPlacingProtocol
|
||||
import nl.kallestruik.dtweaks.tweaks.mobtweaks.NoCreeperGrief
|
||||
import nl.kallestruik.dtweaks.tweaks.mobtweaks.NoDoorBreaking
|
||||
import nl.kallestruik.dtweaks.tweaks.mobtweaks.NoEndermanGrief
|
||||
import nl.kallestruik.dtweaks.tweaks.mobtweaks.VillagerInfo
|
||||
import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.*
|
||||
import nl.kallestruik.dtweaks.tweaks.mobtweaks.*
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import java.io.File
|
||||
import java.util.*
|
||||
|
@ -31,7 +32,8 @@ class DTweaks: JavaPlugin() {
|
|||
lateinit var reflectionUtil: ReflectionUtil
|
||||
private lateinit var trampleManager: TrampleManager
|
||||
private lateinit var commandManager: PaperCommandManager
|
||||
// private lateinit var fakePlayerManager: FakePlayerManager
|
||||
private lateinit var fakePlayerManager: FakePlayerManager
|
||||
private lateinit var noSpawnZoneManager: NoSpawnZoneManager
|
||||
// private lateinit var pocketDimensionManager: PocketDimensionManager
|
||||
}
|
||||
|
||||
|
@ -46,7 +48,8 @@ class DTweaks: JavaPlugin() {
|
|||
reflectionUtil = ReflectionUtil()
|
||||
trampleManager = TrampleManager()
|
||||
commandManager = PaperCommandManager(this)
|
||||
// fakePlayerManager = FakePlayerManager()
|
||||
fakePlayerManager = FakePlayerManager(this)
|
||||
noSpawnZoneManager = NoSpawnZoneManager()
|
||||
// pocketDimensionManager = PocketDimensionManager(mathHelper)
|
||||
|
||||
// Enable brigadier support on ACF
|
||||
|
@ -54,19 +57,24 @@ class DTweaks: JavaPlugin() {
|
|||
|
||||
registerCommandConditions()
|
||||
|
||||
val betterBundles = BetterBundles(this)
|
||||
|
||||
/*
|
||||
* Commands
|
||||
*/
|
||||
// commandManager.registerCommand(CommandMobcaps(reflectionUtil))
|
||||
// commandManager.registerCommand(CommandPlayer(fakePlayerManager, tweakManager))
|
||||
commandManager.registerCommand(CommandPlayer(fakePlayerManager))
|
||||
// commandManager.registerCommand(CommandPocketdim(pocketDimensionManager))
|
||||
commandManager.registerCommand(CommandToggletrample(trampleManager))
|
||||
commandManager.registerCommand(CommandBundle(betterBundles))
|
||||
commandManager.registerCommand(CommandSpawnzones(noSpawnZoneManager))
|
||||
|
||||
/*
|
||||
* Load data from disk
|
||||
*/
|
||||
tweakManager.loadFromFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
|
||||
trampleManager.loadFromFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
|
||||
noSpawnZoneManager.loadFromFile(File(dataFolder, Const.NO_SPAWN_ZONE_FILE_NAME))
|
||||
// pocketDimensionManager.loadData()
|
||||
|
||||
/*
|
||||
|
@ -80,8 +88,10 @@ class DTweaks: JavaPlugin() {
|
|||
tweakManager.registerTweak(CraftableSponge(this))
|
||||
tweakManager.registerTweak(IceDecompression(this))
|
||||
tweakManager.registerTweak(LogsToChests(this))
|
||||
tweakManager.registerTweak(MoreSandstone(this))
|
||||
tweakManager.registerTweak(RedyeTerracotta(this))
|
||||
tweakManager.registerTweak(WoolToString(this))
|
||||
tweakManager.registerTweak(CraftableChainmail(this))
|
||||
|
||||
/*
|
||||
* Crop Tweaks
|
||||
|
@ -102,8 +112,12 @@ class DTweaks: JavaPlugin() {
|
|||
* Miscellaneous Tweaks
|
||||
*/
|
||||
tweakManager.registerTweak(ArmorStandArmorSwapping(this))
|
||||
tweakManager.registerTweak(CarpetBlockPlacingProtocol(this, mathHelper))
|
||||
// tweakManager.registerTweak(FakePlayers(fakePlayerManager))
|
||||
// tweakManager.registerTweak(CarpetBlockPlacingProtocol(this, mathHelper))
|
||||
tweakManager.registerTweak(betterBundles)
|
||||
// tweakManager.registerTweak(DyeableNetherite(this))
|
||||
tweakManager.registerTweak(FakePlayers(fakePlayerManager, this))
|
||||
tweakManager.registerTweak(Hammers(this))
|
||||
tweakManager.registerTweak(NoMelting(this))
|
||||
// tweakManager.registerTweak(SpaceTimePockets(this, pocketDimensionManager))
|
||||
|
||||
/*
|
||||
|
@ -113,6 +127,7 @@ class DTweaks: JavaPlugin() {
|
|||
tweakManager.registerTweak(NoDoorBreaking(this))
|
||||
tweakManager.registerTweak(NoEndermanGrief(this))
|
||||
tweakManager.registerTweak(VillagerInfo(this))
|
||||
tweakManager.registerTweak(NoSpawnZones(this, noSpawnZoneManager))
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
|
@ -121,6 +136,7 @@ class DTweaks: JavaPlugin() {
|
|||
*/
|
||||
tweakManager.saveToFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
|
||||
trampleManager.saveToFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
|
||||
noSpawnZoneManager.saveToFile()
|
||||
// pocketDimensionManager.saveData()
|
||||
}
|
||||
|
||||
|
@ -130,4 +146,6 @@ class DTweaks: JavaPlugin() {
|
|||
throw ConditionFailedException("The tweak ${context.getConfigValue("tweak", "")} is not enabled!")
|
||||
}
|
||||
}
|
||||
|
||||
fun getNamespace(): String = this.name.lowercase(Locale.ROOT)
|
||||
}
|
|
@ -0,0 +1,40 @@
|
|||
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,28 +1,37 @@
|
|||
//package nl.kallestruik.dtweaks.commands
|
||||
//
|
||||
//import co.aikar.commands.BaseCommand
|
||||
//import co.aikar.commands.annotation.*
|
||||
//import nl.kallestruik.dtweaks.managers.FakePlayerManager
|
||||
//import nl.kallestruik.dtweaks.managers.TweakManager
|
||||
//import org.bukkit.command.CommandSender
|
||||
//import org.bukkit.entity.Player
|
||||
//
|
||||
//@CommandAlias("player")
|
||||
//@Conditions("tweakEnabled:tweak=FakePlayers")
|
||||
//class CommandPlayer(
|
||||
// private val fakePlayerManager: FakePlayerManager,
|
||||
// private val tweakManager: TweakManager
|
||||
//): BaseCommand() {
|
||||
//
|
||||
// @Subcommand("spawn")
|
||||
// @CommandCompletion("@players")
|
||||
// fun onSpawn(sender: Player, @Single playerName: String) {
|
||||
// fakePlayerManager.spawnFakePlayer(sender.location, playerName)
|
||||
// }
|
||||
//
|
||||
// @Subcommand("kill")
|
||||
// @CommandCompletion("@players")
|
||||
// fun onKill(sender: Player, @Single playerName: String) {
|
||||
// fakePlayerManager.killFakePlayer(playerName)
|
||||
// }
|
||||
//}
|
||||
package nl.kallestruik.dtweaks.commands
|
||||
|
||||
import co.aikar.commands.BaseCommand
|
||||
import co.aikar.commands.annotation.*
|
||||
import nl.kallestruik.dtweaks.managers.FakePlayerManager
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
@CommandAlias("player")
|
||||
@Conditions("tweakEnabled:tweak=FakePlayers")
|
||||
class CommandPlayer(
|
||||
private val fakePlayerManager: FakePlayerManager
|
||||
): BaseCommand() {
|
||||
|
||||
@Subcommand("spawn")
|
||||
@CommandCompletion("@players")
|
||||
fun onSpawn(sender: Player, @Single playerName: String) {
|
||||
fakePlayerManager.spawnFakePlayer(sender.location, playerName)
|
||||
}
|
||||
|
||||
@Subcommand("kill")
|
||||
@CommandCompletion("@players")
|
||||
fun onKill(sender: Player, @Single playerName: String) {
|
||||
fakePlayerManager.killFakePlayer(playerName)
|
||||
}
|
||||
|
||||
@Subcommand("attack")
|
||||
@CommandCompletion("@players")
|
||||
fun onAttack(sender: Player, @Single playerName: String) {
|
||||
fakePlayerManager.attack(playerName)
|
||||
}
|
||||
|
||||
@Subcommand("use")
|
||||
@CommandCompletion("@players")
|
||||
fun onUse(sender: Player, @Single playerName: String) {
|
||||
fakePlayerManager.use(playerName)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,101 @@
|
|||
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 net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
import nl.kallestruik.dtweaks.managers.NoSpawnZoneManager
|
||||
import org.bukkit.entity.Player
|
||||
|
||||
|
||||
@CommandAlias("spawnzones")
|
||||
@Conditions("tweakEnabled:tweak=NoSpawnZones")
|
||||
class CommandSpawnzones(
|
||||
private val noSpawnZoneManager: NoSpawnZoneManager
|
||||
): BaseCommand() {
|
||||
|
||||
@Subcommand("claim")
|
||||
inner class CommandClaim: BaseCommand() {
|
||||
|
||||
@Subcommand("one")
|
||||
fun onClaimOne(sender: Player) {
|
||||
noSpawnZoneManager.claimChunk(sender.location.chunk.x, sender.location.chunk.z, sender.world.key)
|
||||
noSpawnZoneManager.saveToFile()
|
||||
}
|
||||
|
||||
@Subcommand("square")
|
||||
fun onClaimSquare(sender: Player, radius: Int) {
|
||||
val centerX = sender.location.chunk.x
|
||||
val centerZ = sender.location.chunk.z
|
||||
|
||||
|
||||
for (x in centerX-radius..centerX+radius)
|
||||
for (z in centerZ-radius..centerZ+radius)
|
||||
noSpawnZoneManager.claimChunk(x, z, sender.world.key)
|
||||
|
||||
noSpawnZoneManager.saveToFile()
|
||||
}
|
||||
}
|
||||
|
||||
@Subcommand("unclaim")
|
||||
inner class CommandUnclaim: BaseCommand() {
|
||||
|
||||
@Subcommand("one")
|
||||
fun onClaimOne(sender: Player) {
|
||||
noSpawnZoneManager.unclaimChunk(sender.location.chunk.x, sender.location.chunk.z, sender.world.key)
|
||||
noSpawnZoneManager.saveToFile()
|
||||
}
|
||||
|
||||
@Subcommand("square")
|
||||
fun onClaimSquare(sender: Player, radius: Int) {
|
||||
val centerX = sender.location.chunk.x
|
||||
val centerZ = sender.location.chunk.z
|
||||
|
||||
for (x in centerX-radius..centerX+radius)
|
||||
for (z in centerZ-radius..centerZ+radius)
|
||||
noSpawnZoneManager.unclaimChunk(x, z, sender.world.key)
|
||||
|
||||
noSpawnZoneManager.saveToFile()
|
||||
}
|
||||
}
|
||||
|
||||
@Subcommand("map")
|
||||
fun onMap(sender: Player) {
|
||||
// Print the header of the faction map.
|
||||
sender.sendMessage(Component
|
||||
.empty()
|
||||
.color(NamedTextColor.GRAY)
|
||||
.append(Component.text("---------------["))
|
||||
.append(Component
|
||||
.text(" No Spawn Zones ")
|
||||
.color(NamedTextColor.AQUA))
|
||||
.append(Component.text("]---------------"))
|
||||
)
|
||||
|
||||
val centerX = sender.location.chunk.x
|
||||
val centerZ = sender.location.chunk.z
|
||||
|
||||
// Create and send the claim map.
|
||||
for (x in -5..5) {
|
||||
var row = Component.empty()
|
||||
for (z in -6..6) {
|
||||
row = if (x == 0 && z == 0) {
|
||||
row.append(Component.text(" ■").color(NamedTextColor.YELLOW))
|
||||
} else if (noSpawnZoneManager.isChunkClaimed(centerX + x, centerZ + z, sender.world.key)) {
|
||||
row.append(Component.text(" ■").color(NamedTextColor.AQUA))
|
||||
} else {
|
||||
row.append(Component.text(" ■").color(NamedTextColor.GRAY))
|
||||
}
|
||||
}
|
||||
sender.sendMessage(row)
|
||||
}
|
||||
|
||||
// Print the footer of the faction map.
|
||||
sender.sendMessage(Component
|
||||
.text("---------------------------------------")
|
||||
.color(NamedTextColor.GRAY)
|
||||
)
|
||||
}
|
||||
}
|
|
@ -1,27 +1,19 @@
|
|||
//package nl.kallestruik.dtweaks.fakeplayer
|
||||
//
|
||||
//import io.netty.util.concurrent.Future
|
||||
//import io.netty.util.concurrent.GenericFutureListener
|
||||
//
|
||||
//class FakeConnection(
|
||||
// enumProtocolDirection: EnumProtocolDirection
|
||||
//): NetworkManager(enumProtocolDirection) {
|
||||
// var open = true
|
||||
//
|
||||
// // isOpen()
|
||||
// override fun isConnected(): Boolean {
|
||||
// return open
|
||||
// }
|
||||
//
|
||||
// // hasChannel()
|
||||
// override fun i(): Boolean {
|
||||
// return false
|
||||
// }
|
||||
//
|
||||
// override fun sendPacket(packet: Packet<*>?, genericfuturelistener: GenericFutureListener<out Future<in Void?>?>?) {}
|
||||
//
|
||||
// // disableAutoRead()
|
||||
// override fun stopReading() {}
|
||||
//
|
||||
// override fun handleDisconnection() {}
|
||||
//}
|
||||
package nl.kallestruik.dtweaks.fakeplayer
|
||||
|
||||
import io.netty.channel.embedded.EmbeddedChannel
|
||||
import net.minecraft.network.Connection
|
||||
import net.minecraft.network.protocol.PacketFlow
|
||||
|
||||
|
||||
class FakeConnection(
|
||||
packetFlow: PacketFlow
|
||||
): Connection(packetFlow) {
|
||||
|
||||
init {
|
||||
this.channel = EmbeddedChannel()
|
||||
}
|
||||
|
||||
override fun setReadOnly() {}
|
||||
|
||||
override fun handleDisconnection() {}
|
||||
}
|
|
@ -1,79 +1,68 @@
|
|||
//package nl.kallestruik.dtweaks.fakeplayer
|
||||
//
|
||||
//import com.mojang.authlib.GameProfile
|
||||
//import net.minecraft.server.v1_16_R3.*
|
||||
//import nl.kallestruik.dtweaks.DTweaks
|
||||
//import org.bukkit.Location
|
||||
//import org.bukkit.craftbukkit.v1_16_R3.CraftWorld
|
||||
//
|
||||
//class FakePlayer(
|
||||
// minecraftServer: MinecraftServer?,
|
||||
// worldServer: WorldServer?,
|
||||
// gameProfile: GameProfile?,
|
||||
// playerInteractManager: PlayerInteractManager?
|
||||
//): EntityPlayer(minecraftServer, worldServer, gameProfile, playerInteractManager) {
|
||||
// val locale = "en_US"
|
||||
// private var hasStartingPos = false
|
||||
// private var startingX = 0.0
|
||||
// private var startingY = 0.0
|
||||
// private var startingZ = 0.0
|
||||
// private var startingYaw = 0f
|
||||
// private var startingPitch = 0f
|
||||
//
|
||||
// private constructor(
|
||||
// server: MinecraftServer,
|
||||
// worldIn: WorldServer,
|
||||
// profile: GameProfile?,
|
||||
// interactionManagerIn: PlayerInteractManager,
|
||||
// x: Double,
|
||||
// y: Double,
|
||||
// z: Double,
|
||||
// yaw: Float,
|
||||
// pitch: Float
|
||||
// ) : this(server, worldIn, profile, interactionManagerIn) {
|
||||
// this.hasStartingPos = true
|
||||
// this.startingX = x
|
||||
// this.startingY = y
|
||||
// this.startingZ = z
|
||||
// this.startingYaw = yaw
|
||||
// this.startingPitch = pitch
|
||||
// applyStartingPosition()
|
||||
// }
|
||||
//
|
||||
// companion object {
|
||||
// fun atLocation(location: Location, name: String?): FakePlayer? {
|
||||
// // Split the location into its parts for use later.
|
||||
// val x = location.x
|
||||
// val y = location.y
|
||||
// val z = location.z
|
||||
// val yaw = location.yaw.toDouble()
|
||||
// val pitch = location.pitch.toDouble()
|
||||
// try {
|
||||
// // Get the minecraft server instance.
|
||||
// val minecraftServer = MinecraftServer.getServer()
|
||||
// // Create an empty variable for the world server.
|
||||
// val worldServer = (location.world as CraftWorld).handle
|
||||
// // Get the game profile from the cache (or retrieve it if it is not cached)
|
||||
// var gameProfile = minecraftServer.userCache.getProfile(name) ?: return null
|
||||
// if (gameProfile.properties.containsKey("textures")) {
|
||||
// gameProfile = TileEntitySkull.b(gameProfile, null, true).get()
|
||||
// }
|
||||
//
|
||||
// // Create a player interact manager using the world server.
|
||||
// val playerInteractManager = PlayerInteractManager(worldServer)
|
||||
//
|
||||
// // Create an instance of our fake player.
|
||||
// val instance = FakePlayer(
|
||||
// minecraftServer, worldServer, gameProfile, playerInteractManager, x, y, z,
|
||||
// yaw.toFloat(),
|
||||
// pitch.toFloat()
|
||||
// )
|
||||
// // Create a fake connection for our fake player.
|
||||
// val connection = FakeConnection(EnumProtocolDirection.SERVERBOUND)
|
||||
//
|
||||
// // Set access to connected channels so we can add our own connection.
|
||||
// val serverConnection = minecraftServer.serverConnection
|
||||
//
|
||||
package nl.kallestruik.dtweaks.fakeplayer
|
||||
|
||||
import com.mojang.authlib.GameProfile
|
||||
import net.minecraft.network.chat.TextComponent
|
||||
import net.minecraft.network.protocol.PacketFlow
|
||||
import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket
|
||||
import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.TickTask
|
||||
import net.minecraft.server.level.ServerLevel
|
||||
import net.minecraft.server.level.ServerPlayer
|
||||
import net.minecraft.world.damagesource.DamageSource
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.food.FoodData
|
||||
import net.minecraft.world.level.block.entity.SkullBlockEntity
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class FakePlayer(
|
||||
server: MinecraftServer,
|
||||
val serverLevel: ServerLevel,
|
||||
gameProfile: GameProfile
|
||||
): ServerPlayer(server, serverLevel, gameProfile) {
|
||||
val locale = "en_US"
|
||||
|
||||
companion object {
|
||||
fun atLocation(location: Location, name: String): FakePlayer? {
|
||||
// Get the minecraft server instance.
|
||||
val minecraftServer = MinecraftServer.getServer()
|
||||
// Get the world
|
||||
val serverLevel = (location.world as CraftWorld).handle
|
||||
// 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
|
||||
if (gameProfile.properties.containsKey("textures")) {
|
||||
val result = AtomicReference<GameProfile>()
|
||||
SkullBlockEntity.updateGameprofile(gameProfile, result::set)
|
||||
gameProfile = result.get()
|
||||
}
|
||||
|
||||
// Create an instance of our fake player.
|
||||
val instance = FakePlayer(minecraftServer, serverLevel, gameProfile)
|
||||
|
||||
// Create a fake connection for our fake player.
|
||||
val connection = FakeConnection(PacketFlow.SERVERBOUND)
|
||||
FakePlayerList.placeNewPlayer(minecraftServer.playerList, minecraftServer, connection, instance)
|
||||
|
||||
instance.respawn()
|
||||
instance.teleportTo(serverLevel, location.x, location.y, location.z, location.yaw, location.pitch)
|
||||
instance.dead = false
|
||||
instance.heal(instance.maxHealth)
|
||||
instance.unsetRemoved()
|
||||
instance.maxUpStep = 0.6F
|
||||
|
||||
minecraftServer.playerList.broadcastAll(
|
||||
ClientboundRotateHeadPacket(
|
||||
instance,
|
||||
(instance.yHeadRot * 256 / 360).toInt().toByte()
|
||||
), serverLevel.dimension())
|
||||
|
||||
minecraftServer.playerList.broadcastAll(ClientboundTeleportEntityPacket(instance), serverLevel.dimension())
|
||||
|
||||
instance.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, 0x7f)
|
||||
return instance
|
||||
|
||||
// (DTweaks.reflectionUtil.getValueFromField(
|
||||
// serverConnection!!,
|
||||
// "connectedChannels"
|
||||
|
@ -126,43 +115,36 @@
|
|||
// instance.worldServer.getChunkProvider().movePlayer(instance)
|
||||
// // bp == PLAYER_MODEL_PARTS
|
||||
// instance.datawatcher.set<Byte>(bj, 0x7f.toByte()) // show all model layers (incl. capes)
|
||||
// return instance
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// return null
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// fun applyStartingPosition() {
|
||||
// if (hasStartingPos) {
|
||||
// this.setPositionRotation(startingX, startingY, startingZ, startingYaw, startingPitch)
|
||||
// mot = Vec3D(0.0, 0.0, 0.0)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
//
|
||||
// override fun killEntity() {
|
||||
// server.a(TickTask(server.ai()) { playerConnection.a(ChatComponentText("Killed")) })
|
||||
// }
|
||||
//
|
||||
// override fun tick() {
|
||||
// super.tick()
|
||||
// if (H()) {
|
||||
// I()
|
||||
// }
|
||||
// movementTick()
|
||||
// if (server.ai() % 10 == 0) {
|
||||
// playerConnection.syncPosition()
|
||||
// this.worldServer.getChunkProvider().movePlayer(this)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
}
|
||||
}
|
||||
|
||||
override fun kill() {
|
||||
server.tell(TickTask(server.tickCount) {connection.onDisconnect(TextComponent("Killed"))})
|
||||
}
|
||||
|
||||
override fun die(source: DamageSource) {
|
||||
super.die(source)
|
||||
heal(maxHealth)
|
||||
foodData = FoodData(this)
|
||||
kill()
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
super.tick()
|
||||
|
||||
if (server.tickCount % 10 == 0) {
|
||||
connection.resetPosition()
|
||||
serverLevel.chunkSource.move(this)
|
||||
hasChangedDimension()
|
||||
}
|
||||
}
|
||||
|
||||
// override fun die(cause: DamageSource?) {
|
||||
// super.die(cause)
|
||||
// health = 20f
|
||||
// foodData = FoodMetaData(this)
|
||||
// killEntity()
|
||||
// }
|
||||
//}
|
||||
|
||||
override fun getIpAddress() = "127.0.0.1"
|
||||
}
|
|
@ -1,36 +1,31 @@
|
|||
//package nl.kallestruik.dtweaks.fakeplayer
|
||||
//
|
||||
//import net.minecraft.server.v1_16_R3.*
|
||||
//import nl.kallestruik.dtweaks.DTweaks
|
||||
//import java.lang.reflect.Field
|
||||
//
|
||||
//class FakePlayerConnection(
|
||||
// minecraftServer: MinecraftServer,
|
||||
// networkManager: NetworkManager,
|
||||
// entityPlayer: EntityPlayer
|
||||
//): PlayerConnection(minecraftServer, networkManager, entityPlayer) {
|
||||
// override fun sendPacket(packet: Packet<*>?) {
|
||||
// if (packet is PacketPlayOutKeepAlive) {
|
||||
// val pong = PacketPlayInKeepAlive()
|
||||
// try {
|
||||
// val pingId: Field = DTweaks.reflectionUtil.getField(PacketPlayOutKeepAlive::class.java, "a")
|
||||
// val pongId: Field = DTweaks.reflectionUtil.getField(PacketPlayInKeepAlive::class.java, "a")
|
||||
// pingId.isAccessible = true
|
||||
// pongId.isAccessible = true
|
||||
// pongId[pong] = pingId[packet]
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// this.a(pong)
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// override fun disconnect(message: String?) {
|
||||
// player.killEntity()
|
||||
// }
|
||||
//
|
||||
// override fun a(disconnectReason: IChatBaseComponent?) {
|
||||
// super.a(disconnectReason)
|
||||
// (this.a() as FakeConnection).open = false
|
||||
// }
|
||||
//}
|
||||
package nl.kallestruik.dtweaks.fakeplayer
|
||||
|
||||
import io.netty.util.concurrent.Future
|
||||
import io.netty.util.concurrent.GenericFutureListener
|
||||
import net.minecraft.network.chat.Component
|
||||
import net.minecraft.network.chat.TranslatableComponent
|
||||
import net.minecraft.network.protocol.Packet
|
||||
import net.minecraft.server.MinecraftServer
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl
|
||||
import javax.annotation.Nullable
|
||||
|
||||
class FakePlayerConnection(
|
||||
minecraftServer: MinecraftServer,
|
||||
connection: FakeConnection,
|
||||
player: FakePlayer
|
||||
): ServerGamePacketListenerImpl(minecraftServer, connection, player) {
|
||||
override fun send(packetIn: Packet<*>?) {}
|
||||
override fun send(packet: Packet<*>, listener: GenericFutureListener<out Future<in Void>>?) {}
|
||||
|
||||
override fun disconnect(message: Component) {
|
||||
if (message is TranslatableComponent && (message.key.equals("multiplayer.disconnect.idling") || message.equals("multiplayer.disconnect.duplicate_login")))
|
||||
{
|
||||
player.kill()
|
||||
}
|
||||
}
|
||||
|
||||
override fun tick() {
|
||||
println("Tick for ${player.name}")
|
||||
super.tick()
|
||||
}
|
||||
}
|
|
@ -1,258 +1,165 @@
|
|||
//package nl.kallestruik.dtweaks.fakeplayer
|
||||
//
|
||||
//import com.mojang.serialization.DataResult
|
||||
//import com.mojang.serialization.Dynamic
|
||||
//import io.netty.buffer.Unpooled
|
||||
//import net.minecraft.server.v1_16_R3.*
|
||||
//import nl.kallestruik.dtweaks.DTweaks
|
||||
//import org.apache.logging.log4j.Logger
|
||||
//import org.bukkit.Bukkit
|
||||
//import org.bukkit.craftbukkit.v1_16_R3.CraftWorld
|
||||
//import org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage
|
||||
//import org.bukkit.entity.Player
|
||||
//import org.spigotmc.event.player.PlayerSpawnLocationEvent
|
||||
//import java.util.*
|
||||
//
|
||||
//object FakePlayerList {
|
||||
// fun a(playerList: PlayerList, networkManager: NetworkManager, entityPlayer: EntityPlayer) {
|
||||
// // Setup what are normally class level variables
|
||||
// val server = DTweaks.reflectionUtil.getValueFromField(playerList, "server") as MinecraftServer
|
||||
// val LOGGER = DTweaks.reflectionUtil.getValueFromField(playerList, "LOGGER") as Logger
|
||||
//
|
||||
// val gameProfile = entityPlayer.profile
|
||||
// val userCache = server.userCache
|
||||
// val oldGameProfile = userCache.getProfile(gameProfile.id)
|
||||
// var oldName = if (oldGameProfile == null) gameProfile.name else oldGameProfile.name
|
||||
//
|
||||
// userCache.a(gameProfile)
|
||||
// val playerData = playerList.a(entityPlayer)
|
||||
// if (playerData != null && playerData.hasKey("bukkit")) {
|
||||
// val bukkit = playerData.getCompound("bukkit")
|
||||
// oldName = if (bukkit.hasKeyOfType("lastKnownName", 8)) bukkit.getString("lastKnownName") else oldName
|
||||
// }
|
||||
// val worldKey: ResourceKey<World> = if (playerData != null) {
|
||||
// val dataResult: DataResult<ResourceKey<World>> = DimensionManager.a(
|
||||
// Dynamic(
|
||||
// DynamicOpsNBT.a,
|
||||
// playerData["Dimension"]
|
||||
// )
|
||||
// )
|
||||
// dataResult.resultOrPartial { o -> LOGGER.error(o) }
|
||||
// .orElse(World.OVERWORLD) as ResourceKey<World>
|
||||
// } else {
|
||||
// World.OVERWORLD
|
||||
// }
|
||||
// var worldServer = server.getWorldServer(worldKey) ?: server.E()
|
||||
//
|
||||
// entityPlayer.spawnIn(worldServer)
|
||||
// entityPlayer.playerInteractManager.a(entityPlayer.world as WorldServer)
|
||||
// var s1 = "local"
|
||||
// if (networkManager.getSocketAddress() != null) {
|
||||
// s1 = networkManager.getSocketAddress().toString()
|
||||
// }
|
||||
// val bukkitPlayer: Player = entityPlayer.bukkitEntity
|
||||
// val ev = PlayerSpawnLocationEvent(bukkitPlayer, bukkitPlayer.location)
|
||||
// Bukkit.getPluginManager().callEvent(ev)
|
||||
// val loc = ev.spawnLocation
|
||||
// worldServer = (loc.world as CraftWorld).handle
|
||||
// entityPlayer.spawnIn(worldServer)
|
||||
// entityPlayer.playerInteractManager.a(entityPlayer.world as WorldServer)
|
||||
// entityPlayer.setPosition(loc.x, loc.y, loc.z)
|
||||
//
|
||||
// //entityplayer.setYawPitch(loc.getYaw(), loc.getPitch());
|
||||
// try {
|
||||
// val setYawPitch = Entity::class.java.getDeclaredMethod(
|
||||
// "setYawPitch",
|
||||
// Float::class.javaPrimitiveType,
|
||||
// Float::class.javaPrimitiveType
|
||||
// )
|
||||
// setYawPitch.isAccessible = true
|
||||
// setYawPitch.invoke(entityPlayer, loc.yaw, loc.pitch)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// val worldData = worldServer.getWorldData()
|
||||
//
|
||||
// //playerList.a(entityplayer, (EntityPlayer)null, worldserver1);
|
||||
// try {
|
||||
// val a = PlayerList::class.java.getDeclaredMethod(
|
||||
// "a",
|
||||
// EntityPlayer::class.java,
|
||||
// EntityPlayer::class.java,
|
||||
// WorldServer::class.java
|
||||
// )
|
||||
// a.isAccessible = true
|
||||
// a.invoke(playerList, entityPlayer, null, worldServer)
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
//
|
||||
// //PlayerConnection playerconnection = new PlayerConnection(server, networkmanager, entityplayer);
|
||||
// val playerConnection: PlayerConnection =
|
||||
// (entityPlayer as? FakePlayer)?.let { FakePlayerConnection(server, networkManager, it) }
|
||||
// ?: PlayerConnection(server, networkManager, entityPlayer)
|
||||
// val gameRules = worldServer.gameRules
|
||||
// val doImmediateRespawn = gameRules.getBoolean(GameRules.DO_IMMEDIATE_RESPAWN)
|
||||
// val reducedDebugInfo = gameRules.getBoolean(GameRules.REDUCED_DEBUG_INFO)
|
||||
// try {
|
||||
// playerConnection.sendPacket(
|
||||
// PacketPlayOutLogin(
|
||||
// entityPlayer.id,
|
||||
// entityPlayer.playerInteractManager.gameMode,
|
||||
// entityPlayer.playerInteractManager.c(),
|
||||
// BiomeManager.a(
|
||||
// worldServer.seed
|
||||
// ),
|
||||
// worldData.isHardcore,
|
||||
// server.F(),
|
||||
// DTweaks.reflectionUtil.getValueFromField(playerList, "s") as IRegistryCustom.Dimension,
|
||||
// worldServer.dimensionManager,
|
||||
// worldServer.dimensionKey,
|
||||
// playerList.maxPlayers,
|
||||
// worldServer.spigotConfig.viewDistance,
|
||||
// reducedDebugInfo,
|
||||
// !doImmediateRespawn,
|
||||
// worldServer.isDebugWorld,
|
||||
// worldServer.isFlatWorld
|
||||
// )
|
||||
// )
|
||||
// } catch (e: Exception) {
|
||||
// e.printStackTrace()
|
||||
// }
|
||||
// entityPlayer.bukkitEntity.sendSupportedChannels()
|
||||
// playerConnection.sendPacket(
|
||||
// PacketPlayOutCustomPayload(
|
||||
// PacketPlayOutCustomPayload.a,
|
||||
// PacketDataSerializer(Unpooled.buffer()).a(playerList.server.serverModName)
|
||||
// )
|
||||
// )
|
||||
// playerConnection.sendPacket(PacketPlayOutServerDifficulty(worldData.difficulty, worldData.isDifficultyLocked))
|
||||
// playerConnection.sendPacket(PacketPlayOutAbilities(entityPlayer.abilities))
|
||||
// playerConnection.sendPacket(PacketPlayOutHeldItemSlot(entityPlayer.inventory.itemInHandIndex))
|
||||
// playerConnection.sendPacket(PacketPlayOutRecipeUpdate(server.craftingManager.b()))
|
||||
// playerConnection.sendPacket(PacketPlayOutTags(server.tagRegistry))
|
||||
// playerList.d(entityPlayer)
|
||||
// entityPlayer.statisticManager.c()
|
||||
// entityPlayer.recipeBook.a(entityPlayer)
|
||||
// playerList.sendScoreboard(worldServer.scoreboard, entityPlayer)
|
||||
// server.invalidatePingSample()
|
||||
// val chatMessage = if (entityPlayer.profile.name.equals(oldName, ignoreCase = true)) {
|
||||
// ChatMessage("multiplayer.player.joined", entityPlayer.scoreboardDisplayName)
|
||||
// } else {
|
||||
// ChatMessage("multiplayer.player.joined.renamed", entityPlayer.scoreboardDisplayName, oldName)
|
||||
// }
|
||||
// chatMessage.a(EnumChatFormat.YELLOW)
|
||||
// var joinMessage = CraftChatMessage.fromComponent(chatMessage)
|
||||
// playerConnection.a(
|
||||
// entityPlayer.locX(),
|
||||
// entityPlayer.locY(),
|
||||
// entityPlayer.locZ(),
|
||||
// entityPlayer.yaw,
|
||||
// entityPlayer.pitch
|
||||
// )
|
||||
// playerList.players.add(entityPlayer)
|
||||
//
|
||||
// //playerList.playersByName.put(entityplayer.getName().toLowerCase(Locale.ROOT), entityplayer);
|
||||
// val playersByName = DTweaks.reflectionUtil.getValueFromField(playerList, "playersByName") as HashMap<String, EntityPlayer>
|
||||
// playersByName[entityPlayer.name.toLowerCase(Locale.ROOT)] = entityPlayer
|
||||
//
|
||||
// //playerList.j.put(entityplayer.getUniqueID(), entityplayer);
|
||||
// val playersByUUID = DTweaks.reflectionUtil.getValueFromField(playerList, "j") as HashMap<UUID, EntityPlayer>
|
||||
// playersByUUID[entityPlayer.uniqueID] = entityPlayer
|
||||
//
|
||||
// if (entityPlayer.playerConnection.networkManager.isConnected) {
|
||||
// var i: Int
|
||||
// if (joinMessage != null && joinMessage.isNotEmpty()) {
|
||||
// var var27: Array<IChatBaseComponent?>
|
||||
// val var26 = CraftChatMessage.fromString(joinMessage).also { var27 = it }.size
|
||||
// i = 0
|
||||
// while (i < var26) {
|
||||
// val line = var27[i]
|
||||
// server.playerList.sendAll(PacketPlayOutChat(line, ChatMessageType.SYSTEM, SystemUtils.b))
|
||||
// ++i
|
||||
// }
|
||||
// }
|
||||
// val packet = PacketPlayOutPlayerInfo(PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER, entityPlayer)
|
||||
// for (player in playerList.players) {
|
||||
// if (player.bukkitEntity.canSee(entityPlayer.bukkitEntity)) {
|
||||
// player.playerConnection.sendPacket(packet)
|
||||
// }
|
||||
// if (entityPlayer.bukkitEntity.canSee(player.bukkitEntity)) {
|
||||
// entityPlayer.playerConnection.sendPacket(
|
||||
// PacketPlayOutPlayerInfo(
|
||||
// PacketPlayOutPlayerInfo.EnumPlayerInfoAction.ADD_PLAYER,
|
||||
// player
|
||||
// )
|
||||
package nl.kallestruik.dtweaks.fakeplayer
|
||||
|
||||
import com.destroystokyo.paper.PaperConfig
|
||||
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 net.minecraft.nbt.CompoundTag
|
||||
import net.minecraft.nbt.NbtOps
|
||||
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.*
|
||||
import net.minecraft.server.level.ChunkHolder.ChunkLoadingFailure
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl
|
||||
import net.minecraft.server.players.GameProfileCache
|
||||
import net.minecraft.server.players.PlayerList
|
||||
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 nl.kallestruik.dtweaks.DTweaks
|
||||
import org.apache.logging.log4j.Logger
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.craftbukkit.v1_18_R1.CraftWorld
|
||||
import org.bukkit.entity.Player
|
||||
import org.spigotmc.event.player.PlayerSpawnLocationEvent
|
||||
import java.util.*
|
||||
import java.util.concurrent.CompletableFuture
|
||||
import java.util.function.Consumer
|
||||
|
||||
object FakePlayerList {
|
||||
fun placeNewPlayer(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.addTicketAtLevel(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
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
// entityPlayer.sentListPacket = true
|
||||
// entityPlayer.playerConnection.sendPacket(
|
||||
// PacketPlayOutEntityMetadata(
|
||||
// entityPlayer.id,
|
||||
// DTweaks.reflectionUtil.getValueFromField(entityPlayer, "datawatcher") as DataWatcher, true
|
||||
// )
|
||||
// )
|
||||
// }.thenAccept {
|
||||
//
|
||||
// if (entityPlayer.world === worldServer && !worldServer.getPlayers().contains(entityPlayer)) {
|
||||
// worldServer.addPlayerJoin(entityPlayer)
|
||||
// server.bossBattleCustomData.a(entityPlayer)
|
||||
// }
|
||||
//
|
||||
// worldServer = entityPlayer.worldServer
|
||||
// playerList.a(entityPlayer, worldServer)
|
||||
// if (server.resourcePack.isNotEmpty()) {
|
||||
// entityPlayer.setResourcePack(server.resourcePack, server.resourcePackHash)
|
||||
// }
|
||||
//
|
||||
// for (mobEffect in entityPlayer.getEffects()) {
|
||||
// playerConnection.sendPacket(PacketPlayOutEntityEffect(entityPlayer.id, mobEffect))
|
||||
// }
|
||||
//
|
||||
// if (playerData != null && playerData.hasKeyOfType("RootVehicle", 10)) {
|
||||
// val rootVehicleData = playerData.getCompound("RootVehicle")
|
||||
// val entity = EntityTypes.a(
|
||||
// rootVehicleData.getCompound("Entity"), worldServer
|
||||
// ) { entity1x: Entity? ->
|
||||
// if (!worldServer.addEntitySerialized(entity1x)
|
||||
// ) null else entity1x
|
||||
// }
|
||||
// if (entity != null) {
|
||||
// val uuid: UUID? = if (rootVehicleData.b("Attach")) {
|
||||
// rootVehicleData.a("Attach")
|
||||
// } else {
|
||||
// null
|
||||
// }
|
||||
// if (entity.uniqueID == uuid) {
|
||||
// entityPlayer.a(entity, true)
|
||||
// } else {
|
||||
// for (passenger in entity.allPassengers) {
|
||||
// if (passenger.uniqueID == uuid) {
|
||||
// entityPlayer.a(passenger, true)
|
||||
// break
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// if (!entityPlayer.isPassenger) {
|
||||
// LOGGER.warn("Couldn't reattach entity to player")
|
||||
// worldServer.removeEntity(entity)
|
||||
// for (passenger in entity.allPassengers) {
|
||||
// worldServer.removeEntity(passenger)
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// entityPlayer.syncInventory()
|
||||
// LOGGER.info(
|
||||
// "{}[{}] logged in with entity id {} at ([{}]{}, {}, {})",
|
||||
// entityPlayer.getDisplayName().string,
|
||||
// s1,
|
||||
// entityPlayer.id,
|
||||
// worldServer?.worldDataServer?.name,
|
||||
// entityPlayer.locX(),
|
||||
// entityPlayer.locY(),
|
||||
// entityPlayer.locZ()
|
||||
// )
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
}
|
|
@ -1,30 +1,222 @@
|
|||
//package nl.kallestruik.dtweaks.managers
|
||||
package nl.kallestruik.dtweaks.managers
|
||||
|
||||
import net.minecraft.core.Direction
|
||||
import net.minecraft.world.InteractionHand
|
||||
import net.minecraft.world.entity.Entity
|
||||
import net.minecraft.world.level.ClipContext
|
||||
import net.minecraft.world.phys.*
|
||||
import nl.kallestruik.dlib.ReflectionUtil
|
||||
import nl.kallestruik.dtweaks.DTweaks
|
||||
import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Location
|
||||
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftEntity
|
||||
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer
|
||||
import org.bukkit.scheduler.BukkitRunnable
|
||||
import org.bukkit.scheduler.BukkitTask
|
||||
import java.util.function.Predicate
|
||||
|
||||
|
||||
/*
|
||||
A lot of code in this file is inspired by code from carpet mod.
|
||||
Link: https://github.com/gnembon/fabric-carpet
|
||||
*/
|
||||
class FakePlayerManager(
|
||||
val plugin: DTweaks,
|
||||
) {
|
||||
|
||||
init {
|
||||
// Tick all fake players.
|
||||
FakePlayerTickTask().runTaskTimer(plugin, 10, 10)
|
||||
}
|
||||
|
||||
fun getPlayerByName(name: String): FakePlayer? {
|
||||
val player = Bukkit.getPlayer(name)
|
||||
if (player == null || !player.isOnline) return null
|
||||
return (player as CraftPlayer).handle as? FakePlayer
|
||||
}
|
||||
|
||||
fun toFakePlayer(entity: org.bukkit.entity.Entity): FakePlayer? {
|
||||
return (entity as CraftEntity).handle as? FakePlayer
|
||||
}
|
||||
|
||||
fun spawnFakePlayer(loc: Location, name: String) {
|
||||
val player = Bukkit.getPlayer(name)
|
||||
if (player != null && player.isOnline) return
|
||||
FakePlayer.atLocation(loc, name)
|
||||
}
|
||||
|
||||
fun killFakePlayer(name: String) {
|
||||
getPlayerByName(name)?.kill()
|
||||
}
|
||||
|
||||
fun killAllFakePlayers() {
|
||||
for (player in Bukkit.getOnlinePlayers()) {
|
||||
if (!player.isOnline) continue
|
||||
val fakePlayer = (player as CraftPlayer).handle as? FakePlayer ?: continue
|
||||
fakePlayer.kill()
|
||||
}
|
||||
}
|
||||
|
||||
private fun tickAll() {
|
||||
for (player in Bukkit.getOnlinePlayers()) {
|
||||
if (!player.isOnline) continue
|
||||
val fakePlayer = (player as CraftPlayer).handle as? FakePlayer ?: continue
|
||||
fakePlayer.doTick()
|
||||
}
|
||||
}
|
||||
|
||||
// fun attackInterval(name: String, interval: Int) {
|
||||
//
|
||||
//import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
|
||||
//import org.bukkit.Bukkit
|
||||
//import org.bukkit.Location
|
||||
//import org.bukkit.craftbukkit.v1_16_R3.entity.CraftPlayer
|
||||
//
|
||||
//class FakePlayerManager {
|
||||
//
|
||||
// fun spawnFakePlayer(loc: Location, name: String) {
|
||||
// val player = Bukkit.getPlayer(name)
|
||||
// if (player != null && player.isOnline) return
|
||||
// FakePlayer.atLocation(loc, name)
|
||||
// fakePlayer.swing()
|
||||
// }
|
||||
//
|
||||
// fun killFakePlayer(name: String) {
|
||||
// val player = Bukkit.getPlayer(name)
|
||||
// if (player == null || !player.isOnline) return
|
||||
// val entityPlayer = (player as CraftPlayer).handle as? FakePlayer ?: return
|
||||
// entityPlayer.killEntity()
|
||||
// }
|
||||
//
|
||||
// fun killAllFakePlayers() {
|
||||
// for (player in Bukkit.getOnlinePlayers()) {
|
||||
// if (!player.isOnline) continue
|
||||
// val entityPlayer = (player as CraftPlayer).handle as? FakePlayer ?: continue
|
||||
// entityPlayer.killEntity()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
fun attack(name: String) {
|
||||
val player = getPlayerByName(name) ?: return
|
||||
val target = getTarget(player) ?: return
|
||||
|
||||
when (target.type) {
|
||||
HitResult.Type.BLOCK -> {/*TODO: Not implemented*/}
|
||||
HitResult.Type.ENTITY -> {
|
||||
if (target !is EntityHitResult) return
|
||||
|
||||
player.attack(target.entity);
|
||||
player.swing(InteractionHand.MAIN_HAND);
|
||||
player.resetLastActionTime();
|
||||
}
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
fun use(name: String) {
|
||||
val player = getPlayerByName(name) ?: return
|
||||
val target = getTarget(player) ?: return
|
||||
|
||||
for (hand in InteractionHand.values()) {
|
||||
when (target.type) {
|
||||
HitResult.Type.BLOCK -> {
|
||||
if (target !is BlockHitResult) return
|
||||
|
||||
player.resetLastActionTime()
|
||||
val world = player.getLevel()
|
||||
val pos = target.blockPos
|
||||
val side = target.direction
|
||||
if (pos.y < player.getLevel().maxBuildHeight - (if (side === Direction.UP) 1 else 0)
|
||||
&& world.mayInteract(player, pos)) {
|
||||
val result = player.gameMode.useItemOn(player, world, player.getItemInHand(hand), hand, target)
|
||||
if (result.consumesAction()) {
|
||||
if (result.shouldSwing()) player.swing(hand)
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
HitResult.Type.ENTITY -> {
|
||||
if (target !is EntityHitResult) return
|
||||
|
||||
player.resetLastActionTime()
|
||||
val entity = target.entity
|
||||
val relativeHitPos: Vec3 = target.getLocation().subtract(entity.x, entity.y, entity.z)
|
||||
|
||||
entity.interactAt(player, relativeHitPos, hand).consumesAction()
|
||||
|
||||
// fix for SS itemframe always returns CONSUME even if no action is performed
|
||||
player.interactOn(entity, hand).consumesAction()
|
||||
}
|
||||
}
|
||||
|
||||
player.gameMode.useItem(player, player.getLevel(), player.getItemInHand(hand), hand)
|
||||
}
|
||||
}
|
||||
|
||||
//
|
||||
// Ray tracing code borrowed from carpet mod: https://github.com/gnembon/fabric-carpet/blob/master/src/main/java/carpet/helpers/Tracer.java
|
||||
//
|
||||
|
||||
fun getTarget(player: FakePlayer): HitResult? {
|
||||
val reach: Double = if (player.gameMode.isCreative) 5.0 else 4.5f.toDouble()
|
||||
return rayTrace(player, 1F, reach, false)
|
||||
}
|
||||
|
||||
fun rayTrace(source: FakePlayer, partialTicks: Float, reach: Double, fluids: Boolean): HitResult? {
|
||||
val blockHit = rayTraceBlocks(source, partialTicks, reach, fluids)
|
||||
var maxSqDist = reach * reach
|
||||
if (blockHit != null) {
|
||||
maxSqDist = blockHit.location.distanceToSqr(source.getEyePosition(partialTicks))
|
||||
}
|
||||
val entityHit = rayTraceEntities(source, partialTicks, reach, maxSqDist)
|
||||
return entityHit ?: blockHit
|
||||
}
|
||||
|
||||
fun rayTraceBlocks(source: FakePlayer, partialTicks: Float, reach: Double, fluids: Boolean): BlockHitResult? {
|
||||
val pos: Vec3 = source.getEyePosition(partialTicks)
|
||||
val rotation: Vec3 = source.getViewVector(partialTicks)
|
||||
val reachEnd = pos.add(rotation.x * reach, rotation.y * reach, rotation.z * reach)
|
||||
return source.level.clip(
|
||||
ClipContext(
|
||||
pos,
|
||||
reachEnd,
|
||||
ClipContext.Block.OUTLINE,
|
||||
if (fluids) ClipContext.Fluid.ANY else ClipContext.Fluid.NONE,
|
||||
source
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
fun rayTraceEntities(source: FakePlayer, partialTicks: Float, reach: Double, maxSqDist: Double): EntityHitResult? {
|
||||
val pos = source.getEyePosition(partialTicks)
|
||||
val reachVec = source.getViewVector(partialTicks).scale(reach)
|
||||
val box = source.boundingBox.expandTowards(reachVec).inflate(1.0)
|
||||
return rayTraceEntities(source, pos, pos.add(reachVec), box, maxSqDist) {
|
||||
e -> !e.isSpectator && e.isPickable
|
||||
}
|
||||
}
|
||||
|
||||
fun rayTraceEntities(
|
||||
source: FakePlayer,
|
||||
start: Vec3,
|
||||
end: Vec3,
|
||||
box: AABB,
|
||||
maxSqDistance: Double,
|
||||
predicate: Predicate<Entity>,
|
||||
): EntityHitResult? {
|
||||
val world = source.level
|
||||
var targetDistance = maxSqDistance
|
||||
var target: Entity? = null
|
||||
var targetHitPos: Vec3? = null
|
||||
for (current in world.getEntities(source, box, predicate)) {
|
||||
val currentBox = current.boundingBox.inflate(current.pickRadius.toDouble())
|
||||
val currentHit = currentBox.clip(start, end)
|
||||
if (currentBox.contains(start)) {
|
||||
if (targetDistance >= 0) {
|
||||
target = current
|
||||
targetHitPos = currentHit.orElse(start)
|
||||
targetDistance = 0.0
|
||||
}
|
||||
} else if (currentHit.isPresent) {
|
||||
val currentHitPos: Vec3 = currentHit.get()
|
||||
val currentDistance = start.distanceToSqr(currentHitPos)
|
||||
if (currentDistance < targetDistance || targetDistance == 0.0) {
|
||||
if (current.rootVehicle === source.rootVehicle) {
|
||||
if (targetDistance == 0.0) {
|
||||
target = current
|
||||
targetHitPos = currentHitPos
|
||||
}
|
||||
} else {
|
||||
target = current
|
||||
targetHitPos = currentHitPos
|
||||
targetDistance = currentDistance
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return if (target == null) null else EntityHitResult(target, targetHitPos!!)
|
||||
}
|
||||
|
||||
inner class FakePlayerTickTask: BukkitRunnable() {
|
||||
override fun run() {
|
||||
tickAll()
|
||||
}
|
||||
|
||||
}
|
||||
}
|
|
@ -0,0 +1,70 @@
|
|||
package nl.kallestruik.dtweaks.managers
|
||||
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.configuration.InvalidConfigurationException
|
||||
import org.bukkit.configuration.file.YamlConfiguration
|
||||
import java.io.File
|
||||
import java.io.IOException
|
||||
|
||||
class NoSpawnZoneManager {
|
||||
lateinit var file: File
|
||||
var noSpawnZones: MutableMap<NamespacedKey, MutableSet<Pair<Int, Int>>> = mutableMapOf()
|
||||
|
||||
@Throws(IOException::class, InvalidConfigurationException::class)
|
||||
fun loadFromFile(file: File) {
|
||||
this.file = file
|
||||
file.parentFile.mkdirs()
|
||||
file.createNewFile()
|
||||
val config = YamlConfiguration()
|
||||
config.load(file)
|
||||
noSpawnZones.clear()
|
||||
|
||||
for (world in config.getKeys(false)) {
|
||||
val worldKey = NamespacedKey.fromString(world)!!
|
||||
noSpawnZones[worldKey] = mutableSetOf()
|
||||
for (item in config.getStringList(world)) {
|
||||
val parts = item.split(":")
|
||||
if (parts.size != 2)
|
||||
continue
|
||||
|
||||
noSpawnZones[worldKey]?.add(Pair(parts[0].toInt(), parts[1].toInt()))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Throws(IOException::class, InvalidConfigurationException::class)
|
||||
fun saveToFile() {
|
||||
file.parentFile.mkdirs()
|
||||
file.createNewFile()
|
||||
val config = YamlConfiguration()
|
||||
config.load(file)
|
||||
|
||||
for (entry in noSpawnZones) {
|
||||
val world = entry.key.toString()
|
||||
val list = mutableListOf<String>()
|
||||
for (chunk in entry.value) {
|
||||
list.add("${chunk.first}:${chunk.second}")
|
||||
}
|
||||
|
||||
config[world] = list
|
||||
}
|
||||
|
||||
config.save(file)
|
||||
}
|
||||
|
||||
fun isChunkClaimed(x: Int, z: Int, world: NamespacedKey): Boolean {
|
||||
return noSpawnZones[world]?.contains(Pair(x, z)) ?: false
|
||||
}
|
||||
|
||||
fun claimChunk(x: Int, z: Int, world: NamespacedKey) {
|
||||
val chunks = noSpawnZones.getOrDefault(world, mutableSetOf())
|
||||
chunks.add(Pair(x, z))
|
||||
noSpawnZones[world] = chunks
|
||||
}
|
||||
|
||||
fun unclaimChunk(x: Int, z: Int, world: NamespacedKey) {
|
||||
val chunks = noSpawnZones.getOrDefault(world, mutableSetOf())
|
||||
chunks.remove(Pair(x, z))
|
||||
noSpawnZones[world] = chunks
|
||||
}
|
||||
}
|
|
@ -0,0 +1,51 @@
|
|||
package nl.kallestruik.dtweaks.tweaks.craftingtweaks
|
||||
|
||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.ShapedRecipe
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
|
||||
class CraftableChainmail(
|
||||
private val plugin: JavaPlugin
|
||||
): ITweak {
|
||||
private var helmetRecipeKey = NamespacedKey(plugin, "chainmail_helmet")
|
||||
private var chestplateRecipeKey = NamespacedKey(plugin, "chainmail_chestplate")
|
||||
private var leggingsRecipeKey = NamespacedKey(plugin, "chainmail_leggings")
|
||||
private var bootsRecipeKey = NamespacedKey(plugin, "chainmail_boots")
|
||||
|
||||
override fun getIdentifier(): String = "CraftableChainmail"
|
||||
override fun getCategories(): List<String> = listOf("crafting", "survival")
|
||||
|
||||
override fun onEnable() {
|
||||
val helmetRecipe = ShapedRecipe(helmetRecipeKey, ItemStack(Material.CHAINMAIL_HELMET))
|
||||
helmetRecipe.shape("CCC", "C C")
|
||||
helmetRecipe.setIngredient('C', Material.CHAIN)
|
||||
|
||||
val chestplateRecipe = ShapedRecipe(chestplateRecipeKey, ItemStack(Material.CHAINMAIL_CHESTPLATE))
|
||||
chestplateRecipe.shape("C C", "CCC", "CCC")
|
||||
chestplateRecipe.setIngredient('C', Material.CHAIN)
|
||||
|
||||
val leggingsRecipe = ShapedRecipe(leggingsRecipeKey, ItemStack(Material.CHAINMAIL_LEGGINGS))
|
||||
leggingsRecipe.shape("CCC", "C C", "C C")
|
||||
leggingsRecipe.setIngredient('C', Material.CHAIN)
|
||||
|
||||
val bootsRecipe = ShapedRecipe(bootsRecipeKey, ItemStack(Material.CHAINMAIL_BOOTS))
|
||||
bootsRecipe.shape("C C", "C C")
|
||||
bootsRecipe.setIngredient('C', Material.CHAIN)
|
||||
|
||||
plugin.server.addRecipe(helmetRecipe)
|
||||
plugin.server.addRecipe(chestplateRecipe)
|
||||
plugin.server.addRecipe(leggingsRecipe)
|
||||
plugin.server.addRecipe(bootsRecipe)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
plugin.server.removeRecipe(helmetRecipeKey)
|
||||
plugin.server.removeRecipe(chestplateRecipeKey)
|
||||
plugin.server.removeRecipe(leggingsRecipeKey)
|
||||
plugin.server.removeRecipe(bootsRecipeKey)
|
||||
}
|
||||
}
|
|
@ -0,0 +1,41 @@
|
|||
package nl.kallestruik.dtweaks.tweaks.craftingtweaks
|
||||
|
||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||
import org.bukkit.Bukkit
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.Tag
|
||||
import org.bukkit.inventory.ItemStack
|
||||
import org.bukkit.inventory.RecipeChoice
|
||||
import org.bukkit.inventory.ShapedRecipe
|
||||
import org.bukkit.inventory.ShapelessRecipe
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
|
||||
class MoreSandstone(
|
||||
private val plugin: JavaPlugin
|
||||
): ITweak {
|
||||
private var normalRecipeKey = NamespacedKey(plugin, "sandstone")
|
||||
private var redRecipeKey = NamespacedKey(plugin, "red_sandstone")
|
||||
|
||||
override fun getIdentifier(): String = "MoreSandstone"
|
||||
override fun getCategories(): List<String> = listOf("crafting", "survival")
|
||||
|
||||
override fun onEnable() {
|
||||
val normalRecipe = ShapedRecipe(normalRecipeKey, ItemStack(Material.SANDSTONE, 4))
|
||||
normalRecipe.shape("ss", "ss")
|
||||
normalRecipe.setIngredient('s', Material.SAND)
|
||||
|
||||
val redRecipe = ShapedRecipe(redRecipeKey, ItemStack(Material.RED_SANDSTONE, 4))
|
||||
redRecipe.shape("ss", "ss")
|
||||
redRecipe.setIngredient('s', Material.RED_SAND)
|
||||
|
||||
plugin.server.addRecipe(normalRecipe)
|
||||
plugin.server.addRecipe(redRecipe)
|
||||
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
plugin.server.removeRecipe(normalRecipeKey)
|
||||
plugin.server.removeRecipe(redRecipeKey)
|
||||
}
|
||||
}
|
|
@ -77,7 +77,7 @@ class RedyeTerracotta(
|
|||
}
|
||||
|
||||
private fun addRecipe(key: NamespacedKey, output: Material, dye: Material) {
|
||||
val recipe = ShapedRecipe(key, ItemStack(output))
|
||||
val recipe = ShapedRecipe(key, ItemStack(output, 8))
|
||||
recipe.shape("TTT", "TDT", "TTT")
|
||||
recipe.setIngredient('T', allTerracotta)
|
||||
recipe.setIngredient('D', dye)
|
||||
|
|
|
@ -0,0 +1,345 @@
|
|||
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
|
||||
}
|
||||
}
|
|
@ -0,0 +1,109 @@
|
|||
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
|
||||
|
||||
import net.kyori.adventure.text.Component
|
||||
import net.kyori.adventure.text.format.NamedTextColor
|
||||
import net.kyori.adventure.text.format.TextDecoration
|
||||
import nl.kallestruik.dtweaks.DTweaks
|
||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||
import org.bukkit.Keyed
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.NamespacedKey
|
||||
import org.bukkit.attribute.Attribute
|
||||
import org.bukkit.attribute.AttributeModifier
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.inventory.PrepareSmithingEvent
|
||||
import org.bukkit.inventory.*
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import java.util.*
|
||||
|
||||
class DyeableNetherite(
|
||||
private val plugin: DTweaks
|
||||
): ITweak, Listener {
|
||||
override fun getIdentifier(): String = "DyeableNetherite"
|
||||
override fun getCategories(): List<String> = listOf("miscellaneous", "survival")
|
||||
|
||||
private val helmetRecipeKey = NamespacedKey(plugin, "dyed_netherite_helmet")
|
||||
private val chestplateRecipeKey = NamespacedKey(plugin, "dyed_netherite_chestplate")
|
||||
private val leggingsRecipeKey = NamespacedKey(plugin, "dyed_netherite_leggings")
|
||||
private val bootsRecipeKey = NamespacedKey(plugin, "dyed_netherite_boots")
|
||||
|
||||
private val helmetStats = ArmorStats(2.0, 3.0, 0.1, EquipmentSlot.HEAD)
|
||||
private val chestplateStats = ArmorStats(5.0, 3.0, 0.1, EquipmentSlot.CHEST)
|
||||
private val leggingsStats = ArmorStats(4.0, 3.0, 0.1, EquipmentSlot.LEGS)
|
||||
private val bootsStats = ArmorStats(2.0, 3.0, 0.1, EquipmentSlot.FEET)
|
||||
|
||||
override fun onEnable() {
|
||||
plugin.server.pluginManager.registerEvents(this, plugin)
|
||||
|
||||
addRecipe(helmetRecipeKey, Material.NETHERITE_HELMET, "Netherite Helmet", Material.LEATHER_HELMET)
|
||||
addRecipe(chestplateRecipeKey, Material.NETHERITE_CHESTPLATE, "Netherite Chestplate", Material.LEATHER_CHESTPLATE)
|
||||
addRecipe(leggingsRecipeKey, Material.NETHERITE_LEGGINGS, "Netherite Leggings", Material.LEATHER_LEGGINGS)
|
||||
addRecipe(bootsRecipeKey, Material.NETHERITE_BOOTS, "Netherite Boots", Material.LEATHER_BOOTS)
|
||||
}
|
||||
|
||||
private fun addRecipe(key: NamespacedKey, sourceMaterial: Material, name: String, resultMaterial: Material) {
|
||||
val resultStack = ItemStack(resultMaterial)
|
||||
resultStack.editMeta { it.displayName(Component.text(name).color(NamedTextColor.WHITE).decoration(TextDecoration.ITALIC, false))}
|
||||
val recipe = SmithingRecipe(key, resultStack, RecipeChoice.MaterialChoice(sourceMaterial), RecipeChoice.MaterialChoice(Material.LEATHER))
|
||||
|
||||
plugin.server.addRecipe(recipe)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
HandlerList.unregisterAll(this)
|
||||
plugin.server.removeRecipe(helmetRecipeKey)
|
||||
plugin.server.removeRecipe(chestplateRecipeKey)
|
||||
plugin.server.removeRecipe(leggingsRecipeKey)
|
||||
plugin.server.removeRecipe(bootsRecipeKey)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onSmith(event: PrepareSmithingEvent) {
|
||||
val recipe = event.inventory.recipe ?: return
|
||||
if (!isDyeableNetheriteRecipe(recipe))
|
||||
return
|
||||
|
||||
val result = event.inventory.result ?: return
|
||||
|
||||
when (result.type) {
|
||||
Material.LEATHER_HELMET -> helmetStats.addToItem(result)
|
||||
Material.LEATHER_CHESTPLATE -> chestplateStats.addToItem(result)
|
||||
Material.LEATHER_LEGGINGS -> leggingsStats.addToItem(result)
|
||||
Material.LEATHER_BOOTS -> bootsStats.addToItem(result)
|
||||
else -> return
|
||||
}
|
||||
|
||||
event.inventory.result = result
|
||||
}
|
||||
|
||||
private fun isDyeableNetheriteRecipe(recipe: Recipe): Boolean {
|
||||
if (recipe !is Keyed)
|
||||
return false
|
||||
|
||||
if (recipe.key.namespace != plugin.getNamespace())
|
||||
return false
|
||||
|
||||
if (!recipe.key.key.startsWith("dyed_netherite_"))
|
||||
return false
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
data class ArmorStats(
|
||||
val armor: Double,
|
||||
val toughness: Double,
|
||||
val knockbackResistance: Double,
|
||||
val slot: EquipmentSlot,
|
||||
) {
|
||||
fun addToItem(item: ItemStack) {
|
||||
item.type = Material.DIAMOND
|
||||
item.editMeta {
|
||||
it.addAttributeModifier(Attribute.GENERIC_ARMOR, AttributeModifier(UUID.randomUUID(), "Armor", armor, AttributeModifier.Operation.ADD_NUMBER, slot))
|
||||
it.addAttributeModifier(Attribute.GENERIC_ARMOR_TOUGHNESS, AttributeModifier(UUID.randomUUID(), "Armor Toughness", toughness, AttributeModifier.Operation.ADD_NUMBER, slot))
|
||||
it.addAttributeModifier(Attribute.GENERIC_KNOCKBACK_RESISTANCE, AttributeModifier(UUID.randomUUID(), "Knockback Resistance", knockbackResistance, AttributeModifier.Operation.ADD_NUMBER, slot))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -1,15 +1,48 @@
|
|||
//package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
|
||||
//
|
||||
//import nl.kallestruik.dtweaks.managers.FakePlayerManager
|
||||
//import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||
//
|
||||
//class FakePlayers(
|
||||
// private val fakePlayerManager: FakePlayerManager
|
||||
//): ITweak {
|
||||
// override fun getIdentifier(): String = "FakePlayers"
|
||||
// override fun getCategories(): List<String> = listOf("players")
|
||||
//
|
||||
// override fun onDisable() {
|
||||
// fakePlayerManager.killAllFakePlayers()
|
||||
// }
|
||||
//}
|
||||
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
|
||||
|
||||
import nl.kallestruik.dtweaks.DTweaks
|
||||
import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
|
||||
import nl.kallestruik.dtweaks.managers.FakePlayerManager
|
||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer
|
||||
import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
|
||||
import org.bukkit.entity.Player
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent
|
||||
import org.bukkit.inventory.EquipmentSlot
|
||||
|
||||
class FakePlayers(
|
||||
private val fakePlayerManager: FakePlayerManager,
|
||||
private val plugin: DTweaks
|
||||
): ITweak, Listener {
|
||||
override fun getIdentifier(): String = "FakePlayers"
|
||||
override fun getCategories(): List<String> = listOf("players")
|
||||
|
||||
override fun onEnable() {
|
||||
plugin.server.pluginManager.registerEvents(this, plugin)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
HandlerList.unregisterAll(this)
|
||||
fakePlayerManager.killAllFakePlayers()
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onRightClickEntity(event: PlayerInteractEntityEvent) {
|
||||
if (event.hand != EquipmentSlot.HAND) return
|
||||
val fakePlayer = event.rightClicked as? Player ?: return
|
||||
|
||||
if ((fakePlayer as CraftPlayer).handle !is FakePlayer) return
|
||||
|
||||
val playerItem = event.player.inventory.itemInMainHand.clone()
|
||||
val fakePlayerItem = fakePlayer.inventory.itemInMainHand.clone()
|
||||
|
||||
event.player.inventory.setItemInMainHand(fakePlayerItem)
|
||||
fakePlayer.inventory.setItemInMainHand(playerItem)
|
||||
|
||||
fakePlayer.handle.tick()
|
||||
}
|
||||
}
|
|
@ -0,0 +1,134 @@
|
|||
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)
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,36 @@
|
|||
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
|
||||
|
||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||
import org.bukkit.Material
|
||||
import org.bukkit.entity.ArmorStand
|
||||
import org.bukkit.event.EventHandler
|
||||
import org.bukkit.event.HandlerList
|
||||
import org.bukkit.event.Listener
|
||||
import org.bukkit.event.block.BlockFadeEvent
|
||||
import org.bukkit.event.block.BlockFromToEvent
|
||||
import org.bukkit.event.player.PlayerInteractAtEntityEvent
|
||||
import org.bukkit.inventory.EquipmentSlot
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
|
||||
class NoMelting(
|
||||
private val plugin: JavaPlugin
|
||||
): ITweak, Listener {
|
||||
override fun getIdentifier(): String = "NoMelting"
|
||||
override fun getCategories(): List<String> = listOf("miscellaneous", "survival")
|
||||
|
||||
override fun onEnable() {
|
||||
plugin.server.pluginManager.registerEvents(this, plugin)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
HandlerList.unregisterAll(this)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onClickEntity(event: BlockFadeEvent) {
|
||||
if (event.block.type != Material.SNOW && event.block.type != Material.ICE)
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
|
@ -0,0 +1,44 @@
|
|||
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.managers.NoSpawnZoneManager
|
||||
import nl.kallestruik.dtweaks.tweaks.ITweak
|
||||
import org.bukkit.craftbukkit.v1_18_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.entity.CreatureSpawnEvent
|
||||
import org.bukkit.event.entity.EntitySpawnEvent
|
||||
import org.bukkit.event.player.PlayerInteractEntityEvent
|
||||
import org.bukkit.plugin.java.JavaPlugin
|
||||
import java.util.concurrent.atomic.AtomicReference
|
||||
|
||||
class NoSpawnZones(
|
||||
private val plugin: JavaPlugin,
|
||||
private val noSpawnZoneManager: NoSpawnZoneManager
|
||||
): ITweak, Listener {
|
||||
override fun getIdentifier(): String = "NoSpawnZones"
|
||||
override fun getCategories(): List<String> = listOf("mobs")
|
||||
|
||||
override fun onEnable() {
|
||||
plugin.server.pluginManager.registerEvents(this, plugin)
|
||||
}
|
||||
|
||||
override fun onDisable() {
|
||||
HandlerList.unregisterAll(this)
|
||||
}
|
||||
|
||||
@EventHandler
|
||||
fun onMobSpawn(event: CreatureSpawnEvent) {
|
||||
if (event.spawnReason != CreatureSpawnEvent.SpawnReason.NATURAL)
|
||||
return
|
||||
|
||||
if (!noSpawnZoneManager.isChunkClaimed(event.location.chunk.x, event.location.chunk.z, event.location.world.key))
|
||||
return
|
||||
|
||||
event.isCancelled = true
|
||||
}
|
||||
}
|
|
@ -11,7 +11,12 @@ commands:
|
|||
player:
|
||||
description: "Interact with fake players."
|
||||
permission: op
|
||||
bundle:
|
||||
description: "Admin command for managing custom bundles."
|
||||
permission: op
|
||||
mobcaps:
|
||||
description: "Display mobcap information from your current dimension."
|
||||
pocketdim:
|
||||
description: "Interact with pocket dimensions. Testing command."
|
||||
spawnzones:
|
||||
description: "Manage no spawn zones"
|
||||
|
|
|
@ -17,8 +17,15 @@ HoesHarvestArea: true
|
|||
FakePlayers: true
|
||||
CarpetBlockPlacingProtocol: true
|
||||
NoDoorBreaking: true
|
||||
NoCreeperGrief: true
|
||||
NoCreeperGrief: false
|
||||
NoEndermanGrief: true
|
||||
SugarcaneBonemealing: true
|
||||
SpaceTimePockets: true
|
||||
VillagerInfo: true
|
||||
BetterBundles: true
|
||||
RedyeTerracotta: true
|
||||
DyeableNetherite: true
|
||||
CraftableChainmail: true
|
||||
NoMelting: true
|
||||
Hammers: true
|
||||
NoSpawnZones: true
|
||||
|
|
|
@ -0,0 +1,106 @@
|
|||
from PIL import Image
|
||||
import os
|
||||
import json
|
||||
|
||||
variants = [
|
||||
{"name": "normal", "data": 0},
|
||||
{"name": "iron", "data": 100},
|
||||
{"name": "gold", "data": 200},
|
||||
{"name": "diamond", "data": 300},
|
||||
{"name": "netherite", "data": 400}
|
||||
]
|
||||
|
||||
colors = [
|
||||
{"name": "black", "data": 0},
|
||||
{"name": "blue", "data": 1},
|
||||
{"name": "brown", "data": 2},
|
||||
{"name": "cyan", "data": 3},
|
||||
{"name": "gray", "data": 4},
|
||||
{"name": "green", "data": 5},
|
||||
{"name": "light_blue", "data": 6},
|
||||
{"name": "light_gray", "data": 7},
|
||||
{"name": "lime", "data": 8},
|
||||
{"name": "magenta", "data": 9},
|
||||
{"name": "orange", "data": 10},
|
||||
{"name": "pink", "data": 11},
|
||||
{"name": "purple", "data": 12},
|
||||
{"name": "red", "data": 13},
|
||||
{"name": "white", "data": 14},
|
||||
{"name": "yellow", "data": 15}
|
||||
]
|
||||
|
||||
COLOR_SRC_DIR = "src/bundles/colors"
|
||||
VARIANT_SRC_DIR = "src/bundles/variants"
|
||||
|
||||
MODEL_OUTPUT_DIR = "out/bundles/models"
|
||||
TEXTURE_OUTPUT_DIR = "out/bundles/textures"
|
||||
|
||||
bundle_model = {
|
||||
"parent": "item/generated",
|
||||
"textures": {
|
||||
"layer0": "item/bundle"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"filled": 0.0000001
|
||||
},
|
||||
"model": "item/bundle_filled"
|
||||
},
|
||||
]
|
||||
}
|
||||
|
||||
for variant in variants:
|
||||
variant_name = variant["name"]
|
||||
variant_data = variant["data"]
|
||||
|
||||
for color in colors:
|
||||
color_name = color["name"]
|
||||
color_data = color["data"]
|
||||
|
||||
color_image = Image.open(f"{COLOR_SRC_DIR}/{color_name}_bundle.png")
|
||||
color_image_filled = Image.open(f"{COLOR_SRC_DIR}/{color_name}_bundle_filled.png")
|
||||
|
||||
variant_image = Image.open(f"{VARIANT_SRC_DIR}/cord_{variant_name}.png")
|
||||
variant_image_filled = Image.open(f"{VARIANT_SRC_DIR}/cord_{variant_name}_filled.png")
|
||||
|
||||
color_image.paste(variant_image, None, variant_image)
|
||||
color_image_filled.paste(variant_image_filled, None, variant_image_filled)
|
||||
|
||||
color_image.save(f"{TEXTURE_OUTPUT_DIR}/{color_name}_{variant_name}_bundle.png")
|
||||
color_image_filled.save(f"{TEXTURE_OUTPUT_DIR}/{color_name}_{variant_name}_bundle_filled.png")
|
||||
|
||||
bundle_model["overrides"].append({
|
||||
"predicate": {
|
||||
"custom_model_data": (variant_data + color_data)
|
||||
},
|
||||
"model": f"item/{color_name}_{variant_name}_bundle"
|
||||
})
|
||||
|
||||
bundle_model["overrides"].append({
|
||||
"predicate": {
|
||||
"filled": 0.0000001,
|
||||
"custom_model_data": variant_data + color_data
|
||||
},
|
||||
"model": f"item/{color_name}_{variant_name}_bundle_filled"
|
||||
})
|
||||
|
||||
with open(f"{MODEL_OUTPUT_DIR}/{color_name}_{variant_name}_bundle.json", "w") as output_file:
|
||||
json.dump({
|
||||
"parent": "item/bundle",
|
||||
"textures": {
|
||||
"layer0": f"item/{color_name}_{variant_name}_bundle"
|
||||
}
|
||||
}, output_file, indent=4)
|
||||
|
||||
with open(f"{MODEL_OUTPUT_DIR}/{color_name}_{variant_name}_bundle_filled.json", "w") as output_file:
|
||||
json.dump({
|
||||
"parent": "item/bundle_filled",
|
||||
"textures": {
|
||||
"layer0": f"item/{color_name}_{variant_name}_bundle_filled"
|
||||
}
|
||||
}, output_file, indent=4)
|
||||
|
||||
|
||||
with open(f"{MODEL_OUTPUT_DIR}/bundle.json", "w") as output_file:
|
||||
json.dump(bundle_model, output_file, indent=4)
|
After Width: | Height: | Size: 412 B |
After Width: | Height: | Size: 367 B |
After Width: | Height: | Size: 428 B |
After Width: | Height: | Size: 372 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 435 B |
After Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 424 B |
After Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 415 B |
After Width: | Height: | Size: 360 B |
After Width: | Height: | Size: 447 B |
After Width: | Height: | Size: 374 B |
After Width: | Height: | Size: 439 B |
After Width: | Height: | Size: 374 B |
After Width: | Height: | Size: 431 B |
After Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 437 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 431 B |
After Width: | Height: | Size: 369 B |
After Width: | Height: | Size: 442 B |
After Width: | Height: | Size: 373 B |
After Width: | Height: | Size: 435 B |
After Width: | Height: | Size: 375 B |
After Width: | Height: | Size: 421 B |
After Width: | Height: | Size: 363 B |
After Width: | Height: | Size: 435 B |
After Width: | Height: | Size: 371 B |
After Width: | Height: | Size: 434 B |
After Width: | Height: | Size: 370 B |
After Width: | Height: | Size: 432 B |
After Width: | Height: | Size: 288 B |
After Width: | Height: | Size: 433 B |
After Width: | Height: | Size: 288 B |
After Width: | Height: | Size: 428 B |
After Width: | Height: | Size: 282 B |
After Width: | Height: | Size: 455 B |
After Width: | Height: | Size: 304 B |
After Width: | Height: | Size: 476 B |
After Width: | Height: | Size: 347 B |
|
@ -0,0 +1,6 @@
|
|||
{
|
||||
"parent": "item/handheld",
|
||||
"textures": {
|
||||
"layer0": "item/diamond_hammer"
|
||||
}
|
||||
}
|
After Width: | Height: | Size: 716 B |
|
@ -0,0 +1,14 @@
|
|||
{
|
||||
"parent": "item/handheld",
|
||||
"textures": {
|
||||
"layer0": "item/diamond_pickaxe"
|
||||
},
|
||||
"overrides": [
|
||||
{
|
||||
"predicate": {
|
||||
"custom_model_data": 1
|
||||
},
|
||||
"model": "item/diamond_hammer"
|
||||
},
|
||||
]
|
||||
}
|