diff --git a/build.gradle.kts b/build.gradle.kts index e863638..7367ac5 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,10 +1,10 @@ import org.jetbrains.kotlin.gradle.tasks.KotlinCompile plugins { - kotlin("jvm") version "1.5.31" + kotlin("jvm") version "1.7.0-RC" 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.7" } group = "nl.kallestruik" @@ -20,12 +20,13 @@ repositories { } dependencies { + paperDevBundle("1.19-R0.1-SNAPSHOT") + implementation("co.aikar:acf-paper:0.5.0-SNAPSHOT") - paperDevBundle("1.18.1-R0.1-SNAPSHOT") compileOnly("com.comphenix.protocol:ProtocolLib:4.6.0") compileOnly(kotlin("stdlib-jdk8")) - compileOnly("nl.kallestruik:DLib:1.3.6") + compileOnly("nl.kallestruik:DLib:1.4.4") testImplementation(kotlin("test-junit5")) testImplementation("org.junit.jupiter:junit-jupiter-api:5.6.0") diff --git a/gradlew.bat b/gradlew.bat index 107acd3..ac1b06f 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -1,89 +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 +@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 diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/commands/CommandPlayer.kt b/src/main/kotlin/nl/kallestruik/dtweaks/commands/CommandPlayer.kt index d813fef..84991f1 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/commands/CommandPlayer.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/commands/CommandPlayer.kt @@ -22,16 +22,4 @@ class CommandPlayer( 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) - } } \ No newline at end of file diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayer.kt b/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayer.kt index bfe82cd..9e3f997 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayer.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayer.kt @@ -1,7 +1,7 @@ package nl.kallestruik.dtweaks.fakeplayer import com.mojang.authlib.GameProfile -import net.minecraft.network.chat.TextComponent +import net.minecraft.network.chat.Component import net.minecraft.network.protocol.PacketFlow import net.minecraft.network.protocol.game.ClientboundRotateHeadPacket import net.minecraft.network.protocol.game.ClientboundTeleportEntityPacket @@ -10,18 +10,18 @@ import net.minecraft.server.TickTask import net.minecraft.server.level.ServerLevel import net.minecraft.server.level.ServerPlayer import net.minecraft.world.damagesource.DamageSource -import net.minecraft.world.entity.Entity import net.minecraft.world.food.FoodData import net.minecraft.world.level.block.entity.SkullBlockEntity +import nl.kallestruik.dtweaks.fakeplayer.FakePlayerList.placeFakePlayer import org.bukkit.Location -import org.bukkit.craftbukkit.v1_18_R1.CraftWorld +import org.bukkit.craftbukkit.v1_19_R1.CraftWorld import java.util.concurrent.atomic.AtomicReference class FakePlayer( server: MinecraftServer, - val serverLevel: ServerLevel, + private val serverLevel: ServerLevel, gameProfile: GameProfile -): ServerPlayer(server, serverLevel, gameProfile) { +): ServerPlayer(server, serverLevel, gameProfile, null) { val locale = "en_US" companion object { @@ -43,7 +43,7 @@ class FakePlayer( // Create a fake connection for our fake player. val connection = FakeConnection(PacketFlow.SERVERBOUND) - FakePlayerList.placeNewPlayer(minecraftServer.playerList, minecraftServer, connection, instance) + minecraftServer.playerList.placeFakePlayer(connection, instance) instance.respawn() instance.teleportTo(serverLevel, location.x, location.y, location.z, location.yaw, location.pitch) @@ -119,7 +119,9 @@ class FakePlayer( } override fun kill() { - server.tell(TickTask(server.tickCount) {connection.onDisconnect(TextComponent("Killed"))}) + server.tell(TickTask(server.tickCount) { + connection.onDisconnect(Component.literal("Killed")) + }) } override fun die(source: DamageSource) { diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerConnection.kt b/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerConnection.kt index 3d95a4b..abd247e 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerConnection.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerConnection.kt @@ -3,7 +3,6 @@ package nl.kallestruik.dtweaks.fakeplayer import io.netty.util.concurrent.Future import io.netty.util.concurrent.GenericFutureListener import net.minecraft.network.chat.Component -import net.minecraft.network.chat.TranslatableComponent import net.minecraft.network.protocol.Packet import net.minecraft.server.MinecraftServer import net.minecraft.server.network.ServerGamePacketListenerImpl @@ -18,10 +17,7 @@ class FakePlayerConnection( override fun send(packet: Packet<*>, listener: GenericFutureListener>?) {} override fun disconnect(message: Component) { - if (message is TranslatableComponent && (message.key.equals("multiplayer.disconnect.idling") || message.equals("multiplayer.disconnect.duplicate_login"))) - { - player.kill() - } + player.kill() } override fun tick() { diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerList.kt b/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerList.kt index 75e97df..8ea7143 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerList.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/fakeplayer/FakePlayerList.kt @@ -1,23 +1,29 @@ package nl.kallestruik.dtweaks.fakeplayer -import com.destroystokyo.paper.PaperConfig import com.destroystokyo.paper.event.player.PlayerInitialSpawnEvent import com.mojang.authlib.GameProfile import com.mojang.datafixers.util.Either import com.mojang.serialization.Dynamic import io.netty.buffer.Unpooled +import io.papermc.paper.configuration.GlobalConfiguration +import net.minecraft.core.RegistryAccess import net.minecraft.nbt.CompoundTag import net.minecraft.nbt.NbtOps +import net.minecraft.nbt.Tag import net.minecraft.network.Connection import net.minecraft.network.FriendlyByteBuf import net.minecraft.network.protocol.game.* import net.minecraft.resources.ResourceKey import net.minecraft.server.MinecraftServer -import net.minecraft.server.level.* import net.minecraft.server.level.ChunkHolder.ChunkLoadingFailure +import net.minecraft.server.level.DistanceManager +import net.minecraft.server.level.ServerLevel +import net.minecraft.server.level.ServerPlayer +import net.minecraft.server.level.TicketType import net.minecraft.server.network.ServerGamePacketListenerImpl import net.minecraft.server.players.GameProfileCache import net.minecraft.server.players.PlayerList +import net.minecraft.tags.TagNetworkSerialization import net.minecraft.world.level.ChunkPos import net.minecraft.world.level.GameRules import net.minecraft.world.level.Level @@ -25,18 +31,185 @@ import net.minecraft.world.level.biome.BiomeManager import net.minecraft.world.level.chunk.ChunkAccess import net.minecraft.world.level.dimension.DimensionType import nl.kallestruik.dlib.ReflectionUtil -import nl.kallestruik.dtweaks.DTweaks -import org.apache.logging.log4j.Logger import org.bukkit.Bukkit -import org.bukkit.craftbukkit.v1_18_R1.CraftWorld +import org.bukkit.craftbukkit.v1_19_R1.CraftServer +import org.bukkit.craftbukkit.v1_19_R1.CraftWorld import org.bukkit.entity.Player import org.spigotmc.event.player.PlayerSpawnLocationEvent import java.util.* import java.util.concurrent.CompletableFuture -import java.util.function.Consumer object FakePlayerList { + + fun PlayerList.placeFakePlayer(connection: Connection, player: ServerPlayer) { + player.isRealPlayer = true // Paper - Chunk priority + player.networkManager = connection // Paper + player.loginTime = System.currentTimeMillis() // Paper + + val gameprofile = player.getGameProfile() + val usercache = server.profileCache + val optional = usercache[gameprofile.id] + var s: String? = optional.map { obj: GameProfile -> obj.name }.orElse(gameprofile.name) + + usercache.add(gameprofile) + val nbttagcompound = load(player) + // CraftBukkit start - Better rename detection + // CraftBukkit start - Better rename detection + if (nbttagcompound != null && nbttagcompound.contains("bukkit")) { + val bukkit = nbttagcompound.getCompound("bukkit") + s = if (bukkit.contains("lastKnownName", 8)) bukkit.getString("lastKnownName") else s + } + val lastKnownName = s // Paper + + // CraftBukkit end + + // Paper start - move logic in Entity to here, to use bukkit supplied world UUID. + // CraftBukkit end + + // Paper start - move logic in Entity to here, to use bukkit supplied world UUID. + val resourcekey = + if (nbttagcompound != null && nbttagcompound.contains("WorldUUIDMost") && nbttagcompound.contains("WorldUUIDLeast")) { + val uid = UUID(nbttagcompound.getLong("WorldUUIDMost"), nbttagcompound.getLong("WorldUUIDLeast")) + val bWorld = Bukkit.getServer().getWorld(uid) + if (bWorld != null) { + (bWorld as CraftWorld).handle.dimension() + } else { + Level.OVERWORLD + } + } else if (nbttagcompound != null) { + // Vanilla migration support + // Paper end + val dataresult = DimensionType.parseLegacy( + Dynamic( + NbtOps.INSTANCE, + nbttagcompound["Dimension"] + ) + ) // CraftBukkit - decompile error + dataresult.resultOrPartial { msg: String? -> + + }.orElse(Level.OVERWORLD) + } else { + Level.OVERWORLD + } + + val resourcekey1: ResourceKey = resourcekey + val worldserver = server.getLevel(resourcekey1) + var worldserver1: ServerLevel + + worldserver1 = if (worldserver == null) { + server.overworld() + } else { + worldserver + } + + if (nbttagcompound == null) player.fudgeSpawnLocation(worldserver1) // Paper - only move to spawn on first login, otherwise, stay where you are.... + + + player.setLevel(worldserver1) + // Paper start - make s1 final + // Paper start - make s1 final + val s1: String + + s1 = if (connection.remoteAddress != null) { + if (GlobalConfiguration.get().logging.logPlayerIpAddresses) connection.remoteAddress.toString() else "" // Paper + } else { + "local" + } + // Paper end + + // Spigot start - spawn location event + // Paper end + + // Spigot start - spawn location event + val spawnPlayer: Player = player.bukkitEntity + val ev: PlayerSpawnLocationEvent = + PlayerInitialSpawnEvent(spawnPlayer, spawnPlayer.location) // Paper use our duplicate event + + val cserver = ReflectionUtil().getValueFromField(this, "cserver") as CraftServer + + cserver.pluginManager.callEvent(ev) + + val loc = ev.spawnLocation + worldserver1 = (loc.world as CraftWorld).handle + + player.spawnIn(worldserver1) + player.gameMode.setLevel(player.level as ServerLevel) + player.setPosRaw(loc.x, loc.y, loc.z) + player.setRot(loc.yaw, loc.pitch) + + val worlddata = worldserver1.getLevelData() + + player.loadGameTypes(nbttagcompound) + val playerconnection = ServerGamePacketListenerImpl(server, connection, player) + val gamerules = worldserver1.gameRules + val flag = gamerules.getBoolean(GameRules.RULE_DO_IMMEDIATE_RESPAWN) + val flag1 = gamerules.getBoolean(GameRules.RULE_REDUCEDDEBUGINFO) + + val registryHolder = ReflectionUtil().getValueFromField(this, "t" /* registryHolder -> t */) as RegistryAccess.Frozen + + playerconnection.send( + ClientboundLoginPacket( + player.id, + worlddata.isHardcore, + player.gameMode.gameModeForPlayer, + player.gameMode.previousGameModeForPlayer, + server.levelKeys(), + registryHolder, + worldserver1.dimensionTypeId(), + worldserver1.dimension(), + BiomeManager.obfuscateSeed(worldserver1.seed), + maxPlayers, + worldserver1.getChunkSource().chunkMap.playerChunkManager.targetSendDistance, + worldserver1.getChunkSource().chunkMap.playerChunkManager.targetTickViewDistance, + flag1, + !flag, + worldserver1.isDebug, + worldserver1.isFlat, + player.lastDeathLocation + ) + ) + + player.bukkitEntity.sendSupportedChannels() // CraftBukkit + + playerconnection.send( + ClientboundCustomPayloadPacket( + ClientboundCustomPayloadPacket.BRAND, FriendlyByteBuf(Unpooled.buffer()).writeUtf( + server.serverModName + ) + ) + ) + playerconnection.send(ClientboundChangeDifficultyPacket(worlddata.difficulty, worlddata.isDifficultyLocked)) + playerconnection.send(ClientboundPlayerAbilitiesPacket(player.abilities)) + playerconnection.send(ClientboundSetCarriedItemPacket(player.inventory.selected)) + playerconnection.send(ClientboundUpdateRecipesPacket(server.recipeManager.getRecipes())) + playerconnection.send(ClientboundUpdateTagsPacket(TagNetworkSerialization.serializeTagsToNetwork(registryHolder))) + this.sendPlayerPermissionLevel(player) + player.stats.markAllDirty() + player.recipeBook.sendInitialRecipeBook(player) + updateEntireScoreboard(worldserver1.scoreboard, player) + server.invalidateStatus() + // Paper start - async load spawn in chunk + // Paper start - async load spawn in chunk + val finalWorldserver = worldserver1 + val chunkX = loc.blockX shr 4 + val chunkZ = loc.blockZ shr 4 + val pos = ChunkPos(chunkX, chunkZ) + val playerChunkMap = worldserver1.getChunkSource().chunkMap + val distanceManager: DistanceManager = playerChunkMap.distanceManager + distanceManager.addTicket(TicketType.LOGIN, pos, 31, pos.toLong()) + worldserver1.getChunkSource().markAreaHighPriority(pos, 28, 3) // Paper - Chunk priority + + val postChunkLoadJoin = this::class.java.superclass.getDeclaredMethod("postChunkLoadJoin", ServerPlayer::class.java, ServerLevel::class.java, Connection::class.java, ServerGamePacketListenerImpl::class.java, CompoundTag::class.java, String::class.java, String::class.java) + postChunkLoadJoin.isAccessible = true + postChunkLoadJoin.invoke(this, player, finalWorldserver, connection, playerconnection, + nbttagcompound, "127.0.0.1", lastKnownName) + } + fun placeNewPlayer(playerList: PlayerList, server: MinecraftServer, connection: FakeConnection, player: FakePlayer) { + + } + + fun placeNewPlayerOld(playerList: PlayerList, server: MinecraftServer, connection: FakeConnection, player: FakePlayer) { player.isRealPlayer = true // Paper - Chunk priority player.networkManager = connection // Paper @@ -139,7 +312,7 @@ object FakePlayerList { val pos = ChunkPos(chunkX, chunkZ) val playerChunkMap = worldServer.getChunkSource().chunkMap val distanceManager: DistanceManager = playerChunkMap.distanceManager - distanceManager.addTicketAtLevel(TicketType.LOGIN, pos, 31, pos.toLong()) +// distanceManager.addTicket(TicketType.LOGIN, pos, 31, pos.toLong()) worldServer.getChunkSource().markAreaHighPriority(pos, 28, 3) // Paper - Chunk priority val postChunkLoadJoin = playerList::class.java.superclass.getDeclaredMethod("postChunkLoadJoin", ServerPlayer::class.java, ServerLevel::class.java, Connection::class.java, ServerGamePacketListenerImpl::class.java, CompoundTag::class.java, String::class.java, String::class.java) diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/managers/FakePlayerManager.kt b/src/main/kotlin/nl/kallestruik/dtweaks/managers/FakePlayerManager.kt index e552c4b..085f3b8 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/managers/FakePlayerManager.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/managers/FakePlayerManager.kt @@ -1,20 +1,11 @@ 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 +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftEntity +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer /* @@ -24,12 +15,6 @@ import java.util.function.Predicate 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 @@ -57,166 +42,4 @@ class FakePlayerManager( 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) { -// -// -// fakePlayer.swing() -// } - - fun attack(name: String) { - val player = getPlayerByName(name) ?: return - val target = getTarget(player) ?: return - - when (target.type) { - HitResult.Type.BLOCK -> {/*TODO: Not implemented*/} - HitResult.Type.ENTITY -> { - if (target !is EntityHitResult) return - - player.attack(target.entity); - player.swing(InteractionHand.MAIN_HAND); - player.resetLastActionTime(); - } - else -> return - } - } - - fun use(name: String) { - val player = getPlayerByName(name) ?: return - val target = getTarget(player) ?: return - - for (hand in InteractionHand.values()) { - when (target.type) { - HitResult.Type.BLOCK -> { - if (target !is BlockHitResult) return - - player.resetLastActionTime() - val world = player.getLevel() - val pos = target.blockPos - val side = target.direction - if (pos.y < player.getLevel().maxBuildHeight - (if (side === Direction.UP) 1 else 0) - && world.mayInteract(player, pos)) { - val result = player.gameMode.useItemOn(player, world, player.getItemInHand(hand), hand, target) - if (result.consumesAction()) { - if (result.shouldSwing()) player.swing(hand) - return - } - } - } - HitResult.Type.ENTITY -> { - if (target !is EntityHitResult) return - - player.resetLastActionTime() - val entity = target.entity - val relativeHitPos: Vec3 = target.getLocation().subtract(entity.x, entity.y, entity.z) - - entity.interactAt(player, relativeHitPos, hand).consumesAction() - - // fix for SS itemframe always returns CONSUME even if no action is performed - player.interactOn(entity, hand).consumesAction() - } - } - - player.gameMode.useItem(player, player.getLevel(), player.getItemInHand(hand), hand) - } - } - - // - // Ray tracing code borrowed from carpet mod: https://github.com/gnembon/fabric-carpet/blob/master/src/main/java/carpet/helpers/Tracer.java - // - - fun getTarget(player: FakePlayer): HitResult? { - val reach: Double = if (player.gameMode.isCreative) 5.0 else 4.5f.toDouble() - return rayTrace(player, 1F, reach, false) - } - - fun rayTrace(source: FakePlayer, partialTicks: Float, reach: Double, fluids: Boolean): HitResult? { - val blockHit = rayTraceBlocks(source, partialTicks, reach, fluids) - var maxSqDist = reach * reach - if (blockHit != null) { - maxSqDist = blockHit.location.distanceToSqr(source.getEyePosition(partialTicks)) - } - val entityHit = rayTraceEntities(source, partialTicks, reach, maxSqDist) - return entityHit ?: blockHit - } - - fun rayTraceBlocks(source: FakePlayer, partialTicks: Float, reach: Double, fluids: Boolean): BlockHitResult? { - val pos: Vec3 = source.getEyePosition(partialTicks) - val rotation: Vec3 = source.getViewVector(partialTicks) - val reachEnd = pos.add(rotation.x * reach, rotation.y * reach, rotation.z * reach) - return source.level.clip( - ClipContext( - pos, - reachEnd, - ClipContext.Block.OUTLINE, - if (fluids) ClipContext.Fluid.ANY else ClipContext.Fluid.NONE, - source - ) - ) - } - - fun rayTraceEntities(source: FakePlayer, partialTicks: Float, reach: Double, maxSqDist: Double): EntityHitResult? { - val pos = source.getEyePosition(partialTicks) - val reachVec = source.getViewVector(partialTicks).scale(reach) - val box = source.boundingBox.expandTowards(reachVec).inflate(1.0) - return rayTraceEntities(source, pos, pos.add(reachVec), box, maxSqDist) { - e -> !e.isSpectator && e.isPickable - } - } - - fun rayTraceEntities( - source: FakePlayer, - start: Vec3, - end: Vec3, - box: AABB, - maxSqDistance: Double, - predicate: Predicate, - ): 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() - } - - } } \ No newline at end of file diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/miscellaneoustweaks/FakePlayers.kt b/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/miscellaneoustweaks/FakePlayers.kt index 9023024..9d6c96c 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/miscellaneoustweaks/FakePlayers.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/miscellaneoustweaks/FakePlayers.kt @@ -4,9 +4,7 @@ import nl.kallestruik.dtweaks.DTweaks import nl.kallestruik.dtweaks.fakeplayer.FakePlayer import nl.kallestruik.dtweaks.managers.FakePlayerManager import nl.kallestruik.dtweaks.tweaks.ITweak -import org.bukkit.Material -import org.bukkit.craftbukkit.v1_18_R1.entity.CraftPlayer -import org.bukkit.craftbukkit.v1_18_R1.inventory.CraftItemStack +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftPlayer import org.bukkit.entity.Player import org.bukkit.event.EventHandler import org.bukkit.event.HandlerList diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/NoSpawnZones.kt b/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/NoSpawnZones.kt index e4a6ee6..d4f2b39 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/NoSpawnZones.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/NoSpawnZones.kt @@ -1,20 +1,12 @@ 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, diff --git a/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/VillagerInfo.kt b/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/VillagerInfo.kt index ea9ac9c..4ee0283 100644 --- a/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/VillagerInfo.kt +++ b/src/main/kotlin/nl/kallestruik/dtweaks/tweaks/mobtweaks/VillagerInfo.kt @@ -4,7 +4,7 @@ import net.minecraft.core.GlobalPos import net.minecraft.world.entity.ai.memory.MemoryModuleType import net.minecraft.world.entity.schedule.Activity import nl.kallestruik.dtweaks.tweaks.ITweak -import org.bukkit.craftbukkit.v1_18_R1.entity.CraftVillager +import org.bukkit.craftbukkit.v1_19_R1.entity.CraftVillager import org.bukkit.entity.Villager import org.bukkit.event.EventHandler import org.bukkit.event.HandlerList