Initial commit.

main
kalle 2022-01-30 18:09:54 +01:00
commit f4f043e4d6
50 changed files with 2712 additions and 0 deletions

60
build.gradle.kts Normal file
View File

@ -0,0 +1,60 @@
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
plugins {
kotlin("jvm") version "1.4.32"
id("com.github.johnrengelman.shadow") version "5.2.0"
}
group = "nl.kallestruik"
version = "1.0"
repositories {
mavenCentral()
mavenLocal()
maven("https://papermc.io/repo/repository/maven-public/")
maven("https://repo.aikar.co/content/groups/aikar/")
maven("https://repo.dmulloy2.net/repository/public/")
}
dependencies {
implementation("co.aikar:acf-paper:0.5.0-SNAPSHOT")
compileOnly("com.destroystokyo.paper:paper:1.16.5-R0.1-SNAPSHOT")
compileOnly("com.comphenix.protocol:ProtocolLib:4.6.0")
compileOnly(kotlin("stdlib-jdk8"))
compileOnly("nl.kallestruik:DLib:1.0")
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.compileJava {
options.compilerArgs.add("-parameters")
}
tasks.compileKotlin {
kotlinOptions.javaParameters = true
}
tasks.test {
useJUnitPlatform()
}
tasks.shadowJar {
relocate("co.aikar.commands", "nl.kallestruik.dtweaks.acf")
relocate("co.aikar.locales", "nl.kallestruik.dtweaks.locales")
}
tasks.build {
dependsOn(tasks.shadowJar)
}
tasks.withType<KotlinCompile> {
kotlinOptions.jvmTarget = "11"
}
tasks.processResources {
expand("version" to project.version)
}

1
gradle.properties Normal file
View File

@ -0,0 +1 @@
kotlin.code.style=official

BIN
gradle/wrapper/gradle-wrapper.jar vendored Normal file

Binary file not shown.

View File

@ -0,0 +1,5 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-6.8-bin.zip
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

185
gradlew vendored Executable file
View File

@ -0,0 +1,185 @@
#!/usr/bin/env sh
#
# Copyright 2015 the original author or authors.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
# https://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.
#
##############################################################################
##
## Gradle start up script for UN*X
##
##############################################################################
# Attempt to set APP_HOME
# Resolve links: $0 may be a link
PRG="$0"
# Need this for relative symlinks.
while [ -h "$PRG" ] ; do
ls=`ls -ld "$PRG"`
link=`expr "$ls" : '.*-> \(.*\)$'`
if expr "$link" : '/.*' > /dev/null; then
PRG="$link"
else
PRG=`dirname "$PRG"`"/$link"
fi
done
SAVED="`pwd`"
cd "`dirname \"$PRG\"`/" >/dev/null
APP_HOME="`pwd -P`"
cd "$SAVED" >/dev/null
APP_NAME="Gradle"
APP_BASE_NAME=`basename "$0"`
# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"'
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD="maximum"
warn () {
echo "$*"
}
die () {
echo
echo "$*"
echo
exit 1
}
# OS specific support (must be 'true' or 'false').
cygwin=false
msys=false
darwin=false
nonstop=false
case "`uname`" in
CYGWIN* )
cygwin=true
;;
Darwin* )
darwin=true
;;
MINGW* )
msys=true
;;
NONSTOP* )
nonstop=true
;;
esac
CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar
# Determine the Java command to use to start the JVM.
if [ -n "$JAVA_HOME" ] ; then
if [ -x "$JAVA_HOME/jre/sh/java" ] ; then
# IBM's JDK on AIX uses strange locations for the executables
JAVACMD="$JAVA_HOME/jre/sh/java"
else
JAVACMD="$JAVA_HOME/bin/java"
fi
if [ ! -x "$JAVACMD" ] ; then
die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
else
JAVACMD="java"
which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
Please set the JAVA_HOME variable in your environment to match the
location of your Java installation."
fi
# Increase the maximum file descriptors if we can.
if [ "$cygwin" = "false" -a "$darwin" = "false" -a "$nonstop" = "false" ] ; then
MAX_FD_LIMIT=`ulimit -H -n`
if [ $? -eq 0 ] ; then
if [ "$MAX_FD" = "maximum" -o "$MAX_FD" = "max" ] ; then
MAX_FD="$MAX_FD_LIMIT"
fi
ulimit -n $MAX_FD
if [ $? -ne 0 ] ; then
warn "Could not set maximum file descriptor limit: $MAX_FD"
fi
else
warn "Could not query maximum file descriptor limit: $MAX_FD_LIMIT"
fi
fi
# For Darwin, add options to specify how the application appears in the dock
if $darwin; then
GRADLE_OPTS="$GRADLE_OPTS \"-Xdock:name=$APP_NAME\" \"-Xdock:icon=$APP_HOME/media/gradle.icns\""
fi
# For Cygwin or MSYS, switch paths to Windows format before running java
if [ "$cygwin" = "true" -o "$msys" = "true" ] ; then
APP_HOME=`cygpath --path --mixed "$APP_HOME"`
CLASSPATH=`cygpath --path --mixed "$CLASSPATH"`
JAVACMD=`cygpath --unix "$JAVACMD"`
# We build the pattern for arguments to be converted via cygpath
ROOTDIRSRAW=`find -L / -maxdepth 1 -mindepth 1 -type d 2>/dev/null`
SEP=""
for dir in $ROOTDIRSRAW ; do
ROOTDIRS="$ROOTDIRS$SEP$dir"
SEP="|"
done
OURCYGPATTERN="(^($ROOTDIRS))"
# Add a user-defined pattern to the cygpath arguments
if [ "$GRADLE_CYGPATTERN" != "" ] ; then
OURCYGPATTERN="$OURCYGPATTERN|($GRADLE_CYGPATTERN)"
fi
# Now convert the arguments - kludge to limit ourselves to /bin/sh
i=0
for arg in "$@" ; do
CHECK=`echo "$arg"|egrep -c "$OURCYGPATTERN" -`
CHECK2=`echo "$arg"|egrep -c "^-"` ### Determine if an option
if [ $CHECK -ne 0 ] && [ $CHECK2 -eq 0 ] ; then ### Added a condition
eval `echo args$i`=`cygpath --path --ignore --mixed "$arg"`
else
eval `echo args$i`="\"$arg\""
fi
i=`expr $i + 1`
done
case $i in
0) set -- ;;
1) set -- "$args0" ;;
2) set -- "$args0" "$args1" ;;
3) set -- "$args0" "$args1" "$args2" ;;
4) set -- "$args0" "$args1" "$args2" "$args3" ;;
5) set -- "$args0" "$args1" "$args2" "$args3" "$args4" ;;
6) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" ;;
7) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" ;;
8) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" ;;
9) set -- "$args0" "$args1" "$args2" "$args3" "$args4" "$args5" "$args6" "$args7" "$args8" ;;
esac
fi
# Escape application args
save () {
for i do printf %s\\n "$i" | sed "s/'/'\\\\''/g;1s/^/'/;\$s/\$/' \\\\/" ; done
echo " "
}
APP_ARGS=`save "$@"`
# Collect all arguments for the java command, following the shell quoting and substitution rules
eval set -- $DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS "\"-Dorg.gradle.appname=$APP_BASE_NAME\"" -classpath "\"$CLASSPATH\"" org.gradle.wrapper.GradleWrapperMain "$APP_ARGS"
exec "$JAVACMD" "$@"

89
gradlew.bat vendored Normal file
View File

@ -0,0 +1,89 @@
@rem
@rem Copyright 2015 the original author or authors.
@rem
@rem Licensed under the Apache License, Version 2.0 (the "License");
@rem you may not use this file except in compliance with the License.
@rem You may obtain a copy of the License at
@rem
@rem https://www.apache.org/licenses/LICENSE-2.0
@rem
@rem Unless required by applicable law or agreed to in writing, software
@rem distributed under the License is distributed on an "AS IS" BASIS,
@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
@rem See the License for the specific language governing permissions and
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@rem
@rem ##########################################################################
@rem Set local scope for the variables with windows NT shell
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@rem Resolve any "." and ".." in APP_HOME to make it shorter.
for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
@rem Find java.exe
if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:findJavaFromJavaHome
set JAVA_HOME=%JAVA_HOME:"=%
set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute
echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo.
echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation.
goto fail
:execute
@rem Setup the command line
set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
@rem Execute Gradle
"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
:fail
rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
rem the _cmd.exe /c_ return code!
if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
exit /b 1
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega

3
settings.gradle.kts Normal file
View File

@ -0,0 +1,3 @@
rootProject.name = "DTweaks"

View File

@ -0,0 +1,6 @@
package nl.kallestruik.dtweaks
object Const {
const val TRAMPLE_ENABLED_FILE_NAME = "tramplestore.yml"
const val TWEAK_STATE_FILE_NAME = "tweak_states.yml"
}

View File

@ -0,0 +1,139 @@
package nl.kallestruik.dtweaks
import co.aikar.commands.ConditionFailedException
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.CommandMobcaps
import nl.kallestruik.dtweaks.commands.CommandPlayer
import nl.kallestruik.dtweaks.commands.CommandPocketdim
import nl.kallestruik.dtweaks.commands.CommandToggletrample
import nl.kallestruik.dtweaks.managers.FakePlayerManager
import nl.kallestruik.dtweaks.managers.PocketDimensionManager
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.miscellaneoustweaks.FakePlayers
import nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks.SpaceTimePockets
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 java.io.File
import java.util.*
class DTweaks: JavaPlugin() {
companion object {
private lateinit var random: Random
private lateinit var tweakManager: TweakManager
private lateinit var util: DUtil
private lateinit var mathHelper: MathHelper
lateinit var reflectionUtil: ReflectionUtil
private lateinit var trampleManager: TrampleManager
private lateinit var commandManager: PaperCommandManager
private lateinit var fakePlayerManager: FakePlayerManager
private lateinit var pocketDimensionManager: PocketDimensionManager
}
override fun onEnable() {
/*
* Initialize stuff
*/
random = Random()
tweakManager = TweakManager(this)
util = DUtil(random)
mathHelper = MathHelper()
reflectionUtil = ReflectionUtil()
trampleManager = TrampleManager()
commandManager = PaperCommandManager(this)
fakePlayerManager = FakePlayerManager()
pocketDimensionManager = PocketDimensionManager(mathHelper)
// Enable brigadier support on ACF
commandManager.enableUnstableAPI("brigadier")
registerCommandConditions()
/*
* Commands
*/
commandManager.registerCommand(CommandMobcaps(reflectionUtil))
commandManager.registerCommand(CommandPlayer(fakePlayerManager, tweakManager))
commandManager.registerCommand(CommandPocketdim(pocketDimensionManager))
commandManager.registerCommand(CommandToggletrample(trampleManager))
/*
* Load data from disk
*/
tweakManager.loadFromFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
trampleManager.loadFromFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
pocketDimensionManager.loadData()
/*
* Crafting tweaks
*/
tweakManager.registerTweak(AlternativeDispenserRecipe(this))
tweakManager.registerTweak(CraftableDragonsBreath(this))
tweakManager.registerTweak(CraftableNametag(this))
tweakManager.registerTweak(CraftableSaddle(this))
tweakManager.registerTweak(CraftableShulkerShell(this))
tweakManager.registerTweak(CraftableSponge(this))
tweakManager.registerTweak(IceDecompression(this))
tweakManager.registerTweak(LogsToChests(this))
tweakManager.registerTweak(WoolToString(this))
/*
* Crop Tweaks
*/
tweakManager.registerTweak(HoeHarvestArea(this))
tweakManager.registerTweak(LilypadBonemealing(this, util))
tweakManager.registerTweak(MobsCantTrampleCrops(this))
tweakManager.registerTweak(PlayersCantTrampleCrops(this, trampleManager))
tweakManager.registerTweak(SeedDropPlanting(this))
tweakManager.registerTweak(SugarcaneBonemealing(this))
/*
* Dispenser Tweaks
*/
tweakManager.registerTweak(DispensersCanPlantSaplings(this))
/*
* Miscellaneous Tweaks
*/
tweakManager.registerTweak(ArmorStandArmorSwapping(this))
tweakManager.registerTweak(CarpetBlockPlacingProtocol(this, mathHelper))
tweakManager.registerTweak(FakePlayers(fakePlayerManager))
tweakManager.registerTweak(SpaceTimePockets(this, pocketDimensionManager))
/*
* Mob Tweaks
*/
tweakManager.registerTweak(NoCreeperGrief(this))
tweakManager.registerTweak(NoDoorBreaking(this))
tweakManager.registerTweak(NoEndermanGrief(this))
tweakManager.registerTweak(VillagerInfo(this))
}
override fun onDisable() {
/*
* Save data to disk
*/
tweakManager.saveToFile(File(dataFolder, Const.TWEAK_STATE_FILE_NAME))
trampleManager.saveToFile(File(dataFolder, Const.TRAMPLE_ENABLED_FILE_NAME))
pocketDimensionManager.saveData()
}
private fun registerCommandConditions() {
commandManager.commandConditions.addCondition("tweakEnabled") { context ->
if (!tweakManager.isTweakEnabled(context.getConfigValue("tweak", "")))
throw ConditionFailedException("The tweak ${context.getConfigValue("tweak", "")} is not enabled!")
}
}
}

View File

@ -0,0 +1,75 @@
package nl.kallestruik.dtweaks.commands
import co.aikar.commands.BaseCommand
import co.aikar.commands.annotation.*
import co.aikar.commands.annotation.Optional
import com.mojang.datafixers.util.Pair
import it.unimi.dsi.fastutil.objects.Object2IntMap
import net.kyori.adventure.text.Component
import net.kyori.adventure.text.format.TextColor
import net.minecraft.server.v1_16_R3.ChunkMapDistance
import net.minecraft.server.v1_16_R3.EnumCreatureType
import nl.kallestruik.dlib.ReflectionUtil
import org.bukkit.Bukkit
import org.bukkit.command.CommandSender
import org.bukkit.craftbukkit.v1_16_R3.CraftWorld
import org.bukkit.entity.Player
import java.util.*
@CommandAlias("mobcaps")
class CommandMobcaps(
private val reflectionUtil: ReflectionUtil
): BaseCommand() {
@Default
@Subcommand("view")
@CommandCompletion("@worlds")
fun onMobcaps(sender: CommandSender, @Optional worldName: String?) {
var craftWorld: CraftWorld? = null
if (sender is Player)
craftWorld = (sender.world as CraftWorld)
else if (worldName == null)
sender.sendMessage(Component.text("ERROR: You need to be a player or supply a world name!").color(TextColor.color(0x660000)))
var name = worldName
if (worldName == null) {
name = craftWorld?.name
} else {
val bukkitWorld = Bukkit.getWorld(worldName)
if (bukkitWorld == null)
name = craftWorld?.name
else
craftWorld = (bukkitWorld as CraftWorld)
}
val world = craftWorld?.handle ?: return
val chunkMapDistance = (
reflectionUtil.getValueFromField(world.getChunkProvider(), "chunkMapDistance")
?: return
) as ChunkMapDistance
val chunks = chunkMapDistance.b()
// world.getChunkManager().getSpawnInfo();
val spawnInfo = world.getChunkProvider()?.k() ?: return
val mobs: Object2IntMap<EnumCreatureType> = spawnInfo.b()
val mobcaps = EnumMap<EnumCreatureType, Pair<Int, Int>>(
EnumCreatureType::class.java
)
for (category in EnumCreatureType.values()) {
if (category == EnumCreatureType.MISC) continue
val cur: Int = mobs[category]?: 0
val max = chunks * category.c() / (17 * 17)
mobcaps[category] = Pair(cur, max)
}
sender.sendMessage("=============Mobcaps [${name}]=============")
for ((key, value) in mobcaps) {
val cur = value.first
val max = value.second
sender.sendMessage("${key.getName()}: ${cur}/${max}")
}
}
}

View File

@ -0,0 +1,28 @@
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)
}
}

View File

@ -0,0 +1,25 @@
package nl.kallestruik.dtweaks.commands
import co.aikar.commands.BaseCommand
import co.aikar.commands.annotation.CommandAlias
import co.aikar.commands.annotation.Conditions
import co.aikar.commands.annotation.Subcommand
import nl.kallestruik.dtweaks.managers.PocketDimensionManager
import org.bukkit.entity.Player
@CommandAlias("pocketdim")
@Conditions("tweakEnabled:tweak=SpaceTimePockets")
class CommandPocketdim(
private val pocketDimensionManager: PocketDimensionManager
): BaseCommand() {
@Subcommand("create")
fun onCreate(sender: Player) {
pocketDimensionManager.createPocketForPlayer(sender)
}
@Subcommand("tp")
fun onTp(sender: Player) {
pocketDimensionManager.teleportPlayerIntoPocket(sender, sender.uniqueId)
}
}

View File

@ -0,0 +1,26 @@
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.Default
import nl.kallestruik.dtweaks.managers.TrampleManager
import org.bukkit.ChatColor
import org.bukkit.entity.Player
@CommandAlias("toggletrample")
@Conditions("tweakEnabled:tweak=PlayersCantTrampleCrops")
class CommandToggletrample(
private val trampleManager: TrampleManager
): BaseCommand() {
@Default
fun onToggle(sender: Player) {
if (trampleManager.trampleEnabled.remove(sender.uniqueId)) {
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&2Crop Trampling: &4&lDisabled"))
} else {
trampleManager.trampleEnabled.add(sender.uniqueId)
sender.sendMessage(ChatColor.translateAlternateColorCodes('&', "&2Crop Trampling: &2&lEnabled"))
}
}
}

View File

@ -0,0 +1,30 @@
package nl.kallestruik.dtweaks.fakeplayer
import io.netty.util.concurrent.Future
import io.netty.util.concurrent.GenericFutureListener
import net.minecraft.server.v1_16_R3.EnumProtocolDirection
import net.minecraft.server.v1_16_R3.NetworkManager
import net.minecraft.server.v1_16_R3.Packet
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() {}
}

View File

@ -0,0 +1,168 @@
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
(DTweaks.reflectionUtil.getValueFromField(
serverConnection!!,
"connectedChannels"
) as MutableList<NetworkManager?>).add(connection)
// Connect the fake player to the server using the fake connection.
FakePlayerList.a(minecraftServer.playerList, connection, instance)
// Check if the fake player is not yet in the correct world.
if (instance.world.dimensionKey != worldServer.dimensionKey) {
// Store the old world of the fake player.
val old_world = instance.world as WorldServer
// Remove the fake player from the old world.
old_world.removePlayer(instance)
// Make the fake player not be dead.
instance.dead = false
// Create the fake player in the new world.
worldServer.addEntity(instance)
// Spawn the fake player in the new world.
instance.spawnIn(worldServer)
// Move the fake player to the new world for the server.
minecraftServer.playerList.moveToWorld(instance, old_world, true, null, false)
// requestTeleport(x, y, z, yaw, pitch)
// Request the teleport from the fake player.
instance.playerConnection.a(x, y, z, yaw.toFloat(), pitch.toFloat())
// Set the fake player's world to the new world.
instance.playerInteractManager.world = worldServer
instance.teleportTo(worldServer, BlockPosition(x, y, z))
}
/// Set the fake players health to max.
instance.health = 20.0f
// Make the fake player not be dead.
instance.dead = false
// a == requestTeleport
// Request the teleport from the fake player.
instance.playerConnection.a(x, y, z, yaw.toFloat(), pitch.toFloat())
// G == stepHeight
// Set the fake players step height to 0.6 (The normal value).
instance.G = 0.6f
// Set the fake players gamemode to survival.
playerInteractManager.gameMode = EnumGamemode.SURVIVAL
// Tell everyone in the world about the fake player and where he is.
minecraftServer.playerList.a(
PacketPlayOutEntityHeadRotation(instance, (instance.yaw * 256 / 360).toByte()),
instance.world.dimensionKey
)
minecraftServer.playerList.a(PacketPlayOutEntityTeleport(instance), instance.world.dimensionKey)
// Move the fake player for the worlds chunk provider.
instance.worldServer.getChunkProvider().movePlayer(instance)
// bp == PLAYER_MODEL_PARTS
instance.datawatcher.set<Byte>(bj, 0x7f.toByte()) // show all model layers (incl. capes)
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 die(cause: DamageSource?) {
super.die(cause)
health = 20f
foodData = FoodMetaData(this)
killEntity()
}
}

View File

@ -0,0 +1,36 @@
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
}
}

View File

@ -0,0 +1,258 @@
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
)
)
}
}
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

@ -0,0 +1,30 @@
package nl.kallestruik.dtweaks.managers
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)
}
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()
}
}
}

View File

@ -0,0 +1,110 @@
package nl.kallestruik.dtweaks.managers
import net.minecraft.server.v1_16_R3.MathHelper
import nl.kallestruik.dlib.MathHelper
import nl.kallestruik.dtweaks.spacetimepockets.SpaceTimePocketChunkGenerator
import org.bukkit.*
import org.bukkit.entity.Player
import java.util.*
class PocketDimensionManager(
private val mathHelper: MathHelper
) {
val pocketDimension: World = WorldCreator.name("space-time-pockets").generator(SpaceTimePocketChunkGenerator()).createWorld()!!
private val data = HashMap<UUID, PocketData>()
private var lastCreatedPocket = -1
fun loadData() {
//TODO: Load data from data file on disk.
}
fun saveData() {
//TODO: Save data to file on disk.
}
fun teleportPlayerIntoPocket(player: Player, pocketOwner: UUID) {
var pocketData = data[pocketOwner]
if (pocketData == null) pocketData = if (player.uniqueId == pocketOwner) {
createPocketForPlayer(player)
} else return
player.teleport(
Location(
pocketDimension, (pocketData.startX + 9).toDouble(), 128.0,
(pocketData.startZ + 9).toDouble()
)
)
Bukkit.unloadWorld()
}
fun createPocketForPlayer(player: Player): PocketData {
// Find a spot
val point = findNextFree()
// Load the chunks
for (x in 0..2) {
for (y in 0..2) {
pocketDimension.loadChunk(point.x / 16 + x, point.z / 16 + y)
}
}
// Build the box
for (x in 0..17) {
for (z in 0..17) {
for (y in 0..255) {
if (x == 0 || y == 0 || z == 0 || x == 17 || y == 255 || z == 17) {
pocketDimension.getBlockAt(point.x + x, y, point.z + z).type = Material.BLACK_CONCRETE
}
}
}
}
// Create the spawning platform
pocketDimension.getBlockAt(point.x + 8, 127, point.z + 8).type = Material.STONE
pocketDimension.getBlockAt(point.x + 8, 127, point.z + 9).type = Material.STONE
pocketDimension.getBlockAt(point.x + 9, 127, point.z + 8).type = Material.STONE
pocketDimension.getBlockAt(point.x + 9, 127, point.z + 9).type = Material.STONE
// Unload the chunks
for (x in 0..2) {
for (y in 0..2) {
pocketDimension.unloadChunk(point.x / 16 + x, point.z / 16 + y)
}
}
val pocketData = PocketData(player.uniqueId, point.x, point.z, ArrayList())
data[player.uniqueId] = pocketData
return pocketData
}
private fun findNextFree(): Point {
while (true) {
lastCreatedPocket++
val toCheck = getXYForIndex(lastCreatedPocket)
val chunk = pocketDimension.getChunkAt(
Location(
pocketDimension,
toCheck.x.toDouble(), 0.0, toCheck.z.toDouble()
)
)
val corner = chunk.getBlock(mathHelper.chunkAbs(toCheck.x % 16), 0, mathHelper.chunkAbs(toCheck.z % 16))
if (corner.type == Material.AIR) {
return toCheck
}
}
}
private fun getXYForIndex(index: Int): Point {
// Space the pockets 256 blocks (16 chunks) from each other with each pocket being 16 blocks (and two for walls)
// Also subtract 1 from each point so the interior is chunk aligned.
val x = (256 + 16) * (index % 1000) - 1
val z = (256 + 16) * (index / 1000) - 1
return Point(x, z)
}
class PocketData(var owner: UUID, var startX: Int, var startZ: Int, var queuedGateways: ArrayList<GatewayData?>)
class GatewayData
class Point(var x: Int, var y: Int, var z: Int) {
constructor(x: Int, z: Int) : this(x, 0, z) {}
}
}

View File

@ -0,0 +1,36 @@
package nl.kallestruik.dtweaks.managers
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration
import java.io.File
import java.io.IOException
import java.util.*
class TrampleManager {
var trampleEnabled = HashSet<UUID>()
@Throws(IOException::class, InvalidConfigurationException::class)
fun loadFromFile(file: File) {
file.parentFile.mkdirs()
file.createNewFile()
val config = YamlConfiguration()
config.load(file)
for (item in config.getStringList("enabled"))
trampleEnabled.add(UUID.fromString(item))
}
@Throws(IOException::class, InvalidConfigurationException::class)
fun saveToFile(file: File) {
file.parentFile.mkdirs()
file.createNewFile()
val config = YamlConfiguration()
config.load(file)
val list: MutableList<String> = ArrayList()
for (entry in trampleEnabled)
list.add(entry.toString())
config["enabled"] = list
config.save(file)
}
}

View File

@ -0,0 +1,116 @@
package nl.kallestruik.dtweaks.managers
import nl.kallestruik.dtweaks.Const
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.configuration.InvalidConfigurationException
import org.bukkit.configuration.file.YamlConfiguration
import org.bukkit.plugin.java.JavaPlugin
import java.io.File
import java.io.IOException
import java.util.concurrent.ConcurrentHashMap
class TweakManager(
private val plugin: JavaPlugin
) {
// A HashMap containing the tweak identifier mapped to the instance of the tweak.
private val tweaks: ConcurrentHashMap<String, ITweak> = ConcurrentHashMap<String, ITweak>()
// A HashMap containing categories and the tweak identifiers that belong to them.
private val tweakCategories = HashMap<String, List<String>>()
// A HashMap containing the sate of all the known tweaks.
private val tweakStates = HashMap<String, Boolean>()
/**
* Register a new tweak.
*
* @param tweak An instance of the tweak.
* @return True if the tweak did not yet exist false otherwise.
*/
fun registerTweak(tweak: ITweak): Boolean {
if (tweaks.containsKey(tweak.getIdentifier())) return false
tweaks[tweak.getIdentifier()] = tweak
tweakCategories[tweak.getIdentifier()] = tweak.getCategories()
tweak.onRegister()
if (tweakStates.getOrDefault(tweak.getIdentifier(), false)) tweak.onEnable()
return true
}
/**
* Unregister a tweak.
*
* @param identifier The identifier of the tweak to unregister.
* @return True if the tweak was successfully unregistered false otherwise.
*/
fun unRegisterTweak(identifier: String): Boolean {
if (!tweaks.containsKey(identifier)) return false
val tweak: ITweak? = tweaks[identifier]
tweak?.onDisable()
tweak?.onUnRegister()
tweaks.remove(identifier)
return true
}
/**
* Unregister every tweak that is currently registered.
*/
fun unRegisterAllTweaks() {
for (identifier in tweaks.keys) {
unRegisterTweak(identifier)
}
}
/**
* Enable a tweak.
*
* @param identifier The identifier of the tweak.
* @return True if the tweak exists false otherwise.
*/
fun enableTweak(identifier: String): Boolean {
if (!tweaks.containsKey(identifier)) return false
tweakStates[identifier] = true
tweaks[identifier]?.onEnable()
return true
}
/**
* Disable a tweak.
*
* @param identifier The identifier of the tweak.
* @return True if the tweak exists false otherwise.
*/
fun disableTweak(identifier: String): Boolean {
if (!tweaks.containsKey(identifier)) return false
tweakStates[identifier] = false
tweaks[identifier]?.onDisable()
return true
}
@Throws(IOException::class, InvalidConfigurationException::class)
fun loadFromFile(file: File) {
if (!file.parentFile.exists()) file.parentFile.mkdirs()
if (!file.exists())
plugin.saveResource(file.name, false)
val config = YamlConfiguration()
config.load(file)
for (key in config.getKeys(false)) {
tweakStates[key] = config.getBoolean(key!!)
}
}
@Throws(IOException::class)
fun saveToFile(file: File) {
val config = YamlConfiguration()
for ((key, value) in tweakStates.entries) {
config[key] = value
}
config.save(file)
}
fun isTweakEnabled(tweakId: String): Boolean {
return tweakStates[tweakId] ?: false
}
}

View File

@ -0,0 +1,27 @@
package nl.kallestruik.dtweaks.spacetimepockets
import org.bukkit.World
import org.bukkit.block.Biome
import org.bukkit.craftbukkit.v1_16_R3.generator.CraftChunkData
import org.bukkit.generator.ChunkGenerator
import java.util.*
class SpaceTimePocketChunkGenerator: ChunkGenerator() {
override fun generateChunkData(
world: World,
random: Random,
x: Int,
z: Int,
biome: BiomeGrid
): ChunkData {
for (cx in 0..15) {
for (cz in 0..15) {
for (cy in 0..264) {
biome.setBiome(cx, cy, cz, Biome.THE_VOID)
}
}
}
return CraftChunkData(world)
}
}

View File

@ -0,0 +1,17 @@
package nl.kallestruik.dtweaks.tweaks
import org.bukkit.plugin.java.JavaPlugin
interface ITweak {
fun getIdentifier(): String
fun getCategories(): List<String>
fun onRegister() {}
fun onUnRegister() {}
fun onEnable() {}
fun onDisable() {}
}

View File

@ -0,0 +1,32 @@
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 AlternativeDispenserRecipe(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "dispenser")
override fun getIdentifier(): String = "AlternativeDispenserRecipe"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val dispenserRecipe = ShapedRecipe(recipeKey, ItemStack(Material.DISPENSER))
dispenserRecipe.shape(" TS", "TDS", " TS")
dispenserRecipe.setIngredient('T', Material.STICK)
dispenserRecipe.setIngredient('D', Material.DROPPER)
dispenserRecipe.setIngredient('S', Material.STRING)
plugin.server.addRecipe(dispenserRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,31 @@
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 CraftableDragonsBreath(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "dragon_breath")
override fun getIdentifier(): String = "CraftableDragonsBreath"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val dragonBreathRecipe = ShapedRecipe(recipeKey, ItemStack(Material.DRAGON_BREATH, 3))
dragonBreathRecipe.shape("GCG", " G ")
dragonBreathRecipe.setIngredient('G', Material.GLASS)
dragonBreathRecipe.setIngredient('C', Material.POPPED_CHORUS_FRUIT)
plugin.server.addRecipe(dragonBreathRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,32 @@
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 CraftableNametag(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "nametag")
override fun getIdentifier(): String = "CraftableNametag"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val nametagRecipe = ShapedRecipe(recipeKey, ItemStack(Material.NAME_TAG))
nametagRecipe.shape(" IS", " PI", "P ")
nametagRecipe.setIngredient('I', Material.IRON_INGOT)
nametagRecipe.setIngredient('P', Material.PAPER)
nametagRecipe.setIngredient('S', Material.STRING)
plugin.server.addRecipe(nametagRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,32 @@
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 CraftableSaddle(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "saddle")
override fun getIdentifier(): String = "CraftableSaddle"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val saddleRecipe = ShapedRecipe(recipeKey, ItemStack(Material.SADDLE))
saddleRecipe.shape("LLL", "S S", "I I")
saddleRecipe.setIngredient('L', Material.LEATHER)
saddleRecipe.setIngredient('S', Material.STRING)
saddleRecipe.setIngredient('I', Material.IRON_INGOT)
plugin.server.addRecipe(saddleRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,31 @@
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 CraftableShulkerShell(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "shulker_shell")
override fun getIdentifier(): String = "CraftableShulkerShell"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val shulkerShellRecipe = ShapedRecipe(recipeKey, ItemStack(Material.SHULKER_SHELL))
shulkerShellRecipe.shape("BBB", "F F")
shulkerShellRecipe.setIngredient('B', Material.PURPUR_SLAB)
shulkerShellRecipe.setIngredient('F', Material.POPPED_CHORUS_FRUIT)
plugin.server.addRecipe(shulkerShellRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,31 @@
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 CraftableSponge(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "sponge")
override fun getIdentifier(): String = "CraftableSponge"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val spongeRecipe = ShapedRecipe(recipeKey, ItemStack(Material.SPONGE))
spongeRecipe.shape("KKK", "KDK", "KKK")
spongeRecipe.setIngredient('K', Material.KELP)
spongeRecipe.setIngredient('D', Material.YELLOW_DYE)
plugin.server.addRecipe(spongeRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,36 @@
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.ShapelessRecipe
import org.bukkit.plugin.java.JavaPlugin
class IceDecompression(
private val plugin: JavaPlugin
): ITweak {
private var packedIceKey = NamespacedKey(plugin, "packed_ice")
private var iceKey = NamespacedKey(plugin, "ice")
override fun getIdentifier(): String = "IceDecompression"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
// Blue Ice -> Packed Ice
val packedIceRecipe = ShapelessRecipe(packedIceKey, ItemStack(Material.PACKED_ICE, 9))
packedIceRecipe.addIngredient(Material.BLUE_ICE)
plugin.server.addRecipe(packedIceRecipe)
// Packed Ice -> Ice
val iceRecipe = ShapelessRecipe(iceKey, ItemStack(Material.ICE, 9))
iceRecipe.addIngredient(Material.PACKED_ICE)
plugin.server.addRecipe(iceRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(packedIceKey)
plugin.server.removeRecipe(iceKey)
}
}

View File

@ -0,0 +1,32 @@
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.plugin.java.JavaPlugin
class LogsToChests(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "chest")
override fun getIdentifier(): String = "LogsToChests"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val chestRecipe = ShapedRecipe(recipeKey, ItemStack(Material.CHEST, 4))
chestRecipe.shape("WWW", "W W", "WWW")
chestRecipe.setIngredient('W', RecipeChoice.MaterialChoice(Tag.LOGS))
plugin.server.addRecipe(chestRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,47 @@
package nl.kallestruik.dtweaks.tweaks.craftingtweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Material
import org.bukkit.NamespacedKey
import org.bukkit.inventory.ItemStack
import org.bukkit.inventory.RecipeChoice
import org.bukkit.inventory.ShapedRecipe
import org.bukkit.plugin.java.JavaPlugin
class RedyeTerracotta(
private val plugin: JavaPlugin
): ITweak {
private val blackRecipeKey = NamespacedKey(plugin, "black_terracotta")
private val blueRecipeKey = NamespacedKey(plugin, "blue_terracotta")
private val brownRecipeKey = NamespacedKey(plugin, "brown_terracotta")
private val cyanRecipeKey = NamespacedKey(plugin, "cyan_terracotta")
private val blueRecipeKey = NamespacedKey(plugin, "blue_terracotta")
private val blueRecipeKey = NamespacedKey(plugin, "blue_terracotta")
private val allTerracotta = RecipeChoice.MaterialChoice(Material.TERRACOTTA, Material.BLACK_TERRACOTTA,
Material.BLUE_TERRACOTTA, Material.BROWN_TERRACOTTA, Material.CYAN_TERRACOTTA, Material.GRAY_TERRACOTTA,
Material.GREEN_TERRACOTTA, Material.LIGHT_BLUE_TERRACOTTA,
Material.LIGHT_GRAY_TERRACOTTA, Material.LIME_TERRACOTTA, Material.MAGENTA_TERRACOTTA,
Material.ORANGE_TERRACOTTA, Material.PINK_TERRACOTTA, Material.PURPLE_TERRACOTTA, Material.RED_TERRACOTTA,
Material.WHITE_TERRACOTTA, Material.YELLOW_TERRACOTTA)
override fun getIdentifier(): String = "RedyeTerracotta"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
addRecipe(blackRecipeKey, Material.BLACK_TERRACOTTA, Material.BLACK_DYE)
}
override fun onDisable() {
plugin.server.removeRecipe(blackRecipeKey)
}
private fun addRecipe(key: NamespacedKey, output: Material, dye: Material) {
val recipe = ShapedRecipe(key, ItemStack(output))
recipe.shape("TTT", "TDT", "TTT")
recipe.setIngredient('T', allTerracotta)
recipe.setIngredient('D', dye)
plugin.server.addRecipe(recipe)
}
}

View File

@ -0,0 +1,31 @@
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.ShapelessRecipe
import org.bukkit.plugin.java.JavaPlugin
class WoolToString(
private val plugin: JavaPlugin
): ITweak {
private var recipeKey = NamespacedKey(plugin, "string")
override fun getIdentifier(): String = "WoolToString"
override fun getCategories(): List<String> = listOf("crafting", "survival")
override fun onEnable() {
val stringRecipe = ShapelessRecipe(recipeKey, ItemStack(Material.STRING, 4))
stringRecipe.addIngredient(RecipeChoice.MaterialChoice(Tag.WOOL))
plugin.server.addRecipe(stringRecipe)
}
override fun onDisable() {
plugin.server.removeRecipe(recipeKey)
}
}

View File

@ -0,0 +1,62 @@
package nl.kallestruik.dtweaks.tweaks.croptweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Material
import org.bukkit.block.data.Ageable
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.plugin.java.JavaPlugin
class HoeHarvestArea(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "HoesHarvestArea"
override fun getCategories(): List<String> = listOf("crops", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onHoeBreaksBlock(event: BlockBreakEvent) {
val player = event.player
val block = event.block
val world = block.world
val itemInHand = player.inventory.itemInMainHand
val range = when(itemInHand.type) {
Material.WOODEN_HOE -> 1
Material.STONE_HOE -> 1
Material.IRON_HOE -> 1
Material.GOLDEN_HOE -> 1
Material.DIAMOND_HOE -> 2
Material.NETHERITE_HOE -> 2
else -> return
}
if (!isCrop(block.type)) return
val startLocation = block.location
for (x in -range..range) {
for (z in -range..range) {
val b = world.getBlockAt(startLocation.clone().add(x.toDouble(), 0.0, z.toDouble()))
if (isCrop(b.type)) {
val ageable = b.blockData as Ageable
if (ageable.age == ageable.maximumAge) {
b.breakNaturally()
}
}
}
}
}
private fun isCrop(material: Material): Boolean {
return material == Material.WHEAT || material == Material.BEETROOTS || material == Material.CARROTS || material == Material.POTATOES
}
}

View File

@ -0,0 +1,54 @@
package nl.kallestruik.dtweaks.tweaks.croptweaks
import nl.kallestruik.dlib.DUtil
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Location
import org.bukkit.Material
import org.bukkit.Particle
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.plugin.java.JavaPlugin
class LilypadBonemealing(
private val plugin: JavaPlugin,
private val util: DUtil
): ITweak, Listener {
override fun getIdentifier(): String = "LilypadBonemealing"
override fun getCategories(): List<String> = listOf("crops", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onRightClickBlock(event: PlayerInteractEvent) {
val player = event.player
if (event.hand != EquipmentSlot.HAND) return
if (event.action != Action.RIGHT_CLICK_BLOCK) return
if (event.clickedBlock == null) return
if (event.clickedBlock!!.type != Material.LILY_PAD) return
val itemInHand = player.inventory.itemInMainHand
if (itemInHand.type != Material.BONE_MEAL) return
val world = event.clickedBlock!!.world
val origin = event.clickedBlock!!.location
for (i in 0..5) {
val newPos: Location = origin.clone().add(util.getRandomLocationOffset(0, 3, false))
val newBlock = world.getBlockAt(newPos)
if (newBlock.type != Material.AIR) continue
if (newBlock.getRelative(0, -1, 0).type != Material.WATER) continue
newBlock.type = Material.LILY_PAD
world.spawnParticle(Particle.VILLAGER_HAPPY, newPos, 5, 0.5, 0.5, 0.5)
}
itemInHand.amount = itemInHand.amount - 1
}
}

View File

@ -0,0 +1,32 @@
package nl.kallestruik.dtweaks.tweaks.croptweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityChangeBlockEvent
import org.bukkit.plugin.java.JavaPlugin
class MobsCantTrampleCrops(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "MobsCantTrampleCrops"
override fun getCategories(): List<String> = listOf("crops", "mobs", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onBlockBreak(event: EntityChangeBlockEvent) {
if (event.block.type != Material.FARMLAND) return
if (event.entity is Player) return
event.isCancelled = true
}
}

View File

@ -0,0 +1,35 @@
package nl.kallestruik.dtweaks.tweaks.croptweaks
import nl.kallestruik.dtweaks.managers.TrampleManager
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Material
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityChangeBlockEvent
import org.bukkit.plugin.java.JavaPlugin
class PlayersCantTrampleCrops(
private val plugin: JavaPlugin,
private val trampleManager: TrampleManager
): ITweak, Listener {
override fun getIdentifier(): String = "PlayersCantTrampleCrops"
override fun getCategories(): List<String> = listOf("crops", "survival", "players")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onBlockBreak(event: EntityChangeBlockEvent) {
if (event.block.type != Material.FARMLAND) return
if (event.entity !is Player) return
if (trampleManager.trampleEnabled.contains(event.entity.uniqueId)) return
event.isCancelled = true
}
}

View File

@ -0,0 +1,65 @@
package nl.kallestruik.dtweaks.tweaks.croptweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Bukkit
import org.bukkit.Material
import org.bukkit.Particle
import org.bukkit.World
import org.bukkit.block.Block
import org.bukkit.entity.Item
import org.bukkit.event.Listener
import org.bukkit.plugin.java.JavaPlugin
import org.bukkit.scheduler.BukkitTask
class SeedDropPlanting(
private val plugin: JavaPlugin
): ITweak, Listener {
private lateinit var task: BukkitTask
override fun getIdentifier(): String = "SeedDropPlanting"
override fun getCategories(): List<String> = listOf("crops", "survival")
override fun onEnable() {
task = Bukkit.getScheduler().runTaskTimer(plugin, SeedPlantTask(plugin), (20 * 10).toLong(), (20 * 10).toLong())
}
override fun onDisable() {
task.cancel()
}
private class SeedPlantTask(
private val plugin: JavaPlugin
): Runnable {
override fun run() {
for (world in plugin.server.worlds) {
for (entity in world.entities) {
if (entity is Item) {
val b = world.getBlockAt(entity.location)
val above = world.getBlockAt(entity.location.add(0.0, 1.0, 0.0))
if (b.type == Material.FARMLAND && above.type == Material.AIR) {
when (entity.itemStack.type) {
Material.WHEAT_SEEDS -> plantSeed(entity, world, above, Material.WHEAT)
Material.BEETROOT_SEEDS -> plantSeed(entity, world, above, Material.BEETROOTS)
Material.MELON_SEEDS -> plantSeed(entity, world, above, Material.MELON_STEM)
Material.PUMPKIN_SEEDS -> plantSeed(entity, world, above, Material.PUMPKIN_STEM)
Material.POTATO -> plantSeed(entity, world, above, Material.POTATOES)
Material.CARROT -> plantSeed(entity, world, above, Material.CARROTS)
else -> continue
}
}
}
}
}
}
private fun plantSeed(entity: Item, world: World, block: Block, material: Material) {
block.type = material
world.spawnParticle(Particle.VILLAGER_HAPPY, entity.location, 10)
if (entity.itemStack.amount == 1) {
entity.remove()
} else {
entity.itemStack.amount = entity.itemStack.amount - 1
}
}
}
}

View File

@ -0,0 +1,53 @@
package nl.kallestruik.dtweaks.tweaks.croptweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Material
import org.bukkit.Particle
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.block.Action
import org.bukkit.event.player.PlayerInteractEvent
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.plugin.java.JavaPlugin
class SugarcaneBonemealing(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "SugarcaneBonemealing"
override fun getCategories(): List<String> = listOf("crops", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onRightClickBlock(event: PlayerInteractEvent) {
val player = event.player
if (event.hand != EquipmentSlot.HAND) return
if (event.action != Action.RIGHT_CLICK_BLOCK) return
if (event.clickedBlock == null) return
if (event.clickedBlock!!.type != Material.SUGAR_CANE) return
val itemInHand = player.inventory.itemInMainHand
if (itemInHand.type != Material.BONE_MEAL) return
val world = event.clickedBlock!!.world
val origin = event.clickedBlock!!.location
for (i in 0..3) {
val newPos = origin.clone().add(0.0, i.toDouble(), 0.0)
val newBlock = world.getBlockAt(newPos)
if (newBlock.type != Material.AIR) continue
if (newBlock.getRelative(0, -1, 0).type != Material.SUGAR_CANE) continue
newBlock.type = Material.SUGAR_CANE
world.spawnParticle(Particle.VILLAGER_HAPPY, newPos, 5, 0.5, 0.5, 0.5)
itemInHand.amount = itemInHand.amount - 1
break
}
}
}

View File

@ -0,0 +1,74 @@
package nl.kallestruik.dtweaks.tweaks.dispsensertweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Material
import org.bukkit.Particle
import org.bukkit.Tag
import org.bukkit.block.BlockFace
import org.bukkit.block.data.type.Dispenser
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockDispenseEvent
import org.bukkit.plugin.java.JavaPlugin
class DispensersCanPlantSaplings(
private val plugin: JavaPlugin
): ITweak, Listener {
private val treePlantable = setOf(Material.DIRT, Material.COARSE_DIRT, Material.GRASS_BLOCK, Material.PODZOL, Material.MYCELIUM)
override fun getIdentifier(): String = "DispensersCanPlantSaplings"
override fun getCategories(): List<String> = listOf("dispenser", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onDispenserDispense(event: BlockDispenseEvent) {
if (event.block.type != Material.DISPENSER) return
if (Tag.SAPLINGS.isTagged(event.item.type)) {
val dispenser = event.block.blockData as Dispenser
val facing = dispenser.facing
val targetBlock = if (facing == BlockFace.UP) {
event.block.world.getBlockAt(event.block.location.add(0.0, 2.0, 0.0))
} else {
event.block.world.getBlockAt(
event.block.location.add(
facing.modX.toDouble(),
facing.modY.toDouble(),
facing.modZ.toDouble()
)
)
}
if (targetBlock.type == Material.AIR
&& treePlantable.contains(
event.block.world.getBlockAt(
targetBlock.location.add(
0.0,
-1.0,
0.0
)
).type
)
) {
targetBlock.type = event.item.type
event.isCancelled = true
val dispenserInventory = (event.block.state as org.bukkit.block.Dispenser).inventory
var slot = 0
for (`is` in dispenserInventory.contents) {
if (`is` != null && `is`.type == event.item.type) break
slot++
}
val newItemStack = dispenserInventory.getItem(slot)
newItemStack!!.amount = newItemStack.amount - 1
dispenserInventory.setItem(slot, newItemStack)
event.block.world.spawnParticle(Particle.VILLAGER_HAPPY, targetBlock.location, 5)
}
}
}
}

View File

@ -0,0 +1,52 @@
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.entity.ArmorStand
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerInteractAtEntityEvent
import org.bukkit.inventory.EquipmentSlot
import org.bukkit.plugin.java.JavaPlugin
class ArmorStandArmorSwapping(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "ArmorStandArmorSwapping"
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: PlayerInteractAtEntityEvent) {
if (event.player.isSneaking) {
if (event.rightClicked is ArmorStand) {
val armorStand = event.rightClicked as ArmorStand
val standEquipment = armorStand.equipment
val player = event.player
val playerEquipment = player.equipment
if (standEquipment == null || playerEquipment == null) return
val playerHelmet = playerEquipment.helmet
val playerChestplate = playerEquipment.chestplate
val playerLeggings = playerEquipment.leggings
val playerBoots = playerEquipment.boots
player.inventory.helmet = standEquipment.helmet
player.inventory.chestplate = standEquipment.chestplate
player.inventory.leggings = standEquipment.leggings
player.inventory.boots = standEquipment.boots
armorStand.setItem(EquipmentSlot.HEAD, playerHelmet)
armorStand.setItem(EquipmentSlot.CHEST, playerChestplate)
armorStand.setItem(EquipmentSlot.LEGS, playerLeggings)
armorStand.setItem(EquipmentSlot.FEET, playerBoots)
event.isCancelled = true
}
}
}
}

View File

@ -0,0 +1,151 @@
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
import com.comphenix.protocol.PacketType
import com.comphenix.protocol.ProtocolLibrary
import com.comphenix.protocol.events.PacketAdapter
import com.comphenix.protocol.events.PacketEvent
import com.comphenix.protocol.wrappers.BlockPosition
import com.comphenix.protocol.wrappers.EnumWrappers.Hand
import nl.kallestruik.dlib.MathHelper
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.Bukkit
import org.bukkit.block.BlockFace
import org.bukkit.block.data.Bisected
import org.bukkit.block.data.BlockData
import org.bukkit.block.data.Directional
import org.bukkit.block.data.type.Comparator
import org.bukkit.block.data.type.Repeater
import org.bukkit.block.data.type.Stairs
import org.bukkit.block.data.type.TrapDoor
import org.bukkit.entity.Player
import org.bukkit.event.Listener
import org.bukkit.inventory.ItemStack
import org.bukkit.plugin.java.JavaPlugin
class CarpetBlockPlacingProtocol(
private val plugin: JavaPlugin,
private val mathHelper: MathHelper
): ITweak, Listener {
private val protocolManager = ProtocolLibrary.getProtocolManager()
private var packetListener: PacketListener? = null
override fun getIdentifier(): String = "CarpetBlockPlacingProtocol"
override fun getCategories(): List<String> = listOf("player", "survival")
override fun onEnable() {
this.packetListener = PacketListener(plugin, PacketType.Play.Client.USE_ITEM, mathHelper)
protocolManager.addPacketListener(this.packetListener)
}
override fun onDisable() {
protocolManager.removePacketListener(this.packetListener)
}
internal class PacketListener(
plugin: JavaPlugin?,
packetType: PacketType?,
private val mathHelper: MathHelper
): PacketAdapter(plugin, packetType) {
override fun onPacketReceiving(event: PacketEvent) {
// Make sure the packet is the one we expect.
if (event.packetType !== PacketType.Play.Client.USE_ITEM) return
// Get the hand that the player used.
val hand = event.packet.hands.values[0] ?: return
// Get the MovingObjectPositionBlock and make sure it is not null.
val mopd = event.packet.movingBlockPositions.values[0] ?: return
val player = event.player
// Get the item stack that was clicked with.
val itemStack =
if (hand == Hand.MAIN_HAND) player.inventory.itemInMainHand else player.inventory.itemInOffHand
// Get the hitPos and BlockPos from the mopd.
val hitPos = mopd.posVector
val pos = mopd.blockPosition
// Calculate hitX.
val hitX = hitPos.x - pos.x
// Nothing special so ignore this packet.
if (hitX < 2) return
val code = (hitX - 2).toInt() / 2
val blockData: BlockData = getBlockDataFromCode(code, itemStack, player, pos) ?: return
Bukkit.getScheduler().runTask(plugin, Runnable {
val blockToChange = player.world.getBlockAt(pos.x, pos.y, pos.z)
blockToChange.blockData = blockData
// Cancel any further processing
event.isCancelled = true
// Take one item from the players inventory.
itemStack.amount = itemStack.amount - 1
})
}
private fun getBlockDataFromCode(code: Int, itemStack: ItemStack, player: Player, pos: BlockPosition): BlockData? {
val blockData = Bukkit.createBlockData(itemStack.type)
if (blockData is Repeater) {
val repeater = blockData
val delay: Int = mathHelper.clamp(code shr 4, 1, 4)
repeater.facing = horizontalBlockFaceFromCode(code and 0xF, player)!!
repeater.delay = delay
return repeater
} else if (blockData is TrapDoor) {
val trapDoor = blockData
val block = player.world.getBlockAt(pos.x, pos.y, pos.z)
trapDoor.facing = blockFaceFromCode(code and 0xF)
trapDoor.half = if (code > 0xF) Bisected.Half.TOP else Bisected.Half.BOTTOM
trapDoor.isOpen = block.isBlockPowered || block.isBlockIndirectlyPowered
return trapDoor
} else if (blockData is Comparator) {
val comparator = blockData
val mode = if (code > 0xF) Comparator.Mode.SUBTRACT else Comparator.Mode.COMPARE
comparator.facing = horizontalBlockFaceFromCode(code and 0xF, player)!!
comparator.mode = mode
return comparator
} else if (blockData is Stairs) {
val stairs = blockData
stairs.facing = blockFaceFromCode(code and 0xF)
stairs.half = if (code > 0xF) Bisected.Half.TOP else Bisected.Half.BOTTOM
return stairs
} else if (blockData is Directional) {
val directional = blockData
val possibilities = directional.faces
// Check what type of directional we are dealing with.
if (possibilities.contains(BlockFace.UP)) {
directional.facing = blockFaceFromCode(code)
} else {
directional.facing = horizontalBlockFaceFromCode(code, player)!!
}
return directional
}
return null
}
private fun blockFaceFromCode(code: Int): BlockFace {
return when (code) {
0 -> BlockFace.DOWN
1 -> BlockFace.UP
2 -> BlockFace.NORTH
3 -> BlockFace.SOUTH
4 -> BlockFace.WEST
5 -> BlockFace.EAST
else -> BlockFace.SELF
}
}
private fun blockFaceFromRotation(rotation: Float): BlockFace? {
return if (rotation < 45 && rotation >= -45) BlockFace.SOUTH else if (rotation < 135 && rotation >= 45) BlockFace.WEST else if (rotation >= 135 && rotation < -135) BlockFace.NORTH else BlockFace.EAST
}
private fun horizontalBlockFaceFromCode(code: Int, player: Player): BlockFace? {
val face = blockFaceFromCode(code)
return if (face == BlockFace.UP || face == BlockFace.DOWN) {
blockFaceFromRotation(player.location.yaw)
} else face
}
}
}

View File

@ -0,0 +1,15 @@
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()
}
}

View File

@ -0,0 +1,70 @@
package nl.kallestruik.dtweaks.tweaks.miscellaneoustweaks
import nl.kallestruik.dtweaks.managers.PocketDimensionManager
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.entity.Player
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.block.BlockBreakEvent
import org.bukkit.event.entity.CreatureSpawnEvent
import org.bukkit.event.entity.EntityDamageEvent
import org.bukkit.event.player.PlayerMoveEvent
import org.bukkit.plugin.java.JavaPlugin
class SpaceTimePockets(
private val plugin: JavaPlugin,
private val pocketDimensionManager: PocketDimensionManager
): ITweak, Listener {
override fun getIdentifier(): String = "SpaceTimePockets"
override fun getCategories(): List<String> = listOf("miscellaneous", "survival")
override fun onRegister() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onUnRegister() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onBlockBreak(event: BlockBreakEvent) {
if (event.player.world != pocketDimensionManager.pocketDimension) {
return
}
if (event.block.location.chunk == event.player.location.chunk && event.block.y != 0 && event.block.y != 255) return
event.isCancelled = true
event.player.sendMessage("It seems like a bad idea to break the only thing keeping you from getting lost into the endlessness around you.")
}
@EventHandler
fun onMobSpawn(event: CreatureSpawnEvent) {
if (pocketDimensionManager.pocketDimension != event.location.world) return
event.isCancelled = true
}
@EventHandler
fun onPlayerDamage(event: EntityDamageEvent) {
if (event.entity !is Player) return
if (pocketDimensionManager.pocketDimension != event.entity.world) return
event.isCancelled = true
}
@EventHandler
fun onPlayerFall(event: PlayerMoveEvent) {
if (pocketDimensionManager.pocketDimension != event.from.world
|| pocketDimensionManager.pocketDimension != event.to.world
) return
if (event.from.chunk != event.to.chunk) {
event.player.sendMessage("Something pulls you back from the darkness.")
event.isCancelled = true
}
if (event.to.blockY < 0 || event.to.blockY > 256) {
event.player.sendMessage("Something pulls you back from the darkness.")
val safeLocation = event.player.location
safeLocation.y = 128.0
event.player.teleport(safeLocation)
}
}
}

View File

@ -0,0 +1,33 @@
package nl.kallestruik.dtweaks.tweaks.mobtweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.entity.Creeper
import org.bukkit.entity.EntityType
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityExplodeEvent
import org.bukkit.plugin.java.JavaPlugin
class NoCreeperGrief(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "NoCreeperGrief"
override fun getCategories(): List<String> = listOf("mobs", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onCreeperExplode(event: EntityExplodeEvent) {
if (event.entityType != EntityType.CREEPER) return
val creeper = event.entity as Creeper
creeper.world.createExplosion(creeper.location, event.yield, false, false)
event.isCancelled = true
}
}

View File

@ -0,0 +1,28 @@
package nl.kallestruik.dtweaks.tweaks.mobtweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityBreakDoorEvent
import org.bukkit.plugin.java.JavaPlugin
class NoDoorBreaking(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "NoDoorBreaking"
override fun getCategories(): List<String> = listOf("mobs", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onDoorBreak(event: EntityBreakDoorEvent) {
event.isCancelled = true
}
}

View File

@ -0,0 +1,30 @@
package nl.kallestruik.dtweaks.tweaks.mobtweaks
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.entity.EntityType
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.entity.EntityChangeBlockEvent
import org.bukkit.plugin.java.JavaPlugin
class NoEndermanGrief(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "NoEndermanGrief"
override fun getCategories(): List<String> = listOf("mobs", "survival")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onEndermanPickupBlock(event: EntityChangeBlockEvent) {
if (event.entityType != EntityType.ENDERMAN) return
event.isCancelled = true
}
}

View File

@ -0,0 +1,112 @@
package nl.kallestruik.dtweaks.tweaks.mobtweaks
import net.minecraft.server.v1_16_R3.Activity
import net.minecraft.server.v1_16_R3.EntityVillager
import net.minecraft.server.v1_16_R3.GlobalPos
import net.minecraft.server.v1_16_R3.MemoryModuleType
import nl.kallestruik.dtweaks.tweaks.ITweak
import org.bukkit.craftbukkit.v1_16_R3.entity.CraftVillager
import org.bukkit.entity.Villager
import org.bukkit.event.EventHandler
import org.bukkit.event.HandlerList
import org.bukkit.event.Listener
import org.bukkit.event.player.PlayerInteractEntityEvent
import org.bukkit.plugin.java.JavaPlugin
import java.util.concurrent.atomic.AtomicReference
class VillagerInfo(
private val plugin: JavaPlugin
): ITweak, Listener {
override fun getIdentifier(): String = "VillagerInfo"
override fun getCategories(): List<String> = listOf("mobs")
override fun onEnable() {
plugin.server.pluginManager.registerEvents(this, plugin)
}
override fun onDisable() {
HandlerList.unregisterAll(this)
}
@EventHandler
fun onInteractEvent(event: PlayerInteractEntityEvent) {
if (!event.player.isSneaking) return
val clicked = event.rightClicked as? Villager ?: return
val eVillager: EntityVillager = (clicked as CraftVillager).handle
val homePos: AtomicReference<GlobalPos?> = AtomicReference(null)
eVillager.behaviorController.getMemory(MemoryModuleType.HOME)
.ifPresent { newValue -> homePos.set(newValue) }
val workPos: AtomicReference<GlobalPos?> = AtomicReference(null)
eVillager.behaviorController.getMemory(MemoryModuleType.JOB_SITE).ifPresent { newValue ->
workPos.set(
newValue
)
}
val meetingPos: AtomicReference<GlobalPos?> = AtomicReference(null)
eVillager.behaviorController.getMemory(MemoryModuleType.MEETING_POINT).ifPresent { newValue ->
meetingPos.set(
newValue
)
}
val lastWork: AtomicReference<Long?> = AtomicReference(null)
eVillager.behaviorController.getMemory(MemoryModuleType.LAST_WORKED_AT_POI).ifPresent { newValue ->
lastWork.set(
newValue
)
}
val lastSleep: AtomicReference<Long?> = AtomicReference(null)
eVillager.behaviorController.getMemory(MemoryModuleType.LAST_SLEPT).ifPresent { newValue ->
lastSleep.set(
newValue
)
}
val seenIGRecently: AtomicReference<Boolean?> = AtomicReference(null)
eVillager.behaviorController.getMemory(MemoryModuleType.GOLEM_DETECTED_RECENTLY).ifPresent { newValue ->
seenIGRecently.set(
newValue
)
}
val isPanicking: Boolean = eVillager.behaviorController.c(Activity.PANIC)
val player = event.player
player.sendMessage("=====Villager Info=====")
player.sendMessage("Type: " + clicked.villagerType)
player.sendMessage("Profession: " + clicked.profession)
player.sendMessage("Level: " + clicked.villagerLevel + "(" + clicked.villagerExperience + " xp)")
player.sendMessage("Panic: $isPanicking")
if (homePos.get() != null) player.sendMessage(
java.lang.String.format(
"Home: %s, %s, %s",
homePos.get()?.blockPosition?.x,
homePos.get()?.blockPosition?.y,
homePos.get()?.blockPosition?.z
)
)
if (workPos.get() != null) player.sendMessage(
java.lang.String.format(
"Work: %s, %s, %s",
workPos.get()?.blockPosition?.x,
workPos.get()?.blockPosition?.y,
workPos.get()?.blockPosition?.z
)
)
if (homePos.get() != null) player.sendMessage(
java.lang.String.format(
"Meeting point: %s, %s, %s",
meetingPos.get()?.blockPosition?.x,
meetingPos.get()?.blockPosition?.y,
meetingPos.get()?.blockPosition?.z
)
)
if (lastSleep.get() != null)
player.sendMessage("Last slept: ${lastSleep.get()}")
if (seenIGRecently.get() != null)
player.sendMessage("Seen iron golem Recently: ${seenIGRecently.get()}")
}
}

View File

@ -0,0 +1,17 @@
name: DTweaks
version: ${version}
main: nl.kallestruik.dtweaks.DTweaks
api-version: 1.16
depend:
- "ProtocolLib"
- "DLib"
commands:
toggletrample:
description: "Toggles whether you can trample crops."
player:
description: "Interact with fake players."
permission: op
mobcaps:
description: "Display mobcap information from your current dimension."
pocketdim:
description: "Interact with pocket dimensions. Testing command."

View File

@ -0,0 +1,24 @@
CraftableNametag: true
CraftableSaddle: true
AlternativeDispenserRecipe: true
DispensersCanPlantSaplings: true
CraftableShulkerShell: true
IceDecompression: true
LogsToChests: true
CraftableSponge: true
PlayersCantTrampleCrops: true
WoolToString: true
LilypadBonemealing: true
SeedDropPlanting: true
MobsCantTrampleCrops: true
CraftableDragonsBreath: true
ArmorSwapping: true
HoesHarvestArea: true
FakePlayers: true
CarpetBlockPlacingProtocol: true
NoDoorBreaking: true
NoCreeperGrief: true
NoEndermanGrief: true
SugarcaneBonemealing: true
SpaceTimePockets: true
VillagerInfo: true