feat: Add Better Bundles, Hammers, No Spawn Zones, No Melting, and More Sandstone tweaks

main
kalle 2022-06-21 15:46:17 +02:00
parent 471a683ae3
commit 10145032e2
72 changed files with 1803 additions and 519 deletions

5
.gitignore vendored Normal file
View File

@ -0,0 +1,5 @@
/.gradle/
/.idea/
/build/
/run/
/textures/out/

View File

@ -2,7 +2,8 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins { plugins {
kotlin("jvm") version "1.5.31" 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" id("io.papermc.paperweight.userdev") version "1.3.4"
} }
@ -24,18 +25,13 @@ dependencies {
compileOnly("com.comphenix.protocol:ProtocolLib:4.6.0") compileOnly("com.comphenix.protocol:ProtocolLib:4.6.0")
compileOnly(kotlin("stdlib-jdk8")) compileOnly(kotlin("stdlib-jdk8"))
compileOnly("nl.kallestruik:DLib:1.3.5") compileOnly("nl.kallestruik:DLib:1.3.6")
testImplementation(kotlin("test-junit5")) testImplementation(kotlin("test-junit5"))
testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0") testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0")
testRuntimeOnly("org.junit.jupiter:junit-jupiter-engine: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 { tasks.build {
dependsOn(tasks.shadowJar) dependsOn(tasks.shadowJar)
} }
@ -49,6 +45,11 @@ tasks {
useJUnitPlatform() useJUnitPlatform()
} }
shadowJar {
relocate("co.aikar.commands", "nl.kallestruik.dtweaks.acf")
relocate("co.aikar.locales", "nl.kallestruik.dtweaks.locales")
}
compileJava { compileJava {
options.compilerArgs.add("-parameters") options.compilerArgs.add("-parameters")
} }
@ -56,7 +57,7 @@ tasks {
kotlinOptions.javaParameters = true kotlinOptions.javaParameters = true
} }
withType<KotlinCompile> { withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11" kotlinOptions.jvmTarget = "16"
} }
processResources { processResources {

View File

@ -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)
}

View File

@ -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)
}

View File

@ -3,4 +3,5 @@ package nl.kallestruik.dtweaks
object Const { object Const {
const val TRAMPLE_ENABLED_FILE_NAME = "tramplestore.yml" const val TRAMPLE_ENABLED_FILE_NAME = "tramplestore.yml"
const val TWEAK_STATE_FILE_NAME = "tweak_states.yml" const val TWEAK_STATE_FILE_NAME = "tweak_states.yml"
const val NO_SPAWN_ZONE_FILE_NAME = "no_spawn_store.yml"
} }

View File

@ -5,18 +5,19 @@ import co.aikar.commands.PaperCommandManager
import nl.kallestruik.dlib.DUtil import nl.kallestruik.dlib.DUtil
import nl.kallestruik.dlib.MathHelper import nl.kallestruik.dlib.MathHelper
import nl.kallestruik.dlib.ReflectionUtil import nl.kallestruik.dlib.ReflectionUtil
import nl.kallestruik.dtweaks.commands.CommandBundle
import nl.kallestruik.dtweaks.commands.CommandPlayer
import nl.kallestruik.dtweaks.commands.CommandSpawnzones
import nl.kallestruik.dtweaks.commands.CommandToggletrample 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.TrampleManager
import nl.kallestruik.dtweaks.managers.TweakManager import nl.kallestruik.dtweaks.managers.TweakManager
import nl.kallestruik.dtweaks.tweaks.craftingtweaks.* import nl.kallestruik.dtweaks.tweaks.craftingtweaks.*
import nl.kallestruik.dtweaks.tweaks.croptweaks.* import nl.kallestruik.dtweaks.tweaks.croptweaks.*
import nl.kallestruik.dtweaks.tweaks.dispsensertweaks.DispensersCanPlantSaplings import nl.kallestruik.dtweaks.tweaks.dispsensertweaks.DispensersCanPlantSaplings
import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.ArmorStandArmorSwapping import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.*
import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.CarpetBlockPlacingProtocol import nl.kallestruik.dtweaks.tweaks.mobtweaks.*
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 org.bukkit.plugin.java.JavaPlugin import org.bukkit.plugin.java.JavaPlugin
import java.io.File import java.io.File
import java.util.* import java.util.*
@ -31,7 +32,8 @@ class DTweaks: JavaPlugin() {
lateinit var reflectionUtil: ReflectionUtil lateinit var reflectionUtil: ReflectionUtil
private lateinit var trampleManager: TrampleManager private lateinit var trampleManager: TrampleManager
private lateinit var commandManager: PaperCommandManager private lateinit var commandManager: PaperCommandManager
// private lateinit var fakePlayerManager: FakePlayerManager private lateinit var fakePlayerManager: FakePlayerManager
private lateinit var noSpawnZoneManager: NoSpawnZoneManager
// private lateinit var pocketDimensionManager: PocketDimensionManager // private lateinit var pocketDimensionManager: PocketDimensionManager
} }
@ -46,7 +48,8 @@ class DTweaks: JavaPlugin() {
reflectionUtil = ReflectionUtil() reflectionUtil = ReflectionUtil()
trampleManager = TrampleManager() trampleManager = TrampleManager()
commandManager = PaperCommandManager(this) commandManager = PaperCommandManager(this)
// fakePlayerManager = FakePlayerManager() fakePlayerManager = FakePlayerManager(this)
noSpawnZoneManager = NoSpawnZoneManager()
// pocketDimensionManager = PocketDimensionManager(mathHelper) // pocketDimensionManager = PocketDimensionManager(mathHelper)
// Enable brigadier support on ACF // Enable brigadier support on ACF
@ -54,19 +57,24 @@ class DTweaks: JavaPlugin() {
registerCommandConditions() registerCommandConditions()
val betterBundles = BetterBundles(this)
/* /*
* Commands * Commands
*/ */
// commandManager.registerCommand(CommandMobcaps(reflectionUtil)) // commandManager.registerCommand(CommandMobcaps(reflectionUtil))
// commandManager.registerCommand(CommandPlayer(fakePlayerManager, tweakManager)) commandManager.registerCommand(CommandPlayer(fakePlayerManager))
// commandManager.registerCommand(CommandPocketdim(pocketDimensionManager)) // commandManager.registerCommand(CommandPocketdim(pocketDimensionManager))
commandManager.registerCommand(CommandToggletrample(trampleManager)) commandManager.registerCommand(CommandToggletrample(trampleManager))
commandManager.registerCommand(CommandBundle(betterBundles))
commandManager.registerCommand(CommandSpawnzones(noSpawnZoneManager))
/* /*
* Load data from disk * Load data from disk
*/ */
tweakManager.loadFromFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME)) tweakManager.loadFromFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
trampleManager.loadFromFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME)) trampleManager.loadFromFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
noSpawnZoneManager.loadFromFile(File(dataFolder, Const.NO_SPAWN_ZONE_FILE_NAME))
// pocketDimensionManager.loadData() // pocketDimensionManager.loadData()
/* /*
@ -80,8 +88,10 @@ class DTweaks: JavaPlugin() {
tweakManager.registerTweak(CraftableSponge(this)) tweakManager.registerTweak(CraftableSponge(this))
tweakManager.registerTweak(IceDecompression(this)) tweakManager.registerTweak(IceDecompression(this))
tweakManager.registerTweak(LogsToChests(this)) tweakManager.registerTweak(LogsToChests(this))
tweakManager.registerTweak(MoreSandstone(this))
tweakManager.registerTweak(RedyeTerracotta(this)) tweakManager.registerTweak(RedyeTerracotta(this))
tweakManager.registerTweak(WoolToString(this)) tweakManager.registerTweak(WoolToString(this))
tweakManager.registerTweak(CraftableChainmail(this))
/* /*
* Crop Tweaks * Crop Tweaks
@ -102,8 +112,12 @@ class DTweaks: JavaPlugin() {
* Miscellaneous Tweaks * Miscellaneous Tweaks
*/ */
tweakManager.registerTweak(ArmorStandArmorSwapping(this)) tweakManager.registerTweak(ArmorStandArmorSwapping(this))
tweakManager.registerTweak(CarpetBlockPlacingProtocol(this, mathHelper)) // tweakManager.registerTweak(CarpetBlockPlacingProtocol(this, mathHelper))
// tweakManager.registerTweak(FakePlayers(fakePlayerManager)) 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)) // tweakManager.registerTweak(SpaceTimePockets(this, pocketDimensionManager))
/* /*
@ -113,6 +127,7 @@ class DTweaks: JavaPlugin() {
tweakManager.registerTweak(NoDoorBreaking(this)) tweakManager.registerTweak(NoDoorBreaking(this))
tweakManager.registerTweak(NoEndermanGrief(this)) tweakManager.registerTweak(NoEndermanGrief(this))
tweakManager.registerTweak(VillagerInfo(this)) tweakManager.registerTweak(VillagerInfo(this))
tweakManager.registerTweak(NoSpawnZones(this, noSpawnZoneManager))
} }
override fun onDisable() { override fun onDisable() {
@ -121,6 +136,7 @@ class DTweaks: JavaPlugin() {
*/ */
tweakManager.saveToFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME)) tweakManager.saveToFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
trampleManager.saveToFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME)) trampleManager.saveToFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
noSpawnZoneManager.saveToFile()
// pocketDimensionManager.saveData() // pocketDimensionManager.saveData()
} }
@ -130,4 +146,6 @@ class DTweaks: JavaPlugin() {
throw ConditionFailedException("The tweak ${context.getConfigValue("tweak", "")} is not enabled!") throw ConditionFailedException("The tweak ${context.getConfigValue("tweak", "")} is not enabled!")
} }
} }
fun getNamespace(): String = this.name.lowercase(Locale.ROOT)
} }

View File

@ -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)
}
}

View File

@ -1,28 +1,37 @@
//package nl.kallestruik.dtweaks.commands package nl.kallestruik.dtweaks.commands
//
//import co.aikar.commands.BaseCommand import co.aikar.commands.BaseCommand
//import co.aikar.commands.annotation.* import co.aikar.commands.annotation.*
//import nl.kallestruik.dtweaks.managers.FakePlayerManager import nl.kallestruik.dtweaks.managers.FakePlayerManager
//import nl.kallestruik.dtweaks.managers.TweakManager import org.bukkit.entity.Player
//import org.bukkit.command.CommandSender
//import org.bukkit.entity.Player @CommandAlias("player")
// @Conditions("tweakEnabled:tweak=FakePlayers")
//@CommandAlias("player") class CommandPlayer(
//@Conditions("tweakEnabled:tweak=FakePlayers") private val fakePlayerManager: FakePlayerManager
//class CommandPlayer( ): BaseCommand() {
// private val fakePlayerManager: FakePlayerManager,
// private val tweakManager: TweakManager @Subcommand("spawn")
//): BaseCommand() { @CommandCompletion("@players")
// fun onSpawn(sender: Player, @Single playerName: String) {
// @Subcommand("spawn") fakePlayerManager.spawnFakePlayer(sender.location, playerName)
// @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) {
// @Subcommand("kill") fakePlayerManager.killFakePlayer(playerName)
// @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)
}
}

View File

@ -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)
)
}
}

View File

@ -1,27 +1,19 @@
//package nl.kallestruik.dtweaks.fakeplayer package nl.kallestruik.dtweaks.fakeplayer
//
//import io.netty.util.concurrent.Future import io.netty.channel.embedded.EmbeddedChannel
//import io.netty.util.concurrent.GenericFutureListener import net.minecraft.network.Connection
// import net.minecraft.network.protocol.PacketFlow
//class FakeConnection(
// enumProtocolDirection: EnumProtocolDirection
//): NetworkManager(enumProtocolDirection) { class FakeConnection(
// var open = true packetFlow: PacketFlow
// ): Connection(packetFlow) {
// // isOpen()
// override fun isConnected(): Boolean { init {
// return open this.channel = EmbeddedChannel()
// } }
//
// // hasChannel() override fun setReadOnly() {}
// override fun i(): Boolean {
// return false override fun handleDisconnection() {}
// } }
//
// override fun sendPacket(packet: Packet<*>?, genericfuturelistener: GenericFutureListener<out Future<in Void?>?>?) {}
//
// // disableAutoRead()
// override fun stopReading() {}
//
// override fun handleDisconnection() {}
//}

View File

@ -1,79 +1,68 @@
//package nl.kallestruik.dtweaks.fakeplayer package nl.kallestruik.dtweaks.fakeplayer
//
//import com.mojang.authlib.GameProfile import com.mojang.authlib.GameProfile
//import net.minecraft.server.v1_16_R3.* import net.minecraft.network.chat.TextComponent
//import nl.kallestruik.dtweaks.DTweaks import net.minecraft.network.protocol.PacketFlow
//import org.bukkit.Location import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket
//import org.bukkit.craftbukkit.v1_16_R3.CraftWorld import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket
// import net.minecraft.server.MinecraftServer
//class FakePlayer( import net.minecraft.server.TickTask
// minecraftServer: MinecraftServer?, import net.minecraft.server.level.ServerLevel
// worldServer: WorldServer?, import net.minecraft.server.level.ServerPlayer
// gameProfile: GameProfile?, import net.minecraft.world.damagesource.DamageSource
// playerInteractManager: PlayerInteractManager? import net.minecraft.world.entity.Entity
//): EntityPlayer(minecraftServer, worldServer, gameProfile, playerInteractManager) { import net.minecraft.world.food.FoodData
// val locale = "en_US" import net.minecraft.world.level.block.entity.SkullBlockEntity
// private var hasStartingPos = false import org.bukkit.Location
// private var startingX = 0.0 import org.bukkit.craftbukkit.v1_18_R1.CraftWorld
// private var startingY = 0.0 import java.util.concurrent.atomic.AtomicReference
// private var startingZ = 0.0
// private var startingYaw = 0f class FakePlayer(
// private var startingPitch = 0f server: MinecraftServer,
// val serverLevel: ServerLevel,
// private constructor( gameProfile: GameProfile
// server: MinecraftServer, ): ServerPlayer(server, serverLevel, gameProfile) {
// worldIn: WorldServer, val locale = "en_US"
// profile: GameProfile?,
// interactionManagerIn: PlayerInteractManager, companion object {
// x: Double, fun atLocation(location: Location, name: String): FakePlayer? {
// y: Double, // Get the minecraft server instance.
// z: Double, val minecraftServer = MinecraftServer.getServer()
// yaw: Float, // Get the world
// pitch: Float val serverLevel = (location.world as CraftWorld).handle
// ) : this(server, worldIn, profile, interactionManagerIn) { // Get the game profile from the cache (or retrieve it if it is not cached)
// this.hasStartingPos = true var gameProfile = minecraftServer.profileCache.get(name).takeIf { it.isPresent }?.get() ?: return null
// this.startingX = x if (gameProfile.properties.containsKey("textures")) {
// this.startingY = y val result = AtomicReference<GameProfile>()
// this.startingZ = z SkullBlockEntity.updateGameprofile(gameProfile, result::set)
// this.startingYaw = yaw gameProfile = result.get()
// this.startingPitch = pitch }
// applyStartingPosition()
// } // Create an instance of our fake player.
// val instance = FakePlayer(minecraftServer, serverLevel, gameProfile)
// companion object {
// fun atLocation(location: Location, name: String?): FakePlayer? { // Create a fake connection for our fake player.
// // Split the location into its parts for use later. val connection = FakeConnection(PacketFlow.SERVERBOUND)
// val x = location.x FakePlayerList.placeNewPlayer(minecraftServer.playerList, minecraftServer, connection, instance)
// val y = location.y
// val z = location.z instance.respawn()
// val yaw = location.yaw.toDouble() instance.teleportTo(serverLevel, location.x, location.y, location.z, location.yaw, location.pitch)
// val pitch = location.pitch.toDouble() instance.dead = false
// try { instance.heal(instance.maxHealth)
// // Get the minecraft server instance. instance.unsetRemoved()
// val minecraftServer = MinecraftServer.getServer() instance.maxUpStep = 0.6F
// // Create an empty variable for the world server.
// val worldServer = (location.world as CraftWorld).handle minecraftServer.playerList.broadcastAll(
// // Get the game profile from the cache (or retrieve it if it is not cached) ClientboundRotateHeadPacket(
// var gameProfile = minecraftServer.userCache.getProfile(name) ?: return null instance,
// if (gameProfile.properties.containsKey("textures")) { (instance.yHeadRot * 256 / 360).toInt().toByte()
// gameProfile = TileEntitySkull.b(gameProfile, null, true).get() ), serverLevel.dimension())
// }
// minecraftServer.playerList.broadcastAll(ClientboundTeleportEntityPacket(instance), serverLevel.dimension())
// // Create a player interact manager using the world server.
// val playerInteractManager = PlayerInteractManager(worldServer) instance.entityData.set(DATA_PLAYER_MODE_CUSTOMISATION, 0x7f)
// return instance
// // 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
//
// (DTweaks.reflectionUtil.getValueFromField( // (DTweaks.reflectionUtil.getValueFromField(
// serverConnection!!, // serverConnection!!,
// "connectedChannels" // "connectedChannels"
@ -126,43 +115,36 @@
// instance.worldServer.getChunkProvider().movePlayer(instance) // instance.worldServer.getChunkProvider().movePlayer(instance)
// // bp == PLAYER_MODEL_PARTS // // bp == PLAYER_MODEL_PARTS
// instance.datawatcher.set<Byte>(bj, 0x7f.toByte()) // show all model layers (incl. capes) // instance.datawatcher.set<Byte>(bj, 0x7f.toByte()) // show all model layers (incl. capes)
// return instance }
// } catch (e: Exception) { }
// e.printStackTrace()
// } override fun kill() {
// return null server.tell(TickTask(server.tickCount) {connection.onDisconnect(TextComponent("Killed"))})
// } }
// }
// override fun die(source: DamageSource) {
// super.die(source)
// fun applyStartingPosition() { heal(maxHealth)
// if (hasStartingPos) { foodData = FoodData(this)
// this.setPositionRotation(startingX, startingY, startingZ, startingYaw, startingPitch) kill()
// mot = Vec3D(0.0, 0.0, 0.0) }
// }
// } override fun tick() {
// super.tick()
//
// override fun killEntity() { if (server.tickCount % 10 == 0) {
// server.a(TickTask(server.ai()) { playerConnection.a(ChatComponentText("Killed")) }) connection.resetPosition()
// } serverLevel.chunkSource.move(this)
// hasChangedDimension()
// override fun tick() { }
// super.tick() }
// if (H()) {
// I()
// }
// movementTick()
// if (server.ai() % 10 == 0) {
// playerConnection.syncPosition()
// this.worldServer.getChunkProvider().movePlayer(this)
// }
// }
//
// override fun die(cause: DamageSource?) { // override fun die(cause: DamageSource?) {
// super.die(cause) // super.die(cause)
// health = 20f // health = 20f
// foodData = FoodMetaData(this) // foodData = FoodMetaData(this)
// killEntity() // killEntity()
// } // }
//}
override fun getIpAddress() = "127.0.0.1"
}

View File

@ -1,36 +1,31 @@
//package nl.kallestruik.dtweaks.fakeplayer package nl.kallestruik.dtweaks.fakeplayer
//
//import net.minecraft.server.v1_16_R3.* import io.netty.util.concurrent.Future
//import nl.kallestruik.dtweaks.DTweaks import io.netty.util.concurrent.GenericFutureListener
//import java.lang.reflect.Field import net.minecraft.network.chat.Component
// import net.minecraft.network.chat.TranslatableComponent
//class FakePlayerConnection( import net.minecraft.network.protocol.Packet
// minecraftServer: MinecraftServer, import net.minecraft.server.MinecraftServer
// networkManager: NetworkManager, import net.minecraft.server.network.ServerGamePacketListenerImpl
// entityPlayer: EntityPlayer import javax.annotation.Nullable
//): PlayerConnection(minecraftServer, networkManager, entityPlayer) {
// override fun sendPacket(packet: Packet<*>?) { class FakePlayerConnection(
// if (packet is PacketPlayOutKeepAlive) { minecraftServer: MinecraftServer,
// val pong = PacketPlayInKeepAlive() connection: FakeConnection,
// try { player: FakePlayer
// val pingId: Field = DTweaks.reflectionUtil.getField(PacketPlayOutKeepAlive::class.java, "a") ): ServerGamePacketListenerImpl(minecraftServer, connection, player) {
// val pongId: Field = DTweaks.reflectionUtil.getField(PacketPlayInKeepAlive::class.java, "a") override fun send(packetIn: Packet<*>?) {}
// pingId.isAccessible = true override fun send(packet: Packet<*>, listener: GenericFutureListener<out Future<in Void>>?) {}
// pongId.isAccessible = true
// pongId[pong] = pingId[packet] override fun disconnect(message: Component) {
// } catch (e: Exception) { if (message is TranslatableComponent && (message.key.equals("multiplayer.disconnect.idling") || message.equals("multiplayer.disconnect.duplicate_login")))
// e.printStackTrace() {
// } player.kill()
// this.a(pong) }
// } }
// }
// override fun tick() {
// override fun disconnect(message: String?) { println("Tick for ${player.name}")
// player.killEntity() super.tick()
// } }
// }
// override fun a(disconnectReason: IChatBaseComponent?) {
// super.a(disconnectReason)
// (this.a() as FakeConnection).open = false
// }
//}

View File

@ -1,258 +1,165 @@
//package nl.kallestruik.dtweaks.fakeplayer package nl.kallestruik.dtweaks.fakeplayer
//
//import com.mojang.serialization.DataResult import com.destroystokyo.paper.PaperConfig
//import com.mojang.serialization.Dynamic import com.destroystokyo.paper.event.player.PlayerInitialSpawnEvent
//import io.netty.buffer.Unpooled import com.mojang.authlib.GameProfile
//import net.minecraft.server.v1_16_R3.* import com.mojang.datafixers.util.Either
//import nl.kallestruik.dtweaks.DTweaks import com.mojang.serialization.Dynamic
//import org.apache.logging.log4j.Logger import io.netty.buffer.Unpooled
//import org.bukkit.Bukkit import net.minecraft.nbt.CompoundTag
//import org.bukkit.craftbukkit.v1_16_R3.CraftWorld import net.minecraft.nbt.NbtOps
//import org.bukkit.craftbukkit.v1_16_R3.util.CraftChatMessage import net.minecraft.network.Connection
//import org.bukkit.entity.Player import net.minecraft.network.FriendlyByteBuf
//import org.spigotmc.event.player.PlayerSpawnLocationEvent import net.minecraft.network.protocol.game.*
//import java.util.* import net.minecraft.resources.ResourceKey
// import net.minecraft.server.MinecraftServer
//object FakePlayerList { import net.minecraft.server.level.*
// fun a(playerList: PlayerList, networkManager: NetworkManager, entityPlayer: EntityPlayer) { import net.minecraft.server.level.ChunkHolder.ChunkLoadingFailure
// // Setup what are normally class level variables import net.minecraft.server.network.ServerGamePacketListenerImpl
// val server = DTweaks.reflectionUtil.getValueFromField(playerList, "server") as MinecraftServer import net.minecraft.server.players.GameProfileCache
// val LOGGER = DTweaks.reflectionUtil.getValueFromField(playerList, "LOGGER") as Logger import net.minecraft.server.players.PlayerList
// import net.minecraft.world.level.ChunkPos
// val gameProfile = entityPlayer.profile import net.minecraft.world.level.GameRules
// val userCache = server.userCache import net.minecraft.world.level.Level
// val oldGameProfile = userCache.getProfile(gameProfile.id) import net.minecraft.world.level.biome.BiomeManager
// var oldName = if (oldGameProfile == null) gameProfile.name else oldGameProfile.name import net.minecraft.world.level.chunk.ChunkAccess
// import net.minecraft.world.level.dimension.DimensionType
// userCache.a(gameProfile) import nl.kallestruik.dlib.ReflectionUtil
// val playerData = playerList.a(entityPlayer) import nl.kallestruik.dtweaks.DTweaks
// if (playerData != null && playerData.hasKey("bukkit")) { import org.apache.logging.log4j.Logger
// val bukkit = playerData.getCompound("bukkit") import org.bukkit.Bukkit
// oldName = if (bukkit.hasKeyOfType("lastKnownName", 8)) bukkit.getString("lastKnownName") else oldName import org.bukkit.craftbukkit.v1_18_R1.CraftWorld
// } import org.bukkit.entity.Player
// val worldKey: ResourceKey<World> = if (playerData != null) { import org.spigotmc.event.player.PlayerSpawnLocationEvent
// val dataResult: DataResult<ResourceKey<World>> = DimensionManager.a( import java.util.*
// Dynamic( import java.util.concurrent.CompletableFuture
// DynamicOpsNBT.a, import java.util.function.Consumer
// playerData["Dimension"]
// ) object FakePlayerList {
// ) fun placeNewPlayer(playerList: PlayerList, server: MinecraftServer, connection: FakeConnection, player: FakePlayer) {
// dataResult.resultOrPartial { o -> LOGGER.error(o) } player.isRealPlayer = true // Paper - Chunk priority
// .orElse(World.OVERWORLD) as ResourceKey<World>
// } else { player.networkManager = connection // Paper
// World.OVERWORLD
// } player.loginTime = System.currentTimeMillis() // Paper
// var worldServer = server.getWorldServer(worldKey) ?: server.E()
// val gameProfile: GameProfile = player.getGameProfile()
// entityPlayer.spawnIn(worldServer) val userCache: GameProfileCache = server.getProfileCache()
// entityPlayer.playerInteractManager.a(entityPlayer.world as WorldServer) val optional = userCache[gameProfile.id]
// var s1 = "local" var s: String? = optional.map { obj: GameProfile -> obj.name }.orElse(gameProfile.name)
// if (networkManager.getSocketAddress() != null) {
// s1 = networkManager.getSocketAddress().toString() userCache.add(gameProfile)
// } val nbtTagCompound: CompoundTag? = playerList.load(player)
// val bukkitPlayer: Player = entityPlayer.bukkitEntity // CraftBukkit start - Better rename detection
// val ev = PlayerSpawnLocationEvent(bukkitPlayer, bukkitPlayer.location) // CraftBukkit start - Better rename detection
// Bukkit.getPluginManager().callEvent(ev) if (nbtTagCompound != null && nbtTagCompound.contains("bukkit")) {
// val loc = ev.spawnLocation val bukkit = nbtTagCompound.getCompound("bukkit")
// worldServer = (loc.world as CraftWorld).handle s = if (bukkit.contains("lastKnownName", 8)) bukkit.getString("lastKnownName") else s
// entityPlayer.spawnIn(worldServer) }
// entityPlayer.playerInteractManager.a(entityPlayer.world as WorldServer) val lastKnownName = s // Paper
// entityPlayer.setPosition(loc.x, loc.y, loc.z)
// // CraftBukkit end
// //entityplayer.setYawPitch(loc.getYaw(), loc.getPitch());
// try { // Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
// val setYawPitch = Entity::class.java.getDeclaredMethod( // CraftBukkit end
// "setYawPitch",
// Float::class.javaPrimitiveType, // Paper start - move logic in Entity to here, to use bukkit supplied world UUID.
// Float::class.javaPrimitiveType val resourceKey: ResourceKey<Level> = if (nbtTagCompound != null && nbtTagCompound.contains("WorldUUIDMost") && nbtTagCompound.contains("WorldUUIDLeast")) {
// ) val uid = UUID(nbtTagCompound.getLong("WorldUUIDMost"), nbtTagCompound.getLong("WorldUUIDLeast"))
// setYawPitch.isAccessible = true val bWorld = Bukkit.getServer().getWorld(uid)
// setYawPitch.invoke(entityPlayer, loc.yaw, loc.pitch) if (bWorld != null) {
// } catch (e: Exception) { (bWorld as CraftWorld).handle.dimension()
// e.printStackTrace() } else {
// } Level.OVERWORLD
// val worldData = worldServer.getWorldData() }
// } else if (nbtTagCompound != null) {
// //playerList.a(entityplayer, (EntityPlayer)null, worldserver1); // Vanilla migration support
// try { // Paper end
// val a = PlayerList::class.java.getDeclaredMethod( val dataResult = DimensionType.parseLegacy(
// "a", Dynamic(
// EntityPlayer::class.java, NbtOps.INSTANCE,
// EntityPlayer::class.java, nbtTagCompound["Dimension"]
// WorldServer::class.java )
// ) )
// a.isAccessible = true dataResult.result().orElse(Level.OVERWORLD)
// a.invoke(playerList, entityPlayer, null, worldServer) } else {
// } catch (e: Exception) { Level.OVERWORLD
// e.printStackTrace() }
// }
// var worldServer: ServerLevel = server.getLevel(resourceKey) ?: server.overworld()
// //PlayerConnection playerconnection = new PlayerConnection(server, networkmanager, entityplayer);
// val playerConnection: PlayerConnection = if (nbtTagCompound == null) player.fudgeSpawnLocation(worldServer) // Paper - only move to spawn on first login, otherwise, stay where you are....
// (entityPlayer as? FakePlayer)?.let { FakePlayerConnection(server, networkManager, it) }
// ?: PlayerConnection(server, networkManager, entityPlayer) player.setLevel(worldServer)
// val gameRules = worldServer.gameRules
// val doImmediateRespawn = gameRules.getBoolean(GameRules.DO_IMMEDIATE_RESPAWN)
// val reducedDebugInfo = gameRules.getBoolean(GameRules.REDUCED_DEBUG_INFO) // Spigot start - spawn location event
// try { val spawnPlayer: Player = player.bukkitEntity
// playerConnection.sendPacket( val ev: PlayerSpawnLocationEvent =
// PacketPlayOutLogin( PlayerInitialSpawnEvent(spawnPlayer, spawnPlayer.location) // Paper use our duplicate event
// entityPlayer.id,
// entityPlayer.playerInteractManager.gameMode, Bukkit.getServer().pluginManager.callEvent(ev)
// entityPlayer.playerInteractManager.c(),
// BiomeManager.a( val loc = ev.spawnLocation
// worldServer.seed worldServer = (loc.world as CraftWorld).handle
// ),
// worldData.isHardcore, player.spawnIn(worldServer)
// server.F(), player.gameMode.setLevel(player.level as ServerLevel)
// DTweaks.reflectionUtil.getValueFromField(playerList, "s") as IRegistryCustom.Dimension, // Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
// worldServer.dimensionManager, // Paper start - set raw so we aren't fully joined to the world (not added to chunk or world)
// worldServer.dimensionKey, player.setPosRaw(loc.x, loc.y, loc.z)
// playerList.maxPlayers, player.setRot(loc.yaw, loc.pitch)
// worldServer.spigotConfig.viewDistance, // Paper end
// reducedDebugInfo, // Spigot end
// !doImmediateRespawn,
// worldServer.isDebugWorld, // CraftBukkit - Moved message to after join
// worldServer.isFlatWorld // 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
// } catch (e: Exception) {
// e.printStackTrace() // 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());
// entityPlayer.bukkitEntity.sendSupportedChannels() val worlddata = worldServer.getLevelData()
// playerConnection.sendPacket(
// PacketPlayOutCustomPayload( player.loadGameTypes(nbtTagCompound)
// PacketPlayOutCustomPayload.a, val playerconnection = FakePlayerConnection(server, connection, player)
// PacketDataSerializer(Unpooled.buffer()).a(playerList.server.serverModName) val gamerules = worldServer.gameRules
// )
// ) player.bukkitEntity.sendSupportedChannels() // CraftBukkit
// playerConnection.sendPacket(PacketPlayOutServerDifficulty(worldData.difficulty, worldData.isDifficultyLocked))
// playerConnection.sendPacket(PacketPlayOutAbilities(entityPlayer.abilities)) player.stats.markAllDirty()
// playerConnection.sendPacket(PacketPlayOutHeldItemSlot(entityPlayer.inventory.itemInHandIndex)) player.recipeBook.sendInitialRecipeBook(player)
// playerConnection.sendPacket(PacketPlayOutRecipeUpdate(server.craftingManager.b())) playerList.updateEntireScoreboard(worldServer.scoreboard, player)
// playerConnection.sendPacket(PacketPlayOutTags(server.tagRegistry)) server.invalidateStatus()
// playerList.d(entityPlayer) // Paper start - async load spawn in chunk
// entityPlayer.statisticManager.c() // Paper start - async load spawn in chunk
// entityPlayer.recipeBook.a(entityPlayer) val finalWorldserver = worldServer
// playerList.sendScoreboard(worldServer.scoreboard, entityPlayer) val chunkX = loc.blockX shr 4
// server.invalidatePingSample() val chunkZ = loc.blockZ shr 4
// val chatMessage = if (entityPlayer.profile.name.equals(oldName, ignoreCase = true)) { val pos = ChunkPos(chunkX, chunkZ)
// ChatMessage("multiplayer.player.joined", entityPlayer.scoreboardDisplayName) val playerChunkMap = worldServer.getChunkSource().chunkMap
// } else { val distanceManager: DistanceManager = playerChunkMap.distanceManager
// ChatMessage("multiplayer.player.joined.renamed", entityPlayer.scoreboardDisplayName, oldName) distanceManager.addTicketAtLevel(TicketType.LOGIN, pos, 31, pos.toLong())
// } worldServer.getChunkSource().markAreaHighPriority(pos, 28, 3) // Paper - Chunk priority
// chatMessage.a(EnumChatFormat.YELLOW)
// var joinMessage = CraftChatMessage.fromComponent(chatMessage) 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)
// playerConnection.a( postChunkLoadJoin.isAccessible = true
// entityPlayer.locX(), postChunkLoadJoin.invoke(playerList, player, finalWorldserver, connection, playerconnection,
// entityPlayer.locY(), nbtTagCompound, "127.0.0.1", lastKnownName)
// entityPlayer.locZ(),
// entityPlayer.yaw,
// entityPlayer.pitch // worldServer.getChunkSource().getChunkAtAsynchronously(chunkX, chunkZ, true, false)
// ) // .thenApply { chunk: Either<ChunkAccess, ChunkLoadingFailure> -> // Paper - Chunk priority
// playerList.players.add(entityPlayer) // val updatingChunk = playerChunkMap.getUpdatingChunkIfPresent(pos.toLong())
// // if (updatingChunk != null) {
// //playerList.playersByName.put(entityplayer.getName().toLowerCase(Locale.ROOT), entityplayer); // return@thenApply updatingChunk.entityTickingChunkFuture
// val playersByName = DTweaks.reflectionUtil.getValueFromField(playerList, "playersByName") as HashMap<String, EntityPlayer> // } else {
// playersByName[entityPlayer.name.toLowerCase(Locale.ROOT)] = entityPlayer // return@thenApply CompletableFuture.completedFuture(
// // chunk
// //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
// )
// ) // )
// } // }
// } // }.thenAccept {
// entityPlayer.sentListPacket = true
// entityPlayer.playerConnection.sendPacket(
// PacketPlayOutEntityMetadata(
// entityPlayer.id,
// DTweaks.reflectionUtil.getValueFromField(entityPlayer, "datawatcher") as DataWatcher, true
// )
// )
// //
// 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()
// )
// } // }
// } }
//} }

View File

@ -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 { // fakePlayer.swing()
//
// 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) { fun attack(name: String) {
// val player = Bukkit.getPlayer(name) val player = getPlayerByName(name) ?: return
// if (player == null || !player.isOnline) return val target = getTarget(player) ?: return
// val entityPlayer = (player as CraftPlayer).handle as? FakePlayer ?: return
// entityPlayer.killEntity() when (target.type) {
// } HitResult.Type.BLOCK -> {/*TODO: Not implemented*/}
// HitResult.Type.ENTITY -> {
// fun killAllFakePlayers() { if (target !is EntityHitResult) return
// for (player in Bukkit.getOnlinePlayers()) {
// if (!player.isOnline) continue player.attack(target.entity);
// val entityPlayer = (player as CraftPlayer).handle as? FakePlayer ?: continue player.swing(InteractionHand.MAIN_HAND);
// entityPlayer.killEntity() 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()
}
}
}

View File

@ -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
}
}

View File

@ -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)
}
}

View File

@ -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)
}
}

View File

@ -77,7 +77,7 @@ class RedyeTerracotta(
} }
private fun addRecipe(key: NamespacedKey, output: Material, dye: Material) { 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.shape("TTT", "TDT", "TTT")
recipe.setIngredient('T', allTerracotta) recipe.setIngredient('T', allTerracotta)
recipe.setIngredient('D', dye) recipe.setIngredient('D', dye)

View File

@ -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
}
}

View File

@ -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))
}
}
}
}

View File

@ -1,15 +1,48 @@
//package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
//
//import nl.kallestruik.dtweaks.managers.FakePlayerManager import nl.kallestruik.dtweaks.DTweaks
//import nl.kallestruik.dtweaks.tweaks.ITweak import nl.kallestruik.dtweaks.fakeplayer.FakePlayer
// import nl.kallestruik.dtweaks.managers.FakePlayerManager
//class FakePlayers( import nl.kallestruik.dtweaks.tweaks.ITweak
// private val fakePlayerManager: FakePlayerManager import org.bukkit.Material
//): ITweak { import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer
// override fun getIdentifier(): String = "FakePlayers" import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack
// override fun getCategories(): List<String> = listOf("players") import org.bukkit.entity.Player
// import org.bukkit.event.EventHandler
// override fun onDisable() { import org.bukkit.event.HandlerList
// fakePlayerManager.killAllFakePlayers() 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()
}
}

View File

@ -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)
}
}
}

View File

@ -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
}
}

View File

@ -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
}
}

View File

@ -11,7 +11,12 @@ commands:
player: player:
description: "Interact with fake players." description: "Interact with fake players."
permission: op permission: op
bundle:
description: "Admin command for managing custom bundles."
permission: op
mobcaps: mobcaps:
description: "Display mobcap information from your current dimension." description: "Display mobcap information from your current dimension."
pocketdim: pocketdim:
description: "Interact with pocket dimensions. Testing command." description: "Interact with pocket dimensions. Testing command."
spawnzones:
description: "Manage no spawn zones"

View File

@ -17,8 +17,15 @@ HoesHarvestArea: true
FakePlayers: true FakePlayers: true
CarpetBlockPlacingProtocol: true CarpetBlockPlacingProtocol: true
NoDoorBreaking: true NoDoorBreaking: true
NoCreeperGrief: true NoCreeperGrief: false
NoEndermanGrief: true NoEndermanGrief: true
SugarcaneBonemealing: true SugarcaneBonemealing: true
SpaceTimePockets: true SpaceTimePockets: true
VillagerInfo: true VillagerInfo: true
BetterBundles: true
RedyeTerracotta: true
DyeableNetherite: true
CraftableChainmail: true
NoMelting: true
Hammers: true
NoSpawnZones: true

106
textures/make_bundles.py Normal file
View File

@ -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)

Binary file not shown.

After

Width:  |  Height:  |  Size: 412 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 367 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 372 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 424 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 415 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 360 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 447 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 439 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 374 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 437 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 431 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 369 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 442 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 373 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 375 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 421 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 363 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 435 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 371 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 434 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 370 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 433 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 288 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 428 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 282 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 455 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 304 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 476 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 347 B

View File

@ -0,0 +1,6 @@
{
"parent": "item/handheld",
"textures": {
"layer0": "item/diamond_hammer"
}
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 716 B

View File

@ -0,0 +1,14 @@
{
"parent": "item/handheld",
"textures": {
"layer0": "item/diamond_pickaxe"
},
"overrides": [
{
"predicate": {
"custom_model_data": 1
},
"model": "item/diamond_hammer"
},
]
}