Updated 1.21 -> 1.21.3

This commit is contained in:
叁玖领域 2024-10-28 00:37:00 +08:00
parent 4d166edc20
commit ea2e64ac00
50 changed files with 710 additions and 560 deletions

View File

@ -53,3 +53,13 @@
* `LP.KeepLeashNotDropTime` - 此规则决定,当拴绳关系创建时一段时间里,即是距离已经达到了断裂距离,也保持其不断裂 [默认值: 240ticks ,可设置范围[80, 1200]ticks]
* `LP.DisableMoveCheck` - 此规则启用将会禁止服务器对玩家进行速度过快修正 [默认值: True]
Please use a paste site for large blocks of code/logs, instead of dumping it in chat or taking a screenshot.
Here's a list of some paste sites and their size limits:
https://gist.github.com/: [Free] [SignUp] 100MB
https://paste.gemwire.uk/: [Free] 10MB
https://paste.ee/: [Free] 1MB, [SignUp] 6MB
https://pastebin.com/: [Free] 512KB, [SignUp] [Paid] 10MB
https://hastebin.com/: [Free] 400KB
https://gist.github.com/: [Free] [SignUp] 100MB

View File

@ -3,7 +3,7 @@ plugins {
id 'eclipse'
id 'idea'
id 'maven-publish'
id 'net.neoforged.gradle.userdev' version '7.0.145'
id 'net.neoforged.gradle.userdev' version '7.0.165'
}
tasks.named('wrapper', Wrapper).configure {
@ -25,11 +25,10 @@ repositories {
base {
archivesName = mod_id
}
// Mojang ships Java 21 to end users starting in 1.20.5, so mods should target Java 21.
java.toolchain.languageVersion = JavaLanguageVersion.of(21)
//minecraft.accessTransformers.file rootProject.file('src/main/resources/META-INF/accesstransformer.cfg')
minecraft.accessTransformers.file file('src/main/resources/META-INF/accesstransformer.cfg')
//minecraft.accessTransformers.entry public net.minecraft.client.Minecraft textureManager # textureManager
// Default run configurations.
@ -172,4 +171,4 @@ idea {
downloadSources = true
downloadJavadoc = true
}
}
}

View File

@ -2,6 +2,14 @@
org.gradle.jvmargs=-Xmx8G
org.gradle.daemon=false
org.gradle.debug=false
org.gradle.parallel=true
org.gradle.caching=true
org.gradle.configuration-cache=false
#read more on this at https://github.com/neoforged/ModDevGradle?tab=readme-ov-file#better-minecraft-parameter-names--javadoc-parchment
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
parchment_minecraft_version=1.21
parchment_mappings_version=2024.07.28
#read more on this at https://github.com/neoforged/NeoGradle/blob/NG_7.0/README.md#apply-parchment-mappings
# you can also find the latest versions at: https://parchmentmc.org/docs/getting-started
@ -10,17 +18,19 @@ neogradle.subsystems.parchment.mappingsVersion=2024.07.28
# Environment Properties
# You can find the latest versions here: https://projects.neoforged.net/neoforged/neoforge
# The Minecraft version must agree with the Neo version to get a valid artifact
minecraft_version=1.21
minecraft_version=1.21.3
# The Minecraft version range can use any release version of Minecraft as bounds.
# Snapshots, pre-releases, and release candidates are not guaranteed to sort properly
# as they do not follow standard versioning conventions.
minecraft_version_range=[1.21,1.22)
minecraft_version_range=[1.21.1,1.22)
enable_accesstransformers=true
# The Neo version must agree with the Minecraft version to get a valid artifact
neo_version=21.0.157
neo_version=21.3.0-beta
# The Neo version range can use any version of Neo as bounds
neo_version_range=[21.0.0-beta,)
neo_version_range=[21.1.0,)
# The loader version range can only use the major version of FML as bounds
loader_version_range=[4,)
neoform_version=1.21.3-20241023.131943
## Mod Properties
@ -32,7 +42,7 @@ mod_name=Leashed Player
# The license of the mod. Review your options at https://choosealicense.com/. All Rights Reserved is the default.
mod_license=MIT
# The mod version. See https://semver.org/
mod_version=0.0.3.9.4
mod_version=1.21.3 0.0.3.9.4
# The group ID for the mod. It is only important when publishing as an artifact to a Maven repository.
# This should match the base package used for the mod sources.
# See https://maven.apache.org/guides/mini/guide-naming-conventions.html

View File

@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://mirrors.cloud.tencent.com/gradle/gradle-8.9-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME

2
gradlew vendored
View File

@ -249,4 +249,4 @@ eval "set -- $(
tr '\n' ' '
)" '"$@"'
exec "$JAVACMD" "$@"
exec "$JAVACMD" "$@"

2
gradlew.bat vendored
View File

@ -91,4 +91,4 @@ exit /b %EXIT_CODE%
:mainEnd
if "%OS%"=="Windows_NT" endlocal
:omega
:omega

View File

@ -1,4 +1,4 @@
// 1.21 2024-10-23T13:15:06.1102778 Item Models: leashedplayer
// 1.21.3 2024-10-27T23:14:21.0486567 Item Models: leashedplayer
5846df9d85726428905701120ef34c9324c20faf assets/leashedplayer/models/item/bow_lra_pulling_0.json
845a7316b86e26f88c6932d4ef2656126503727a assets/leashedplayer/models/item/bow_lra_pulling_1.json
5bd1f9f28b91005c587f1c38fb77cd19b59495e3 assets/leashedplayer/models/item/bow_lra_pulling_2.json

View File

@ -1,2 +1,2 @@
// 1.21 2024-10-23T13:15:06.1082841 Registries
6f79a674215db9f9d2820b1c7f052c60ce729fee data/leashedplayer/painting_variant/group_photo.json
// 1.21.3 2024-10-27T23:14:21.047502 Registries
84106976f4f71012fc5bd1784303a0d135623c77 data/leashedplayer/painting_variant/group_photo.json

View File

@ -1,2 +1,2 @@
// 1.21 2024-10-23T13:15:06.1012494 Tags for minecraft:item mod id leashedplayer
// 1.21.3 2024-10-27T23:14:21.0349914 Tags for minecraft:item mod id leashedplayer
36c1cccc1dfa448620c4e9cbc4a7d73986ff9e47 data/minecraft/tags/item/arrows.json

View File

@ -1,2 +1,2 @@
// 1.21 2024-10-23T14:43:16.8619078 Languages: en_us for mod: leashedplayer
// 1.21.3 2024-10-27T23:14:21.0486567 Languages: en_us for mod: leashedplayer
4dc2ca922a540c7133a4a6867dfcd8bfec5a1db4 assets/leashedplayer/lang/en_us.json

View File

@ -1 +1 @@
// 1.21 2024-10-23T13:15:06.1052755 Tags for minecraft:block mod id leashedplayer
// 1.21.3 2024-10-27T23:14:21.0429914 Tags for minecraft:block mod id leashedplayer

View File

@ -1,2 +1,2 @@
// 1.21 2024-10-23T13:15:06.1052755 Tags for minecraft:painting_variant mod id leashedplayer
// 1.21.3 2024-10-27T23:14:21.0429914 Tags for minecraft:painting_variant mod id leashedplayer
e081a053d7c2f2d3238cf38436185ef23d234505 data/minecraft/tags/painting_variant/placeable.json

View File

@ -1,2 +1,2 @@
// 1.21 2024-10-23T13:15:06.1042677 Languages: lzh for mod: leashedplayer
// 1.21.3 2024-10-27T23:14:21.0429914 Languages: lzh for mod: leashedplayer
bf21a9e8fbc5a3846fb05b4fa0859e0917b2202f assets/leashedplayer/lang/lzh.json

View File

@ -1,7 +0,0 @@
// 1.21 2024-10-23T13:15:06.1092763 Recipes
1b45d1ad8dc73f1787c97777ad13d9771c9e0ad1 data/leashedplayer/advancement/recipes/misc/leash_rope_arrow.json
974d74538b3e172946f2e169036b453b6eb6bc0a data/leashedplayer/recipe/leash_rope_arrow.json
c0e05f359296d3e28573fa1b205ac44736376622 data/minecraft/advancement/recipes/misc/spectral_leash_rope_arrow_with_glowstone_dust.json
131fcbef603bfde7204d8e1ad15e4544696926bf data/minecraft/advancement/recipes/misc/spectral_leash_rope_arrow_with_leash_rope_arrow.json
bb5909aa91d878c8f0ef9999881cfe89532509dd data/minecraft/recipe/spectral_leash_rope_arrow_with_glowstone_dust.json
a1381da885fbedec01243c78afbb0a50ca803ee4 data/minecraft/recipe/spectral_leash_rope_arrow_with_leash_rope_arrow.json

View File

@ -1,2 +1,2 @@
// 1.21 2024-10-23T14:43:16.860909 Languages: zh_cn for mod: leashedplayer
// 1.21.3 2024-10-27T23:14:21.047502 Languages: zh_cn for mod: leashedplayer
35bc6c3001138c5306d1ee9d55ef3dfbfd417e08 assets/leashedplayer/lang/zh_cn.json

View File

@ -1,4 +1,4 @@
// 1.21 2024-10-23T14:19:10.2054361 Advancements
// 1.21.3 2024-10-27T23:14:21.0497079 Advancements
4d97adba079f1966090a52443bb439319f550680 data/leashedplayer/advancement/advancement_leash_arrow.json
f16184b81ea35a0fbd8f2c49b085a96c32818c69 data/leashedplayer/advancement/dog_running_player.json
bce12ed339b3b0fded263ba039f7a4e6fcfb84ca data/leashedplayer/advancement/follow_arrow.json

View File

@ -1,2 +1,2 @@
// 1.21 2024-10-23T14:43:16.8589078 Languages: zh_tw for mod: leashedplayer
// 1.21.3 2024-10-27T23:14:21.0467812 Languages: zh_tw for mod: leashedplayer
c6df14a1f53a3e892ebc6b396b552ff27f1a7580 assets/leashedplayer/lang/zh_tw.json

View File

@ -1,5 +1,11 @@
{
"asset_id": "leashedplayer:group_photo",
"author": {
"translate": "painting.leashedplayer.group_photo.author"
},
"height": 3,
"title": {
"translate": "painting.leashedplayer.group_photo.title"
},
"width": 4
}

View File

@ -2,12 +2,8 @@
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "minecraft:lead"
},
{
"item": "minecraft:arrow"
}
"minecraft:lead",
"minecraft:arrow"
],
"result": {
"count": 1,

View File

@ -1,43 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_glowstone_dust": {
"conditions": {
"items": [
{
"items": "minecraft:glowstone_dust"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_lead": {
"conditions": {
"items": [
{
"items": "minecraft:lead"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "minecraft:spectral_leash_rope_arrow_with_glowstone_dust"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_lead",
"has_glowstone_dust"
]
],
"rewards": {
"recipes": [
"minecraft:spectral_leash_rope_arrow_with_glowstone_dust"
]
}
}

View File

@ -1,43 +0,0 @@
{
"parent": "minecraft:recipes/root",
"criteria": {
"has_lead": {
"conditions": {
"items": [
{
"items": "minecraft:lead"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_spectral_arrow": {
"conditions": {
"items": [
{
"items": "minecraft:spectral_arrow"
}
]
},
"trigger": "minecraft:inventory_changed"
},
"has_the_recipe": {
"conditions": {
"recipe": "minecraft:spectral_leash_rope_arrow_with_leash_rope_arrow"
},
"trigger": "minecraft:recipe_unlocked"
}
},
"requirements": [
[
"has_the_recipe",
"has_lead",
"has_spectral_arrow"
]
],
"rewards": {
"recipes": [
"minecraft:spectral_leash_rope_arrow_with_leash_rope_arrow"
]
}
}

View File

@ -1,21 +0,0 @@
{
"type": "minecraft:crafting_shaped",
"category": "misc",
"key": {
"#": {
"item": "leashedplayer:leash_rope_arrow"
},
"$": {
"item": "minecraft:glowstone_dust"
}
},
"pattern": [
" $ ",
"$#$",
" $ "
],
"result": {
"count": 1,
"id": "leashedplayer:spectral_leash_rope_arrow"
}
}

View File

@ -1,16 +0,0 @@
{
"type": "minecraft:crafting_shapeless",
"category": "misc",
"ingredients": [
{
"item": "minecraft:lead"
},
{
"item": "minecraft:spectral_arrow"
}
],
"result": {
"count": 1,
"id": "leashedplayer:spectral_leash_rope_arrow"
}
}

View File

@ -1,10 +1,14 @@
package com.r3944realms.leashedplayer;
import com.mojang.blaze3d.vertex.PoseStack;
import com.r3944realms.leashedplayer.client.renders.LeashRendererUtil;
import com.r3944realms.leashedplayer.client.renders.entities.LeashRopeArrowRenderer;
import com.r3944realms.leashedplayer.client.renders.entities.SpectralLeashRopeArrowRenderer;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import com.r3944realms.leashedplayer.content.items.type.ILeashRopeArrow;
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
import net.minecraft.client.renderer.item.ItemProperties;
import net.minecraft.core.component.DataComponents;
import net.minecraft.resources.ResourceLocation;
@ -15,28 +19,44 @@ import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.fml.event.lifecycle.FMLClientSetupEvent;
import net.neoforged.neoforge.client.event.EntityRenderersEvent;
import net.neoforged.neoforge.client.event.RenderLevelStageEvent;
import net.neoforged.neoforge.client.event.RenderPlayerEvent;
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD, modid = LeashedPlayer.MOD_ID)
public class ClientEventHandler {
@SubscribeEvent
public static void onRegisterItemProperties(FMLClientSetupEvent event) {
event.enqueueWork(() -> {
ItemProperties.register(Items.CROSSBOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow"),
((pStack, pLevel, pEntity, pSeed) -> {
ChargedProjectiles chargedProjectiles = pStack.get(DataComponents.CHARGED_PROJECTILES);
return chargedProjectiles != null && (chargedProjectiles.contains(ModItemRegister.LEASH_ROPE_ARROW.get()) || chargedProjectiles.contains(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get())) ? 1.0F : 0.0F;
}));
ItemProperties.register(Items.BOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow_pulling"),
((pStack, pLevel, pEntity, pSeed) ->
(pEntity != null && pEntity.isUsingItem() && pEntity.getUseItem() == pStack && ILeashRopeArrow.isLeashRopeArrow(pStack, pEntity)) ? 1.0F: 0.0F
));
});
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.GAME, modid = LeashedPlayer.MOD_ID)
public static class Game {
@SubscribeEvent
public static void onPlayerRendererEventPre(RenderPlayerEvent.Pre event) {
PlayerRenderState renderState = event.getRenderState();
if(((IPlayerRenderStateExtension)renderState).getPlayerLeashState() != null) {
LeashRendererUtil.renderLeash(event.getPoseStack(), event.getMultiBufferSource(), renderState);
}
}
}
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD, modid = LeashedPlayer.MOD_ID)
public static class Mod {
@SubscribeEvent
public static void onRegisterItemProperties(FMLClientSetupEvent event) {
event.enqueueWork(() -> {
ItemProperties.register(Items.CROSSBOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow"),
((pStack, pLevel, pEntity, pSeed) -> {
ChargedProjectiles chargedProjectiles = pStack.get(DataComponents.CHARGED_PROJECTILES);
return chargedProjectiles != null && (chargedProjectiles.contains(ModItemRegister.LEASH_ROPE_ARROW.get()) || chargedProjectiles.contains(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get())) ? 1.0F : 0.0F;
}));
ItemProperties.register(Items.BOW, ResourceLocation.withDefaultNamespace("leash_rope_arrow_pulling"),
((pStack, pLevel, pEntity, pSeed) ->
(pEntity != null && pEntity.isUsingItem() && pEntity.getUseItem() == pStack && ILeashRopeArrow.isLeashRopeArrow(pStack, pEntity)) ? 1.0F: 0.0F
));
});
}
@SubscribeEvent
public static void RegisterRenderer(EntityRenderersEvent.RegisterRenderers event) {
event.registerEntityRenderer(ModEntityRegister.LEASH_ROPE_ARROW.get(), LeashRopeArrowRenderer::new);
event.registerEntityRenderer(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), SpectralLeashRopeArrowRenderer::new);
}
}
@SubscribeEvent
public static void RegisterRenderer(EntityRenderersEvent.RegisterRenderers event) {
event.registerEntityRenderer(ModEntityRegister.LEASH_ROPE_ARROW.get(), LeashRopeArrowRenderer::new);
event.registerEntityRenderer(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), SpectralLeashRopeArrowRenderer::new);
}
}

View File

@ -0,0 +1,367 @@
package com.r3944realms.leashedplayer.client.renders;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.datafixers.util.Either;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
import com.r3944realms.leashedplayer.modInterface.IPlayerRendererExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.client.Camera;
import net.minecraft.client.Minecraft;
import net.minecraft.client.multiplayer.ClientLevel;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.LightTexture;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.entity.vehicle.AbstractMinecart;
import net.minecraft.world.entity.vehicle.NewMinecartBehavior;
import net.minecraft.world.level.Level;
import net.minecraft.world.level.LightLayer;
import net.minecraft.world.phys.AABB;
import net.minecraft.world.phys.Vec3;
import org.joml.Matrix4f;
import java.util.List;
import java.util.UUID;
public class LeashRendererUtil {
/**
* <h1>1. 角度与弧度转换</h1>
* {@snippet lang=java :
* double d0 = (double)(pEntity.getPreciseBodyRotation(pPartialTick) * (float)(Math.PI / 180.0)) + (Math.PI / 2);
* }
* <ul>
* <li><code>pEntity.getPreciseBodyRotation(pPartialTick)</code> 返回实体的旋转角度通常是以度为单位/li>
* <li> <code>(Math.PI / 180.0)</code> 是将度数转换为弧度的乘数因为大多数三角函数 <code>cos</code> <code>sin</code>都需要弧度值</li>
* <li><code>+ (Math.PI / 2)</code> 用于将结果平移90度四分之一圆可能是为了校正方向或设置起始方向 </li>
* </ul>
*
* <p>
* <h1> 2. 三角函数计算位移</h1>
* {@snippet lang=java :
* double d1 = Math.cos(d0) * vec31.z + Math.sin(d0) * vec31.x;
* double d2 = Math.sin(d0) * vec31.z - Math.cos(d0) * vec31.x;
* }
* <ul>
* <li><code>d1</code> <code>d2</code> 是利用三角函数 <code>cos</code> <code>sin</code> 计算出来的位移量用于确定实体相对于其旋转的实际位置</li>
* <li><code>Math.cos(d0) * vec31.z</code> <code>Math.sin(d0) * vec31.x</code> 分别计算沿 X Z 轴的位移分量这种计算通常用于旋转一个点或向量</li>
* <li>两个公式结合起来用于旋转平面内的一个点 <code>(vec31.x, vec31.z)</code>从而得到旋转后的新坐标</li>
* </ul>
* <p>
* <h1> 3. 线性插值 (Lerp) </h1>
* {@snippet lang=java :
* double d3 = Mth.lerp(pPartialTick, pEntity.xo, pEntity.getX()) + d1;
* double d4 = Mth.lerp(pPartialTick, pEntity.yo, pEntity.getY()) + vec31.y;
* double d5 = Mth.lerp(pPartialTick, pEntity.zo, pEntity.getZ()) + d2;
* }
* <ul>
* <li><code>Mth.lerp</code> 是线性插值函数通常用于在两个值之间平滑过渡</li>
* <li><code>pEntity.xo</code>, <code>pEntity.yo</code>, <code>pEntity.zo</code> 是实体在上一个刻度tick中的位置 <code>pEntity.getX()</code>, <code>pEntity.getY()</code>, <code>pEntity.getZ()</code> 是当前刻度的位置</li>
* <li><code>pPartialTick</code> 介于 <code>0</code> <code>1</code> 之间用来平滑过渡使得动画更加流畅</li>
* </ul>
* <p>
* <h1> 4. 向量差值 </h1>
* {@snippet lang=java :
* float f = (float)(vec3.x - d3);
* float f1 = (float)(vec3.y - d4);
* float f2 = (float)(vec3.z - d5);
* }
* <ul>
* <li>计算两个点<code>vec3</code> <code>(d3, d4, d5)</code>之间的差值得到的 <code>f</code><code>f1</code><code>f2</code> 是向量差用于后续的渲染计算</li>
* </ul>
* <p>
* <h1> 5. 逆平方根与比例因子 </h1>
* {@snippet lang=java :
* float f4 = Mth.invSqrt(f * f + f2 * f2) * 0.025F / 2.0F;
* }
* <ul>
* <li><code>Mth.invSqrt</code> 计算的是逆平方根通常用于归一化向量或调整比例</li>
* <li><code>f * f + f2 * f2</code> 是计算向量 <code>(f, f2)</code> 的平方和用于得到其长度的平方</li>
* <li>乘以 <code>0.025F / 2.0F</code> 用于缩放结果使得线条在渲染时具有合适的比例</li>
* </ul>
* <p>
* <h1> 6. 循环绘制 </h1>
* {@snippet lang=java :
* for (int i1 = 0; i1 <= 24; i1++) {
* addVertexPair(vertexconsumer, matrix4f, f, f1, f2, i, j, k, l, 0.025F, 0.025F, f5, f6, i1, false);
* }
* }
* <ul>
* <li>循环从 <code>0</code> <code>24</code>用于创建24个顶点对形成一个链状结构或绳索的外观</li>
* <li>每个循环迭代都会更新顶点的位置颜色光照等属性使得链状结构被绘制出来</li>
* </ul>
* <p>
* <h1> 总结 </h1>
* 这些数学运算主要用于计算实体在三维空间中的位置和方向以确保在渲染链状结构如拴住的绳索链条能够跟随实体的移动和旋转并正确显示在图形编程中这些计算非常常见尤其是在处理旋转插值和光照效果时
*/
public static void renderLeash(
com.mojang.blaze3d.vertex.PoseStack poseStack,
net.minecraft.client.renderer.MultiBufferSource bufferSource,
PlayerRenderState playerRenderState
) {
float f = 0.025F;
// 获得绳索持有者的位置
PlayerLeashState leashState = ((IPlayerRenderStateExtension)playerRenderState).getPlayerLeashState();
if (leashState == null)
return;
Vec3 Holder = leashState.pos;
Vec3 o = leashState.o;
// 计算实体的朝向角度弧度
float partialTick = playerRenderState.partialTick;
double entityRotationAngleRadians = (double)(leashState.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2);
// 计算实体的绳索偏移此处add偏移让渲染拴绳显示在玩家头部下大约在脖子处
Vec3 cameraEntityLeashOffset = new Vec3(0.0, playerRenderState.eyeHeight , playerRenderState.boundingBoxWidth * 0.4F).add(0, 0, -0.2);
double leashOffsetX = Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.z + Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
double leashOffsetZ = Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.z - Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
// 计算实体当前的实际位置
double entityPosX = Mth.lerp(partialTick, o.x, playerRenderState.x) + leashOffsetX;
double entityPosY = Mth.lerp(partialTick, o.y, playerRenderState.y) + cameraEntityLeashOffset.y;
double entityPosZ = Mth.lerp(partialTick, o.z, playerRenderState.z) + leashOffsetZ;
// 计算绳索的相对位置差
float deltaX = (float)(Holder.x - entityPosX);
float deltaY = (float)(Holder.y - entityPosY);
float deltaZ = (float)(Holder.z - entityPosZ);
// 计算比例因子用于调节绳索的粗细
float leashLengthRatio = Mth.invSqrt(deltaX * deltaX + deltaZ * deltaZ) * 0.025F / 2.0F;
// 计算比例因子用于调节绳索的粗细
float leashXZScaleX = deltaZ * leashLengthRatio;
float leashXZScaleZ = deltaX * leashLengthRatio;
poseStack.pushPose();
poseStack.translate(leashState.offset);
VertexConsumer vertexconsumer = bufferSource.getBuffer(RenderType.leash());
Matrix4f matrix4f = poseStack.last().pose();
for (int i = 0; i <= 24; i++) {
addVertexPair(
vertexconsumer,
matrix4f,
deltaX,
deltaY,
deltaZ,
leashState.startBlockLight,
leashState.endBlockLight,
leashState.startSkyLight,
leashState.endSkyLight,
0.025F,
0.025F,
leashXZScaleX,
leashXZScaleZ,
i,
false
);
}
for (int j = 24; j >= 0; j--) {
addVertexPair(
vertexconsumer,
matrix4f,
deltaX,
deltaY,
deltaZ,
leashState.startBlockLight,
leashState.endBlockLight,
leashState.startSkyLight,
leashState.endSkyLight,
0.025F,
0.0F,
leashXZScaleX,
leashXZScaleZ,
j,
true
);
}
poseStack.popPose();
}
protected static void addVertexPair(
VertexConsumer buffer,
Matrix4f pose,
float startX,
float startY,
float startZ,
int entityBlockLight,
int holderBlockLight,
int entitySkyLight,
int holderSkyLight,
float yOffset,
float dy,
float dx,
float dz,
int index,
boolean reverse
) {
float f = (float)index / 24.0F;
int i = (int)Mth.lerp(f, (float)entityBlockLight, (float)holderBlockLight);
int j = (int)Mth.lerp(f, (float)entitySkyLight, (float)holderSkyLight);
int k = LightTexture.pack(i, j);
float f1 = index % 2 == (reverse ? 1 : 0) ? 0.7F : 1.0F;
float f2 = 0.5F * f1;
float f3 = 0.4F * f1;
float f4 = 0.3F * f1;
float f5 = startX * f;
float f6 = startY > 0.0F ? startY * f * f : startY - startY * (1.0F - f) * (1.0F - f);
float f7 = startZ * f;
buffer.addVertex(pose, f5 - dx, f6 + dy, f7 + dz).setColor(f2, f3, f4, 1.0F).setLight(k);
buffer.addVertex(pose, f5 + dx, f6 + yOffset - dy, f7 - dz).setColor(f2, f3, f4, 1.0F).setLight(k);
}
public static <E extends net.minecraft.world.entity.Entity> void renderLeashForCamera(
Camera camera,
float partialTick,
com.mojang.blaze3d.vertex.PoseStack poseStack,
net.minecraft.client.renderer.MultiBufferSource bufferSource,
E leashHolder,
Vec3 holderOffset
) {
poseStack.pushPose();
// 获得绳索持有者的位置
Vec3 leashHolderPosition = leashHolder.getRopeHoldPosition(partialTick).add(holderOffset);
// 获取当前观察的实体
Entity cameraEntity = camera.getEntity();
// 计算实体的朝向角度弧度
double entityRotationAngleRadians = (double)(cameraEntity.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2);
// 计算实体的绳索偏移此处add偏移让渲染拴绳显示在玩家头部下大约在脖子处
Vec3 cameraEntityLeashOffset = cameraEntity.getLeashOffset(partialTick).add(0, -0.2, -0.5);
double leashOffsetX = Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.z + Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
double leashOffsetZ = Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.z - Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
// 计算实体当前的实际位置
double entityPosX = Mth.lerp(partialTick, cameraEntity.xo, cameraEntity.getX()) + leashOffsetX;
double entityPosY = Mth.lerp(partialTick, cameraEntity.yo, cameraEntity.getY()) + cameraEntityLeashOffset.y;
double entityPosZ = Mth.lerp(partialTick, cameraEntity.zo, cameraEntity.getZ()) + leashOffsetZ;
// 在当前变换矩阵上应用偏移
poseStack.translate(leashOffsetX, cameraEntityLeashOffset.y , leashOffsetZ);
// 计算绳索的相对位置差
float deltaX = (float)(leashHolderPosition.x - entityPosX);
float deltaY = (float)(leashHolderPosition.y - entityPosY);
float deltaZ = (float)(leashHolderPosition.z - entityPosZ);
// 获取顶点消费者用于绘制绳索
VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.leash());
Matrix4f matrix = poseStack.last().pose();
// 计算比例因子用于调节绳索的粗细
float leashLengthRatio = Mth.invSqrt(deltaX * deltaX + deltaZ * deltaZ) * 0.025F / 2.0F;
float leashXZScaleX = deltaZ * leashLengthRatio;
float leashXZScaleZ = deltaX * leashLengthRatio;
// 获取光照信息
BlockPos cameraEntityBlockPos = BlockPos.containing(cameraEntity.getEyePosition(partialTick));
BlockPos leashHolderBlockPos = BlockPos.containing(leashHolder.getEyePosition(partialTick));
int cameraEntityBlockLightLevel = 15;
int leashHolderBlockLightLevel = 0; //getBlockLightLevel(leashHolder, leashHolderBlockPos);
int cameraEntitySkyLightLevel = cameraEntity.level().getBrightness(LightLayer.SKY, cameraEntityBlockPos);
int leashHolderSkyLightLevel = cameraEntity.level().getBrightness(LightLayer.SKY, leashHolderBlockPos);
// 绘制绳索的上半部分
for (int segment = 0; segment <= 24; segment++) {
addVertexPair(vertexConsumer, matrix, deltaX, deltaY, deltaZ, cameraEntityBlockLightLevel, leashHolderBlockLightLevel, cameraEntitySkyLightLevel, leashHolderSkyLightLevel, 0.025F, 0.025F, leashXZScaleX, leashXZScaleZ, segment, false);
}
// 绘制绳索的下半部分
for (int segment = 24; segment >= 0; segment--) {
addVertexPair(vertexConsumer, matrix, deltaX, deltaY, deltaZ, cameraEntityBlockLightLevel, leashHolderBlockLightLevel, cameraEntitySkyLightLevel, leashHolderSkyLightLevel, 0.025F, 0.0F, leashXZScaleX, leashXZScaleZ, segment, true);
}
poseStack.popPose();
}
public static void levelRenderLeash(ClientLevel level, Camera pCamera, PoseStack poseStack, MultiBufferSource.BufferSource multibuffersource$buffersource) {
for(Entity entity : level.entitiesForRendering()) {
//对于玩家实体拴绳渲染从第一人称视角
if (entity instanceof AbstractClientPlayer abstractClientPlayer) {
if(!(pCamera.getEntity() instanceof AbstractClientPlayer)) continue;
Minecraft mc = Minecraft.getInstance();
PlayerRenderer playerRenderer = (PlayerRenderer) mc.getEntityRenderDispatcher().getRenderer(abstractClientPlayer);
IPlayerRendererExtension playerRendererExtension = (IPlayerRendererExtension) playerRenderer;
if (mc.options.getCameraType().isFirstPerson()) {
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashDataFromEntityData();
if(leashDataFromEntityData == null) continue;
Either<UUID, BlockPos> delayedLeashInfo = leashDataFromEntityData.delayedLeashInfo;
if(delayedLeashInfo != null) {
float partialTickTime = pCamera.getPartialTickTime();
Vec3 position = pCamera.getPosition();
double dX = Mth.lerp(partialTickTime, abstractClientPlayer.xOld, abstractClientPlayer.getX()) - position.x;
double dY = Mth.lerp(partialTickTime, abstractClientPlayer.yOld, abstractClientPlayer.getY()) - position.y;
double dZ = Mth.lerp(partialTickTime, abstractClientPlayer.zOld, abstractClientPlayer.getZ()) - position.z;
Vec3 vec3 = getRenderOffset(entity, partialTickTime);
double dX_ = dX + vec3.x();
double dY_ = dY + vec3.y();
double dZ_ = dZ + vec3.z();
poseStack.pushPose();
poseStack.translate(dX_, dY_, dZ_);
if (delayedLeashInfo.right().isPresent() && delayedLeashInfo.left().isEmpty()) {
renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, LeashFenceKnotEntity.getOrCreateKnot(level, delayedLeashInfo.right().get()), Vec3.ZERO);
} else if (delayedLeashInfo.right().isEmpty() && delayedLeashInfo.left().isPresent()) {
Player playerByUUID = level.getPlayerByUUID(delayedLeashInfo.left().get());
if (playerByUUID != null) {
renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, playerByUUID, Vec3.ZERO);
} else {
double MaxLeashLength = ((ILivingEntityExtension) abstractClientPlayer).getLeashLength() * LeashedPlayer.M1() * LeashedPlayer.M2();
List<Entity> entities = level.getEntities(
null,
new AABB(
abstractClientPlayer.getX() - MaxLeashLength,
abstractClientPlayer.getY() - MaxLeashLength,
abstractClientPlayer.getZ() - MaxLeashLength,
abstractClientPlayer.getX() + MaxLeashLength,
abstractClientPlayer.getY() + MaxLeashLength,
abstractClientPlayer.getZ() + MaxLeashLength
)
);
Entity holder = null;
for (Entity entity_ : entities) {
if(entity_.getUUID().equals(delayedLeashInfo.left().get())) {
holder = entity_;
break;
}
}
if (holder != null) {
if(holder instanceof LeashRopeArrow) {
renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder, new Vec3(0.,-0.09, 0));//TODO: 待擴展Vec3吗
}
else renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder, Vec3.ZERO);
}
}
break;
}
}
}
}
}
}
public static Vec3 getRenderOffset(Entity entity, float partialTickTime) {
Vec3 ret = Vec3.ZERO;
if(entity.isPassenger()
&& entity.getVehicle() instanceof AbstractMinecart abstractminecart
&& abstractminecart.getBehavior() instanceof NewMinecartBehavior newminecartbehavior
&& newminecartbehavior.cartHasPosRotLerp()
) {
double d2 = Mth.lerp(partialTickTime, abstractminecart.xOld, abstractminecart.getX());
double d0 = Mth.lerp(partialTickTime, abstractminecart.yOld, abstractminecart.getY());
double d1 = Mth.lerp(partialTickTime, abstractminecart.zOld, abstractminecart.getZ());
ret = newminecartbehavior.getCartLerpPosition(partialTickTime).subtract(new Vec3(d2, d0, d1));
}
return ret;
}
}

View File

@ -0,0 +1,30 @@
package com.r3944realms.leashedplayer.client.renders;
import net.minecraft.util.Mth;
import net.minecraft.world.phys.Vec3;
public class PlayerLeashState {
public Vec3 o, pos, offset;
public float yRotO, yRot;
public int startBlockLight;
public int endBlockLight;
public int startSkyLight;
public int endSkyLight;
public float getPreciseBodyRotation(float pPartialTick) {
return Mth.lerp(pPartialTick, this.yRotO, this.yRot);
}
public PlayerLeashState() {
this.offset = Vec3.ZERO;
this.o = Vec3.ZERO;
this.pos = Vec3.ZERO;
this.yRot = 0.0f;
this.yRotO = 0.0f;
this.startBlockLight = 0;
this.endBlockLight = 0;
this.startSkyLight = 15;
this.endSkyLight = 15;
}
}

View File

@ -4,20 +4,27 @@ import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import net.minecraft.client.renderer.entity.ArrowRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.state.ArrowRenderState;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import org.jetbrains.annotations.NotNull;
@OnlyIn(Dist.CLIENT)
public class LeashRopeArrowRenderer extends ArrowRenderer<LeashRopeArrow> {
public class LeashRopeArrowRenderer extends ArrowRenderer<LeashRopeArrow, ArrowRenderState> {
public static final ResourceLocation LEASH_ROPE_ARROW = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/entity/projectiles/leash_rope_arrow.png");
public LeashRopeArrowRenderer(EntityRendererProvider.Context pContext) {
super(pContext);
}
@Override
public @NotNull ResourceLocation getTextureLocation(@NotNull LeashRopeArrow pEntity) {
public @NotNull ArrowRenderState createRenderState() {
return new ArrowRenderState();
}
@Override
protected @NotNull ResourceLocation getTextureLocation(@NotNull ArrowRenderState arrowRenderState) {
return LEASH_ROPE_ARROW;
}
}

View File

@ -4,20 +4,28 @@ import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.SpectralLeashRopeArrow;
import net.minecraft.client.renderer.entity.ArrowRenderer;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.state.ArrowRenderState;
import net.minecraft.resources.ResourceLocation;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.api.distmarker.OnlyIn;
import org.jetbrains.annotations.NotNull;
@OnlyIn(Dist.CLIENT)
public class SpectralLeashRopeArrowRenderer extends ArrowRenderer<SpectralLeashRopeArrow> {
public class SpectralLeashRopeArrowRenderer extends ArrowRenderer<SpectralLeashRopeArrow, ArrowRenderState> {
public static final ResourceLocation SPECTRAL_LEASH_ROPE_ARROW = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/entity/projectiles/spectral_leash_rope_arrow.png");
public SpectralLeashRopeArrowRenderer(EntityRendererProvider.Context pContext) {
super(pContext);
}
@Override
public @NotNull ResourceLocation getTextureLocation(@NotNull SpectralLeashRopeArrow pEntity) {
public @NotNull ArrowRenderState createRenderState() {
return new ArrowRenderState();
}
@Override
protected @NotNull ResourceLocation getTextureLocation(@NotNull ArrowRenderState arrowRenderState) {
return SPECTRAL_LEASH_ROPE_ARROW;
}
}

View File

@ -2,6 +2,8 @@ package com.r3944realms.leashedplayer.content.entities;
import com.r3944realms.leashedplayer.LeashedPlayer;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.MobCategory;
import net.neoforged.bus.api.IEventBus;
@ -17,7 +19,7 @@ public class ModEntityRegister {
.eyeHeight(0.13F)
.clientTrackingRange(4)
.updateInterval(20)
.build("leash_rope_arrow")
.build(ResourceKey.create(Registries.ENTITY_TYPE, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "leash_rope_arrow")))
);
public static final DeferredHolder<EntityType<?>, EntityType<SpectralLeashRopeArrow>> SPECTRAL_LEASH_ROPE_ARROW = ENTITY_TYPE.register(
"spectral_leash_rope_arrow",
@ -26,7 +28,7 @@ public class ModEntityRegister {
.eyeHeight(0.13F)
.clientTrackingRange(4)
.updateInterval(20)
.build("spectral_leash_rope_arrow")
.build(ResourceKey.create(Registries.ENTITY_TYPE, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "spectral_leash_rope_arrow")))
);
// public static final DeferredHolder<EntityType<?>, EntityType<ChainTieEntity>> CHAIN_TIE = ENTITY_TYPE.register(
// "chain_tie",

View File

@ -33,7 +33,7 @@ public class SpectralLeashRopeArrow extends LeashRopeArrow {
@Override
public void tick() {
super.tick();
if (this.level().isClientSide && !this.inGround) {
if (this.level().isClientSide && !this.isInGround()) {
this.level().addParticle(ParticleTypes.INSTANT_EFFECT, this.getX(), this.getY(), this.getZ(), 0.0, 0.0, 0.0);
}
}

View File

@ -1,6 +1,8 @@
package com.r3944realms.leashedplayer.content.gamerules;
import net.minecraft.server.MinecraftServer;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.level.GameRules;
import net.minecraft.world.level.Level;
@ -25,7 +27,7 @@ public enum GameruleRegistry {
if (gameruleDataTypes.get(gameruleName) != RuleDataType.BOOLEAN) {
return false;
}
return level.getGameRules().getBoolean((GameRules.Key<GameRules.BooleanValue>) gamerules.get(gameruleName));
return ((ServerLevel)level).getGameRules().getBoolean((GameRules.Key<GameRules.BooleanValue>) gamerules.get(gameruleName));
}
@SuppressWarnings("unchecked")
public static Integer getGameruleIntValue(Level level, String gameruleName) {
@ -35,7 +37,7 @@ public enum GameruleRegistry {
if (gameruleDataTypes.get(gameruleName) != RuleDataType.INTEGER) {
return 0;
}
return level.getGameRules().getInt((GameRules.Key<GameRules.IntegerValue>)gamerules.get(gameruleName));
return ((ServerLevel)level).getGameRules().getInt((GameRules.Key<GameRules.IntegerValue>)gamerules.get(gameruleName));
}
public void registerGamerule(String gameruleName, GameRules.Category category, boolean pDefault) {
@ -53,7 +55,7 @@ public enum GameruleRegistry {
gameruleDataTypes.put(gameruleName, RuleDataType.INTEGER);
}
public void registerGamerule(String gameruleName, GameRules.Category category, int pDefault, int pMin, int pMax, BiConsumer<MinecraftServer, GameRules.IntegerValue> pChangeListener) {
gamerules.put(gameruleName, GameRules.register(gameruleName, category, GameRules.IntegerValue.create(pDefault, pMin, pMax, pChangeListener)));
gamerules.put(gameruleName, GameRules.register(gameruleName, category, GameRules.IntegerValue.create(pDefault, pMin, pMax, FeatureFlagSet.of(), pChangeListener)));
gameruleDataTypes.put(gameruleName, RuleDataType.INTEGER);
}
public void registerGamerule(String gameruleName, GameRules.Category category,float value) {

View File

@ -4,6 +4,7 @@ import com.mojang.brigadier.arguments.FloatArgumentType;
import com.mojang.brigadier.context.CommandContext;
import net.minecraft.commands.CommandSourceStack;
import net.minecraft.server.MinecraftServer;
import net.minecraft.world.flag.FeatureFlagSet;
import net.minecraft.world.level.GameRules;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@ -38,7 +39,8 @@ public class Gamerules {
(FloatArgumentType::floatArg,
pType -> new FloatValue(pType, pDefaultValue),
pChangeListener,
GameRules.GameRuleTypeVisitor::visit
GameRules.GameRuleTypeVisitor::visit,
FeatureFlagSet.of()
);
}
public static GameRules.Type<FloatValue> create(
@ -48,7 +50,8 @@ public class Gamerules {
() -> FloatArgumentType.floatArg(pMin, pMax),
pType -> new FloatValue(pType, pDefaultValue),
pChangeListener,
GameRules.GameRuleTypeVisitor::visit
GameRules.GameRuleTypeVisitor::visit,
FeatureFlagSet.of()
);
}
public FloatValue(GameRules.Type<FloatValue> pType, float value) {

View File

@ -5,6 +5,9 @@ import com.r3944realms.leashedplayer.content.items.type.LeashRopeArrowItem;
import com.r3944realms.leashedplayer.content.items.type.SpectralLeashRopeArrowItem;
import com.r3944realms.leashedplayer.content.items.type.TestItem;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.core.registries.Registries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
@ -24,8 +27,8 @@ public class ModItemRegister {
() -> new SpectralLeashRopeArrowItem(new Item.Properties().stacksTo(16)));
public static final Supplier<Item> FABRIC = ModItemRegister.register("fabric",
() -> new TestItem(new Item.Properties().stacksTo(1))
);
() -> new TestItem(new Item.Properties().stacksTo(1)
.setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "fabric")))));
public static Supplier<Item> register(String name, Supplier<Item> supplier) {
return register(name, supplier, true);

View File

@ -1,11 +1,15 @@
package com.r3944realms.leashedplayer.content.items.type;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.core.Position;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.Projectile;
@ -22,7 +26,7 @@ import java.util.List;
public class LeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{
public static final String descKey = "item.leash_rope_arrow.description";
public LeashRopeArrowItem(Item.Properties pProperties) {
super(pProperties);
super(pProperties.setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "leash_rope_arrow")))) ;
}
public @NotNull AbstractArrow createArrow(@NotNull Level pLevel, @NotNull ItemStack pAmmo, @NotNull LivingEntity pShooter, @Nullable ItemStack pWeapon) {
@ -36,7 +40,7 @@ public class LeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{
return arrow;
}
@Override
public @NotNull Component getDescription() {
return Component.translatable(descKey).withStyle(ChatFormatting.GRAY);
}

View File

@ -1,12 +1,16 @@
package com.r3944realms.leashedplayer.content.items.type;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
import com.r3944realms.leashedplayer.content.entities.SpectralLeashRopeArrow;
import net.minecraft.ChatFormatting;
import net.minecraft.core.Direction;
import net.minecraft.core.Position;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.projectile.AbstractArrow;
import net.minecraft.world.entity.projectile.Projectile;
@ -23,7 +27,7 @@ import java.util.List;
public class SpectralLeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{
public static final String descKey = "item.spectral_leash_rope_arrow.description";
public SpectralLeashRopeArrowItem(Properties pProperties) {
super(pProperties);
super(pProperties.setId(ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "spectral_leash_rope_arrow"))));
}
public @NotNull AbstractArrow createArrow(@NotNull Level pLevel, @NotNull ItemStack pAmmo, @NotNull LivingEntity pShooter, @Nullable ItemStack pWeapon) {
return new SpectralLeashRopeArrow(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), pShooter, pLevel, pAmmo.copyWithCount(1), pWeapon);
@ -36,7 +40,6 @@ public class SpectralLeashRopeArrowItem extends ArrowItem implements ILeashRopeA
return arrow;
}
@Override
public @NotNull Component getDescription() {
return Component.translatable(descKey).withStyle(ChatFormatting.GRAY);
}

View File

@ -7,10 +7,9 @@ import com.r3944realms.leashedplayer.client.renders.gui.IFadingProcessBarRendere
import com.r3944realms.leashedplayer.client.renders.gui.IProcessBarRenderer;
import com.r3944realms.leashedplayer.client.renders.gui.TestProcessBarRenderer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResultHolder;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.level.Level;
import org.jetbrains.annotations.NotNull;
@ -21,7 +20,7 @@ public class TestItem extends Item {
}
@Override
public @NotNull InteractionResultHolder<ItemStack> use(@NotNull Level pLevel, @NotNull Player pPlayer, @NotNull InteractionHand pUsedHand) {
public @NotNull InteractionResult use(@NotNull Level pLevel, @NotNull Player pPlayer, @NotNull InteractionHand pUsedHand) {
if(!pLevel.isClientSide()){
//some lo
}

View File

@ -1,19 +1,22 @@
package com.r3944realms.leashedplayer.content.paintings;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModPaintingVariants;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.decoration.PaintingVariant;
import net.neoforged.bus.api.IEventBus;
import net.neoforged.neoforge.registries.DeferredRegister;
import org.jetbrains.annotations.NotNull;
import java.util.Optional;
import java.util.function.Supplier;
public class ModPaintingsRegister {
public static final DeferredRegister<PaintingVariant> PAINTING_VARIANT =
DeferredRegister.create(Registries.PAINTING_VARIANT, LeashedPlayer.MOD_ID);
public static final Supplier<PaintingVariant> GROUP_PHOTO = PAINTING_VARIANT.register("group_photo", () -> new PaintingVariant(1920, 1080, getAssetId("group_photo")));
public static final Supplier<PaintingVariant> GROUP_PHOTO = PAINTING_VARIANT.register("group_photo", () -> new PaintingVariant(1920, 1080, getAssetId("group_photo"), Optional.of(Component.translatable(ModPaintingVariants.getPaintingVariantTitleKey(ModPaintingVariants.GROUP_PHOTO))), Optional.of(Component.translatable(ModPaintingVariants.getPaintingVariantAuthorKey(ModPaintingVariants.GROUP_PHOTO)))));
private static @NotNull ResourceLocation getAssetId( String paint_name) {
return ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/painting/"+paint_name+".png");

View File

@ -5,6 +5,7 @@ import com.r3944realms.leashedplayer.datagen.provider.*;
import com.r3944realms.leashedplayer.utils.Enum.LanguageEnum;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.DataProvider;
import net.minecraft.data.PackOutput;
import net.neoforged.bus.api.SubscribeEvent;
import net.neoforged.fml.common.EventBusSubscriber;
import net.neoforged.neoforge.common.data.ExistingFileHelper;
@ -17,7 +18,6 @@ public class ModDataGeneratorHandler {
@SubscribeEvent
public static void genData(GatherDataEvent event) {
CompletableFuture<HolderLookup.Provider> holderFolder = event.getLookupProvider();
ExistingFileHelper existingFileHelper = event.getExistingFileHelper();
/*Language Provider ENGLISH CHINESE(SIM/TRA)*/
addLanguage(event, LanguageEnum.English);
@ -44,9 +44,10 @@ public class ModDataGeneratorHandler {
);
}
private static void RecipeGenerator(GatherDataEvent event, CompletableFuture<HolderLookup.Provider> future) {
PackOutput packOutput = event.getGenerator().getPackOutput();
event.getGenerator().addProvider(
event.includeServer(),
(DataProvider.Factory<ModRecipeProvider>) pOutput -> new ModRecipeProvider(pOutput, future)
new ModRecipeProvider.Runner(packOutput, future)
);
}
private static void ModTagsProvider(GatherDataEvent event, CompletableFuture<HolderLookup.Provider> completableFuture, ExistingFileHelper helper) {

View File

@ -10,7 +10,9 @@ import net.minecraft.advancements.Advancement;
import net.minecraft.advancements.AdvancementHolder;
import net.minecraft.advancements.AdvancementType;
import net.minecraft.advancements.critereon.*;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderLookup;
import net.minecraft.core.registries.Registries;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.EntityType;
@ -26,6 +28,7 @@ public class ModAdvancementGenerator implements AdvancementProvider.AdvancementG
private final ResourceLocation ADV_BG = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/gui/advancements/backgrounds/leashed_player.png");
@Override
public void generate(HolderLookup.@NotNull Provider registries, @NotNull Consumer<AdvancementHolder> saver, @NotNull ExistingFileHelper existingFileHelper) {
HolderGetter<EntityType<?>> holdergetter = registries.lookupOrThrow(Registries.ENTITY_TYPE);
AdvancementHolder hasLeashRopeItem = Advancement.Builder.advancement().display(
Items.LEAD,
Component.translatable(ModAdvancementKey.LEASH_START.getNameKey()),
@ -74,7 +77,7 @@ public class ModAdvancementGenerator implements AdvancementProvider.AdvancementG
true,
true
).addCriterion("leash_self", LeashPlayerTrigger.TriggerInstance.LeashPlayer(
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(EntityType.LEASH_KNOT))
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, EntityType.LEASH_KNOT))
))
.parent(hasLeashRopeItem).save(saver, ModAdvancementKey.LEASHED_SELF.getNameWithNameSpace());
AdvancementHolder followLeashRopeArrow = Advancement.Builder.advancement().display(
@ -87,7 +90,7 @@ public class ModAdvancementGenerator implements AdvancementProvider.AdvancementG
false,
true
).addCriterion("leash_arrow", LeashPlayerTrigger.TriggerInstance.LeashPlayer(
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(ModEntityRegister.LEASH_ROPE_ARROW.get()))
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, ModEntityRegister.LEASH_ROPE_ARROW.get()))
))
.parent(hasLeashRopeArrow)
.save(saver, ModAdvancementKey.FOLLOW_LEASH_ARROW.getNameWithNameSpace());
@ -101,7 +104,7 @@ public class ModAdvancementGenerator implements AdvancementProvider.AdvancementG
true,
true
).addCriterion("leash_by_wo_do", LeashPlayerTrigger.TriggerInstance.LeashPlayer(
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(EntityType.WOLF))
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, EntityType.WOLF))
))
.parent(hasLeashRopeArrow).save(saver, ModAdvancementKey.DOG_RUNNING_PLAYER.getNameWithNameSpace());
@ -116,7 +119,7 @@ public class ModAdvancementGenerator implements AdvancementProvider.AdvancementG
true
).addCriterion("leash_other_player",
LeashPlayerTrigger.TriggerInstance.LeashPlayer(
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(EntityType.PLAYER))
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, EntityType.PLAYER))
)
)
.parent(hasLeashRopeItem).save(saver, ModAdvancementKey.LEASHED_FRIEND.getNameWithNameSpace());

View File

@ -1,34 +1,36 @@
package com.r3944realms.leashedplayer.datagen.provider;
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
import net.minecraft.core.HolderGetter;
import net.minecraft.core.HolderLookup;
import net.minecraft.data.PackOutput;
import net.minecraft.data.recipes.*;
import net.minecraft.data.recipes.packs.VanillaRecipeProvider;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import org.jetbrains.annotations.NotNull;
import java.util.concurrent.CompletableFuture;
public class ModRecipeProvider extends RecipeProvider {
public ModRecipeProvider(PackOutput pOutput, CompletableFuture<HolderLookup.Provider> future) {
super(pOutput, future);
public ModRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
super(registries, output);
}
@Override
protected void buildRecipes(@NotNull RecipeOutput pRecipeOutput) {
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, ModItemRegister.LEASH_ROPE_ARROW.get(),1)
protected void buildRecipes() {
this.shapeless(RecipeCategory.MISC, ModItemRegister.LEASH_ROPE_ARROW.get(), 1)
.requires(Items.LEAD)
.requires(Items.ARROW)
.unlockedBy("has_lead",has(Items.LEAD))
.save(pRecipeOutput);
ShapelessRecipeBuilder.shapeless(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
.save(this.output);
this.shapeless(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
.requires(Items.LEAD)
.requires(Items.SPECTRAL_ARROW)
.unlockedBy("has_lead",has(Items.LEAD))
.unlockedBy("has_spectral_arrow",has(Items.SPECTRAL_ARROW))
.save(pRecipeOutput, "spectral_leash_rope_arrow_with_leash_rope_arrow");
ShapedRecipeBuilder.shaped(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
.save(this.output);
this.shaped(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
.pattern(" $ ")
.pattern("$#$")
.pattern(" $ ")
@ -36,7 +38,24 @@ public class ModRecipeProvider extends RecipeProvider {
.define('$', Items.GLOWSTONE_DUST)
.unlockedBy("has_lead",has(Items.LEAD))
.unlockedBy("has_glowstone_dust",has(Items.GLOWSTONE_DUST))
.save(pRecipeOutput,"spectral_leash_rope_arrow_with_glowstone_dust");
.save(this.output,"2");
}
public static class Runner extends RecipeProvider.Runner {
public Runner(PackOutput pPackOutput, CompletableFuture<HolderLookup.Provider> providerCompletableFuture) {
super(pPackOutput, providerCompletableFuture);
}
@Override
@NotNull
public RecipeProvider createRecipeProvider(HolderLookup.@NotNull Provider provider, @NotNull RecipeOutput output) {
return new ModRecipeProvider(provider, output);
}
@Override
public @NotNull String getName() {
return "LeashedPlayer Recipes";
}
}

View File

@ -3,10 +3,13 @@ package com.r3944realms.leashedplayer.datagen.provider.attributes;
import com.r3944realms.leashedplayer.LeashedPlayer;
import net.minecraft.core.registries.Registries;
import net.minecraft.data.worldgen.BootstrapContext;
import net.minecraft.network.chat.Component;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.entity.decoration.PaintingVariant;
import java.util.Optional;
public class ModPaintingVariants {
public static final ResourceKey<PaintingVariant> GROUP_PHOTO = create("group_photo");
@ -14,10 +17,10 @@ public class ModPaintingVariants {
PaintingVariantBootstrap(pContext);
}
public static void PaintingVariantBootstrap(BootstrapContext<PaintingVariant> pContext) {
ModPaintingVariants.register(pContext, ModPaintingVariants.GROUP_PHOTO, 4, 3);
ModPaintingVariants.register(pContext, ModPaintingVariants.GROUP_PHOTO, 4, 3, Component.translatable(ModPaintingVariants.getPaintingVariantTitleKey(ModPaintingVariants.GROUP_PHOTO)), Component.translatable(ModPaintingVariants.getPaintingVariantAuthorKey(ModPaintingVariants.GROUP_PHOTO)));
}
private static void register(BootstrapContext<PaintingVariant> pContext, ResourceKey<PaintingVariant> pKey, int pWidth, int pHeight) {
pContext.register(pKey, new PaintingVariant(pWidth, pHeight, pKey.location()));
private static void register(BootstrapContext<PaintingVariant> pContext, ResourceKey<PaintingVariant> pKey, int pWidth, int pHeight, Component title, Component author) {
pContext.register(pKey, new PaintingVariant(pWidth, pHeight, pKey.location(), Optional.of(title), Optional.of(author)));
}
private static ResourceKey<PaintingVariant> create(String pName) {
return ResourceKey.create(Registries.PAINTING_VARIANT, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, pName));

View File

@ -1,8 +1,10 @@
package com.r3944realms.leashedplayer.mixin.both;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.server.level.ServerLevel;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.Leashable;
import net.minecraft.world.level.Level;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
@ -12,6 +14,8 @@ import org.spongepowered.asm.mixin.injection.Redirect;
public abstract class MixinEntity {
@Shadow public abstract void igniteForSeconds(float pSeconds);
@Shadow public abstract Level level();
/**
* 这里重定向当实体类实现了{@link PlayerLeashable}接口时<br/>
* 阻止原版的{@link Leashable} 的tickLeash方法调用将其<br/>
@ -21,11 +25,11 @@ public abstract class MixinEntity {
*/
@Redirect(
method = "baseTick",
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Leashable;tickLeash(Lnet/minecraft/world/entity/Entity;)V")
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Leashable;tickLeash(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;)V")
)
<E extends Entity & Leashable> void checkAndCancelIfTure(E entity) {
if(!(entity instanceof PlayerLeashable)) {
Leashable.tickLeash(entity);
<E extends Entity & Leashable> void checkAndCancelIfTure(ServerLevel f, E entity) {
if(!(entity instanceof PlayerLeashable) && level() instanceof ServerLevel serverLevel_) {
Leashable.tickLeash(serverLevel_, entity);
}
}

View File

@ -1,30 +0,0 @@
package com.r3944realms.leashedplayer.mixin.client;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.entity.EntityRenderer;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.phys.Vec3;
import org.jetbrains.annotations.NotNull;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(EntityRenderer.class)
public abstract class MixinEntityRenderer {
@Redirect(
method = {"renderLeash"},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/world/entity/Entity;getLeashOffset(F)Lnet/minecraft/world/phys/Vec3;"
)
)
private @NotNull Vec3 ret(Entity instance, float pPartialTick) {
if(instance instanceof AbstractClientPlayer) {
//为了使拴绳在在第三视角下位于玩家脖子处
return instance.getLeashOffset(pPartialTick).add(0, -0.2, -0.2);//TODO:待擴展Vec3
}
return instance.getLeashOffset(pPartialTick);//非实现这个接口则不变
}
}

View File

@ -1,5 +1,6 @@
package com.r3944realms.leashedplayer.mixin.client;
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.datafixers.util.Either;
import com.r3944realms.leashedplayer.LeashedPlayer;
@ -34,6 +35,8 @@ import javax.annotation.Nullable;
import java.util.List;
import java.util.UUID;
import static com.r3944realms.leashedplayer.client.renders.LeashRendererUtil.levelRenderLeash;
@Mixin(LevelRenderer.class)
public abstract class MixinLevelRenderer {
@Shadow
@ -49,82 +52,15 @@ public abstract class MixinLevelRenderer {
@Inject(
method = {"renderLevel"},
at = @At(
value = "INVOKE",
target = "Lnet/minecraft/client/renderer/RenderBuffers;bufferSource()Lnet/minecraft/client/renderer/MultiBufferSource$BufferSource;",
shift = At.Shift.AFTER
)
at = @At(value = "HEAD")
)
private void renderLevel(DeltaTracker pDeltaTracker, boolean pRenderBlockOutline, Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, Matrix4f pFrustumMatrix, Matrix4f pProjectionMatrix, CallbackInfo ci) {
private void renderLevel(GraphicsResourceAllocator pGraphicsResourceAllocator, DeltaTracker pDeltaTracker, boolean pRenderBlockOutline, Camera pCamera, GameRenderer pGameRenderer, LightTexture pLightTexture, Matrix4f pFrustumMatrix, Matrix4f pProjectionMatrix, CallbackInfo ci) {
assert this.level != null;
PoseStack poseStack = new PoseStack();
MultiBufferSource.BufferSource multibuffersource$buffersource = this.renderBuffers.bufferSource();
for(Entity entity : this.level.entitiesForRendering()) {
//对于玩家实体拴绳渲染从第一人称视角
if (entity instanceof AbstractClientPlayer abstractClientPlayer) {
if(!(pCamera.getEntity() instanceof AbstractClientPlayer)) continue;
Minecraft mc = Minecraft.getInstance();
PlayerRenderer playerRenderer = (PlayerRenderer) mc.getEntityRenderDispatcher().getRenderer(abstractClientPlayer);
IPlayerRendererExtension playerRendererExtension = (IPlayerRendererExtension) playerRenderer;
if (mc.options.getCameraType().isFirstPerson()) {
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashDataFromEntityData();
if(leashDataFromEntityData == null) continue;
Either<UUID, BlockPos> delayedLeashInfo = leashDataFromEntityData.delayedLeashInfo;
if(delayedLeashInfo != null) {
float partialTickTime = pCamera.getPartialTickTime();
Vec3 position = pCamera.getPosition();
double dX = Mth.lerp(partialTickTime, abstractClientPlayer.xOld, abstractClientPlayer.getX()) - position.x;
double dY = Mth.lerp(partialTickTime, abstractClientPlayer.yOld, abstractClientPlayer.getY()) - position.y;
double dZ = Mth.lerp(partialTickTime, abstractClientPlayer.zOld, abstractClientPlayer.getZ()) - position.z;
Vec3 vec3 = playerRenderer.getRenderOffset(abstractClientPlayer, partialTickTime);
double dX_ = dX + vec3.x();
double dY_ = dY + vec3.y();
double dZ_ = dZ + vec3.z();
poseStack.pushPose();
poseStack.translate(dX_, dY_, dZ_);
ClientLevel level = mc.level;
if (delayedLeashInfo.right().isPresent() && delayedLeashInfo.left().isEmpty()) {
assert level != null;
playerRendererExtension.renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, LeashFenceKnotEntity.getOrCreateKnot(level, delayedLeashInfo.right().get()));
} else if (delayedLeashInfo.right().isEmpty() && delayedLeashInfo.left().isPresent()) {
assert level != null;
Player playerByUUID = level.getPlayerByUUID(delayedLeashInfo.left().get());
if (playerByUUID != null) {
playerRendererExtension.renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, playerByUUID);
} else {
double MaxLeashLength = ((ILivingEntityExtension) abstractClientPlayer).getLeashLength() * LeashedPlayer.M1() * LeashedPlayer.M2();
List<Entity> entities = level.getEntities(
null,
new AABB(
abstractClientPlayer.getX() - MaxLeashLength,
abstractClientPlayer.getY() - MaxLeashLength,
abstractClientPlayer.getZ() - MaxLeashLength,
abstractClientPlayer.getX() + MaxLeashLength,
abstractClientPlayer.getY() + MaxLeashLength,
abstractClientPlayer.getZ() + MaxLeashLength
)
);
Entity holder = null;
for (Entity entity_ : entities) {
if(entity_.getUUID().equals(delayedLeashInfo.left().get())) {
holder = entity_;
break;
}
}
if (holder != null) {
if(holder instanceof LeashRopeArrow) {
playerRendererExtension.renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder, new Vec3(0.,-0.09, 0));//TODO: 待擴展Vec3吗
}
else playerRendererExtension.renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder);
}
}
break;
}
}
}
}
}
levelRenderLeash(level, pCamera, poseStack, multibuffersource$buffersource);
}
}

View File

@ -0,0 +1,28 @@
package com.r3944realms.leashedplayer.mixin.client;
import com.r3944realms.leashedplayer.client.renders.PlayerLeashState;
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
import org.jetbrains.annotations.Nullable;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
@SuppressWarnings({"AddedMixinMembersNamePattern"})
@Mixin(PlayerRenderState.class)
public class MixinPlayerRenderState implements IPlayerRenderStateExtension {
@Unique
@Nullable
private PlayerLeashState playerLeashState;
@Override
public @Nullable PlayerLeashState getPlayerLeashState() {
return playerLeashState;
}
@Override
public void setPlayerLeashState(@Nullable PlayerLeashState playerRenderState) {
this.playerLeashState = playerRenderState;
}
}

View File

@ -4,8 +4,10 @@ import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.blaze3d.vertex.VertexConsumer;
import com.mojang.datafixers.util.Either;
import com.r3944realms.leashedplayer.LeashedPlayer;
import com.r3944realms.leashedplayer.client.renders.PlayerLeashState;
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
import com.r3944realms.leashedplayer.modInterface.IPlayerRendererExtension;
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
import net.minecraft.client.Camera;
@ -18,6 +20,8 @@ import net.minecraft.client.renderer.RenderType;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.client.renderer.entity.state.EntityRenderState;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
import net.minecraft.core.BlockPos;
import net.minecraft.util.Mth;
import net.minecraft.world.entity.Entity;
@ -38,238 +42,66 @@ import java.util.List;
import java.util.UUID;
@Mixin(PlayerRenderer.class)
public abstract class MixinPlayerRenderer extends LivingEntityRenderer<AbstractClientPlayer, PlayerModel<AbstractClientPlayer>> implements IPlayerRendererExtension {
public MixinPlayerRenderer(EntityRendererProvider.Context pContext, PlayerModel<AbstractClientPlayer> pModel, float pShadowRadius) {
public abstract class MixinPlayerRenderer extends LivingEntityRenderer<AbstractClientPlayer, PlayerRenderState, PlayerModel> implements IPlayerRendererExtension {
public MixinPlayerRenderer(EntityRendererProvider.Context pContext, PlayerModel pModel, float pShadowRadius) {
super(pContext, pModel, pShadowRadius);
}
@Inject(
at = @At("HEAD"),
method = "render(Lnet/minecraft/client/player/AbstractClientPlayer;FFLcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/client/renderer/MultiBufferSource;I)V"
)
private void renderMixin(AbstractClientPlayer pEntity, float pEntityYaw, float pPartialTicks, PoseStack pPoseStack, MultiBufferSource pBuffer, int pPackedLight, CallbackInfo ci) {
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) pEntity).getLeashDataFromEntityData();
if(leashDataFromEntityData == null) return;
Either<UUID, BlockPos> delayedLeashInfo = leashDataFromEntityData.delayedLeashInfo;
if(delayedLeashInfo != null) {
Minecraft mc = Minecraft.getInstance();
ClientLevel level = mc.level;
if (delayedLeashInfo.right().isPresent() && delayedLeashInfo.left().isEmpty()) {
assert level != null;
renderLeash(pEntity, pPartialTicks, pPoseStack, pBuffer, LeashFenceKnotEntity.getOrCreateKnot(level, delayedLeashInfo.right().get()));
} else if (delayedLeashInfo.right().isEmpty() && delayedLeashInfo.left().isPresent()) {
assert level != null;
Player playerByUUID = level.getPlayerByUUID(delayedLeashInfo.left().get());
if (playerByUUID != null) {
renderLeash(pEntity, pPartialTicks, pPoseStack, pBuffer, playerByUUID);
} else {
double breakDistanceTime = (leashDataFromEntityData.leashHolder instanceof LeashRopeArrow) ? LeashedPlayer.M1() * LeashedPlayer.M2() : LeashedPlayer.M1();
double MaxLeashLength = ((ILivingEntityExtension) pEntity).getLeashLength() * breakDistanceTime;
List<Entity> entities = level.getEntities(
null,
new AABB(
pEntity.getX() - MaxLeashLength,
pEntity.getY() - MaxLeashLength,
pEntity.getZ() - MaxLeashLength,
pEntity.getX() + MaxLeashLength,
pEntity.getY() + MaxLeashLength,
pEntity.getZ() + MaxLeashLength
)
);
Entity holder = null;
for (Entity entity_ : entities) {
if(entity_.getUUID().equals(delayedLeashInfo.left().get())) {
holder = entity_;
break;
@Inject(method = {"extractRenderState(Lnet/minecraft/client/player/AbstractClientPlayer;Lnet/minecraft/client/renderer/entity/state/PlayerRenderState;F)V"}, at = @At("TAIL"))
public void extractRenderState(AbstractClientPlayer abstractClientPlayer, PlayerRenderState playerRenderState, float partTicks, CallbackInfo ci) {
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashDataFromEntityData();
IPlayerRenderStateExtension iPlayerRenderStateExtension = (IPlayerRenderStateExtension) playerRenderState;
if(leashDataFromEntityData != null) {
Either<UUID, BlockPos> delayedLeashInfo = leashDataFromEntityData.delayedLeashInfo;
PlayerLeashState playerLeashState = new PlayerLeashState();
if (delayedLeashInfo != null) {
Minecraft mc = Minecraft.getInstance();
ClientLevel level = mc.level;
if (delayedLeashInfo.right().isPresent() && delayedLeashInfo.left().isEmpty()) {
assert level != null;
playerLeashState.pos = delayedLeashInfo.right().get().getCenter().add(0.0, abstractClientPlayer.getEyeHeight() *0.7, 0);
} else if (delayedLeashInfo.right().isEmpty() && delayedLeashInfo.left().isPresent()) {
assert level != null;
Player playerByUUID = level.getPlayerByUUID(delayedLeashInfo.left().get());
if (playerByUUID != null) {
playerLeashState.pos = playerByUUID.position().add(0.0, abstractClientPlayer.getEyeHeight() *0.7, 0);
} else {
double breakDistanceTime = (leashDataFromEntityData.leashHolder instanceof LeashRopeArrow) ? LeashedPlayer.M1() * LeashedPlayer.M2() : LeashedPlayer.M1();
double MaxLeashLength = ((ILivingEntityExtension) abstractClientPlayer).getLeashLength() * breakDistanceTime;
List<Entity> entities = level.getEntities(
null,
new AABB(
abstractClientPlayer.getX() - MaxLeashLength,
abstractClientPlayer.getY() - MaxLeashLength,
abstractClientPlayer.getZ() - MaxLeashLength,
abstractClientPlayer.getX() + MaxLeashLength,
abstractClientPlayer.getY() + MaxLeashLength,
abstractClientPlayer.getZ() + MaxLeashLength
)
);
Entity holder = null;
for (Entity entity_ : entities) {
if (entity_.getUUID().equals(delayedLeashInfo.left().get())) {
holder = entity_;
break;
}
}
}
if (holder != null) {
if(holder instanceof LeashRopeArrow) {
renderLeash(pEntity, pPartialTicks, pPoseStack, pBuffer, holder, new Vec3(0,0, 0));//TODO: 待擴展Vec3
if (holder != null) {
if (holder instanceof LeashRopeArrow) {
playerLeashState.pos = holder.position().add(0.0, abstractClientPlayer.getEyeHeight() *0.7, 0);//TODO: 待擴展Vec3
} else playerLeashState.pos = holder.position().add(0.0, abstractClientPlayer.getEyeHeight() *0.7, 0);
}
else renderLeash(pEntity, pPartialTicks, pPoseStack, pBuffer, holder);
}
}
playerLeashState.o = new Vec3(abstractClientPlayer.xo, abstractClientPlayer.yo, abstractClientPlayer.zo);
Entity leashHolder = leashDataFromEntityData.leashHolder;
playerLeashState.yRotO = abstractClientPlayer.yRotO;
playerLeashState.yRot = abstractClientPlayer.getYRot();
iPlayerRenderStateExtension.setPlayerLeashState(playerLeashState);
}
}
}
/**
* <h1>1. 角度与弧度转换</h1>
* {@snippet lang=java :
* double d0 = (double)(pEntity.getPreciseBodyRotation(pPartialTick) * (float)(Math.PI / 180.0)) + (Math.PI / 2);
* }
* <ul>
* <li><code>pEntity.getPreciseBodyRotation(pPartialTick)</code> 返回实体的旋转角度通常是以度为单位/li>
* <li> <code>(Math.PI / 180.0)</code> 是将度数转换为弧度的乘数因为大多数三角函数 <code>cos</code> <code>sin</code>都需要弧度值</li>
* <li><code>+ (Math.PI / 2)</code> 用于将结果平移90度四分之一圆可能是为了校正方向或设置起始方向 </li>
* </ul>
*
* <p>
* <h1> 2. 三角函数计算位移</h1>
* {@snippet lang=java :
* double d1 = Math.cos(d0) * vec31.z + Math.sin(d0) * vec31.x;
* double d2 = Math.sin(d0) * vec31.z - Math.cos(d0) * vec31.x;
* }
* <ul>
* <li><code>d1</code> <code>d2</code> 是利用三角函数 <code>cos</code> <code>sin</code> 计算出来的位移量用于确定实体相对于其旋转的实际位置</li>
* <li><code>Math.cos(d0) * vec31.z</code> <code>Math.sin(d0) * vec31.x</code> 分别计算沿 X Z 轴的位移分量这种计算通常用于旋转一个点或向量</li>
* <li>两个公式结合起来用于旋转平面内的一个点 <code>(vec31.x, vec31.z)</code>从而得到旋转后的新坐标</li>
* </ul>
* <p>
* <h1> 3. 线性插值 (Lerp) </h1>
* {@snippet lang=java :
* double d3 = Mth.lerp(pPartialTick, pEntity.xo, pEntity.getX()) + d1;
* double d4 = Mth.lerp(pPartialTick, pEntity.yo, pEntity.getY()) + vec31.y;
* double d5 = Mth.lerp(pPartialTick, pEntity.zo, pEntity.getZ()) + d2;
* }
* <ul>
* <li><code>Mth.lerp</code> 是线性插值函数通常用于在两个值之间平滑过渡</li>
* <li><code>pEntity.xo</code>, <code>pEntity.yo</code>, <code>pEntity.zo</code> 是实体在上一个刻度tick中的位置 <code>pEntity.getX()</code>, <code>pEntity.getY()</code>, <code>pEntity.getZ()</code> 是当前刻度的位置</li>
* <li><code>pPartialTick</code> 介于 <code>0</code> <code>1</code> 之间用来平滑过渡使得动画更加流畅</li>
* </ul>
* <p>
* <h1> 4. 向量差值 </h1>
* {@snippet lang=java :
* float f = (float)(vec3.x - d3);
* float f1 = (float)(vec3.y - d4);
* float f2 = (float)(vec3.z - d5);
* }
* <ul>
* <li>计算两个点<code>vec3</code> <code>(d3, d4, d5)</code>之间的差值得到的 <code>f</code><code>f1</code><code>f2</code> 是向量差用于后续的渲染计算</li>
* </ul>
* <p>
* <h1> 5. 逆平方根与比例因子 </h1>
* {@snippet lang=java :
* float f4 = Mth.invSqrt(f * f + f2 * f2) * 0.025F / 2.0F;
* }
* <ul>
* <li><code>Mth.invSqrt</code> 计算的是逆平方根通常用于归一化向量或调整比例</li>
* <li><code>f * f + f2 * f2</code> 是计算向量 <code>(f, f2)</code> 的平方和用于得到其长度的平方</li>
* <li>乘以 <code>0.025F / 2.0F</code> 用于缩放结果使得线条在渲染时具有合适的比例</li>
* </ul>
* <p>
* <h1> 6. 循环绘制 </h1>
* {@snippet lang=java :
* for (int i1 = 0; i1 <= 24; i1++) {
* addVertexPair(vertexconsumer, matrix4f, f, f1, f2, i, j, k, l, 0.025F, 0.025F, f5, f6, i1, false);
* }
* }
* <ul>
* <li>循环从 <code>0</code> <code>24</code>用于创建24个顶点对形成一个链状结构或绳索的外观</li>
* <li>每个循环迭代都会更新顶点的位置颜色光照等属性使得链状结构被绘制出来</li>
* </ul>
* <p>
* <h1> 总结 </h1>
* 这些数学运算主要用于计算实体在三维空间中的位置和方向以确保在渲染链状结构如拴住的绳索链条能够跟随实体的移动和旋转并正确显示在图形编程中这些计算非常常见尤其是在处理旋转插值和光照效果时
*/
@SuppressWarnings("AddedMixinMembersNamePattern")
@Unique
public <E extends net.minecraft.world.entity.Entity> void renderLeashForCamera(
Camera camera,
float partialTick,
com.mojang.blaze3d.vertex.PoseStack poseStack,
net.minecraft.client.renderer.MultiBufferSource bufferSource,
E leashHolder,
Vec3 holderOffset
) {
poseStack.pushPose();
// 获得绳索持有者的位置
Vec3 leashHolderPosition = leashHolder.getRopeHoldPosition(partialTick).add(holderOffset);
// 获取当前观察的实体
Entity cameraEntity = camera.getEntity();
// 计算实体的朝向角度弧度
double entityRotationAngleRadians = (double)(cameraEntity.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2);
// 计算实体的绳索偏移此处add偏移让渲染拴绳显示在玩家头部下大约在脖子处
Vec3 cameraEntityLeashOffset = cameraEntity.getLeashOffset(partialTick).add(0, -0.2, -0.5);
double leashOffsetX = Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.z + Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
double leashOffsetZ = Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.z - Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
// 计算实体当前的实际位置
double entityPosX = Mth.lerp(partialTick, cameraEntity.xo, cameraEntity.getX()) + leashOffsetX;
double entityPosY = Mth.lerp(partialTick, cameraEntity.yo, cameraEntity.getY()) + cameraEntityLeashOffset.y;
double entityPosZ = Mth.lerp(partialTick, cameraEntity.zo, cameraEntity.getZ()) + leashOffsetZ;
// 在当前变换矩阵上应用偏移
poseStack.translate(leashOffsetX, cameraEntityLeashOffset.y , leashOffsetZ);
// 计算绳索的相对位置差
float deltaX = (float)(leashHolderPosition.x - entityPosX);
float deltaY = (float)(leashHolderPosition.y - entityPosY);
float deltaZ = (float)(leashHolderPosition.z - entityPosZ);
// 获取顶点消费者用于绘制绳索
VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.leash());
Matrix4f matrix = poseStack.last().pose();
// 计算比例因子用于调节绳索的粗细
float leashLengthRatio = Mth.invSqrt(deltaX * deltaX + deltaZ * deltaZ) * 0.025F / 2.0F;
float leashXZScaleX = deltaZ * leashLengthRatio;
float leashXZScaleZ = deltaX * leashLengthRatio;
// 获取光照信息
BlockPos cameraEntityBlockPos = BlockPos.containing(cameraEntity.getEyePosition(partialTick));
BlockPos leashHolderBlockPos = BlockPos.containing(leashHolder.getEyePosition(partialTick));
int cameraEntityBlockLightLevel = this.getBlockLightLevel((AbstractClientPlayer) cameraEntity, cameraEntityBlockPos);
int leashHolderBlockLightLevel = 0; //getBlockLightLevel(leashHolder, leashHolderBlockPos);
int cameraEntitySkyLightLevel = cameraEntity.level().getBrightness(LightLayer.SKY, cameraEntityBlockPos);
int leashHolderSkyLightLevel = cameraEntity.level().getBrightness(LightLayer.SKY, leashHolderBlockPos);
// 绘制绳索的上半部分
for (int segment = 0; segment <= 24; segment++) {
addVertexPair(vertexConsumer, matrix, deltaX, deltaY, deltaZ, cameraEntityBlockLightLevel, leashHolderBlockLightLevel, cameraEntitySkyLightLevel, leashHolderSkyLightLevel, 0.025F, 0.025F, leashXZScaleX, leashXZScaleZ, segment, false);
} else {
iPlayerRenderStateExtension.setPlayerLeashState(null);
}
// 绘制绳索的下半部分
for (int segment = 24; segment >= 0; segment--) {
addVertexPair(vertexConsumer, matrix, deltaX, deltaY, deltaZ, cameraEntityBlockLightLevel, leashHolderBlockLightLevel, cameraEntitySkyLightLevel, leashHolderSkyLightLevel, 0.025F, 0.0F, leashXZScaleX, leashXZScaleZ, segment, true);
}
poseStack.popPose();
}
@SuppressWarnings("AddedMixinMembersNamePattern")
@Unique
protected <E extends Entity> void renderLeash(AbstractClientPlayer pEntity, float pPartialTick, PoseStack pPoseStack, MultiBufferSource pBufferSource, E pLeashHolder, Vec3 holderOffset) {
pPoseStack.pushPose();
Vec3 vec3 = pLeashHolder.getRopeHoldPosition(pPartialTick).add(holderOffset);
double d0 = (double)(pEntity.getPreciseBodyRotation(pPartialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2);
Vec3 vec31 = pEntity.getLeashOffset(pPartialTick).add(0, -0.2, -0.2);//TODO:待擴展Vec3);
double d1 = Math.cos(d0) * vec31.z + Math.sin(d0) * vec31.x;
double d2 = Math.sin(d0) * vec31.z - Math.cos(d0) * vec31.x;
double d3 = Mth.lerp(pPartialTick, pEntity.xo, pEntity.getX()) + d1;
double d4 = Mth.lerp(pPartialTick, pEntity.yo, pEntity.getY()) + vec31.y;
double d5 = Mth.lerp(pPartialTick, pEntity.zo, pEntity.getZ()) + d2;
pPoseStack.translate(d1, vec31.y, d2);
float f = (float)(vec3.x - d3);
float f1 = (float)(vec3.y - d4);
float f2 = (float)(vec3.z - d5);
float f3 = 0.025F;
VertexConsumer vertexconsumer = pBufferSource.getBuffer(RenderType.leash());
Matrix4f matrix4f = pPoseStack.last().pose();
float f4 = Mth.invSqrt(f * f + f2 * f2) * 0.025F / 2.0F;
float f5 = f2 * f4;
float f6 = f * f4;
BlockPos blockpos = BlockPos.containing(pEntity.getEyePosition(pPartialTick));
BlockPos blockpos1 = BlockPos.containing(pLeashHolder.getEyePosition(pPartialTick));
int i = this.getBlockLightLevel(pEntity, blockpos);
int j = 0;
int k = pEntity.level().getBrightness(LightLayer.SKY, blockpos);
int l = pEntity.level().getBrightness(LightLayer.SKY, blockpos1);
for (int i1 = 0; i1 <= 24; i1++) {
addVertexPair(vertexconsumer, matrix4f, f, f1, f2, i, j, k, l, 0.025F, 0.025F, f5, f6, i1, false);
}
for (int j1 = 24; j1 >= 0; j1--) {
addVertexPair(vertexconsumer, matrix4f, f, f1, f2, i, j, k, l, 0.025F, 0.0F, f5, f6, j1, true);
}
pPoseStack.popPose();
}
}

View File

@ -7,7 +7,9 @@ import net.minecraft.network.protocol.game.ServerboundMovePlayerPacket;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.server.network.ServerGamePacketListenerImpl;
import net.minecraft.world.entity.Entity;
import net.minecraft.world.entity.RelativeMovement;
import net.minecraft.world.entity.PositionMoveRotation;
import net.minecraft.world.entity.Relative;
import net.minecraft.world.phys.Vec3;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
@ -26,8 +28,8 @@ public class MixinServerGamePacketListenerImpl {
public ServerPlayer player;
@Unique
private List<Entity> Pl$LeashPlayers = new ArrayList<>();
@Inject(method = {"teleport(DDDFFLjava/util/Set;)V"}, at = {@At("HEAD")})
private void teleportHead(double pX, double pY, double pZ, float pYaw, float pPitch, Set<RelativeMovement> pRelativeSet, CallbackInfo ci) {
@Inject(method = {"teleport(Lnet/minecraft/world/entity/PositionMoveRotation;Ljava/util/Set;)V"}, at = {@At("HEAD")})
private void teleportHead(PositionMoveRotation positionMoveRotation, Set<Relative> pRelativeSet, CallbackInfo ci) {
try {
//獲取Holder
this.Pl$LeashPlayers = ((PlayerLeashable)this.player).getLeashHolder() != null ? Collections.emptyList() : Objects.requireNonNull(this.player.getServer()).getPlayerList().getPlayers().stream().filter(serverPlayer -> (serverPlayer instanceof PlayerLeashable) && ((PlayerLeashable)serverPlayer).getLeashHolder() == this.player && player != serverPlayer).collect(Collectors.toList());
@ -35,17 +37,18 @@ public class MixinServerGamePacketListenerImpl {
logger.error("Internal Error:",e);
}
}
@Inject(method = {"teleport(DDDFFLjava/util/Set;)V"}, at = {@At("TAIL")})
private void teleportTail(double pX, double pY, double pZ, float pYaw, float pPitch, Set<RelativeMovement> pRelativeSet, CallbackInfo ci) {
@Inject(method = {"teleport(Lnet/minecraft/world/entity/PositionMoveRotation;Ljava/util/Set;)V"}, at = {@At("TAIL")})
private void teleportTail(PositionMoveRotation moveRotation, Set<Relative> pRelativeSet, CallbackInfo ci) {
if(GameruleRegistry.getGameruleBoolValue(this.player.serverLevel(), TeleportWithLeashedPlayers.ID)) {
for (Entity Pl$LeashPlayer : this.Pl$LeashPlayers) {
if(Pl$LeashPlayer instanceof ServerPlayer) {
if(Pl$LeashPlayer instanceof PlayerLeashable playerLeashable) {
playerLeashable.dropLeash(false,false);
if(((ServerPlayer) playerLeashable).serverLevel() == this.player.serverLevel()) {
((ServerPlayer) playerLeashable).connection.teleport(pX, pY, pZ, pYaw, pPitch, pRelativeSet);
((ServerPlayer) playerLeashable).connection.teleport(moveRotation, pRelativeSet);
} else {
((ServerPlayer) playerLeashable).teleportTo(this.player.serverLevel(), pX, pY, pZ, pYaw, pPitch);
Vec3 vec3 = moveRotation.deltaMovement();
((ServerPlayer) playerLeashable).teleportTo(this.player.serverLevel(), vec3.x, vec3.y, vec3.z, pRelativeSet, moveRotation.yRot(), moveRotation.yRot(),false);
((ServerPlayer) playerLeashable).stopRiding();
}
playerLeashable.setLeashedTo(this.player, true);

View File

@ -0,0 +1,9 @@
package com.r3944realms.leashedplayer.modInterface;
import com.r3944realms.leashedplayer.client.renders.PlayerLeashState;
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
public interface IPlayerRenderStateExtension {
PlayerLeashState getPlayerLeashState();
void setPlayerLeashState(PlayerLeashState playerRenderState);
}

View File

@ -5,9 +5,9 @@ protected net.minecraft.client.renderer.entity.EntityRenderer renderLeash(Lnet/m
#priavte ->protected
protected net.minecraft.client.renderer.entity.EntityRenderer addVertexPair(Lcom/mojang/blaze3d/vertex/VertexConsumer;Lorg/joml/Matrix4f;FFFIIIIFFFFIZ)V # addVertexPair
#这个方法原包为package-priavet 有时需要限制范围故修改
public net.minecraft.world.level.GameRules$IntegerValue create(IIILjava/util/function/BiConsumer;)Lnet/minecraft/world/level/GameRules$Type; # create
public net.minecraft.world.level.GameRules$IntegerValue create(IIILnet/minecraft/world/flag/FeatureFlagSet;Ljava/util/function/BiConsumer;)Lnet/minecraft/world/level/GameRules$Type; # create
#因为'net.minecraft.world.level.GameRules.Type' 中<init>不为 public。无法从外部软件包访问
public net.minecraft.world.level.GameRules$Type <init>(Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/world/level/GameRules$VisitorCaller;)V # Type
public net.minecraft.world.level.GameRules$Type <init>(Ljava/util/function/Supplier;Ljava/util/function/Function;Ljava/util/function/BiConsumer;Lnet/minecraft/world/level/GameRules$VisitorCaller;Lnet/minecraft/world/flag/FeatureFlagSet;)V # Type
#因为'net.minecraft.world.level.GameRules.VisitorCaller' 在 'net.minecraft.world.level.GameRules' 中不为 public。无法从外部软件包访问
public net.minecraft.world.level.GameRules$VisitorCaller #Interface
#private -> public
@ -18,4 +18,4 @@ protected net.minecraft.world.entity.projectile.AbstractArrow life # life
public net.minecraft.world.effect.MobEffect <init>(Lnet/minecraft/world/effect/MobEffectCategory;I)V # MobEffect
#private -> protected
protected net.minecraft.world.entity.projectile.Projectile cachedOwner # cachedOwner
protected net.minecraft.world.entity.projectile.Projectile ownerUUID # ownerUUID
protected net.minecraft.world.entity.projectile.Projectile ownerUUID # ownerUUID

View File

@ -9,9 +9,9 @@
"server.MixinServerGamePacketListenerImpl"
],
"client": [
"client.MixinEntityRenderer",
"client.MixinLevelRenderer",
"client.MixinPlayerRenderer"
"client.MixinPlayerRenderer",
"client.MixinPlayerRenderState"
],
"refmap": "whimsicality.refmap.json",
"required": true,