version 0.0.7
This commit is contained in:
parent
0f5e9ee4ea
commit
eb3cca667a
13
build.gradle
13
build.gradle
|
|
@ -89,7 +89,6 @@ minecraft {
|
|||
mixin {
|
||||
add sourceSets.main, "${mod_id}.refmap.json"
|
||||
config "${mod_id}.mixins.json"
|
||||
|
||||
}
|
||||
|
||||
sourceSets.main.resources { srcDir 'src/generated/resources' }
|
||||
|
|
@ -122,13 +121,13 @@ dependencies {
|
|||
minecraft "net.minecraftforge:forge:${minecraft_version}-${forge_version}"
|
||||
compileOnly 'org.spongepowered:mixin:0.8.5'
|
||||
implementation(annotationProcessor("io.github.llamalad7:mixinextras-common:0.4.1"))
|
||||
|
||||
implementation(jarJar("io.github.llamalad7:mixinextras-forge:0.4.1") {
|
||||
jarJar.ranged(it, "[0.4.1,)")
|
||||
})
|
||||
|
||||
implementation fg.deobf("dev.kosmx.player-anim:player-animation-lib-forge:1.0.2-rc1+1.20")
|
||||
implementation fg.deobf("io.github.kosmx.bendy-lib:bendy-lib-forge:4.0.0")
|
||||
implementation fg.deobf("curse.maven:freecam-by-zergatul-618947:5402097")
|
||||
// implementation fg.deobf("curse.maven:freecam-by-zergatul-618947:5402097")
|
||||
}
|
||||
|
||||
tasks.named('processResources', ProcessResources).configure {
|
||||
|
|
@ -163,7 +162,9 @@ tasks.named('jar', Jar).configure {
|
|||
"Implementation-Title" : project.name,
|
||||
"Implementation-Version" : project.jar.archiveVersion,
|
||||
"Implementation-Vendor" : mod_authors,
|
||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
|
||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
"MixinConfigs" : "${mod_id}.mixins.json"
|
||||
])
|
||||
}
|
||||
|
||||
finalizedBy 'reobfJar'
|
||||
|
|
@ -186,7 +187,9 @@ tasks.register('deobfJar', Jar) {
|
|||
"Implementation-Title" : project.name,
|
||||
"Implementation-Version" : project.jar.archiveVersion,
|
||||
"Implementation-Vendor" : mod_authors,
|
||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ")])
|
||||
"Implementation-Timestamp": new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"),
|
||||
"MixinConfigs" : "${mod_id}.mixins.json"
|
||||
])
|
||||
}
|
||||
dependsOn classes
|
||||
}
|
||||
|
|
|
|||
|
|
@ -12,7 +12,7 @@ mapping_version=2023.09.03-1.20.1
|
|||
mod_id=sccore
|
||||
mod_name=SnowyCrescentCore
|
||||
mod_license=GNU AGPL 3.0
|
||||
mod_version=1.20.1-0.0.4
|
||||
mod_version=1.20.1-0.0.7
|
||||
mod_group_id=com.linearpast
|
||||
mod_authors=LostInLinearPast
|
||||
mod_description=A lib about capability and player animator.
|
||||
|
|
|
|||
10
sccore/animation/sccore/animation.layer.json
Normal file
10
sccore/animation/sccore/animation.layer.json
Normal file
|
|
@ -0,0 +1,10 @@
|
|||
[
|
||||
{
|
||||
"key": "sccore:normal_layers",
|
||||
"priority": 42
|
||||
},
|
||||
{
|
||||
"key": "sccore:ride_layers",
|
||||
"priority": 43
|
||||
}
|
||||
]
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// 1.20.1 2025-10-30T21:02:30.6951333 Languages: zh_cn
|
||||
feac50843a3ec6d5a3ad4c4e917d0f19a2b857cb assets/sccore/lang/zh_cn.json
|
||||
|
|
@ -0,0 +1,2 @@
|
|||
// 1.20.1 2025-10-30T21:02:30.6972105 Languages: en_us
|
||||
165168d6118e3dde833169d2ab1bc0028d425d55 assets/sccore/lang/en_us.json
|
||||
40
src/generated/resources/assets/sccore/lang/en_us.json
Normal file
40
src/generated/resources/assets/sccore/lang/en_us.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"translation.sccore.animation.command_cooldown": "You cannot execute this command, cooling down: %s seconds.",
|
||||
"translation.sccore.animation.unknown_animation": "Unknown animation %s, please check if your resource packs is complete.",
|
||||
"translation.sccore.animation.without_animation_ride_entity": "Command run fail, full or unsupported animations.",
|
||||
"translation.sccore.command.animation.accept_apply_expired": "Application expired.(%s minute(s))",
|
||||
"translation.sccore.command.animation.accept_apply_success": "%s has accepted the application of %s.",
|
||||
"translation.sccore.command.animation.accept_apply_too_far": "You are too far apart. (%s block(s))",
|
||||
"translation.sccore.command.animation.accept_invite_expired": "Invite expired.(%s minute(s))",
|
||||
"translation.sccore.command.animation.accept_invite_success": "Invitation accepted.",
|
||||
"translation.sccore.command.animation.accept_invite_too_far": "You are too far apart. (%s block(s))",
|
||||
"translation.sccore.command.animation.accept_message_click": "Click here to accept.",
|
||||
"translation.sccore.command.animation.accept_request_expired": "Request expired.(%s minute(s))",
|
||||
"translation.sccore.command.animation.accept_request_success": "Request accepted.",
|
||||
"translation.sccore.command.animation.animation_json_path": "%s",
|
||||
"translation.sccore.command.animation.animation_layer_not_present": "Animation layer is not present.",
|
||||
"translation.sccore.command.animation.animation_not_present": "Animation is not present.",
|
||||
"translation.sccore.command.animation.animation_to_json": "The animation %s has been stored in the path on %s:",
|
||||
"translation.sccore.command.animation.applied_join_message": "%S§b§l Apply for §r to join your animation. ",
|
||||
"translation.sccore.command.animation.apply_expired": "%s has accepted your animation application but the application has expired. (%s minute(s))",
|
||||
"translation.sccore.command.animation.apply_join_message": "Application sent.",
|
||||
"translation.sccore.command.animation.apply_success": "%s has accepted your animation application.",
|
||||
"translation.sccore.command.animation.apply_too_far": "%s has accepted your animation application but you are too far apart. (%s block(s))",
|
||||
"translation.sccore.command.animation.clear_animations": "Animation cleared.",
|
||||
"translation.sccore.command.animation.command_run_fail": "Command run fail.",
|
||||
"translation.sccore.command.animation.command_run_success": "Command run success.",
|
||||
"translation.sccore.command.animation.invite_expired": "%s has accepted your animation invitation but the invitation has expired. (%s minute(s))",
|
||||
"translation.sccore.command.animation.invite_message": "Invitation sent.",
|
||||
"translation.sccore.command.animation.invite_success": "%s has accepted your animation invitation.",
|
||||
"translation.sccore.command.animation.invite_too_far": "%s has accepted your animation invitation but you are too far apart. (%s block(s))",
|
||||
"translation.sccore.command.animation.invited_message": "%s§c§l invites§r you to animation: %s. ",
|
||||
"translation.sccore.command.animation.play_animation_fail": "Fail to play animation with: %s",
|
||||
"translation.sccore.command.animation.play_animation_success": "Successfully played animation on %s player(s).",
|
||||
"translation.sccore.command.animation.refresh_animations": "Animation refreshed.",
|
||||
"translation.sccore.command.animation.remove_animation_fail": "Fail to remove animation with: %s",
|
||||
"translation.sccore.command.animation.remove_animation_success": "Successfully removed animation on %s player(s).",
|
||||
"translation.sccore.command.animation.request_expired": "%s has accepted your animation request but the request has expired. (%s minute(s))",
|
||||
"translation.sccore.command.animation.request_message": "Request sent.",
|
||||
"translation.sccore.command.animation.request_success": "%s has accepted your animation request.",
|
||||
"translation.sccore.command.animation.requested_message": "%s§d§l requests§r you to animation: %s. "
|
||||
}
|
||||
40
src/generated/resources/assets/sccore/lang/zh_cn.json
Normal file
40
src/generated/resources/assets/sccore/lang/zh_cn.json
Normal file
|
|
@ -0,0 +1,40 @@
|
|||
{
|
||||
"translation.sccore.animation.command_cooldown": "你不能执行该指令,冷却中:%s 秒。",
|
||||
"translation.sccore.animation.unknown_animation": "未知的动画%s,请检查你的资源包是否完整。",
|
||||
"translation.sccore.animation.without_animation_ride_entity": "命令执行错误,已满人或不支持的动画。",
|
||||
"translation.sccore.command.animation.accept_apply_expired": "申请已超时。(%s分钟)",
|
||||
"translation.sccore.command.animation.accept_apply_success": "%s 接受了 %s 的申请。",
|
||||
"translation.sccore.command.animation.accept_apply_too_far": "你们距离太远了。(%s格)",
|
||||
"translation.sccore.command.animation.accept_invite_expired": "邀请已超时。(%s分钟)",
|
||||
"translation.sccore.command.animation.accept_invite_success": "已接受邀请。",
|
||||
"translation.sccore.command.animation.accept_invite_too_far": "你们距离太远了。(%s格)",
|
||||
"translation.sccore.command.animation.accept_message_click": "单击此处同意。",
|
||||
"translation.sccore.command.animation.accept_request_expired": "请求已超时。(%s分钟)",
|
||||
"translation.sccore.command.animation.accept_request_success": "已接受请求。",
|
||||
"translation.sccore.command.animation.animation_json_path": "%s",
|
||||
"translation.sccore.command.animation.animation_layer_not_present": "动画层不存在。",
|
||||
"translation.sccore.command.animation.animation_not_present": "动画不存在。",
|
||||
"translation.sccore.command.animation.animation_to_json": "动画%s已经存储到%s路径:",
|
||||
"translation.sccore.command.animation.applied_join_message": "%s§b§l 申请§r加入动画。",
|
||||
"translation.sccore.command.animation.apply_expired": "%s 接受了你的动画申请,但是申请超时了。(%s分钟)",
|
||||
"translation.sccore.command.animation.apply_join_message": "已发送申请。",
|
||||
"translation.sccore.command.animation.apply_success": "%s 接受了你的动画申请。",
|
||||
"translation.sccore.command.animation.apply_too_far": "%s 接受了你的动画申请,但你们距离太远了。(%s格)",
|
||||
"translation.sccore.command.animation.clear_animations": "动画已清除。",
|
||||
"translation.sccore.command.animation.command_run_fail": "命令执行失败。",
|
||||
"translation.sccore.command.animation.command_run_success": "命令执行成功。",
|
||||
"translation.sccore.command.animation.invite_expired": "%s 接受了你的动画邀请,但是邀请超时了。(%s分钟)",
|
||||
"translation.sccore.command.animation.invite_message": "已发送邀请。",
|
||||
"translation.sccore.command.animation.invite_success": "%s 接受了你的动画邀请。",
|
||||
"translation.sccore.command.animation.invite_too_far": "%s 接受了你的动画邀请,但你们距离太远了。(%s格)",
|
||||
"translation.sccore.command.animation.invited_message": "%s§c§l 邀请§r你进行动画:%s。",
|
||||
"translation.sccore.command.animation.play_animation_fail": "在这些玩家上播放动画失败:%s",
|
||||
"translation.sccore.command.animation.play_animation_success": "在%s个玩家上播放动画成功。",
|
||||
"translation.sccore.command.animation.refresh_animations": "动画同步状态已刷新。",
|
||||
"translation.sccore.command.animation.remove_animation_fail": "在这些玩家上移除动画失败:%s",
|
||||
"translation.sccore.command.animation.remove_animation_success": "在%s个玩家上移除动画成功。",
|
||||
"translation.sccore.command.animation.request_expired": "%s 接受了你的动画请求,但是请求超时了。(%s分钟)",
|
||||
"translation.sccore.command.animation.request_message": "已发送请求。",
|
||||
"translation.sccore.command.animation.request_success": "%s 接受了你的动画请求。",
|
||||
"translation.sccore.command.animation.requested_message": "%s§d§l 请求§r你进行动画:%s。"
|
||||
}
|
||||
|
|
@ -1,11 +1,11 @@
|
|||
package com.linearpast.sccore;
|
||||
|
||||
|
||||
import com.linearpast.sccore.animation.registry.AnimationRegistry;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||
import com.linearpast.sccore.core.ModChannel;
|
||||
import com.linearpast.sccore.core.ModCommands;
|
||||
import com.linearpast.sccore.core.ModConfigs;
|
||||
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||
import com.linearpast.sccore.example.animation.ModAnimation;
|
||||
import com.linearpast.sccore.example.capability.ModCapability;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
|
|
@ -27,15 +27,14 @@ public class SnowyCrescentCore {
|
|||
|
||||
public SnowyCrescentCore() {
|
||||
ModLoadingContext modLoadingContext = ModLoadingContext.get();
|
||||
modLoadingContext.registerConfig(ModConfig.Type.COMMON, ModConfigs.Common.SPEC);
|
||||
modLoadingContext.registerConfig(ModConfig.Type.SERVER, ModConfigs.Server.SPEC);
|
||||
|
||||
IEventBus modBus = FMLJavaModLoadingContext.get().getModEventBus();
|
||||
IEventBus forgeBus = MinecraftForge.EVENT_BUS;
|
||||
|
||||
CapabilityUtils.registerHandler(forgeBus);
|
||||
ModChannel.register();
|
||||
AnimationRegistry.register();
|
||||
AnimationRegistry.addAnimationListener(forgeBus, modBus);
|
||||
AnimationUtils.register(forgeBus, modBus);
|
||||
ModCommands.registerCommands(forgeBus, modBus);
|
||||
|
||||
if(!FMLEnvironment.production || Boolean.getBoolean(ENABLE_EXAMPLES_PROPERTY_KEY)) {
|
||||
|
|
|
|||
|
|
@ -10,6 +10,7 @@ import com.linearpast.sccore.animation.network.toclient.SyncAnimationPacket;
|
|||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRequestPacket;
|
||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRidePacket;
|
||||
import com.linearpast.sccore.core.ModChannel;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
||||
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
||||
|
|
@ -17,7 +18,11 @@ import dev.kosmx.playerAnim.api.layered.modifier.AbstractFadeModifier;
|
|||
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||
import dev.kosmx.playerAnim.core.util.Ease;
|
||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
|
|
@ -25,10 +30,14 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
|||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.UUID;
|
||||
|
||||
public class AnimationPlayer {
|
||||
public static void requestAnimationToServer(ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
ModChannel.sendToServer(new PlayAnimationRequestPacket(layer, animation));
|
||||
|
||||
public static void requestAnimationToServer(@Nullable AbstractClientPlayer player, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
UUID uuid = null;
|
||||
if(player != null) uuid = player.getUUID();
|
||||
ModChannel.sendToServer(new PlayAnimationRequestPacket(uuid, layer, animation));
|
||||
}
|
||||
|
||||
public static boolean serverPlayAnimation(ServerPlayer serverPlayer, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
|
|
@ -43,12 +52,10 @@ public class AnimationPlayer {
|
|||
|
||||
public static boolean playAnimationWithRide(ServerPlayer serverPlayer, ResourceLocation layer, @Nullable ResourceLocation animation, boolean force){
|
||||
if(animation != null) {
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
||||
if(data == null) return false;
|
||||
data.setRideAnimLayer(layer);
|
||||
return AnimationRideEntity.create(serverPlayer, layer, animation, force);
|
||||
} else {
|
||||
serverPlayer.unRide();
|
||||
AnimationDataCapability.getCapability(serverPlayer).ifPresent(IAnimationCapability::removeRiderAnimation);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -63,19 +70,26 @@ public class AnimationPlayer {
|
|||
data.clearAnimations();
|
||||
}
|
||||
|
||||
public static void syncAnimation(ServerPlayer player, ServerPlayer target, ResourceLocation layer) {
|
||||
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID(), layer), player);
|
||||
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID(), layer), target);
|
||||
public static void syncAnimation(ServerPlayer player, ServerPlayer target) {
|
||||
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID()), player);
|
||||
ModChannel.sendToPlayer(new SyncAnimationPacket(player.getUUID(), target.getUUID()), target);
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void syncAnimation(AbstractClientPlayer clientPlayer, AbstractClientPlayer target, ResourceLocation layer) {
|
||||
public static void syncAnimation(AbstractClientPlayer clientPlayer, AbstractClientPlayer target) {
|
||||
try {
|
||||
IAnimationCapability clientPlayerData = AnimationDataCapability.getCapability(clientPlayer).orElse(null);
|
||||
if(clientPlayerData == null) return;
|
||||
IAnimationCapability targetData = AnimationDataCapability.getCapability(target).orElse(null);
|
||||
if(targetData == null) return;
|
||||
ResourceLocation clientPlayerLayer = clientPlayerData.getRiderAnimLayer();
|
||||
ResourceLocation targetLayer = targetData.getRiderAnimLayer();
|
||||
if(clientPlayerLayer == null || targetLayer == null) return;
|
||||
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||
.getPlayerAssociatedData(clientPlayer).get(layer);
|
||||
.getPlayerAssociatedData(clientPlayer).get(clientPlayerLayer);
|
||||
ModifierLayer<IAnimation> targetModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||
.getPlayerAssociatedData(target).get(layer);
|
||||
.getPlayerAssociatedData(target).get(targetLayer);
|
||||
if(modifierLayer == null || targetModifierLayer == null) return;
|
||||
IMixinKeyframeAnimationPlayer animation = (IMixinKeyframeAnimationPlayer) modifierLayer.getAnimation();
|
||||
KeyframeAnimationPlayer targetAnimation = (KeyframeAnimationPlayer) targetModifierLayer.getAnimation();
|
||||
|
|
@ -87,8 +101,11 @@ public class AnimationPlayer {
|
|||
|
||||
@SuppressWarnings("unchecked")
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void playAnimation(AbstractClientPlayer clientPlayer, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
public static void playAnimation(@Nullable AbstractClientPlayer clientPlayer, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
try {
|
||||
LocalPlayer localPlayer = Minecraft.getInstance().player;
|
||||
if(clientPlayer == null) clientPlayer = localPlayer;
|
||||
if(clientPlayer == null) return;
|
||||
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||
.getPlayerAssociatedData(clientPlayer).get(layer);
|
||||
if(animation == null) {
|
||||
|
|
@ -104,7 +121,14 @@ public class AnimationPlayer {
|
|||
if(anim == null) return;
|
||||
if(modifierLayer == null) return;
|
||||
KeyframeAnimation keyframeAnimation = anim.getAnimation();
|
||||
if(keyframeAnimation == null) return;
|
||||
if(keyframeAnimation == null) {
|
||||
if(localPlayer == null) return;
|
||||
localPlayer.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.UNKNOWN_ANIMATION.getKey(),
|
||||
animation.toString()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return;
|
||||
};
|
||||
Objects.requireNonNull(modifierLayer).replaceAnimationWithFade(
|
||||
AbstractFadeModifier.standardFadeIn(3, Ease.INOUTSINE),
|
||||
new KeyframeAnimationPlayer(keyframeAnimation)
|
||||
|
|
|
|||
|
|
@ -5,13 +5,15 @@ import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
|||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.Ride;
|
||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||
import com.linearpast.sccore.animation.event.AnimationLayerRegistry;
|
||||
import com.linearpast.sccore.animation.event.EntityRendererRegistry;
|
||||
import com.linearpast.sccore.animation.event.PlayerTickEvent;
|
||||
import com.linearpast.sccore.animation.event.client.CameraAnglesModify;
|
||||
import com.linearpast.sccore.animation.event.client.ClientPlayerTick;
|
||||
import com.linearpast.sccore.animation.event.client.EntityRendererRegisterEvent;
|
||||
import com.linearpast.sccore.animation.network.toserver.RefreshAnimationPacket;
|
||||
import com.linearpast.sccore.animation.registry.AnimationEntities;
|
||||
import com.linearpast.sccore.animation.registry.AnimationRegistry;
|
||||
import com.linearpast.sccore.animation.register.AnimationCapabilities;
|
||||
import com.linearpast.sccore.animation.register.AnimationChannels;
|
||||
import com.linearpast.sccore.animation.register.AnimationEntities;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import com.linearpast.sccore.core.ModChannel;
|
||||
import com.linearpast.sccore.core.ModLazyRun;
|
||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||
|
|
@ -40,14 +42,15 @@ public class AnimationUtils {
|
|||
@Override
|
||||
public void addCommonListener(IEventBus forgeBus, IEventBus modBus) {
|
||||
AnimationEntities.register(modBus);
|
||||
modBus.addListener(AnimationLayerRegistry::onCommonSetUp);
|
||||
forgeBus.addListener(AnimationRegistry::onServerStarted);
|
||||
forgeBus.addListener(AnimationRegistry::onPlayerLoggedIn);
|
||||
forgeBus.addListener(PlayerTickEvent::onPlayerTickEvent);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addClientListener(IEventBus forgeBus, IEventBus modBus) {
|
||||
forgeBus.addListener(CameraAnglesModify::changeCameraView);
|
||||
modBus.addListener(AnimationLayerRegistry::onClientSetup);
|
||||
modBus.addListener(EntityRendererRegistry::registerEntityRenderer);
|
||||
modBus.addListener(EntityRendererRegisterEvent::registerEntityRenderer);
|
||||
forgeBus.addListener(ClientPlayerTick::onPlayerTick);
|
||||
forgeBus.addListener(ClientPlayerTick::delayRuns);
|
||||
}
|
||||
|
|
@ -56,21 +59,21 @@ public class AnimationUtils {
|
|||
/**
|
||||
* <pre>
|
||||
* Play animation.
|
||||
* If run in Dist.CLIENT, the serverPlayer can be null.
|
||||
* If run in Dist.CLIENT, player can be null, it will play animation only client.
|
||||
* If animation be null, it will remove animation on layer.
|
||||
* </pre>
|
||||
* @param serverPlayer Target player
|
||||
* @param player Target player
|
||||
* @param layer Target layer
|
||||
* @param animation Animation
|
||||
* @return If success
|
||||
*/
|
||||
public static boolean playAnimation(@Nullable ServerPlayer serverPlayer, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
public static boolean playAnimation(@Nullable Player player, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||
if(isAnimationLayerPresent(layer) && (animation == null || isAnimationPresent(animation))) {
|
||||
if(serverPlayer != null) {
|
||||
if(player instanceof ServerPlayer serverPlayer) {
|
||||
return AnimationPlayer.serverPlayAnimation(serverPlayer, layer, animation);
|
||||
}else {
|
||||
AnimationPlayer.requestAnimationToServer(layer, animation);
|
||||
}else if(player == null || player instanceof AbstractClientPlayer) {
|
||||
AnimationPlayer.requestAnimationToServer((AbstractClientPlayer) player, layer, animation);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -78,6 +81,24 @@ public class AnimationUtils {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Client send request to server and run play animation. <br>
|
||||
* Only play animation with client self.
|
||||
* @param layer Target layer
|
||||
* @param animation Target animation
|
||||
* @return If success
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static boolean requestAnimationClient(@Nullable AbstractClientPlayer player, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||
if(isAnimationLayerPresent(layer) && (animation == null || isAnimationPresent(animation))) {
|
||||
AnimationPlayer.requestAnimationToServer(player, layer, animation);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* <pre>
|
||||
* Play animation with ride. Player will ride an entity, then play animation.
|
||||
|
|
@ -100,7 +121,8 @@ public class AnimationUtils {
|
|||
if(serverPlayer != null) {
|
||||
if(serverPlayer.getVehicle() != null && force) serverPlayer.unRide();
|
||||
else if(serverPlayer.getVehicle() != null) return false;
|
||||
AnimationPlayer.playAnimationWithRide(serverPlayer, layer, animation, true);
|
||||
return AnimationPlayer.playAnimationWithRide(serverPlayer, layer, animation, true);
|
||||
|
||||
} else {
|
||||
AnimationPlayer.requestAnimationRideToServer(layer, animation, force);
|
||||
return true;
|
||||
|
|
@ -113,12 +135,12 @@ public class AnimationUtils {
|
|||
/**
|
||||
* Remove animation.
|
||||
* @see AnimationUtils#playAnimation
|
||||
* @param serverPlayer Target player
|
||||
* @param player Target player
|
||||
* @param layer Target layer
|
||||
* @return If success
|
||||
*/
|
||||
public static boolean removeAnimation(@Nullable ServerPlayer serverPlayer, ResourceLocation layer) {
|
||||
return playAnimation(serverPlayer, layer, null);
|
||||
public static boolean removeAnimation(@Nullable Player player, ResourceLocation layer) {
|
||||
return playAnimation(player, layer, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -147,20 +169,20 @@ public class AnimationUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test if layer exist animation which is playing.
|
||||
* Test if layer exist animation which is not stop.
|
||||
* <p>
|
||||
* Only in dist client
|
||||
* @param player Target player
|
||||
* @param layer Target layer
|
||||
* @return If layer exist animation which is playing
|
||||
* @return True when the currentTick not larger than stopTick
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean isClientAnimationPlaying(AbstractClientPlayer player, @Nullable ResourceLocation layer) {
|
||||
public static boolean isClientAnimationNotStop(AbstractClientPlayer player, @Nullable ResourceLocation layer) {
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||
try {
|
||||
Set<ResourceLocation> resourceLocations = new HashSet<>();
|
||||
if(layer == null) resourceLocations = AnimationLayerRegistry.getAnimLayers().keySet();
|
||||
if(layer == null) resourceLocations = AnimationRegistry.getLayers().keySet();
|
||||
else resourceLocations.add(layer);
|
||||
for (ResourceLocation location : resourceLocations) {
|
||||
ModifierLayer<IAnimation> animationModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||
|
|
@ -177,25 +199,55 @@ public class AnimationUtils {
|
|||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if layer exist animation which is not end.
|
||||
* <p>
|
||||
* Only in dist client
|
||||
* @param player Target player
|
||||
* @param layer Target layer
|
||||
* @return True when animation is loop, or currentTick not larger than endTick
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
@SuppressWarnings("unchecked")
|
||||
public static boolean isClientAnimationNotEnd(AbstractClientPlayer player, @Nullable ResourceLocation layer) {
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> {
|
||||
try {
|
||||
Set<ResourceLocation> resourceLocations = new HashSet<>();
|
||||
if(layer == null) resourceLocations = AnimationRegistry.getLayers().keySet();
|
||||
else resourceLocations.add(layer);
|
||||
for (ResourceLocation location : resourceLocations) {
|
||||
ModifierLayer<IAnimation> animationModifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||
.getPlayerAssociatedData(player).get(location);
|
||||
if(animationModifierLayer == null) continue;
|
||||
KeyframeAnimationPlayer animation = (KeyframeAnimationPlayer) animationModifierLayer.getAnimation();
|
||||
if(animation == null) return false;
|
||||
int currentTick = animation.getCurrentTick();
|
||||
boolean isLoop = animation.getData().isInfinite;
|
||||
int endTick = animation.getData().endTick;
|
||||
return isLoop || currentTick <= endTick;
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
return false;
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync animation tick to client
|
||||
* @param player Player
|
||||
* @param target Target player
|
||||
* @param layer Target layer
|
||||
*/
|
||||
public static void syncAnimation(ServerPlayer player, ServerPlayer target, ResourceLocation layer) {
|
||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationPlayer.syncAnimation(player, target, layer));
|
||||
public static void syncAnimation(ServerPlayer player, ServerPlayer target) {
|
||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationPlayer.syncAnimation(player, target));
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync animation tick on client
|
||||
* @param player Player
|
||||
* @param target Target player
|
||||
* @param layer Target layer
|
||||
*/
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void syncAnimation(AbstractClientPlayer player, AbstractClientPlayer target, ResourceLocation layer) {
|
||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationPlayer.syncAnimation(player, target, layer));
|
||||
public static void syncAnimation(AbstractClientPlayer player, AbstractClientPlayer target) {
|
||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationPlayer.syncAnimation(player, target));
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -266,43 +318,34 @@ public class AnimationUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Test if layer exist and has been register.
|
||||
* Test if layer exist and has been invite.
|
||||
* @param layer Target layer
|
||||
* @return If layer exist and has been register
|
||||
* @return If layer exist and has been invite
|
||||
*/
|
||||
public static boolean isAnimationLayerPresent(ResourceLocation layer) {
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> AnimationLayerRegistry.isLayerPresent(layer));
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> AnimationRegistry.getLayers().containsKey(layer));
|
||||
}
|
||||
|
||||
/**
|
||||
* Test if animation exist and has been register.
|
||||
* Test if animation exist and has been invite.
|
||||
* @param location Animation resource location
|
||||
* @return If animation exist and has been register
|
||||
* @return If animation exist and has been invited
|
||||
*/
|
||||
public static boolean isAnimationPresent(ResourceLocation location) {
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> AnimationRegistry.isAnimationPresent(location));
|
||||
return ANIMATION_RUNNER.testLoadedAndCall(() -> AnimationRegistry.getAnimations().containsKey(location));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an animation through static function
|
||||
* @param location Animation resource location
|
||||
* @param animation Animation data
|
||||
* The register handler
|
||||
* @param forgeBus Forge event bus
|
||||
* @param modBus Mod event bus
|
||||
*/
|
||||
public static void registerAnimation(ResourceLocation location, Animation animation) {
|
||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationRegistry.registerAnimation(location, animation));
|
||||
}
|
||||
|
||||
/**
|
||||
* Register an animation layer through static function. <br>
|
||||
* The number is bigger and the priority is higher. <br>
|
||||
* It must run before these events : <br>
|
||||
* {@link net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent} <br>
|
||||
* {@link net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent}
|
||||
* @param location Layer location key
|
||||
* @param priority Layer priority,
|
||||
*/
|
||||
public static void registerAnimationLayer(ResourceLocation location, int priority) {
|
||||
ANIMATION_RUNNER.testLoadedAndRun(() -> AnimationLayerRegistry.registerPlayerAnimation(location, priority));
|
||||
public static void register(IEventBus forgeBus, IEventBus modBus){
|
||||
AnimationUtils.ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||
AnimationCapabilities.registerAnimationCapability();
|
||||
AnimationChannels.registerChannel();
|
||||
});
|
||||
AnimationUtils.ANIMATION_RUNNER.testLoadedAndAddListener(forgeBus, modBus);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -314,7 +357,7 @@ public class AnimationUtils {
|
|||
*/
|
||||
@Nullable
|
||||
public static Animation getAnimation(ResourceLocation location) {
|
||||
return AnimationRegistry.getAnimation(location);
|
||||
return AnimationRegistry.getAnimations().getOrDefault(location, null);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -377,11 +420,13 @@ public class AnimationUtils {
|
|||
IAnimationCapability data = AnimationDataCapability.getCapability(clientPlayer).orElse(null);
|
||||
if(data == null) return;
|
||||
Set<ResourceLocation> oldLayers = new HashSet<>(data.getAnimations().keySet());
|
||||
oldLayers.forEach(layer -> {
|
||||
if (isClientAnimationPlaying(clientPlayer, layer)) {
|
||||
boolean dirty = false;
|
||||
for (ResourceLocation layer : Set.copyOf(oldLayers)) {
|
||||
if (!isClientAnimationNotStop(clientPlayer, layer)) {
|
||||
oldLayers.remove(layer);
|
||||
dirty = true;
|
||||
}
|
||||
});
|
||||
ModChannel.sendToServer(new RefreshAnimationPacket(oldLayers));
|
||||
}
|
||||
if(dirty) ModChannel.sendToServer(new RefreshAnimationPacket(oldLayers));
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,8 +3,8 @@ package com.linearpast.sccore.animation.capability;
|
|||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||
import com.linearpast.sccore.animation.event.AnimationLayerRegistry;
|
||||
import com.linearpast.sccore.animation.network.toclient.AnimationCapabilityPacket;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||
import com.linearpast.sccore.capability.data.ICapabilitySync;
|
||||
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
||||
|
|
@ -12,6 +12,7 @@ import com.linearpast.sccore.capability.network.SimpleCapabilityPacket;
|
|||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
|
|
@ -23,15 +24,20 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
|||
|
||||
public static final String AnimMap = "AnimMap";
|
||||
public static final String RideAnimLayer = "RideAnimLayer";
|
||||
public static final String RideAnimation = "RideAnimation";
|
||||
|
||||
private final Map<ResourceLocation, ResourceLocation> animMap = new HashMap<>();
|
||||
private ResourceLocation rideAnimLayer;
|
||||
private ResourceLocation rideAnimation;
|
||||
|
||||
@Override
|
||||
public void mergeAnimations(Map<ResourceLocation, ResourceLocation> animations) {
|
||||
animations.forEach((key, value) -> {
|
||||
if (AnimationLayerRegistry.getAnimLayers().containsKey(key)) {
|
||||
if (AnimationRegistry.getLayers().containsKey(key)) {
|
||||
if (AnimationUtils.isAnimationPresent(value)) {
|
||||
if(this.rideAnimLayer.equals(key)) {
|
||||
removeRiderAnimation();
|
||||
}
|
||||
this.animMap.put(key, value);
|
||||
setDirty(true);
|
||||
}
|
||||
|
|
@ -41,8 +47,11 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
|||
|
||||
@Override
|
||||
public boolean mergeAnimation(ResourceLocation layer, ResourceLocation animation) {
|
||||
if (AnimationLayerRegistry.getAnimLayers().containsKey(layer)) {
|
||||
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
||||
if (AnimationUtils.isAnimationPresent(animation)) {
|
||||
if(this.rideAnimLayer.equals(layer)) {
|
||||
removeRiderAnimation();
|
||||
}
|
||||
this.animMap.put(layer, animation);
|
||||
setDirty(true);
|
||||
return true;
|
||||
|
|
@ -84,14 +93,34 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
|||
}
|
||||
|
||||
@Override
|
||||
public void setRideAnimLayer(ResourceLocation rideAnimLayer) {
|
||||
this.rideAnimLayer = rideAnimLayer;
|
||||
setDirty(true);
|
||||
public ResourceLocation getRiderAnimLayer() {
|
||||
return rideAnimLayer;
|
||||
}
|
||||
|
||||
@Override
|
||||
public ResourceLocation getRideAnimLayer() {
|
||||
return rideAnimLayer;
|
||||
public ResourceLocation getRiderAnimation() {
|
||||
return rideAnimation;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRiderAnimation(@NotNull ResourceLocation layer, @NotNull ResourceLocation animation) {
|
||||
if(AnimationUtils.isAnimationLayerPresent(layer)) {
|
||||
if(AnimationUtils.isAnimationPresent(animation)) {
|
||||
this.rideAnimLayer = layer;
|
||||
this.rideAnimation = animation;
|
||||
if(animMap.get(layer) != null) {
|
||||
animMap.remove(layer);
|
||||
}
|
||||
setDirty(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void removeRiderAnimation() {
|
||||
this.rideAnimLayer = null;
|
||||
this.rideAnimation = null;
|
||||
setDirty(true);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -99,6 +128,8 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
|||
IAnimationCapability data = (IAnimationCapability) oldData;
|
||||
this.animMap.clear();
|
||||
this.animMap.putAll(data.getAnimations());
|
||||
this.rideAnimLayer = data.getRiderAnimLayer();
|
||||
this.rideAnimation = data.getRiderAnimation();
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -111,12 +142,15 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
|||
tag.put(AnimMap, animMapTag);
|
||||
}
|
||||
if(rideAnimLayer != null) tag.putString(RideAnimLayer, rideAnimLayer.toString());
|
||||
if(rideAnimation != null) tag.putString(RideAnimation, rideAnimation.toString());
|
||||
return tag;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void fromTag(CompoundTag tag) {
|
||||
this.animMap.clear();
|
||||
this.rideAnimLayer = null;
|
||||
this.rideAnimation = null;
|
||||
if(tag.contains(AnimMap)) {
|
||||
CompoundTag animMapTag = tag.getCompound(AnimMap);
|
||||
animMapTag.getAllKeys().forEach(key -> this.animMap.put(
|
||||
|
|
@ -125,6 +159,7 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
|||
));
|
||||
}
|
||||
if(tag.contains(RideAnimLayer)) this.rideAnimLayer = new ResourceLocation(tag.getString(RideAnimLayer));
|
||||
if(tag.contains(RideAnimation)) this.rideAnimation = new ResourceLocation(tag.getString(RideAnimation));
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -138,9 +173,10 @@ public class AnimationDataCapability extends SimplePlayerCapabilitySync implemen
|
|||
map.forEach((key, value) -> {
|
||||
if(!AnimationUtils.isAnimationLayerPresent(key)) this.animMap.remove(key);
|
||||
if(!AnimationUtils.isAnimationPresent(value)) this.animMap.remove(key);
|
||||
if(key.equals(rideAnimLayer)) this.animMap.remove(key);
|
||||
});
|
||||
this.rideAnimLayer = null;
|
||||
if(rideAnimLayer != null && !AnimationUtils.isAnimationLayerPresent(rideAnimLayer)) {
|
||||
removeRiderAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
public static Optional<IAnimationCapability> getCapability(Player player){
|
||||
|
|
|
|||
|
|
@ -16,6 +16,8 @@ public interface IAnimationCapability extends ICapabilitySync<Player> {
|
|||
void clearAnimations();
|
||||
boolean isAnimationPresent(ResourceLocation layer);
|
||||
|
||||
void setRideAnimLayer(ResourceLocation layer);
|
||||
ResourceLocation getRideAnimLayer();
|
||||
ResourceLocation getRiderAnimLayer();
|
||||
ResourceLocation getRiderAnimation();
|
||||
void setRiderAnimation(ResourceLocation layer, ResourceLocation animation);
|
||||
void removeRiderAnimation();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,191 @@
|
|||
package com.linearpast.sccore.animation.command;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class ApplyJoinAnimCommand {
|
||||
private static final Map<UUID, Map<UUID, ApplyRecord>> applies = new HashMap<>();
|
||||
record ApplyRecord(long time, boolean isForce){}
|
||||
private static final Map<UUID, Long> lastAppliedMap = new HashMap<>();
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||
animCommand
|
||||
.then(literal("joinApply")
|
||||
.then(argument("target", EntityArgument.player())
|
||||
.executes(ApplyJoinAnimCommand::tryJoinAnimation)
|
||||
.then(argument("force", BoolArgumentType.bool())
|
||||
.executes(ApplyJoinAnimCommand::tryJoinAnimation)
|
||||
)
|
||||
)
|
||||
.then(literal("accept")
|
||||
.then(argument("player", EntityArgument.player())
|
||||
.executes(ApplyJoinAnimCommand::acceptJoinAnimation)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int tryJoinAnimation(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
boolean force = false;
|
||||
try {force = BoolArgumentType.getBool(context, "force");}
|
||||
catch (Exception ignored) {}
|
||||
ServerPlayer target = EntityArgument.getPlayer(context, "target");
|
||||
ServerPlayer player;
|
||||
try {player = EntityArgument.getPlayer(context, "player");}
|
||||
catch (Exception e) { player = source.getPlayerOrException(); }
|
||||
|
||||
Entity vehicle = target.getVehicle();
|
||||
if(!(vehicle instanceof AnimationRideEntity rideEntity) || !rideEntity.canAddPassenger(player)) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.WITHOUT_ANIMATION_RIDE_ENTITY.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//cooldown
|
||||
Long lastApplied = lastAppliedMap.getOrDefault(player.getUUID(), null);
|
||||
long now = System.currentTimeMillis();
|
||||
int applyCooldown = ModConfigs.Server.applyCooldown.get() * 1000;
|
||||
if(!(lastApplied == null || now - lastApplied > applyCooldown)) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_COOLDOWN.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
lastAppliedMap.put(player.getUUID(), now);
|
||||
|
||||
UUID rideEntityUUID = rideEntity.getUUID();
|
||||
Map<UUID, ApplyRecord> applyRecordMap = applies.getOrDefault(rideEntityUUID, new HashMap<>());
|
||||
applyRecordMap.put(player.getUUID(), new ApplyRecord(now, force));
|
||||
applies.put(rideEntityUUID, applyRecordMap);
|
||||
|
||||
//click event
|
||||
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim joinApply accept " + player.getName().getString())
|
||||
).withUnderlined(true);
|
||||
|
||||
//send message to all participants
|
||||
for (Entity passenger : rideEntity.getPassengers()) {
|
||||
passenger.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.APPLIED_JOIN_MESSAGE.getKey(),
|
||||
player.getName().copy()
|
||||
).append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
||||
).setStyle(pStyle)));
|
||||
}
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.APPLY_JOIN_MESSAGE.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int acceptJoinAnimation(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer target = source.getPlayerOrException();
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "player");
|
||||
if(!(target.getVehicle() instanceof AnimationRideEntity rideEntity) || !rideEntity.canAddPassenger(player)) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.WITHOUT_ANIMATION_RIDE_ENTITY.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
|
||||
Map<UUID, ApplyRecord> applyRecordMap = applies.getOrDefault(rideEntity.getUUID(), null);
|
||||
if(applyRecordMap == null) throw new Exception();
|
||||
ApplyRecord applyRecord = applyRecordMap.getOrDefault(player.getUUID(), null);
|
||||
|
||||
//test if expired
|
||||
long now = System.currentTimeMillis();
|
||||
Integer applyDuration = ModConfigs.Server.applyDuration.get();
|
||||
if(now - applyRecord.time > applyDuration * 1000 || applyDuration == 0) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_APPLY_EXPIRED.getKey(),
|
||||
applyDuration
|
||||
).withStyle(ChatFormatting.RED));
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.APPLY_EXPIRED.getKey(),
|
||||
target.getName().copy(),
|
||||
applyDuration
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//test if in range
|
||||
Integer applyDistance = ModConfigs.Server.applyDistance.get();
|
||||
if(player.position().distanceToSqr(rideEntity.position()) > applyDistance * applyDistance || applyDistance == 0) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_APPLY_TOO_FAR.getKey(),
|
||||
applyDistance
|
||||
).withStyle(ChatFormatting.RED));
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.APPLY_TOO_FAR.getKey(),
|
||||
target.getName().copy(),
|
||||
applyDistance
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
applyRecordMap.remove(player.getUUID());
|
||||
applies.put(player.getUUID(), applyRecordMap);
|
||||
|
||||
//define message
|
||||
MutableComponent successMessage = Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_APPLY_SUCCESS.getKey(),
|
||||
target.getName().copy(),
|
||||
player.getName().copy()
|
||||
).withStyle(ChatFormatting.GREEN);
|
||||
|
||||
//play
|
||||
AnimationUtils.joinAnimation(player, target, applyRecord.isForce);
|
||||
|
||||
//send message
|
||||
source.sendSuccess(() -> successMessage, true);
|
||||
for (Entity passenger : rideEntity.getPassengers()) {
|
||||
if(!passenger.getUUID().equals(target.getUUID()) && !passenger.getUUID().equals(player.getUUID())) {
|
||||
passenger.sendSystemMessage(successMessage);
|
||||
}
|
||||
}
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.APPLY_SUCCESS.getKey(),
|
||||
target.getName().copy()
|
||||
).withStyle(ChatFormatting.GREEN));
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,178 @@
|
|||
package com.linearpast.sccore.animation.command;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class CombineAnimCommand {
|
||||
private static final Map<UUID, Long> lastInvitedMap = new HashMap<>();
|
||||
record InviteRecord(long time, ResourceLocation layer, ResourceLocation animation, boolean isForce){}
|
||||
private static final Map<UUID, Map<UUID, InviteRecord>> invites = new HashMap<>();
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||
animCommand.then(literal("invite")
|
||||
.then(argument("player", EntityArgument.player())
|
||||
.then(argument("layer", AnimationLayerArgument.layer())
|
||||
.then(argument("anim", AnimationArgument.animation())
|
||||
.executes(CombineAnimCommand::invite)
|
||||
.then(argument("force", BoolArgumentType.bool())
|
||||
.executes(CombineAnimCommand::invite)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(literal("accept")
|
||||
.then(argument("player", EntityArgument.player())
|
||||
.executes(CombineAnimCommand::acceptInvite)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int invite(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
//get info
|
||||
boolean force = false;
|
||||
try {force = BoolArgumentType.getBool(context, "force");}
|
||||
catch (Exception ignored) {}
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
||||
|
||||
//cooldown
|
||||
Long lastInvited = lastInvitedMap.getOrDefault(player.getUUID(), null);
|
||||
long now = System.currentTimeMillis();
|
||||
int inviteCooldown = ModConfigs.Server.inviteCooldown.get() * 1000;
|
||||
if(!(lastInvited == null || now - lastInvited > inviteCooldown)) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_COOLDOWN.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
lastInvitedMap.put(player.getUUID(), now);
|
||||
|
||||
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
||||
String animString = AnimationArgument.getAnimation(context, "anim");
|
||||
ResourceLocation layer = new ResourceLocation(layerString);
|
||||
ResourceLocation anim = new ResourceLocation(animString);
|
||||
|
||||
//test info present
|
||||
boolean animationPresent = AnimationUtils.isAnimationPresent(anim);
|
||||
boolean animationLayerPresent = AnimationUtils.isAnimationLayerPresent(layer);
|
||||
if(!animationLayerPresent || !animationPresent) throw new Exception();
|
||||
|
||||
//update static cache
|
||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), new HashMap<>());
|
||||
inviteRecordMap.put(target.getUUID(), new InviteRecord(System.currentTimeMillis(), layer, anim, force));
|
||||
invites.put(player.getUUID(), inviteRecordMap);
|
||||
|
||||
//click event
|
||||
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim invite accept " + player.getName().getString())
|
||||
).withUnderlined(true);
|
||||
//send message
|
||||
target.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.INVITED_MESSAGE.getKey(),
|
||||
player.getName().copy(),
|
||||
anim.toString()
|
||||
).append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
||||
).setStyle(pStyle)));
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.INVITE_MESSAGE.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int acceptInvite(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer target = source.getPlayerOrException();
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "player");
|
||||
|
||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), null);
|
||||
if(inviteRecordMap == null) throw new Exception();
|
||||
InviteRecord inviteRecord = inviteRecordMap.getOrDefault(target.getUUID(), null);
|
||||
if(inviteRecord == null) throw new Exception();
|
||||
|
||||
//test if expired
|
||||
long now = System.currentTimeMillis();
|
||||
Integer inviteDuration = ModConfigs.Server.inviteDuration.get();
|
||||
if(now - inviteRecord.time > inviteDuration * 1000 || inviteDuration == 0) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_INVITE_EXPIRED.getKey(),
|
||||
inviteDuration
|
||||
).withStyle(ChatFormatting.RED));
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.INVITE_EXPIRED.getKey(),
|
||||
target.getName().copy(),
|
||||
inviteDuration
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//test if in range
|
||||
Integer inviteDistance = ModConfigs.Server.inviteDistance.get();
|
||||
if(player.position().distanceToSqr(target.position()) > inviteDistance * inviteDistance || inviteDistance == 0) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_INVITE_TOO_FAR.getKey(),
|
||||
inviteDistance
|
||||
).withStyle(ChatFormatting.RED));
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.INVITE_TOO_FAR.getKey(),
|
||||
target.getName().copy(),
|
||||
inviteDistance
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
inviteRecordMap.remove(target.getUUID());
|
||||
invites.put(player.getUUID(), inviteRecordMap);
|
||||
|
||||
//play animation
|
||||
AnimationUtils.startAnimationTogether(player, inviteRecord.layer, inviteRecord.animation, inviteRecord.isForce, target);
|
||||
|
||||
//send message
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_INVITE_SUCCESS.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.INVITE_SUCCESS.getKey(),
|
||||
target.getName().copy()
|
||||
).withStyle(ChatFormatting.GREEN));
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,168 @@
|
|||
package com.linearpast.sccore.animation.command;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Comparator;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class GenerateJsonCommand {
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||
animCommand.then(literal("json").requires(cs -> cs.hasPermission(2))
|
||||
.then(literal("clearFile").executes(GenerateJsonCommand::clearJson))
|
||||
.then(literal("generate")
|
||||
.then(literal("anim")
|
||||
.then(literal("example").executes(GenerateJsonCommand::generateExample))
|
||||
.executes(context -> generateJson(context, false, false))
|
||||
.then(argument("reset", BoolArgumentType.bool())
|
||||
.executes(context ->
|
||||
generateJson(context, false, BoolArgumentType.getBool(context, "reset"))
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(literal("layer")
|
||||
.executes(context -> generateJson(context, true, false))
|
||||
.then(argument("reset", BoolArgumentType.bool())
|
||||
.executes(context ->
|
||||
generateJson(context, true, BoolArgumentType.getBool(context, "reset"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
//clear path, remove file.
|
||||
private static void clearPath(Path dir) throws IOException {
|
||||
if (!Files.exists(dir)) return;
|
||||
try (var pathStream = Files.walk(dir)) {
|
||||
pathStream.sorted(Comparator.reverseOrder()).forEach(path -> {
|
||||
try {
|
||||
Files.delete(path);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (RuntimeException ignored) {}
|
||||
}
|
||||
|
||||
private static int generateJson(CommandContext<CommandSourceStack> context, boolean isLayer, boolean isReset) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
//get animation path
|
||||
Path animationPath = getAnimationPath(source);
|
||||
if (!Files.exists(animationPath)) {
|
||||
try {Files.createDirectories(animationPath);}
|
||||
catch (IOException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
if(isReset) clearPath(animationPath);
|
||||
|
||||
//generate json layer or animation
|
||||
if(isLayer) {
|
||||
//generate
|
||||
Path path = AnimLayerJson.Writer.syntaxImmediately(animationPath);
|
||||
//send message
|
||||
MutableComponent component = Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
||||
"layer", "Server"
|
||||
).withStyle(ChatFormatting.GREEN);
|
||||
component.append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
||||
path.toString()
|
||||
));
|
||||
source.sendSuccess(() -> component, true);
|
||||
} else {
|
||||
//generate
|
||||
for (Animation value : AnimationRegistry.getAnimations().values()) {
|
||||
AnimJson.Writer.stream(animationPath, value).syntax();
|
||||
}
|
||||
//send message
|
||||
MutableComponent component = Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
||||
"anim", "Server"
|
||||
).withStyle(ChatFormatting.GREEN);
|
||||
component.append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
||||
animationPath.toString()
|
||||
));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int clearJson(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
//clear path
|
||||
Path animationPath = getAnimationPath(source);
|
||||
clearPath(animationPath);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int generateExample(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
//generate
|
||||
Path animationPath = getAnimationPath(source);
|
||||
Path path = AnimJson.Writer.syntaxExample(animationPath);
|
||||
//send message
|
||||
MutableComponent component = Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
||||
"anim example", "Server"
|
||||
).withStyle(ChatFormatting.GREEN);
|
||||
component.append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
||||
path.toString()
|
||||
));
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get animation path
|
||||
* @param source command source
|
||||
* @return path
|
||||
*/
|
||||
private static Path getAnimationPath(CommandSourceStack source) {
|
||||
MinecraftServer server = source.getServer();
|
||||
Path dataPackPath = server.getWorldPath(LevelResource.DATAPACK_DIR);
|
||||
return dataPackPath.resolve("animation");
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,258 @@
|
|||
package com.linearpast.sccore.animation.command;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.builder.RequiredArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class PlayAnimCommand {
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand){
|
||||
RequiredArgumentBuilder<CommandSourceStack, String> animCommandParam = argument("layer", AnimationLayerArgument.layer())
|
||||
.then(argument("animation", AnimationArgument.animation())
|
||||
.executes(context -> playAnimation(context, false))
|
||||
.then(argument("withRide", BoolArgumentType.bool())
|
||||
.executes(context -> playAnimation(
|
||||
context, BoolArgumentType.getBool(context, "withRide")
|
||||
))
|
||||
.then(argument("forced", BoolArgumentType.bool())
|
||||
.executes(context -> playAnimation(
|
||||
context, BoolArgumentType.getBool(context, "withRide"))
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
animCommand
|
||||
.then(literal("playSelf")
|
||||
.then(animCommandParam))
|
||||
.then(literal("play")
|
||||
.then(argument("players", EntityArgument.players())
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.then(animCommandParam)
|
||||
))
|
||||
.then(literal("remove")
|
||||
.executes(PlayAnimCommand::clearAnimation)
|
||||
.then(argument("players", EntityArgument.players())
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.executes(PlayAnimCommand::clearAnimation)
|
||||
.then(argument("layer", AnimationLayerArgument.layer())
|
||||
.executes(PlayAnimCommand::removeAnimation)
|
||||
)
|
||||
)
|
||||
.then(argument("layer", AnimationLayerArgument.layer())
|
||||
.executes(PlayAnimCommand::removeAnimation)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int playAnimation(CommandContext<CommandSourceStack> context, boolean withRide) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> players = null;
|
||||
ServerPlayer player = null;
|
||||
try {players = EntityArgument.getPlayers(context, "players");}
|
||||
catch (Exception ignored) { player = source.getPlayerOrException(); }
|
||||
String animation = AnimationArgument.getAnimation(context, "animation");
|
||||
String layer = AnimationLayerArgument.getLayer(context, "layer");
|
||||
ResourceLocation layerLocation = new ResourceLocation(layer);
|
||||
ResourceLocation animLocation = new ResourceLocation(animation);
|
||||
boolean animationPresent = AnimationUtils.isAnimationPresent(animLocation);
|
||||
boolean layerPresent = AnimationUtils.isAnimationLayerPresent(layerLocation);
|
||||
if(!animationPresent) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_NOT_PRESENT.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
if(!layerPresent) {
|
||||
source.sendFailure(Component.literal(
|
||||
ModLang.TranslatableMessage.ANIMATION_LAYER_NOT_PRESENT.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//play with players
|
||||
if(players != null) {
|
||||
Set<ServerPlayer> playerSet = Set.copyOf(players);
|
||||
Collection<ServerPlayer> finalPlayers = players;
|
||||
playerSet.forEach(p -> {
|
||||
if(withRide) {
|
||||
boolean forced = false;
|
||||
try { forced = BoolArgumentType.getBool(context, "forced");}
|
||||
catch (Exception ignored) {}
|
||||
if(AnimationUtils.playAnimationWithRide(p, layerLocation, animLocation, forced)) {
|
||||
finalPlayers.remove(p);
|
||||
}
|
||||
} else {
|
||||
if (AnimationUtils.playAnimation(p, layerLocation, animLocation)) {
|
||||
finalPlayers.remove(p);
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
int successNum = playerSet.size() - players.size();
|
||||
if(successNum > 0) {
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.PLAY_ANIMATION_SUCCESS.getKey(),
|
||||
successNum
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
}
|
||||
List<ServerPlayer> list = players.stream().toList();
|
||||
if(!list.isEmpty()) {
|
||||
MutableComponent failPlayers = Component.literal("");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
failPlayers.append(list.get(i).getName().copy());
|
||||
if (i < list.size() - 1) {
|
||||
failPlayers.append(", ");
|
||||
}
|
||||
}
|
||||
failPlayers.append(".");
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.PLAY_ANIMATION_FAIL.getKey(),
|
||||
failPlayers
|
||||
).withStyle(ChatFormatting.RED));
|
||||
}
|
||||
}
|
||||
|
||||
//play with self
|
||||
if(player != null) {
|
||||
if(withRide) {
|
||||
boolean forced = false;
|
||||
try { forced = BoolArgumentType.getBool(context, "forced");}
|
||||
catch (Exception ignored) {}
|
||||
AnimationUtils.playAnimationWithRide(player, layerLocation, animLocation, forced);
|
||||
} else {
|
||||
AnimationUtils.playAnimation(player, layerLocation, animLocation);
|
||||
}
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int removeAnimation(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> players = null;
|
||||
ServerPlayer player = null;
|
||||
try {players = EntityArgument.getPlayers(context, "players");}
|
||||
catch (Exception ignored) { player = source.getPlayerOrException(); }
|
||||
String layer = AnimationLayerArgument.getLayer(context, "layer");
|
||||
ResourceLocation layerLocation = new ResourceLocation(layer);
|
||||
boolean layerPresent = AnimationUtils.isAnimationLayerPresent(layerLocation);
|
||||
if(!layerPresent) {
|
||||
source.sendFailure(Component.literal(
|
||||
ModLang.TranslatableMessage.ANIMATION_LAYER_NOT_PRESENT.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
|
||||
//remove with players
|
||||
if(players != null) {
|
||||
Set<ServerPlayer> playerSet = Set.copyOf(players);
|
||||
Collection<ServerPlayer> finalPlayers = players;
|
||||
playerSet.forEach(p -> {
|
||||
if(p.getVehicle() instanceof AnimationRideEntity rideEntity && rideEntity.getLayer().equals(layerLocation)) {
|
||||
p.unRide();
|
||||
finalPlayers.remove(p);
|
||||
}
|
||||
if (AnimationUtils.removeAnimation(p, layerLocation)) {
|
||||
finalPlayers.remove(p);
|
||||
}
|
||||
});
|
||||
int successNum = playerSet.size() - players.size();
|
||||
if(successNum > 0) {
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.REMOVE_ANIMATION_SUCCESS.getKey(),
|
||||
successNum
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
}
|
||||
List<ServerPlayer> list = players.stream().toList();
|
||||
if(!list.isEmpty()) {
|
||||
MutableComponent failPlayers = Component.literal("");
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
failPlayers.append(list.get(i).getName().copy());
|
||||
if (i < list.size() - 1) {
|
||||
failPlayers.append(", ");
|
||||
}
|
||||
}
|
||||
failPlayers.append(".");
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.REMOVE_ANIMATION_FAIL.getKey(),
|
||||
failPlayers
|
||||
).withStyle(ChatFormatting.RED));
|
||||
}
|
||||
}
|
||||
|
||||
//remove with self
|
||||
if(player != null) {
|
||||
if(player.getVehicle() instanceof AnimationRideEntity rideEntity && rideEntity.getLayer().equals(layerLocation)) {
|
||||
player.unRide();
|
||||
}
|
||||
AnimationUtils.removeAnimation(player, layerLocation);
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int clearAnimation(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> players;
|
||||
try {players = EntityArgument.getPlayers(context, "players");}
|
||||
catch (Exception ignored) { players = Set.of(source.getPlayerOrException()); }
|
||||
Set.copyOf(players).forEach(player -> {
|
||||
if(player.getVehicle() instanceof AnimationRideEntity) {
|
||||
player.unRide();
|
||||
}
|
||||
AnimationUtils.clearAnimation(player);
|
||||
});
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.CLEAR_ANIMATIONS.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,186 +0,0 @@
|
|||
package com.linearpast.sccore.animation.command;
|
||||
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class PlayAnimationCommand {
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand){
|
||||
animCommand.then(literal("play").then(argument("players", EntityArgument.players()).then(
|
||||
argument("layer", AnimationLayerArgument.layer())
|
||||
.then(argument("animation", AnimationArgument.animation())
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.executes(context -> playAnimation(context, false))
|
||||
.then(argument("withRide", BoolArgumentType.bool())
|
||||
.executes(context -> playAnimation(
|
||||
context, BoolArgumentType.getBool(context, "withRide")
|
||||
))
|
||||
.then(argument("forced", BoolArgumentType.bool())
|
||||
.executes(context -> playAnimation(
|
||||
context, BoolArgumentType.getBool(context, "withRide"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)));
|
||||
animCommand.then(literal("remove")
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.executes(PlayAnimationCommand::clearAnimation)
|
||||
.then(argument("players", EntityArgument.players())
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.executes(PlayAnimationCommand::clearAnimation)
|
||||
.then(argument("layer", AnimationLayerArgument.layer())
|
||||
.executes(PlayAnimationCommand::removeAnimation)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int playAnimation(CommandContext<CommandSourceStack> ctx, boolean withRide) {
|
||||
CommandSourceStack source = ctx.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> players = EntityArgument.getPlayers(ctx, "players");
|
||||
String animation = AnimationArgument.getAnimation(ctx, "animation").replace("$", ":");
|
||||
String layer = AnimationLayerArgument.getLayer(ctx, "layer").replace("$", ":");
|
||||
ResourceLocation layerLocation = new ResourceLocation(layer);
|
||||
ResourceLocation animLocation = new ResourceLocation(animation);
|
||||
boolean animationPresent = AnimationUtils.isAnimationPresent(animLocation);
|
||||
boolean layerPresent = AnimationUtils.isAnimationLayerPresent(layerLocation);
|
||||
if(!animationPresent) {
|
||||
source.sendFailure(Component.literal("Animation is not present.").withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
if(!layerPresent) {
|
||||
source.sendFailure(Component.literal("Layer is not present.").withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
Set<ServerPlayer> playerSet = Set.copyOf(players);
|
||||
playerSet.forEach(player -> {
|
||||
if(withRide) {
|
||||
boolean forced = false;
|
||||
try { forced = BoolArgumentType.getBool(ctx, "forced");}
|
||||
catch (Exception ignored) {}
|
||||
if(AnimationUtils.playAnimationWithRide(player, layerLocation, animLocation, forced)) {
|
||||
players.remove(player);
|
||||
}
|
||||
} else {
|
||||
if (AnimationUtils.playAnimation(player, layerLocation, animLocation)) {
|
||||
players.remove(player);
|
||||
}
|
||||
}
|
||||
});
|
||||
MutableComponent fail = Component.literal("Fail to play animation with: ");
|
||||
int successNum = playerSet.size() - players.size();
|
||||
if(successNum > 0) {
|
||||
MutableComponent success = Component.literal("Success to play animation with ")
|
||||
.append(successNum + "")
|
||||
.append(" player");
|
||||
if(successNum > 1) success.append("s.");
|
||||
else success.append(".");
|
||||
source.sendSuccess(() -> success.withStyle(ChatFormatting.GREEN), true);
|
||||
}
|
||||
List<ServerPlayer> list = players.stream().toList();
|
||||
if(!list.isEmpty()) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
fail.append(list.get(i).getName());
|
||||
if (i < list.size() - 1) {
|
||||
fail.append(", ");
|
||||
}
|
||||
}
|
||||
fail.append(".");
|
||||
source.sendFailure(fail.withStyle(ChatFormatting.RED));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.literal("Run command failure.").withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int removeAnimation(CommandContext<CommandSourceStack> ctx) {
|
||||
CommandSourceStack source = ctx.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> players = EntityArgument.getPlayers(ctx, "players");
|
||||
String layer = AnimationLayerArgument.getLayer(ctx, "layer").replace("$", ":");
|
||||
ResourceLocation layerLocation = new ResourceLocation(layer);
|
||||
boolean layerPresent = AnimationUtils.isAnimationLayerPresent(layerLocation);
|
||||
if(!layerPresent) {
|
||||
source.sendFailure(Component.literal("Layer is not present.").withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
Set<ServerPlayer> playerSet = Set.copyOf(players);
|
||||
playerSet.forEach(player -> {
|
||||
if(player.getVehicle() instanceof AnimationRideEntity rideEntity && rideEntity.getLayer().equals(layerLocation)) {
|
||||
player.unRide();
|
||||
players.remove(player);
|
||||
}
|
||||
if (AnimationUtils.removeAnimation(player, layerLocation)) {
|
||||
players.remove(player);
|
||||
}
|
||||
});
|
||||
MutableComponent fail = Component.literal("Fail to remove animation with: ");
|
||||
int successNum = playerSet.size() - players.size();
|
||||
if(successNum > 0) {
|
||||
MutableComponent success = Component.literal("Success to remove animation with ")
|
||||
.append(successNum + "")
|
||||
.append(" player");
|
||||
if(successNum > 1) success.append("s.");
|
||||
else success.append(".");
|
||||
source.sendSuccess(() -> success.withStyle(ChatFormatting.GREEN), true);
|
||||
}
|
||||
List<ServerPlayer> list = players.stream().toList();
|
||||
if(!list.isEmpty()) {
|
||||
for (int i = 0; i < list.size(); i++) {
|
||||
fail.append(list.get(i).getName());
|
||||
if (i < list.size() - 1) {
|
||||
fail.append(", ");
|
||||
}
|
||||
}
|
||||
fail.append(".");
|
||||
source.sendFailure(fail.withStyle(ChatFormatting.RED));
|
||||
}
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.literal("Run command failure.").withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int clearAnimation(CommandContext<CommandSourceStack> ctx) {
|
||||
CommandSourceStack source = ctx.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> players;
|
||||
try {players = EntityArgument.getPlayers(ctx, "players");}
|
||||
catch (Exception ignored) { players = Set.of(source.getPlayerOrException()); }
|
||||
Set.copyOf(players).forEach(player -> {
|
||||
if(player.getVehicle() instanceof AnimationRideEntity) {
|
||||
player.unRide();
|
||||
}
|
||||
AnimationUtils.clearAnimation(player);
|
||||
});
|
||||
source.sendSuccess(() -> Component.literal("Animation cleared.").withStyle(ChatFormatting.GREEN), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.literal("Run command failure.").withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
package com.linearpast.sccore.animation.command;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||
import com.linearpast.sccore.core.configs.ModConfigs;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.Style;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.UUID;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
/**
|
||||
* Request target player play animation.
|
||||
*/
|
||||
public class RequestAnimCommand {
|
||||
private static final Map<UUID, Long> lastRequestedMap = new HashMap<>();
|
||||
record InviteRecord(long time, ResourceLocation layer, ResourceLocation animation, boolean withRide, boolean isForce) {}
|
||||
private static final Map<UUID, Map<UUID, InviteRecord>> invites = new HashMap<>();
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||
animCommand.then(literal("request")
|
||||
.then(argument("player", EntityArgument.player()).then(
|
||||
argument("layer", AnimationLayerArgument.layer())
|
||||
.then(argument("animation", AnimationArgument.animation())
|
||||
.requires(cs -> cs.hasPermission(2))
|
||||
.executes(context -> invite(context, false))
|
||||
.then(argument("withRide", BoolArgumentType.bool())
|
||||
.executes(context -> invite(
|
||||
context, BoolArgumentType.getBool(context, "withRide")
|
||||
))
|
||||
.then(argument("forced", BoolArgumentType.bool())
|
||||
.executes(context -> invite(
|
||||
context, BoolArgumentType.getBool(context, "withRide"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
))
|
||||
.then(literal("accept")
|
||||
.then(argument("player", EntityArgument.player())
|
||||
.executes(RequestAnimCommand::accept)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static int invite(CommandContext<CommandSourceStack> context, boolean withRide) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
//get info
|
||||
boolean force = false;
|
||||
try {
|
||||
force = BoolArgumentType.getBool(context, "force");
|
||||
} catch (Exception ignored) {}
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
ServerPlayer target = EntityArgument.getPlayer(context, "player");
|
||||
|
||||
//cooldown
|
||||
Long lastRequested = lastRequestedMap.getOrDefault(player.getUUID(), null);
|
||||
long now = System.currentTimeMillis();
|
||||
int requestCooldown = ModConfigs.Server.requestCooldown.get() * 1000;
|
||||
if(!(lastRequested == null || now - lastRequested > requestCooldown)) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_COOLDOWN.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
lastRequestedMap.put(player.getUUID(), now);
|
||||
|
||||
String layerString = AnimationLayerArgument.getLayer(context, "layer");
|
||||
String animString = AnimationArgument.getAnimation(context, "animation");
|
||||
ResourceLocation layer = new ResourceLocation(layerString);
|
||||
ResourceLocation anim = new ResourceLocation(animString);
|
||||
|
||||
//test info present
|
||||
boolean animationPresent = AnimationUtils.isAnimationPresent(anim);
|
||||
boolean animationLayerPresent = AnimationUtils.isAnimationLayerPresent(layer);
|
||||
if(!animationLayerPresent || !animationPresent) throw new Exception();
|
||||
|
||||
//update static cache
|
||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), new HashMap<>());
|
||||
inviteRecordMap.put(target.getUUID(), new InviteRecord(System.currentTimeMillis(), layer, anim, force, withRide));
|
||||
invites.put(player.getUUID(), inviteRecordMap);
|
||||
|
||||
//click event
|
||||
Style pStyle = Style.EMPTY.withBold(true).withColor(ChatFormatting.GREEN).withClickEvent(
|
||||
new ClickEvent(ClickEvent.Action.RUN_COMMAND, "/sccore anim request accept " + player.getName().getString())
|
||||
).withUnderlined(true);
|
||||
|
||||
//send message
|
||||
target.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.REQUESTED_MESSAGE.getKey(),
|
||||
player.getName().copy(),
|
||||
anim.toString()
|
||||
).append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_MESSAGE_CLICK.getKey()
|
||||
).setStyle(pStyle)));
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.REQUEST_MESSAGE.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int accept(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer target = source.getPlayerOrException();
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "player");
|
||||
|
||||
//get request record and test
|
||||
Map<UUID, InviteRecord> inviteRecordMap = invites.getOrDefault(player.getUUID(), null);
|
||||
if(inviteRecordMap == null) throw new Exception();
|
||||
InviteRecord inviteRecord = inviteRecordMap.getOrDefault(target.getUUID(), null);
|
||||
if(inviteRecord == null) throw new Exception();
|
||||
long now = System.currentTimeMillis();
|
||||
Integer requestDuration = ModConfigs.Server.requestDuration.get();
|
||||
|
||||
//test if expired
|
||||
if(now - inviteRecord.time > requestDuration * 1000 || requestDuration == 0) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_REQUEST_EXPIRED.getKey(),
|
||||
requestDuration
|
||||
).withStyle(ChatFormatting.RED));
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.REQUEST_EXPIRED.getKey(),
|
||||
target.getName().copy(),
|
||||
requestDuration
|
||||
).withStyle(ChatFormatting.RED));
|
||||
return 0;
|
||||
}
|
||||
inviteRecordMap.remove(target.getUUID());
|
||||
invites.put(player.getUUID(), inviteRecordMap);
|
||||
boolean withRide = inviteRecord.withRide;
|
||||
|
||||
//play
|
||||
if(withRide) {
|
||||
AnimationUtils.playAnimationWithRide(target, inviteRecord.layer, inviteRecord.animation, inviteRecord.isForce);
|
||||
}else {
|
||||
AnimationUtils.playAnimation(target, inviteRecord.layer, inviteRecord.animation);
|
||||
}
|
||||
|
||||
//send message
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.ACCEPT_REQUEST_SUCCESS.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
player.sendSystemMessage(Component.translatable(
|
||||
ModLang.TranslatableMessage.REQUEST_SUCCESS.getKey(),
|
||||
target.getName().copy()
|
||||
).withStyle(ChatFormatting.GREEN));
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,7 @@
|
|||
package com.linearpast.sccore.animation.command.argument;
|
||||
|
||||
import com.linearpast.sccore.animation.registry.AnimationRegistry;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
|
@ -12,36 +13,61 @@ import net.minecraft.commands.CommandSourceStack;
|
|||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.HashSet;
|
||||
import java.util.Objects;
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AnimationArgument implements ArgumentType<String> {
|
||||
private static final Supplier<Collection<String>> EXAMPLES = () -> AnimationRegistry.getAnimations().keySet().stream()
|
||||
.map(ResourceLocation::toString).collect(Collectors.toSet());
|
||||
private static final Supplier<Collection<String>> EXAMPLES = AnimationArgument::getAnimationNames;
|
||||
private static final DynamicCommandExceptionType UNKNOWN_TYPE = new DynamicCommandExceptionType(
|
||||
animation -> Component.literal("Unknow animation : " + animation.toString())
|
||||
);
|
||||
|
||||
private final Set<String> animationNames;
|
||||
private final Supplier<Set<String>> animationNames;
|
||||
public AnimationArgument() {
|
||||
this.animationNames = AnimationRegistry.getAnimations().keySet().stream()
|
||||
.map(ResourceLocation::toString).collect(Collectors.toSet());
|
||||
this.animationNames = AnimationArgument::getAnimationNames;
|
||||
}
|
||||
|
||||
private static Set<String> getAnimationNames(){
|
||||
HashSet<String> set = new HashSet<>();
|
||||
AnimationRegistry.getAnimations().forEach((key, value) -> {
|
||||
String name = value.getName();
|
||||
if(name != null && !set.contains(name)) {
|
||||
set.add(name);
|
||||
} else set.add(key.toString());
|
||||
});
|
||||
return set;
|
||||
}
|
||||
|
||||
public static AnimationArgument animation() {
|
||||
return new AnimationArgument();
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static ResourceLocation getAnimationByName(String name) {
|
||||
for (Animation animation : AnimationRegistry.getAnimations().values()) {
|
||||
if (Objects.equals(animation.getName(), name)) {
|
||||
return animation.getKey();
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
public static String getAnimation(CommandContext<CommandSourceStack> context, String name) {
|
||||
return context.getArgument(name, String.class);
|
||||
String argument = context.getArgument(name, String.class);
|
||||
if(argument.contains(":")) return argument;
|
||||
ResourceLocation animationByName = getAnimationByName(argument);
|
||||
if(animationByName == null) return argument;
|
||||
else return animationByName.toString();
|
||||
}
|
||||
|
||||
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
|
||||
return SharedSuggestionProvider.suggest(animationNames, builder);
|
||||
return SharedSuggestionProvider.suggest(animationNames.get(), builder);
|
||||
}
|
||||
|
||||
public Collection<String> getExamples() {
|
||||
|
|
@ -54,7 +80,7 @@ public class AnimationArgument implements ArgumentType<String> {
|
|||
reader.skip();
|
||||
}
|
||||
String s = reader.getString().substring(start, reader.getCursor());
|
||||
if (!animationNames.contains(s)) {
|
||||
if (!animationNames.get().contains(s)) {
|
||||
throw UNKNOWN_TYPE.create(s);
|
||||
} else {
|
||||
return s;
|
||||
|
|
|
|||
|
|
@ -1,6 +1,6 @@
|
|||
package com.linearpast.sccore.animation.command.argument;
|
||||
|
||||
import com.linearpast.sccore.animation.event.AnimationLayerRegistry;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import com.mojang.brigadier.StringReader;
|
||||
import com.mojang.brigadier.arguments.ArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
|
|
@ -20,15 +20,15 @@ import java.util.function.Supplier;
|
|||
import java.util.stream.Collectors;
|
||||
|
||||
public class AnimationLayerArgument implements ArgumentType<String> {
|
||||
private static final Supplier<Collection<String>> EXAMPLES = () -> AnimationLayerRegistry.getAnimLayers().keySet().stream()
|
||||
private static final Supplier<Collection<String>> EXAMPLES = () -> AnimationRegistry.getLayers().keySet().stream()
|
||||
.map(ResourceLocation::toString).collect(Collectors.toSet());
|
||||
private static final DynamicCommandExceptionType UNKNOWN_TYPE = new DynamicCommandExceptionType(
|
||||
layer -> Component.literal("Unknow layer : " + layer.toString())
|
||||
);
|
||||
|
||||
private final Set<String> animationLayers;
|
||||
private final Supplier<Set<String>> animationLayers;
|
||||
public AnimationLayerArgument() {
|
||||
this.animationLayers = AnimationLayerRegistry.getAnimLayers().keySet().stream()
|
||||
this.animationLayers = () -> AnimationRegistry.getLayers().keySet().stream()
|
||||
.map(ResourceLocation::toString).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
|
|
@ -41,7 +41,7 @@ public class AnimationLayerArgument implements ArgumentType<String> {
|
|||
}
|
||||
|
||||
public <S> CompletableFuture<Suggestions> listSuggestions(CommandContext<S> context, SuggestionsBuilder builder) {
|
||||
return SharedSuggestionProvider.suggest(animationLayers, builder);
|
||||
return SharedSuggestionProvider.suggest(animationLayers.get(), builder);
|
||||
}
|
||||
|
||||
public Collection<String> getExamples() {
|
||||
|
|
@ -54,7 +54,7 @@ public class AnimationLayerArgument implements ArgumentType<String> {
|
|||
reader.skip();
|
||||
}
|
||||
String s = reader.getString().substring(start, reader.getCursor());
|
||||
if (!animationLayers.contains(s)) {
|
||||
if (!animationLayers.get().contains(s)) {
|
||||
throw UNKNOWN_TYPE.create(s);
|
||||
} else {
|
||||
return s;
|
||||
|
|
|
|||
|
|
@ -0,0 +1,177 @@
|
|||
package com.linearpast.sccore.animation.command.client;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import com.mojang.brigadier.arguments.BoolArgumentType;
|
||||
import com.mojang.brigadier.arguments.StringArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.ClickEvent;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.chat.Style;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.Comparator;
|
||||
|
||||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
public class GenerateJsonClientCommand {
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand) {
|
||||
animCommand.then(literal("jsonClient")
|
||||
.then(argument("path", StringArgumentType.string())
|
||||
.suggests((context, builder) -> {
|
||||
try {
|
||||
File gameDirectory = Minecraft.getInstance().gameDirectory;
|
||||
Path animation = gameDirectory.toPath().resolve(SnowyCrescentCore.MODID).resolve("animation");
|
||||
if(!animation.toFile().exists()) {
|
||||
Files.createDirectories(animation);
|
||||
}
|
||||
String replace = animation.toString().replace("\\", "\\\\");
|
||||
builder.suggest("\"" + replace + "\"");
|
||||
return builder.buildFuture();
|
||||
} catch (Exception e) { return builder.buildFuture(); }
|
||||
})
|
||||
.then(literal("clearFile").executes(GenerateJsonClientCommand::clearJson))
|
||||
.then(literal("generate")
|
||||
.then(literal("anim")
|
||||
.then(literal("example").executes(GenerateJsonClientCommand::generateExample))
|
||||
.executes(context -> generateJson(context, false, false))
|
||||
.then(argument("reset", BoolArgumentType.bool())
|
||||
.executes(context ->
|
||||
generateJson(context, false, BoolArgumentType.getBool(context, "reset"))
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(literal("layer")
|
||||
.executes(context -> generateJson(context, true, false))
|
||||
.then(argument("reset", BoolArgumentType.bool())
|
||||
.executes(context ->
|
||||
generateJson(context, true, BoolArgumentType.getBool(context, "reset"))
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
private static void clearPath(Path dir) throws IOException {
|
||||
if (!Files.exists(dir)) return;
|
||||
try (var pathStream = Files.walk(dir)) {
|
||||
pathStream.sorted(Comparator.reverseOrder()).forEach(path -> {
|
||||
try {
|
||||
Files.delete(path);
|
||||
} catch (IOException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (RuntimeException ignored) {}
|
||||
}
|
||||
|
||||
private static int generateJson(CommandContext<CommandSourceStack> context, boolean isLayer, boolean isReset) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
String pathString = StringArgumentType.getString(context, "path");
|
||||
Path animationPath = Minecraft.getInstance().gameDirectory.toPath().resolve(pathString).resolve("animation");
|
||||
if (!Files.exists(animationPath)) {
|
||||
try {Files.createDirectories(animationPath);}
|
||||
catch (IOException e) { throw new RuntimeException(e); }
|
||||
}
|
||||
if(isReset) clearPath(animationPath);
|
||||
if(isLayer) {
|
||||
Path path = AnimLayerJson.Writer.syntaxImmediately(animationPath);
|
||||
MutableComponent component = Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
||||
"layer", "Client"
|
||||
);
|
||||
Style style = Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, animationPath.toString()))
|
||||
.withColor(ChatFormatting.GREEN).withBold(true).withUnderlined(true);
|
||||
component.append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
||||
path.toString()
|
||||
).setStyle(style));
|
||||
source.sendSuccess(() -> component, true);
|
||||
} else {
|
||||
for (Animation value : AnimationRegistry.getAnimations().values()) {
|
||||
AnimJson.Writer.stream(animationPath, value).syntax();
|
||||
}
|
||||
MutableComponent component = Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
||||
"anim", "Client"
|
||||
);
|
||||
Style style = Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, animationPath.toString()))
|
||||
.withColor(ChatFormatting.GREEN).withBold(true).withUnderlined(true);
|
||||
component.append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
||||
animationPath.toString()
|
||||
).withStyle(style));
|
||||
source.sendSuccess(() -> component, true);
|
||||
}
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int clearJson(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
String pathString = StringArgumentType.getString(context, "path");
|
||||
Path animationPath = Minecraft.getInstance().gameDirectory.toPath().resolve(pathString).resolve("animation");
|
||||
clearPath(animationPath);
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_SUCCESS.getKey()
|
||||
), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int generateExample(CommandContext<CommandSourceStack> context) {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
String pathString = StringArgumentType.getString(context, "path");
|
||||
Path animationPath = Minecraft.getInstance().gameDirectory.toPath().resolve(pathString);
|
||||
Path path = AnimJson.Writer.syntaxExample(animationPath);
|
||||
MutableComponent component = Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_TO_JSON.getKey(),
|
||||
"anim example", "Client"
|
||||
);
|
||||
Style style = Style.EMPTY.withClickEvent(new ClickEvent(ClickEvent.Action.OPEN_FILE, path.toString()))
|
||||
.withColor(ChatFormatting.GREEN).withBold(true).withUnderlined(true);
|
||||
component.append(Component.translatable(
|
||||
ModLang.TranslatableMessage.ANIMATION_JSON_PATH.getKey(),
|
||||
path.toString()
|
||||
).setStyle(style));
|
||||
source.sendSuccess(() -> component, true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
|
|
@ -1,6 +1,8 @@
|
|||
package com.linearpast.sccore.animation.command.client;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.ChatFormatting;
|
||||
|
|
@ -14,9 +16,9 @@ import net.minecraftforge.api.distmarker.OnlyIn;
|
|||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class AnimationRefreshCommand {
|
||||
public class RefreshAnimCommand {
|
||||
public static void register(LiteralArgumentBuilder<CommandSourceStack> animCommand){
|
||||
animCommand.then(literal("refresh").executes(AnimationRefreshCommand::refresh));
|
||||
animCommand.then(literal("refresh").executes(RefreshAnimCommand::refresh));
|
||||
}
|
||||
|
||||
private static int refresh(CommandContext<CommandSourceStack> ctx){
|
||||
|
|
@ -26,9 +28,14 @@ public class AnimationRefreshCommand {
|
|||
LocalPlayer player = instance.player;
|
||||
if(player == null) throw new RuntimeException();
|
||||
AnimationUtils.refreshAnimation(player);
|
||||
source.sendSuccess(() -> Component.literal("Animation refreshed.").withStyle(ChatFormatting.GREEN), true);
|
||||
source.sendSuccess(() -> Component.translatable(
|
||||
ModLang.TranslatableMessage.REFRESH_ANIMATIONS.getKey()
|
||||
).withStyle(ChatFormatting.GREEN), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.literal("Run command failure.").withStyle(ChatFormatting.RED));
|
||||
source.sendFailure(Component.translatable(
|
||||
ModLang.TranslatableMessage.COMMAND_RUN_FAIL.getKey()
|
||||
).withStyle(ChatFormatting.RED));
|
||||
SnowyCrescentCore.log.error(e.getMessage());
|
||||
return 0;
|
||||
}
|
||||
return 1;
|
||||
|
|
@ -5,8 +5,11 @@ import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationRegistry;
|
|||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.regex.Pattern;
|
||||
|
||||
public class Animation {
|
||||
private final ResourceLocation name;
|
||||
private @Nullable String name;
|
||||
private final ResourceLocation key;
|
||||
private KeyframeAnimation animation;
|
||||
private float heightModifier = 1.0f;
|
||||
private float camYaw;
|
||||
|
|
@ -16,15 +19,37 @@ public class Animation {
|
|||
private @Nullable Animation.LyingType lyingType;
|
||||
private @Nullable Ride ride;
|
||||
|
||||
public Animation(ResourceLocation name) {
|
||||
this.name = name;
|
||||
Animation(ResourceLocation key) {
|
||||
this.key = key;
|
||||
}
|
||||
|
||||
public static Animation create(ResourceLocation name) {
|
||||
return new Animation(name);
|
||||
}
|
||||
|
||||
public enum LyingType {
|
||||
RIGHT,
|
||||
LEFT,
|
||||
FRONT,
|
||||
BACK
|
||||
RIGHT("RIGHT"),
|
||||
LEFT("LEFT"),
|
||||
FRONT("FRONT"),
|
||||
BACK("BACK");
|
||||
private final String name;
|
||||
LyingType(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static LyingType getLyingType(String name) {
|
||||
for (LyingType type : LyingType.values()) {
|
||||
if (type.name.equals(name)) {
|
||||
return type;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
|
||||
public Animation withLyingType(@Nullable Animation.LyingType lyingType) {
|
||||
|
|
@ -77,6 +102,18 @@ public class Animation {
|
|||
return this;
|
||||
}
|
||||
|
||||
public Animation withName(String name) {
|
||||
String regex = "^[a-zA-Z0-9_-]+$";
|
||||
Pattern pattern = Pattern.compile(regex);
|
||||
if (!pattern.matcher(name).matches()) {
|
||||
throw new IllegalArgumentException(
|
||||
"Invalid animation name: " + name + ", must match " + regex
|
||||
);
|
||||
}
|
||||
this.name = name;
|
||||
return this;
|
||||
}
|
||||
|
||||
public void setLyingType(@Nullable LyingType lyingType) {
|
||||
this.lyingType = lyingType;
|
||||
}
|
||||
|
|
@ -95,7 +132,7 @@ public class Animation {
|
|||
|
||||
@Nullable
|
||||
public KeyframeAnimation getAnimation() {
|
||||
return PlayerAnimationRegistry.getAnimation(name);
|
||||
return PlayerAnimationRegistry.getAnimation(key);
|
||||
}
|
||||
|
||||
public @Nullable Animation.LyingType getLyingType() {
|
||||
|
|
@ -114,7 +151,11 @@ public class Animation {
|
|||
return ride;
|
||||
}
|
||||
|
||||
public ResourceLocation getName() {
|
||||
public ResourceLocation getKey() {
|
||||
return key;
|
||||
}
|
||||
|
||||
public @Nullable String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,195 @@
|
|||
package com.linearpast.sccore.animation.data.util;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.Ride;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileNotFoundException;
|
||||
import java.io.FileReader;
|
||||
import java.io.FileWriter;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
|
||||
public class AnimJson {
|
||||
private static final String Key = "key";
|
||||
private static final String Name = "name";
|
||||
private static final String LyingType = "lyingType";
|
||||
private static final String HeightModifier = "heightModifier";
|
||||
private static final String CamY = "camY";
|
||||
private static final String CamPitch = "camPitch";
|
||||
private static final String CamRoll = "camRoll";
|
||||
private static final String CamYaw = "camYaw";
|
||||
private static final String WithRide = "withRide";
|
||||
private static final String Offset = "offset";
|
||||
private static final String XRot = "xRot";
|
||||
private static final String YRot = "yRot";
|
||||
private static final String ExistTick = "existTick";
|
||||
private static final String ComponentsAnimation = "componentsAnimation";
|
||||
|
||||
public static class Reader {
|
||||
private final JsonElement originElement;
|
||||
Reader(Path jsonFile) throws Exception {
|
||||
File file = jsonFile.toFile();
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException("File does not exist: " + file.getAbsolutePath());
|
||||
}
|
||||
this.originElement = JsonParser.parseReader(new FileReader(file));
|
||||
}
|
||||
|
||||
Reader(JsonElement originElement) {
|
||||
this.originElement = originElement;
|
||||
}
|
||||
|
||||
public static Reader stream(Path path) throws Exception {
|
||||
return new Reader(path);
|
||||
}
|
||||
|
||||
public static Reader stream(JsonElement jsonElement) {
|
||||
return new Reader(jsonElement);
|
||||
}
|
||||
|
||||
public Animation parse() {
|
||||
return fromJson();
|
||||
}
|
||||
|
||||
public Animation fromJson() {
|
||||
try {
|
||||
JsonObject json = originElement.getAsJsonObject();
|
||||
Animation animation = Animation.create(new ResourceLocation(json.get(Key).getAsString()));
|
||||
if(json.has(Name)) animation.withName(json.get(Name).getAsString());
|
||||
if(json.has(LyingType)) animation.withLyingType(Animation.LyingType.valueOf(json.get(LyingType).getAsString()));
|
||||
animation.withHeightModifier(json.get(HeightModifier).getAsFloat())
|
||||
.withCamY(json.get(CamY).getAsFloat())
|
||||
.withCamPitch(json.get(CamPitch).getAsFloat())
|
||||
.withCamRoll(json.get(CamRoll).getAsFloat())
|
||||
.withCamYaw(json.get(CamYaw).getAsFloat());
|
||||
if(json.has(WithRide)){
|
||||
Ride ride = Ride.create();
|
||||
JsonObject withRide = json.get(WithRide).getAsJsonObject();
|
||||
JsonObject offsetJson = withRide.get(Offset).getAsJsonObject();
|
||||
if(withRide.has(ComponentsAnimation)){
|
||||
JsonArray elements = withRide.get(ComponentsAnimation).getAsJsonArray();
|
||||
for (JsonElement element : elements) {
|
||||
String componentKeyString = element.getAsString();
|
||||
ResourceLocation componentKey = new ResourceLocation(componentKeyString);
|
||||
ride.addComponentAnimation(componentKey);
|
||||
}
|
||||
}
|
||||
Vec3 offset = new Vec3(
|
||||
offsetJson.get("x").getAsDouble(),
|
||||
offsetJson.get("y").getAsDouble(),
|
||||
offsetJson.get("z").getAsDouble()
|
||||
);
|
||||
ride.withOffset(offset).withExistTick(withRide.get(ExistTick).getAsInt())
|
||||
.withXRot(withRide.get(XRot).getAsFloat())
|
||||
.withYRot(withRide.get(YRot).getAsFloat());
|
||||
animation.withRide(ride);
|
||||
}
|
||||
return animation;
|
||||
} catch (Exception e) {
|
||||
throw new JsonParseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Writer {
|
||||
private static final String example = "example";
|
||||
private final @Nullable Path file;
|
||||
private final Animation animation;
|
||||
Writer(@Nullable Path file, Animation animation) {
|
||||
this.animation = animation;
|
||||
this.file = file;
|
||||
}
|
||||
|
||||
public static Writer stream(Path path, Animation animation) {
|
||||
return new Writer(path, animation);
|
||||
}
|
||||
|
||||
public static Writer stream(Animation animation) {
|
||||
return new Writer(null, animation);
|
||||
}
|
||||
|
||||
public static Path syntaxExample(Path directory) throws Exception {
|
||||
ResourceLocation exampleLocation = new ResourceLocation(SnowyCrescentCore.MODID, Writer.example);
|
||||
Animation example = Animation.create(exampleLocation)
|
||||
.withName(Writer.example)
|
||||
.withLyingType(Animation.LyingType.RIGHT)
|
||||
.withHeightModifier(0.3f)
|
||||
.withCamY(-1.3f)
|
||||
.withCamPitch(-90.0f)
|
||||
.withCamRoll(90.0f)
|
||||
.withCamYaw(90.0f)
|
||||
.withRide(Ride.create()
|
||||
.withOffset(new Vec3(0.0f, 1.0f, 0.0f))
|
||||
.withExistTick(200)
|
||||
.withXRot(180)
|
||||
.withYRot(0)
|
||||
.addComponentAnimation(exampleLocation)
|
||||
);
|
||||
Writer writer = stream(directory, example);
|
||||
return writer.syntax();
|
||||
}
|
||||
|
||||
public Path syntax() throws Exception {
|
||||
if(file == null) throw new NullPointerException("file is null");
|
||||
Path modIdPath = file.resolve(animation.getKey().getNamespace());
|
||||
Path resultPath = modIdPath.resolve(animation.getKey().getPath() + ".anim.json");
|
||||
if(animation.getName() != null) {
|
||||
resultPath = modIdPath.resolve(animation.getName() + ".anim.json");
|
||||
if(resultPath.toFile().exists()) {
|
||||
resultPath = modIdPath.resolve(animation.getKey().getPath() + ".anim.json");
|
||||
}
|
||||
}
|
||||
if(resultPath.toFile().exists()) return resultPath;
|
||||
if(!Files.exists(modIdPath)) Files.createDirectories(modIdPath);
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
try (FileWriter writer = new FileWriter(resultPath.toFile())) {
|
||||
gson.toJson(toJson(), writer);
|
||||
return resultPath;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public JsonElement toJson() {
|
||||
JsonObject json = new JsonObject();
|
||||
ResourceLocation key = animation.getKey();
|
||||
json.addProperty(Key, key.toString());
|
||||
if (animation.getName() != null) json.addProperty(Name, animation.getName());
|
||||
if (animation.getLyingType() != null) json.addProperty(LyingType, animation.getLyingType().getName());
|
||||
json.addProperty(HeightModifier, animation.getHeightModifier());
|
||||
json.addProperty(CamY, animation.getCamY());
|
||||
json.addProperty(CamPitch, animation.getCamPitch());
|
||||
json.addProperty(CamRoll, animation.getCamRoll());
|
||||
json.addProperty(CamYaw, animation.getCamYaw());
|
||||
Ride ride = animation.getRide();
|
||||
if(ride != null) {
|
||||
JsonObject jsonRide = new JsonObject();
|
||||
JsonObject jsonOffset = new JsonObject();
|
||||
Vec3 offset = ride.getOffset();
|
||||
jsonOffset.addProperty("x", offset.x);
|
||||
jsonOffset.addProperty("y", offset.y);
|
||||
jsonOffset.addProperty("z", offset.z);
|
||||
jsonRide.add(Offset, jsonOffset);
|
||||
jsonRide.addProperty(XRot, ride.getXRot());
|
||||
jsonRide.addProperty(YRot, ride.getYRot());
|
||||
jsonRide.addProperty(ExistTick, ride.getExistTick());
|
||||
|
||||
if(!ride.getComponentAnimations().isEmpty()) {
|
||||
JsonArray jsonComponents = new JsonArray();
|
||||
ride.getComponentAnimations().forEach(component ->
|
||||
jsonComponents.add(component.toString())
|
||||
);
|
||||
jsonRide.add(ComponentsAnimation, jsonComponents);
|
||||
}
|
||||
json.add(WithRide, jsonRide);
|
||||
}
|
||||
return json;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.linearpast.sccore.animation.data.util;
|
||||
|
||||
import com.google.gson.*;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.io.*;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class AnimLayerJson {
|
||||
|
||||
private static final String Key = "key";
|
||||
private static final String Priority = "priority";
|
||||
|
||||
public static class Reader {
|
||||
private final JsonElement originElement;
|
||||
|
||||
Reader(Path jsonFile) throws Exception {
|
||||
File file = jsonFile.toFile();
|
||||
if (!file.exists()) {
|
||||
throw new FileNotFoundException("File does not exist: " + file.getAbsolutePath());
|
||||
}
|
||||
this.originElement = JsonParser.parseReader(new FileReader(file));
|
||||
}
|
||||
|
||||
Reader(JsonElement originElement) {
|
||||
this.originElement = originElement;
|
||||
}
|
||||
|
||||
public static Reader stream(Path path) throws Exception {
|
||||
return new Reader(path);
|
||||
}
|
||||
|
||||
public static Reader stream(JsonElement jsonElement) {
|
||||
return new Reader(jsonElement);
|
||||
}
|
||||
|
||||
public Map<ResourceLocation, Integer> parse() {
|
||||
return fromJson();
|
||||
}
|
||||
|
||||
private Map<ResourceLocation, Integer> fromJson() {
|
||||
try {
|
||||
JsonArray jsonArray = originElement.getAsJsonArray();
|
||||
Map<ResourceLocation, Integer> map = new HashMap<>();
|
||||
for (JsonElement element : jsonArray) {
|
||||
JsonObject jsonObject = element.getAsJsonObject();
|
||||
ResourceLocation location = new ResourceLocation(jsonObject.get(Key).getAsString());
|
||||
int priority = jsonObject.get(Priority).getAsInt();
|
||||
map.put(location, priority);
|
||||
}
|
||||
return map;
|
||||
} catch (Exception e) {
|
||||
throw new JsonParseException(e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static class Writer {
|
||||
private final Path file;
|
||||
private final Map<ResourceLocation, Integer> layers = AnimationRegistry.getLayers();
|
||||
private final Map<String, Set<ResourceLocation>> layerNames = new HashMap<>();
|
||||
Writer(Path file) {
|
||||
this.file = file;
|
||||
for (ResourceLocation location : layers.keySet()) {
|
||||
String namespace = location.getNamespace();
|
||||
Set<ResourceLocation> locationSet = layerNames.getOrDefault(namespace, new HashSet<>());
|
||||
locationSet.add(location);
|
||||
layerNames.put(namespace, locationSet);
|
||||
}
|
||||
}
|
||||
|
||||
public static Writer stream(Path path) {
|
||||
return new Writer(path);
|
||||
}
|
||||
|
||||
public static Path syntaxImmediately(Path directory) throws IOException {
|
||||
Writer writer = stream(directory);
|
||||
return writer.syntax();
|
||||
}
|
||||
|
||||
public Map<String, JsonElement> allToJson() {
|
||||
Map<String, JsonElement> map = new HashMap<>();
|
||||
for (String namespace : layerNames.keySet()) {
|
||||
Set<ResourceLocation> locationSet = layerNames.get(namespace);
|
||||
JsonElement json = toJson(locationSet);
|
||||
map.put(namespace, json);
|
||||
}
|
||||
return map;
|
||||
}
|
||||
|
||||
public Path syntax(String ... namespaces) throws IOException {
|
||||
Set<String> namespaceSet;
|
||||
if(namespaces.length == 0) {
|
||||
namespaceSet = layerNames.keySet();
|
||||
} else {
|
||||
namespaceSet = Arrays.stream(namespaces).collect(Collectors.toSet());
|
||||
}
|
||||
|
||||
for (String name : namespaceSet) {
|
||||
Set<ResourceLocation> locationSet = layerNames.get(name);
|
||||
Path modIdPath = file.resolve(name);
|
||||
Path resultPath = modIdPath.resolve("animation.layer.json");
|
||||
if(!Files.exists(modIdPath)) Files.createDirectories(modIdPath);
|
||||
Gson gson = new GsonBuilder().setPrettyPrinting().create();
|
||||
try (FileWriter writer = new FileWriter(resultPath.toFile())) {
|
||||
gson.toJson(toJson(locationSet), writer);
|
||||
}
|
||||
}
|
||||
return file;
|
||||
}
|
||||
|
||||
private JsonElement toJson(Set<ResourceLocation> locationSet) {
|
||||
JsonArray jsonArray = new JsonArray();
|
||||
for (ResourceLocation location : locationSet) {
|
||||
if(layers.containsKey(location)) {
|
||||
JsonObject jsonObject = new JsonObject();
|
||||
jsonObject.addProperty(Key, location.toString());
|
||||
jsonObject.addProperty(Priority, layers.get(location));
|
||||
jsonArray.add(jsonObject);
|
||||
}
|
||||
}
|
||||
return jsonArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,7 +5,7 @@ import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
|||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.Ride;
|
||||
import com.linearpast.sccore.animation.registry.AnimationEntities;
|
||||
import com.linearpast.sccore.animation.register.AnimationEntities;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.protocol.Packet;
|
||||
import net.minecraft.network.protocol.game.ClientGamePacketListener;
|
||||
|
|
@ -20,9 +20,7 @@ import net.minecraftforge.network.NetworkHooks;
|
|||
import net.minecraftforge.server.ServerLifecycleHooks;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.HashSet;
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
import java.util.*;
|
||||
|
||||
public class AnimationRideEntity extends Entity {
|
||||
public AnimationRideEntity(Level pLevel) {
|
||||
|
|
@ -35,6 +33,7 @@ public class AnimationRideEntity extends Entity {
|
|||
private static final String Layer = "Layer";
|
||||
|
||||
private final Set<ServerPlayer> players = new HashSet<>();
|
||||
private final Map<ResourceLocation, UUID> animationPair = new HashMap<>();
|
||||
private Animation animation;
|
||||
private ServerPlayer player;
|
||||
private ResourceLocation layer;
|
||||
|
|
@ -43,6 +42,13 @@ public class AnimationRideEntity extends Entity {
|
|||
this.player = pPlayer;
|
||||
this.layer = layer;
|
||||
this.animation = animation;
|
||||
Ride ride = animation.getRide();
|
||||
if(ride != null) {
|
||||
List<ResourceLocation> componentAnimations = ride.getComponentAnimations();
|
||||
for (ResourceLocation componentAnimation : componentAnimations) {
|
||||
animationPair.put(componentAnimation, null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public ResourceLocation getLayer() {
|
||||
|
|
@ -53,6 +59,10 @@ public class AnimationRideEntity extends Entity {
|
|||
return players;
|
||||
}
|
||||
|
||||
public ServerPlayer getPlayer() {
|
||||
return player;
|
||||
}
|
||||
|
||||
public Animation getAnimation() {
|
||||
return animation;
|
||||
}
|
||||
|
|
@ -88,7 +98,7 @@ public class AnimationRideEntity extends Entity {
|
|||
pCompound.putUUID(PlayerUUID, player.getUUID());
|
||||
pCompound.putString(Layer, layer.toString());
|
||||
if(animation != null) {
|
||||
pCompound.putString(Animation, animation.getName().toString());
|
||||
pCompound.putString(Animation, animation.getKey().toString());
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -98,18 +108,6 @@ public class AnimationRideEntity extends Entity {
|
|||
if(!this.level().isClientSide) {
|
||||
Ride ride = animation == null ? null : animation.getRide();
|
||||
if(!this.getPassengers().contains(player) || (ride != null && ride.getExistTick() > 0 && this.tickCount >= ride.getExistTick())) {
|
||||
if(player != null) {
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||
if(data != null) {
|
||||
AnimationUtils.removeAnimation(player, layer);
|
||||
data.setRideAnimLayer(null);
|
||||
}
|
||||
}
|
||||
if(ride != null) players.forEach(player -> {
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||
AnimationUtils.removeAnimation(player, layer);
|
||||
if(data != null) data.setRideAnimLayer(null);
|
||||
});
|
||||
this.remove(RemovalReason.DISCARDED);
|
||||
}
|
||||
}
|
||||
|
|
@ -139,6 +137,9 @@ public class AnimationRideEntity extends Entity {
|
|||
Animation anim = AnimationUtils.getAnimation(animation);
|
||||
if(anim == null) return false;
|
||||
if(anim.getRide() == null) return false;
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(pPlayer).orElse(null);
|
||||
if(data == null) return false;
|
||||
data.setRiderAnimation(layer, animation);
|
||||
AnimationRideEntity seat = new AnimationRideEntity(pPlayer, layer, anim);
|
||||
float xRot = anim.getRide().getXRot();
|
||||
float yRot = anim.getRide().getYRot();
|
||||
|
|
@ -149,7 +150,7 @@ public class AnimationRideEntity extends Entity {
|
|||
seat.setPos(pos.x, pos.y + 0.35f, pos.z);
|
||||
pPlayer.level().addFreshEntity(seat);
|
||||
pPlayer.startRiding(seat, force);
|
||||
return AnimationUtils.playAnimation(pPlayer, layer, animation);
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
|
|
@ -184,9 +185,17 @@ public class AnimationRideEntity extends Entity {
|
|||
List<ResourceLocation> componentAnimations = ride.getComponentAnimations();
|
||||
if(componentAnimations.isEmpty()) return;
|
||||
if(passengerNum > componentAnimations.size()) return;
|
||||
ResourceLocation location = componentAnimations.get(passengerNum - 1);
|
||||
AnimationUtils.playAnimation(serverPlayer, layer, location);
|
||||
AnimationUtils.syncAnimation(serverPlayer, player, layer);
|
||||
ResourceLocation animLocation = null;
|
||||
for (ResourceLocation location : animationPair.keySet()) {
|
||||
if(animationPair.get(location) == null)
|
||||
animLocation = location;
|
||||
}
|
||||
if(animLocation == null) return;
|
||||
animationPair.put(animLocation, serverPlayer.getUUID());
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
||||
if(data == null) return;
|
||||
data.setRiderAnimation(layer, animLocation);
|
||||
AnimationUtils.syncAnimation(serverPlayer, player);
|
||||
players.add(serverPlayer);
|
||||
}
|
||||
}
|
||||
|
|
@ -196,13 +205,20 @@ public class AnimationRideEntity extends Entity {
|
|||
super.removePassenger(entity);
|
||||
if(entity instanceof ServerPlayer serverPlayer) {
|
||||
AnimationUtils.removeAnimation(serverPlayer, layer);
|
||||
AnimationDataCapability.getCapability(serverPlayer).ifPresent(data -> data.setRideAnimLayer(null));
|
||||
players.remove(serverPlayer);
|
||||
new HashMap<>(animationPair).forEach((key, value) -> {
|
||||
if(Objects.equals(value, serverPlayer.getUUID())) {
|
||||
animationPair.put(key, null);
|
||||
}
|
||||
});
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(serverPlayer).orElse(null);
|
||||
if(data == null) return;
|
||||
data.removeRiderAnimation();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean canAddPassenger(@NotNull Entity pPassenger) {
|
||||
public boolean canAddPassenger(@NotNull Entity pPassenger) {
|
||||
boolean isServerPlayer = pPassenger instanceof ServerPlayer;
|
||||
int size = players.size();
|
||||
Ride ride = animation.getRide();
|
||||
|
|
|
|||
|
|
@ -1,49 +0,0 @@
|
|||
package com.linearpast.sccore.animation.event;
|
||||
|
||||
import com.linearpast.sccore.animation.event.create.AnimationLayerRegisterEvent;
|
||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationFactory;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.fml.ModLoader;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLClientSetupEvent;
|
||||
import net.minecraftforge.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AnimationLayerRegistry {
|
||||
private static final Map<ResourceLocation, Integer> animLayers = new HashMap<>();
|
||||
|
||||
public static void onClientSetup(FMLClientSetupEvent event) {
|
||||
onCommonSetUp(null);
|
||||
event.enqueueWork(() -> animLayers.forEach((location, integer) ->
|
||||
PlayerAnimationFactory.ANIMATION_DATA_FACTORY.registerFactory(location, integer,
|
||||
AnimationLayerRegistry::registerPlayerAnimation
|
||||
)
|
||||
));
|
||||
}
|
||||
|
||||
public static void onCommonSetUp(FMLCommonSetupEvent event) {
|
||||
AnimationLayerRegisterEvent layerEvent = new AnimationLayerRegisterEvent();
|
||||
ModLoader.get().postEvent(layerEvent);
|
||||
animLayers.putAll(layerEvent.getLayers());
|
||||
}
|
||||
|
||||
public static void registerPlayerAnimation(ResourceLocation location, int priority) {
|
||||
animLayers.put(location, priority);
|
||||
}
|
||||
|
||||
public static Map<ResourceLocation, Integer> getAnimLayers() {
|
||||
return animLayers;
|
||||
}
|
||||
|
||||
public static boolean isLayerPresent(ResourceLocation layer) {
|
||||
return animLayers.containsKey(layer);
|
||||
}
|
||||
|
||||
private static IAnimation registerPlayerAnimation(AbstractClientPlayer player) {
|
||||
return new ModifierLayer<>();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.linearpast.sccore.animation.event;
|
||||
|
||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraftforge.event.TickEvent;
|
||||
|
||||
public class PlayerTickEvent {
|
||||
public static void onPlayerTickEvent(TickEvent.PlayerTickEvent event) {
|
||||
if (event.side.isServer() && event.phase == TickEvent.Phase.END) {
|
||||
if(event.player.tickCount % 20 == 0) {
|
||||
Player player = event.player;
|
||||
if(!(player.getVehicle() instanceof AnimationRideEntity)){
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||
if(data == null) return;
|
||||
if(data.getRiderAnimLayer() != null) {
|
||||
data.removeRiderAnimation();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,10 +1,10 @@
|
|||
package com.linearpast.sccore.animation.event;
|
||||
package com.linearpast.sccore.animation.event.client;
|
||||
|
||||
import com.linearpast.sccore.animation.entity.renderer.AnimationRideRenderer;
|
||||
import com.linearpast.sccore.animation.registry.AnimationEntities;
|
||||
import com.linearpast.sccore.animation.register.AnimationEntities;
|
||||
import net.minecraftforge.client.event.EntityRenderersEvent;
|
||||
|
||||
public class EntityRendererRegistry {
|
||||
public class EntityRendererRegisterEvent {
|
||||
public static void registerEntityRenderer(EntityRenderersEvent.RegisterRenderers event) {
|
||||
event.registerEntityRenderer(AnimationEntities.RIDE.get(), AnimationRideRenderer::new);
|
||||
}
|
||||
|
|
@ -2,28 +2,22 @@ package com.linearpast.sccore.animation.event.create;
|
|||
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
import net.minecraftforge.fml.event.IModBusEvent;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* You can listen this event to register an animation layer <br>
|
||||
* Generally, the static function is better.
|
||||
* @see com.linearpast.sccore.animation.AnimationUtils#registerAnimationLayer
|
||||
* You can listen this event to invite an animation layer <br>
|
||||
* It is only useful in server
|
||||
*/
|
||||
public class AnimationLayerRegisterEvent extends Event implements IModBusEvent {
|
||||
public class AnimationLayerRegisterEvent extends Event {
|
||||
private final Map<ResourceLocation, Integer> layers = new HashMap<>();
|
||||
|
||||
public AnimationLayerRegisterEvent() {
|
||||
|
||||
}
|
||||
|
||||
public Map<ResourceLocation, Integer> getLayers() {
|
||||
return layers;
|
||||
}
|
||||
|
||||
public void putLayer(ResourceLocation key, Integer value) {
|
||||
public void registerLayer(ResourceLocation key, Integer value) {
|
||||
layers.put(key, value);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,24 @@
|
|||
package com.linearpast.sccore.animation.event.create;
|
||||
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.eventbus.api.Event;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
/**
|
||||
* You can listen this event to invite an animation <br>
|
||||
* It is only useful in server
|
||||
*/
|
||||
public class AnimationRegisterEvent extends Event {
|
||||
private final Map<ResourceLocation, Animation> animations = new HashMap<>();
|
||||
|
||||
public Map<ResourceLocation, Animation> getAnimations() {
|
||||
return new HashMap<>(animations);
|
||||
}
|
||||
|
||||
public void registerAnimation(ResourceLocation location, Animation animation) {
|
||||
animations.put(location, animation);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,12 @@
|
|||
package com.linearpast.sccore.animation.mixin;
|
||||
|
||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public interface IMixinPlayerAnimationFactoryHolder {
|
||||
record DataHolder(@Nullable ResourceLocation id, int priority, @NotNull IAnimation animation) {}
|
||||
|
||||
void sccore$clearAnimations();
|
||||
}
|
||||
|
|
@ -1,7 +1,6 @@
|
|||
package com.linearpast.sccore.animation.network.toclient;
|
||||
|
||||
import com.linearpast.sccore.animation.AnimationPlayer;
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||
import com.linearpast.sccore.capability.data.player.SimplePlayerCapabilitySync;
|
||||
|
|
@ -50,14 +49,24 @@ public class AnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
|||
}
|
||||
|
||||
private void testPlayAnimations(AbstractClientPlayer player, CompoundTag tag, IAnimationCapability data) {
|
||||
Set<ResourceLocation> oldLayerSet = new HashSet<>();
|
||||
if(data != null) oldLayerSet.addAll(data.getAnimations().keySet());
|
||||
if(data == null) return;
|
||||
ResourceLocation oldRiderAnimLayer = data.getRiderAnimLayer();
|
||||
String riderAnimLayerString = tag.getString(AnimationDataCapability.RideAnimLayer);
|
||||
ResourceLocation newRiderAnimLayer = riderAnimLayerString.isEmpty() ? null : new ResourceLocation(riderAnimLayerString);
|
||||
if(!Objects.equals(oldRiderAnimLayer, newRiderAnimLayer)) {
|
||||
String riderAnimationString = tag.getString(AnimationDataCapability.RideAnimation);
|
||||
ResourceLocation newRiderAnimation = riderAnimationString.isEmpty() ? null : new ResourceLocation(riderAnimationString);
|
||||
if(oldRiderAnimLayer != null) AnimationPlayer.playAnimation(player, oldRiderAnimLayer, null);
|
||||
if(newRiderAnimLayer != null) AnimationPlayer.playAnimation(player, newRiderAnimLayer, newRiderAnimation);
|
||||
}
|
||||
|
||||
Set<ResourceLocation> oldLayerSet = new HashSet<>(data.getAnimations().keySet());
|
||||
CompoundTag animMap = tag.getCompound(AnimationDataCapability.AnimMap);
|
||||
for (String newLayerString : animMap.getAllKeys()) {
|
||||
ResourceLocation newLayerLocation = new ResourceLocation(newLayerString);
|
||||
String newAnimString = animMap.getString(newLayerString);
|
||||
ResourceLocation newAnimLocation = newAnimString.isEmpty() ? null : new ResourceLocation(newAnimString);
|
||||
ResourceLocation oldAnimLocation = data == null ? null : data.getAnimation(newLayerLocation);
|
||||
ResourceLocation oldAnimLocation = data.getAnimation(newLayerLocation);
|
||||
if (!Objects.equals(newAnimLocation, oldAnimLocation)) {
|
||||
AnimationPlayer.playAnimation(player, newLayerLocation, newAnimLocation);
|
||||
}
|
||||
|
|
@ -67,10 +76,7 @@ public class AnimationCapabilityPacket extends SimpleCapabilityPacket<Player> {
|
|||
AnimationPlayer.playAnimation(player, oldLayerLocation, null);
|
||||
}
|
||||
|
||||
if(!tag.contains(AnimationDataCapability.RideAnimLayer)) {
|
||||
if(data != null && data.getRideAnimLayer() != null) {
|
||||
AnimationUtils.playAnimation(null, data.getRideAnimLayer(), null);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -0,0 +1,47 @@
|
|||
package com.linearpast.sccore.animation.network.toclient;
|
||||
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AnimationClientStatusPacket(int status) {
|
||||
public enum Status {
|
||||
ANIM_CACHE_CLEAR(0),
|
||||
LAYER_CACHE_CLEAR(1),
|
||||
ANIM_REGISTER(2),
|
||||
LAYER_REGISTER(3),;
|
||||
private final int value;
|
||||
Status(final int value) {
|
||||
this.value = value;
|
||||
}
|
||||
@Nullable
|
||||
public static Status getStatus(final int value) {
|
||||
for (Status status : values()) {
|
||||
if (status.value == value) {
|
||||
return status;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
}
|
||||
public AnimationClientStatusPacket(Status status) {
|
||||
this(status.value);
|
||||
}
|
||||
public AnimationClientStatusPacket(FriendlyByteBuf buf) {
|
||||
this(buf.readInt());
|
||||
}
|
||||
public void encode(FriendlyByteBuf buf) {
|
||||
buf.writeInt(status);
|
||||
}
|
||||
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
||||
NetworkEvent.Context context = supplier.get();
|
||||
context.enqueueWork(() -> {
|
||||
Status state = Status.getStatus(status);
|
||||
if(state == null) return;
|
||||
AnimationRegistry.ClientCache.animationStatusUpdate(state);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.linearpast.sccore.animation.network.toclient;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.google.gson.JsonParser;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public record AnimationJsonPacket(String json, boolean isLayer) {
|
||||
public AnimationJsonPacket(FriendlyByteBuf buf) {
|
||||
this(buf.readUtf(), buf.readBoolean());
|
||||
}
|
||||
public void encode(FriendlyByteBuf buf) {
|
||||
buf.writeUtf(json);
|
||||
buf.writeBoolean(isLayer);
|
||||
}
|
||||
|
||||
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
||||
NetworkEvent.Context context = supplier.get();
|
||||
context.enqueueWork(() -> {
|
||||
context.setPacketHandled(true);
|
||||
JsonElement element = JsonParser.parseString(json);
|
||||
if(isLayer) {
|
||||
Map<ResourceLocation, Integer> parse = AnimLayerJson.Reader.stream(element).parse();
|
||||
parse.forEach(AnimationRegistry.ClientCache::cacheAddAnimationLayer);
|
||||
} else {
|
||||
Animation animation = AnimJson.Reader.stream(element).parse();
|
||||
AnimationRegistry.ClientCache.cacheAddAnimation(animation.getKey(), animation);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -6,7 +6,6 @@ import net.minecraft.client.Minecraft;
|
|||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
|
||||
import java.util.AbstractMap;
|
||||
|
|
@ -16,23 +15,19 @@ import java.util.function.Supplier;
|
|||
public class SyncAnimationPacket {
|
||||
private final UUID playerUUID;
|
||||
private final UUID targetUUID;
|
||||
private final ResourceLocation layer;
|
||||
public SyncAnimationPacket(UUID playerUUID, UUID targetUUID, ResourceLocation layer) {
|
||||
public SyncAnimationPacket(UUID playerUUID, UUID targetUUID) {
|
||||
this.playerUUID = playerUUID;
|
||||
this.targetUUID = targetUUID;
|
||||
this.layer = layer;
|
||||
}
|
||||
|
||||
public SyncAnimationPacket(FriendlyByteBuf buf) {
|
||||
this.playerUUID = buf.readUUID();
|
||||
this.targetUUID = buf.readUUID();
|
||||
this.layer = buf.readResourceLocation();
|
||||
}
|
||||
|
||||
public void encode(FriendlyByteBuf buf) {
|
||||
buf.writeUUID(this.playerUUID);
|
||||
buf.writeUUID(this.targetUUID);
|
||||
buf.writeResourceLocation(this.layer);
|
||||
}
|
||||
|
||||
public void handle(Supplier<NetworkEvent.Context> supplier) {
|
||||
|
|
@ -45,7 +40,7 @@ public class SyncAnimationPacket {
|
|||
AbstractClientPlayer player = (AbstractClientPlayer) level.getPlayerByUUID(playerUUID);
|
||||
AbstractClientPlayer target = (AbstractClientPlayer) level.getPlayerByUUID(targetUUID);
|
||||
ClientPlayerTick.runs.put(
|
||||
() -> AnimationPlayer.syncAnimation(player, target, layer),
|
||||
() -> AnimationPlayer.syncAnimation(player, target),
|
||||
new AbstractMap.SimpleEntry<>(5, 0)
|
||||
);
|
||||
|
||||
|
|
|
|||
|
|
@ -1,45 +1,52 @@
|
|||
package com.linearpast.sccore.animation.network.toserver;
|
||||
|
||||
import com.linearpast.sccore.animation.AnimationPlayer;
|
||||
import com.linearpast.sccore.animation.event.AnimationLayerRegistry;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraftforge.network.NetworkEvent;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class PlayAnimationRequestPacket {
|
||||
private final ResourceLocation layer;
|
||||
private @Nullable ResourceLocation animation;
|
||||
public PlayAnimationRequestPacket(ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
private @Nullable UUID uuid;
|
||||
public PlayAnimationRequestPacket(@Nullable UUID uuid, ResourceLocation layer, @Nullable ResourceLocation animation) {
|
||||
this.layer = layer;
|
||||
this.animation = animation;
|
||||
this.uuid = uuid;
|
||||
}
|
||||
public PlayAnimationRequestPacket(FriendlyByteBuf buf){
|
||||
this.layer = buf.readResourceLocation();
|
||||
try {
|
||||
this.animation = buf.readResourceLocation();
|
||||
this.uuid = buf.readUUID();
|
||||
} catch (Exception e) {
|
||||
this.animation = null;
|
||||
this.uuid = null;
|
||||
}
|
||||
}
|
||||
public void encode(FriendlyByteBuf buf){
|
||||
buf.writeResourceLocation(layer);
|
||||
if(animation != null){
|
||||
buf.writeResourceLocation(animation);
|
||||
}
|
||||
if(animation != null) buf.writeResourceLocation(animation);
|
||||
if(uuid != null) buf.writeUUID(uuid);
|
||||
}
|
||||
|
||||
public void handle(Supplier<NetworkEvent.Context> supplier){
|
||||
NetworkEvent.Context context = supplier.get();
|
||||
context.enqueueWork(() -> {
|
||||
context.setPacketHandled(true);
|
||||
if (AnimationLayerRegistry.getAnimLayers().containsKey(layer)) {
|
||||
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
||||
ServerPlayer target;
|
||||
ServerPlayer sender = context.getSender();
|
||||
if(sender == null) return;
|
||||
AnimationPlayer.serverPlayAnimation(sender, layer, animation);
|
||||
if(sender == null || sender.getServer() == null) return;
|
||||
if(this.uuid == null) target = sender;
|
||||
else target = sender.getServer().getPlayerList().getPlayer(this.uuid);
|
||||
AnimationPlayer.serverPlayAnimation(target, layer, animation);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.linearpast.sccore.animation.network.toserver;
|
||||
|
||||
import com.linearpast.sccore.animation.AnimationPlayer;
|
||||
import com.linearpast.sccore.animation.event.AnimationLayerRegistry;
|
||||
import com.linearpast.sccore.animation.register.AnimationRegistry;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
|
@ -43,7 +43,7 @@ public class PlayAnimationRidePacket {
|
|||
NetworkEvent.Context context = supplier.get();
|
||||
context.enqueueWork(() -> {
|
||||
context.setPacketHandled(true);
|
||||
if (AnimationLayerRegistry.getAnimLayers().containsKey(layer)) {
|
||||
if (AnimationRegistry.getLayers().containsKey(layer)) {
|
||||
ServerPlayer sender = context.getSender();
|
||||
if(sender == null) return;
|
||||
AnimationPlayer.playAnimationWithRide(sender, layer, animation, force);
|
||||
|
|
|
|||
|
|
@ -0,0 +1,31 @@
|
|||
package com.linearpast.sccore.animation.register;
|
||||
|
||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||
import com.linearpast.sccore.animation.network.toclient.AnimationCapabilityPacket;
|
||||
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||
import com.linearpast.sccore.capability.data.player.PlayerCapabilityRegistry;
|
||||
import com.linearpast.sccore.capability.network.CapabilityChannel;
|
||||
import com.linearpast.sccore.core.ModChannel;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.common.capabilities.CapabilityToken;
|
||||
|
||||
public class AnimationCapabilities {
|
||||
public static void registerAnimationCapability() {
|
||||
CapabilityChannel channel = CapabilityUtils.createChannel();
|
||||
CapabilityUtils.registerPlayerCapabilityWithNetwork(
|
||||
AnimationDataCapability.key,
|
||||
new PlayerCapabilityRegistry.CapabilityRecord<>(
|
||||
AnimationDataCapability.class,
|
||||
CapabilityManager.get(new CapabilityToken<>() {}),
|
||||
IAnimationCapability.class
|
||||
),
|
||||
channel,
|
||||
ModChannel.getAndAddCid(),
|
||||
AnimationCapabilityPacket.class,
|
||||
AnimationCapabilityPacket::new,
|
||||
AnimationCapabilityPacket::encode,
|
||||
AnimationCapabilityPacket::handle
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.linearpast.sccore.animation.register;
|
||||
|
||||
import com.linearpast.sccore.animation.network.toclient.AnimationClientStatusPacket;
|
||||
import com.linearpast.sccore.animation.network.toclient.AnimationJsonPacket;
|
||||
import com.linearpast.sccore.animation.network.toclient.SyncAnimationPacket;
|
||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRequestPacket;
|
||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRidePacket;
|
||||
import com.linearpast.sccore.animation.network.toserver.RefreshAnimationPacket;
|
||||
import com.linearpast.sccore.core.ModChannel;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
|
||||
public class AnimationChannels {
|
||||
public static void registerChannel() {
|
||||
ModChannel.INSTANCE.messageBuilder(SyncAnimationPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_CLIENT)
|
||||
.decoder(SyncAnimationPacket::new)
|
||||
.encoder(SyncAnimationPacket::encode)
|
||||
.consumerMainThread(SyncAnimationPacket::handle)
|
||||
.add();
|
||||
ModChannel.INSTANCE.messageBuilder(AnimationJsonPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_CLIENT)
|
||||
.decoder(AnimationJsonPacket::new)
|
||||
.encoder(AnimationJsonPacket::encode)
|
||||
.consumerMainThread(AnimationJsonPacket::handle)
|
||||
.add();
|
||||
ModChannel.INSTANCE.messageBuilder(AnimationClientStatusPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_CLIENT)
|
||||
.decoder(AnimationClientStatusPacket::new)
|
||||
.encoder(AnimationClientStatusPacket::encode)
|
||||
.consumerMainThread(AnimationClientStatusPacket::handle)
|
||||
.add();
|
||||
|
||||
ModChannel.INSTANCE.messageBuilder(PlayAnimationRequestPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.decoder(PlayAnimationRequestPacket::new)
|
||||
.encoder(PlayAnimationRequestPacket::encode)
|
||||
.consumerMainThread(PlayAnimationRequestPacket::handle)
|
||||
.add();
|
||||
ModChannel.INSTANCE.messageBuilder(PlayAnimationRidePacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.decoder(PlayAnimationRidePacket::new)
|
||||
.encoder(PlayAnimationRidePacket::encode)
|
||||
.consumerMainThread(PlayAnimationRidePacket::handle)
|
||||
.add();
|
||||
ModChannel.INSTANCE.messageBuilder(RefreshAnimationPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.decoder(RefreshAnimationPacket::new)
|
||||
.encoder(RefreshAnimationPacket::encode)
|
||||
.consumerMainThread(RefreshAnimationPacket::handle)
|
||||
.add();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,9 +1,11 @@
|
|||
package com.linearpast.sccore.animation.command;
|
||||
package com.linearpast.sccore.animation.register;
|
||||
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.command.*;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationArgument;
|
||||
import com.linearpast.sccore.animation.command.argument.AnimationLayerArgument;
|
||||
import com.linearpast.sccore.animation.command.client.AnimationRefreshCommand;
|
||||
import com.linearpast.sccore.animation.command.client.GenerateJsonClientCommand;
|
||||
import com.linearpast.sccore.animation.command.client.RefreshAnimCommand;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.synchronization.ArgumentTypeInfo;
|
||||
|
|
@ -17,8 +19,11 @@ public class AnimationCommands {
|
|||
public static void commonCommandRegister(LiteralArgumentBuilder<CommandSourceStack> builder) {
|
||||
if(AnimationUtils.ANIMATION_RUNNER.isModLoaded()){
|
||||
LiteralArgumentBuilder<CommandSourceStack> anim = literal("anim");
|
||||
PlayAnimationCommand.register(anim);
|
||||
|
||||
PlayAnimCommand.register(anim);
|
||||
RequestAnimCommand.register(anim);
|
||||
CombineAnimCommand.register(anim);
|
||||
GenerateJsonCommand.register(anim);
|
||||
ApplyJoinAnimCommand.register(anim);
|
||||
builder.then(anim);
|
||||
}
|
||||
}
|
||||
|
|
@ -26,7 +31,8 @@ public class AnimationCommands {
|
|||
public static void clientCommandRegister(LiteralArgumentBuilder<CommandSourceStack> builder) {
|
||||
if(AnimationUtils.ANIMATION_RUNNER.isModLoaded()) {
|
||||
LiteralArgumentBuilder<CommandSourceStack> anim = literal("anim");
|
||||
AnimationRefreshCommand.register(anim);
|
||||
RefreshAnimCommand.register(anim);
|
||||
GenerateJsonClientCommand.register(anim);
|
||||
builder.then(anim);
|
||||
}
|
||||
}
|
||||
|
|
@ -1,4 +1,4 @@
|
|||
package com.linearpast.sccore.animation.registry;
|
||||
package com.linearpast.sccore.animation.register;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.entity.AnimationRideEntity;
|
||||
|
|
@ -0,0 +1,309 @@
|
|||
package com.linearpast.sccore.animation.register;
|
||||
|
||||
import com.google.gson.JsonElement;
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.util.AnimJson;
|
||||
import com.linearpast.sccore.animation.data.util.AnimLayerJson;
|
||||
import com.linearpast.sccore.animation.event.create.AnimationLayerRegisterEvent;
|
||||
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
||||
import com.linearpast.sccore.animation.mixin.IMixinPlayerAnimationFactoryHolder;
|
||||
import com.linearpast.sccore.animation.network.toclient.AnimationClientStatusPacket;
|
||||
import com.linearpast.sccore.animation.network.toclient.AnimationJsonPacket;
|
||||
import com.linearpast.sccore.core.ModChannel;
|
||||
import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||
import dev.kosmx.playerAnim.api.layered.KeyframeAnimationPlayer;
|
||||
import dev.kosmx.playerAnim.api.layered.ModifierLayer;
|
||||
import dev.kosmx.playerAnim.core.data.KeyframeAnimation;
|
||||
import dev.kosmx.playerAnim.core.util.Pair;
|
||||
import dev.kosmx.playerAnim.impl.animation.AnimationApplier;
|
||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationAccess;
|
||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationFactory;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.storage.LevelResource;
|
||||
import net.minecraftforge.api.distmarker.Dist;
|
||||
import net.minecraftforge.api.distmarker.OnlyIn;
|
||||
import net.minecraftforge.common.MinecraftForge;
|
||||
import net.minecraftforge.event.entity.player.PlayerEvent;
|
||||
import net.minecraftforge.event.server.ServerStartedEvent;
|
||||
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.lang.reflect.Field;
|
||||
import java.lang.reflect.Method;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Path;
|
||||
import java.nio.file.Paths;
|
||||
import java.nio.file.StandardOpenOption;
|
||||
import java.util.*;
|
||||
import java.util.function.Predicate;
|
||||
import java.util.stream.Collectors;
|
||||
import java.util.stream.Stream;
|
||||
import java.util.zip.ZipEntry;
|
||||
import java.util.zip.ZipFile;
|
||||
|
||||
public class AnimationRegistry {
|
||||
private static final Map<ResourceLocation, Animation> animations = new HashMap<>();
|
||||
private static final Map<ResourceLocation, Integer> layers = new HashMap<>();
|
||||
|
||||
public static Map<ResourceLocation, Animation> getAnimations() {
|
||||
return Map.copyOf(animations);
|
||||
}
|
||||
|
||||
public static Map<ResourceLocation, Integer> getLayers() {
|
||||
return Map.copyOf(layers);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void registerAnimations(Map<ResourceLocation, Animation> animationMap) {
|
||||
animations.clear();
|
||||
animations.putAll(animationMap);
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static void registerLayers(Map<ResourceLocation, Integer> layerMap) {
|
||||
layers.clear();
|
||||
layers.putAll(layerMap);
|
||||
}
|
||||
|
||||
public static void onServerStarted(ServerStartedEvent event) {
|
||||
Path dataPackPath = event.getServer().getWorldPath(LevelResource.DATAPACK_DIR);
|
||||
Path animationPath = dataPackPath.resolve("animation");
|
||||
if (!Files.exists(animationPath)) {
|
||||
try {
|
||||
Files.createDirectories(animationPath);
|
||||
} catch (IOException e) { return; }
|
||||
}
|
||||
|
||||
safeUnzip(dataPackPath.resolve("animation.zip").toString(), animationPath.toAbsolutePath().toString());
|
||||
Set<Path> animZipPaths = getAllFile(
|
||||
dataPackPath.resolve("animation"),
|
||||
path -> path.toString().endsWith(".anim.zip")
|
||||
);
|
||||
Set<Path> layerZipPaths = getAllFile(
|
||||
dataPackPath.resolve("animation"),
|
||||
path -> path.toString().endsWith(".layer.zip")
|
||||
);
|
||||
for (Path zipPath : animZipPaths) {
|
||||
safeUnzip(zipPath.toString(), animationPath.toAbsolutePath().toString());
|
||||
}
|
||||
for (Path zipPath : layerZipPaths) {
|
||||
safeUnzip(zipPath.toString(), animationPath.toAbsolutePath().toString());
|
||||
}
|
||||
|
||||
Set<Path> animPaths = getAllFile(
|
||||
dataPackPath.resolve("animation"),
|
||||
path -> path.toString().endsWith(".anim.json")
|
||||
);
|
||||
Set<Path> layerPaths = getAllFile(
|
||||
dataPackPath.resolve("animation"),
|
||||
path -> path.getFileName().toString().equals("animation.layer.json")
|
||||
);
|
||||
Set<Animation> animationsSet = new HashSet<>();
|
||||
Map<ResourceLocation, Integer> layersMap = new HashMap<>();
|
||||
for (Path path : animPaths) {
|
||||
try {
|
||||
AnimJson.Reader reader = AnimJson.Reader.stream(path);
|
||||
Animation anim = reader.parse();
|
||||
animationsSet.add(anim);
|
||||
} catch (Exception ignored) {
|
||||
SnowyCrescentCore.log.error("Failed to parse animation JSON: {}", path.toString());
|
||||
}
|
||||
}
|
||||
for (Path path : layerPaths) {
|
||||
try {
|
||||
AnimLayerJson.Reader reader = AnimLayerJson.Reader.stream(path);
|
||||
Map<ResourceLocation, Integer> parse = reader.parse();
|
||||
layersMap.putAll(parse);
|
||||
} catch (Exception ignored) {
|
||||
SnowyCrescentCore.log.error("Failed to parse layer JSON: {}", path.toString());
|
||||
}
|
||||
}
|
||||
|
||||
animations.clear();
|
||||
AnimationRegisterEvent animationRegisterEvent = new AnimationRegisterEvent();
|
||||
MinecraftForge.EVENT_BUS.post(animationRegisterEvent);
|
||||
Map<ResourceLocation, Animation> animationMap = animationRegisterEvent.getAnimations();
|
||||
animations.putAll(animationMap);
|
||||
animations.putAll(animationsSet.stream().collect(Collectors.toMap(Animation::getKey, animation -> animation)));
|
||||
|
||||
layers.clear();
|
||||
AnimationLayerRegisterEvent layerRegisterEvent = new AnimationLayerRegisterEvent();
|
||||
MinecraftForge.EVENT_BUS.post(layerRegisterEvent);
|
||||
Map<ResourceLocation, Integer> layerMap = layerRegisterEvent.getLayers();
|
||||
layers.putAll(layerMap);
|
||||
layers.putAll(layersMap);
|
||||
}
|
||||
|
||||
public static void onPlayerLoggedIn(PlayerEvent.PlayerLoggedInEvent event) {
|
||||
if (event.getEntity() instanceof ServerPlayer serverPlayer) {
|
||||
MinecraftServer server = serverPlayer.getServer();
|
||||
if(server == null) return;
|
||||
Path dataPackPath = server.getWorldPath(LevelResource.DATAPACK_DIR);
|
||||
Path animationPath = dataPackPath.resolve("animation");
|
||||
if (!Files.exists(animationPath)) {
|
||||
try {Files.createDirectories(animationPath);}
|
||||
catch (IOException e) { return; }
|
||||
}
|
||||
ModChannel.sendToPlayer(new AnimationClientStatusPacket(AnimationClientStatusPacket.Status.ANIM_CACHE_CLEAR), serverPlayer);
|
||||
for (Animation value : animations.values()) {
|
||||
JsonElement json = AnimJson.Writer.stream(value).toJson();
|
||||
String string = json.toString();
|
||||
ModChannel.sendToPlayer(new AnimationJsonPacket(string, false), serverPlayer);
|
||||
}
|
||||
ModChannel.sendToPlayer(new AnimationClientStatusPacket(AnimationClientStatusPacket.Status.ANIM_REGISTER), serverPlayer);
|
||||
ModChannel.sendToPlayer(new AnimationClientStatusPacket(AnimationClientStatusPacket.Status.LAYER_CACHE_CLEAR), serverPlayer);
|
||||
Map<String, JsonElement> jsonElementMap = AnimLayerJson.Writer.stream(animationPath).allToJson();
|
||||
jsonElementMap.forEach((key, value) ->
|
||||
ModChannel.sendToPlayer(new AnimationJsonPacket(value.toString(), true), serverPlayer)
|
||||
);
|
||||
ModChannel.sendToPlayer(new AnimationClientStatusPacket(AnimationClientStatusPacket.Status.LAYER_REGISTER), serverPlayer);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static Set<Path> getAllFile(Path directory, Predicate<Path> filter) {
|
||||
try (Stream<Path> walk = Files.walk(directory)) {
|
||||
return walk.filter(Files::isRegularFile)
|
||||
.filter(filter)
|
||||
.collect(Collectors.toSet());
|
||||
} catch (Exception ignored) {
|
||||
return Collections.emptySet();
|
||||
}
|
||||
}
|
||||
|
||||
private static void safeUnzip(String zipFile, String destDir) {
|
||||
Path destPath = Paths.get(destDir).toAbsolutePath();
|
||||
|
||||
try (ZipFile zip = new ZipFile(zipFile)) {
|
||||
Files.createDirectories(destPath);
|
||||
Enumeration<? extends ZipEntry> entries = zip.entries();
|
||||
|
||||
while (entries.hasMoreElements()) {
|
||||
ZipEntry entry = entries.nextElement();
|
||||
Path entryPath = destPath.resolve(entry.getName()).normalize();
|
||||
|
||||
if (entry.isDirectory()) {
|
||||
Files.createDirectories(entryPath);
|
||||
} else {
|
||||
Files.createDirectories(entryPath.getParent());
|
||||
try (InputStream in = zip.getInputStream(entry);
|
||||
OutputStream out = Files.newOutputStream(entryPath, StandardOpenOption.CREATE)) {
|
||||
byte[] buffer = new byte[8192];
|
||||
int bytesRead;
|
||||
while ((bytesRead = in.read(buffer)) != -1) {
|
||||
out.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (Exception ignored) {}
|
||||
}
|
||||
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public static class ClientCache {
|
||||
private static final Map<ResourceLocation, Animation> animationsCache = new HashMap<>();
|
||||
private static final Map<ResourceLocation, Integer> layersCache = new HashMap<>();
|
||||
|
||||
public static void cacheAddAnimation(ResourceLocation location, Animation animation) {
|
||||
animationsCache.put(location, animation);
|
||||
}
|
||||
|
||||
public static void cacheAddAnimationLayer(ResourceLocation location, Integer priority) {
|
||||
layersCache.put(location, priority);
|
||||
}
|
||||
|
||||
@SuppressWarnings({"JavaReflectionMemberAccess", "UnstableApiUsage", "unchecked"})
|
||||
public static void animationStatusUpdate(AnimationClientStatusPacket.Status status) {
|
||||
switch (status) {
|
||||
case ANIM_CACHE_CLEAR -> animationsCache.clear();
|
||||
case LAYER_CACHE_CLEAR -> {
|
||||
((IMixinPlayerAnimationFactoryHolder)(PlayerAnimationFactory.ANIMATION_DATA_FACTORY))
|
||||
.sccore$clearAnimations();
|
||||
layersCache.clear();
|
||||
}
|
||||
case ANIM_REGISTER -> registerAnimations(animationsCache);
|
||||
case LAYER_REGISTER -> {
|
||||
registerLayers(layersCache);
|
||||
layersCache.forEach((key, value) ->
|
||||
PlayerAnimationFactory.ANIMATION_DATA_FACTORY.registerFactory(
|
||||
key, value, ClientCache::registerPlayerAnimation
|
||||
)
|
||||
);
|
||||
ClientLevel level = Minecraft.getInstance().level;
|
||||
if(level == null) {
|
||||
SnowyCrescentCore.log.error("{} : Level is null", ClientCache.class.getName());
|
||||
return;
|
||||
}
|
||||
for (AbstractClientPlayer player : level.players()) {
|
||||
try {
|
||||
if (player == null) throw new Exception("player is null");
|
||||
Class<?> playerClass = Player.class;
|
||||
Field animationStackField = playerClass.getDeclaredField("animationStack");
|
||||
animationStackField.setAccessible(true);
|
||||
Method createAnimationStack = playerClass.getDeclaredMethod("createAnimationStack");
|
||||
createAnimationStack.setAccessible(true);
|
||||
AnimationStack newAnimationStack = (AnimationStack) createAnimationStack.invoke(player);
|
||||
AnimationStack oldAnimationStack = (AnimationStack) animationStackField.get(player);
|
||||
Field layersField = AnimationStack.class.getDeclaredField("layers");
|
||||
layersField.setAccessible(true);
|
||||
ArrayList<Pair<Integer, IAnimation>> oldArrayList = (ArrayList<Pair<Integer, IAnimation>>) layersField.get(oldAnimationStack);
|
||||
ArrayList<Pair<Integer, IAnimation>> newArrayList = (ArrayList<Pair<Integer, IAnimation>>) layersField.get(newAnimationStack);
|
||||
ArrayList<Pair<Integer, IAnimation>> result = new ArrayList<>();
|
||||
ArrayList<Pair<Integer, IAnimation>> newListCopy = new ArrayList<>(newArrayList);
|
||||
for (Pair<Integer, IAnimation> oldPair : oldArrayList) {
|
||||
newListCopy.removeIf(pair -> {
|
||||
if(pair.getLeft().equals(oldPair.getLeft())) {
|
||||
result.add(pair);
|
||||
return true;
|
||||
} else {
|
||||
result.add(oldPair);
|
||||
return false;
|
||||
}
|
||||
});
|
||||
}
|
||||
result.addAll(newListCopy);
|
||||
layersField.set(newAnimationStack, result);
|
||||
animationStackField.set(player, newAnimationStack);
|
||||
Field animationApplierField = playerClass.getDeclaredField("animationApplier");
|
||||
animationApplierField.setAccessible(true);
|
||||
animationApplierField.set(player, new AnimationApplier(newAnimationStack));
|
||||
IAnimationCapability data = AnimationDataCapability.getCapability(player).orElse(null);
|
||||
if(data == null) return;
|
||||
Map<ResourceLocation, ResourceLocation> dataAnimations = data.getAnimations();
|
||||
ResourceLocation riderAnimLayer = data.getRiderAnimLayer();
|
||||
if(riderAnimLayer != null) {
|
||||
dataAnimations.put(riderAnimLayer, data.getRiderAnimation());
|
||||
}
|
||||
for (ResourceLocation location : dataAnimations.keySet()) {
|
||||
ModifierLayer<IAnimation> modifierLayer = (ModifierLayer<IAnimation>) PlayerAnimationAccess
|
||||
.getPlayerAssociatedData(player).get(location);
|
||||
if(modifierLayer == null) continue;
|
||||
KeyframeAnimation animation = animations.get(dataAnimations.get(location)).getAnimation();
|
||||
if(animation == null) continue;
|
||||
modifierLayer.setAnimation(new KeyframeAnimationPlayer(animation));
|
||||
}
|
||||
}catch (Exception e){
|
||||
SnowyCrescentCore.log.error("Failed to register on {} animation layer: {}", player, e.getMessage(), e);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static IAnimation registerPlayerAnimation(AbstractClientPlayer player) {
|
||||
return new ModifierLayer<>();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -1,98 +0,0 @@
|
|||
package com.linearpast.sccore.animation.registry;
|
||||
|
||||
import com.linearpast.sccore.animation.AnimationUtils;
|
||||
import com.linearpast.sccore.animation.capability.AnimationDataCapability;
|
||||
import com.linearpast.sccore.animation.capability.inter.IAnimationCapability;
|
||||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.network.toclient.AnimationCapabilityPacket;
|
||||
import com.linearpast.sccore.animation.network.toclient.SyncAnimationPacket;
|
||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRequestPacket;
|
||||
import com.linearpast.sccore.animation.network.toserver.PlayAnimationRidePacket;
|
||||
import com.linearpast.sccore.animation.network.toserver.RefreshAnimationPacket;
|
||||
import com.linearpast.sccore.capability.CapabilityUtils;
|
||||
import com.linearpast.sccore.capability.data.player.PlayerCapabilityRegistry;
|
||||
import com.linearpast.sccore.capability.network.CapabilityChannel;
|
||||
import com.linearpast.sccore.core.ModChannel;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraftforge.common.capabilities.CapabilityManager;
|
||||
import net.minecraftforge.common.capabilities.CapabilityToken;
|
||||
import net.minecraftforge.eventbus.api.IEventBus;
|
||||
import net.minecraftforge.network.NetworkDirection;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class AnimationRegistry {
|
||||
private static final Map<ResourceLocation, Animation> animations = new HashMap<>();
|
||||
|
||||
public static Map<ResourceLocation, Animation> getAnimations() {
|
||||
return animations;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public static Animation getAnimation(ResourceLocation location) {
|
||||
return animations.get(location);
|
||||
}
|
||||
|
||||
public static void registerAnimation(ResourceLocation location, Animation animation) {
|
||||
animations.put(location, animation);
|
||||
}
|
||||
|
||||
public static boolean isAnimationPresent(ResourceLocation location) {
|
||||
return animations.containsKey(location);
|
||||
}
|
||||
|
||||
public static void addAnimationListener(IEventBus forgeBus, IEventBus modBus) {
|
||||
AnimationUtils.ANIMATION_RUNNER.testLoadedAndAddListener(forgeBus, modBus);
|
||||
}
|
||||
|
||||
private static void registerAnimationCapability() {
|
||||
CapabilityChannel channel = CapabilityUtils.createChannel();
|
||||
CapabilityUtils.registerPlayerCapabilityWithNetwork(
|
||||
AnimationDataCapability.key,
|
||||
new PlayerCapabilityRegistry.CapabilityRecord<>(
|
||||
AnimationDataCapability.class,
|
||||
CapabilityManager.get(new CapabilityToken<>() {}),
|
||||
IAnimationCapability.class
|
||||
),
|
||||
channel,
|
||||
ModChannel.getAndAddCid(),
|
||||
AnimationCapabilityPacket.class,
|
||||
AnimationCapabilityPacket::new,
|
||||
AnimationCapabilityPacket::encode,
|
||||
AnimationCapabilityPacket::handle
|
||||
);
|
||||
}
|
||||
|
||||
private static void registerChannel() {
|
||||
ModChannel.INSTANCE.messageBuilder(SyncAnimationPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_CLIENT)
|
||||
.decoder(SyncAnimationPacket::new)
|
||||
.encoder(SyncAnimationPacket::encode)
|
||||
.consumerMainThread(SyncAnimationPacket::handle)
|
||||
.add();
|
||||
|
||||
ModChannel.INSTANCE.messageBuilder(PlayAnimationRequestPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.decoder(PlayAnimationRequestPacket::new)
|
||||
.encoder(PlayAnimationRequestPacket::encode)
|
||||
.consumerMainThread(PlayAnimationRequestPacket::handle)
|
||||
.add();
|
||||
ModChannel.INSTANCE.messageBuilder(PlayAnimationRidePacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.decoder(PlayAnimationRidePacket::new)
|
||||
.encoder(PlayAnimationRidePacket::encode)
|
||||
.consumerMainThread(PlayAnimationRidePacket::handle)
|
||||
.add();
|
||||
ModChannel.INSTANCE.messageBuilder(RefreshAnimationPacket.class, ModChannel.getAndAddCid(), NetworkDirection.PLAY_TO_SERVER)
|
||||
.decoder(RefreshAnimationPacket::new)
|
||||
.encoder(RefreshAnimationPacket::encode)
|
||||
.consumerMainThread(RefreshAnimationPacket::handle)
|
||||
.add();
|
||||
}
|
||||
|
||||
public static void register(){
|
||||
AnimationUtils.ANIMATION_RUNNER.testLoadedAndRun(() -> {
|
||||
registerAnimationCapability();
|
||||
registerChannel();
|
||||
});
|
||||
}
|
||||
}
|
||||
|
|
@ -24,7 +24,7 @@ import java.util.function.Supplier;
|
|||
public class CapabilityUtils {
|
||||
|
||||
/**
|
||||
* Simultaneously register player capability and corresponding network packets
|
||||
* Simultaneously invite player capability and corresponding network packets
|
||||
* @param key The unique name of capability
|
||||
* @param capabilityRecord Registration data for capability
|
||||
* @param channelRegister You should create an instance in advance to pass in, see: {@link CapabilityUtils#createChannel}
|
||||
|
|
@ -49,7 +49,7 @@ public class CapabilityUtils {
|
|||
}
|
||||
|
||||
/**
|
||||
* Simultaneously register entity capability and corresponding network packets
|
||||
* Simultaneously invite entity capability and corresponding network packets
|
||||
* @param key The unique name of capability
|
||||
* @param capabilityRecord Registration data for capability
|
||||
* @param channelRegister You should create an instance in advance to pass in, see: {@link CapabilityUtils#createChannel}
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class EntityCapabilityHandler {
|
|||
ICapabilitySync<?> capabilitySync = (ICapabilitySync<?>) record.aClass().getDeclaredConstructor().newInstance();
|
||||
event.addCapability(key, new EntityCapabilityProvider<>(key, capabilitySync));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to instantiate capability sync class {}. Your capability register is wrong.", record.aClass(), e);
|
||||
log.error("Failed to instantiate capability sync class {}. Your capability invite is wrong.", record.aClass(), e);
|
||||
}
|
||||
}
|
||||
}));
|
||||
|
|
|
|||
|
|
@ -57,7 +57,7 @@ public class PlayerCapabilityHandler {
|
|||
ICapabilitySync<?> capabilitySync = (ICapabilitySync<?>) record.aClass().getDeclaredConstructor().newInstance();
|
||||
event.addCapability(key, new PlayerCapabilityProvider<>(key, capabilitySync));
|
||||
} catch (Exception e) {
|
||||
log.error("Failed to instantiate capability sync class {}. Your capability register is wrong.", record.aClass(), e);
|
||||
log.error("Failed to instantiate capability sync class {}. Your capability invite is wrong.", record.aClass(), e);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
|
|
|||
|
|
@ -29,7 +29,7 @@ public class CapabilityChannel {
|
|||
}
|
||||
|
||||
/**
|
||||
* Add a network packet through this method and register
|
||||
* Add a network packet through this method and invite
|
||||
* @param clazz Network packet class
|
||||
* @param cid index
|
||||
* @param decoder decoder
|
||||
|
|
|
|||
|
|
@ -1,7 +1,7 @@
|
|||
package com.linearpast.sccore.core;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.animation.command.AnimationCommands;
|
||||
import com.linearpast.sccore.animation.register.AnimationCommands;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandBuildContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
|
|
|||
|
|
@ -1,20 +0,0 @@
|
|||
package com.linearpast.sccore.core;
|
||||
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
|
||||
public class ModConfigs {
|
||||
public static class Common {
|
||||
public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||
public static final ForgeConfigSpec SPEC;
|
||||
|
||||
public static final ForgeConfigSpec.ConfigValue<Boolean> enableExample;
|
||||
|
||||
static {
|
||||
BUILDER.push("Development");
|
||||
enableExample = BUILDER.comment("Enable some example for lib.")
|
||||
.define("enableExample", false);
|
||||
BUILDER.pop();
|
||||
SPEC = BUILDER.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.linearpast.sccore.core.configs;
|
||||
|
||||
import net.minecraftforge.common.ForgeConfigSpec;
|
||||
|
||||
public class ModConfigs {
|
||||
public enum ConfigName {
|
||||
inviteDuration("inviteDuration"),
|
||||
inviteDistance("inviteDistance"),
|
||||
inviteCooldown("inviteCooldown"),
|
||||
requestDuration("requestDuration"),
|
||||
requestCooldown("requestCooldown"),
|
||||
applyDistance("applyDistance"),
|
||||
applyDuration("applyDuration"),
|
||||
applyCooldown("applyCooldown"),
|
||||
;
|
||||
|
||||
private final String name;
|
||||
ConfigName(String name){
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
public String getName() {
|
||||
return name;
|
||||
}
|
||||
}
|
||||
public static class Server {
|
||||
public static final ForgeConfigSpec.Builder BUILDER = new ForgeConfigSpec.Builder();
|
||||
public static final ForgeConfigSpec SPEC;
|
||||
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> inviteDuration;
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> inviteDistance;
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> inviteCooldown;
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> requestDuration;
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> requestCooldown;
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> applyDistance;
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> applyDuration;
|
||||
public static final ForgeConfigSpec.ConfigValue<Integer> applyCooldown;
|
||||
|
||||
static {
|
||||
BUILDER.push("Animation");
|
||||
inviteDuration = BUILDER.comment("Animation invite duration. Ignore when zero. (seconds)")
|
||||
.defineInRange(ConfigName.inviteDuration.name, 120, 0, Integer.MAX_VALUE);
|
||||
inviteDistance = BUILDER.comment("Animation invite max distance. Ignore when zero. (blocks)")
|
||||
.defineInRange(ConfigName.inviteDistance.name, 6, 0, Integer.MAX_VALUE);
|
||||
inviteCooldown = BUILDER.comment("Animation invite cooldown. (seconds)")
|
||||
.defineInRange(ConfigName.inviteCooldown.name, 60, 0, Integer.MAX_VALUE);
|
||||
requestDuration = BUILDER.comment("Animation request duration. Ignore when zero (seconds)")
|
||||
.defineInRange(ConfigName.requestDuration.name, 120, 0, Integer.MAX_VALUE);
|
||||
requestCooldown = BUILDER.comment("Animation request cooldown. (seconds)")
|
||||
.defineInRange(ConfigName.requestCooldown.name, 60, 0, Integer.MAX_VALUE);
|
||||
applyDuration = BUILDER.comment("Animation apply duration. Ignore when zero. (seconds)")
|
||||
.defineInRange(ConfigName.applyDuration.name, 120, 0, Integer.MAX_VALUE);
|
||||
applyDistance = BUILDER.comment("Animation apply max distance. Ignore when zero. (blocks)")
|
||||
.defineInRange(ConfigName.applyDistance.name, 6, 0, Integer.MAX_VALUE);
|
||||
applyCooldown = BUILDER.comment("Animation apply cooldown. (seconds)")
|
||||
.defineInRange(ConfigName.applyCooldown.name, 60, 0, Integer.MAX_VALUE);
|
||||
BUILDER.pop();
|
||||
SPEC = BUILDER.build();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.linearpast.sccore.core.datagen;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.core.datagen.provider.ModLangProvider;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.DataGenerator;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraftforge.common.data.ExistingFileHelper;
|
||||
import net.minecraftforge.data.event.GatherDataEvent;
|
||||
import net.minecraftforge.eventbus.api.SubscribeEvent;
|
||||
import net.minecraftforge.fml.common.Mod;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@Mod.EventBusSubscriber(modid = SnowyCrescentCore.MODID, bus = Mod.EventBusSubscriber.Bus.MOD)
|
||||
public class DataGenEvent {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void gatherData(GatherDataEvent event) {
|
||||
DataGenerator generator = event.getGenerator();
|
||||
PackOutput packOutput = generator.getPackOutput();
|
||||
CompletableFuture<HolderLookup.Provider> lookupProvider = event.getLookupProvider();
|
||||
ExistingFileHelper helper = event.getExistingFileHelper();
|
||||
|
||||
generator.addProvider(event.includeClient(), new ModLangProvider(packOutput, ModLangProvider.Lang.EN_US));
|
||||
generator.addProvider(event.includeClient(), new ModLangProvider(packOutput, ModLangProvider.Lang.ZH_CN));
|
||||
}
|
||||
}
|
||||
238
src/main/java/com/linearpast/sccore/core/datagen/ModLang.java
Normal file
238
src/main/java/com/linearpast/sccore/core/datagen/ModLang.java
Normal file
|
|
@ -0,0 +1,238 @@
|
|||
package com.linearpast.sccore.core.datagen;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class ModLang {
|
||||
public record LangEntity<T>(T key, String zhCn, String enUs) { }
|
||||
public static final List<LangEntity<?>> langList = new ArrayList<>();
|
||||
private final static String translationString = "translation." + SnowyCrescentCore.MODID;
|
||||
private final static String command = ".command";
|
||||
private static final String animation = ".animation";
|
||||
public enum TranslatableMessage{
|
||||
COMMAND_RUN_FAIL(new LangEntity<>(
|
||||
translationString + command + animation + ".command_run_fail",
|
||||
"命令执行失败。",
|
||||
"Command run fail."
|
||||
)),
|
||||
COMMAND_RUN_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".command_run_success",
|
||||
"命令执行成功。",
|
||||
"Command run success."
|
||||
)),
|
||||
ANIMATION_NOT_PRESENT(new LangEntity<>(
|
||||
translationString + command + animation + ".animation_not_present",
|
||||
"动画不存在。",
|
||||
"Animation is not present."
|
||||
)),
|
||||
ANIMATION_LAYER_NOT_PRESENT(new LangEntity<>(
|
||||
translationString + command + animation + ".animation_layer_not_present",
|
||||
"动画层不存在。",
|
||||
"Animation layer is not present."
|
||||
)),
|
||||
PLAY_ANIMATION_FAIL(new LangEntity<>(
|
||||
translationString + command + animation + ".play_animation_fail",
|
||||
"在这些玩家上播放动画失败:%s",
|
||||
"Fail to play animation with: %s"
|
||||
)),
|
||||
PLAY_ANIMATION_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".play_animation_success",
|
||||
"在%s个玩家上播放动画成功。",
|
||||
"Successfully played animation on %s player(s)."
|
||||
)),
|
||||
REMOVE_ANIMATION_FAIL(new LangEntity<>(
|
||||
translationString + command + animation + ".remove_animation_fail",
|
||||
"在这些玩家上移除动画失败:%s",
|
||||
"Fail to remove animation with: %s"
|
||||
)),
|
||||
REMOVE_ANIMATION_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".remove_animation_success",
|
||||
"在%s个玩家上移除动画成功。",
|
||||
"Successfully removed animation on %s player(s)."
|
||||
)),
|
||||
CLEAR_ANIMATIONS(new LangEntity<>(
|
||||
translationString + command + animation + ".clear_animations",
|
||||
"动画已清除。",
|
||||
"Animation cleared."
|
||||
)),
|
||||
REFRESH_ANIMATIONS(new LangEntity<>(
|
||||
translationString + command + animation + ".refresh_animations",
|
||||
"动画同步状态已刷新。",
|
||||
"Animation refreshed."
|
||||
)),
|
||||
ACCEPT_MESSAGE_CLICK(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_message_click",
|
||||
"单击此处同意。",
|
||||
"Click here to accept."
|
||||
)),
|
||||
INVITE_MESSAGE(new LangEntity<>(
|
||||
translationString + command + animation + ".invite_message",
|
||||
"已发送邀请。",
|
||||
"Invitation sent."
|
||||
)),
|
||||
INVITED_MESSAGE(new LangEntity<>(
|
||||
translationString + command + animation + ".invited_message",
|
||||
"%s§c§l 邀请§r你进行动画:%s。",
|
||||
"%s§c§l invites§r you to animation: %s. "
|
||||
)),
|
||||
ACCEPT_INVITE_EXPIRED(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_invite_expired",
|
||||
"邀请已超时。(%s分钟)",
|
||||
"Invite expired.(%s minute(s))"
|
||||
)),
|
||||
INVITE_EXPIRED(new LangEntity<>(
|
||||
translationString + command + animation + ".invite_expired",
|
||||
"%s 接受了你的动画邀请,但是邀请超时了。(%s分钟)",
|
||||
"%s has accepted your animation invitation but the invitation has expired. (%s minute(s))"
|
||||
)),
|
||||
ACCEPT_INVITE_TOO_FAR(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_invite_too_far",
|
||||
"你们距离太远了。(%s格)",
|
||||
"You are too far apart. (%s block(s))"
|
||||
)),
|
||||
INVITE_TOO_FAR(new LangEntity<>(
|
||||
translationString + command + animation + ".invite_too_far",
|
||||
"%s 接受了你的动画邀请,但你们距离太远了。(%s格)",
|
||||
"%s has accepted your animation invitation but you are too far apart. (%s block(s))"
|
||||
)),
|
||||
ACCEPT_INVITE_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_invite_success",
|
||||
"已接受邀请。",
|
||||
"Invitation accepted."
|
||||
)),
|
||||
INVITE_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".invite_success",
|
||||
"%s 接受了你的动画邀请。",
|
||||
"%s has accepted your animation invitation."
|
||||
)),
|
||||
REQUEST_MESSAGE(new LangEntity<>(
|
||||
translationString + command + animation + ".request_message",
|
||||
"已发送请求。",
|
||||
"Request sent."
|
||||
)),
|
||||
REQUESTED_MESSAGE(new LangEntity<>(
|
||||
translationString + command + animation + ".requested_message",
|
||||
"%s§d§l 请求§r你进行动画:%s。",
|
||||
"%s§d§l requests§r you to animation: %s. "
|
||||
)),
|
||||
ACCEPT_REQUEST_EXPIRED(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_request_expired",
|
||||
"请求已超时。(%s分钟)",
|
||||
"Request expired.(%s minute(s))"
|
||||
)),
|
||||
REQUEST_EXPIRED(new LangEntity<>(
|
||||
translationString + command + animation + ".request_expired",
|
||||
"%s 接受了你的动画请求,但是请求超时了。(%s分钟)",
|
||||
"%s has accepted your animation request but the request has expired. (%s minute(s))"
|
||||
)),
|
||||
ACCEPT_REQUEST_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_request_success",
|
||||
"已接受请求。",
|
||||
"Request accepted."
|
||||
)),
|
||||
REQUEST_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".request_success",
|
||||
"%s 接受了你的动画请求。",
|
||||
"%s has accepted your animation request."
|
||||
)),
|
||||
APPLY_JOIN_MESSAGE(new LangEntity<>(
|
||||
translationString + command + animation + ".apply_join_message",
|
||||
"已发送申请。",
|
||||
"Application sent."
|
||||
)),
|
||||
APPLIED_JOIN_MESSAGE(new LangEntity<>(
|
||||
translationString + command + animation + ".applied_join_message",
|
||||
"%s§b§l 申请§r加入动画。",
|
||||
"%S§b§l Apply for §r to join your animation. "
|
||||
)),
|
||||
ACCEPT_APPLY_EXPIRED(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_apply_expired",
|
||||
"申请已超时。(%s分钟)",
|
||||
"Application expired.(%s minute(s))"
|
||||
)),
|
||||
APPLY_EXPIRED(new LangEntity<>(
|
||||
translationString + command + animation + ".apply_expired",
|
||||
"%s 接受了你的动画申请,但是申请超时了。(%s分钟)",
|
||||
"%s has accepted your animation application but the application has expired. (%s minute(s))"
|
||||
)),
|
||||
ACCEPT_APPLY_TOO_FAR(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_apply_too_far",
|
||||
"你们距离太远了。(%s格)",
|
||||
"You are too far apart. (%s block(s))"
|
||||
)),
|
||||
APPLY_TOO_FAR(new LangEntity<>(
|
||||
translationString + command + animation + ".apply_too_far",
|
||||
"%s 接受了你的动画申请,但你们距离太远了。(%s格)",
|
||||
"%s has accepted your animation application but you are too far apart. (%s block(s))"
|
||||
)),
|
||||
ACCEPT_APPLY_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".accept_apply_success",
|
||||
"%s 接受了 %s 的申请。",
|
||||
"%s has accepted the application of %s."
|
||||
)),
|
||||
APPLY_SUCCESS(new LangEntity<>(
|
||||
translationString + command + animation + ".apply_success",
|
||||
"%s 接受了你的动画申请。",
|
||||
"%s has accepted your animation application."
|
||||
)),
|
||||
WITHOUT_ANIMATION_RIDE_ENTITY(new LangEntity<>(
|
||||
translationString + animation + ".without_animation_ride_entity",
|
||||
"命令执行错误,已满人或不支持的动画。",
|
||||
"Command run fail, full or unsupported animations."
|
||||
)),
|
||||
COMMAND_COOLDOWN(new LangEntity<>(
|
||||
translationString + animation + ".command_cooldown",
|
||||
"你不能执行该指令,冷却中:%s 秒。",
|
||||
"You cannot execute this command, cooling down: %s seconds."
|
||||
)),
|
||||
ANIMATION_TO_JSON(new LangEntity<>(
|
||||
translationString + command + animation + ".animation_to_json",
|
||||
"动画%s已经存储到%s路径:",
|
||||
"The animation %s has been stored in the path on %s:"
|
||||
)),
|
||||
ANIMATION_JSON_PATH(new LangEntity<>(
|
||||
translationString + command + animation + ".animation_json_path",
|
||||
"%s",
|
||||
"%s"
|
||||
)),
|
||||
UNKNOWN_ANIMATION(new LangEntity<>(
|
||||
translationString + animation + ".unknown_animation",
|
||||
"未知的动画%s,请检查你的资源包是否完整。",
|
||||
"Unknown animation %s, please check if your resource packs is complete."
|
||||
)),
|
||||
UNSAFE_FILE_DIRECTORY(new LangEntity<>(
|
||||
translationString + command + animation + ".unsafe_file_directory",
|
||||
"你选择的文件路径并不安全",
|
||||
"%s"
|
||||
)),
|
||||
;
|
||||
|
||||
private final LangEntity<String> langEntity;
|
||||
TranslatableMessage(LangEntity<String> lang){
|
||||
this.langEntity = lang;
|
||||
}
|
||||
|
||||
public String getKey() {
|
||||
return langEntity.key;
|
||||
}
|
||||
}
|
||||
|
||||
public static void initLang() {
|
||||
langList.clear();
|
||||
|
||||
initLangMessage();
|
||||
}
|
||||
|
||||
private static void initLangMessage() {
|
||||
for (TranslatableMessage value : TranslatableMessage.values()) {
|
||||
langList.add(value.langEntity);
|
||||
}
|
||||
}
|
||||
|
||||
public static String getSoundKey(SoundEvent soundEvent){
|
||||
return "subtitle." + SnowyCrescentCore.MODID + ".sound." + soundEvent.getLocation().getPath();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,73 @@
|
|||
package com.linearpast.sccore.core.datagen.provider;
|
||||
|
||||
import com.linearpast.sccore.SnowyCrescentCore;
|
||||
import com.linearpast.sccore.core.datagen.ModLang;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.enchantment.Enchantment;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraftforge.common.data.LanguageProvider;
|
||||
|
||||
|
||||
public class ModLangProvider extends LanguageProvider {
|
||||
|
||||
private final Lang lang;
|
||||
|
||||
static {
|
||||
ModLang.initLang();
|
||||
}
|
||||
|
||||
public ModLangProvider(PackOutput output, Lang lang) {
|
||||
super(output, SnowyCrescentCore.MODID, lang.getLangName());
|
||||
this.lang = lang;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addTranslations() {
|
||||
switch (lang){
|
||||
case EN_US -> ModLang.langList.forEach(langEntity -> addTranslation(langEntity.key(), langEntity.enUs()));
|
||||
case ZH_CN -> ModLang.langList.forEach(langEntity -> addTranslation(langEntity.key(), langEntity.zhCn()));
|
||||
}
|
||||
}
|
||||
|
||||
private <T> void addTranslation(T o, String string) {
|
||||
if(o instanceof Item object){
|
||||
add(object,string);
|
||||
}else if(o instanceof Block object){
|
||||
add(object,string);
|
||||
}else if(o instanceof String object){
|
||||
add(object,string);
|
||||
}else if(o instanceof ItemStack object){
|
||||
add(object,string);
|
||||
}else if(o instanceof Enchantment object){
|
||||
add(object,string);
|
||||
}else if(o instanceof MobEffect object){
|
||||
add(object,string);
|
||||
}else if(o instanceof EntityType<?> object) {
|
||||
add(object,string);
|
||||
}else if(o instanceof SoundEvent object) {
|
||||
add(ModLang.getSoundKey(object),string);
|
||||
}else {
|
||||
throw new RuntimeException("Unknown object type: " + o.getClass());
|
||||
}
|
||||
}
|
||||
|
||||
public enum Lang{
|
||||
|
||||
ZH_CN("zh_cn"),
|
||||
EN_US("en_us"),
|
||||
;
|
||||
|
||||
private final String langName;
|
||||
Lang(String langName) {
|
||||
this.langName = langName;
|
||||
}
|
||||
public String getLangName() {
|
||||
return langName;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -5,6 +5,7 @@ import com.linearpast.sccore.animation.AnimationUtils;
|
|||
import com.linearpast.sccore.animation.data.Animation;
|
||||
import com.linearpast.sccore.animation.data.Ride;
|
||||
import com.linearpast.sccore.animation.event.create.AnimationLayerRegisterEvent;
|
||||
import com.linearpast.sccore.animation.event.create.AnimationRegisterEvent;
|
||||
import com.linearpast.sccore.example.animation.event.ExampleCommandEvent;
|
||||
import com.linearpast.sccore.example.animation.event.ExamplePlayerAttackEvent;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
|
@ -32,29 +33,48 @@ public class ModAnimation {
|
|||
public static final ResourceLocation WaltzGentleman = new ResourceLocation(SnowyCrescentCore.MODID, "waltz_gentleman");
|
||||
public static final ResourceLocation WaltzLady = new ResourceLocation(SnowyCrescentCore.MODID, "waltz_lady");
|
||||
|
||||
public static void register(IEventBus forgeBus, IEventBus modBus) {
|
||||
//You must define corresponding Animation to register
|
||||
Animation amLTRL = new Animation(AmLyingToRightLying)
|
||||
/**
|
||||
* You can register animation layer by event or json <br>
|
||||
* See wiki (If I'm done.)
|
||||
* @param event event
|
||||
*/
|
||||
public static void onLayerRegister(AnimationLayerRegisterEvent event) {
|
||||
event.registerLayer(normalLayers, 42);
|
||||
}
|
||||
|
||||
/**
|
||||
* You can register animation by event or json <br>
|
||||
* See wiki (If I'm done.)
|
||||
* @param event event
|
||||
*/
|
||||
public static void onAnimationRegister(AnimationRegisterEvent event) {
|
||||
//You must define corresponding Animation to invite
|
||||
Animation amLTRL = Animation.create(AmLyingToRightLying)
|
||||
.withLyingType(Animation.LyingType.RIGHT)
|
||||
.withRide(Ride.create().addComponentAnimation(AmStandToLying));
|
||||
Animation amSTL = new Animation(AmStandToLying)
|
||||
.withName("Lying-to-Right-Lying");
|
||||
Animation amSTL = Animation.create(AmStandToLying)
|
||||
.withName("Stand-to-Lying")
|
||||
.withLyingType(Animation.LyingType.FRONT);
|
||||
|
||||
Animation waltzGentleman = new Animation(WaltzGentleman)
|
||||
Animation waltzGentleman = Animation.create(WaltzGentleman)
|
||||
.withName("Waltz-Gentleman")
|
||||
.withRide(Ride.create().addComponentAnimation(WaltzLady));
|
||||
Animation waltzLady = new Animation(WaltzLady)
|
||||
.withCamYaw(180);
|
||||
|
||||
//You can use it to register an Animation
|
||||
AnimationUtils.registerAnimation(AmLyingToRightLying, amLTRL);
|
||||
AnimationUtils.registerAnimation(AmStandToLying, amSTL);
|
||||
AnimationUtils.registerAnimation(WaltzGentleman, waltzGentleman);
|
||||
AnimationUtils.registerAnimation(WaltzLady, waltzLady);
|
||||
Animation waltzLady = Animation.create(WaltzLady)
|
||||
.withName("Waltz-Lady")
|
||||
.withCamYaw(180)
|
||||
.withRide(Ride.create().addComponentAnimation(WaltzGentleman));
|
||||
|
||||
//You can use it to invite an Animation
|
||||
event.registerAnimation(AmLyingToRightLying, amLTRL);
|
||||
event.registerAnimation(AmStandToLying, amSTL);
|
||||
event.registerAnimation(WaltzGentleman, waltzGentleman);
|
||||
event.registerAnimation(WaltzLady, waltzLady);
|
||||
}
|
||||
|
||||
public static void register(IEventBus forgeBus, IEventBus modBus) {
|
||||
//Register by event
|
||||
//Or use AnimationUtils.registerAnimationLayer(ResourceLocation layer, int priority);
|
||||
modBus.addListener(ModAnimation::onLayerRegister);
|
||||
forgeBus.addListener(ModAnimation::onLayerRegister);
|
||||
forgeBus.addListener(ModAnimation::onAnimationRegister);
|
||||
|
||||
//Try to play animation
|
||||
forgeBus.addListener(ExamplePlayerAttackEvent::onPlayerAttack);
|
||||
|
|
@ -63,8 +83,4 @@ public class ModAnimation {
|
|||
forgeBus.addListener(ExamplePlayerAttackEvent::onInputEvent);
|
||||
}
|
||||
}
|
||||
|
||||
public static void onLayerRegister(AnimationLayerRegisterEvent event) {
|
||||
event.putLayer(normalLayers, 42);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -23,6 +23,7 @@ import java.util.UUID;
|
|||
import static net.minecraft.commands.Commands.argument;
|
||||
import static net.minecraft.commands.Commands.literal;
|
||||
|
||||
@Deprecated
|
||||
public class ExampleCommandEvent {
|
||||
record InviteRecord(long time, ResourceLocation layer, ResourceLocation animation, boolean isForce){}
|
||||
private static final Map<UUID, Map<UUID, InviteRecord>> invites = new HashMap<>();
|
||||
|
|
|
|||
|
|
@ -16,8 +16,7 @@ import net.minecraftforge.event.entity.player.AttackEntityEvent;
|
|||
|
||||
public class ExamplePlayerAttackEvent {
|
||||
/**
|
||||
* when attack sheep, will play stand to lying animation <br>
|
||||
* when attack other player, will play animation together
|
||||
* when attack sheep, will play stand to lying animation
|
||||
* @param event event
|
||||
*/
|
||||
public static void onPlayerAttack(AttackEntityEvent event) {
|
||||
|
|
@ -32,18 +31,7 @@ public class ExamplePlayerAttackEvent {
|
|||
AnimationUtils.playAnimation(player, ModAnimation.normalLayers, null);
|
||||
}
|
||||
}
|
||||
if(target instanceof ServerPlayer serverPlayer) {
|
||||
AnimationUtils.startAnimationTogether(
|
||||
serverPlayer,
|
||||
ModAnimation.normalLayers,
|
||||
ModAnimation.AmLyingToRightLying,
|
||||
true,
|
||||
player
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -23,11 +23,11 @@ public class ModCapability {
|
|||
* @see CapabilityUtils#registerPlayerCapabilityWithNetwork
|
||||
*/
|
||||
public static void register(){
|
||||
//If you want to register network packets in your own mod, to use : createChannel(INSTANCE)
|
||||
//If you want to invite network packets in your own mod, to use : createChannel(INSTANCE)
|
||||
//And don't forget to rewrite all the sendToClient methods in the capability class
|
||||
CapabilityChannel channel = CapabilityUtils.createChannel();
|
||||
//Register the entity capability and its network packet
|
||||
//If you want register about player, please use CapabilityUtils.registerPlayerCapabilityWithNetwork()
|
||||
//If you want invite about player, please use CapabilityUtils.registerPlayerCapabilityWithNetwork()
|
||||
CapabilityUtils.registerEntityCapabilityWithNetwork(
|
||||
//A resourceLocation, named arbitrarily without repetition
|
||||
SheepDataCapability.key,
|
||||
|
|
|
|||
|
|
@ -5,7 +5,7 @@ import net.minecraft.world.entity.animal.Sheep;
|
|||
|
||||
/**
|
||||
* The interface inheritance ICapabilitySync is required, but the interface is not necessary (you can directly use the cap class itself during registration) <br>
|
||||
* Common methods for sharing caps that may be used.
|
||||
* Server methods for sharing caps that may be used.
|
||||
*/
|
||||
public interface ISheepData extends ICapabilitySync<Sheep> {
|
||||
Integer getValue();
|
||||
|
|
|
|||
|
|
@ -0,0 +1,62 @@
|
|||
package com.linearpast.sccore.mixin.animation.client;
|
||||
|
||||
import com.linearpast.sccore.animation.mixin.IMixinPlayerAnimationFactoryHolder;
|
||||
import dev.kosmx.playerAnim.api.layered.AnimationStack;
|
||||
import dev.kosmx.playerAnim.api.layered.IAnimation;
|
||||
import dev.kosmx.playerAnim.minecraftApi.PlayerAnimationFactory;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Function;
|
||||
|
||||
@Mixin(PlayerAnimationFactory.FactoryHolder.class)
|
||||
public class MixinPlayerAnimationFactoryHolder implements IMixinPlayerAnimationFactoryHolder {
|
||||
@Unique
|
||||
@Final
|
||||
private static List<Function<AbstractClientPlayer, DataHolder>> sccore$factories = new ArrayList<>();
|
||||
|
||||
@Inject(
|
||||
method = "prepareAnimations",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true,
|
||||
remap = false
|
||||
)
|
||||
private void prepareAnimations(AbstractClientPlayer player, AnimationStack playerStack, Map<ResourceLocation, IAnimation> animationMap, CallbackInfo ci) {
|
||||
for (Function<AbstractClientPlayer, DataHolder> factory: sccore$factories) {
|
||||
DataHolder dataHolder = factory.apply(player);
|
||||
if (dataHolder != null) {
|
||||
playerStack.addAnimLayer(dataHolder.priority(), dataHolder.animation());
|
||||
if (dataHolder.id() != null) {
|
||||
animationMap.put(dataHolder.id(), dataHolder.animation());
|
||||
}
|
||||
}
|
||||
}
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "registerFactory",
|
||||
at = @At("HEAD"),
|
||||
cancellable = true,
|
||||
remap = false
|
||||
)
|
||||
private void registerFactory(ResourceLocation id, int priority, PlayerAnimationFactory factory, CallbackInfo ci) {
|
||||
sccore$factories.add(player -> Optional.ofNullable(factory.invoke(player)).map(animation -> new DataHolder(id, priority, animation)).orElse(null));
|
||||
ci.cancel();
|
||||
}
|
||||
|
||||
@Unique
|
||||
public void sccore$clearAnimations() {
|
||||
sccore$factories.clear();
|
||||
}
|
||||
}
|
||||
|
|
@ -32,4 +32,11 @@ modId = "playeranimator"
|
|||
mandatory = false
|
||||
versionRange = "[1.0.1,)"
|
||||
ordering = "AFTER"
|
||||
side = "BOTH"
|
||||
|
||||
[[dependencies."${mod_id}"]]
|
||||
modId = "bendylib"
|
||||
mandatory = false
|
||||
versionRange = "[4.0.0,)"
|
||||
ordering = "AFTER"
|
||||
side = "BOTH"
|
||||
|
|
@ -6,7 +6,8 @@
|
|||
"refmap": "sccore.refmap.json",
|
||||
"plugin": "com.linearpast.sccore.mixin.SCCoreMixinPlugin",
|
||||
"mixins": [
|
||||
"animation.MixinEntity"
|
||||
"animation.MixinEntity",
|
||||
"animation.client.MixinPlayerAnimationFactoryHolder"
|
||||
],
|
||||
"client": [
|
||||
"animation.client.MixinEntity",
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user