This commit is contained in:
AverageGithub 2024-05-10 17:52:52 +02:00
parent 434b27835f
commit 4b242a31ae
24 changed files with 477 additions and 137 deletions

View File

@ -1,8 +1,8 @@
package com.artillexstudios.axminions.api.warnings
import com.artillexstudios.axapi.hologram.HologramFactory
import com.artillexstudios.axapi.hologram.Hologram
import com.artillexstudios.axapi.hologram.HologramLine
import com.artillexstudios.axminions.api.config.Config
import net.kyori.adventure.text.Component
import com.artillexstudios.axminions.api.minions.Minion
abstract class Warning(private val name: String) {
@ -11,15 +11,14 @@ abstract class Warning(private val name: String) {
return this.name
}
abstract fun getContent(): Component
abstract fun getContent(): String
fun display(minion: Minion) {
if (!Config.DISPLAY_WARNINGS()) return
if (minion.getWarning() == null) {
val hologram = HologramFactory.get()
.spawnHologram(minion.getLocation().clone().add(0.0, 1.35, 0.0), minion.getLocation().toString())
hologram.addLine(getContent())
val hologram = Hologram(minion.getLocation().clone().add(0.0, 1.35, 0.0), minion.getLocation().toString())
hologram.addLine(getContent(), HologramLine.Type.TEXT)
minion.setWarning(this)
minion.setWarningHologram(hologram)
}

View File

@ -1,13 +1,11 @@
package com.artillexstudios.axminions.api.warnings.impl
import net.kyori.adventure.text.Component
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.warnings.Warning
class WarningContainerFull : Warning("container_full") {
override fun getContent(): Component {
return StringUtils.format(Messages.CONTAINER_FULL_WARNING())
override fun getContent(): String {
return Messages.CONTAINER_FULL_WARNING()
}
}

View File

@ -1,13 +1,11 @@
package com.artillexstudios.axminions.api.warnings.impl
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.warnings.Warning
import net.kyori.adventure.text.Component
class WarningNoCharge : Warning("no_charge") {
override fun getContent(): Component {
return StringUtils.format(Messages.NO_CHARGE_WARNING())
override fun getContent(): String {
return Messages.NO_CHARGE_WARNING()
}
}

View File

@ -1,13 +1,11 @@
package com.artillexstudios.axminions.api.warnings.impl
import net.kyori.adventure.text.Component
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.warnings.Warning
class WarningNoContainer : Warning("no_container") {
override fun getContent(): Component {
return StringUtils.format(Messages.NO_CONTAINER_WARNING())
override fun getContent(): String {
return Messages.NO_CONTAINER_WARNING()
}
}

View File

@ -1,13 +1,11 @@
package com.artillexstudios.axminions.api.warnings.impl
import net.kyori.adventure.text.Component
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.warnings.Warning
class WarningNoTool : Warning("no_tool") {
override fun getContent(): Component {
return StringUtils.format(Messages.NO_TOOL_WARNING())
override fun getContent(): String {
return Messages.NO_TOOL_WARNING()
}
}

View File

@ -1,13 +1,11 @@
package com.artillexstudios.axminions.api.warnings.impl
import net.kyori.adventure.text.Component
import com.artillexstudios.axapi.utils.StringUtils
import com.artillexstudios.axminions.api.config.Messages
import com.artillexstudios.axminions.api.warnings.Warning
class WarningNoWaterNearby : Warning("no_water_nearby") {
override fun getContent(): Component {
return StringUtils.format(Messages.NO_WATER_NEARBY_WARNING())
override fun getContent(): String {
return Messages.NO_WATER_NEARBY_WARNING()
}
}

View File

@ -1,9 +1,9 @@
plugins {
id 'java-library'
id 'com.github.johnrengelman.shadow' version "8.1.1"
id 'io.github.goooler.shadow' version "8.1.7"
id 'maven-publish'
id 'java'
id 'org.jetbrains.kotlin.jvm' version '1.9.22'
id 'org.jetbrains.kotlin.jvm' version '1.9.23'
}
group = 'com.artillexstudios.axminions'
@ -26,13 +26,14 @@ dependencies {
implementation project(path: ":nms:v1_20_R1", configuration: "reobf")
implementation project(path: ":nms:v1_20_R2", configuration: "reobf")
implementation project(path: ":nms:v1_20_R3", configuration: "reobf")
implementation project(path: ":nms:v1_20_R4", configuration: "reobf")
}
allprojects {
apply plugin: 'org.jetbrains.kotlin.jvm'
apply plugin: 'java'
apply plugin: 'java-library'
apply plugin: 'com.github.johnrengelman.shadow'
apply plugin: 'io.github.goooler.shadow'
kotlin {
jvmToolchain(17)
@ -142,12 +143,6 @@ allprojects {
compileOnly 'com.github.Maxlego08:zShop-API:3.0.5'
compileOnly 'me.clip:placeholderapi:2.11.5'
}
compileKotlin {
kotlinOptions {
javaParameters = true
}
}
}

Binary file not shown.

View File

@ -1,5 +1,7 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.2-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.7-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME
zipStorePath=wrapper/dists

30
gradlew vendored
View File

@ -55,7 +55,7 @@
# Darwin, MinGW, and NonStop.
#
# (3) This script is generated from the Groovy template
# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt
# within the Gradle project.
#
# You can find Gradle at https://github.com/gradle/gradle/.
@ -80,13 +80,10 @@ do
esac
done
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
APP_NAME="Gradle"
# This is normally unused
# shellcheck disable=SC2034
APP_BASE_NAME=${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"'
APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit
# Use the maximum available, or set MAX_FD != -1 to use that value.
MAX_FD=maximum
@ -133,22 +130,29 @@ 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.
if ! command -v java >/dev/null 2>&1
then
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
fi
# Increase the maximum file descriptors if we can.
if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then
case $MAX_FD in #(
max*)
# In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
MAX_FD=$( ulimit -H -n ) ||
warn "Could not query maximum file descriptor limit"
esac
case $MAX_FD in #(
'' | soft) :;; #(
*)
# In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked.
# shellcheck disable=SC3045
ulimit -n "$MAX_FD" ||
warn "Could not set maximum file descriptor limit to $MAX_FD"
esac
@ -193,6 +197,10 @@ if "$cygwin" || "$msys" ; then
done
fi
# 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"'
# Collect all arguments for the java command;
# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of
# shell script including quotes and variable substitutions, so put them in
@ -205,6 +213,12 @@ set -- \
org.gradle.wrapper.GradleWrapperMain \
"$@"
# Stop when "xargs" is not available.
if ! command -v xargs >/dev/null 2>&1
then
die "xargs is not available"
fi
# Use "xargs" to parse quoted args.
#
# With -n1 it outputs one arg per line, with the quotes and backslashes removed.

15
gradlew.bat vendored
View File

@ -14,7 +14,7 @@
@rem limitations under the License.
@rem
@if "%DEBUG%" == "" @echo off
@if "%DEBUG%"=="" @echo off
@rem ##########################################################################
@rem
@rem Gradle startup script for Windows
@ -25,7 +25,8 @@
if "%OS%"=="Windows_NT" setlocal
set DIRNAME=%~dp0
if "%DIRNAME%" == "" set DIRNAME=.
if "%DIRNAME%"=="" set DIRNAME=.
@rem This is normally unused
set APP_BASE_NAME=%~n0
set APP_HOME=%DIRNAME%
@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome
set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1
if "%ERRORLEVEL%" == "0" goto execute
if %ERRORLEVEL% equ 0 goto execute
echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
:end
@rem End local scope for the variables with windows NT shell
if "%ERRORLEVEL%"=="0" goto mainEnd
if %ERRORLEVEL% equ 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
set EXIT_CODE=%ERRORLEVEL%
if %EXIT_CODE% equ 0 set EXIT_CODE=1
if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE%
exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal

View File

@ -1,5 +1,5 @@
plugins {
id("io.papermc.paperweight.userdev") version "1.5.10" apply false
id("io.papermc.paperweight.userdev") version "1.7.0" apply false
}
group = "com.artillexstudios.axminions"

View File

@ -7,6 +7,17 @@ version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.19.2-R0.1-SNAPSHOT")
pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat")
}
java {
toolchain {
languageVersion = JavaLanguageVersion.of(17)
}
}
kotlin {
jvmToolchain(17)
}
tasks {

View File

@ -7,6 +7,7 @@ version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.19.3-R0.1-SNAPSHOT")
pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat")
}
tasks {

View File

@ -7,6 +7,7 @@ version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.19.4-R0.1-SNAPSHOT")
pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat")
}
tasks {

View File

@ -7,6 +7,7 @@ version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.20-R0.1-SNAPSHOT")
pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat")
}
tasks {

View File

@ -7,6 +7,7 @@ version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.20.2-R0.1-SNAPSHOT")
pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat")
}
tasks {

View File

@ -7,6 +7,7 @@ version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.20.4-R0.1-SNAPSHOT")
pluginRemapper("net.fabricmc:tiny-remapper:0.10.3:fat")
}
tasks {

View File

@ -35,6 +35,6 @@ class NMSHandler : NMSHandler {
override fun getExp(block: Block, itemStack: ItemStack): Int {
val craftBlock = block as CraftBlock
return craftBlock.nms.block.getExpDrop((block.state as CraftBlockState).handle, craftBlock.handle.minecraftWorld, CraftLocation.toBlockPosition(block.location), CraftItemStack.unwrap(itemStack), true)
return craftBlock.nms.block.getExpDrop((block.state as CraftBlockState).handle, craftBlock.handle.minecraftWorld, CraftLocation.toBlockPosition(block.location), CraftItemStack.asNMSCopy(itemStack), true)
}
}

24
nms/v1_20_R4/build.gradle Normal file
View File

@ -0,0 +1,24 @@
plugins {
id("io.papermc.paperweight.userdev")
}
group = 'com.artillexstudios.axminions.nms'
version = '1.0-SNAPSHOT'
dependencies {
paperweight.paperDevBundle("1.20.5-R0.1-SNAPSHOT")
}
kotlin {
jvmToolchain(21)
}
tasks {
build {
dependsOn(reobfJar)
}
reobfJar {
mustRunAfter(shadowJar)
}
}

View File

@ -0,0 +1,218 @@
package com.artillexstudios.axminions.nms.v1_20_R4
import com.artillexstudios.axminions.api.events.MinionKillEntityEvent
import com.artillexstudios.axminions.api.events.PreMinionDamageEntityEvent
import com.artillexstudios.axminions.api.minions.Minion
import java.util.UUID
import net.minecraft.core.particles.ParticleTypes
import net.minecraft.server.level.ServerLevel
import net.minecraft.util.Mth
import net.minecraft.world.effect.MobEffectInstance
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.EntityType
import net.minecraft.world.entity.EquipmentSlot
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.animal.Fox
import net.minecraft.world.entity.decoration.ArmorStand
import net.minecraft.world.item.AxeItem
import net.minecraft.world.item.ItemStack
import net.minecraft.world.item.SwordItem
import net.minecraft.world.item.TridentItem
import net.minecraft.world.item.enchantment.EnchantmentHelper
import org.bukkit.Bukkit
import org.bukkit.craftbukkit.CraftWorld
import org.bukkit.craftbukkit.entity.CraftEntity
import org.bukkit.craftbukkit.inventory.CraftItemStack
import org.bukkit.enchantments.Enchantment
import org.bukkit.entity.Entity
import org.bukkit.entity.Player
import org.bukkit.event.entity.EntityPotionEffectEvent
object DamageHandler {
private var DUMMY_ENTITY = Fox(EntityType.FOX, (Bukkit.getWorlds().get(0) as CraftWorld).handle)
fun getUUID() : UUID {
return DUMMY_ENTITY.uuid
}
fun damage(source: Minion, entity: Entity) {
val nmsEntity = (entity as CraftEntity).handle
synchronized(DUMMY_ENTITY) {
var f = 1
val nmsItem: ItemStack
if (source.getTool() == null) {
nmsItem = ItemStack.EMPTY
} else {
nmsItem = CraftItemStack.asNMSCopy(source.getTool())
if (nmsItem.item is SwordItem) {
f = (f + (nmsItem.item as SwordItem).tier.attackDamageBonus).toInt()
}
if (nmsItem.item is AxeItem) {
f = (f + (nmsItem.item as SwordItem).tier.attackDamageBonus).toInt()
}
if (nmsItem.item is TridentItem) {
f = (f + TridentItem.BASE_DAMAGE).toInt()
}
}
DUMMY_ENTITY.setItemSlot(EquipmentSlot.MAINHAND, nmsItem)
if (!nmsEntity.isAttackable || entity is Player) return
val f2 = 1.0f
var f1 = EnchantmentHelper.getDamageBonus(nmsItem, nmsEntity.type)
f = (f * (0.2f + f2 * f2 * 0.8f)).toInt()
f1 *= f2
if (f > 0.0f || f1 > 0.0f) {
var flag3 = false
val b0: Byte = 0
val i = b0 + (source.getTool()?.getEnchantmentLevel(Enchantment.KNOCKBACK) ?: 0)
f = (f * 1.5f).toInt()
f = (f + f1).toInt()
if (nmsItem.item is SwordItem) {
flag3 = true
}
var f3 = 0.0f
var flag4 = false
val j = (source.getTool()?.getEnchantmentLevel(Enchantment.FIRE_ASPECT) ?: 0)
if (nmsEntity is LivingEntity) {
f3 = nmsEntity.health
if (j > 0 && !nmsEntity.isOnFire()) {
flag4 = true
nmsEntity.igniteForSeconds(1, false)
}
}
val event = PreMinionDamageEntityEvent(source, entity as org.bukkit.entity.LivingEntity, f.toDouble())
Bukkit.getPluginManager().callEvent(event)
if (event.isCancelled) {
return
}
val flag5 = nmsEntity.hurt(nmsEntity.damageSources().noAggroMobAttack(DUMMY_ENTITY), f.toFloat())
if (flag5) {
if ((nmsEntity as LivingEntity).isDeadOrDying) {
val killEvent = MinionKillEntityEvent(source, entity)
Bukkit.getPluginManager().callEvent(killEvent)
}
if (i > 0) {
if (nmsEntity is LivingEntity) {
(nmsEntity).knockback(
(i.toFloat() * 0.5f).toDouble(),
Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble(),
(-Mth.cos(source.getLocation().yaw * 0.017453292f)).toDouble()
)
} else {
nmsEntity.push(
(-Mth.sin(source.getLocation().yaw * 0.017453292f) * i.toFloat() * 0.5f).toDouble(),
0.1,
(Mth.cos(source.getLocation().yaw * 0.017453292f) * i.toFloat() * 0.5f).toDouble()
)
}
}
if (flag3) {
val sweep = source.getTool()?.getEnchantmentLevel(Enchantment.SWEEPING_EDGE) ?: 0
val f4 =
1.0f + if (sweep > 0) EnchantmentHelper.getSweepingDamageRatio(sweep) else 0.0f * f
val list: List<LivingEntity> = (source.getLocation().world as CraftWorld).handle
.getEntitiesOfClass(LivingEntity::class.java, nmsEntity.boundingBox.inflate(1.0, 0.25, 1.0)).filter { it !is Player }
val iterator: Iterator<*> = list.iterator()
while (iterator.hasNext()) {
val entityliving: LivingEntity = iterator.next() as LivingEntity
if ((entityliving !is ArmorStand || !(entityliving).isMarker) && source.getLocation()
.distanceSquared(
(entity as Entity).location
) < 9.0
) {
val damageEvent = PreMinionDamageEntityEvent(
source,
entityliving.bukkitEntity as org.bukkit.entity.LivingEntity,
f4.toDouble()
)
Bukkit.getPluginManager().callEvent(damageEvent)
if (event.isCancelled) {
return
}
// CraftBukkit start - Only apply knockback if the damage hits
if (entityliving.hurt(nmsEntity.damageSources().noAggroMobAttack(DUMMY_ENTITY), f4)) {
if (entityliving.isDeadOrDying) {
val killEvent = MinionKillEntityEvent(source, entity)
Bukkit.getPluginManager().callEvent(killEvent)
}
entityliving.knockback(
0.4000000059604645,
Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble(),
(-Mth.cos(source.getLocation().yaw * 0.017453292f)).toDouble()
)
}
// CraftBukkit end
}
}
val d0 = -Mth.sin(source.getLocation().yaw * 0.017453292f).toDouble()
val d1 = Mth.cos(source.getLocation().yaw * 0.017453292f).toDouble()
if ((source.getLocation().world as CraftWorld).handle is ServerLevel) {
((source.getLocation().world as CraftWorld).handle as ServerLevel).sendParticles(
ParticleTypes.SWEEP_ATTACK,
source.getLocation().x + d0,
source.getLocation().y + 0.5,
source.getLocation().z + d1,
0,
d0,
0.0,
d1,
0.0
)
}
}
if (nmsEntity is LivingEntity) {
val f5: Float = f3 - nmsEntity.health
if (j > 0) {
nmsEntity.igniteForSeconds(j * 4, false)
}
if ((source.getLocation().world as CraftWorld).handle is ServerLevel && f5 > 2.0f) {
val k = (f5.toDouble() * 0.5).toInt()
((source.getLocation().world as CraftWorld).handle).sendParticles(
ParticleTypes.DAMAGE_INDICATOR,
nmsEntity.getX(),
nmsEntity.getY(0.5),
nmsEntity.getZ(),
k,
0.1,
0.0,
0.1,
0.2
)
}
}
} else {
if (flag4) {
nmsEntity.clearFire()
}
}
}
}
}
}

View File

@ -0,0 +1,39 @@
package com.artillexstudios.axminions.nms.v1_20_R4
import com.artillexstudios.axminions.api.minions.Minion
import net.minecraft.server.MinecraftServer
import net.minecraft.world.level.storage.loot.BuiltInLootTables
import net.minecraft.world.level.storage.loot.LootParams
import net.minecraft.world.level.storage.loot.parameters.LootContextParamSets
import net.minecraft.world.level.storage.loot.parameters.LootContextParams
import net.minecraft.world.phys.Vec3
import org.bukkit.Location
import org.bukkit.craftbukkit.CraftWorld
import org.bukkit.craftbukkit.inventory.CraftItemStack
import org.bukkit.inventory.ItemStack
object LootHandler {
fun generateFishingLoot(minion: Minion, waterLocation: Location): List<ItemStack> {
val nmsItem: net.minecraft.world.item.ItemStack = if (minion.getTool() == null) {
net.minecraft.world.item.ItemStack.EMPTY
} else {
CraftItemStack.asNMSCopy(minion.getTool())
}
val level = (minion.getLocation().world as CraftWorld).handle
val lootparams = LootParams.Builder(level).withParameter(
LootContextParams.ORIGIN, Vec3(waterLocation.x, waterLocation.y, waterLocation.z)
).withParameter(LootContextParams.TOOL, nmsItem).withOptionalParameter(LootContextParams.THIS_ENTITY, null)
.create(LootContextParamSets.FISHING)
val lootTable = MinecraftServer.getServer().reloadableRegistries().getLootTable(BuiltInLootTables.FISHING);
return lootTable.getRandomItems(lootparams).stream().map { original: net.minecraft.world.item.ItemStack? ->
CraftItemStack.asBukkitCopy(
original
)
}.toList()
}
}

View File

@ -0,0 +1,40 @@
package com.artillexstudios.axminions.nms.v1_20_R4
import com.artillexstudios.axminions.api.minions.Minion
import com.artillexstudios.axminions.nms.NMSHandler
import java.util.UUID
import net.minecraft.core.BlockPos
import net.minecraft.world.entity.MobCategory
import org.bukkit.Location
import org.bukkit.block.Block
import org.bukkit.craftbukkit.block.CraftBlock
import org.bukkit.craftbukkit.block.CraftBlockState
import org.bukkit.craftbukkit.entity.CraftEntity
import org.bukkit.craftbukkit.inventory.CraftItemStack
import org.bukkit.craftbukkit.util.CraftLocation
import org.bukkit.entity.Entity
import org.bukkit.inventory.ItemStack
class NMSHandler : NMSHandler {
override fun attack(source: Minion, target: Entity) {
DamageHandler.damage(source, target)
}
override fun generateRandomFishingLoot(minion: Minion, waterLocation: Location): List<ItemStack> {
return LootHandler.generateFishingLoot(minion, waterLocation)
}
override fun isAnimal(entity: Entity): Boolean {
return (entity as CraftEntity).handle.type.category == MobCategory.CREATURE
}
override fun getAnimalUUID(): UUID {
return DamageHandler.getUUID()
}
override fun getExp(block: Block, itemStack: ItemStack): Int {
val craftBlock = block as CraftBlock
return craftBlock.nms.block.getExpDrop((block.state as CraftBlockState).handle, craftBlock.handle.minecraftWorld, CraftLocation.toBlockPosition(block.location), CraftItemStack.asNMSCopy(itemStack), true)
}
}

View File

@ -19,4 +19,4 @@ include 'nms:v1_19_R3'
include 'nms:v1_20_R1'
include 'nms:v1_20_R2'
include 'nms:v1_20_R3'
include 'nms:v1_20_R4'