Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion BANNER.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,7 +67,7 @@ BetterModel supports **player model with using user's custom skin without textur

## 🏗️ Supported environment

[![](https://img.shields.io/badge/minecraft-1.21.4%7E26.1.x-8FCA5C?style=for-the-badge)](https://www.minecraft.net/en-us/download/server)
[![](https://img.shields.io/badge/minecraft-1.21.4%7E26.2.x-8FCA5C?style=for-the-badge)](https://www.minecraft.net/en-us/download/server)
[![](https://img.shields.io/badge/java-25%7E-ED8B00?style=for-the-badge)](https://adoptium.net/)

### Bukkit
Expand Down
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -55,7 +55,7 @@ BetterModel aims to be a reliable engine that provides stable, high-quality anim

## 🛠️ Build info

[![](https://img.shields.io/badge/minecraft-1.21.4%7E26.1.x-8FCA5C)](https://www.minecraft.net/en-us/download/server)
[![](https://img.shields.io/badge/minecraft-1.21.4%7E26.2.x-8FCA5C)](https://www.minecraft.net/en-us/download/server)
[![](https://img.shields.io/badge/java-25%7E-ED8B00)](https://adoptium.net/)

#### Build
Expand Down
7 changes: 6 additions & 1 deletion api/src/main/java/kr/toxicity/model/api/nms/NMSVersion.java
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,12 @@ public enum NMSVersion {
* Minecraft 26.1.x
* @since 3.0.0
*/
V26_R1(84)
V26_R1(84),
/**
* Minecraft 26.2.x
* @since 3.2.0
*/
V26_R2(88)
;
/**
* The resource pack format version (pack.mcmeta).
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,10 @@
* @param patch minor update
*/
public record MinecraftVersion(int major, int minor, int patch) implements Comparable<MinecraftVersion> {
/**
* 26.2
*/
public static final MinecraftVersion V26_2 = of(26, 2, 0);
/**
* 26.1.2
*/
Expand Down
7 changes: 4 additions & 3 deletions buildSrc/src/main/kotlin/Extensions.kt
Original file line number Diff line number Diff line change
Expand Up @@ -8,9 +8,7 @@ val Project.libs
get() = rootProject.extensions.getByName("libs") as LibrariesForLibs

val LATEST_VERSION = listOf(
"26.1",
"26.1.1",
"26.1.2"
"26.2"
)

val SUPPORTED_VERSIONS = buildList {
Expand All @@ -23,6 +21,9 @@ val SUPPORTED_VERSIONS = buildList {
"1.21.9",
"1.21.10",
"1.21.11",
"26.1",
"26.1.1",
"26.1.2"
))
addAll(LATEST_VERSION)
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ import org.bstats.bukkit.Metrics
import org.bukkit.Bukkit
import org.semver4j.Semver

private typealias Latest = kr.toxicity.model.bukkit.nms.v26_R1.NMSImpl
private typealias Latest = kr.toxicity.model.bukkit.nms.v26_R2.NMSImpl

internal class BetterModelProperties(
private val plugin: AbstractBetterModelPlugin
Expand All @@ -37,7 +37,8 @@ internal class BetterModelProperties(

val version = parse(Bukkit.getBukkitVersion().substringBefore('-'))
val nms = when (version) {
V26_1, V26_1_1, V26_1_2 -> Latest()
V26_2 -> Latest()
V26_1, V26_1_1, V26_1_2 -> kr.toxicity.model.bukkit.nms.v26_R1.NMSImpl()
V1_21_11 -> kr.toxicity.model.bukkit.nms.v1_21_R7.NMSImpl()
V1_21_9, V1_21_10 -> kr.toxicity.model.bukkit.nms.v1_21_R6.NMSImpl()
V1_21_6, V1_21_7, V1_21_8 -> kr.toxicity.model.bukkit.nms.v1_21_R5.NMSImpl()
Expand Down
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
Expand Up @@ -7,4 +7,4 @@ org.gradle.parallel=true
org.gradle.jvmargs=-Xmx2g -XX:MaxMetaspaceSize=512m -XX:+HeapDumpOnOutOfMemoryError -Dfile.encoding=UTF-8

project_version=3.2.0
minecraft_version=26.1.2
minecraft_version=26.2
8 changes: 4 additions & 4 deletions gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,11 @@ shadow = "9.4.2"
minotaur = "2.9.0"
hangarPublish = "0.1.4"

fabric-api = "0.151.0+26.1.2"
fabric-api = "0.152.1+26.2"
fabric-language-kotlin = "1.13.12+kotlin.2.4.0"

cloud-bukkit = "2.0.0-beta.15"
cloud-mod = "2.0.0-beta.16"
cloud-mod = "2.0.0-SNAPSHOT" #TODO cloud-mod = "2.0.0-beta.17"
cloud-core = "2.0.0"

configurate = "4.2.0"
Expand All @@ -28,14 +28,14 @@ adventure-api = "net.kyori:adventure-api:4.26.1"
adventure-examination = "net.kyori:examination-api:1.3.0"
adventure-option = "net.kyori:option:1.1.0"
adventure-platform-bukkit = "net.kyori:adventure-platform-bukkit:4.4.1"
adventure-platform-fabric = "net.kyori:adventure-platform-fabric:6.9.0"
adventure-platform-fabric = "net.kyori:adventure-platform-fabric:7.0.0-SNAPSHOT"

asm-tree = "org.ow2.asm:asm-tree:9.10.1"

fabric-loader = "net.fabricmc:fabric-loader:0.19.3"
fabric-language-kotlin = { module = "net.fabricmc:fabric-language-kotlin", version.ref = "fabric-language-kotlin" }

polymer-resource-pack = "eu.pb4:polymer-resource-pack:0.16.5+26.1.2"
polymer-resource-pack = "eu.pb4:polymer-resource-pack:0.17.0+26.2-rc-2"

configurate-core = { module = "org.spongepowered:configurate-core", version.ref = "configurate" }
configurate-yaml = { module = "org.spongepowered:configurate-yaml", version.ref = "configurate" }
Expand Down
7 changes: 7 additions & 0 deletions nms/v26_R2/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
plugins {
alias(libs.plugins.convention.paperweight)
}

dependencies {
paperweight.paperDevBundle("26.2-rc-2.build.+")
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
/*
* This source file is part of BetterModel.
* Copyright (c) 2026 toxicity188
* Licensed under the MIT License.
* See LICENSE.md file for full license text.
*/

package kr.toxicity.model.bukkit.nms.v26_R2;

import kr.toxicity.model.api.nms.HitBox;
import net.minecraft.world.entity.EntityTypes;
import net.minecraft.world.entity.decoration.ArmorStand;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;

abstract class AbstractHitBox extends ArmorStand implements HitBox {

AbstractHitBox(@NotNull Level level) {
super(EntityTypes.ARMOR_STAND, level);
}

@Override //Only for provide compiler hint for Kotlin jvm
public final boolean equals(@Nullable Object other) {
return super.equals(other);
}

@Override //Only for provide compiler hint for Kotlin jvm
public final int hashCode() {
return super.hashCode();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,85 @@
/*
* This source file is part of BetterModel.
* Copyright (c) 2026 toxicity188
* Licensed under the MIT License.
* See LICENSE.md file for full license text.
*/

package kr.toxicity.model.bukkit.nms.v26_R2

import kr.toxicity.model.api.bukkit.entity.BaseBukkitEntity
import kr.toxicity.model.api.platform.PlatformEntity
import kr.toxicity.model.api.platform.PlatformLocation
import kr.toxicity.model.api.platform.PlatformPlayer
import net.minecraft.server.level.ServerPlayer
import net.minecraft.world.effect.MobEffects
import net.minecraft.world.entity.Entity
import net.minecraft.world.entity.LivingEntity
import net.minecraft.world.entity.ai.attributes.Attributes
import org.bukkit.craftbukkit.entity.CraftEntity
import org.bukkit.persistence.PersistentDataHolder
import org.joml.Vector3f
import java.util.*
import java.util.stream.Stream

internal data class BaseEntityImpl(
private val delegate: CraftEntity
) : BaseBukkitEntity, PersistentDataHolder by delegate {
override fun customName(): AdventureComponent? = handle().run {
if (this is ServerPlayer) (customName ?: name).asAdventure() else customName?.asAdventure()?.takeIf {
isCustomNameVisible
}
}

override fun entity(): org.bukkit.entity.Entity = delegate
override fun handle(): Entity = delegate.vanillaEntity
override fun uuid(): UUID = delegate.uniqueId
override fun id(): Int = handle().id
override fun dead(): Boolean = (handle() as? LivingEntity)?.isDeadOrDying == true || handle().removalReason != null || !handle().valid
override fun invisible(): Boolean = handle().isInvisible || (handle() as? LivingEntity)?.hasEffect(MobEffects.INVISIBILITY) == true
override fun glow(): Boolean = handle().isCurrentlyGlowing

override fun onWalk(): Boolean {
return handle().isWalking()
}

override fun scale(): Double {
val handle = handle()
return if (handle is LivingEntity) handle.scale.toDouble() else 1.0
}

override fun pitch(): Float = handle().xRot
override fun ground(): Boolean = handle().onGround()
override fun bodyYaw(): Float = handle().let { if (it is LivingEntity) it.yBodyRot else it.yRot }
override fun yaw(): Float = handle().yRot
override fun headYaw(): Float = handle().let { if (it is LivingEntity) it.yHeadRot else it.yRot }
override fun fly(): Boolean = handle().isFlying

override fun damageTick(): Float {
val handle = handle()
if (handle !is LivingEntity) return 0F
val duration = handle.invulnerableDuration.toFloat()
if (duration <= 0F) return 0F
val knockBack = 1 - (handle.getAttribute(Attributes.KNOCKBACK_RESISTANCE)?.value?.toFloat() ?: 0F)
return handle.invulnerableTime.toFloat() / duration * knockBack
}

override fun walkSpeed(): Float {
val handle = handle()
if (handle !is LivingEntity) return 0F
if (!handle.onGround) return 1F
val speed = handle.getEffect(MobEffects.SPEED)?.amplifier ?: 0
val slow = handle.getEffect(MobEffects.SLOWNESS)?.amplifier ?: 0
return (1F + (speed - slow) * 0.2F)
.coerceAtLeast(0.2F)
.coerceAtMost(2F)
}

override fun passengerPosition(dest: Vector3f): Vector3f {
return handle().passengerPosition(dest)
}

override fun platform(): PlatformEntity = delegate.wrap()
override fun trackedBy(): Stream<PlatformPlayer> = delegate.trackedBy.stream().map { it.wrap() }
override fun location(): PlatformLocation = delegate.location.wrap()
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
/*
* This source file is part of BetterModel.
* Copyright (c) 2026 toxicity188
* Licensed under the MIT License.
* See LICENSE.md file for full license text.
*/

package kr.toxicity.model.bukkit.nms.v26_R2

import kr.toxicity.model.api.bukkit.entity.BaseBukkitEntity
import kr.toxicity.model.api.bukkit.entity.BaseBukkitPlayer
import kr.toxicity.model.api.nms.Profiled
import kr.toxicity.model.api.platform.PlatformPlayer
import kr.toxicity.model.api.player.PlayerSkinParts
import kr.toxicity.model.api.profile.ModelProfile
import net.minecraft.util.Mth
import org.bukkit.craftbukkit.entity.CraftPlayer
import org.bukkit.entity.Player
import java.util.stream.Stream

internal data class BasePlayerImpl(
private val delegate: CraftPlayer,
private val profile: () -> ModelProfile,
private val skinParts: () -> PlayerSkinParts
) : BaseBukkitEntity by BaseEntityImpl(delegate), BaseBukkitPlayer, Profiled by ProfiledImpl(PlayerArmorImpl(delegate), profile, skinParts) {

override fun entity(): Player = delegate

override fun updateInventory() {
delegate.handle.containerMenu.sendAllDataToRemote()
}

override fun platform(): PlatformPlayer = delegate.wrap()

override fun trackedBy(): Stream<PlatformPlayer> = Stream.concat(
Stream.of(delegate),
delegate.trackedBy.stream()
).map {
it.wrap()
}

override fun bodyYaw(): Float {
val handle = delegate.handle
var yaw = -45 * handle.xMovement()
if (handle.zMovement() < 0) yaw *= -1
return Mth.wrapDegrees(handle.yHeadRot + yaw)
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
/*
* This source file is part of BetterModel.
* Copyright (c) 2026 toxicity188
* Licensed under the MIT License.
* See LICENSE.md file for full license text.
*/

package kr.toxicity.model.bukkit.nms.v26_R2

import kr.toxicity.model.api.bukkit.platform.*
import kr.toxicity.model.api.bukkit.platform.BukkitAdapter.adapt
import kr.toxicity.model.api.bukkit.platform.BukkitItemStack
import kr.toxicity.model.api.platform.*
import org.bukkit.Location
import org.bukkit.OfflinePlayer
import org.bukkit.World
import org.bukkit.entity.Entity
import org.bukkit.entity.LivingEntity
import org.bukkit.entity.Player
import org.bukkit.inventory.ItemStack

internal fun Entity.wrap() = adapt(this)
internal fun LivingEntity.wrap() = adapt(this)
internal fun OfflinePlayer.wrap() = adapt(this)
internal fun Player.wrap() = adapt(this)
internal fun Location.wrap() = adapt(this)
internal fun World.wrap() = adapt(this)
internal fun ItemStack.wrap() = adapt(this)

internal fun PlatformEntity.unwarp(): Entity = (this as BukkitEntity).source()
internal fun PlatformLivingEntity.unwarp(): LivingEntity = (this as BukkitLivingEntity).source()
internal fun PlatformOfflinePlayer.unwarp(): OfflinePlayer = (this as BukkitOfflinePlayer).source()
internal fun PlatformPlayer.unwarp(): Player = (this as BukkitPlayer).source()
internal fun PlatformLocation.unwarp(): Location = (this as BukkitLocation).source()
internal fun PlatformWorld.unwarp(): World = (this as BukkitWorld).source()
internal fun PlatformItemStack.unwarp(): ItemStack = (this as BukkitItemStack).source()
Loading