init 1.21.5
This commit is contained in:
commit
c3bff64c61
|
|
@ -0,0 +1,125 @@
|
|||
package com.r3944realms.leashedplayer;
|
||||
|
||||
import com.r3944realms.leashedplayer.client.renderer.LeashRendererUtil;
|
||||
import com.r3944realms.leashedplayer.client.renderer.PlayerLeashState;
|
||||
import com.r3944realms.leashedplayer.client.renderer.entities.ChestItemLayerRenderer;
|
||||
import com.r3944realms.leashedplayer.client.renderer.entities.LeashRopeArrowRenderer;
|
||||
import com.r3944realms.leashedplayer.client.renderer.entities.SpectralLeashRopeArrowRenderer;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.ConditionalRangeItemModel;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.properties.conditional.ChargeExtend;
|
||||
import com.r3944realms.leashedplayer.content.ModKeyMapping;
|
||||
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
|
||||
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import com.r3944realms.leashedplayer.network.server.Code;
|
||||
import com.r3944realms.leashedplayer.network.server.DecreaseLeashRopeLength;
|
||||
import com.r3944realms.leashedplayer.network.server.IncreaseLeashRopeLength;
|
||||
import com.r3944realms.leashedplayer.utils.Util;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.player.LocalPlayer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
|
||||
import net.minecraft.client.resources.PlayerSkin;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.HitResult;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.client.event.*;
|
||||
import net.neoforged.neoforge.network.PacketDistributor;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
|
||||
public class ClientEventHandler {
|
||||
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.GAME, modid = LeashedPlayer.MOD_ID)
|
||||
public static class Game {
|
||||
@SubscribeEvent
|
||||
public static void onPlayerRendererEventPre(RenderPlayerEvent.Post event) {
|
||||
PlayerRenderState renderState = event.getRenderState();
|
||||
PlayerLeashState playerLeashState = ((IPlayerRenderStateExtension) renderState).getPlayerLeashState();
|
||||
if(playerLeashState != null) {
|
||||
if (playerLeashState.vanilaLeashState != null)
|
||||
LeashRendererUtil.renderLeash(event.getPoseStack(), event.getMultiBufferSource(), playerLeashState.vanilaLeashState);
|
||||
else
|
||||
LeashRendererUtil.renderLeash(event.getPoseStack(), event.getMultiBufferSource(), renderState);
|
||||
}
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void onKetBoardInput(InputEvent.Key event) {
|
||||
Minecraft minecraft = Minecraft.getInstance();
|
||||
LocalPlayer player = minecraft.player;
|
||||
assert player != null;
|
||||
if (ModKeyMapping.KEY_ADD_LEASH_LENGTH.isDown()) {
|
||||
PlayerLeashable playerLeashable = (PlayerLeashable) player;
|
||||
if (playerLeashable.getLeashDataFromEntityData() == null) {
|
||||
assert minecraft.level != null;
|
||||
List<HitResult> refLookAtEntityHitResult = Util.getRefLookAtEntityHitResult(player, minecraft.level, 32, entity -> entity instanceof LivingEntity);
|
||||
Entity theNearestEntityFromHitResultList = Util.getTheNearestEntityFromHitResultList(player, refLookAtEntityHitResult);
|
||||
if(theNearestEntityFromHitResultList != null) {
|
||||
if (theNearestEntityFromHitResultList instanceof Player refPlayer) {
|
||||
PacketDistributor.sendToServer(new IncreaseLeashRopeLength(Code.OTHER_ST, refPlayer.getStringUUID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playerLeashable.getLeashDataFromEntityData() != null) {
|
||||
PacketDistributor.sendToServer(new IncreaseLeashRopeLength(Code.SELF, player.getStringUUID()));
|
||||
}
|
||||
}
|
||||
if (ModKeyMapping.KEY_SUB_LEASH_LENGTH.isDown()) {
|
||||
PlayerLeashable playerLeashable = (PlayerLeashable) player;
|
||||
if (playerLeashable.getLeashDataFromEntityData() == null) {
|
||||
assert minecraft.level != null;
|
||||
List<HitResult> refLookAtEntityHitResult = Util.getRefLookAtEntityHitResult(player, minecraft.level, 32, entity -> entity instanceof LivingEntity);
|
||||
Entity theNearestEntityFromHitResultList = Util.getTheNearestEntityFromHitResultList(player, refLookAtEntityHitResult);
|
||||
if(theNearestEntityFromHitResultList != null) {
|
||||
if (theNearestEntityFromHitResultList instanceof Player refPlayer) {
|
||||
PacketDistributor.sendToServer(new DecreaseLeashRopeLength(Code.OTHER_ST, refPlayer.getStringUUID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
if (playerLeashable.getLeashDataFromEntityData() != null) {
|
||||
PacketDistributor.sendToServer(new DecreaseLeashRopeLength(Code.SELF, player.getStringUUID()));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@EventBusSubscriber(value = Dist.CLIENT, bus = EventBusSubscriber.Bus.MOD, modid = LeashedPlayer.MOD_ID)
|
||||
public static class Mod {
|
||||
@SubscribeEvent
|
||||
public static void onRegisterItemModels(RegisterItemModelsEvent event) {
|
||||
event.register(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "conditional_range"), ConditionalRangeItemModel.Unbaked.MAP_CODEC);
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void registrySelectItemModelProperty(RegisterSelectItemModelPropertyEvent event) {
|
||||
event.register(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "charge_extend_type"), ChargeExtend.TYPE);
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void registerKeyMapping(RegisterKeyMappingsEvent event) {
|
||||
event.register(ModKeyMapping.KEY_ADD_LEASH_LENGTH);
|
||||
event.register(ModKeyMapping.KEY_SUB_LEASH_LENGTH);
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void onAddLayers (EntityRenderersEvent.AddLayers event){
|
||||
PlayerRenderer renderer = event.getSkin(PlayerSkin.Model.WIDE);
|
||||
if (renderer instanceof PlayerRenderer playerRenderer) {
|
||||
playerRenderer.addLayer(new ChestItemLayerRenderer<>(playerRenderer, event.getContext().getEntityRenderDispatcher().getItemInHandRenderer()));
|
||||
}
|
||||
PlayerRenderer slimRenderer = event.getSkin(PlayerSkin.Model.SLIM);
|
||||
if (slimRenderer instanceof PlayerRenderer slimPlayerRenderer) {
|
||||
slimPlayerRenderer.addLayer(new ChestItemLayerRenderer<>(slimPlayerRenderer, event.getContext().getEntityRenderDispatcher().getItemInHandRenderer()));
|
||||
}
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void RegisterRenderer(EntityRenderersEvent.RegisterRenderers event) {
|
||||
event.registerEntityRenderer(ModEntityRegister.LEASH_ROPE_ARROW.get(), LeashRopeArrowRenderer::new);
|
||||
event.registerEntityRenderer(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), SpectralLeashRopeArrowRenderer::new);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,108 @@
|
|||
package com.r3944realms.leashedplayer;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
|
||||
import com.r3944realms.leashedplayer.content.commands.MotionCommand;
|
||||
import com.r3944realms.leashedplayer.content.commands.TickCommand;
|
||||
import com.r3944realms.leashedplayer.content.effects.ModPotionRegister;
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.content.misc.LeadBreakItemBehavior;
|
||||
import com.r3944realms.leashedplayer.utils.Util;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.animal.Fox;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.PotionBrewing;
|
||||
import net.minecraft.world.item.alchemy.Potions;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
import net.neoforged.neoforge.event.AnvilUpdateEvent;
|
||||
import net.neoforged.neoforge.event.RegisterCommandsEvent;
|
||||
import net.neoforged.neoforge.event.brewing.RegisterBrewingRecipesEvent;
|
||||
import net.neoforged.neoforge.event.tick.EntityTickEvent;
|
||||
|
||||
|
||||
public class CommonEventHandler {
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID)
|
||||
public static class Game extends CommonEventHandler {
|
||||
@SubscribeEvent
|
||||
public static void onRegisterCommander(RegisterCommandsEvent event) {
|
||||
CommandDispatcher<CommandSourceStack> dispatcher = event.getDispatcher();
|
||||
LeashCommand.register(dispatcher);
|
||||
MotionCommand.register(dispatcher);
|
||||
TickCommand.register(dispatcher);
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void OnRegisterPotionBrewing(RegisterBrewingRecipesEvent event) {
|
||||
PotionBrewing.Builder builder = event.getBuilder();
|
||||
builder.addMix(Potions.WATER, Items.SLIME_BALL, ModPotionRegister.NO_LEASH);
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void OnLivingTickEvent(EntityTickEvent.Post event) {
|
||||
Entity entity = event.getEntity();
|
||||
Level level = entity.level();
|
||||
if (level.isClientSide()) {
|
||||
return;
|
||||
}
|
||||
if (entity instanceof Fox fox) {
|
||||
if (fox.getMainHandItem().is(ItemTags.ANVIL)) {
|
||||
fox.setItemSlot(EquipmentSlot.MAINHAND, ItemStack.EMPTY);
|
||||
Util.throwItemTowardsLook(fox, ModItemRegister.NEOFORGE.get(), 0.3f, 0.1f);
|
||||
fox.playSound(SoundEvents.FOX_EAT);
|
||||
} else if (fox.getMainHandItem().is(ModItemRegister.NEOFORGE.get())) {
|
||||
// 繞圈參數
|
||||
float rotationSpeed = 10.0f; // 每 tick 旋轉的角度
|
||||
// 計算新的旋轉角度
|
||||
fox.yBodyRot += rotationSpeed; // 身體旋轉
|
||||
fox.yHeadRot += rotationSpeed; // 頭部旋轉
|
||||
fox.yRotO += rotationSpeed; // 當前旋轉角度
|
||||
fox.yHeadRotO += rotationSpeed; // 頭部的當前旋轉角度
|
||||
|
||||
// 確保旋轉角度不超出 360 度,重置為 0 以便持續旋轉
|
||||
if (fox.yBodyRot >= 360) fox.yBodyRot -= 360;
|
||||
if (fox.yHeadRot >= 360) fox.yHeadRot -= 360;
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void OnAnvilUpdated(AnvilUpdateEvent event) {
|
||||
String name = event.getName();
|
||||
ItemStack left = event.getLeft();
|
||||
if (left.is(Items.ANVIL) && name != null && name.equals("NeoForge")) {
|
||||
event.setCost(1);
|
||||
event.setOutput(ModItemRegister.NEOFORGE.get().getDefaultInstance());
|
||||
} else if (left.is(ModItemRegister.NEOFORGE.get().asItem()) && name != null && name.equals("Forge")) {
|
||||
ItemStack instance = Items.ANVIL.getDefaultInstance();
|
||||
instance.set(DataComponents.CUSTOM_NAME, Component.literal("Forge").withStyle(ChatFormatting.BOLD).withStyle(ChatFormatting.AQUA));
|
||||
event.setOutput(instance);
|
||||
event.setCost(1);
|
||||
}
|
||||
}
|
||||
}
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
|
||||
public static class Mod extends CommonEventHandler {
|
||||
@SubscribeEvent
|
||||
public static void onCommonSetup(FMLCommonSetupEvent event) {
|
||||
event.enqueueWork(() -> {
|
||||
DispenserBlock.registerProjectileBehavior(ModItemRegister.LEASH_ROPE_ARROW.get());
|
||||
DispenserBlock.registerProjectileBehavior(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get());
|
||||
DispenserBlock.registerProjectileBehavior(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get());
|
||||
DispenserBlock.registerBehavior(ModItemRegister.AMETHYST_SHEARS.get(), new LeadBreakItemBehavior());
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,70 @@
|
|||
package com.r3944realms.leashedplayer;
|
||||
|
||||
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
|
||||
import com.r3944realms.leashedplayer.content.criteriaTriggers.ModCriteriaTriggers;
|
||||
import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
|
||||
import com.r3944realms.leashedplayer.content.effects.ModPotionRegister;
|
||||
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
|
||||
import com.r3944realms.leashedplayer.content.items.ModCreativeTab;
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.content.items.repcipe.ModRecipeRegister;
|
||||
import com.r3944realms.leashedplayer.content.paintings.ModPaintingsRegister;
|
||||
import com.r3944realms.leashedplayer.content.sounds.ModSoundRegister;
|
||||
import com.r3944realms.leashedplayer.utils.Util;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.fml.ModLoadingContext;
|
||||
import net.neoforged.fml.common.Mod;
|
||||
import net.neoforged.fml.config.ModConfig;
|
||||
|
||||
import static com.r3944realms.leashedplayer.utils.Logger.logger;
|
||||
@Mod(LeashedPlayer.MOD_ID)
|
||||
public class LeashedPlayer {
|
||||
public static final String MOD_ID = "leashedplayer";
|
||||
private static Double M1;//拴繩掉落距離倍基數
|
||||
private static Double M2;//繩箭拴繩掉落距離倍基數
|
||||
private static Integer M3; //拴绳最小长度
|
||||
private static Integer M4; //拴绳最大长度
|
||||
public LeashedPlayer(IEventBus event) {
|
||||
ModItemRegister.register(event);
|
||||
ModRecipeRegister.register(event);
|
||||
ModSoundRegister.register(event);
|
||||
ModPaintingsRegister.register(event);
|
||||
ModEffectRegister.register(event);
|
||||
ModPotionRegister.register(event);
|
||||
ModEntityRegister.register(event);
|
||||
ModCreativeTab.register(event);
|
||||
ModCriteriaTriggers.register(event);
|
||||
initiation();
|
||||
}
|
||||
private void initiation() {
|
||||
logger.info("Initializing LeashedPlayer Mod");
|
||||
String leashedPlayerCommonConfig = "LeashedPlayerCommonConfig";
|
||||
Util.configFileCreate(new String[]{leashedPlayerCommonConfig});
|
||||
ModLoadingContext.get().getActiveContainer().registerConfig(ModConfig.Type.COMMON, LeashPlayerCommonConfig.SPEC, MOD_ID + "/" + leashedPlayerCommonConfig + "/LeashPlayer.toml");
|
||||
}
|
||||
public static Double M1() {
|
||||
if(M1 == null) {
|
||||
M1 = LeashPlayerCommonConfig.TheLeashBreakLengthTimesBase.get();
|
||||
}
|
||||
return M1;
|
||||
}
|
||||
public static Double M2() {
|
||||
if(M2 == null) {
|
||||
M2 = LeashPlayerCommonConfig.TheMultipleThatLeashRopeArrowBreakLength.get();
|
||||
}
|
||||
return M2;
|
||||
}
|
||||
public static Integer M3() {
|
||||
if(M3 == null) {
|
||||
M3 = LeashPlayerCommonConfig.MinimumLeashLengthCanBeSet.get();
|
||||
}
|
||||
return M3;
|
||||
}
|
||||
public static Integer M4() {
|
||||
if(M4 == null) {
|
||||
M4 = LeashPlayerCommonConfig.MaximumLeashLengthCanBeSet.get();
|
||||
}
|
||||
return M4;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.r3944realms.leashedplayer.client.processBar;
|
||||
|
||||
/**
|
||||
* 进度条
|
||||
|
||||
*/
|
||||
public interface IProcessBar {
|
||||
/**
|
||||
*
|
||||
* @return 存活计数 (<=0 则会被清除)
|
||||
*/
|
||||
int aliveCount();
|
||||
/**
|
||||
* 维持计数
|
||||
*/
|
||||
void retain();
|
||||
void decreaseAliveCount();
|
||||
void setRenderStatus(boolean status);
|
||||
boolean shouldRender();
|
||||
int getCurrentProcess();
|
||||
int getMaxProcess();
|
||||
void setMaxProcess(int maxProcess);
|
||||
void setProcess(int process);
|
||||
void resetProcess();
|
||||
|
||||
/**
|
||||
* 完成进度条执行的任务,由实现者实现
|
||||
*/
|
||||
void completeTask();
|
||||
default void decrease() {
|
||||
int updateValue = getCurrentProcess() - 1;
|
||||
if(updateValue < 0) {
|
||||
setRenderStatus(false);
|
||||
setProcess(0);
|
||||
}
|
||||
else {
|
||||
setRenderStatus(true);
|
||||
setProcess(updateValue);
|
||||
}
|
||||
}
|
||||
default void increase() {
|
||||
int updateValue = getCurrentProcess() + 1;
|
||||
if(updateValue > getMaxProcess()) {
|
||||
setRenderStatus(false);
|
||||
setProcess(getMaxProcess());
|
||||
completeTask();//执行任务
|
||||
}
|
||||
else {
|
||||
setRenderStatus(true);
|
||||
setProcess(updateValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,92 @@
|
|||
package com.r3944realms.leashedplayer.client.processBar;
|
||||
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.network.chat.ChatType;
|
||||
import net.minecraft.network.chat.Component;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class TestProcessBar implements IProcessBar {
|
||||
private int aliveCount = 0;
|
||||
private boolean isRendering;
|
||||
private int maxProgress;
|
||||
private int progress;
|
||||
public TestProcessBar() {
|
||||
aliveCount++;
|
||||
isRendering = false;
|
||||
maxProgress = 100;
|
||||
progress = 0;
|
||||
}
|
||||
public TestProcessBar(int maxProgress) {
|
||||
aliveCount++;
|
||||
isRendering = false;
|
||||
this.maxProgress = maxProgress;
|
||||
progress = 0;
|
||||
}
|
||||
public TestProcessBar(int maxProgress, int progress) {
|
||||
aliveCount++;
|
||||
isRendering = false;
|
||||
this.maxProgress = maxProgress;
|
||||
this.progress = progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int aliveCount() {
|
||||
return aliveCount;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void retain() {
|
||||
aliveCount++;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void decreaseAliveCount() {
|
||||
aliveCount = aliveCount > 0 ? aliveCount - 1 : 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setRenderStatus(boolean status) {
|
||||
isRendering = status;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldRender() {
|
||||
return isRendering;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCurrentProcess() {
|
||||
return progress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getMaxProcess() {
|
||||
return maxProgress;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setMaxProcess(int maxProcess) {
|
||||
this.maxProgress = maxProcess;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcess(int process) {
|
||||
this.progress = process < 0 ? 0 : (Math.min(process, maxProgress));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resetProcess() {
|
||||
this.progress = 0;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void completeTask() {
|
||||
Runnable runnable = () -> {
|
||||
if (Minecraft.getInstance().player != null) {
|
||||
Minecraft.getInstance().getChatListener().handleDisguisedChatMessage(Component.literal("Completed"), ChatType.bind(ChatType.MSG_COMMAND_OUTGOING, Minecraft.getInstance().player));
|
||||
}
|
||||
};
|
||||
CompletableFuture.runAsync(runnable);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,540 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.blaze3d.vertex.VertexConsumer;
|
||||
import com.mojang.datafixers.util.Either;
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.LightTexture;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderType;
|
||||
import net.minecraft.client.renderer.entity.state.EntityRenderState;
|
||||
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.vehicle.AbstractMinecart;
|
||||
import net.minecraft.world.entity.vehicle.NewMinecartBehavior;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.LightLayer;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import org.joml.Matrix4f;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.UUID;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class LeashRendererUtil {
|
||||
public static void renderLeash(PoseStack poseStack, MultiBufferSource buffer, EntityRenderState.LeashState leashState) {
|
||||
float f = 0.025F;
|
||||
|
||||
float f1 = (float)(leashState.end.x - leashState.start.x);
|
||||
float f2 = (float)(leashState.end.y - leashState.start.y + 0.2);
|
||||
float f3 = (float)(leashState.end.z - leashState.start.z);
|
||||
float f4 = Mth.invSqrt(f1 * f1 + f3 * f3) * 0.025F / 2.0F;
|
||||
float f5 = f3 * f4;
|
||||
float f6 = f1 * f4;
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(leashState.offset.add(0, -0.2, -0.2));
|
||||
VertexConsumer vertexconsumer = buffer.getBuffer(RenderType.leash());
|
||||
Matrix4f matrix4f = poseStack.last().pose();
|
||||
|
||||
for (int i = 0; i <= 24; i++) {
|
||||
addVertexPair(
|
||||
vertexconsumer,
|
||||
matrix4f,
|
||||
f1,
|
||||
f2,
|
||||
f3,
|
||||
leashState.startBlockLight,
|
||||
leashState.endBlockLight,
|
||||
leashState.startSkyLight,
|
||||
leashState.endSkyLight,
|
||||
0.025F,
|
||||
0.025F,
|
||||
f5,
|
||||
f6,
|
||||
i,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
for (int j = 24; j >= 0; j--) {
|
||||
addVertexPair(
|
||||
vertexconsumer,
|
||||
matrix4f,
|
||||
f1,
|
||||
f2,
|
||||
f3,
|
||||
leashState.startBlockLight,
|
||||
leashState.endBlockLight,
|
||||
leashState.startSkyLight,
|
||||
leashState.endSkyLight,
|
||||
0.025F,
|
||||
0.0F,
|
||||
f5,
|
||||
f6,
|
||||
j,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
/**
|
||||
* <h1>1. 角度与弧度转换</h1>
|
||||
* {@snippet lang=java :
|
||||
* double d0 = (double)(pEntity.getPreciseBodyRotation(pPartialTick) * (float)(Math.PI / 180.0)) + (Math.PI / 2);
|
||||
* }
|
||||
* <ul>
|
||||
* <li><code>pEntity.getPreciseBodyRotation(pPartialTick)</code> 返回实体的旋转角度(通常是以度为单位)。/li>
|
||||
* <li> <code>(Math.PI / 180.0)</code> 是将度数转换为弧度的乘数,因为大多数三角函数(如 <code>cos</code> 和 <code>sin</code>)都需要弧度值。</li>
|
||||
* <li><code>+ (Math.PI / 2)</code> 用于将结果平移90度(四分之一圆),可能是为了校正方向或设置起始方向。 </li>
|
||||
* </ul>
|
||||
*
|
||||
* <p>
|
||||
* <h1> 2. 三角函数计算位移</h1>
|
||||
* {@snippet lang=java :
|
||||
* double d1 = Math.cos(d0) * vec31.z + Math.sin(d0) * vec31.x;
|
||||
* double d2 = Math.sin(d0) * vec31.z - Math.cos(d0) * vec31.x;
|
||||
* }
|
||||
* <ul>
|
||||
* <li><code>d1</code> 和 <code>d2</code> 是利用三角函数 <code>cos</code> 和 <code>sin</code> 计算出来的位移量,用于确定实体相对于其旋转的实际位置。</li>
|
||||
* <li><code>Math.cos(d0) * vec31.z</code> 和 <code>Math.sin(d0) * vec31.x</code> 分别计算沿 X 和 Z 轴的位移分量,这种计算通常用于旋转一个点或向量。</li>
|
||||
* <li>两个公式结合起来用于旋转平面内的一个点 <code>(vec31.x, vec31.z)</code>,从而得到旋转后的新坐标。</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <h1> 3. 线性插值 (Lerp) </h1>
|
||||
* {@snippet lang=java :
|
||||
* double d3 = Mth.lerp(pPartialTick, pEntity.xo, pEntity.getX()) + d1;
|
||||
* double d4 = Mth.lerp(pPartialTick, pEntity.yo, pEntity.getY()) + vec31.y;
|
||||
* double d5 = Mth.lerp(pPartialTick, pEntity.zo, pEntity.getZ()) + d2;
|
||||
* }
|
||||
* <ul>
|
||||
* <li><code>Mth.lerp</code> 是线性插值函数,通常用于在两个值之间平滑过渡。</li>
|
||||
* <li><code>pEntity.xo</code>, <code>pEntity.yo</code>, <code>pEntity.zo</code> 是实体在上一个刻度(tick)中的位置,而 <code>pEntity.getX()</code>, <code>pEntity.getY()</code>, <code>pEntity.getZ()</code> 是当前刻度的位置。</li>
|
||||
* <li><code>pPartialTick</code> 介于 <code>0</code> 和 <code>1</code> 之间,用来平滑过渡,使得动画更加流畅。</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <h1> 4. 向量差值 </h1>
|
||||
* {@snippet lang=java :
|
||||
* float f = (float)(vec3.x - d3);
|
||||
* float f1 = (float)(vec3.y - d4);
|
||||
* float f2 = (float)(vec3.z - d5);
|
||||
* }
|
||||
* <ul>
|
||||
* <li>计算两个点(<code>vec3</code> 和 <code>(d3, d4, d5)</code>)之间的差值,得到的 <code>f</code>,<code>f1</code>,<code>f2</code> 是向量差,用于后续的渲染计算。</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <h1> 5. 逆平方根与比例因子 </h1>
|
||||
* {@snippet lang=java :
|
||||
* float f4 = Mth.invSqrt(f * f + f2 * f2) * 0.025F / 2.0F;
|
||||
* }
|
||||
* <ul>
|
||||
* <li><code>Mth.invSqrt</code> 计算的是逆平方根(通常用于归一化向量或调整比例)。</li>
|
||||
* <li><code>f * f + f2 * f2</code> 是计算向量 <code>(f, f2)</code> 的平方和,用于得到其长度的平方。</li>
|
||||
* <li>乘以 <code>0.025F / 2.0F</code> 用于缩放结果,使得线条在渲染时具有合适的比例。</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <h1> 6. 循环绘制 </h1>
|
||||
* {@snippet lang=java :
|
||||
* for (int i1 = 0; i1 <= 24; i1++) {
|
||||
* addVertexPair(vertexconsumer, matrix4f, f, f1, f2, i, j, k, l, 0.025F, 0.025F, f5, f6, i1, false);
|
||||
* }
|
||||
* }
|
||||
* <ul>
|
||||
* <li>循环从 <code>0</code> 到 <code>24</code>,用于创建24个顶点对,形成一个链状结构(或绳索)的外观。</li>
|
||||
* <li>每个循环迭代都会更新顶点的位置、颜色、光照等属性,使得链状结构被绘制出来。</li>
|
||||
* </ul>
|
||||
* <p>
|
||||
* <h1> 总结 </h1>
|
||||
* 这些数学运算主要用于计算实体在三维空间中的位置和方向,以确保在渲染链状结构(如拴住的绳索)时,链条能够跟随实体的移动和旋转并正确显示。在图形编程中,这些计算非常常见,尤其是在处理旋转、插值和光照效果时。
|
||||
*/
|
||||
|
||||
public static void renderLeash(
|
||||
PoseStack poseStack,
|
||||
MultiBufferSource bufferSource,
|
||||
PlayerRenderState playerRenderState
|
||||
) {
|
||||
float f = 0.025F;
|
||||
// 获得绳索持有者的位置
|
||||
PlayerLeashState leashState = ((IPlayerRenderStateExtension)playerRenderState).getPlayerLeashState();
|
||||
if (leashState == null)
|
||||
return;
|
||||
Vec3 Holder = leashState.pos;//TODO:问题修复
|
||||
Vec3 o = leashState.o;
|
||||
// 计算实体的朝向角度(弧度)
|
||||
float partialTick = playerRenderState.partialTick;
|
||||
double entityRotationAngleRadians = (double)(leashState.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2);
|
||||
// 计算实体的绳索偏移,此处add偏移让渲染拴绳显示在玩家头部下(大约在脖子处
|
||||
// Logger.logger.info("eyeHeight:{}",playerRenderState.eyeHeight);
|
||||
Vec3 cameraEntityLeashOffset = new Vec3(0.0, leashState.eyeHeight , playerRenderState.boundingBoxWidth * 0.4F).add(0, -0.2, -0.2);
|
||||
double leashOffsetX = Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.z + Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
|
||||
double leashOffsetZ = Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.z - Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
|
||||
// 计算实体当前的实际位置
|
||||
double entityPosX = Mth.lerp(partialTick, o.x, playerRenderState.x) + leashOffsetX;
|
||||
double entityPosY = Mth.lerp(partialTick, o.y, playerRenderState.y) + cameraEntityLeashOffset.y;
|
||||
double entityPosZ = Mth.lerp(partialTick, o.z, playerRenderState.z) + leashOffsetZ;
|
||||
|
||||
// 计算绳索的相对位置差
|
||||
float deltaX = (float)(Holder.x - entityPosX);
|
||||
float deltaY = (float)(Holder.y - entityPosY);
|
||||
float deltaZ = (float)(Holder.z - entityPosZ);
|
||||
// 计算比例因子,用于调节绳索的粗细
|
||||
float leashLengthRatio = Mth.invSqrt(deltaX * deltaX + deltaZ * deltaZ) * 0.025F / 2.0F;
|
||||
// 计算比例因子,用于调节绳索的粗细
|
||||
float leashXZScaleX = deltaZ * leashLengthRatio;
|
||||
float leashXZScaleZ = deltaX * leashLengthRatio;
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(leashOffsetX, cameraEntityLeashOffset.y,leashOffsetZ);
|
||||
VertexConsumer vertexconsumer = bufferSource.getBuffer(RenderType.leash());
|
||||
Matrix4f matrix4f = poseStack.last().pose();
|
||||
|
||||
for (int i = 0; i <= 24; i++) {
|
||||
addVertexPair(
|
||||
vertexconsumer,
|
||||
matrix4f,
|
||||
deltaX,
|
||||
deltaY,
|
||||
deltaZ,
|
||||
leashState.startBlockLight,
|
||||
leashState.endBlockLight,
|
||||
leashState.startSkyLight,
|
||||
leashState.endSkyLight,
|
||||
0.025F,
|
||||
0.025F,
|
||||
leashXZScaleX,
|
||||
leashXZScaleZ,
|
||||
i,
|
||||
false
|
||||
);
|
||||
}
|
||||
|
||||
for (int j = 24; j >= 0; j--) {
|
||||
addVertexPair(
|
||||
vertexconsumer,
|
||||
matrix4f,
|
||||
deltaX,
|
||||
deltaY,
|
||||
deltaZ,
|
||||
leashState.startBlockLight,
|
||||
leashState.endBlockLight,
|
||||
leashState.startSkyLight,
|
||||
leashState.endSkyLight,
|
||||
0.025F,
|
||||
0.0F,
|
||||
leashXZScaleX,
|
||||
leashXZScaleZ,
|
||||
j,
|
||||
true
|
||||
);
|
||||
}
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
|
||||
protected static void addVertexPair(
|
||||
VertexConsumer buffer,
|
||||
Matrix4f pose,
|
||||
float startX,
|
||||
float startY,
|
||||
float startZ,
|
||||
int entityBlockLight,
|
||||
int holderBlockLight,
|
||||
int entitySkyLight,
|
||||
int holderSkyLight,
|
||||
float yOffset,
|
||||
float dy,
|
||||
float dx,
|
||||
float dz,
|
||||
int index,
|
||||
boolean reverse
|
||||
) {
|
||||
float f = (float)index / 24.0F;
|
||||
int i = (int)Mth.lerp(f, (float)entityBlockLight, (float)holderBlockLight);
|
||||
int j = (int)Mth.lerp(f, (float)entitySkyLight, (float)holderSkyLight);
|
||||
int k = LightTexture.pack(i, j);
|
||||
float f1 = index % 2 == (reverse ? 1 : 0) ? 0.7F : 1.0F;
|
||||
float f2 = 0.5F * f1;
|
||||
float f3 = 0.4F * f1;
|
||||
float f4 = 0.3F * f1;
|
||||
float f5 = startX * f;
|
||||
float f6 = startY > 0.0F ? startY * f * f : startY - startY * (1.0F - f) * (1.0F - f);
|
||||
float f7 = startZ * f;
|
||||
buffer.addVertex(pose, f5 - dx, f6 + dy, f7 + dz).setColor(f2, f3, f4, 1.0F).setLight(k);
|
||||
buffer.addVertex(pose, f5 + dx, f6 + yOffset - dy, f7 - dz).setColor(f2, f3, f4, 1.0F).setLight(k);
|
||||
}
|
||||
public static <E extends Entity> void renderLeashForCamera(
|
||||
Camera camera,
|
||||
float partialTick,
|
||||
PoseStack poseStack,
|
||||
MultiBufferSource bufferSource,
|
||||
E leashHolder,
|
||||
Vec3 holderOffset
|
||||
) {
|
||||
|
||||
poseStack.pushPose();
|
||||
// Logger.logger.info("eyeHeight{}", camera.getEntity().getEyeHeight());
|
||||
// 获得绳索持有者的位置
|
||||
Vec3 leashHolderPosition = leashHolder.getRopeHoldPosition(partialTick).add(holderOffset);
|
||||
|
||||
// 获取当前观察的实体
|
||||
Entity cameraEntity = camera.getEntity();
|
||||
|
||||
// 计算实体的朝向角度(弧度)
|
||||
double entityRotationAngleRadians = (double)(cameraEntity.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0)) + (Math.PI / 2);
|
||||
|
||||
// 计算实体的绳索偏移,此处add偏移让渲染拴绳显示在玩家头部下(大约在脖子处
|
||||
Vec3 cameraEntityLeashOffset = cameraEntity.getLeashOffset(partialTick).add(0, -0.2, -0.5);
|
||||
double leashOffsetX = Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.z + Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
|
||||
double leashOffsetZ = Math.sin(entityRotationAngleRadians) * cameraEntityLeashOffset.z - Math.cos(entityRotationAngleRadians) * cameraEntityLeashOffset.x;
|
||||
|
||||
// 计算实体当前的实际位置
|
||||
double entityPosX = Mth.lerp(partialTick, cameraEntity.xo, cameraEntity.getX()) + leashOffsetX;
|
||||
double entityPosY = Mth.lerp(partialTick, cameraEntity.yo, cameraEntity.getY()) + cameraEntityLeashOffset.y;
|
||||
double entityPosZ = Mth.lerp(partialTick, cameraEntity.zo, cameraEntity.getZ()) + leashOffsetZ;
|
||||
|
||||
// 在当前变换矩阵上应用偏移
|
||||
poseStack.translate(leashOffsetX, cameraEntityLeashOffset.y , leashOffsetZ);
|
||||
|
||||
// 计算绳索的相对位置差
|
||||
float deltaX = (float)(leashHolderPosition.x - entityPosX);
|
||||
float deltaY = (float)(leashHolderPosition.y - entityPosY);
|
||||
float deltaZ = (float)(leashHolderPosition.z - entityPosZ);
|
||||
|
||||
// 获取顶点消费者,用于绘制绳索
|
||||
VertexConsumer vertexConsumer = bufferSource.getBuffer(RenderType.leash());
|
||||
Matrix4f matrix = poseStack.last().pose();
|
||||
|
||||
// 计算比例因子,用于调节绳索的粗细
|
||||
float leashLengthRatio = Mth.invSqrt(deltaX * deltaX + deltaZ * deltaZ) * 0.025F / 2.0F;
|
||||
float leashXZScaleX = deltaZ * leashLengthRatio;
|
||||
float leashXZScaleZ = deltaX * leashLengthRatio;
|
||||
|
||||
// 获取光照信息
|
||||
BlockPos cameraEntityBlockPos = BlockPos.containing(cameraEntity.getEyePosition(partialTick));
|
||||
BlockPos leashHolderBlockPos = BlockPos.containing(leashHolder.getEyePosition(partialTick));
|
||||
int cameraEntityBlockLightLevel = getBlockLightLevel(cameraEntity, cameraEntityBlockPos);
|
||||
int leashHolderBlockLightLevel = getBlockLightLevel(leashHolder, leashHolderBlockPos); //getBlockLightLevel(leashHolder, leashHolderBlockPos);
|
||||
int cameraEntitySkyLightLevel = cameraEntity.level().getBrightness(LightLayer.SKY, cameraEntityBlockPos);
|
||||
int leashHolderSkyLightLevel = cameraEntity.level().getBrightness(LightLayer.SKY, leashHolderBlockPos);
|
||||
|
||||
// 绘制绳索的上半部分
|
||||
for (int segment = 0; segment <= 24; segment++) {
|
||||
addVertexPair(vertexConsumer, matrix, deltaX, deltaY, deltaZ, cameraEntityBlockLightLevel, leashHolderBlockLightLevel, cameraEntitySkyLightLevel, leashHolderSkyLightLevel, 0.025F, 0.025F, leashXZScaleX, leashXZScaleZ, segment, false);
|
||||
}
|
||||
|
||||
// 绘制绳索的下半部分
|
||||
for (int segment = 24; segment >= 0; segment--) {
|
||||
addVertexPair(vertexConsumer, matrix, deltaX, deltaY, deltaZ, cameraEntityBlockLightLevel, leashHolderBlockLightLevel, cameraEntitySkyLightLevel, leashHolderSkyLightLevel, 0.025F, 0.0F, leashXZScaleX, leashXZScaleZ, segment, true);
|
||||
}
|
||||
|
||||
poseStack.popPose();
|
||||
}
|
||||
public static void levelRenderLeash(ClientLevel level, Camera pCamera, PoseStack poseStack, MultiBufferSource.BufferSource multibuffersource$buffersource) {
|
||||
for(Entity entity : level.entitiesForRendering()) {
|
||||
//对于玩家实体拴绳渲染(从第一人称视角)
|
||||
if (entity instanceof AbstractClientPlayer abstractClientPlayer) {
|
||||
if(!(pCamera.getEntity() instanceof AbstractClientPlayer)) continue;
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
if (mc.options.getCameraType().isFirstPerson()) {
|
||||
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashDataFromEntityData();
|
||||
if(leashDataFromEntityData == null) continue;
|
||||
Either<UUID, BlockPos> delayedLeashInfo = leashDataFromEntityData.delayedLeashInfo;
|
||||
if(delayedLeashInfo != null) {
|
||||
float partialTickTime = pCamera.getPartialTickTime();
|
||||
Vec3 position = pCamera.getPosition();
|
||||
double dX = Mth.lerp(partialTickTime, abstractClientPlayer.xOld, abstractClientPlayer.getX()) - position.x;
|
||||
double dY = Mth.lerp(partialTickTime, abstractClientPlayer.yOld, abstractClientPlayer.getY()) - position.y;
|
||||
double dZ = Mth.lerp(partialTickTime, abstractClientPlayer.zOld, abstractClientPlayer.getZ()) - position.z;
|
||||
Vec3 vec3 = getRenderOffset(entity, partialTickTime);
|
||||
double dX_ = dX + vec3.x();
|
||||
double dY_ = dY + vec3.y();
|
||||
double dZ_ = dZ + vec3.z();
|
||||
poseStack.pushPose();
|
||||
poseStack.translate(dX_, dY_, dZ_);
|
||||
if (delayedLeashInfo.right().isPresent() && delayedLeashInfo.left().isEmpty()) {
|
||||
renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, LeashFenceKnotEntity.getOrCreateKnot(level, delayedLeashInfo.right().get()), Vec3.ZERO);
|
||||
} else if (delayedLeashInfo.right().isEmpty() && delayedLeashInfo.left().isPresent()) {
|
||||
Player playerByUUID = level.getPlayerByUUID(delayedLeashInfo.left().get());
|
||||
if (playerByUUID != null) {
|
||||
renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, playerByUUID, Vec3.ZERO);
|
||||
} else {
|
||||
double MaxLeashLength = ((ILivingEntityExtension) abstractClientPlayer).getLeashLength() * LeashedPlayer.M1() * LeashedPlayer.M2();
|
||||
List<Entity> entities = level.getEntities(
|
||||
null,
|
||||
new AABB(
|
||||
abstractClientPlayer.getX() - MaxLeashLength,
|
||||
abstractClientPlayer.getY() - MaxLeashLength,
|
||||
abstractClientPlayer.getZ() - MaxLeashLength,
|
||||
abstractClientPlayer.getX() + MaxLeashLength,
|
||||
abstractClientPlayer.getY() + MaxLeashLength,
|
||||
abstractClientPlayer.getZ() + MaxLeashLength
|
||||
)
|
||||
);
|
||||
Entity holder = null;
|
||||
for (Entity entity_ : entities) {
|
||||
if(entity_.getUUID().equals(delayedLeashInfo.left().get())) {
|
||||
holder = entity_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (holder != null) {
|
||||
if(holder instanceof LeashRopeArrow) {
|
||||
renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder, new Vec3(0.,-0.09, 0));//TODO: 待擴展Vec3吗?
|
||||
}
|
||||
else renderLeashForCamera(pCamera, partialTickTime, poseStack, multibuffersource$buffersource, holder, Vec3.ZERO);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
public static Vec3 getRenderOffset(Entity entity, float partialTickTime) {
|
||||
Vec3 ret = Vec3.ZERO;
|
||||
if(entity.isPassenger()
|
||||
&& entity.getVehicle() instanceof AbstractMinecart abstractminecart
|
||||
&& abstractminecart.getBehavior() instanceof NewMinecartBehavior newminecartbehavior
|
||||
&& newminecartbehavior.cartHasPosRotLerp()
|
||||
) {
|
||||
double d2 = Mth.lerp(partialTickTime, abstractminecart.xOld, abstractminecart.getX());
|
||||
double d0 = Mth.lerp(partialTickTime, abstractminecart.yOld, abstractminecart.getY());
|
||||
double d1 = Mth.lerp(partialTickTime, abstractminecart.zOld, abstractminecart.getZ());
|
||||
ret = newminecartbehavior.getCartLerpPosition(partialTickTime).subtract(new Vec3(d2, d0, d1));
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
public static void createPlayerLeashState(AbstractClientPlayer abstractClientPlayer, IPlayerRenderStateExtension playerRenderState, float partialTick) {
|
||||
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) abstractClientPlayer).getLeashDataFromEntityData();
|
||||
Leashable.LeashData leashData = ((PlayerLeashable) abstractClientPlayer).getLeashData();
|
||||
PlayerRenderState playerRs = (PlayerRenderState)playerRenderState;
|
||||
if (leashDataFromEntityData != null) {
|
||||
Entity leashHolder = leashDataFromEntityData.leashHolder;
|
||||
Either<UUID, BlockPos> delayedLeashInfo = leashDataFromEntityData.delayedLeashInfo;
|
||||
PlayerLeashState playerLeashState = new PlayerLeashState();
|
||||
if (delayedLeashInfo != null) {
|
||||
createPlayerLeashState_(abstractClientPlayer, playerRenderState, leashDataFromEntityData, delayedLeashInfo, playerLeashState, partialTick);
|
||||
BlockPos blockpos1 = BlockPos.containing(abstractClientPlayer.getEyePosition(partialTick));
|
||||
playerLeashState.startBlockLight = getBlockLightLevel(abstractClientPlayer, blockpos1);
|
||||
playerLeashState.startSkyLight = abstractClientPlayer.level().getBrightness(LightLayer.SKY, blockpos1);
|
||||
} else if(leashHolder != null) {
|
||||
createPlayerLeashState__(abstractClientPlayer, playerRenderState, leashHolder, playerLeashState, partialTick);
|
||||
} else {
|
||||
playerRenderState.setPlayerLeashState(null);
|
||||
}
|
||||
} else if(leashData != null) {
|
||||
playerRs.leashState = null;
|
||||
Entity leashHolder = ((PlayerLeashable) abstractClientPlayer).getLeashHolder();
|
||||
PlayerLeashState playerLeashState = playerRenderState.getPlayerLeashState();
|
||||
if (leashHolder != null & playerLeashState != null) {
|
||||
float f = leashHolder.getPreciseBodyRotation(partialTick) * (float) (Math.PI / 180.0);
|
||||
Vec3 vec3 = abstractClientPlayer.getLeashOffset(partialTick).yRot(-f);
|
||||
BlockPos blockpos1 = BlockPos.containing(abstractClientPlayer.getEyePosition(partialTick));
|
||||
BlockPos blockpos = BlockPos.containing(leashHolder.getEyePosition(partialTick));
|
||||
playerLeashState.vanilaLeashState = new EntityRenderState.LeashState();
|
||||
|
||||
EntityRenderState.LeashState entityrenderstate$leashstate = playerLeashState.vanilaLeashState;
|
||||
entityrenderstate$leashstate.offset = vec3;
|
||||
entityrenderstate$leashstate.start = abstractClientPlayer.getPosition(partialTick).add(vec3);
|
||||
entityrenderstate$leashstate.end = leashHolder.getRopeHoldPosition(partialTick);
|
||||
entityrenderstate$leashstate.startBlockLight = getBlockLightLevel(abstractClientPlayer, blockpos1);
|
||||
entityrenderstate$leashstate.endBlockLight = getBlockLightLevel(leashHolder, blockpos);
|
||||
entityrenderstate$leashstate.startSkyLight = abstractClientPlayer.level().getBrightness(LightLayer.SKY, blockpos1);
|
||||
entityrenderstate$leashstate.endSkyLight = abstractClientPlayer.level().getBrightness(LightLayer.SKY, blockpos);
|
||||
} else {
|
||||
playerRenderState.setPlayerLeashState(null);
|
||||
}
|
||||
} else {
|
||||
playerRenderState.setPlayerLeashState(null);
|
||||
}
|
||||
}
|
||||
private static <T extends Entity> int getBlockLightLevel(T entity, BlockPos pos) {
|
||||
return entity.isOnFire() ? 15 : entity.level().getBrightness(LightLayer.BLOCK, pos);
|
||||
}
|
||||
private static int getBlockLightLevel(Level level, BlockPos pos) {
|
||||
return level.getBrightness(LightLayer.BLOCK, pos);
|
||||
}
|
||||
|
||||
|
||||
private static void createPlayerLeashState__(AbstractClientPlayer abstractClientPlayer, IPlayerRenderStateExtension playerRenderState, Entity leashHolder, PlayerLeashState playerLeashState, float partialTick) {
|
||||
playerLeashState.pos = leashHolder.position().add(0.0, leashHolder.getEyeHeight() * 0.6, -0.2);
|
||||
playerLeashState.o = abstractClientPlayer.getPosition(partialTick);
|
||||
playerLeashState.yRotO = abstractClientPlayer.yRotO;
|
||||
playerLeashState.yRot = abstractClientPlayer.getYRot();
|
||||
playerLeashState.eyeHeight = abstractClientPlayer.getEyeHeight();
|
||||
playerRenderState.setPlayerLeashState(playerLeashState);
|
||||
}
|
||||
|
||||
private static void createPlayerLeashState_(AbstractClientPlayer abstractClientPlayer, IPlayerRenderStateExtension playerRenderState, Leashable.LeashData leashDataFromEntityData, Either<UUID, BlockPos> delayedLeashInfo, PlayerLeashState playerLeashState, float partialTick) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
ClientLevel level = mc.level;
|
||||
if (delayedLeashInfo.right().isPresent() && delayedLeashInfo.left().isEmpty()) {
|
||||
assert level != null;
|
||||
playerLeashState.pos = delayedLeashInfo.right().get().getCenter();
|
||||
playerLeashState.endBlockLight = getBlockLightLevel(level, delayedLeashInfo.right().get());
|
||||
playerLeashState.endSkyLight = level.getBrightness(LightLayer.SKY, delayedLeashInfo.right().get());
|
||||
} else if (delayedLeashInfo.right().isEmpty() && delayedLeashInfo.left().isPresent()) {
|
||||
assert level != null;
|
||||
Player playerByUUID = level.getPlayerByUUID(delayedLeashInfo.left().get());
|
||||
if (playerByUUID != null) {
|
||||
playerLeashState.pos = playerByUUID.position().add(0.0, playerByUUID.getEyeHeight() * 0.6, 0);
|
||||
} else {
|
||||
double breakDistanceTime = (leashDataFromEntityData.leashHolder instanceof LeashRopeArrow) ? LeashedPlayer.M1() * LeashedPlayer.M2() : LeashedPlayer.M1();
|
||||
double MaxLeashLength = ((ILivingEntityExtension) abstractClientPlayer).getLeashLength() * breakDistanceTime;
|
||||
List<Entity> entities = level.getEntities(
|
||||
null,
|
||||
new AABB(
|
||||
abstractClientPlayer.getX() - MaxLeashLength * LeashedPlayer.M2(),
|
||||
abstractClientPlayer.getY() - MaxLeashLength * LeashedPlayer.M2(),
|
||||
abstractClientPlayer.getZ() - MaxLeashLength * LeashedPlayer.M2(),
|
||||
abstractClientPlayer.getX() + MaxLeashLength * LeashedPlayer.M2(),
|
||||
abstractClientPlayer.getY() + MaxLeashLength * LeashedPlayer.M2(),
|
||||
abstractClientPlayer.getZ() + MaxLeashLength * LeashedPlayer.M2()
|
||||
)
|
||||
);
|
||||
Entity holder = null;
|
||||
for (Entity entity_ : entities) {
|
||||
if (entity_.getUUID().equals(delayedLeashInfo.left().get())) {
|
||||
holder = entity_;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (holder != null) {
|
||||
playerLeashState.pos = holder.position().add(0.0, holder.getEyeHeight() * 0.6, 0);//TODO: 待擴展Vec3
|
||||
playerLeashState.endBlockLight = getBlockLightLevel(level, holder.getOnPos());
|
||||
playerLeashState.endSkyLight = level.getBrightness(LightLayer.SKY, holder.getOnPos());
|
||||
} else {
|
||||
playerLeashState.pos = abstractClientPlayer.position();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
playerLeashState.o = abstractClientPlayer.getPosition(partialTick);
|
||||
playerLeashState.yRotO = abstractClientPlayer.yRotO;
|
||||
playerLeashState.yRot = abstractClientPlayer.getYRot();
|
||||
playerLeashState.eyeHeight = abstractClientPlayer.getEyeHeight();
|
||||
|
||||
playerRenderState.setPlayerLeashState(playerLeashState);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer;
|
||||
|
||||
import net.minecraft.client.renderer.entity.state.EntityRenderState;
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class PlayerLeashState {
|
||||
public Vec3 o, pos, offset;
|
||||
public float yRotO, yRot;
|
||||
public float eyeHeight;
|
||||
public int startBlockLight;
|
||||
public int endBlockLight;
|
||||
public int startSkyLight;
|
||||
public int endSkyLight;
|
||||
@Nullable
|
||||
public EntityRenderState.LeashState vanilaLeashState;
|
||||
|
||||
public float getPreciseBodyRotation(float pPartialTick) {
|
||||
return Mth.lerp(pPartialTick, this.yRotO, this.yRot);
|
||||
}
|
||||
|
||||
|
||||
public PlayerLeashState() {
|
||||
this.offset = Vec3.ZERO;
|
||||
this.o = Vec3.ZERO;
|
||||
this.pos = Vec3.ZERO;
|
||||
this.yRot = 0.0f;
|
||||
this.yRotO = 0.0f;
|
||||
this.eyeHeight = 0.0f;
|
||||
this.startBlockLight = 0;
|
||||
this.endBlockLight = 0;
|
||||
this.startSkyLight = 15;
|
||||
this.endSkyLight = 15;
|
||||
this.vanilaLeashState = null;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer;
|
||||
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class PlayerSlotItemLayerState {
|
||||
public LivingEntity entity;
|
||||
public PlayerSlotItemLayerState(LivingEntity entity) {
|
||||
this.entity = entity;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,120 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.entities;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.mojang.math.Axis;
|
||||
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
|
||||
import net.minecraft.client.model.EntityModel;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.renderer.ItemInHandRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.entity.RenderLayerParent;
|
||||
import net.minecraft.client.renderer.entity.layers.RenderLayer;
|
||||
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
|
||||
import net.minecraft.world.entity.EquipmentSlot;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class ChestItemLayerRenderer<S extends PlayerRenderState, M extends EntityModel<S>> extends RenderLayer<S, M> {
|
||||
|
||||
private final ItemInHandRenderer heldItemRenderer;
|
||||
|
||||
public ChestItemLayerRenderer(RenderLayerParent<S, M> context, ItemInHandRenderer heldItemRenderer) {
|
||||
super(context);
|
||||
this.heldItemRenderer = heldItemRenderer;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void render(@NotNull PoseStack poseStack, @NotNull MultiBufferSource bufferSource, int packedLight, @NotNull S renderState, float yRot, float xRot) {
|
||||
ItemDisplayContext mode = ItemDisplayContext.FIXED;
|
||||
IPlayerRenderStateExtension rs = (IPlayerRenderStateExtension) renderState;
|
||||
LivingEntity entity = rs.getPlayerSlotItemLayerState().entity;
|
||||
ItemStack chestStack = entity.getItemBySlot(EquipmentSlot.CHEST);
|
||||
if (!chestStack.isEmpty()) {
|
||||
if (!(entity.getEquipmentSlotForItem(chestStack).equals(EquipmentSlot.CHEST))) {
|
||||
poseStack.pushPose();
|
||||
((PlayerModel) this.getParentModel()).body.translateAndRotate(poseStack);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
poseStack.translate(0, -0.24f, 0);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||
this.heldItemRenderer.renderItem(entity, chestStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.scale(1.01f, 1.01f, 1.01f);
|
||||
poseStack.translate(0, -1 / 4f, 0);
|
||||
this.heldItemRenderer.renderItem(entity, chestStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.popPose();
|
||||
poseStack.pushPose();
|
||||
((PlayerModel) this.getParentModel()).rightArm.translateAndRotate(poseStack);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
poseStack.scale(2/3f, 2/3f, 2/3f);
|
||||
poseStack.translate(-1/12f, 0, 0);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||
this.heldItemRenderer.renderItem(entity, chestStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.scale(0.99f, 0.99f, 0.99f);
|
||||
poseStack.translate(0, -1/2f, 0);
|
||||
this.heldItemRenderer.renderItem(entity, chestStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.popPose();
|
||||
poseStack.pushPose();
|
||||
((PlayerModel) this.getParentModel()).leftArm.translateAndRotate(poseStack);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
poseStack.scale(2/3f, 2/3f, 2/3f);
|
||||
poseStack.translate(1/12f, 0, 0);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||
this.heldItemRenderer.renderItem(entity, chestStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.scale(0.99f, 0.99f, 0.99f);
|
||||
poseStack.translate(0, -1/2f, 0);
|
||||
this.heldItemRenderer.renderItem(entity, chestStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
ItemStack legsStack = entity.getItemBySlot(EquipmentSlot.LEGS);
|
||||
if (!legsStack.isEmpty()) {
|
||||
if (!(entity.getEquipmentSlotForItem(legsStack).equals(EquipmentSlot.LEGS))) {
|
||||
poseStack.pushPose();
|
||||
((PlayerModel) this.getParentModel()).rightLeg.translateAndRotate(poseStack);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
poseStack.scale(2/3f, 2/3f, 2/3f);
|
||||
poseStack.translate(0, -1/6f, 0);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||
this.heldItemRenderer.renderItem(entity, legsStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.scale(1.01f, 1.01f, 1.01f);
|
||||
poseStack.translate(0, -1/3f, 0);
|
||||
this.heldItemRenderer.renderItem(entity, legsStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.popPose();
|
||||
poseStack.pushPose();
|
||||
((PlayerModel) this.getParentModel()).leftLeg.translateAndRotate(poseStack);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
poseStack.scale(2/3f, 2/3f, 2/3f);
|
||||
poseStack.translate(0, -1/6f, 0);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||
this.heldItemRenderer.renderItem(entity, legsStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.scale(1.01f, 1.01f, 1.01f);
|
||||
poseStack.translate(0, -1/3f, 0);
|
||||
this.heldItemRenderer.renderItem(entity, legsStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
ItemStack feetStack = entity.getItemBySlot(EquipmentSlot.FEET);
|
||||
if (!feetStack.isEmpty()) {
|
||||
if (!(entity.getEquipmentSlotForItem(feetStack).equals(EquipmentSlot.FEET))) {
|
||||
poseStack.pushPose();
|
||||
((PlayerModel) this.getParentModel()).rightLeg.translateAndRotate(poseStack);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
poseStack.scale(0.75f, 0.75f, 0.75f);
|
||||
poseStack.translate(0, -0.8f, 0);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||
this.heldItemRenderer.renderItem(entity, feetStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.popPose();
|
||||
poseStack.pushPose();
|
||||
((PlayerModel) this.getParentModel()).leftLeg.translateAndRotate(poseStack);
|
||||
poseStack.mulPose(Axis.XP.rotationDegrees(180));
|
||||
poseStack.scale(0.75f, 0.75f, 0.75f);
|
||||
poseStack.translate(0, -0.8f, 0);
|
||||
poseStack.mulPose(Axis.YP.rotationDegrees(180));
|
||||
this.heldItemRenderer.renderItem(entity, feetStack, mode, poseStack, bufferSource, packedLight);
|
||||
poseStack.popPose();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.entities;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import net.minecraft.client.renderer.entity.ArrowRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.state.ArrowRenderState;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class LeashRopeArrowRenderer extends ArrowRenderer<LeashRopeArrow, ArrowRenderState> {
|
||||
public static final ResourceLocation LEASH_ROPE_ARROW = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/entity/projectiles/leash_rope_arrow.png");
|
||||
public LeashRopeArrowRenderer(EntityRendererProvider.Context pContext) {
|
||||
super(pContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ArrowRenderState createRenderState() {
|
||||
return new ArrowRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull ResourceLocation getTextureLocation(@NotNull ArrowRenderState arrowRenderState) {
|
||||
return LEASH_ROPE_ARROW;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.entities;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.entities.SpectralLeashRopeArrow;
|
||||
import net.minecraft.client.renderer.entity.ArrowRenderer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.state.ArrowRenderState;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class SpectralLeashRopeArrowRenderer extends ArrowRenderer<SpectralLeashRopeArrow, ArrowRenderState> {
|
||||
public static final ResourceLocation SPECTRAL_LEASH_ROPE_ARROW = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/entity/projectiles/spectral_leash_rope_arrow.png");
|
||||
|
||||
public SpectralLeashRopeArrowRenderer(EntityRendererProvider.Context pContext) {
|
||||
super(pContext);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ArrowRenderState createRenderState() {
|
||||
return new ArrowRenderState();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull ResourceLocation getTextureLocation(@NotNull ArrowRenderState arrowRenderState) {
|
||||
return SPECTRAL_LEASH_ROPE_ARROW;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,42 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.gui;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.client.event.RenderGuiEvent;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, value = Dist.CLIENT)
|
||||
public class AdaptiveGuiRendererHandler {
|
||||
private static final Map<IProcessBar, IProcessBarRenderer<? extends IProcessBar>> processBars = Maps.newConcurrentMap();
|
||||
public static void addProcessBar(IProcessBar processBar, IProcessBarRenderer<? extends IProcessBar> renderer) {
|
||||
processBars.put(processBar, renderer);
|
||||
}
|
||||
public static IProcessBarRenderer<? extends IProcessBar> getProcessBarRenderer(IProcessBar processBar) {
|
||||
return processBars.get(processBar);
|
||||
}
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onRendererLevel(RenderGuiEvent.Pre event) {
|
||||
PoseStack matrixStack = event.getGuiGraphics().pose();
|
||||
GuiGraphics guiGraphics = event.getGuiGraphics();
|
||||
processBars.keySet().forEach(
|
||||
processBar -> {
|
||||
IProcessBarRenderer<? extends IProcessBar> renderer = processBars.get(processBar);
|
||||
if(processBar.shouldRender()) {
|
||||
renderer.renderProcessBar(matrixStack, guiGraphics);
|
||||
} else {
|
||||
if (processBar.aliveCount() <= 0) {//计数为非正时移除
|
||||
processBars.remove(processBar);
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,83 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
|
||||
import com.r3944realms.leashedplayer.client.processBar.TestProcessBar;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
|
||||
public interface IFadingProcessBarRenderer<T extends IProcessBar> extends IProcessBarRenderer<T> {
|
||||
/**
|
||||
* @return 当前透明度,0.0(完全透明)到 1.0(完全不透明)
|
||||
*/
|
||||
float getFadeAlpha();
|
||||
void setFadeAlpha(float alpha);
|
||||
/**
|
||||
* @return 是否淡入
|
||||
*/
|
||||
boolean isFadingIn();
|
||||
void setFadingIn(boolean fadingIn);
|
||||
/**
|
||||
* @return 是否淡出
|
||||
*/
|
||||
boolean isFadingOut();
|
||||
void setFadingOut(boolean fadingOut);
|
||||
/**
|
||||
* @return 淡化速度
|
||||
*/
|
||||
float getFadeRate();
|
||||
void setFadeRate(float fadeRate);
|
||||
/**
|
||||
* @return 完全淡入/淡出所需时间(秒)
|
||||
*/
|
||||
float getFadeDuration();
|
||||
void setFadeDuration(float fadeDuration);
|
||||
/**
|
||||
* 更新淡化效果
|
||||
*/
|
||||
default void updateFadeEffect() {
|
||||
float fadeSpeed = getFadeRate() / getFadeDuration();
|
||||
if (isFadingIn()) {
|
||||
fadeInTick(fadeSpeed);
|
||||
|
||||
} else if (isFadingOut()) {
|
||||
fadeOutTick(fadeSpeed);
|
||||
if(getFadeAlpha() <= 0.0F){
|
||||
if (getProcessBar().getCurrentProcess() != 0 || getProcessBar().getCurrentProcess() != getProcessBar().getMaxProcess()) {
|
||||
getProcessBar().retain();
|
||||
}
|
||||
stopRender();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Do Not Override, instead of using <code>renderProcessBar0()</code><br/>
|
||||
* 请勿重载,请重载renderProcessBar0()替代
|
||||
* @deprecated
|
||||
*/
|
||||
@Deprecated
|
||||
@Override
|
||||
default void renderProcessBar(PoseStack poseStack, GuiGraphics guiGraphics) {
|
||||
updateFadeEffect();
|
||||
renderProcessBar0(poseStack, guiGraphics);
|
||||
}
|
||||
void renderProcessBar0(PoseStack poseStack, GuiGraphics guiGraphics);
|
||||
|
||||
default void fadeInTick(float fadeSpeed) {
|
||||
if (getFadeAlpha() >= 1.0f) {
|
||||
setFadingIn(false);
|
||||
return;
|
||||
}
|
||||
setFadeAlpha(Math.min(getFadeAlpha() + fadeSpeed, 1.0f));
|
||||
|
||||
}
|
||||
default void fadeOutTick(float fadeSpeed) {
|
||||
if (getFadeAlpha() >= 1.0f) {
|
||||
setFadingOut(false);
|
||||
return;
|
||||
}
|
||||
setFadeAlpha(Math.max(getFadeAlpha() - fadeSpeed, 0.0f));
|
||||
}
|
||||
|
||||
void setProcessBar(TestProcessBar processBar);
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
|
||||
public interface IProcessBarRenderer<T extends IProcessBar> {
|
||||
T getProcessBar();
|
||||
void setProcessBar(T processBar);
|
||||
void renderProcessBar(PoseStack poseStack, GuiGraphics guiGraphics);
|
||||
default void stopRender() {
|
||||
T processBar = getProcessBar();
|
||||
processBar.decreaseAliveCount();
|
||||
processBar.setRenderStatus(false);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,90 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.client.event.ClientTickEvent;
|
||||
import net.neoforged.neoforge.client.event.RenderGuiEvent;
|
||||
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, value = Dist.CLIENT)
|
||||
public class ProcessBarRenderer {
|
||||
|
||||
private static boolean isRendering = false;
|
||||
private static final int progressDuration = 100;
|
||||
private static int currentProgress = 0;
|
||||
public static void startRenderingProgressBar(Player player) {
|
||||
isRendering = true;
|
||||
currentProgress = 0;
|
||||
}
|
||||
public static void stopRenderingProgressBar() {
|
||||
isRendering = false;
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void onClientTick(ClientTickEvent.Pre event) {
|
||||
if (isRendering) {
|
||||
currentProgress++;
|
||||
if (currentProgress >= progressDuration) {
|
||||
stopRenderingProgressBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
@SubscribeEvent
|
||||
public static void onRendererLevel(RenderGuiEvent.Pre event) {
|
||||
PoseStack matrixStack = event.getGuiGraphics().pose();
|
||||
GuiGraphics guiGraphics = event.getGuiGraphics();
|
||||
if(isRendering) {
|
||||
renderProgressBar(matrixStack, guiGraphics);
|
||||
}
|
||||
}
|
||||
public static float getProgress() {
|
||||
return (float) currentProgress / progressDuration;
|
||||
}
|
||||
private static void renderProgressBar(PoseStack matrixStack, GuiGraphics guiGraphics) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
int screenWidth = mc.getWindow().getGuiScaledWidth();
|
||||
int screenHeight = mc.getWindow().getGuiScaledHeight();
|
||||
|
||||
// 设置进度条的位置和尺寸
|
||||
int barWidth = screenWidth / 4;
|
||||
int barHeight = 12;
|
||||
int x = (screenWidth - barWidth) / 2;
|
||||
int y = screenHeight - 47;
|
||||
|
||||
// 绘制背景(灰色)
|
||||
guiGraphics.fill(x, y, x + barWidth, y + barHeight, 0xFF555555);
|
||||
|
||||
// 计算当前进度并绘制前景(渐变颜色)
|
||||
float progress = getProgress();
|
||||
int progressWidth = (int) (progress * barWidth);
|
||||
|
||||
// 渐变颜色效果:从红色到绿色
|
||||
int color = lerpColor(progress);
|
||||
guiGraphics.fill(x, y, x + progressWidth, y + barHeight, color);
|
||||
|
||||
// 绘制边框:分别绘制四条边
|
||||
int borderColor = 0xFFFFFFFF; // 白色
|
||||
guiGraphics.fill(x - 1, y - 1, x + barWidth + 1, y, borderColor); // 顶边
|
||||
guiGraphics.fill(x - 1, y + barHeight, x + barWidth + 1, y + barHeight + 1, borderColor); // 底边
|
||||
guiGraphics.fill(x - 1, y, x, y + barHeight, borderColor); // 左边
|
||||
guiGraphics.fill(x + barWidth, y, x + barWidth + 1, y + barHeight, borderColor); // 右边
|
||||
}
|
||||
|
||||
// 渐变颜色计算
|
||||
private static int lerpColor(float progress) {
|
||||
int a = (int) (getAlpha(-65536) * (1 - progress) + getAlpha(-16711936) * progress);
|
||||
int r = (int) (getRed(-65536) * (1 - progress) + getRed(-16711936) * progress);
|
||||
int g = (int) (getGreen(-65536) * (1 - progress) + getGreen(-16711936) * progress);
|
||||
int b = (int) (getBlue(-65536) * (1 - progress) + getBlue(-16711936) * progress);
|
||||
return (a << 24) | (r << 16) | (g << 8) | b;
|
||||
}
|
||||
|
||||
private static int getAlpha(int color) { return (color >> 24) & 0xFF; }
|
||||
private static int getRed(int color) { return (color >> 16) & 0xFF; }
|
||||
private static int getGreen(int color) { return (color >> 8) & 0xFF; }
|
||||
private static int getBlue(int color) { return color & 0xFF; }
|
||||
}
|
||||
|
|
@ -0,0 +1,161 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.gui;
|
||||
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
|
||||
import com.r3944realms.leashedplayer.client.processBar.TestProcessBar;
|
||||
import com.r3944realms.leashedplayer.utils.ColorUtil;
|
||||
import net.minecraft.client.Minecraft;
|
||||
import net.minecraft.client.gui.GuiGraphics;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class TestProcessBarRenderer implements IFadingProcessBarRenderer<IProcessBar>{
|
||||
@Nullable
|
||||
private TestProcessBar processBar;
|
||||
private float FadeAlpha;
|
||||
private boolean fadingIn, fadingOut;
|
||||
private float FadeRate;
|
||||
private float FadeDuration;
|
||||
|
||||
public TestProcessBarRenderer(boolean fadingIn, boolean fadingOut, float FadeRate, float FadeDuration){
|
||||
this.fadingIn = fadingIn;
|
||||
this.fadingOut = fadingOut;
|
||||
this.FadeRate = FadeRate;
|
||||
this.FadeDuration = FadeDuration;
|
||||
this.FadeAlpha = 0.0F;
|
||||
}
|
||||
|
||||
public TestProcessBarRenderer(boolean fadingIn, boolean fadingOut, float FadeRate, float FadeDuration, float FadeAlpha){
|
||||
this.fadingIn = fadingIn;
|
||||
this.fadingOut = fadingOut;
|
||||
this.FadeRate = FadeRate;
|
||||
this.FadeDuration = FadeDuration;
|
||||
this.FadeAlpha = FadeAlpha;
|
||||
}
|
||||
|
||||
public TestProcessBarRenderer(TestProcessBar bar, boolean fadingIn, boolean fadingOut, float FadeRate, float FadeDuration) {
|
||||
this(fadingIn, fadingOut, FadeRate, FadeDuration);
|
||||
setProcessBar(bar);
|
||||
}
|
||||
|
||||
public TestProcessBarRenderer(TestProcessBar bar, boolean fadingIn, boolean fadingOut, float FadeRate, float FadeDuration, float FadeAlpha) {
|
||||
this(fadingIn, fadingOut, FadeRate, FadeDuration, FadeAlpha);
|
||||
setProcessBar(bar);
|
||||
}
|
||||
|
||||
public TestProcessBarRenderer() {
|
||||
this(true, false, 0.02f, 10.0f, 0.0f);
|
||||
}
|
||||
|
||||
public TestProcessBarRenderer(TestProcessBar bar) {
|
||||
this(true, false, 0.02f, 10.0f);
|
||||
setProcessBar(bar);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public float getFadeAlpha() {
|
||||
return this.FadeAlpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadeAlpha(float alpha) {
|
||||
this.FadeAlpha = alpha;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFadingIn() {
|
||||
return this.fadingIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadingIn(boolean fadingIn) {
|
||||
this.fadingIn = fadingIn;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isFadingOut() {
|
||||
return this.fadingOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadingOut(boolean fadingOut) {
|
||||
this.fadingOut = fadingOut;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFadeRate() {
|
||||
return this.FadeRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadeRate(float fadeRate) {
|
||||
this.FadeRate = fadeRate;
|
||||
}
|
||||
|
||||
@Override
|
||||
public float getFadeDuration() {
|
||||
return this.FadeDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFadeDuration(float fadeDuration) {
|
||||
this.FadeDuration = fadeDuration;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @Nullable TestProcessBar getProcessBar() {
|
||||
return this.processBar;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcessBar(IProcessBar processBar) {
|
||||
if(processBar instanceof TestProcessBar pB){
|
||||
setProcessBar(pB);
|
||||
} else throw new UnsupportedOperationException("Not supported Non-TestProcessBar");
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setProcessBar(TestProcessBar processBar) {
|
||||
this.processBar = processBar;
|
||||
}
|
||||
|
||||
|
||||
|
||||
@Override
|
||||
public void renderProcessBar0(PoseStack poseStack, GuiGraphics guiGraphics) {
|
||||
Minecraft mc = Minecraft.getInstance();
|
||||
int screenWidth = mc.getWindow().getGuiScaledWidth();
|
||||
int screenHeight = mc.getWindow().getGuiScaledHeight();
|
||||
|
||||
int elementWidth = 200;
|
||||
int elementHeight = 12;
|
||||
int x = (screenWidth - elementWidth) / 2;
|
||||
int y = screenHeight - elementHeight - 47; // 控制 GUI 元素的位置
|
||||
|
||||
// 计算透明度
|
||||
float progress = 0;
|
||||
if (getProcessBar() != null) {
|
||||
progress = (float) getProcessBar().getCurrentProcess() / getProcessBar().getMaxProcess();
|
||||
}
|
||||
int alpha = (int) (FadeAlpha * 255);
|
||||
int backgroundColor = (alpha << 24) | 0xFF555555; // 背景颜色
|
||||
int foregroundColor = (alpha << 24) | ColorUtil.lerpColor(progress);; // 前景颜色
|
||||
|
||||
// 绘制背景
|
||||
guiGraphics.fill(x, y, x + elementWidth, y + elementHeight, backgroundColor);
|
||||
|
||||
// 绘制前景(例如进度条)
|
||||
|
||||
int progressWidth = (int) (progress * elementWidth);
|
||||
guiGraphics.fill(x, y, x + progressWidth, y + elementHeight, foregroundColor);
|
||||
|
||||
// 绘制边框
|
||||
int borderColor = 0xFFFFFFFF; // 白色边框
|
||||
guiGraphics.fill(x - 1, y - 1, x + elementWidth + 1, y, borderColor); // 顶边
|
||||
guiGraphics.fill(x - 1, y + elementHeight, x + elementWidth + 1, y + elementHeight + 1, borderColor); // 底边
|
||||
guiGraphics.fill(x - 1, y, x, y + elementHeight, borderColor); // 左边
|
||||
guiGraphics.fill(x + elementWidth, y, x + elementWidth + 1, y + elementHeight, borderColor); // 右边
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,139 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.item;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange.ConditionalRangeItemModelProperties;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange.ConditionalRangeItemModelProperty;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.ItemModelResolver;
|
||||
import net.minecraft.client.renderer.item.ItemModels;
|
||||
import net.minecraft.client.renderer.item.ItemStackRenderState;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ConditionalRangeItemModel implements ItemModel {
|
||||
private final ConditionalRangeItemModelProperty property;
|
||||
private final float scale;
|
||||
private final float[] onTrueThresholds;
|
||||
private final float[] onFalseThresholds;
|
||||
private final ItemModel[] onTrueModels;
|
||||
private final ItemModel[] onFalseModels;
|
||||
private final ItemModel fallback;
|
||||
public ConditionalRangeItemModel(ConditionalRangeItemModelProperty property, float scale, float[] onTrueThresholds, float[] onFalseThresholds, ItemModel[] onTrueModels, ItemModel[] onFalseModels, ItemModel fallback) {
|
||||
this.property = property;
|
||||
this.scale = scale;
|
||||
this.onTrueThresholds = onTrueThresholds;
|
||||
this.onFalseThresholds = onFalseThresholds;
|
||||
this.onTrueModels = onTrueModels;
|
||||
this.onFalseModels = onFalseModels;
|
||||
this.fallback = fallback;
|
||||
}
|
||||
private static int lastIndexLessOrEqual(float[] thresholds, float value) {
|
||||
if (thresholds.length < 16) {
|
||||
for (int k = 0; k < thresholds.length; k++) {
|
||||
if (thresholds[k] > value) {
|
||||
return k - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return thresholds.length - 1;
|
||||
} else {
|
||||
int i = Arrays.binarySearch(thresholds, value);
|
||||
if (i < 0) {
|
||||
int j = ~i;
|
||||
return j - 1;
|
||||
} else {
|
||||
return i;
|
||||
}
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void update(@NotNull ItemStackRenderState renderState, @NotNull ItemStack stack, @NotNull ItemModelResolver itemModelResolver, @NotNull ItemDisplayContext displayContext, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed) {
|
||||
ConditionalRangeItemModelProperty.ConditionalRangeData conditionalRangeData = this.property.get(stack, level, entity, seed, displayContext);
|
||||
float f = conditionalRangeData.floatValue() * this.scale;
|
||||
boolean b = conditionalRangeData.boolValue();
|
||||
ItemModel itemModel;
|
||||
if(Float.isNaN(f)) {
|
||||
itemModel = this.fallback; ;
|
||||
} else {
|
||||
int i;
|
||||
if (b) {
|
||||
i = lastIndexLessOrEqual(this.onTrueThresholds, f);
|
||||
}
|
||||
else {
|
||||
i = lastIndexLessOrEqual(this.onFalseThresholds, f);
|
||||
}
|
||||
itemModel = i == -1 ? this.fallback : b ? onTrueModels[i] : onFalseModels[i];
|
||||
|
||||
}
|
||||
itemModel.update(renderState, stack, itemModelResolver, displayContext, level, entity, seed);
|
||||
}
|
||||
public record Entry(float threshold, ItemModel.Unbaked model) {
|
||||
public static final Codec<Entry> CODEC = RecordCodecBuilder.create(
|
||||
instance -> instance.group(
|
||||
Codec.FLOAT.fieldOf("threshold").forGetter(Entry::threshold),
|
||||
ItemModels.CODEC.fieldOf("model").forGetter(Entry::model)
|
||||
).apply(instance, Entry::new)
|
||||
);
|
||||
public static final Comparator<Entry> BY_THRESHOLD = Comparator.comparingDouble(Entry::threshold);
|
||||
}
|
||||
public record Unbaked(
|
||||
ConditionalRangeItemModelProperty property, float scale, List<Entry> trueModels, List<Entry> falseModels, Optional<ItemModel.Unbaked> fallback
|
||||
) implements ItemModel.Unbaked {
|
||||
public static final MapCodec<Unbaked> MAP_CODEC = RecordCodecBuilder.mapCodec(
|
||||
instance -> instance.group(
|
||||
ConditionalRangeItemModelProperties.MAP_CODEC.forGetter(Unbaked::property),
|
||||
Codec.FLOAT.optionalFieldOf("scale", 1.0F).forGetter(Unbaked::scale),
|
||||
Entry.CODEC.listOf().fieldOf("trueModels").forGetter(Unbaked::trueModels),
|
||||
Entry.CODEC.listOf().fieldOf("falseModels").forGetter(Unbaked::falseModels),
|
||||
ItemModels.CODEC.optionalFieldOf("fallback").forGetter(Unbaked::fallback)
|
||||
).apply(instance, Unbaked::new)
|
||||
);
|
||||
@Override
|
||||
public @NotNull MapCodec<? extends ItemModel.Unbaked> type() {
|
||||
return MAP_CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemModel bake(@NotNull BakingContext context) {
|
||||
float[] floatArrA = new float[this.trueModels.size()];
|
||||
float[] floatArrB = new float[this.falseModels.size()];
|
||||
ItemModel[] itemModelArrA = new ItemModel[this.trueModels.size()];
|
||||
ItemModel[] itemModelArrB = new ItemModel[this.falseModels.size()];
|
||||
List<Entry> trueModelList = new ArrayList<>(this.trueModels);
|
||||
List<Entry> falseModelList = new ArrayList<>(this.falseModels);
|
||||
trueModelList.sort(Entry.BY_THRESHOLD);
|
||||
falseModelList.sort(Entry.BY_THRESHOLD);
|
||||
for (int i = 0; i < trueModelList.size(); i++) {
|
||||
Entry rangeselectitemmodel$entry = trueModelList.get(i);
|
||||
floatArrA[i] = rangeselectitemmodel$entry.threshold;
|
||||
itemModelArrA[i] = rangeselectitemmodel$entry.model.bake(context);
|
||||
}
|
||||
for (int i = 0; i < falseModels.size(); i++) {
|
||||
Entry rangeselectitemmodel$entry = falseModelList.get(i);
|
||||
floatArrB[i] = rangeselectitemmodel$entry.threshold;
|
||||
itemModelArrB[i] = rangeselectitemmodel$entry.model.bake(context);
|
||||
}
|
||||
ItemModel itemmodel = this.fallback.map(p_387030_ -> p_387030_.bake(context)).orElse(context.missingItemModel());
|
||||
return new ConditionalRangeItemModel(this.property, this.scale, floatArrA, floatArrB, itemModelArrA, itemModelArrB, itemmodel);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void resolveDependencies(@NotNull Resolver resolver) {
|
||||
this.fallback.ifPresent(itemModel -> itemModel.resolveDependencies(resolver));
|
||||
this.trueModels.forEach(entry -> entry.model.resolveDependencies(resolver));
|
||||
this.falseModels.forEach(entry -> entry.model.resolveDependencies(resolver));
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,46 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.item.properties.conditional;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.r3944realms.leashedplayer.content.items.type.ILeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.extend.CrossbowItem$ChargeTypeExtend;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.item.properties.select.SelectItemModelProperty;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.component.ChargedProjectiles;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public record ChargeExtend() implements SelectItemModelProperty<CrossbowItem$ChargeTypeExtend> {
|
||||
public static Codec<CrossbowItem$ChargeTypeExtend> CODEC = CrossbowItem$ChargeTypeExtend.CODEC;
|
||||
public static Type<ChargeExtend, CrossbowItem$ChargeTypeExtend> TYPE = Type.create(
|
||||
MapCodec.unit(new ChargeExtend()), CODEC
|
||||
);
|
||||
@Override
|
||||
public @NotNull CrossbowItem$ChargeTypeExtend get(@NotNull ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, @NotNull ItemDisplayContext displayContext) {
|
||||
ChargedProjectiles chargedprojectiles = stack.get(DataComponents.CHARGED_PROJECTILES);
|
||||
if(chargedprojectiles == null || chargedprojectiles.isEmpty()) {
|
||||
return CrossbowItem$ChargeTypeExtend.NONE;
|
||||
} else {
|
||||
return ILeashRopeArrow.isLeashRopeArrow(stack, entity) ? CrossbowItem$ChargeTypeExtend.LEASH_ROPE_ARROW :
|
||||
chargedprojectiles.contains(Items.FIREWORK_ROCKET) ? CrossbowItem$ChargeTypeExtend.ROCKET : CrossbowItem$ChargeTypeExtend.ARROW;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Codec<CrossbowItem$ChargeTypeExtend> valueCodec() {
|
||||
return CODEC;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Type<? extends SelectItemModelProperty<CrossbowItem$ChargeTypeExtend>, CrossbowItem$ChargeTypeExtend> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.r3944realms.leashedplayer.content.items.type.ILeashRopeArrow;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.item.properties.numeric.UseDuration;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public record BowPull() implements ConditionalRangeItemModelProperty {
|
||||
public static final MapCodec<BowPull> MAP_CODEC = MapCodec.unit(new BowPull());
|
||||
@Override
|
||||
public ConditionalRangeData get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext displayContext) {
|
||||
|
||||
if (entity != null && entity.getUseItem() == stack) {
|
||||
return ConditionalRangeData.create(ILeashRopeArrow.isLeashRopeArrow(stack, entity), (float)UseDuration.useDuration(stack, entity));
|
||||
}
|
||||
else return ConditionalRangeData.create(false, 0.0F);
|
||||
}
|
||||
|
||||
@Override
|
||||
public MapCodec<? extends ConditionalRangeItemModelProperty> type() {
|
||||
return MAP_CODEC;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public class ConditionalRangeItemModelProperties {
|
||||
private static final ExtraCodecs.LateBoundIdMapper<ResourceLocation, MapCodec<? extends ConditionalRangeItemModelProperty>> ID_MAPPER = new ExtraCodecs.LateBoundIdMapper<>();
|
||||
public static final MapCodec<ConditionalRangeItemModelProperty> MAP_CODEC = ID_MAPPER.codec(ResourceLocation.CODEC)
|
||||
.dispatchMap("property", ConditionalRangeItemModelProperty::type, mapCodec -> mapCodec);
|
||||
public static void bootstrap() {
|
||||
ID_MAPPER.put(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "bow_pull"), BowPull.MAP_CODEC);
|
||||
net.neoforged.fml.ModLoader.postEvent(new com.r3944realms.leashedplayer.content.events.RegisterConditionalRangeItemPropertyEvent(ID_MAPPER));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange;
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemDisplayContext;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
public interface ConditionalRangeItemModelProperty {
|
||||
ConditionalRangeData get(ItemStack stack, @Nullable ClientLevel level, @Nullable LivingEntity entity, int seed, ItemDisplayContext displayContext);
|
||||
|
||||
MapCodec<? extends ConditionalRangeItemModelProperty> type();
|
||||
record ConditionalRangeData(boolean boolValue, float floatValue) {
|
||||
public static ConditionalRangeData create(boolean boolValue, float floatValue) {
|
||||
return new ConditionalRangeData(boolValue, floatValue);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.r3944realms.leashedplayer.config;
|
||||
|
||||
import net.neoforged.neoforge.common.ModConfigSpec;
|
||||
|
||||
public class LeashPlayerCommonConfig {
|
||||
public static ModConfigSpec.Builder BUILDER = new ModConfigSpec.Builder();
|
||||
public static final ModConfigSpec SPEC;
|
||||
public static final ModConfigSpec.ConfigValue<String> LeashedPlayerModCommandPrefix;
|
||||
public static final ModConfigSpec.BooleanValue EnableLeashPlayerCommandPrefix;
|
||||
public static ModConfigSpec.IntValue MinimumLeashLengthCanBeSet, MaximumLeashLengthCanBeSet, TheLeashArrowMaxLifeTime;
|
||||
public static ModConfigSpec.DoubleValue TheMultipleThatLeashRopeArrowBreakLength, TheLeashBreakLengthTimesBase;
|
||||
static {
|
||||
BUILDER.comment("Leash Player Config");
|
||||
|
||||
BUILDER.comment("Leash Player Command");
|
||||
BUILDER.push("Command");
|
||||
EnableLeashPlayerCommandPrefix = BUILDER.comment("The prefix of this mod's commands"," [ Default: true] ").define("EnableLeashPlayerCommand", true);
|
||||
LeashedPlayerModCommandPrefix = BUILDER.comment("The prefix of this mod's commands"," [ Default:'lp'] ").define("LeashedPlayerModCommandPrefix", "lp");
|
||||
|
||||
BUILDER.pop();
|
||||
BUILDER.comment("Leash Player Arrow");
|
||||
BUILDER.push("LeashRopeArrow");
|
||||
TheMultipleThatLeashRopeArrowBreakLength = BUILDER.comment("How many times is the length of the arrow rope based on BreakLength TimeBase", "[ Default : 5.0f, Invalid Range:[2.0f, 10.0f] ]").defineInRange("TheMultipleArrowBreak", 5.0f, 2.0f , 10.0f);
|
||||
TheLeashArrowMaxLifeTime = BUILDER.comment("If the LeashArrowEntity's life is bigger than this value ,it will be discarded", "[ Default : 2400, Invalid Range:[1200 , 10240]]").defineInRange("TheLeashArrowMaxLifeTime",2400, 1200, 10240);
|
||||
BUILDER.pop();
|
||||
BUILDER.comment("Leash Player Misc");
|
||||
BUILDER.push("Misc");
|
||||
BUILDER.comment("Leash Player Length");
|
||||
BUILDER.push("LeashLength");
|
||||
TheLeashBreakLengthTimesBase = BUILDER.comment("When it exceeds how many times, the leash will drop"," [ Default:3.0f, Valid Range:[3.0f, 6.0f] ]").defineInRange("BreakLengthTimeBase", 3.0f, 3.0f ,6.0f);
|
||||
MinimumLeashLengthCanBeSet = BUILDER.comment("The minimum integer's length of Leash", " [ Default:5, Invalid Range:[2,10] ]").defineInRange("MinLeashLength", 5, 2, 10);
|
||||
MaximumLeashLengthCanBeSet = BUILDER.comment("The maximum integer's length of Leash", " [ Default:1024, Invalid Range:[32, 1024] ]").defineInRange("MaxLeashLength", 1024, 32, 1024);
|
||||
BUILDER.pop().pop();
|
||||
|
||||
|
||||
|
||||
SPEC = BUILDER.build();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.r3944realms.leashedplayer.content;
|
||||
|
||||
import com.mojang.blaze3d.platform.InputConstants;
|
||||
import net.minecraft.client.KeyMapping;
|
||||
import net.neoforged.neoforge.client.settings.KeyConflictContext;
|
||||
import net.neoforged.neoforge.client.settings.KeyModifier;
|
||||
import org.lwjgl.glfw.GLFW;
|
||||
|
||||
public class ModKeyMapping {
|
||||
static String KEY_ROOT_ = "key.leashedplayer.";
|
||||
public static String CATEGORY = "key.leashedplayer.category";
|
||||
public static String
|
||||
ADD_LEASH_LENGTH_KEY = KEY_ROOT_ + "leash_length.add",
|
||||
SUB_LEASH_LENGTH_KEY = KEY_ROOT_ + "leash_length.sub",
|
||||
NOT_SUPPORT_TO_NOT_PLAYER_ENTITY = KEY_ROOT_ + "leash_length.not_support_to_not_player_entity";
|
||||
|
||||
|
||||
public static final KeyMapping KEY_ADD_LEASH_LENGTH =
|
||||
new KeyMapping(
|
||||
ADD_LEASH_LENGTH_KEY,
|
||||
KeyConflictContext.IN_GAME,
|
||||
KeyModifier.CONTROL,
|
||||
InputConstants.Type.KEYSYM,
|
||||
GLFW.GLFW_KEY_UP,
|
||||
CATEGORY
|
||||
);
|
||||
public static final KeyMapping KEY_SUB_LEASH_LENGTH =
|
||||
new KeyMapping(
|
||||
SUB_LEASH_LENGTH_KEY,
|
||||
KeyConflictContext.IN_GAME,
|
||||
KeyModifier.CONTROL,
|
||||
InputConstants.Type.KEYSYM,
|
||||
GLFW.GLFW_KEY_DOWN,
|
||||
CATEGORY
|
||||
);
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.r3944realms.leashedplayer.content.commands;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class Command {
|
||||
public static final String PREFIX = LeashPlayerCommonConfig.LeashedPlayerModCommandPrefix.get();
|
||||
public static boolean SHOULD_USE_PREFIX = LeashPlayerCommonConfig.EnableLeashPlayerCommandPrefix.get();
|
||||
static LiteralArgumentBuilder<CommandSourceStack> getLiterArgumentBuilderOfCSS(String name, boolean shouldAddToList, @Nullable List<LiteralArgumentBuilder<CommandSourceStack>> list) {
|
||||
LiteralArgumentBuilder<CommandSourceStack> literal = Commands.literal(name);
|
||||
if (shouldAddToList) {
|
||||
assert list != null;
|
||||
list.add(literal);
|
||||
}
|
||||
return literal;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,58 @@
|
|||
package com.r3944realms.leashedplayer.content.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.Connection;
|
||||
import net.minecraft.network.PacketSendListener;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.chat.MutableComponent;
|
||||
import net.minecraft.network.protocol.common.ClientboundDisconnectPacket;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.commands.Command.SHOULD_USE_PREFIX;
|
||||
import static com.r3944realms.leashedplayer.content.commands.Command.getLiterArgumentBuilderOfCSS;
|
||||
|
||||
public class DebugCommand {
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
@Nullable List<LiteralArgumentBuilder<CommandSourceStack>> nodeList = SHOULD_USE_PREFIX ? null : new ArrayList<>();
|
||||
LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder = Commands.literal(Command.PREFIX);
|
||||
LiteralArgumentBuilder<CommandSourceStack> $$DebugRoot = getLiterArgumentBuilderOfCSS("debug", !SHOULD_USE_PREFIX, nodeList);
|
||||
com.mojang.brigadier.Command<CommandSourceStack> kickTargets = context -> {
|
||||
for(ServerPlayer entity : EntityArgument.getPlayers(context, "targets")){
|
||||
MutableComponent literal = Component.literal("You are already connected to this proxy!");
|
||||
Connection connection = entity.connection.getConnection();
|
||||
connection.send(new ClientboundDisconnectPacket(literal), PacketSendListener.thenRun(() -> connection.disconnect(literal)));
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
com.mojang.brigadier.Command<CommandSourceStack> kickSelf = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
if (source.getEntity() instanceof ServerPlayer serverPlayer) {
|
||||
MutableComponent literal = Component.literal("You are already connected to this proxy!");
|
||||
Connection connection = serverPlayer.connection.getConnection();
|
||||
connection.send(new ClientboundDisconnectPacket(literal), PacketSendListener.thenRun(() -> connection.disconnect(literal)));
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
LiteralArgumentBuilder<CommandSourceStack> debugKick = $$DebugRoot.requires(commandSourceStack -> commandSourceStack.hasPermission(2))
|
||||
.then(
|
||||
Commands.literal("kick").executes(kickSelf)
|
||||
.then(Commands.argument("targets", EntityArgument.entities())
|
||||
.executes(kickTargets)
|
||||
)
|
||||
);
|
||||
if(SHOULD_USE_PREFIX){
|
||||
literalArgumentBuilder.then(debugKick);
|
||||
dispatcher.register(literalArgumentBuilder);
|
||||
} else {
|
||||
nodeList.forEach(dispatcher::register);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,485 @@
|
|||
package com.r3944realms.leashedplayer.content.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.FloatArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.Server.CreateLeashFenceKnotEntityIfAbsent;
|
||||
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.commands.arguments.coordinates.BlockPosArgument;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collection;
|
||||
import java.util.List;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.commands.Command.getLiterArgumentBuilderOfCSS;
|
||||
|
||||
public class LeashCommand {
|
||||
public static final Integer MIN_VALUE = LeashPlayerCommonConfig.MinimumLeashLengthCanBeSet.get();
|
||||
public static final Integer MAX_VALUE = LeashPlayerCommonConfig.MaximumLeashLengthCanBeSet.get();
|
||||
private final static String LEASHEDPLAYER_LEASH_MESSAGE_ = "leashedplayer.command.leash.message.";
|
||||
|
||||
public final static String LEASH_FAILED = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.length.failed";
|
||||
|
||||
public final static String LEASH_LENGTH_SHOW = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.length.show",
|
||||
LEASH_LENGTH_SET = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.length.set",
|
||||
LEASH_DATA = LEASHEDPLAYER_LEASH_MESSAGE_ + "leash.data",
|
||||
LEASH_DATA_CLEAR = LEASH_DATA + ".clear"
|
||||
;
|
||||
|
||||
public final static String NO_LEASH_DATA = LEASH_DATA + ".null",
|
||||
LEASH_DATA_SHOW = LEASH_DATA + ".show",
|
||||
LEASH_DATA_SET = LEASH_DATA + ".set",
|
||||
LEASH_DATA_SET_FAILED_DIFF_LEVEL = LEASH_DATA_SET + ".failed.diff_level",
|
||||
LEASH_DATA_SET_FAILED_TOO_FAR = LEASH_DATA_SET + ".failed.too_far",
|
||||
LEASH_DATA_SET_FAILED_NO_KNOT_EXISTED_IN_THAT_POS = LEASH_DATA_SET + ".failed.no_knot_exist_in_that_pos",
|
||||
LEASH_DATA_SET_FAILED_FORBID_SAME_ENTITY = LEASH_DATA_SET + ".failed.forbid_same_entity",
|
||||
LEASH_DATA_CLEAR_FAILED_NO_DATA = LEASH_DATA_CLEAR + ".leash.clear.failed.no_data"
|
||||
;
|
||||
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
boolean shouldUsePrefix = LeashPlayerCommonConfig.EnableLeashPlayerCommandPrefix.get();
|
||||
@Nullable List<LiteralArgumentBuilder<CommandSourceStack>> nodeList = shouldUsePrefix ? null : new ArrayList<>();
|
||||
LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder = Commands.literal(com.r3944realms.leashedplayer.content.commands.Command.PREFIX);
|
||||
LiteralArgumentBuilder<CommandSourceStack> $$leashRoot = getLiterArgumentBuilderOfCSS("leash", !shouldUsePrefix, nodeList);
|
||||
|
||||
Command<CommandSourceStack> getSelfLeashLength = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
float leashLength = ((ILivingEntityExtension)player).getLeashLength();
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> getRefPlayerLeashLength = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
|
||||
float leashLength = ((ILivingEntityExtension)player).getLeashLength();
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> getRefPlayersLeashLength = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
|
||||
playerCol.forEach(player -> {
|
||||
float leashLength = ((ILivingEntityExtension) player).getLeashLength();
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SHOW, player.getDisplayName(), leashLength), true);
|
||||
});
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> setSelfLengthLeashLength = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
float leashLength = context.getArgument("leashLength", Float.class);
|
||||
((ILivingEntityExtension)player).setLeashLength(leashLength);
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> setRefPlayerLengthLeashLength = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
|
||||
float leashLength = context.getArgument("leashLength", Float.class);
|
||||
((ILivingEntityExtension)player).setLeashLength(leashLength);
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> setRefPlayersLengthLeashLength = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
float leashLength = context.getArgument("leashLength", Float.class);
|
||||
try {
|
||||
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
|
||||
playerCol.forEach(player -> {
|
||||
try {
|
||||
((ILivingEntityExtension)player).setLeashLength(leashLength);
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_LENGTH_SET, player.getDisplayName(), leashLength), true);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
//获取Data 构造一个MutableComponent显示数据
|
||||
Command<CommandSourceStack> geSelfLeashData = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
Integer x = LeashLengthGetResultInt(player, source);
|
||||
if (x != null) return x;
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
Command<CommandSourceStack> getRefPlayerLeashData = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
|
||||
Integer x = LeashLengthGetResultInt(player, source);
|
||||
if (x != null) return x;
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> getRefPlayersLeashData = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
|
||||
playerCol.forEach(player -> {
|
||||
try {
|
||||
LeashLengthGetResultInt(player, source);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
//设置前要判断其实体距离(同一维度,且距离不得大于其绳长的1.2倍(待定,也许可以设置在配置文件里)
|
||||
Command<CommandSourceStack> setSelfLeashDataEntity = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
Integer x = LeashDataEntitySetResultInt(context, player, source);
|
||||
if (x != null) return x;
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> setSelfLeashDataByBlockPos = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
Integer x = LeashDataBlockPosSetResultInt(context, source, player);
|
||||
if (x != null) return x;
|
||||
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
Command<CommandSourceStack> setRefPlayerLeashDataEntity = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
|
||||
Integer x = LeashDataEntitySetResultInt(context, player, source);
|
||||
if (x != null) return x;
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> setRefPlayersLeashDataEntity = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
|
||||
playerCol.forEach(player -> {
|
||||
try {
|
||||
LeashDataEntitySetResultInt(context, player, source);
|
||||
} catch (CommandSyntaxException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> setRefPlayersLeashDataByBlockPos = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
|
||||
playerCol.forEach(player -> {
|
||||
LeashDataBlockPosSetResultInt(context, source, player);
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> setRefPlayerLeashDataByBlockPos = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
|
||||
Integer x = LeashDataBlockPosSetResultInt(context, source, player);
|
||||
if (x != null) return x;
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
Command<CommandSourceStack> clearSelfLeashData = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = source.getPlayerOrException();
|
||||
Integer x = LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()), player);
|
||||
if (x != null) return x;
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> clearRefPlayerLeashData = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
ServerPlayer player = EntityArgument.getPlayer(context, "targetPlayer");
|
||||
Integer x = LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()),player);
|
||||
if (x != null) return x;
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> clearRefPlayersLeashData = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
try {
|
||||
Collection<ServerPlayer> playerCol = EntityArgument.getPlayers(context, "targetPlayers");
|
||||
playerCol.forEach(player -> {
|
||||
try {
|
||||
LeashDataClearResultInt(source, PlayerLeashable.getLeashDataEntity(player, source.getLevel()),player);
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
});
|
||||
|
||||
} catch (Exception e) {
|
||||
source.sendFailure(Component.translatable(LEASH_FAILED));
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> SelfLeashLength = $$leashRoot.then(Commands.literal("length").executes(getSelfLeashLength)
|
||||
.then(Commands.literal("get").executes(getSelfLeashLength))
|
||||
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setSelfLengthLeashLength))
|
||||
)
|
||||
);
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> RefPlayerLeashLength = $$leashRoot.then(
|
||||
Commands.literal("length")
|
||||
.then(Commands.argument("targetPlayer", EntityArgument.player()).executes(getRefPlayerLeashLength)
|
||||
.then(Commands.literal("get").executes(getRefPlayerLeashLength))
|
||||
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
|
||||
.then(
|
||||
Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefPlayerLengthLeashLength)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.argument("targetPlayers", EntityArgument.players()).executes(getRefPlayersLeashLength)
|
||||
.then(Commands.literal("get").executes(getRefPlayersLeashLength))
|
||||
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
|
||||
.then(
|
||||
Commands.argument("leashLength", FloatArgumentType.floatArg(MIN_VALUE, MAX_VALUE)).executes(setRefPlayersLengthLeashLength)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> RefPLayerData = $$leashRoot.then(
|
||||
Commands.literal("data")
|
||||
.then(Commands.argument("targetPlayer", EntityArgument.player()).executes(getRefPlayerLeashData)
|
||||
.then(Commands.literal("get")
|
||||
.executes(getRefPlayerLeashData)
|
||||
)
|
||||
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("holderEntity", EntityArgument.entity())
|
||||
.executes(setRefPlayerLeashDataEntity)
|
||||
)
|
||||
.then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
|
||||
.executes(setRefPlayerLeashDataByBlockPos)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefPlayerLeashData))
|
||||
)
|
||||
.then(Commands.argument("targetPlayers", EntityArgument.players()).executes(getRefPlayersLeashData)
|
||||
.then(Commands.literal("get")
|
||||
.executes(getRefPlayersLeashData)
|
||||
)
|
||||
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("holderEntity", EntityArgument.entity())
|
||||
.executes(setRefPlayersLeashDataEntity)
|
||||
)
|
||||
.then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
|
||||
.executes(setRefPlayersLeashDataByBlockPos)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("clear").requires(cs -> cs.hasPermission(2)).executes(clearRefPlayersLeashData))
|
||||
));
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> SelfData = $$leashRoot.then(
|
||||
Commands.literal("data")
|
||||
.then(Commands.literal("get")
|
||||
.executes(geSelfLeashData)
|
||||
)
|
||||
.then(Commands.literal("set").requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("holderEntity", EntityArgument.entity())
|
||||
.executes(setSelfLeashDataEntity)
|
||||
)
|
||||
.then(Commands.argument("BlockPos", BlockPosArgument.blockPos())
|
||||
.executes(setSelfLeashDataByBlockPos)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("clear").requires(cs -> cs.hasPermission(2))
|
||||
.executes(clearSelfLeashData)
|
||||
)
|
||||
);
|
||||
|
||||
if(shouldUsePrefix) {
|
||||
literalArgumentBuilder
|
||||
.then(RefPlayerLeashLength)
|
||||
.then(SelfLeashLength)
|
||||
.then(RefPLayerData)
|
||||
.then(SelfData);
|
||||
dispatcher.register(literalArgumentBuilder);
|
||||
} else {
|
||||
nodeList.forEach(dispatcher::register);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private static @Nullable Integer LeashLengthGetResultInt(ServerPlayer player, CommandSourceStack source) throws Exception {
|
||||
Leashable.LeashData leashDataFromEntityData = ((PlayerLeashable) player).getLeashDataFromEntityData();
|
||||
|
||||
if(leashDataFromEntityData == null) {
|
||||
source.sendSuccess(() -> Component.translatable(NO_LEASH_DATA, player.getDisplayName()), true);
|
||||
return 1;
|
||||
} else {
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntityOrThrown(leashDataFromEntityData, source.getLevel());
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_DATA_SHOW, player.getDisplayName(), leashDataEntity.getDisplayName()), true);
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Nullable Integer LeashDataBlockPosSetResultInt(CommandContext<CommandSourceStack> context, CommandSourceStack source, ServerPlayer player) {
|
||||
BlockPos blockPos = BlockPosArgument.getBlockPos(context, "BlockPos");
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashFenceKnotEntity(source.getLevel(), blockPos);
|
||||
PlayerLeashable leashedPlayer = (PlayerLeashable) player;
|
||||
Component targetPlayerDisplayName = player.getDisplayName();
|
||||
if(leashDataEntity == null) {
|
||||
ServerLevel level = context.getSource().getLevel();
|
||||
if(GameruleRegistry.getGameruleBoolValue(level,CreateLeashFenceKnotEntityIfAbsent.ID)) {
|
||||
if(level.getBlockState(blockPos).is(BlockTags.FENCES)) {
|
||||
Entity leashKnotFence = PlayerLeashable.createLeashKnotFence(level, blockPos);
|
||||
leashedPlayer.setLeashedTo(leashKnotFence, true);
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_DATA_SET, targetPlayerDisplayName, leashKnotFence.getDisplayName()), true);
|
||||
return null;
|
||||
}
|
||||
}
|
||||
source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_NO_KNOT_EXISTED_IN_THAT_POS, blockPos.getX(), blockPos.getY(), blockPos.getZ()));
|
||||
return 1;
|
||||
}
|
||||
Component leashDataEntityDisplayName = leashDataEntity.getDisplayName();
|
||||
|
||||
return LeashDataCommonPartSetResultInt(source, player, leashDataEntity, leashedPlayer, targetPlayerDisplayName, leashDataEntityDisplayName);
|
||||
}
|
||||
|
||||
private static @Nullable Integer LeashDataEntitySetResultInt(CommandContext<CommandSourceStack> context, ServerPlayer player, CommandSourceStack source) throws CommandSyntaxException {
|
||||
Entity leashDataEntity = EntityArgument.getEntity(context, "holderEntity");
|
||||
PlayerLeashable leashedPlayer = (PlayerLeashable) player;
|
||||
Component targetPlayerDisplayName = player.getDisplayName();
|
||||
Component leashDataEntityDisplayName = leashDataEntity.getDisplayName();
|
||||
if(player.equals(leashDataEntity)) {
|
||||
source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_FORBID_SAME_ENTITY));
|
||||
return 1;
|
||||
}
|
||||
return LeashDataCommonPartSetResultInt(source, player, leashDataEntity, leashedPlayer, targetPlayerDisplayName, leashDataEntityDisplayName);
|
||||
}
|
||||
|
||||
private static @Nullable Integer LeashDataCommonPartSetResultInt(CommandSourceStack source, ServerPlayer player, Entity leashDataEntity, PlayerLeashable leashedPlayer, Component targetPlayerDisplayName, Component leashDataEntityDisplayName) {
|
||||
if(player.level() != leashDataEntity.level()) {
|
||||
source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_DIFF_LEVEL, targetPlayerDisplayName, leashDataEntityDisplayName));
|
||||
return 2;
|
||||
}
|
||||
ILivingEntityExtension targetPlayerExtension = (ILivingEntityExtension) player;
|
||||
if (player.distanceTo(leashDataEntity) > targetPlayerExtension.getLeashLength() * 1.2f) {
|
||||
source.sendFailure(Component.translatable(LEASH_DATA_SET_FAILED_TOO_FAR, targetPlayerDisplayName, leashDataEntityDisplayName, targetPlayerExtension.getLeashLength()));
|
||||
return 3;
|
||||
}
|
||||
leashedPlayer.setLeashedTo(leashDataEntity, true);
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_DATA_SET, targetPlayerDisplayName, leashDataEntityDisplayName), true);
|
||||
return null;
|
||||
}
|
||||
|
||||
private static @Nullable Integer LeashDataClearResultInt(CommandSourceStack source, Entity leashDataEntity, ServerPlayer serverPlayer) {
|
||||
if(leashDataEntity == null) {
|
||||
source.sendFailure(Component.translatable(LEASH_DATA_CLEAR_FAILED_NO_DATA, serverPlayer.getDisplayName()));
|
||||
return 1;
|
||||
}
|
||||
Leashable.dropLeash((Entity & Leashable) serverPlayer, true, false);
|
||||
source.sendSuccess(() -> Component.translatable(LEASH_DATA_CLEAR, serverPlayer.getDisplayName(), leashDataEntity.getDisplayName()), true);
|
||||
return null;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.r3944realms.leashedplayer.content.commands;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.DoubleArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
|
||||
import com.r3944realms.leashedplayer.network.client.UpdatePlayerMovement;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.neoforged.neoforge.network.PacketDistributor;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.commands.Command.getLiterArgumentBuilderOfCSS;
|
||||
|
||||
public class MotionCommand {
|
||||
private final static String LEASHED_PLAYER_MOTION_MESSAGE_ = "leashedplayer.command.motion.message.";
|
||||
public final static String MOTION_SETTER_SUCCESSFUL = LEASHED_PLAYER_MOTION_MESSAGE_ + "setter.successful",
|
||||
MOTION_ADDER_SUCCESSFUL = LEASHED_PLAYER_MOTION_MESSAGE_ + "adder.successful",
|
||||
MOTION_MULTIPLY_SUCCESSFUL = LEASHED_PLAYER_MOTION_MESSAGE_ + "multiply.successful";
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
boolean shouldUsePrefix = LeashPlayerCommonConfig.EnableLeashPlayerCommandPrefix.get();
|
||||
@Nullable List<LiteralArgumentBuilder<CommandSourceStack>> nodeList = shouldUsePrefix ? null : new ArrayList<>();
|
||||
LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder = Commands.literal(com.r3944realms.leashedplayer.content.commands.Command.PREFIX);
|
||||
LiteralArgumentBuilder<CommandSourceStack> $$motionRoot = getLiterArgumentBuilderOfCSS("motion", !shouldUsePrefix, nodeList);
|
||||
Command<CommandSourceStack> motionVecAdder = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
for(Entity entity : EntityArgument.getEntities(context, "targets")){
|
||||
Vec3 motionVec = new Vec3(
|
||||
DoubleArgumentType.getDouble(context, "vecX"),
|
||||
DoubleArgumentType.getDouble(context, "vecY"),
|
||||
DoubleArgumentType.getDouble(context, "vecZ")
|
||||
);
|
||||
if(entity instanceof ServerPlayer player) {
|
||||
PacketDistributor.sendToPlayer(player, new UpdatePlayerMovement(UpdatePlayerMovement.Operation.ADD, motionVec.x, motionVec.y, motionVec.z));
|
||||
player.addDeltaMovement(new Vec3(motionVec.x, motionVec.y, motionVec.z));
|
||||
} else {
|
||||
entity.addDeltaMovement(motionVec);
|
||||
}
|
||||
double vecX = entity.getDeltaMovement().x, vecY = entity.getDeltaMovement().y, vecZ = entity.getDeltaMovement().z;
|
||||
source.sendSuccess(() -> Component.translatable(MOTION_ADDER_SUCCESSFUL, entity.getName().copy().withStyle(), vecX, vecY, vecZ), true);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> motionVecSetter = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
for(Entity entity : EntityArgument.getEntities(context, "targets")){
|
||||
Vec3 motionVec = new Vec3(
|
||||
DoubleArgumentType.getDouble(context, "vecX"),
|
||||
DoubleArgumentType.getDouble(context, "vecY"),
|
||||
DoubleArgumentType.getDouble(context, "vecZ")
|
||||
);
|
||||
if(entity instanceof ServerPlayer player) {
|
||||
PacketDistributor.sendToPlayer(player, new UpdatePlayerMovement(UpdatePlayerMovement.Operation.SET, motionVec.x, motionVec.y, motionVec.z));
|
||||
player.setDeltaMovement(new Vec3(motionVec.x, motionVec.y, motionVec.z));
|
||||
} else {
|
||||
entity.setDeltaMovement(motionVec);
|
||||
}
|
||||
double vecX = entity.getDeltaMovement().x, vecY = entity.getDeltaMovement().y, vecZ = entity.getDeltaMovement().z;
|
||||
source.sendSuccess(() -> Component.translatable(MOTION_SETTER_SUCCESSFUL, entity.getName().copy(), vecX, vecY, vecZ), true);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
Command<CommandSourceStack> motionVecMultiply = context -> {
|
||||
CommandSourceStack source = context.getSource();
|
||||
for(Entity entity : EntityArgument.getEntities(context, "targets")){
|
||||
Vec3 motionFactorVec = new Vec3(
|
||||
DoubleArgumentType.getDouble(context, "vecXFactor"),
|
||||
DoubleArgumentType.getDouble(context, "vecYFactor"),
|
||||
DoubleArgumentType.getDouble(context, "vecZFactor")
|
||||
);
|
||||
if(entity instanceof ServerPlayer player) {
|
||||
PacketDistributor.sendToPlayer(player, new UpdatePlayerMovement(UpdatePlayerMovement.Operation.MULTIPLY, motionFactorVec.x, motionFactorVec.y, motionFactorVec.z));
|
||||
player.setDeltaMovement(entity.getDeltaMovement().multiply(motionFactorVec));
|
||||
} else {
|
||||
entity.setDeltaMovement(entity.getDeltaMovement().multiply(motionFactorVec));
|
||||
}
|
||||
double vecX = entity.getDeltaMovement().x, vecY = entity.getDeltaMovement().y, vecZ = entity.getDeltaMovement().z;
|
||||
source.sendSuccess(() -> Component.translatable(MOTION_MULTIPLY_SUCCESSFUL, entity.getName().copy(), vecX, vecY, vecZ), true);
|
||||
}
|
||||
return 0;
|
||||
};
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> Motion = $$motionRoot.requires(cs -> cs.hasPermission(2))
|
||||
.then(Commands.argument("targets", EntityArgument.entities())
|
||||
.then(Commands.literal("add")
|
||||
.then(Commands.argument("vecX", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecY", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecZ", DoubleArgumentType.doubleArg())
|
||||
.executes(motionVecAdder)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("set")
|
||||
.then(Commands.argument("vecX", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecY", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecZ", DoubleArgumentType.doubleArg())
|
||||
.executes(motionVecSetter)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("multiply")
|
||||
.then(Commands.argument("vecXFactor", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecYFactor", DoubleArgumentType.doubleArg())
|
||||
.then(Commands.argument("vecZFactor", DoubleArgumentType.doubleArg())
|
||||
.executes(motionVecMultiply)
|
||||
)
|
||||
)
|
||||
)
|
||||
)
|
||||
);
|
||||
if(shouldUsePrefix){
|
||||
literalArgumentBuilder.then(Motion);
|
||||
dispatcher.register(literalArgumentBuilder);
|
||||
} else {
|
||||
nodeList.forEach(dispatcher::register);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,181 @@
|
|||
package com.r3944realms.leashedplayer.content.commands;
|
||||
|
||||
import com.mojang.brigadier.CommandDispatcher;
|
||||
import com.mojang.brigadier.arguments.FloatArgumentType;
|
||||
import com.mojang.brigadier.arguments.IntegerArgumentType;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.SharedSuggestionProvider;
|
||||
import net.minecraft.commands.arguments.TimeArgument;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.ServerTickRateManager;
|
||||
import net.minecraft.util.TimeUtil;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.commands.Command.getLiterArgumentBuilderOfCSS;
|
||||
|
||||
public class TickCommand {
|
||||
private static final float MAX_TICKRATE = 10000.0F;
|
||||
private static final String DEFAULT_TICKRATE = String.valueOf(20);
|
||||
|
||||
public static void register(CommandDispatcher<CommandSourceStack> dispatcher) {
|
||||
boolean shouldUsePrefix = LeashPlayerCommonConfig.EnableLeashPlayerCommandPrefix.get();
|
||||
@Nullable List<LiteralArgumentBuilder<CommandSourceStack>> nodeList = shouldUsePrefix ? null : new ArrayList<>();
|
||||
LiteralArgumentBuilder<CommandSourceStack> literalArgumentBuilder = Commands.literal(Command.PREFIX);
|
||||
LiteralArgumentBuilder<CommandSourceStack> $$TickRoot = getLiterArgumentBuilderOfCSS("tick", !shouldUsePrefix, nodeList);
|
||||
|
||||
LiteralArgumentBuilder<CommandSourceStack> Tick = $$TickRoot.requires(p_308941_ -> p_308941_.hasPermission(2))
|
||||
.then(Commands.literal("query").executes(p_308950_ -> tickQuery(p_308950_.getSource())))
|
||||
.then(
|
||||
Commands.literal("rate")
|
||||
.then(
|
||||
Commands.argument("rate", FloatArgumentType.floatArg(1.0F, 10000.0F))
|
||||
.suggests((p_308897_, p_308880_) -> SharedSuggestionProvider.suggest(new String[]{DEFAULT_TICKRATE}, p_308880_))
|
||||
.executes(p_309119_ -> setTickingRate(p_309119_.getSource(), FloatArgumentType.getFloat(p_309119_, "rate")))
|
||||
)
|
||||
)
|
||||
.then(
|
||||
Commands.literal("step")
|
||||
.executes(p_309496_ -> step(p_309496_.getSource(), 1))
|
||||
.then(Commands.literal("stop").executes(p_309035_ -> stopStepping(p_309035_.getSource())))
|
||||
.then(
|
||||
Commands.argument("time", TimeArgument.time(1))
|
||||
.suggests((p_309113_, p_309105_) -> SharedSuggestionProvider.suggest(new String[]{"1t", "1s"}, p_309105_))
|
||||
.executes(p_308930_ -> step(p_308930_.getSource(), IntegerArgumentType.getInteger(p_308930_, "time")))
|
||||
)
|
||||
)
|
||||
.then(
|
||||
Commands.literal("sprint")
|
||||
.then(Commands.literal("stop").executes(p_309190_ -> stopSprinting(p_309190_.getSource())))
|
||||
.then(
|
||||
Commands.argument("time", TimeArgument.time(1))
|
||||
.suggests((p_308987_, p_309101_) -> SharedSuggestionProvider.suggest(new String[]{"60s", "1d", "3d"}, p_309101_))
|
||||
.executes(p_308904_ -> sprint(p_308904_.getSource(), IntegerArgumentType.getInteger(p_308904_, "time")))
|
||||
)
|
||||
)
|
||||
.then(Commands.literal("unfreeze").executes(p_309184_ -> setFreeze(p_309184_.getSource(), false)))
|
||||
.then(Commands.literal("freeze").executes(p_309070_ -> setFreeze(p_309070_.getSource(), true)));
|
||||
if(shouldUsePrefix){
|
||||
literalArgumentBuilder.then(Tick);
|
||||
dispatcher.register(literalArgumentBuilder);
|
||||
} else {
|
||||
nodeList.forEach(dispatcher::register);
|
||||
}
|
||||
}
|
||||
|
||||
private static String nanosToMilisString(long nanos) {
|
||||
return String.format("%.1f", (float)nanos / (float) TimeUtil.NANOSECONDS_PER_MILLISECOND);
|
||||
}
|
||||
|
||||
private static int setTickingRate(CommandSourceStack source, float tickRate) {
|
||||
ServerTickRateManager servertickratemanager = source.getServer().tickRateManager();
|
||||
servertickratemanager.setTickRate(tickRate);
|
||||
String s = String.format("%.1f", tickRate);
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.rate.success", s), true);
|
||||
return (int)tickRate;
|
||||
}
|
||||
|
||||
private static int tickQuery(CommandSourceStack source) {
|
||||
ServerTickRateManager servertickratemanager = source.getServer().tickRateManager();
|
||||
String s = nanosToMilisString(source.getServer().getAverageTickTimeNanos());
|
||||
float f = servertickratemanager.tickrate();
|
||||
String s1 = String.format("%.1f", f);
|
||||
if (servertickratemanager.isSprinting()) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.status.sprinting"), false);
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.query.rate.sprinting", s1, s), false);
|
||||
} else {
|
||||
if (servertickratemanager.isFrozen()) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.status.frozen"), false);
|
||||
} else if (servertickratemanager.nanosecondsPerTick() < source.getServer().getAverageTickTimeNanos()) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.status.lagging"), false);
|
||||
} else {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.status.running"), false);
|
||||
}
|
||||
|
||||
String s2 = nanosToMilisString(servertickratemanager.nanosecondsPerTick());
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.query.rate.running", s1, s, s2), false);
|
||||
}
|
||||
|
||||
long[] along = Arrays.copyOf(source.getServer().getTickTimesNanos(), source.getServer().getTickTimesNanos().length);
|
||||
Arrays.sort(along);
|
||||
String s3 = nanosToMilisString(along[along.length / 2]);
|
||||
String s4 = nanosToMilisString(along[(int)((double)along.length * 0.95)]);
|
||||
String s5 = nanosToMilisString(along[(int)((double)along.length * 0.99)]);
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.query.percentiles", s3, s4, s5, along.length), false);
|
||||
return (int)f;
|
||||
}
|
||||
|
||||
private static int sprint(CommandSourceStack source, int sprintTime) {
|
||||
boolean flag = source.getServer().tickRateManager().requestGameToSprint(sprintTime);
|
||||
if (flag) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.sprint.stop.success"), true);
|
||||
}
|
||||
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.status.sprinting"), true);
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int setFreeze(CommandSourceStack source, boolean frozen) {
|
||||
ServerTickRateManager servertickratemanager = source.getServer().tickRateManager();
|
||||
if (frozen) {
|
||||
if (servertickratemanager.isSprinting()) {
|
||||
servertickratemanager.stopSprinting();
|
||||
}
|
||||
|
||||
if (servertickratemanager.isSteppingForward()) {
|
||||
servertickratemanager.stopStepping();
|
||||
}
|
||||
}
|
||||
|
||||
servertickratemanager.setFrozen(frozen);
|
||||
if (frozen) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.status.frozen"), true);
|
||||
} else {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.status.running"), true);
|
||||
}
|
||||
|
||||
return frozen ? 1 : 0;
|
||||
}
|
||||
|
||||
private static int step(CommandSourceStack source, int ticks) {
|
||||
ServerTickRateManager servertickratemanager = source.getServer().tickRateManager();
|
||||
boolean flag = servertickratemanager.stepGameIfPaused(ticks);
|
||||
if (flag) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.step.success", ticks), true);
|
||||
} else {
|
||||
source.sendFailure(Component.translatable("commands.tick.step.fail"));
|
||||
}
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
private static int stopStepping(CommandSourceStack source) {
|
||||
ServerTickRateManager servertickratemanager = source.getServer().tickRateManager();
|
||||
boolean flag = servertickratemanager.stopStepping();
|
||||
if (flag) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.step.stop.success"), true);
|
||||
return 1;
|
||||
} else {
|
||||
source.sendFailure(Component.translatable("commands.tick.step.stop.fail"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
private static int stopSprinting(CommandSourceStack source) {
|
||||
ServerTickRateManager servertickratemanager = source.getServer().tickRateManager();
|
||||
boolean flag = servertickratemanager.stopSprinting();
|
||||
if (flag) {
|
||||
source.sendSuccess(() -> Component.translatable("commands.tick.sprint.stop.success"), true);
|
||||
return 1;
|
||||
} else {
|
||||
source.sendFailure(Component.translatable("commands.tick.sprint.stop.fail"));
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.r3944realms.leashedplayer.content.criteriaTriggers;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import com.mojang.serialization.codecs.RecordCodecBuilder;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.advancements.Criterion;
|
||||
import net.minecraft.advancements.critereon.ContextAwarePredicate;
|
||||
import net.minecraft.advancements.critereon.EntityPredicate;
|
||||
import net.minecraft.advancements.critereon.SimpleCriterionTrigger;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class LeashPlayerTrigger extends SimpleCriterionTrigger<LeashPlayerTrigger.TriggerInstance> {
|
||||
|
||||
@Override
|
||||
public @NotNull Codec<TriggerInstance> codec() {
|
||||
return TriggerInstance.CODEC;
|
||||
}
|
||||
public void trigger(ServerPlayer pPlayer, Entity pHolderEntity) {
|
||||
this.trigger(pPlayer, pl -> pl.matches(pPlayer, pHolderEntity));
|
||||
}
|
||||
|
||||
public record TriggerInstance(Optional<ContextAwarePredicate> player, Optional<EntityPredicate> holder) implements SimpleInstance {
|
||||
public static final Codec<TriggerInstance> CODEC =
|
||||
RecordCodecBuilder.create(instance ->
|
||||
instance.group(
|
||||
EntityPredicate.ADVANCEMENT_CODEC.optionalFieldOf("player").forGetter(TriggerInstance::player),
|
||||
EntityPredicate.CODEC.optionalFieldOf("holder").forGetter(TriggerInstance::holder)
|
||||
)
|
||||
.apply(instance, TriggerInstance::new));
|
||||
// public static Criterion<TriggerInstance> LeashSelf() {
|
||||
// return ModCriteriaTriggers.LEASH_PLAYER_TRIGGER.get().createCriterion(new TriggerInstance(Optional.empty(), Optional.empty()));
|
||||
// }
|
||||
public static Criterion<TriggerInstance> LeashPlayer(EntityPredicate.Builder holder) {
|
||||
return ModCriteriaTriggers.LEASH_PLAYER_TRIGGER.get().createCriterion(new TriggerInstance(Optional.empty(), Optional.of(holder.build())));
|
||||
}
|
||||
|
||||
public boolean matches(ServerPlayer player, Entity holder) {
|
||||
PlayerLeashable ppl = (PlayerLeashable) player;
|
||||
return ppl.isLeashed() && holder.equals(PlayerLeashable.getLeashDataEntity(player, player.serverLevel())) && this.holder.isPresent() && this.holder.get().matches(player, holder);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,17 @@
|
|||
package com.r3944realms.leashedplayer.content.criteriaTriggers;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.advancements.CriterionTrigger;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
public class ModCriteriaTriggers {
|
||||
public static final DeferredRegister<CriterionTrigger<?>> TRIGGERS = DeferredRegister.create(Registries.TRIGGER_TYPE, LeashedPlayer.MOD_ID);
|
||||
public static final DeferredHolder<CriterionTrigger<?>, LeashPlayerTrigger> LEASH_PLAYER_TRIGGER =
|
||||
TRIGGERS.register("leash_player", LeashPlayerTrigger::new);
|
||||
public static void register(IEventBus eventBus) {
|
||||
TRIGGERS.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
package com.r3944realms.leashedplayer.content.effects;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.effects.type.NoLeashEffect;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectCategory;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModEffectRegister {
|
||||
public static DeferredRegister<MobEffect> MOB_EFFECT = DeferredRegister.create(Registries.MOB_EFFECT, LeashedPlayer.MOD_ID);
|
||||
public static DeferredHolder<MobEffect, ? extends MobEffect> NO_LEASH_EFFECT = register(
|
||||
"no_leash",
|
||||
() -> new NoLeashEffect(MobEffectCategory.NEUTRAL, 12063764)
|
||||
);
|
||||
public static <T extends MobEffect>DeferredHolder<MobEffect, T> register(String name, Supplier<T> effect) {
|
||||
return MOB_EFFECT.register(name, effect);
|
||||
}
|
||||
|
||||
public static String getEffectKey(MobEffect effect) {
|
||||
return effect.getDescriptionId();
|
||||
}
|
||||
public static String getModEffectKey(DeferredHolder<MobEffect, ? extends MobEffect> effect) {
|
||||
return getEffectKey(effect.get());
|
||||
}
|
||||
public static void register(IEventBus eventBus) {
|
||||
MOB_EFFECT.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,41 @@
|
|||
package com.r3944realms.leashedplayer.content.effects;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.item.alchemy.Potion;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModPotionRegister {
|
||||
public static DeferredRegister<Potion> POTIONS = DeferredRegister.create(Registries.POTION, LeashedPlayer.MOD_ID);
|
||||
public static final DeferredHolder<Potion, Potion> NO_LEASH = register("no_leash",
|
||||
() -> new Potion("no_leash", new MobEffectInstance(ModEffectRegister.NO_LEASH_EFFECT, 7200, 0))
|
||||
);
|
||||
public static <T extends Potion>DeferredHolder<Potion, Potion> register(String Name, Supplier<T> supplier) {
|
||||
return POTIONS.register(Name, supplier);
|
||||
}
|
||||
/**
|
||||
*
|
||||
* @param name the Name of Potion
|
||||
* @param type (char)<br/> [ <br/> 0 & 3 ~ 255 : potion <br/>1 : lingering_potion <br/>2 : splash_potion<br/>]
|
||||
* @return Language Key
|
||||
*/
|
||||
public static String getPotionNameKey(String name, char type) {
|
||||
return "item.minecraft." +
|
||||
(type == 1 ? "lingering_potion" :
|
||||
(type == 2 ? "splash_potion" : "potion")
|
||||
)
|
||||
+ ".effect." + name;
|
||||
}
|
||||
public static String getTippedArrowNameKey(String Name) {
|
||||
return "item.minecraft.tipped_arrow.effect." + Name;
|
||||
}
|
||||
|
||||
public static void register(IEventBus eventBus) {
|
||||
POTIONS.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,38 @@
|
|||
package com.r3944realms.leashedplayer.content.effects.type;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectCategory;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class NoLeashEffect extends MobEffect {
|
||||
public NoLeashEffect(MobEffectCategory pCategory, int pColor) {
|
||||
super(pCategory, pColor);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean applyEffectTick(@NotNull ServerLevel level, @NotNull LivingEntity pLivingEntity, int pAmplifier) {
|
||||
MobEffectInstance effect = pLivingEntity.getEffect(ModEffectRegister.NO_LEASH_EFFECT);
|
||||
if(effect != null && effect.getDuration() != 0) {
|
||||
if (pLivingEntity instanceof Leashable leashable) {
|
||||
if (leashable.getLeashHolder() instanceof LeashRopeArrow arrow) {
|
||||
arrow.dropLeashHandler();
|
||||
Leashable.dropLeash((Entity & Leashable) leashable,true, false);
|
||||
}
|
||||
Leashable.dropLeash((Entity & Leashable) leashable,true, true);
|
||||
}
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyEffectTickThisTick(int pDuration, int pAmplifier) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.r3944realms.leashedplayer.content.effects.type;
|
||||
|
||||
import net.minecraft.world.effect.MobEffect;
|
||||
import net.minecraft.world.effect.MobEffectCategory;
|
||||
|
||||
|
||||
public class StunnedEffect extends MobEffect {
|
||||
public StunnedEffect() {
|
||||
super(MobEffectCategory.HARMFUL, 0XFFFBC5);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,457 @@
|
|||
package com.r3944realms.leashedplayer.content.entities;
|
||||
|
||||
import com.r3944realms.leashedplayer.config.LeashPlayerCommonConfig;
|
||||
import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.Server.KeepLeashNotDropTime;
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.particles.ColorParticleOption;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
|
||||
import net.minecraft.world.entity.item.ItemEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.PotionContents;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.BlockHitResult;
|
||||
import net.minecraft.world.phys.EntityHitResult;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class LeashRopeArrow extends AbstractArrow {
|
||||
public static final String PUSH_SHIFT_TO_PICKUP_QUICKLY = "leashedplayer.leash_rope_arrow.try_to_pickup.push_shift_tip";
|
||||
private static final int EXPOSED_POTION_DECAY_TIME = 600;
|
||||
private static final int NO_EFFECT_COLOR = -1;
|
||||
private static final EntityDataAccessor<Integer> ID_EFFECT_COLOR = SynchedEntityData.defineId(LeashRopeArrow.class, EntityDataSerializers.INT);
|
||||
private static final byte EVENT_POTION_PUFF = 0;
|
||||
private static final int maxLifeTime = LeashPlayerCommonConfig.TheLeashArrowMaxLifeTime.get();
|
||||
protected LeashRopeArrow(EntityType<? extends AbstractArrow> entityType,Level pLevel) {
|
||||
super(entityType, pLevel);
|
||||
|
||||
}
|
||||
private PotionContents getPotionContents() {
|
||||
ItemStack pickupItemStackOrigin = this.getPickupItemStackOrigin();
|
||||
pickupItemStackOrigin.setCount(1);
|
||||
return pickupItemStackOrigin.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY);
|
||||
}
|
||||
|
||||
public void addEffect(MobEffectInstance pEffectInstance) {
|
||||
this.setPotionContents(this.getPotionContents().withEffectAdded(pEffectInstance));
|
||||
}
|
||||
|
||||
private void setPotionContents(PotionContents pPotionContents) {
|
||||
this.getPickupItemStackOrigin().set(DataComponents.POTION_CONTENTS, pPotionContents);
|
||||
this.updateColor();
|
||||
}
|
||||
|
||||
private void updateColor() {
|
||||
PotionContents potioncontents = this.getPotionContents();
|
||||
this.entityData.set(ID_EFFECT_COLOR, potioncontents.equals(PotionContents.EMPTY) ? -1 : potioncontents.getColor());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void defineSynchedData(SynchedEntityData.@NotNull Builder pBuilder) {
|
||||
super.defineSynchedData(pBuilder);
|
||||
pBuilder.define(ID_EFFECT_COLOR, -1);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void setPickupItemStack(@NotNull ItemStack pPickupItemStack) {
|
||||
super.setPickupItemStack(pPickupItemStack);
|
||||
this.updateColor();
|
||||
}
|
||||
|
||||
public LeashRopeArrow(EntityType<? extends AbstractArrow> entityType, double pX, double pY, double pZ, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon, @Nullable ServerPlayer serverPlayer) {
|
||||
super(entityType, pX, pY, pZ, pLevel, pPickupItemStack, pFiredFromWeapon);
|
||||
this.updateColor();
|
||||
if(serverPlayer != null && !level().isClientSide) {
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity(serverPlayer, (ServerLevel) level());
|
||||
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.setOwner(null);//将先前的箭矢置空
|
||||
}
|
||||
((PlayerLeashable)serverPlayer).setLeashedTo(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
public LeashRopeArrow(EntityType<? extends AbstractArrow> entityType, LivingEntity pOwner, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon) {
|
||||
super(entityType, pOwner, pLevel, pPickupItemStack, pFiredFromWeapon);
|
||||
this.updateColor();
|
||||
if (pOwner instanceof PlayerLeashable lPlayer && !level().isClientSide) {
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) lPlayer, (ServerLevel) level());
|
||||
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.setOwner(null);
|
||||
}
|
||||
lPlayer.setLeashedTo(this, true);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull ItemStack getDefaultPickupItem() {
|
||||
return new ItemStack(ModItemRegister.LEASH_ROPE_ARROW.get());
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setOwner(@Nullable Entity pEntity) {
|
||||
boolean isNull = pEntity == null;
|
||||
this.ownerUUID = isNull ? null : pEntity.getUUID();
|
||||
this.cachedOwner = isNull ? null : pEntity;
|
||||
this.pickup = this.pickup == Pickup.CREATIVE_ONLY ? this.pickup : Pickup.DISALLOWED;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean tryPickup(@NotNull Player pPlayer) {
|
||||
//时间1.40 禁止
|
||||
//时间2.240
|
||||
// 如果(非仅创造拾取)
|
||||
// 如果 (按Shift )
|
||||
// 如果(拥有者) -> 拾取到完整箭,取消绑定(super给父类处理)
|
||||
// 否则:时间仍为原需时间 ->不能获取完整的箭,重绑定(当前拥有者的Holder是否为本箭,“是”才重绑定)
|
||||
// 否则: 禁止
|
||||
// 否则:
|
||||
// 如果 (按Shift )
|
||||
// 如果(拥有者) -> 且拾取到完整箭,取消绑定
|
||||
// 否则:时间仍为原需时间 ->不能获取完整的箭,重绑定
|
||||
// 否则: 禁止
|
||||
//时间3
|
||||
// 如果(拥有者) -> 拾取到完整箭,取消绑定
|
||||
// 否则:不能获取完整的箭,重绑定
|
||||
|
||||
if(life <= 40 ) {
|
||||
return false;
|
||||
} else {
|
||||
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
|
||||
if(this.getOwner() != null) {//未有Owner始终可检
|
||||
if(life <= 240) {
|
||||
if(pPlayer.isShiftKeyDown()) {
|
||||
Entity leashDataEntity = this.getOwner() instanceof PlayerLeashable ? PlayerLeashable.getLeashDataEntity((ServerPlayer) this.getOwner(), (ServerLevel) level()) : this.getOwner();
|
||||
if(this.ownedBy(pPlayer)) {
|
||||
this.pickup = Pickup.ALLOWED;
|
||||
if(this.equals(leashDataEntity)) {
|
||||
pPlayer.playSound(SoundEvents.LEASH_KNOT_BREAK, 1, 1);
|
||||
Leashable.dropLeash((Entity & Leashable)playerLeashable, true, false);
|
||||
}
|
||||
} else {
|
||||
if(life >= 120) {
|
||||
Entity owner = getOwner();
|
||||
if( owner != null ) {
|
||||
// if(this.equals(leashDataEntity)) {
|
||||
if(owner instanceof PlayerLeashable player) {
|
||||
player.setLeashedTo(pPlayer, true);
|
||||
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
} else if(owner instanceof Leashable leashable) {
|
||||
leashable.setLeashedTo(pPlayer, true);
|
||||
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
}
|
||||
ItemEntity itemEntity = new ItemEntity(level(), getX(), getY(), getZ(), getOrginalItemStack());
|
||||
level().addFreshEntity(itemEntity);
|
||||
discard();
|
||||
// }
|
||||
}
|
||||
} else return false;
|
||||
}
|
||||
} else {
|
||||
((ServerPlayer)pPlayer).sendSystemMessage(Component.translatable(PUSH_SHIFT_TO_PICKUP_QUICKLY), true);
|
||||
return false;
|
||||
}
|
||||
|
||||
} else {
|
||||
Entity leashDataEntity = this.getOwner() instanceof PlayerLeashable ? PlayerLeashable.getLeashDataEntity((ServerPlayer) this.getOwner(), (ServerLevel) level()) : this.getOwner();
|
||||
if(this.ownedBy(pPlayer)) {
|
||||
this.pickup = Pickup.ALLOWED;
|
||||
if(this.equals(leashDataEntity)) {
|
||||
pPlayer.playSound(SoundEvents.LEASH_KNOT_BREAK, 1, 1);
|
||||
Leashable.dropLeash((Entity & Leashable) playerLeashable,true, false);
|
||||
}
|
||||
} else {
|
||||
Entity owner = getOwner();
|
||||
if(owner instanceof PlayerLeashable player) {
|
||||
player.setLeashedTo(pPlayer, true);
|
||||
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
} else if(owner instanceof Leashable leashable) {
|
||||
leashable.setLeashedTo(pPlayer, true);
|
||||
pPlayer.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
}
|
||||
ItemEntity itemEntity = new ItemEntity(level(), getX(), getY(), getZ(), getOrginalItemStack());
|
||||
level().addFreshEntity(itemEntity);
|
||||
discard();
|
||||
|
||||
}
|
||||
}
|
||||
} else if (this.pickup != Pickup.CREATIVE_ONLY) this.pickup = Pickup.ALLOWED;
|
||||
else return pPlayer.hasInfiniteMaterials() && this.pickup == Pickup.CREATIVE_ONLY;
|
||||
|
||||
}
|
||||
|
||||
return super.tryPickup(pPlayer);
|
||||
}
|
||||
protected void hitOnEntityHandler(Entity pEntity) {
|
||||
if(pEntity instanceof LivingEntity pLiving) {
|
||||
super.doPostHurtEffects(pLiving);
|
||||
Entity entity = this.getEffectSource();
|
||||
PotionContents potioncontents = this.getPotionContents();
|
||||
if (potioncontents.potion().isPresent()) {
|
||||
for (MobEffectInstance mobeffectinstance : potioncontents.potion().get().value().getEffects()) {
|
||||
pLiving.addEffect(
|
||||
new MobEffectInstance(
|
||||
mobeffectinstance.getEffect(),
|
||||
Math.max(mobeffectinstance.mapDuration(p_268168_ -> p_268168_ / 8), 1),
|
||||
mobeffectinstance.getAmplifier(),
|
||||
mobeffectinstance.isAmbient(),
|
||||
mobeffectinstance.isVisible()
|
||||
),
|
||||
entity
|
||||
);
|
||||
}
|
||||
}
|
||||
for (MobEffectInstance effectInstance : potioncontents.customEffects()) {
|
||||
pLiving.addEffect(effectInstance, entity);
|
||||
}
|
||||
}
|
||||
}
|
||||
protected ItemStack getOrginalItemStack() {
|
||||
return Items.ARROW.getDefaultInstance();
|
||||
}
|
||||
protected ItemStack getSelfItemStack() {
|
||||
return ModItemRegister.LEASH_ROPE_ARROW.get().getDefaultInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void tickDespawn() {
|
||||
this.life++;
|
||||
if (this.life >= maxLifeTime) {
|
||||
ItemEntity leash_rope_arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getSelfItemStack());
|
||||
this.level().addFreshEntity(leash_rope_arrow);
|
||||
this.discard();
|
||||
}
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (this.level().isClientSide) {
|
||||
if (this.isInGround()) {
|
||||
if (this.inGroundTime % 5 == 0) {
|
||||
this.makeParticle(1);
|
||||
}
|
||||
} else {
|
||||
this.makeParticle(2);
|
||||
}
|
||||
} else if (this.isInGround() && this.inGroundTime != 0 && !this.getPotionContents().equals(PotionContents.EMPTY) && this.inGroundTime >= 600) {
|
||||
this.level().broadcastEntityEvent(this, (byte)0);
|
||||
this.setPickupItemStack(new ItemStack(getSelfItemStack().getItem()));
|
||||
}
|
||||
}
|
||||
|
||||
private void makeParticle(int pParticleAmount) {
|
||||
int i = this.getColor();
|
||||
if (i != -1 && pParticleAmount > 0) {
|
||||
for (int j = 0; j < pParticleAmount; j++) {
|
||||
this.level()
|
||||
.addParticle(
|
||||
ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, i),
|
||||
this.getRandomX(0.5),
|
||||
this.getRandomY(),
|
||||
this.getRandomZ(0.5),
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public int getColor() {
|
||||
return this.entityData.get(ID_EFFECT_COLOR);
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
protected void onHitBlock(@NotNull BlockHitResult pResult) {
|
||||
if(!level().isClientSide) {
|
||||
if (getOwner() instanceof PlayerLeashable pL) {
|
||||
if (this.level().getBlockState(pResult.getBlockPos()).is(BlockTags.FENCES)) {
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
|
||||
if(leashDataEntity != null) {
|
||||
Leashable.dropLeash((Entity & Leashable) pL, true, !(leashDataEntity instanceof LeashRopeArrow));
|
||||
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.dropLeashHandler();
|
||||
}
|
||||
}
|
||||
Entity leashKnotFence = PlayerLeashable.createLeashKnotFence((ServerLevel) this.level(), pResult.getBlockPos());
|
||||
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
|
||||
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
|
||||
pL.setLeashedTo(leashKnotFence, true);
|
||||
leashKnotFence.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
|
||||
this.level().addFreshEntity(arrow);
|
||||
discard();
|
||||
}
|
||||
} else if(getOwner() instanceof Leashable L) {
|
||||
if (this.level().getBlockState(pResult.getBlockPos()).is(BlockTags.FENCES)) {
|
||||
Entity leashDataEntity = this.getOwner();
|
||||
if(leashDataEntity != null) {
|
||||
leashDataEntity.playSound(SoundEvents.LEASH_KNOT_BREAK, 1, 1);
|
||||
Leashable.dropLeash((Entity & Leashable) L,true, false);
|
||||
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.setOwner(null);
|
||||
}
|
||||
}
|
||||
Entity leashKnotFence = LeashFenceKnotEntity.getOrCreateKnot(this.level(), pResult.getBlockPos());
|
||||
L.setLeashedTo(leashKnotFence, true);
|
||||
leashKnotFence.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
|
||||
this.level().addFreshEntity(arrow);
|
||||
discard();
|
||||
}
|
||||
}
|
||||
}
|
||||
super.onHitBlock(pResult);
|
||||
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void onHitEntity(@NotNull EntityHitResult pResult) {
|
||||
if (!level().isClientSide()) {
|
||||
Entity entity = pResult.getEntity();
|
||||
hitOnEntityHandler(entity);
|
||||
if (this.getOwner() instanceof LivingEntity livingEntity ) {
|
||||
MobEffectInstance effect = livingEntity.getEffect(ModEffectRegister.NO_LEASH_EFFECT);
|
||||
if (effect != null && effect.getDuration() != 0) {
|
||||
this.dropLeashHandler();
|
||||
}
|
||||
}
|
||||
if(entity instanceof LivingEntity livingEntity) {
|
||||
if(livingEntity.equals(this.getOwner())) return;
|
||||
if(this.getOwner() == null && livingEntity instanceof PlayerLeashable pL) { //发射器发出或命令生成
|
||||
setOwner(livingEntity);
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
|
||||
if(leashDataEntity != null) {
|
||||
Leashable.dropLeash((Entity & Leashable) pL,true, !(leashDataEntity instanceof LeashRopeArrow));
|
||||
if(leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.dropLeashHandler();
|
||||
}
|
||||
}
|
||||
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
|
||||
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
|
||||
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
pL.setLeashedTo(this, true);
|
||||
} else if (this.getOwner() instanceof PlayerLeashable pL) {
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
|
||||
if(leashDataEntity != null) {
|
||||
Leashable.dropLeash((Entity & Leashable) pL, true, !(leashDataEntity instanceof LeashRopeArrow));
|
||||
if (leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.dropLeashHandler();
|
||||
}
|
||||
}
|
||||
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
|
||||
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
|
||||
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
|
||||
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
pL.setLeashedTo(pResult.getEntity(), true);
|
||||
this.level().addFreshEntity(arrow);
|
||||
discard();
|
||||
} else {
|
||||
if (entity instanceof Leashable leashable) {
|
||||
if (getOwner() == null) {
|
||||
Entity leashDataEntity = leashable.getLeashHolder();
|
||||
if (leashDataEntity != null) {
|
||||
Leashable.dropLeash((Entity & Leashable) leashable,true, !(leashDataEntity instanceof LeashRopeArrow));
|
||||
if (leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.dropLeashHandler();
|
||||
}
|
||||
}
|
||||
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
leashable.setLeashedTo(this, true);
|
||||
this.setOwner(entity);
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (entity instanceof LivingEntity living) {
|
||||
if (this.getOwner() != null && this.getOwner()instanceof Leashable leashable) {
|
||||
livingEntity.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
leashable.setLeashedTo(living, true);
|
||||
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
|
||||
this.level().addFreshEntity(arrow);
|
||||
discard();
|
||||
return;
|
||||
}
|
||||
}
|
||||
ItemEntity lead = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, Items.LEAD.getDefaultInstance());
|
||||
this.level().addFreshEntity(lead);
|
||||
}
|
||||
}
|
||||
else if (entity instanceof LeashFenceKnotEntity leashKnotFence) {
|
||||
if (getOwner() instanceof PlayerLeashable pL) {
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) getOwner(), (ServerLevel) level());
|
||||
if (leashDataEntity != null) {
|
||||
Leashable.dropLeash((Entity & Leashable) pL,true, true);
|
||||
if (leashDataEntity instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.dropLeashHandler();
|
||||
}
|
||||
}
|
||||
ItemEntity arrow = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, getOrginalItemStack());
|
||||
ILivingEntityExtension pLL = (ILivingEntityExtension) pL;
|
||||
pLL.setKeepLeashTick(GameruleRegistry.getGameruleIntValue(level(), KeepLeashNotDropTime.ID));
|
||||
leashKnotFence.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
pL.setLeashedTo(leashKnotFence, true);
|
||||
this.level().addFreshEntity(arrow);
|
||||
discard();
|
||||
}
|
||||
} else {
|
||||
ItemEntity lead = new ItemEntity(this.level(), this.position().x, this.position().y, this.position().z, Items.LEAD.getDefaultInstance());
|
||||
this.level().addFreshEntity(lead);
|
||||
}
|
||||
}
|
||||
}
|
||||
/**
|
||||
* Handles an entity event received from a {@link net.minecraft.network.protocol.game.ClientboundEntityEventPacket}.
|
||||
*/
|
||||
@Override
|
||||
public void handleEntityEvent(byte pId) {
|
||||
if (pId == 0) {
|
||||
int i = this.getColor();
|
||||
if (i != -1) {
|
||||
float f = (float)(i >> 16 & 0xFF) / 255.0F;
|
||||
float f1 = (float)(i >> 8 & 0xFF) / 255.0F;
|
||||
float f2 = (float)(i & 0xFF) / 255.0F;
|
||||
|
||||
for (int j = 0; j < 20; j++) {
|
||||
this.level()
|
||||
.addParticle(
|
||||
ColorParticleOption.create(ParticleTypes.ENTITY_EFFECT, f, f1, f2),
|
||||
this.getRandomX(0.5),
|
||||
this.getRandomY(),
|
||||
this.getRandomZ(0.5),
|
||||
0.0,
|
||||
0.0,
|
||||
0.0
|
||||
);
|
||||
}
|
||||
}
|
||||
} else {
|
||||
super.handleEntityEvent(pId);
|
||||
}
|
||||
}
|
||||
public void dropLeashHandler() {
|
||||
this.playSound(SoundEvents.LEASH_KNOT_PLACE, 1, 1);
|
||||
this.setOwner(null);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.r3944realms.leashedplayer.content.entities;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.MobCategory;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
public class ModEntityRegister {
|
||||
public static final DeferredRegister<EntityType<?>> ENTITY_TYPE = DeferredRegister.create(Registries.ENTITY_TYPE, LeashedPlayer.MOD_ID);
|
||||
public static final DeferredHolder<EntityType<?> ,EntityType<LeashRopeArrow>> LEASH_ROPE_ARROW = ENTITY_TYPE.register(
|
||||
"leash_rope_arrow",
|
||||
() -> EntityType.Builder.<LeashRopeArrow>of(LeashRopeArrow::new, MobCategory.MISC)
|
||||
.sized(0.5F, 0.5F)
|
||||
.eyeHeight(0.13F)
|
||||
.clientTrackingRange(4)
|
||||
.updateInterval(20)
|
||||
.build(ResourceKey.create(Registries.ENTITY_TYPE, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "leash_rope_arrow")))
|
||||
);
|
||||
public static final DeferredHolder<EntityType<?>, EntityType<SpectralLeashRopeArrow>> SPECTRAL_LEASH_ROPE_ARROW = ENTITY_TYPE.register(
|
||||
"spectral_leash_rope_arrow",
|
||||
() -> EntityType.Builder.<SpectralLeashRopeArrow>of(SpectralLeashRopeArrow::new, MobCategory.MISC)
|
||||
.sized(0.5F, 0.5F)
|
||||
.eyeHeight(0.13F)
|
||||
.clientTrackingRange(4)
|
||||
.updateInterval(20)
|
||||
.build(ResourceKey.create(Registries.ENTITY_TYPE, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "spectral_leash_rope_arrow")))
|
||||
);
|
||||
|
||||
public static String getEntityNameKey(String entityName) {
|
||||
return "entity." + LeashedPlayer.MOD_ID + "." + entityName;
|
||||
}
|
||||
public static void register(IEventBus eventBus) {
|
||||
ENTITY_TYPE.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,81 @@
|
|||
package com.r3944realms.leashedplayer.content.entities;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import net.minecraft.core.particles.ParticleTypes;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.effect.MobEffectInstance;
|
||||
import net.minecraft.world.effect.MobEffects;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
public class SpectralLeashRopeArrow extends LeashRopeArrow {
|
||||
private int duration = 200;
|
||||
|
||||
public SpectralLeashRopeArrow(EntityType<? extends AbstractArrow> entityType, double pX, double pY, double pZ, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon, @Nullable ServerPlayer serverPlayer) {
|
||||
super(entityType, pX, pY, pZ, pLevel, pPickupItemStack, pFiredFromWeapon, serverPlayer);
|
||||
}
|
||||
|
||||
protected SpectralLeashRopeArrow(EntityType<? extends AbstractArrow> entityType, Level pLevel) {
|
||||
super(entityType, pLevel);
|
||||
}
|
||||
|
||||
public SpectralLeashRopeArrow(EntityType<? extends AbstractArrow> entityType, LivingEntity pOwner, Level pLevel, ItemStack pPickupItemStack, @Nullable ItemStack pFiredFromWeapon) {
|
||||
super(entityType, pOwner, pLevel, pPickupItemStack, pFiredFromWeapon);
|
||||
}
|
||||
@Override
|
||||
public void tick() {
|
||||
super.tick();
|
||||
if (this.level().isClientSide && !this.isInGround()) {
|
||||
this.level().addParticle(ParticleTypes.INSTANT_EFFECT, this.getX(), this.getY(), this.getZ(), 0.0, 0.0, 0.0);
|
||||
}
|
||||
}
|
||||
@Override
|
||||
protected void doPostHurtEffects(@NotNull LivingEntity pLiving) {
|
||||
super.doPostHurtEffects(pLiving);
|
||||
MobEffectInstance mobeffectinstance = new MobEffectInstance(MobEffects.GLOWING, this.duration, 0);
|
||||
pLiving.addEffect(mobeffectinstance, this.getEffectSource());
|
||||
}
|
||||
|
||||
/**
|
||||
* (abstract) Protected helper method to read subclass entity data from NBT.
|
||||
*/
|
||||
@Override
|
||||
public void readAdditionalSaveData(@NotNull CompoundTag pCompound) {
|
||||
super.readAdditionalSaveData(pCompound);
|
||||
if (pCompound.contains("Duration")) {
|
||||
this.duration = pCompound.getInt("Duration").orElse(200);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void addAdditionalSaveData(@NotNull CompoundTag pCompound) {
|
||||
super.addAdditionalSaveData(pCompound);
|
||||
pCompound.putInt("Duration", this.duration);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ItemStack getOrginalItemStack() {
|
||||
return Items.SPECTRAL_ARROW.getDefaultInstance();
|
||||
}
|
||||
@Override
|
||||
protected ItemStack getSelfItemStack() {
|
||||
return ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get().getDefaultInstance();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void hitOnEntityHandler(Entity pEntity) {
|
||||
if(pEntity instanceof LivingEntity livingEntity) {
|
||||
livingEntity.addEffect(new MobEffectInstance(MobEffects.GLOWING, this.duration, 0));
|
||||
} else {
|
||||
super.hitOnEntityHandler(pEntity);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.r3944realms.leashedplayer.content.events;
|
||||
|
||||
|
||||
import com.mojang.serialization.MapCodec;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange.ConditionalRangeItemModelProperty;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.util.ExtraCodecs;
|
||||
import net.neoforged.bus.api.Event;
|
||||
import net.neoforged.fml.event.IModBusEvent;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
/**
|
||||
* Event fired when special model renderers are registered.
|
||||
* <p>
|
||||
* This event is fired during the model registration process for conditional range select item model properties.
|
||||
* It is used to register property codecs which can be used to create custom conditional range select item model properties.
|
||||
* <p>
|
||||
* This event is fired on the mod event bus.
|
||||
*/
|
||||
public class RegisterConditionalRangeItemPropertyEvent extends Event implements IModBusEvent {
|
||||
private final ExtraCodecs.LateBoundIdMapper<ResourceLocation, MapCodec<? extends ConditionalRangeItemModelProperty>> idMapper;
|
||||
@ApiStatus.Internal
|
||||
public RegisterConditionalRangeItemPropertyEvent(ExtraCodecs.LateBoundIdMapper<ResourceLocation, MapCodec<? extends ConditionalRangeItemModelProperty>> idMapper) {
|
||||
this.idMapper = idMapper;
|
||||
}
|
||||
|
||||
public void register(ResourceLocation location, MapCodec<? extends ConditionalRangeItemModelProperty> source) {
|
||||
this.idMapper.put(location, source);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,107 @@
|
|||
package com.r3944realms.leashedplayer.content.gamerules;
|
||||
|
||||
import com.mojang.brigadier.arguments.FloatArgumentType;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class GameRules {
|
||||
public static final String GAMERULE_PREFIX = "LP.";
|
||||
public static final GameruleRegistry GAMERULE_REGISTRY = GameruleRegistry.INSTANCE;
|
||||
public static final HashMap<String, Boolean> gamerulesBooleanValuesClient = new HashMap<>();
|
||||
public static final HashMap<String, Integer> gameruleIntegerValuesClient = new HashMap<>();
|
||||
public static final HashMap<String, Float> gameruleFloatValuesClient = new HashMap<>();
|
||||
public static final String RULE_KEY_PERFix_ = "gamerule." + GAMERULE_PREFIX;
|
||||
public static String getDescriptionKey(Class<?> gameRuleClass) {
|
||||
return RULE_KEY_PERFix_ + gameRuleClass.getSimpleName() + ".description";
|
||||
}
|
||||
public static String getDescriptionKey(String gameRuleName) {
|
||||
return RULE_KEY_PERFix_ + gameRuleName + ".description";
|
||||
}
|
||||
|
||||
public static String getNameKey(Class<?> gameRuleClass) {
|
||||
return RULE_KEY_PERFix_ + gameRuleClass.getSimpleName();
|
||||
}
|
||||
//此次定义了一个浮点数类型的游戏规则
|
||||
public static class FloatValue extends net.minecraft.world.level.GameRules.Value<FloatValue> {
|
||||
private float value;
|
||||
|
||||
public static net.minecraft.world.level.GameRules.Type<FloatValue> create(
|
||||
float pDefaultValue, BiConsumer<MinecraftServer, FloatValue> pChangeListener
|
||||
) {
|
||||
return new net.minecraft.world.level.GameRules.Type<>
|
||||
(FloatArgumentType::floatArg,
|
||||
pType -> new FloatValue(pType, pDefaultValue),
|
||||
pChangeListener,
|
||||
net.minecraft.world.level.GameRules.GameRuleTypeVisitor::visit,
|
||||
FloatValue.class,
|
||||
FeatureFlagSet.of()
|
||||
);
|
||||
}
|
||||
public static net.minecraft.world.level.GameRules.Type<FloatValue> create(
|
||||
float pDefaultValue, float pMin, float pMax , BiConsumer<MinecraftServer, FloatValue> pChangeListener
|
||||
) {
|
||||
return new net.minecraft.world.level.GameRules.Type<>(
|
||||
() -> FloatArgumentType.floatArg(pMin, pMax),
|
||||
pType -> new GameRules.FloatValue(pType, pDefaultValue),//
|
||||
pChangeListener,
|
||||
net.minecraft.world.level.GameRules.GameRuleTypeVisitor::visit,
|
||||
FloatValue.class,
|
||||
FeatureFlagSet.of()
|
||||
);
|
||||
}
|
||||
public FloatValue(net.minecraft.world.level.GameRules.Type<GameRules.FloatValue> pType, float value) {
|
||||
super(pType);
|
||||
this.value = value;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void updateFromArgument(@NotNull CommandContext<CommandSourceStack> pContext, @NotNull String pParamName) {
|
||||
this.value = FloatArgumentType.getFloat(pContext, pParamName);
|
||||
}
|
||||
public float get() {
|
||||
return this.value;
|
||||
}
|
||||
|
||||
public void set(float pValue, @Nullable MinecraftServer pServer) {
|
||||
this.value = pValue;
|
||||
this.onChanged(pServer);
|
||||
}
|
||||
@Override
|
||||
protected void deserialize(@NotNull String pValue) {
|
||||
this.value = Float.parseFloat(pValue);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String serialize() {
|
||||
return Float.toString(this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getCommandResult() {
|
||||
return 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull FloatValue getSelf() {
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected @NotNull FloatValue copy() {
|
||||
return new FloatValue(this.type, this.value);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setFrom(FloatValue pValue, @Nullable MinecraftServer pServer) {
|
||||
this.value = pValue.value;
|
||||
this.onChanged(pServer);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,71 @@
|
|||
package com.r3944realms.leashedplayer.content.gamerules;
|
||||
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.world.level.Level;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public enum GameruleRegistry {
|
||||
INSTANCE;
|
||||
public static final Map<String, net.minecraft.world.level.GameRules.Key<?>> gamerules = new HashMap<>();;
|
||||
public static final Map<String, RuleDataType> gameruleDataTypes = new HashMap<>();
|
||||
public enum RuleDataType {
|
||||
BOOLEAN,
|
||||
INTEGER,
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
|
||||
public static boolean getGameruleBoolValue(Level level, String gameruleName) {
|
||||
if (level.isClientSide && GameRules.gamerulesBooleanValuesClient.containsKey(gameruleName)) {
|
||||
return GameRules.gamerulesBooleanValuesClient.get(gameruleName);
|
||||
}
|
||||
if (gameruleDataTypes.get(gameruleName) != RuleDataType.BOOLEAN) {
|
||||
return false;
|
||||
}
|
||||
return ((ServerLevel)level).getGameRules().getBoolean((net.minecraft.world.level.GameRules.Key<net.minecraft.world.level.GameRules.BooleanValue>) gamerules.get(gameruleName));
|
||||
}
|
||||
@SuppressWarnings("unchecked")
|
||||
public static Integer getGameruleIntValue(Level level, String gameruleName) {
|
||||
if (level.isClientSide && GameRules.gameruleIntegerValuesClient.containsKey(gameruleName)) {
|
||||
return GameRules.gameruleIntegerValuesClient.get(gameruleName);
|
||||
}
|
||||
if (gameruleDataTypes.get(gameruleName) != RuleDataType.INTEGER) {
|
||||
return 0;
|
||||
}
|
||||
return ((ServerLevel)level).getGameRules().getInt((net.minecraft.world.level.GameRules.Key<net.minecraft.world.level.GameRules.IntegerValue>)gamerules.get(gameruleName));
|
||||
}
|
||||
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, boolean pDefault) {
|
||||
registerGamerule(gameruleName, category, pDefault, (s,i)->{});//最后一个仅占位无用
|
||||
}
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, boolean pDefault, BiConsumer<MinecraftServer, net.minecraft.world.level.GameRules.BooleanValue> pChangeListener) {
|
||||
gamerules.put(gameruleName, net.minecraft.world.level.GameRules.register(gameruleName, category, net.minecraft.world.level.GameRules.BooleanValue.create(pDefault, pChangeListener)));
|
||||
gameruleDataTypes.put(gameruleName, RuleDataType.BOOLEAN);
|
||||
}
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, int pDefault) {
|
||||
registerGamerule(gameruleName, category, pDefault, (BiConsumer<MinecraftServer, net.minecraft.world.level.GameRules.IntegerValue>) (s, i)->{});//最后一个仅占位无用
|
||||
}
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, int pDefault, BiConsumer<MinecraftServer, net.minecraft.world.level.GameRules.IntegerValue> pChangeListener) {
|
||||
gamerules.put(gameruleName, net.minecraft.world.level.GameRules.register(gameruleName, category, net.minecraft.world.level.GameRules.IntegerValue.create(pDefault, pChangeListener)));
|
||||
gameruleDataTypes.put(gameruleName, RuleDataType.INTEGER);
|
||||
}
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, int pDefault, int pMin, int pMax, BiConsumer<MinecraftServer, net.minecraft.world.level.GameRules.IntegerValue> pChangeListener) {
|
||||
gamerules.put(gameruleName, net.minecraft.world.level.GameRules.register(gameruleName, category, net.minecraft.world.level.GameRules.IntegerValue.create(pDefault, pMin, pMax, FeatureFlagSet.of(), pChangeListener)));
|
||||
gameruleDataTypes.put(gameruleName, RuleDataType.INTEGER);
|
||||
}
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, float value) {
|
||||
registerGamerule(gameruleName, category, value, (s,i)->{});
|
||||
}
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, float pDefault, BiConsumer<MinecraftServer, GameRules.FloatValue> pChangeListener) {
|
||||
gamerules.put(gameruleName, net.minecraft.world.level.GameRules.register(gameruleName, category, GameRules.FloatValue.create(pDefault, pChangeListener)));
|
||||
gameruleDataTypes.put(gameruleName, RuleDataType.INTEGER);
|
||||
}
|
||||
public void registerGamerule(String gameruleName, net.minecraft.world.level.GameRules.Category category, float pDefault, float pMin, float pMax, BiConsumer<MinecraftServer, GameRules.FloatValue> pChangeListener) {
|
||||
gamerules.put(gameruleName, net.minecraft.world.level.GameRules.register(gameruleName, category, GameRules.FloatValue.create(pDefault, pMin, pMax,pChangeListener)));
|
||||
gameruleDataTypes.put(gameruleName, RuleDataType.INTEGER);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.r3944realms.leashedplayer.content.gamerules.Server;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.GameRules;
|
||||
import com.r3944realms.leashedplayer.utils.Util;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.gamerules.GameRules.GAMERULE_REGISTRY;
|
||||
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
|
||||
public class CreateLeashFenceKnotEntityIfAbsent {
|
||||
public static final boolean DEFAULT_VALUE = true;
|
||||
public static final String ID = Util.getGameruleName(CreateLeashFenceKnotEntityIfAbsent.class);
|
||||
public static final String DESCRIPTION_KEY = GameRules.getDescriptionKey(CreateLeashFenceKnotEntityIfAbsent.class);
|
||||
public static final String NAME_KEY = GameRules.getNameKey(CreateLeashFenceKnotEntityIfAbsent.class);
|
||||
public static final net.minecraft.world.level.GameRules.Category CATEGORY = net.minecraft.world.level.GameRules.Category.PLAYER;
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onCommonSetup(final FMLCommonSetupEvent event) {
|
||||
GAMERULE_REGISTRY.registerGamerule(ID, CATEGORY, DEFAULT_VALUE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.r3944realms.leashedplayer.content.gamerules.Server;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.GameRules;
|
||||
import com.r3944realms.leashedplayer.utils.Util;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.gamerules.GameRules.GAMERULE_REGISTRY;
|
||||
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
|
||||
public class KeepLeashNotDropTime {
|
||||
public static final int DEFAULT_VALUE = 240;
|
||||
public static final String ID = Util.getGameruleName(KeepLeashNotDropTime.class);
|
||||
public static final String DESCRIPTION_KEY = GameRules.getDescriptionKey(KeepLeashNotDropTime.class);
|
||||
public static final String NAME_KEY = GameRules.getNameKey(KeepLeashNotDropTime.class);
|
||||
public static final net.minecraft.world.level.GameRules.Category CATEGORY = net.minecraft.world.level.GameRules.Category.MISC;
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onCommonSetup(final FMLCommonSetupEvent event) {
|
||||
GAMERULE_REGISTRY.registerGamerule(ID, CATEGORY, DEFAULT_VALUE, 80, 1200, (BiConsumer<MinecraftServer, net.minecraft.world.level.GameRules.IntegerValue>) (i, j)->{});
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.r3944realms.leashedplayer.content.gamerules.Server;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.GameRules;
|
||||
import com.r3944realms.leashedplayer.utils.Util;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.fml.event.lifecycle.FMLCommonSetupEvent;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.gamerules.GameRules.GAMERULE_REGISTRY;
|
||||
|
||||
//It had so Long Name at first.(
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
|
||||
public class TeleportWithLeashedPlayers {
|
||||
public static final boolean DEFAULT_VALUE = true;
|
||||
public static final String ID = Util.getGameruleName(TeleportWithLeashedPlayers.class);
|
||||
public static final String DESCRIPTION_KEY = GameRules.getDescriptionKey(TeleportWithLeashedPlayers.class);
|
||||
public static final String NAME_KEY = GameRules.getNameKey(TeleportWithLeashedPlayers.class);
|
||||
public static final net.minecraft.world.level.GameRules.Category CATEGORY = net.minecraft.world.level.GameRules.Category.PLAYER;
|
||||
|
||||
@SubscribeEvent
|
||||
public static void onCommonSetup(final FMLCommonSetupEvent event) {
|
||||
GAMERULE_REGISTRY.registerGamerule(ID, CATEGORY, DEFAULT_VALUE);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,85 @@
|
|||
package com.r3944realms.leashedplayer.content.items;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.flag.FeatureFlagSet;
|
||||
import net.minecraft.world.item.CreativeModeTab;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.alchemy.Potion;
|
||||
import net.minecraft.world.item.alchemy.PotionContents;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.common.CommonHooks;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Objects;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModCreativeTab {
|
||||
public static final DeferredRegister<CreativeModeTab> CREATIVE_MODE_TABS =
|
||||
DeferredRegister.create(Registries.CREATIVE_MODE_TAB, LeashedPlayer.MOD_ID);
|
||||
public static final String LEASHED_PLAYER_TAB_STRING = "creativetab." + LeashedPlayer.MOD_ID;
|
||||
public static final String LEASHED_PLAYER_ITEM = "leashedplayer_tab";
|
||||
public static final Supplier<CreativeModeTab> TEST_TAB = CREATIVE_MODE_TABS.register(LEASHED_PLAYER_ITEM,() -> CreativeModeTab.builder()
|
||||
.title(Component.translatable(getCreativeMod(LEASHED_PLAYER_ITEM)))
|
||||
.icon(() -> ModItemRegister.LEASH_ROPE_ARROW.get().getDefaultInstance())
|
||||
.displayItems(((pParameters, pOutput) -> {
|
||||
pOutput.accept(Items.LEAD);
|
||||
pOutput.accept(Items.BOW);
|
||||
pOutput.accept(Items.CROSSBOW);
|
||||
pOutput.accept(ModItemRegister.LEASH_ROPE_ARROW.get());
|
||||
pOutput.accept(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get());
|
||||
pOutput.accept(ModItemRegister.AMETHYST_SHEARS.get());
|
||||
pOutput.accept(ModItemRegister.NEOFORGE.get());
|
||||
pParameters.holders()
|
||||
.lookup(Registries.POTION)
|
||||
.ifPresent(potionRegistryLookup1 ->
|
||||
potionRegistryLookup1.listElements()
|
||||
.filter(potionReference -> Objects.requireNonNull(potionReference.getKey()).location().getNamespace().equals(LeashedPlayer.MOD_ID))
|
||||
.map(potionReference -> PotionContents.createItemStack(Items.POTION, potionReference))
|
||||
.forEach(pOutput::accept));
|
||||
pParameters.holders()
|
||||
.lookup(Registries.POTION)
|
||||
.ifPresent(potionRegistryLookup1 ->
|
||||
potionRegistryLookup1.listElements()
|
||||
.filter(potionReference -> Objects.requireNonNull(potionReference.getKey()).location().getNamespace().equals(LeashedPlayer.MOD_ID))
|
||||
.map(potionReference -> PotionContents.createItemStack(Items.SPLASH_POTION, potionReference))
|
||||
.forEach(pOutput::accept));
|
||||
pParameters.holders()
|
||||
.lookup(Registries.POTION)
|
||||
.ifPresent(potionRegistryLookup1 ->
|
||||
potionRegistryLookup1.listElements()
|
||||
.filter(potionReference -> Objects.requireNonNull(potionReference.getKey()).location().getNamespace().equals(LeashedPlayer.MOD_ID))
|
||||
.map(potionReference -> PotionContents.createItemStack(Items.LINGERING_POTION, potionReference))
|
||||
.forEach(pOutput::accept));
|
||||
pParameters.holders()
|
||||
.lookup(Registries.POTION)
|
||||
.ifPresent(
|
||||
pPotions -> generatePotionEffectTypes(
|
||||
pOutput,
|
||||
pPotions,
|
||||
ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get(),
|
||||
CreativeModeTab.TabVisibility.PARENT_AND_SEARCH_TABS,
|
||||
pParameters.enabledFeatures()
|
||||
)
|
||||
);
|
||||
})).build());
|
||||
private static void generatePotionEffectTypes(
|
||||
CreativeModeTab.Output pOutput, HolderLookup<Potion> pPotions, Item pItem, CreativeModeTab.TabVisibility pTabVisibility, FeatureFlagSet pRequiredFeatures
|
||||
) {
|
||||
pPotions.listElements()
|
||||
.filter(potionReference -> potionReference.value().isEnabled(pRequiredFeatures))
|
||||
.map(potionReference -> PotionContents.createItemStack(pItem, potionReference))
|
||||
.forEach(itemStack -> pOutput.accept(itemStack, pTabVisibility));
|
||||
}
|
||||
public static String getCreativeMod(@NotNull String tabs) {
|
||||
return LEASHED_PLAYER_TAB_STRING + "." + tabs;
|
||||
}
|
||||
public static void register(IEventBus eventBus) {
|
||||
CREATIVE_MODE_TABS.register(eventBus);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,65 @@
|
|||
package com.r3944realms.leashedplayer.content.items;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.items.type.*;
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModJukeboxSongs;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.JukeboxSong;
|
||||
import net.minecraft.world.item.Rarity;
|
||||
import net.minecraft.world.item.ShearsItem;
|
||||
import net.minecraft.world.item.alchemy.PotionContents;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModItemRegister {
|
||||
public static final DeferredRegister<Item> ITEMS =
|
||||
DeferredRegister.create(BuiltInRegistries.ITEM, LeashedPlayer.MOD_ID);
|
||||
public static final List<DeferredHolder<Item, Item>> ITEM_SUPPLIER = new ArrayList<>();
|
||||
public static final DeferredHolder<Item, Item> LEASH_ROPE_ARROW = ModItemRegister.register("leash_rope_arrow",
|
||||
() -> new LeashRopeArrowItem(new Item.Properties().stacksTo(16)
|
||||
.setId(ModItemResourceKeys.LEASH_ROPE_ARROW.getResourceKey()))
|
||||
);
|
||||
public static final DeferredHolder<Item, Item> SPECTRAL_LEASH_ROPE_ARROW = ModItemRegister.register("spectral_leash_rope_arrow",
|
||||
() -> new SpectralLeashRopeArrowItem(new Item.Properties().stacksTo(16)
|
||||
.setId(ModItemResourceKeys.SPECTRAL_LEASH_ROPE_ARROW.getResourceKey())));
|
||||
|
||||
public static final DeferredHolder<Item, Item> TIPPED_LEASH_ROPE_ARROW = ModItemRegister.register("tipped_leash_rope_arrow",
|
||||
() -> new TippedLeashRopeArrowItem(new Item.Properties().stacksTo(16).component(DataComponents.POTION_CONTENTS, PotionContents.EMPTY)
|
||||
.setId(ModItemResourceKeys.TIPPED_LEASH_ROPE_ARROW.getResourceKey())));
|
||||
public static final DeferredHolder<Item, Item> AMETHYST_SHEARS = ModItemRegister.register("amethyst_shears",
|
||||
() -> new LeadBreakerItem(ModToolMaterials.AMETHYST, new Item.Properties().durability(100).component(DataComponents.TOOL, LeadBreakerItem.createToolProperties())
|
||||
.stacksTo(1)
|
||||
.setId(ModItemResourceKeys.AMETHYST_SHEARS.getResourceKey())));
|
||||
public static final DeferredHolder<Item, Item> FABRIC = ModItemRegister.register("fabric",
|
||||
() -> new TestItem(new Item.Properties().stacksTo(1)
|
||||
.setId(ModItemResourceKeys.FABRIC.getResourceKey())));
|
||||
public static final DeferredHolder<Item, Item> NEOFORGE = ModItemRegister.register("neoforge",
|
||||
() -> new Item(DistProperties(ModJukeboxSongs.FOX_MUSIC)
|
||||
.setId(ModItemResourceKeys.NEOFORGE.getResourceKey())));
|
||||
|
||||
public static Item.Properties DistProperties(ResourceKey<JukeboxSong> song) {
|
||||
return new Item.Properties().stacksTo(1).rarity(Rarity.RARE).jukeboxPlayable(song);
|
||||
}
|
||||
|
||||
public static DeferredHolder<Item, Item> register(String name, Supplier<Item> supplier) {
|
||||
return register(name, supplier, true);
|
||||
}
|
||||
|
||||
public static DeferredHolder<Item, Item> register(String name, Supplier<Item> supplier, boolean shouldJoinSupplierLists) {
|
||||
DeferredHolder<Item, Item> supplierItem = ITEMS.register(name, supplier);
|
||||
if(shouldJoinSupplierLists) ITEM_SUPPLIER.add(supplierItem);
|
||||
return supplierItem;
|
||||
}
|
||||
|
||||
public static void register(IEventBus eventBus) {
|
||||
ITEMS.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,29 @@
|
|||
package com.r3944realms.leashedplayer.content.items;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
|
||||
public enum ModItemResourceKeys {
|
||||
LEASH_ROPE_ARROW(ModItemRegister.LEASH_ROPE_ARROW),
|
||||
SPECTRAL_LEASH_ROPE_ARROW(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW),
|
||||
TIPPED_LEASH_ROPE_ARROW (ModItemRegister.TIPPED_LEASH_ROPE_ARROW),
|
||||
AMETHYST_SHEARS(ModItemRegister.AMETHYST_SHEARS),
|
||||
FABRIC(ModItemRegister.FABRIC),
|
||||
NEOFORGE(ModItemRegister.NEOFORGE)
|
||||
;
|
||||
private final ResourceKey<Item> resourceKey;
|
||||
ModItemResourceKeys(String name) {
|
||||
resourceKey = ResourceKey.create(Registries.ITEM, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, name));
|
||||
}
|
||||
ModItemResourceKeys(DeferredHolder<Item, Item> item) {
|
||||
resourceKey = ResourceKey.create(Registries.ITEM, item.getId());
|
||||
}
|
||||
|
||||
public ResourceKey<Item> getResourceKey() {
|
||||
return resourceKey;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,13 @@
|
|||
package com.r3944realms.leashedplayer.content.items;
|
||||
|
||||
import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModItemTags;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.item.ToolMaterial;
|
||||
|
||||
public class ModToolMaterials {
|
||||
public static final ToolMaterial AMETHYST =
|
||||
new ToolMaterial(BlockTags.INCORRECT_FOR_DIAMOND_TOOL,
|
||||
100, 8.0F, 2.0F, 15,
|
||||
ModItemTags.AMETHYST_TOOL_MATERIALS
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,27 @@
|
|||
package com.r3944realms.leashedplayer.content.items.repcipe;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.world.item.crafting.CustomRecipe;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
public class ModRecipeRegister {
|
||||
public static final DeferredRegister<RecipeSerializer<?>> RECIPE_SERIALIZER =
|
||||
DeferredRegister.create(BuiltInRegistries.RECIPE_SERIALIZER, LeashedPlayer.MOD_ID);
|
||||
|
||||
public static final DeferredHolder<RecipeSerializer<?>, RecipeSerializer<TippedLeashRopeArrowRecipe.TippedLeashRopeArrowARecipe>> TIPPED_LEASH_ROPE_ARROW_A_RECIPE =
|
||||
RECIPE_SERIALIZER.register("tipped_leash_rope_arrow_a_recipe", () ->
|
||||
new CustomRecipe.Serializer<>(TippedLeashRopeArrowRecipe.TippedLeashRopeArrowARecipe::new)
|
||||
);
|
||||
public static final DeferredHolder<RecipeSerializer<?>, RecipeSerializer<TippedLeashRopeArrowRecipe.TippedLeashRopeArrowBRecipe>> TIPPED_LEASH_ROPE_ARROW_B_RECIPE =
|
||||
RECIPE_SERIALIZER.register("tipped_leash_rope_arrow_b_recipe", () ->
|
||||
new CustomRecipe.Serializer<>(TippedLeashRopeArrowRecipe.TippedLeashRopeArrowBRecipe::new)
|
||||
);
|
||||
|
||||
public static void register(IEventBus eventBus) {
|
||||
RECIPE_SERIALIZER.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,106 @@
|
|||
package com.r3944realms.leashedplayer.content.items.repcipe;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.item.crafting.CraftingBookCategory;
|
||||
import net.minecraft.world.item.crafting.CraftingInput;
|
||||
import net.minecraft.world.item.crafting.CustomRecipe;
|
||||
import net.minecraft.world.item.crafting.RecipeSerializer;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public abstract class TippedLeashRopeArrowRecipe {
|
||||
public static class TippedLeashRopeArrowARecipe extends CustomRecipe {
|
||||
public TippedLeashRopeArrowARecipe(CraftingBookCategory pCategory) {
|
||||
super(pCategory);
|
||||
}
|
||||
|
||||
public boolean matches(CraftingInput pInput, @NotNull Level pLevel) {
|
||||
if (pInput.width() == 3 && pInput.height() == 3) {
|
||||
for (int i = 0; i < pInput.height(); i++) {
|
||||
for (int j = 0; j < pInput.width(); j++) {
|
||||
ItemStack itemstack = pInput.getItem(j, i);
|
||||
if (itemstack.isEmpty()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (j == 1 && i == 1) {
|
||||
if (!itemstack.is(Items.LINGERING_POTION)) {
|
||||
return false;
|
||||
}
|
||||
} else if (!itemstack.is(ModItemRegister.LEASH_ROPE_ARROW.get())) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
} else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull ItemStack assemble(CraftingInput pInput, HolderLookup.@NotNull Provider pRegistries) {
|
||||
ItemStack itemstack = pInput.getItem(1, 1);
|
||||
if (!itemstack.is(Items.LINGERING_POTION)) {
|
||||
return ItemStack.EMPTY;
|
||||
} else {
|
||||
ItemStack itemstack1 = new ItemStack(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get(), 8);
|
||||
itemstack1.set(DataComponents.POTION_CONTENTS, itemstack.get(DataComponents.POTION_CONTENTS));
|
||||
return itemstack1;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull RecipeSerializer<? extends CustomRecipe> getSerializer() {
|
||||
return ModRecipeRegister.TIPPED_LEASH_ROPE_ARROW_A_RECIPE.get();
|
||||
}
|
||||
}
|
||||
public static class TippedLeashRopeArrowBRecipe extends CustomRecipe {
|
||||
|
||||
public TippedLeashRopeArrowBRecipe(CraftingBookCategory pCategory) {
|
||||
super(pCategory);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean matches(CraftingInput pInput, @NotNull Level pLevel) {
|
||||
int tipped_arrow_count = 0, lead_count = 0;
|
||||
for (int i = 0; i < pInput.width(); i++) {
|
||||
for (int j = 0; j < pInput.height(); j++) {
|
||||
if (pInput.getItem(i, j).is(Items.TIPPED_ARROW))
|
||||
tipped_arrow_count++;
|
||||
else if(pInput.getItem(i, j).is(Items.LEAD))
|
||||
lead_count++;
|
||||
}
|
||||
}
|
||||
return tipped_arrow_count == 1 && lead_count == 1;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull ItemStack assemble(@NotNull CraftingInput pInput, HolderLookup.@NotNull Provider pRegistries) {
|
||||
ItemStack tipped_arrow = null;
|
||||
NODE:for (int i = 0; i < pInput.width(); i++) {
|
||||
for (int j = 0; j < pInput.height(); j++) {
|
||||
if (pInput.getItem(i, j).is(Items.TIPPED_ARROW)) {
|
||||
tipped_arrow = pInput.getItem(i, j);
|
||||
break NODE;
|
||||
}
|
||||
}
|
||||
}
|
||||
if(tipped_arrow != null) {
|
||||
ItemStack itemstack1 = new ItemStack(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get(), 1);
|
||||
itemstack1.set(DataComponents.POTION_CONTENTS, tipped_arrow.get(DataComponents.POTION_CONTENTS));
|
||||
return itemstack1;
|
||||
}
|
||||
return ItemStack.EMPTY;
|
||||
}
|
||||
@Override
|
||||
public @NotNull RecipeSerializer<? extends CustomRecipe> getSerializer() {
|
||||
return ModRecipeRegister.TIPPED_LEASH_ROPE_ARROW_B_RECIPE.get();
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.r3944realms.leashedplayer.content.items.type;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.BowItem;
|
||||
import net.minecraft.world.item.CrossbowItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.component.ChargedProjectiles;
|
||||
|
||||
public interface ILeashRopeArrow {
|
||||
static boolean isLeashRopeArrow(ItemStack bowStack, LivingEntity entity) {
|
||||
Item item = bowStack.getItem();
|
||||
if(item instanceof BowItem) {
|
||||
if (entity == null) return false;
|
||||
ItemStack projectile = entity.getProjectile(bowStack);
|
||||
return projectile.getItem() instanceof ILeashRopeArrow;
|
||||
|
||||
} else if (item instanceof CrossbowItem) {
|
||||
ChargedProjectiles chargedProjectiles = bowStack.get(DataComponents.CHARGED_PROJECTILES);
|
||||
return chargedProjectiles != null &&
|
||||
(chargedProjectiles.contains(ModItemRegister.LEASH_ROPE_ARROW.get()) ||
|
||||
chargedProjectiles.contains(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get()) ||
|
||||
chargedProjectiles.contains(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get()));
|
||||
}
|
||||
// if (entity instanceof Player player) {
|
||||
// if (bowStack.getItem() instanceof CrossbowItem) {}
|
||||
// // 获取将要发射的弹药
|
||||
// ItemStack projectileStack = player.getProjectile(bowStack);
|
||||
//
|
||||
// // 判断该弹药是否为拴绳箭
|
||||
// return projectileStack.getItem() instanceof ILeashRopeArrow;
|
||||
// } else if (entity == null) {
|
||||
// if (bowStack.getItem() instanceof CrossbowItem ) {
|
||||
// ChargedProjectiles chargedProjectiles = bowStack.get(DataComponents.CHARGED_PROJECTILES);
|
||||
// if (chargedProjectiles == null || chargedProjectiles.isEmpty()) {
|
||||
// return false;
|
||||
// }
|
||||
// return chargedProjectiles.contains(ModItemRegister.LEASH_ROPE_ARROW.get()) ||
|
||||
// chargedProjectiles.contains(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get()) ||
|
||||
// chargedProjectiles.contains(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get());
|
||||
// }
|
||||
// }
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,128 @@
|
|||
package com.r3944realms.leashedplayer.content.items.type;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModItemTags;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.core.HolderGetter;
|
||||
import net.minecraft.core.HolderSet;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.ShearsItem;
|
||||
import net.minecraft.world.item.ToolMaterial;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.Tool;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
import net.minecraft.world.item.enchantment.Enchantable;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.minecraft.world.level.block.Blocks;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class LeadBreakerItem extends ShearsItem {
|
||||
private final ToolMaterial toolMaterial;
|
||||
public static final String HOVER_KEY = "leashedplayer.lead_breaker.item.desc",
|
||||
MESSAGE_USE_SUF = "leashedplayer.lead_breaker.item.use_suf",
|
||||
MESSAGE_USE_FAI = "leashedplayer.lead_breaker.item.use_fai";
|
||||
public LeadBreakerItem(ToolMaterial toolMaterial, Properties properties) {
|
||||
super(properties.durability(toolMaterial.durability())
|
||||
.component(DataComponents.ENCHANTABLE, new Enchantable(toolMaterial.enchantmentValue()))
|
||||
.repairable(ModItemTags.AMETHYST_TOOL_MATERIALS)
|
||||
.enchantable(toolMaterial.enchantmentValue()));
|
||||
this.toolMaterial = toolMaterial;
|
||||
}
|
||||
|
||||
public static Tool createToolProperties() {
|
||||
HolderGetter<Block> holdergetter = BuiltInRegistries.acquireBootstrapRegistrationLookup(BuiltInRegistries.BLOCK);
|
||||
return new Tool(
|
||||
List.of(
|
||||
Tool.Rule.minesAndDrops(HolderSet.direct(BuiltInRegistries.BLOCK.wrapAsHolder(Blocks.COBWEB)), 18.0F),
|
||||
Tool.Rule.overrideSpeed(holdergetter.getOrThrow(BlockTags.LEAVES), 25.0F),
|
||||
Tool.Rule.overrideSpeed(holdergetter.getOrThrow(BlockTags.WOOL), 8.0F),
|
||||
Tool.Rule.overrideSpeed(HolderSet.direct(BuiltInRegistries.BLOCK.wrapAsHolder(Blocks.VINE), BuiltInRegistries.BLOCK.wrapAsHolder(Blocks.GLOW_LICHEN)), 4.0F)
|
||||
),
|
||||
1.0F,
|
||||
1,
|
||||
true
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public @NotNull InteractionResult interactLivingEntity(@NotNull ItemStack stack, @NotNull Player player, @NotNull LivingEntity entity, @NotNull InteractionHand hand) {
|
||||
if(!entity.level().isClientSide) {
|
||||
if (entity instanceof PlayerLeashable playerLeashable) {
|
||||
if (playerLeashable.isLeashed()){
|
||||
entity.playSound(SoundEvents.SHEEP_SHEAR, 1.0F, 1.0F);
|
||||
Entity leashHolder = playerLeashable.getLeashHolder();
|
||||
Leashable.dropLeash((Entity & Leashable) playerLeashable,true, !(leashHolder instanceof LeashRopeArrow));
|
||||
if (leashHolder instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.setOwner(null);
|
||||
}
|
||||
if (!player.isCreative()) stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand));
|
||||
if (leashHolder != null) {
|
||||
((ServerPlayer)player).sendSystemMessage(Component.translatable(MESSAGE_USE_SUF, entity.getDisplayName(), leashHolder.getDisplayName()), true);
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
} else return InteractionResult.PASS;
|
||||
} else if (entity instanceof Leashable leashable) {
|
||||
if (leashable.isLeashed()){
|
||||
entity.playSound(SoundEvents.SHEEP_SHEAR, 1.0F, 1.0F);
|
||||
Entity leashHolder = leashable.getLeashHolder();
|
||||
Leashable.dropLeash((Entity & Leashable) leashable, true, !(leashHolder instanceof LeashRopeArrow));
|
||||
if (leashable.getLeashHolder() instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.setOwner(null);
|
||||
}
|
||||
if (!player.isCreative()) stack.hurtAndBreak(1, player, LivingEntity.getSlotForHand(hand));
|
||||
if (leashHolder != null) {
|
||||
((ServerPlayer)player).sendSystemMessage(Component.translatable(MESSAGE_USE_SUF, entity.getDisplayName(), leashHolder.getDisplayName()), true);
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
} else return InteractionResult.PASS;
|
||||
}
|
||||
}
|
||||
return InteractionResult.PASS;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull InteractionResult use(@NotNull Level pLevel, @NotNull Player pPlayer, @NotNull InteractionHand pUsedHand) {
|
||||
if (!pLevel.isClientSide && pUsedHand == InteractionHand.MAIN_HAND) {
|
||||
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
|
||||
if (playerLeashable.isLeashed()) {
|
||||
Entity leashHolder = playerLeashable.getLeashHolder();
|
||||
if(!(leashHolder instanceof LeashRopeArrow)) {
|
||||
Leashable.dropLeash((Entity & Leashable) playerLeashable,true, true);
|
||||
pPlayer.getItemInHand(pUsedHand).hurtAndBreak(10, pPlayer, LivingEntity.getSlotForHand(pUsedHand));
|
||||
if (leashHolder != null) {
|
||||
((ServerPlayer)pPlayer).sendSystemMessage(Component.translatable(MESSAGE_USE_SUF, pPlayer.getDisplayName(), leashHolder.getDisplayName()), true);
|
||||
}
|
||||
return InteractionResult.SUCCESS;
|
||||
}
|
||||
((ServerPlayer)pPlayer).sendSystemMessage(Component.translatable(MESSAGE_USE_FAI, pPlayer.getDisplayName(), leashHolder.getDisplayName()), true);
|
||||
}
|
||||
}
|
||||
if(pLevel.isClientSide) {
|
||||
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
|
||||
if (playerLeashable.getLeashDataFromEntityData() != null) {
|
||||
pPlayer.playSound(SoundEvents.SHEEP_SHEAR, 1.0F, 1.0F);
|
||||
}
|
||||
}
|
||||
return super.use(pLevel, pPlayer, pUsedHand);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(@NotNull ItemStack pItemStack, @NotNull TooltipContext pTooltipComponents, @NotNull TooltipDisplay pTooltipDisplay, Consumer<Component> pConsumer, @NotNull TooltipFlag pTooltipFlag) {
|
||||
pConsumer.accept(Component.translatable(HOVER_KEY));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.r3944realms.leashedplayer.content.items.type;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import net.minecraft.world.item.ArrowItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class LeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{
|
||||
public static final String descKey = "item.leash_rope_arrow.description",
|
||||
DESC_1 = "item.leash_rope_arrow.desc.1",
|
||||
DESC_2 = "item.leash_rope_arrow.desc.2",
|
||||
DESC_3 = "item.leash_rope_arrow.desc.3",
|
||||
DESC_4 = "item.leash_rope_arrow.desc.4",
|
||||
DESC_5 = "item.leash_rope_arrow.desc.5";
|
||||
public static final String
|
||||
DESC_V_1 = "item.variant.leash_rope_arrow.desc.1",
|
||||
DESC_V_2 = "item.variant.leash_rope_arrow.desc.2";
|
||||
public LeashRopeArrowItem(Properties pProperties) {
|
||||
super(pProperties) ;
|
||||
}
|
||||
|
||||
public @NotNull AbstractArrow createArrow(@NotNull Level pLevel, @NotNull ItemStack pAmmo, @NotNull LivingEntity pShooter, @Nullable ItemStack pWeapon) {
|
||||
return new LeashRopeArrow(ModEntityRegister.LEASH_ROPE_ARROW.get(),pShooter, pLevel, pAmmo.copyWithCount(1), pWeapon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Projectile asProjectile(@NotNull Level pLevel, @NotNull Position pPos, @NotNull ItemStack pStack, @NotNull Direction pDirection) {
|
||||
LeashRopeArrow arrow = new LeashRopeArrow(ModEntityRegister.LEASH_ROPE_ARROW.get(), pPos.x(), pPos.y(), pPos.z(), pLevel, pStack,null, null);
|
||||
arrow.pickup = AbstractArrow.Pickup.DISALLOWED;
|
||||
return arrow;
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public void appendHoverText(@NotNull ItemStack pItemStack, @NotNull TooltipContext pTooltipComponents, @NotNull TooltipDisplay pTooltipDisplay, Consumer<Component> pConsumer, @NotNull TooltipFlag pTooltipFlag) {
|
||||
pConsumer.accept(Component.translatable(LeashRopeArrowItem.DESC_1));
|
||||
pConsumer.accept(Component.translatable(LeashRopeArrowItem.DESC_2));
|
||||
pConsumer.accept(Component.translatable(LeashRopeArrowItem.DESC_3));
|
||||
pConsumer.accept(Component.translatable(LeashRopeArrowItem.DESC_4));
|
||||
pConsumer.accept(Component.translatable(LeashRopeArrowItem.DESC_5));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.r3944realms.leashedplayer.content.items.type;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
|
||||
import com.r3944realms.leashedplayer.content.entities.SpectralLeashRopeArrow;
|
||||
import net.minecraft.ChatFormatting;
|
||||
import net.minecraft.core.Direction;
|
||||
import net.minecraft.core.Position;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.projectile.AbstractArrow;
|
||||
import net.minecraft.world.entity.projectile.Projectile;
|
||||
import net.minecraft.world.item.ArrowItem;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.List;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class SpectralLeashRopeArrowItem extends ArrowItem implements ILeashRopeArrow{
|
||||
public static final String descKey = "item.spectral_leash_rope_arrow.description",
|
||||
DESC = "item.spectral_leash_rope_arrow.desc";
|
||||
public SpectralLeashRopeArrowItem(Properties pProperties) {
|
||||
super(pProperties);
|
||||
}
|
||||
public @NotNull AbstractArrow createArrow(@NotNull Level pLevel, @NotNull ItemStack pAmmo, @NotNull LivingEntity pShooter, @Nullable ItemStack pWeapon) {
|
||||
return new SpectralLeashRopeArrow(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), pShooter, pLevel, pAmmo.copyWithCount(1), pWeapon);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Projectile asProjectile(@NotNull Level pLevel, @NotNull Position pPos, @NotNull ItemStack pStack, @NotNull Direction pDirection) {
|
||||
LeashRopeArrow arrow = new SpectralLeashRopeArrow(ModEntityRegister.SPECTRAL_LEASH_ROPE_ARROW.get(), pPos.x(), pPos.y(), pPos.z(), pLevel, this.getDefaultInstance(),null, null);
|
||||
arrow.pickup = AbstractArrow.Pickup.DISALLOWED;
|
||||
return arrow;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(@NotNull ItemStack pItemStack, @NotNull TooltipContext pTooltipComponents, @NotNull TooltipDisplay pTooltipDisplay, Consumer<Component> pConsumer, @NotNull TooltipFlag pTooltipFlag) {
|
||||
pConsumer.accept(Component.translatable(LeashRopeArrowItem.DESC_V_1));
|
||||
pConsumer.accept(Component.translatable(LeashRopeArrowItem.DESC_V_2));
|
||||
pConsumer.accept(Component.translatable(DESC));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,47 @@
|
|||
package com.r3944realms.leashedplayer.content.items.type;
|
||||
|
||||
import com.r3944realms.leashedplayer.client.processBar.IProcessBar;
|
||||
import com.r3944realms.leashedplayer.client.processBar.TestProcessBar;
|
||||
import com.r3944realms.leashedplayer.client.renderer.gui.AdaptiveGuiRendererHandler;
|
||||
import com.r3944realms.leashedplayer.client.renderer.gui.IFadingProcessBarRenderer;
|
||||
import com.r3944realms.leashedplayer.client.renderer.gui.IProcessBarRenderer;
|
||||
import com.r3944realms.leashedplayer.client.renderer.gui.TestProcessBarRenderer;
|
||||
import net.minecraft.world.InteractionHand;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class TestItem extends Item {
|
||||
public TestProcessBar testProcessBar = null;
|
||||
public TestItem(Properties pProperties) {
|
||||
super(pProperties);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull InteractionResult use(@NotNull Level pLevel, @NotNull Player pPlayer, @NotNull InteractionHand pUsedHand) {
|
||||
if(!pLevel.isClientSide()){
|
||||
//some lo
|
||||
}
|
||||
else {
|
||||
if (testProcessBar == null) {
|
||||
testProcessBar = new TestProcessBar();
|
||||
testProcessBar.setRenderStatus(true);
|
||||
TestProcessBarRenderer testProcessBarRenderer = new TestProcessBarRenderer(testProcessBar);
|
||||
AdaptiveGuiRendererHandler.addProcessBar(testProcessBar, testProcessBarRenderer);
|
||||
} else {
|
||||
if(testProcessBar.getCurrentProcess() >= testProcessBar.getMaxProcess()) {
|
||||
testProcessBar.increase();
|
||||
IProcessBarRenderer<? extends IProcessBar> processBarRenderer = AdaptiveGuiRendererHandler.getProcessBarRenderer(testProcessBar);
|
||||
((IFadingProcessBarRenderer<?>)processBarRenderer).setFadingOut(true);
|
||||
testProcessBar = null;
|
||||
} else {
|
||||
testProcessBar.increase();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
return super.use(pLevel, pPlayer, pUsedHand);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,49 @@
|
|||
package com.r3944realms.leashedplayer.content.items.type;
|
||||
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.component.DataComponents;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.TooltipFlag;
|
||||
import net.minecraft.world.item.alchemy.Potion;
|
||||
import net.minecraft.world.item.alchemy.PotionContents;
|
||||
import net.minecraft.world.item.alchemy.Potions;
|
||||
import net.minecraft.world.item.component.TooltipDisplay;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Optional;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class TippedLeashRopeArrowItem extends LeashRopeArrowItem {
|
||||
public static final String TIPPED_LEASH_ROPE_ARROW_NAME = "item.tipped_leash_rope_arrow.name";
|
||||
public static final String DESC = "item.tipped_leash_rope_arrow.desc";
|
||||
public TippedLeashRopeArrowItem(Properties pProperties) {
|
||||
super(pProperties);
|
||||
}
|
||||
@Override
|
||||
public @NotNull ItemStack getDefaultInstance() {
|
||||
ItemStack itemstack = super.getDefaultInstance();
|
||||
itemstack.set(DataComponents.POTION_CONTENTS, new PotionContents(Potions.POISON));
|
||||
return itemstack;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void appendHoverText(@NotNull ItemStack pItemStack, @NotNull TooltipContext pTooltipComponents, @NotNull TooltipDisplay pTooltipDisplay, Consumer<Component> pConsumer, @NotNull TooltipFlag pTooltipFlag) {
|
||||
super.appendHoverText(pItemStack, pTooltipComponents, pTooltipDisplay, pConsumer, pTooltipFlag);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull Component getName(@NotNull ItemStack pStack) {
|
||||
Optional<Holder<Potion>> pPotion = pStack.getOrDefault(DataComponents.POTION_CONTENTS, PotionContents.EMPTY).potion();
|
||||
String s = null,s1;
|
||||
if (pPotion.isPresent()) {
|
||||
s = pPotion.get().value().name();
|
||||
}
|
||||
boolean flag = s == null;
|
||||
s1 = pPotion.flatMap(Holder::unwrapKey).map(p_331494_ -> p_331494_.location().getPath()).orElse("empty");
|
||||
String potionTranslateKey = "item.minecraft.potion.effect." + (flag ? s1: s);
|
||||
return Component.translatable(TIPPED_LEASH_ROPE_ARROW_NAME, Component.translatable(potionTranslateKey));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,78 @@
|
|||
package com.r3944realms.leashedplayer.content.misc;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.core.dispenser.BlockSource;
|
||||
import net.minecraft.core.dispenser.OptionalDispenseItemBehavior;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.sounds.SoundEvents;
|
||||
import net.minecraft.sounds.SoundSource;
|
||||
import net.minecraft.tags.BlockTags;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntitySelector;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.level.block.BeehiveBlock;
|
||||
import net.minecraft.world.level.block.DispenserBlock;
|
||||
import net.minecraft.world.level.block.entity.BeehiveBlockEntity;
|
||||
import net.minecraft.world.level.block.state.BlockState;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class LeadBreakItemBehavior extends OptionalDispenseItemBehavior {
|
||||
@Override
|
||||
protected @NotNull ItemStack execute(@NotNull BlockSource blockSource, @NotNull ItemStack item) {
|
||||
ServerLevel serverLevel = blockSource.level();
|
||||
if(!serverLevel.isClientSide()) {
|
||||
BlockPos blockPos = blockSource.pos().relative(blockSource.state().getValue(DispenserBlock.FACING));
|
||||
this.setSuccess(tryShearBeehive(serverLevel, blockPos) || tryShearLivingEntity(serverLevel, blockPos, item));
|
||||
if (this.isSuccess()) {
|
||||
item.hurtAndBreak(1, serverLevel, null, p_348118_ -> {
|
||||
});
|
||||
}
|
||||
}
|
||||
return item;
|
||||
}
|
||||
private static boolean tryShearBeehive(ServerLevel level, BlockPos pos) {
|
||||
BlockState blockstate = level.getBlockState(pos);
|
||||
if (blockstate.is(BlockTags.BEEHIVES, p_202454_ -> p_202454_.hasProperty(BeehiveBlock.HONEY_LEVEL) && p_202454_.getBlock() instanceof BeehiveBlock)) {
|
||||
int i = blockstate.getValue(BeehiveBlock.HONEY_LEVEL);
|
||||
if (i >= 5) {
|
||||
level.playSound(null, pos, SoundEvents.BEEHIVE_SHEAR, SoundSource.BLOCKS, 1.0F, 1.0F);
|
||||
BeehiveBlock.dropHoneycomb(level, pos);
|
||||
((BeehiveBlock)blockstate.getBlock())
|
||||
.releaseBeesAndResetHoneyLevel(level, blockstate, pos, null, BeehiveBlockEntity.BeeReleaseStatus.BEE_RELEASED);
|
||||
level.gameEvent(null, GameEvent.SHEAR, pos);
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
private static boolean tryShearLivingEntity(ServerLevel level, BlockPos pos, ItemStack item) {
|
||||
for (LivingEntity livingentity : level.getEntitiesOfClass(LivingEntity.class, new AABB(pos), EntitySelector.NO_SPECTATORS)) {
|
||||
if (livingentity instanceof PlayerLeashable playerLeashable) {
|
||||
if (playerLeashable.isLeashed()){
|
||||
Leashable.dropLeash((Entity & Leashable)playerLeashable, true, !(playerLeashable.getLeashHolder() instanceof LeashRopeArrow));
|
||||
if (playerLeashable.getLeashHolder() instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.setOwner(null);
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
} else if (livingentity instanceof Leashable leashable) {
|
||||
if (leashable.isLeashed()) {
|
||||
Leashable.dropLeash((Entity & Leashable) leashable,true, !(leashable.getLeashHolder() instanceof LeashRopeArrow));
|
||||
if (leashable.getLeashHolder() instanceof LeashRopeArrow leashRopeArrow) {
|
||||
leashRopeArrow.setOwner(null);
|
||||
}
|
||||
return true;
|
||||
} else return false;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.r3944realms.leashedplayer.content.paintings;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModPaintingVariants;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.decoration.PaintingVariant;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.Optional;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModPaintingsRegister {
|
||||
public static final DeferredRegister<PaintingVariant> PAINTING_VARIANT =
|
||||
DeferredRegister.create(Registries.PAINTING_VARIANT, LeashedPlayer.MOD_ID);
|
||||
public static final Supplier<PaintingVariant> GROUP_PHOTO = PAINTING_VARIANT.register("group_photo", () -> new PaintingVariant(1920, 1080, getAssetId("group_photo"), Optional.of(Component.translatable(ModPaintingVariants.getPaintingVariantTitleKey(ModPaintingVariants.GROUP_PHOTO))), Optional.of(Component.translatable(ModPaintingVariants.getPaintingVariantAuthorKey(ModPaintingVariants.GROUP_PHOTO)))));
|
||||
|
||||
private static @NotNull ResourceLocation getAssetId(String paint_name) {
|
||||
return ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/painting/"+paint_name+".png");
|
||||
}
|
||||
|
||||
public static void register(IEventBus eventBus) {
|
||||
PAINTING_VARIANT.register(eventBus);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.r3944realms.leashedplayer.content.sounds;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.neoforged.bus.api.IEventBus;
|
||||
import net.neoforged.neoforge.registries.DeferredHolder;
|
||||
import net.neoforged.neoforge.registries.DeferredRegister;
|
||||
|
||||
import java.util.function.Supplier;
|
||||
|
||||
public class ModSoundRegister {
|
||||
public static DeferredRegister<SoundEvent> SOUNDS = DeferredRegister.create(BuiltInRegistries.SOUND_EVENT, LeashedPlayer.MOD_ID);
|
||||
public static ResourceLocation RL_FOX_MUSIC = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "music/what_does_the_fox_say");
|
||||
public static final DeferredHolder<SoundEvent, SoundEvent> FOX_MUSIC =
|
||||
ModSoundRegister.register("what_does_the_fox_say", () -> SoundEvent.createFixedRangeEvent(
|
||||
RL_FOX_MUSIC,
|
||||
128
|
||||
));
|
||||
|
||||
public static DeferredHolder<SoundEvent, SoundEvent> register(String name, Supplier<SoundEvent> supplier){
|
||||
return SOUNDS.register(name, supplier);
|
||||
|
||||
}
|
||||
public static void register(IEventBus modBus){
|
||||
SOUNDS.register(modBus);
|
||||
}
|
||||
public static String getJukeboxSongTranslateKey(String name) {
|
||||
return "jukebox_song." + LeashedPlayer.MOD_ID + "." + name;
|
||||
}
|
||||
public static String getSubTitleTranslateKey(String name) {
|
||||
return "sound." + LeashedPlayer.MOD_ID + ".subtitle." + name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.r3944realms.leashedplayer.datagen.LanguageAndOtherData;
|
||||
|
||||
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
public enum ModAdvancementKey {
|
||||
LEASH_START("leash_start", null),
|
||||
LEASHED_FRIEND("leashed_friend", LEASH_START),
|
||||
LEASHED_SELF("leashed_self", LEASH_START),
|
||||
LEASH_ARROW("leash_arrow", LEASH_START),
|
||||
ADVANCEMENT_LEASH_ARROW("advancement_leash_arrow", LEASH_ARROW),
|
||||
FOLLOW_LEASH_ARROW("follow_arrow", LEASH_ARROW),
|
||||
DOG_RUNNING_PLAYER("dog_running_player", LEASH_ARROW),
|
||||
NO_LEASH("no_leash", LEASH_START),
|
||||
LEASH_TERMINATOR("leash_terminator", LEASH_START),
|
||||
TIPPED_LEASH_ARROW("tipped_leash_arrow", LEASH_ARROW),
|
||||
NEO_FOX("neo_fox", LEASH_START),
|
||||
;
|
||||
private final String Name;
|
||||
@Nullable
|
||||
private final ModAdvancementKey Parent;
|
||||
ModAdvancementKey(String name, @Nullable ModAdvancementKey parent) {
|
||||
this.Name = name;
|
||||
this.Parent = parent;
|
||||
}
|
||||
|
||||
public @Nullable ModAdvancementKey getParent() {
|
||||
return Parent;
|
||||
}
|
||||
public String getNameKey() {
|
||||
return "advancement." + LeashedPlayer.MOD_ID + "." + Name;
|
||||
}
|
||||
|
||||
public String getDescKey() {
|
||||
return this.getNameKey() + ".desc";
|
||||
}
|
||||
public String getNameWithNameSpace() {
|
||||
return LeashedPlayer.MOD_ID + ":" + this.Name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.r3944realms.leashedplayer.datagen.LanguageAndOtherData;
|
||||
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.tags.TagKey;
|
||||
import net.minecraft.world.item.Item;
|
||||
|
||||
public final class ModItemTags {
|
||||
public static final TagKey<Item> AMETHYST_TOOL_MATERIALS = bind("amethyst_tool_materials");
|
||||
|
||||
private ModItemTags() {
|
||||
}
|
||||
|
||||
private static TagKey<Item> bind(String name) {
|
||||
return TagKey.create(Registries.ITEM, ResourceLocation.withDefaultNamespace(name));
|
||||
}
|
||||
|
||||
public static TagKey<Item> create(final ResourceLocation name) {
|
||||
return TagKey.create(Registries.ITEM, name);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,235 @@
|
|||
package com.r3944realms.leashedplayer.datagen.LanguageAndOtherData;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.ModKeyMapping;
|
||||
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
|
||||
import com.r3944realms.leashedplayer.content.commands.MotionCommand;
|
||||
import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
|
||||
import com.r3944realms.leashedplayer.content.effects.ModPotionRegister;
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.Server.CreateLeashFenceKnotEntityIfAbsent;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.Server.KeepLeashNotDropTime;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.Server.TeleportWithLeashedPlayers;
|
||||
import com.r3944realms.leashedplayer.content.items.ModCreativeTab;
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.content.items.type.LeadBreakerItem;
|
||||
import com.r3944realms.leashedplayer.content.items.type.LeashRopeArrowItem;
|
||||
import com.r3944realms.leashedplayer.content.items.type.SpectralLeashRopeArrowItem;
|
||||
import com.r3944realms.leashedplayer.content.items.type.TippedLeashRopeArrowItem;
|
||||
import com.r3944realms.leashedplayer.content.sounds.ModSoundRegister;
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModPaintingVariants;
|
||||
import com.r3944realms.leashedplayer.network.server.Code;
|
||||
import com.r3944realms.leashedplayer.network.server.DecreaseLeashRopeLength;
|
||||
import com.r3944realms.leashedplayer.network.server.IncreaseLeashRopeLength;
|
||||
import com.r3944realms.leashedplayer.utils.Enum.LanguageEnum;
|
||||
import com.r3944realms.leashedplayer.utils.Enum.ModPartEnum;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.function.Supplier;
|
||||
|
||||
import static com.r3944realms.leashedplayer.content.items.ModCreativeTab.LEASHED_PLAYER_ITEM;
|
||||
|
||||
public enum ModLangKeyValue {
|
||||
KEY_CATEGORY(ModKeyMapping.CATEGORY, ModPartEnum.NAME, "Leashed Player", "可拴玩家", "可拴玩家", false),
|
||||
KEY_ADD_LEASH_OTHER_LEASH_LENGTH(ModKeyMapping.ADD_LEASH_LENGTH_KEY, ModPartEnum.NAME, "Increase the Length of Leash Rope", "增加拴绳长度", "增加拴繩長度", false),
|
||||
KEY_SUB_LEASH_OTHER_LEASH_LENGTH(ModKeyMapping.SUB_LEASH_LENGTH_KEY, ModPartEnum.NAME, "Decrease the Length of Leash Rope", "减小拴绳长度", "減小拴繩長度", false),
|
||||
//ITEM
|
||||
ITEM_LEASH_ROPE_ARROW(ModItemRegister.LEASH_ROPE_ARROW, ModPartEnum.ITEM, "Leash Rope Arrow", "拴绳箭", "拴繩箭", true),
|
||||
ITEM_SPECTRAL_LEASH_ROPE_ARROW(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW, ModPartEnum.ITEM, "Spectral Leash Rope Arrow", "拴绳光灵箭", "拴繩光靈箭", true),
|
||||
TEST_FABRIC_ITEM(ModItemRegister.FABRIC, ModPartEnum.ITEM, "Fabric", "Fabric", "Fabric", true),
|
||||
AMETHYST_SHEARS(ModItemRegister.AMETHYST_SHEARS, ModPartEnum.ITEM, "Amethyst Shears", "紫水晶剪刀", "紫水晶剪刀", true),
|
||||
NEO_FORGE(ModItemRegister.NEOFORGE, ModPartEnum.ITEM, "NeoForge", "NeoForge", "NeoForge", false),
|
||||
TIPPED_LEASH_ROPE_ARROW(TippedLeashRopeArrowItem.TIPPED_LEASH_ROPE_ARROW_NAME, ModPartEnum.ITEM, "Tipped Leash Rope Arrow Soaked By %1$s", "用%1$s浸泡过的拴绳箭", "蘸有%1$s的拴繩箭", false),
|
||||
//ITEM_DESC
|
||||
DESC_ITEM_LEASH_R_ARROW_ONE(LeashRopeArrowItem.DESC_1, ModPartEnum.DESCRIPTION, "§7This arrow will carry the owner along with its flight:", "§7该箭将会携带拥有者随其飞行", "§7該箭將會攜帶擁有者隨其飛行:", false),
|
||||
DESC_ITEM_LEASH_R_ARROW_TWO(LeashRopeArrowItem.DESC_2, ModPartEnum.DESCRIPTION, "§c1.§r If it hits a fence or an entity, it will leash the owner to it and drop as a normal arrow.", "§c1.§r 若击中栅栏或生物时,将持有者拴在其上并已普通箭形式掉落;", "§c1.§r 若擊中柵欄或生物時,將持有者拴在其上並以普通箭的形式掉落;", false),
|
||||
DESC_ITEM_LEASH_R_ARROW_THREE(LeashRopeArrowItem.DESC_3, ModPartEnum.DESCRIPTION,"§c2.§r Crouching near the arrow allows for faster retrieval. If the arrow's owner is not the player, the owner will be leashed to the player who picks it up.", "§c2.§r 靠近该箭下蹲可以更快拾取该箭,如果该箭持有者不是自己,则持有者将被拾取者拴住;", "§c2.§r 靠近該箭下蹲可以更快拾取該箭,如果該箭的持有者不是自己,則持有者將被拾取者拴住;", false),
|
||||
DESC_ITEM_LEASH_R_ARROW_FOUR(LeashRopeArrowItem.DESC_4, ModPartEnum.DESCRIPTION, "§c3.§r When fired from its launcher, the first entity hit will become the arrow's owner and will fly along with it.", "§c3.§r 当前其发射器里发射,第一个射中的生物将成为此箭的持有者并随箭飞行;", "§c3.§r 當箭從發射器發射時,第一個射中的生物將成為此箭的持有者並隨箭飛行;", false),
|
||||
DESC_ITEM_LEASH_R_ARROW_FIVE(LeashRopeArrowItem.DESC_5, ModPartEnum.DESCRIPTION, "§c4.§r Under the §c§l\"no_leash\"§r effect, the behavior of the arrow when fired will follow the launcher’s behavior.", "§c4.§r 在§c§l禁拴§7(§c§lno_leash§7)§r效果下,射出的箭行为同发射器。","§c4.§r 在§c§l禁拴§7(§c§lno_leash§7)§r效果下,射出的箭行為將與發射器的行為相同。", false),
|
||||
DESC_ITEM_LEASH_ROPE_ARROW(LeashRopeArrowItem.descKey, ModPartEnum.DESCRIPTION, "Arrows with ropes attached?","带有拴绳的箭矢?", "帶有拴繩的箭矢?", false),
|
||||
DESC_ITEM_V_LEASH_R_ARROW_ONE(LeashRopeArrowItem.DESC_V_1, ModPartEnum.DESCRIPTION, "§7A variant of Leash Rope Arrow", "§7拴绳箭的一个变种", "§7拴繩箭矢的一個變種", false),
|
||||
DESC_ITEM_V_LEASH_R_ARROW_TWO(LeashRopeArrowItem.DESC_V_2, ModPartEnum.DESCRIPTION, "§c1.§r The function is the same as its original one。", "§c1.§r 功能同其本体;", "§c1.§r 功能與本體一致;", false),
|
||||
DESC_ITEM_S_LEASH_R_ARROW_THREE(SpectralLeashRopeArrowItem.DESC, ModPartEnum.DESCRIPTION, "§c2.§r Strike the entity to give it a §e§lGlowing§r effect.", "§c2.§r 击中实体给与其§e§l发光§7(§e§lGlowing§7)§r效果", "擊中實體給予其§e§l發光§7(§e§lGlowing§7)§r效果", false),
|
||||
DESC_ITEM_T_LEASH_R_ARROW_THREE(TippedLeashRopeArrowItem.DESC, ModPartEnum.DESCRIPTION, "§c2.§rStrike the entity to give it a Potion effect.", "§c2.§r 击中实体给与其药水效果", "擊中實體給予其药水效果", false),
|
||||
DESC_ITEM_LEAD_BREAKER(LeadBreakerItem.HOVER_KEY, ModPartEnum.DESCRIPTION, "§7can break the link of leash", "§7可以破坏拴绳链接", "§7可以破壞拴繩鏈接", false),
|
||||
|
||||
//PAINTING
|
||||
GROUP_PHOTO_TITLE(ModPaintingVariants.getPaintingVariantTitleKey(ModPaintingVariants.GROUP_PHOTO),ModPartEnum.TITLE, "§dGroup Photo §7[§6memorable§7]§r", "§d集体照 §7[§6纪念§7]§r", "§d集體照 §7[§6紀念§7]§r", false),
|
||||
GROUP_PHOTO_AUTHOR(ModPaintingVariants.getPaintingVariantAuthorKey(ModPaintingVariants.GROUP_PHOTO),ModPartEnum.AUTHOR, "§9Leisure §4Time §eDock§r","§9闲趣§4时§e坞§r","§9閑趣§4時§e塢§r",false),
|
||||
//ENTITY
|
||||
LEASH_ROPE_ARROW(ModEntityRegister.getEntityNameKey("leash_rope_arrow"), ModPartEnum.ENTITY, "Leash Rope Arrow", "拴绳箭", "拴繩箭", false),
|
||||
SPECTRAL_LEASH_ROPE_ARROW(ModEntityRegister.getEntityNameKey("spectral_leash_rope_arrow"), ModPartEnum.ENTITY, "Spectral Leash Rope Arrow", "拴绳光灵箭", "拴繩光靈箭", false),
|
||||
kID(ModEntityRegister.getEntityNameKey("kid_player"), ModPartEnum.ENTITY, "Kid", "小孩", "小孩", "幼", false),
|
||||
NESTLE_ROPE_ARROW(ModEntityRegister.getEntityNameKey("nestle_rope_arrow"), ModPartEnum.ENTITY, "Nestle Rope Arrow", "贴贴拴绳箭", "貼貼拴繩箭", false),
|
||||
//DIST
|
||||
ST_WHAT_DOES_THE_FOX_SAY(ModSoundRegister.getSubTitleTranslateKey("what_does_the_fox_say"), ModPartEnum.TITLE, "Great Chu will rise again! Chen She will be king!", "大楚兴~ 陈胜王~~", "大楚興~ 陳勝王~~", false),
|
||||
JB_WHAT_DOES_THE_FOX_SAY(ModSoundRegister.getJukeboxSongTranslateKey("what_does_the_fox_say"), ModPartEnum.DESCRIPTION, "What does the fox say?", "狐狸是怎么叫的?", "狐狸是怎麽叫的?", false),
|
||||
//CREATIVE_TAB
|
||||
CREATIVE_TAB_NAME(ModCreativeTab.getCreativeMod(LEASHED_PLAYER_ITEM), ModPartEnum.CREATIVE_TAB, "Leashed Player","可拴玩家", "可拴玩家", false),
|
||||
//COMMAND_MESSAGE
|
||||
MESSAGE_LEASH_LENGTH_FAILED(LeashCommand.LEASH_FAILED, ModPartEnum.COMMAND, "Failed (Internal Error, maybe your command is incorrect)", "失败(内部错误,可能是你输的指令有误)", "失敗(内部錯誤,,可能你輸入的指令有誤)", false),
|
||||
MESSAGE_LEASH_LENGTH_SHOW(LeashCommand.LEASH_LENGTH_SHOW, ModPartEnum.COMMAND, "The Leash Length of %1$s is %2$s blocks", "%1$s的拴绳长度为%2$s格", "%1$s的拴繩長度為%2$s格" , false),
|
||||
MESSAGE_LEASH_LENGTH_SET(LeashCommand.LEASH_LENGTH_SET, ModPartEnum.COMMAND, "The Leash length of %1$s is set to %2$s blocks", "%1$s的拴绳长度被设置为%2$s格", "%1$s的拴繩長度被設置為%2$s格" , false),
|
||||
MESSAGE_LEASH_GET_LEASH_DATA(LeashCommand.LEASH_DATA_SHOW, ModPartEnum.COMMAND, "%1$s's LeashDataEntity is %2$s", "%1$s的拴绳数据实体为%2$s", "%1$s拴繩數據實體為%2$s",false),
|
||||
MESSAGE_LEASH_NO_LEASH_DATA(LeashCommand.NO_LEASH_DATA, ModPartEnum.COMMAND, "%1$s has no LeashDataEntity", "%1$s沒有拴绳数据实体", "%1$s沒有拴繩數據實體", false),
|
||||
MESSAGE_LEASH_SET_LEASH_DATA(LeashCommand.LEASH_DATA_SET, ModPartEnum.COMMAND, "%1$s LeashDataEntity now is set as %2$s", "%1$s拴绳数据实体被设置为%2$s", "%1$s拴繩數據實體設置為%2$s", false),
|
||||
MESSAGE_LEASH_SET_FAILED_DIFF_LEVEL(LeashCommand.LEASH_DATA_SET_FAILED_DIFF_LEVEL, ModPartEnum.COMMAND,"%1$s and %2$s are not at a same level", "%1$s和%2$s不在同一维度上", "%1$s和%2$s不在同一緯度上", false),
|
||||
MESSAGE_LEASH_SET_FAILED_TOO_FAR(LeashCommand.LEASH_DATA_SET_FAILED_TOO_FAR, ModPartEnum.COMMAND,"The distance between %1$s and %2$s is larger than the 1.2 times of LeashLength, LeashLength is %3$s blocks", "%1$s到%2$s的距离超过了1.2倍 拴绳长度,原长:%3$s 格", "%1$s到%2$s的距離超過了1.2倍拴繩長度,原長:%3$s 格", false),
|
||||
MESSAGE_LEASH_SET_FAILED_NO_KNOT_EXIST_IN_THAT_POS(LeashCommand.LEASH_DATA_SET_FAILED_NO_KNOT_EXISTED_IN_THAT_POS, ModPartEnum.COMMAND, "No knot found at (X:%f,Y:%f,Z:%f)", "未找到拴绳结在(X:%f, Y:%f, Z:%f)处", "未找到拴繩結在(X:%f, Y:%f, Z:%f)処", false),
|
||||
MESSAGE_LEASH_CLEAR(LeashCommand.LEASH_DATA_CLEAR, ModPartEnum.COMMAND, "%1$s's LeashData(LeashHolderEntity: %2$s) now is clear", "%1$s的拴绳数据(拴绳持有者实体:%2$s)现在已清除", "%1$s的拴繩數據(拴繩持有者實體:%2$s)現在已清除", false),
|
||||
MESSAGE_LEASH_SET_FAILED_FORBID_SAME_ENTITY(LeashCommand.LEASH_DATA_SET_FAILED_FORBID_SAME_ENTITY, ModPartEnum.COMMAND, "Prohibit setting the same entity","禁止设置同一实体", "禁止設置同一實體", false),
|
||||
MESSAGE_LEASH_CLEAR_FAILED(LeashCommand.LEASH_DATA_CLEAR_FAILED_NO_DATA, ModPartEnum.COMMAND, "%1$s has no LeashData can be clear", "%1$s沒有拴绳数据可清除", "%1$s沒有拴繩數據實體可被清除", false),
|
||||
MESSAGE_MOTION_ADDER_SUCCESSFUL(MotionCommand.MOTION_ADDER_SUCCESSFUL, ModPartEnum.COMMAND, "§bAdd Successfully.§a%s§7:§f[§eVec§7: §a(§f%f§7,§f%f§7,§f%f§a)§f]§r","§b添加成功.§a%s§7:§f[§e加速度§7:§a(§f%f§7,§f%f§7,§f%f§a)§f]§r","§b添加成功.§a%s§7:§f[§e加速度§7:§a(§f%f§7,§f%f§7,§f%f§a)§f]§r", false),
|
||||
MESSAGE_MOTION_SETTER_SUCCESSFUL(MotionCommand.MOTION_SETTER_SUCCESSFUL, ModPartEnum.COMMAND, "§bSet Successfully.§a%s§7:§f[§eVec§7: §a(§f%f§7,§f%f§7,§f%f§a)§f]§r","§b设置成功.§a%s§7:§f[§e加速度§7:§a(§f%f§7,§f%f§7,§f%f§a)§f]§r","§b設置成功.§a%s§7:§f[§e加速度§7:§a(§f%f§7,§f%f§7,§f%f§a)§f]§r",false),
|
||||
MESSAGE_MOTION_MULTIPLY_SUCCESSFUL(MotionCommand.MOTION_MULTIPLY_SUCCESSFUL, ModPartEnum.COMMAND, "§bMultiply Successfully.§a%s§7:§f[§eVec§7: §a(§f%f§7,§f%f§7,§f%f§a)§f]§r","§b倍乘成功.§a%s§7:§f[§e加速度§7:§a(§f%f§7,§f%f§7,§f%f§a)§f]§r","§b倍乘成功.§a%s§7:§f[§e加速度§7:§a(§f%f§7,§f%f§7,§f%f§a)§f]§r",false),
|
||||
MESSAGE_LEASH_BREAKER_USE_SUF(LeadBreakerItem.MESSAGE_USE_SUF, ModPartEnum.MESSAGE, "§aSuccessfully break §f%1$s§a 's Leashed Link to §f%2$s ", "§a成功剪断§f%2$s§a对§f%1$s§a拴绳链接", "§a成功剪斷§f%2$s§a對§f%1$s§a拴繩鏈接", false),
|
||||
MESSAGE_LEASH_BREAKER_USE_FAI(LeadBreakerItem.MESSAGE_USE_FAI, ModPartEnum.MESSAGE, "§cFailed to break §f%1$s§c 's Leashed Link to §f%2$s", "§c无法剪断§f%2$s§c对§f%1$s§c拴绳链接", "§c未能剪斷§f%2$s§c對§f%1$s§c拴繩鏈接", false),
|
||||
MESSAGE_LEASH_NOT_SUPPORT_TO_NOT_PLAYER_ENTITY(ModKeyMapping.NOT_SUPPORT_TO_NOT_PLAYER_ENTITY, ModPartEnum.MESSAGE, "Only work on Players", "只在玩家身上有效", "僅對玩家有效", false),
|
||||
MESSAGE_LEASH_ADD_LEASH_LENGTH(IncreaseLeashRopeLength.INCREASE_LEASH_ROPE_LENGTH, ModPartEnum.MESSAGE, "§aIncrease the §f%s §aLength of Leash Rope§7(§bLength§7:§e%d§7)", "§a增加§f%s的拴绳长度§a§7(§b长度§7:§e%d§7)", "§a增加§f%s§a的拴繩長度§7(§長度§7:§e%d§7)", false),
|
||||
MESSAGE_LEASH_SUB_LEASH_LENGTH(DecreaseLeashRopeLength.DECREASE_LEASH_ROPE_LENGTH, ModPartEnum.MESSAGE, "§Decrease the §f%s §cLength of Leash Rope§7(§bLength§7:§e%d§7)", "§c减少§f%s的拴绳长度§c§7(§b长度§7:§e%d§7)", "§c減少§f%s§c的拴繩長度§7(§長度§7:§e%d§7)", false),
|
||||
MESSAGE_LEASH_ADD_SELF_LEASH_LENGTH(IncreaseLeashRopeLength.INCREASE_SELF_LEASH_ROPE_LENGTH, ModPartEnum.MESSAGE, "§aIncrease the Length of Leash Rope§7(§bLength§7:§e%d§7)", "§a增加拴绳长度§a§7(§b长度§7:§e%d§7)", "§a增加拴繩長度§7(§長度§7:§e%d§7)", false),
|
||||
MESSAGE_LEASH_SUB_SELF_LEASH_LENGTH(DecreaseLeashRopeLength.DECREASE_SELF_LEASH_ROPE_LENGTH, ModPartEnum.MESSAGE, "§cDecrease the Length of Leash Rope§7(§bLength§7:§e%d§7)", "§c减少拴绳长度§c§7(§b长度§7:§e%d§7)", "§c減少拴繩長度§7(§長度§7:§e%d§7)", false),
|
||||
MESSAGE_LEASH_FAILED_SET_LENGTH(Code.LEASH_LENGTH_FAILED_SET, ModPartEnum.MESSAGE, "§cFailed", "§c失败", "§c失敗", false),
|
||||
//GAME_RULE_NAME
|
||||
TELEPORT_WITH_LEASHED_PLAYERS_NAME(TeleportWithLeashedPlayers.NAME_KEY, ModPartEnum.NAME, "Teleport leashed player with player holder", "被拴玩家随玩家持有者传送", "被拴玩家随玩家持有者傳送" ,false),
|
||||
CREATE_LEASH_FENCE_KNOT_ENTITY_IF_ABSENT_NAME(CreateLeashFenceKnotEntityIfAbsent.NAME_KEY, ModPartEnum.NAME, "Create Leash Fence Knot Entity if absent", "如果缺失则创建拴绳结", "如果缺失則創建拴繩結", false),
|
||||
KEEP_LEASH_NOT_DROP_TIME_NAME(KeepLeashNotDropTime.NAME_KEY, ModPartEnum.NAME, "Keep leash alive Time", "保持拴绳不掉落的时间", "保持其不掉落的時間", false),
|
||||
|
||||
TRY_TO_PICKUP_LEASHED_ROPE_ARROW(LeashRopeArrow.PUSH_SHIFT_TO_PICKUP_QUICKLY, ModPartEnum.MESSAGE, "§aPush §f§lShift§a to pick up quickly", "§a按下§f§lShift键§a以加快拾取", "§a按下§f§lShift鍵§a以加速拾取", false),
|
||||
//GAME_RULE_DESCRIPTION
|
||||
TELEPORT_WITH_LEASHED_DESCRIPTION(TeleportWithLeashedPlayers.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION, "Holder will teleport with their leashed players ", "传送时将被拴玩家与持有者一起传送", "將被拴玩家將隨持有者一起傳送" ,false),
|
||||
CREATE_LEASH_FENCE_KNOT_ENTITY_IF_ABSENT_DESCRIPTION(CreateLeashFenceKnotEntityIfAbsent.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION, "Create LeashKnot Entity if it's absent on fence", "如果在栅栏处缺失拴绳结,则创建它", "如果在柵欄処缺失拴繩結,則創建它", false),
|
||||
KEEP_LEASH_NOT_DROP_TIME_DESCRIPTION(KeepLeashNotDropTime.DESCRIPTION_KEY, ModPartEnum.DESCRIPTION,"The time of Keep new leash which has far distance alive (Tick)", "当距离过远时,保持新建拴绳不掉落的时间 (刻)", "儅距離過遠時,保持其不掉落的時間(刻)", false),
|
||||
|
||||
|
||||
//ADV_NAME
|
||||
LEASH_START(ModAdvancementKey.LEASH_START.getNameKey(), ModPartEnum.NAME, "The Power of Traction", "牵引之力", "牽引之力", false),
|
||||
LEASH_LR_ARROW(ModAdvancementKey.LEASH_ARROW.getNameKey(), ModPartEnum.NAME, "Arrow with a Tether?" , "拴绳之箭?", "拴繩之箭?", false),
|
||||
LEASH_SLP_ARROW(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getNameKey(), ModPartEnum.NAME, "More advanced flash arrow with a Tether?", "更闪亮的拴绳箭?", "更閃亮的拴繩箭?", false),
|
||||
LEASH_SELF(ModAdvancementKey.LEASHED_SELF.getNameKey(), ModPartEnum.NAME, "Stable Connection", "稳固联结" ,"穩固聯結", false),
|
||||
LEASH_PLAYER(ModAdvancementKey.LEASHED_FRIEND.getNameKey(),ModPartEnum.NAME, "Be bound by Rope", "拴绳链接", "拴繩鏈接" , false),
|
||||
FOLLOW_ARROW(ModAdvancementKey.FOLLOW_LEASH_ARROW.getNameKey(), ModPartEnum.NAME, "Launch!!!", "启航!!!" , "啓航!!!",false),
|
||||
FOLLOW_WOLF(ModAdvancementKey.DOG_RUNNING_PLAYER.getNameKey(), ModPartEnum.NAME, "It's Walking human time.", "遛“人”时间", "遛“人”時間",false),
|
||||
TERMINATOR(ModAdvancementKey.LEASH_TERMINATOR.getNameKey(), ModPartEnum.NAME, "The Lead Terminator", "拴绳终结者","拴繩終結者", false),
|
||||
NO_LEASH(ModAdvancementKey.NO_LEASH.getNameKey(), ModPartEnum.NAME, "Don't tie me up", "勿拴我", "請恁勿拴唔", false),
|
||||
TIPPED_LEASH_ARROW(ModAdvancementKey.TIPPED_LEASH_ARROW.getNameKey(), ModPartEnum.NAME, "God said there should be more arrows", "神说要有更多箭矢", "神說要有更多箭矢", false),
|
||||
NEO_FOX(ModAdvancementKey.NEO_FOX.getNameKey(), ModPartEnum.NAME, "NEOFORGE!", "NEOFORGE!", "NEOFORGE!", false),
|
||||
//ADV_DESC
|
||||
LEASH_START_DESC(ModAdvancementKey.LEASH_START.getDescKey(), ModPartEnum.DESCRIPTION, "Journey to becoming a Leash Expert", "拴绳大师之路", "拴繩大師之路", false),
|
||||
LEASH_LR_ARROW_DESC(ModAdvancementKey.LEASH_ARROW.getDescKey(), ModPartEnum.DESCRIPTION, "Maybe you can using it to shoot some mob?", "也许可以用它来发射生物?", "也許可以用它發射生物?", false),
|
||||
LEASH_SLP_ARROW_DESC(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getDescKey(), ModPartEnum.DESCRIPTION, "Well, apart from glowing, there doesn't seem to be any other difference", "嗯,除了发光,似乎没有什么其它不同了" ,"嗯,除了發光,其它好像沒什麽不同", false),
|
||||
LEASH_SELF_DESC(ModAdvancementKey.LEASHED_SELF.getDescKey(), ModPartEnum.DESCRIPTION, "“Restrain oneself with a rope", "用拴绳拴住自己" ,"用栓繩拴住自己", false),
|
||||
LEASH_PLAYER_DESC(ModAdvancementKey.LEASHED_FRIEND.getDescKey(),ModPartEnum.DESCRIPTION, "Be Bond by player with lead", "被玩家用拴绳链接", "被玩家用拴繩鏈接", false),
|
||||
FOLLOW_ARROW_DESC(ModAdvancementKey.FOLLOW_LEASH_ARROW.getDescKey(), ModPartEnum.DESCRIPTION, "Mc, what are you talking about in physics?", "抱歉,我的世界不存在物理学" , "抱歉,麦块不講物理學",false),
|
||||
FOLLOW_WOLF_DESC(ModAdvancementKey.DOG_RUNNING_PLAYER.getDescKey(), ModPartEnum.DESCRIPTION, "In the park where dogs are not allowed to be walked, the dog decided to walk the human instead", "公园不能遛狗,于是狗站起来遛人", "公園裏不許遛狗,於是狗站起來遛人",false),
|
||||
NO_LEASH_DESC(ModAdvancementKey.NO_LEASH.getDescKey(), ModPartEnum.DESCRIPTION, "You cannot be leashed by ANY", "你不会被任何东西拴住", "恁不會被任何拴住", false),
|
||||
TERMINATOR_DESC(ModAdvancementKey.LEASH_TERMINATOR.getDescKey(), ModPartEnum.DESCRIPTION, "I am Lead Terminator!", "我來终结拴绳者!", "吾將終結拴繩!", false),
|
||||
TIPPED_LEASH_ARROW_DESC(ModAdvancementKey.TIPPED_LEASH_ARROW.getDescKey(), ModPartEnum.DESCRIPTION, "A dazzling array of Leash Rope arrows", "真是琳琅满目啊", "真是琳琅滿目啊", false),
|
||||
NEO_FOX_DESC(ModAdvancementKey.NEO_FOX.getDescKey(), ModPartEnum.DESCRIPTION, "It seems can be equipped.", "似乎可以戴头上", "似乎可以戴著", false),
|
||||
|
||||
//MOB_EFFECT
|
||||
NO_LEASH_EFFECT(ModEffectRegister.getEffectKey(ModEffectRegister.NO_LEASH_EFFECT.get()), ModPartEnum.NAME, "No Leash", "禁拴", "禁拴", false),
|
||||
//POTION
|
||||
NO_LEASH_POTION(ModPotionRegister.getPotionNameKey("no_leash", (char) 0), ModPartEnum.NAME, "No Leash Potion", "禁拴药水", "禁拴藥水", false),
|
||||
NO_LEASH_POTION_SPLASH(ModPotionRegister.getPotionNameKey("no_leash", (char) 2), ModPartEnum.NAME, "Splash No Leash Potion", "喷溅型禁拴药水", "噴濺型禁拴藥水", false),
|
||||
NO_LEASH_POTION_LINGERING(ModPotionRegister.getPotionNameKey("no_leash", (char) 1), ModPartEnum.NAME, "Splash No Leash Potion", "滞留型禁拴药水", "滯留型禁拴藥水", false),
|
||||
//ARROW
|
||||
NO_LEASH_ARROW(ModPotionRegister.getTippedArrowNameKey("no_leash"), ModPartEnum.ITEM, "Arrow of No Leash", "禁拴之箭", "禁拴之箭", false),
|
||||
;
|
||||
private final Supplier<?> supplier;
|
||||
private String key;
|
||||
private final String US_EN;
|
||||
private final String SIM_CN;
|
||||
private final String TRA_CN;
|
||||
private final String LZH;
|
||||
private final Boolean Default;
|
||||
private final ModPartEnum MPE;
|
||||
ModLangKeyValue(Supplier<?> Supplier, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, String LZH, Boolean isDefault) {
|
||||
this.supplier = Supplier;
|
||||
this.MPE = MPE;
|
||||
this.US_EN = US_EN;
|
||||
this.SIM_CN = SIM_CN;
|
||||
this.TRA_CN = TRA_CN;
|
||||
this.LZH = LZH;
|
||||
this.Default = isDefault;
|
||||
}
|
||||
ModLangKeyValue(@NotNull String ResourceKey, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, String LZH, Boolean isDefault) {
|
||||
this.supplier = null;
|
||||
this.key = ResourceKey;
|
||||
this.MPE = MPE;
|
||||
this.US_EN = US_EN;
|
||||
this.SIM_CN = SIM_CN;
|
||||
this.TRA_CN = TRA_CN;
|
||||
this.LZH = LZH;
|
||||
this.Default = isDefault;
|
||||
}
|
||||
ModLangKeyValue(Supplier<?> Supplier, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, Boolean isDefault) {
|
||||
this(Supplier, MPE, US_EN, SIM_CN, TRA_CN, null, isDefault);
|
||||
}
|
||||
ModLangKeyValue(@NotNull String ResourceKey, ModPartEnum MPE, String US_EN, String SIM_CN, String TRA_CN, Boolean isDefault) {
|
||||
this(ResourceKey, MPE, US_EN, SIM_CN, TRA_CN, null, isDefault);
|
||||
}
|
||||
public static String getLan(LanguageEnum lan, ModLangKeyValue key) {
|
||||
if (lan == null || lan == LanguageEnum.English) return getEnglish(key);
|
||||
else {
|
||||
switch (lan) {
|
||||
case SimpleChinese -> {
|
||||
return getSimpleChinese(key);
|
||||
}
|
||||
case TraditionalChinese -> {
|
||||
return getTraditionalChinese(key);
|
||||
}
|
||||
case LiteraryChinese -> {
|
||||
return getLiteraryChinese(key);
|
||||
}
|
||||
default -> {
|
||||
return getEnglish(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
private static String getEnglish(ModLangKeyValue key) {
|
||||
return key.US_EN;
|
||||
}
|
||||
private static String getSimpleChinese(ModLangKeyValue key) {
|
||||
return key.SIM_CN;
|
||||
}
|
||||
private static String getTraditionalChinese(ModLangKeyValue key) {
|
||||
return key.TRA_CN;
|
||||
}
|
||||
@Nullable
|
||||
public static String getLiteraryChinese(ModLangKeyValue key) {
|
||||
return key.LZH;
|
||||
}
|
||||
public String getKey() {
|
||||
if(key == null){
|
||||
switch (MPE) {//Don't need to use "break;"[Java feature];
|
||||
case CREATIVE_TAB, MESSAGE, INFO, DEFAULT, COMMAND, CONFIG -> throw new UnsupportedOperationException("The Key value is NULL! Please use the correct constructor and write the parameters correctly");
|
||||
case ITEM -> key = (getItem()).getDescriptionId();
|
||||
case BLOCK -> key =(getBlock()).getDescriptionId();
|
||||
|
||||
}
|
||||
//需要完善
|
||||
}
|
||||
return key;
|
||||
}
|
||||
@SuppressWarnings("null")
|
||||
public Item getItem() {
|
||||
assert supplier != null;
|
||||
return (Item)supplier.get();
|
||||
}
|
||||
@SuppressWarnings("null")
|
||||
public Block getBlock() {
|
||||
assert supplier != null;
|
||||
return (Block)supplier.get();
|
||||
}
|
||||
public boolean isDefaultItem(){
|
||||
return MPE == ModPartEnum.ITEM && Default;
|
||||
}
|
||||
public boolean isDefaultBlock() {
|
||||
return MPE == ModPartEnum.BLOCK && Default;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,94 @@
|
|||
package com.r3944realms.leashedplayer.datagen;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.datagen.provider.*;
|
||||
import com.r3944realms.leashedplayer.utils.Enum.LanguageEnum;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.data.event.GatherDataEvent;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
|
||||
public class ModDataGeneratorHandler {
|
||||
@SubscribeEvent
|
||||
public static void genData(GatherDataEvent.Client event) {
|
||||
CompletableFuture<HolderLookup.Provider> holderFolder = event.getLookupProvider();
|
||||
/*Language Provider ENGLISH CHINESE(SIM/TRA)*/
|
||||
addLanguage(event, LanguageEnum.English);
|
||||
addLanguage(event, LanguageEnum.SimpleChinese);
|
||||
addLanguage(event, LanguageEnum.TraditionalChinese);
|
||||
addLanguage(event, LanguageEnum.LiteraryChinese);
|
||||
ModDataPackBuiltInEntriesProvider(event, holderFolder);
|
||||
RecipeGenerator(event, holderFolder);
|
||||
ModTagsProvider(event, holderFolder);
|
||||
ModPaintVariantTagsProvider(event, holderFolder);
|
||||
ModSoundProvider(event);
|
||||
ModModelDataGenerate(event);
|
||||
ModAdvancementProvider(event, holderFolder);
|
||||
}
|
||||
private static void addLanguage(GatherDataEvent event, LanguageEnum language){
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModLanguageProvider>) pOutput -> new ModLanguageProvider(pOutput, LeashedPlayer.MOD_ID, language)
|
||||
);
|
||||
}
|
||||
|
||||
private static void RecipeGenerator(GatherDataEvent event, CompletableFuture<HolderLookup.Provider> future) {
|
||||
PackOutput packOutput = event.getGenerator().getPackOutput();
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
new ModRecipeProvider.Runner(packOutput, future)
|
||||
);
|
||||
}
|
||||
private static void ModTagsProvider(GatherDataEvent event, CompletableFuture<HolderLookup.Provider> completableFuture) {
|
||||
ModBlockTagProvider modBlockTagProvider = event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModBlockTagProvider>) pOutput -> {
|
||||
return new ModBlockTagProvider(pOutput, completableFuture, LeashedPlayer.MOD_ID);
|
||||
}
|
||||
|
||||
);
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModItemTagProvider>) pOutput ->
|
||||
new ModItemTagProvider(pOutput, completableFuture, modBlockTagProvider.contentsGetter())
|
||||
);
|
||||
}
|
||||
private static void ModSoundProvider(GatherDataEvent event) {
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModSoundDefinitionsProvider>) pOutput ->
|
||||
new ModSoundDefinitionsProvider(pOutput,LeashedPlayer.MOD_ID)
|
||||
);
|
||||
}
|
||||
private static void ModDataPackBuiltInEntriesProvider(GatherDataEvent event, CompletableFuture<HolderLookup.Provider> future) {
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModDataPackBuiltInEntriesProvider>) pOutput -> new ModDataPackBuiltInEntriesProvider(pOutput, future)
|
||||
);
|
||||
}
|
||||
private static void ModAdvancementProvider(GatherDataEvent event, CompletableFuture<HolderLookup.Provider> pLookUpProvider) {
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModAdvancementProvider>) pOutput -> new ModAdvancementProvider(pOutput, pLookUpProvider));
|
||||
}
|
||||
private static void ModPaintVariantTagsProvider(GatherDataEvent event, CompletableFuture<HolderLookup.Provider> completableFuture) {
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModPaintingVariantTagsProvider>) pOutput -> {
|
||||
return new ModPaintingVariantTagsProvider(pOutput, completableFuture, LeashedPlayer.MOD_ID);
|
||||
}
|
||||
);
|
||||
}
|
||||
private static void ModModelDataGenerate(GatherDataEvent event) {
|
||||
event.getGenerator().addProvider(
|
||||
true,
|
||||
(DataProvider.Factory<ModModelDataProvider>) pOutput -> new ModModelDataProvider(pOutput, LeashedPlayer.MOD_ID)
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,175 @@
|
|||
package com.r3944realms.leashedplayer.datagen.generator;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.criteriaTriggers.LeashPlayerTrigger;
|
||||
import com.r3944realms.leashedplayer.content.effects.ModEffectRegister;
|
||||
import com.r3944realms.leashedplayer.content.entities.ModEntityRegister;
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModAdvancementKey;
|
||||
import net.minecraft.advancements.Advancement;
|
||||
import net.minecraft.advancements.AdvancementHolder;
|
||||
import net.minecraft.advancements.AdvancementType;
|
||||
import net.minecraft.advancements.critereon.*;
|
||||
import net.minecraft.core.HolderGetter;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.advancements.AdvancementSubProvider;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.item.Items;
|
||||
|
||||
import java.util.function.Consumer;
|
||||
|
||||
|
||||
public class ModAdvancementGenerator implements AdvancementSubProvider {
|
||||
private final ResourceLocation ADV_BG = ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, "textures/gui/advancements/backgrounds/leashed_player");
|
||||
|
||||
@Override
|
||||
public void generate(HolderLookup.Provider registries, Consumer<AdvancementHolder> saver) {
|
||||
HolderGetter<EntityType<?>> holdergetter = registries.lookupOrThrow(Registries.ENTITY_TYPE);
|
||||
AdvancementHolder hasLeashRopeItem = Advancement.Builder.advancement().display(
|
||||
Items.LEAD,
|
||||
Component.translatable(ModAdvancementKey.LEASH_START.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.LEASH_START.getDescKey()),
|
||||
ADV_BG,
|
||||
AdvancementType.TASK,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
).addCriterion("has_leash_rope_item", InventoryChangeTrigger.TriggerInstance.hasItems(Items.LEAD))
|
||||
.save(saver, ModAdvancementKey.LEASH_START.getNameWithNameSpace());
|
||||
|
||||
AdvancementHolder hasLeashRopeArrow = Advancement.Builder.advancement().display(
|
||||
ModItemRegister.LEASH_ROPE_ARROW.get(),
|
||||
Component.translatable(ModAdvancementKey.LEASH_ARROW.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.LEASH_ARROW.getDescKey()),
|
||||
null,
|
||||
AdvancementType.TASK,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
).addCriterion("has_leash_rope_item", InventoryChangeTrigger.TriggerInstance.hasItems(ModItemRegister.LEASH_ROPE_ARROW.get()))
|
||||
.parent(hasLeashRopeItem)
|
||||
.save(saver, ModAdvancementKey.LEASH_ARROW.getNameWithNameSpace());
|
||||
|
||||
AdvancementHolder hasFlashLeashRopeArrow = Advancement.Builder.advancement().display(
|
||||
ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),
|
||||
Component.translatable(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getDescKey()),
|
||||
null,
|
||||
AdvancementType.TASK,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
).addCriterion("has_flash_leash_rope_item", InventoryChangeTrigger.TriggerInstance.hasItems(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get()))
|
||||
.parent(hasLeashRopeArrow)
|
||||
.save(saver, ModAdvancementKey.ADVANCEMENT_LEASH_ARROW.getNameWithNameSpace());
|
||||
|
||||
AdvancementHolder leashedMySelf = Advancement.Builder.advancement().display(
|
||||
Items.PLAYER_HEAD,
|
||||
Component.translatable(ModAdvancementKey.LEASHED_SELF.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.LEASHED_SELF.getDescKey()),
|
||||
null,
|
||||
AdvancementType.TASK,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
).addCriterion("leash_self", LeashPlayerTrigger.TriggerInstance.LeashPlayer(
|
||||
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, EntityType.LEASH_KNOT))
|
||||
))
|
||||
.parent(hasLeashRopeItem).save(saver, ModAdvancementKey.LEASHED_SELF.getNameWithNameSpace());
|
||||
AdvancementHolder followLeashRopeArrow = Advancement.Builder.advancement().display(
|
||||
ModItemRegister.LEASH_ROPE_ARROW.get(),
|
||||
Component.translatable(ModAdvancementKey.FOLLOW_LEASH_ARROW.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.FOLLOW_LEASH_ARROW.getDescKey()),
|
||||
null,
|
||||
AdvancementType.TASK,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
).addCriterion("leash_arrow", LeashPlayerTrigger.TriggerInstance.LeashPlayer(
|
||||
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, ModEntityRegister.LEASH_ROPE_ARROW.get()))
|
||||
))
|
||||
.parent(hasLeashRopeArrow)
|
||||
.save(saver, ModAdvancementKey.FOLLOW_LEASH_ARROW.getNameWithNameSpace());
|
||||
AdvancementHolder dogRunPlayer = Advancement.Builder.advancement().display(
|
||||
Items.BONE,
|
||||
Component.translatable(ModAdvancementKey.DOG_RUNNING_PLAYER.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.DOG_RUNNING_PLAYER.getDescKey()),
|
||||
null,
|
||||
AdvancementType.CHALLENGE,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
).addCriterion("leash_by_wo_do", LeashPlayerTrigger.TriggerInstance.LeashPlayer(
|
||||
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, EntityType.WOLF))
|
||||
))
|
||||
.parent(hasLeashRopeArrow).save(saver, ModAdvancementKey.DOG_RUNNING_PLAYER.getNameWithNameSpace());
|
||||
|
||||
AdvancementHolder leashedOther = Advancement.Builder.advancement().display(
|
||||
Items.LEAD,
|
||||
Component.translatable(ModAdvancementKey.LEASHED_FRIEND.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.LEASHED_FRIEND.getDescKey()),
|
||||
null,
|
||||
AdvancementType.TASK,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
).addCriterion("leash_other_player",
|
||||
LeashPlayerTrigger.TriggerInstance.LeashPlayer(
|
||||
EntityPredicate.Builder.entity().entityType(EntityTypePredicate.of(holdergetter, EntityType.PLAYER))
|
||||
)
|
||||
)
|
||||
.parent(hasLeashRopeItem).save(saver, ModAdvancementKey.LEASHED_FRIEND.getNameWithNameSpace());
|
||||
AdvancementHolder lead_rope_terminator = Advancement.Builder.advancement().display(
|
||||
ModItemRegister.AMETHYST_SHEARS.get(),
|
||||
Component.translatable(ModAdvancementKey.LEASH_TERMINATOR.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.LEASH_TERMINATOR.getDescKey()),
|
||||
null,
|
||||
AdvancementType.TASK,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
).addCriterion("has_amethyst_shears", InventoryChangeTrigger.TriggerInstance.hasItems(ModItemRegister.AMETHYST_SHEARS.get())
|
||||
).parent(hasLeashRopeItem).save(saver, ModAdvancementKey.LEASH_TERMINATOR.getNameWithNameSpace());
|
||||
|
||||
AdvancementHolder no_leash = Advancement.Builder.advancement().display(
|
||||
Items.BARRIER,
|
||||
Component.translatable(ModAdvancementKey.NO_LEASH.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.NO_LEASH.getDescKey()),
|
||||
null,
|
||||
AdvancementType.GOAL,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
).addCriterion("no_leash",
|
||||
EffectsChangedTrigger.TriggerInstance.hasEffects(
|
||||
MobEffectsPredicate.Builder.effects()
|
||||
.and(ModEffectRegister.NO_LEASH_EFFECT)
|
||||
)
|
||||
).parent(hasLeashRopeItem).save(saver, ModAdvancementKey.NO_LEASH.getNameWithNameSpace());
|
||||
AdvancementHolder tipped_leash_arrow = Advancement.Builder.advancement().display(
|
||||
ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get(),
|
||||
Component.translatable(ModAdvancementKey.TIPPED_LEASH_ARROW.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.TIPPED_LEASH_ARROW.getDescKey()),
|
||||
null,
|
||||
AdvancementType.GOAL,
|
||||
true,
|
||||
true,
|
||||
true
|
||||
).addCriterion("has_tipped_leash_arrow", InventoryChangeTrigger.TriggerInstance.hasItems(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get())
|
||||
).parent(hasLeashRopeArrow).save(saver, ModAdvancementKey.TIPPED_LEASH_ARROW.getNameWithNameSpace());
|
||||
AdvancementHolder neo_fox = Advancement.Builder.advancement().display(
|
||||
ModItemRegister.NEOFORGE.get(),
|
||||
Component.translatable(ModAdvancementKey.NEO_FOX.getNameKey()),
|
||||
Component.translatable(ModAdvancementKey.NEO_FOX.getDescKey()),
|
||||
null,
|
||||
AdvancementType.GOAL,
|
||||
true,
|
||||
false,
|
||||
true
|
||||
).addCriterion("has_neo_fox", InventoryChangeTrigger.TriggerInstance.hasItems(ModItemRegister.NEOFORGE.get())
|
||||
).parent(hasLeashRopeItem).save(saver, ModAdvancementKey.NEO_FOX.getNameWithNameSpace());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,21 @@
|
|||
package com.r3944realms.leashedplayer.datagen.generator;
|
||||
|
||||
import net.minecraft.client.data.models.BlockModelGenerators;
|
||||
import net.minecraft.client.data.models.ItemModelOutput;
|
||||
import net.minecraft.client.data.models.blockstates.BlockModelDefinitionGenerator;
|
||||
import net.minecraft.client.data.models.model.ModelInstance;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
public class ModBlockModelGenerator extends BlockModelGenerators {
|
||||
public ModBlockModelGenerator(Consumer<BlockModelDefinitionGenerator> blockStateOutput, ItemModelOutput itemModelOutput, BiConsumer<ResourceLocation, ModelInstance> modelOutput) {
|
||||
super(blockStateOutput, itemModelOutput, modelOutput);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,129 @@
|
|||
package com.r3944realms.leashedplayer.datagen.generator;
|
||||
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.ConditionalRangeItemModel;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.properties.conditional.ChargeExtend;
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange.BowPull;
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModLangKeyValue;
|
||||
import com.r3944realms.leashedplayer.extend.CrossbowItem$ChargeTypeExtend;
|
||||
import net.minecraft.client.data.models.ItemModelGenerators;
|
||||
import net.minecraft.client.data.models.ItemModelOutput;
|
||||
import net.minecraft.client.data.models.model.ItemModelUtils;
|
||||
import net.minecraft.client.data.models.model.ModelInstance;
|
||||
import net.minecraft.client.data.models.model.ModelLocationUtils;
|
||||
import net.minecraft.client.data.models.model.ModelTemplates;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.client.renderer.item.properties.numeric.CrossbowPull;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.function.BiConsumer;
|
||||
|
||||
public class ModItemModelGenerator extends ItemModelGenerators {
|
||||
private static List<Item> objectList;
|
||||
public ModItemModelGenerator(ItemModelOutput itemModelOutput, BiConsumer<ResourceLocation, ModelInstance> modelOutput) {
|
||||
super(itemModelOutput, modelOutput);
|
||||
objectList = new ArrayList<>();
|
||||
init();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void run() {
|
||||
DefaultModItemModelRegister();
|
||||
generateTippedArrow(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get());
|
||||
generateCrossbow(Items.CROSSBOW);
|
||||
generateBow(Items.BOW);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
for(ModLangKeyValue obj : ModLangKeyValue.values()) {
|
||||
if(!obj.isDefaultItem()) continue;
|
||||
objectList.add(obj.getItem());
|
||||
}
|
||||
}
|
||||
/**
|
||||
* @implNote <br/> 先有纹理才会成功构建
|
||||
*/
|
||||
private void DefaultModItemModelRegister() {
|
||||
objectList.forEach(i -> generateFlatItem(i, ModelTemplates.FLAT_ITEM));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void generateBow(@NotNull Item bowItem) {
|
||||
ItemModel.Unbaked itemmodel$unbaked = ItemModelUtils.plainModel(ModelLocationUtils.getModelLocation(bowItem));
|
||||
ItemModel.Unbaked itemmodel$unbaked1 = ItemModelUtils.plainModel(this.createFlatItemModel(bowItem, "_pulling_0", ModelTemplates.BOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked2 = ItemModelUtils.plainModel(this.createFlatItemModel(bowItem, "_pulling_1", ModelTemplates.BOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked3 = ItemModelUtils.plainModel(this.createFlatItemModel(bowItem, "_pulling_2", ModelTemplates.BOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked4 = ItemModelUtils.plainModel(
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.createFlatItemModelByPath(LeashedPlayer.MOD_ID, "item/bow_lra_pulling_0", ModelTemplates.BOW, this.modelOutput)
|
||||
);
|
||||
ItemModel.Unbaked itemmodel$unbaked5 = ItemModelUtils.plainModel(
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.createFlatItemModelByPath(LeashedPlayer.MOD_ID, "item/bow_lra_pulling_1", ModelTemplates.BOW, this.modelOutput)
|
||||
|
||||
);
|
||||
ItemModel.Unbaked itemmodel$unbaked6 = ItemModelUtils.plainModel(
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.createFlatItemModelByPath(LeashedPlayer.MOD_ID, "item/bow_lra_pulling_2", ModelTemplates.BOW, this.modelOutput)
|
||||
);
|
||||
this.itemModelOutput
|
||||
.accept(
|
||||
bowItem,
|
||||
ItemModelUtils.conditional(
|
||||
ItemModelUtils.isUsingItem(),
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.conditionalRange(
|
||||
new BowPull(),
|
||||
0.05F,
|
||||
itemmodel$unbaked1,
|
||||
new ConditionalRangeItemModel.Entry[] {
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.override(itemmodel$unbaked4, 0.0F),
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.override(itemmodel$unbaked5, 0.65F),
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.override(itemmodel$unbaked6, 0.9F)
|
||||
},
|
||||
new ConditionalRangeItemModel.Entry[] {
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.override(itemmodel$unbaked1, 0.0F),
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.override(itemmodel$unbaked2, 0.65F),
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.override(itemmodel$unbaked3, 0.9F)
|
||||
}
|
||||
),
|
||||
itemmodel$unbaked
|
||||
)
|
||||
);
|
||||
}
|
||||
@Override
|
||||
public void generateCrossbow(@NotNull Item crossbowItem) {
|
||||
ItemModel.Unbaked itemmodel$unbaked = ItemModelUtils.plainModel(ModelLocationUtils.getModelLocation(crossbowItem));
|
||||
ItemModel.Unbaked itemmodel$unbaked1 = ItemModelUtils.plainModel(this.createFlatItemModel(crossbowItem, "_pulling_0", ModelTemplates.CROSSBOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked2 = ItemModelUtils.plainModel(this.createFlatItemModel(crossbowItem, "_pulling_1", ModelTemplates.CROSSBOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked3 = ItemModelUtils.plainModel(this.createFlatItemModel(crossbowItem, "_pulling_2", ModelTemplates.CROSSBOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked4 = ItemModelUtils.plainModel(this.createFlatItemModel(crossbowItem, "_arrow", ModelTemplates.CROSSBOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked5 = ItemModelUtils.plainModel(this.createFlatItemModel(crossbowItem, "_firework", ModelTemplates.CROSSBOW));
|
||||
ItemModel.Unbaked itemmodel$unbaked6 = ItemModelUtils.plainModel(
|
||||
com.r3944realms.leashedplayer.utils.dataModel.ItemModelUtils.createFlatItemModelByPath(LeashedPlayer.MOD_ID, "item/crossbow_leash_rope_arrow", ModelTemplates.CROSSBOW, this.modelOutput)
|
||||
);
|
||||
this.itemModelOutput
|
||||
.accept(
|
||||
crossbowItem,
|
||||
ItemModelUtils.conditional(
|
||||
ItemModelUtils.isUsingItem(),
|
||||
ItemModelUtils.rangeSelect(
|
||||
new CrossbowPull(),
|
||||
itemmodel$unbaked1,
|
||||
ItemModelUtils.override(itemmodel$unbaked2, 0.58F),
|
||||
ItemModelUtils.override(itemmodel$unbaked3, 1.0F)
|
||||
),
|
||||
ItemModelUtils.select(
|
||||
new ChargeExtend(),
|
||||
itemmodel$unbaked,
|
||||
ItemModelUtils.when(CrossbowItem$ChargeTypeExtend.ARROW, itemmodel$unbaked4),
|
||||
ItemModelUtils.when(CrossbowItem$ChargeTypeExtend.ROCKET, itemmodel$unbaked5),
|
||||
ItemModelUtils.when(CrossbowItem$ChargeTypeExtend.LEASH_ROPE_ARROW, itemmodel$unbaked6)
|
||||
)
|
||||
)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,22 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import com.r3944realms.leashedplayer.datagen.generator.ModAdvancementGenerator;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.advancements.AdvancementProvider;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ModAdvancementProvider extends AdvancementProvider {
|
||||
/**
|
||||
* Constructs an advancement provider using the generators to write the
|
||||
* advancements to a file.
|
||||
*
|
||||
* @param output the target directory of the data generator
|
||||
* @param registries a future of a lookup for registries and their objects
|
||||
*/
|
||||
public ModAdvancementProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
|
||||
super(output, registries, List.of(new ModAdvancementGenerator()));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.neoforged.neoforge.common.data.BlockTagsProvider;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ModBlockTagProvider extends BlockTagsProvider {
|
||||
public ModBlockTagProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> lookupProvider, String modId) {
|
||||
super(output, lookupProvider, modId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addTags(HolderLookup.@NotNull Provider pProvider) {
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModJukeboxSongs;
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModPaintingVariants;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.core.RegistrySetBuilder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.neoforged.neoforge.common.data.DatapackBuiltinEntriesProvider;
|
||||
|
||||
import java.util.Set;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ModDataPackBuiltInEntriesProvider extends DatapackBuiltinEntriesProvider {
|
||||
public static final RegistrySetBuilder BUILDER = new RegistrySetBuilder()
|
||||
.add(Registries.PAINTING_VARIANT, ModPaintingVariants::bootstrap)
|
||||
.add(Registries.JUKEBOX_SONG, ModJukeboxSongs::bootstrap);
|
||||
public ModDataPackBuiltInEntriesProvider(PackOutput output, CompletableFuture<HolderLookup.Provider> registries) {
|
||||
super(output, registries, BUILDER, Set.of(LeashedPlayer.MOD_ID));
|
||||
CompletableFuture<HolderLookup.Provider> registryProvider = getRegistryProvider();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,43 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModItemTags;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.tags.ItemTagsProvider;
|
||||
import net.minecraft.tags.ItemTags;
|
||||
import net.minecraft.world.item.Items;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.neoforged.neoforge.common.Tags;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ModItemTagProvider extends ItemTagsProvider {
|
||||
|
||||
public ModItemTagProvider(PackOutput pOutput, CompletableFuture<HolderLookup.Provider> pLookupProvider, CompletableFuture<TagLookup<Block>> pBlockTags) {
|
||||
super(pOutput, pLookupProvider, pBlockTags, LeashedPlayer.MOD_ID);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addTags(HolderLookup.@NotNull Provider pProvider) {
|
||||
this.tag(ItemTags.ARROWS)
|
||||
.add(ModItemRegister.LEASH_ROPE_ARROW.get())
|
||||
.add(ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get())
|
||||
.add(ModItemRegister.TIPPED_LEASH_ROPE_ARROW.get());
|
||||
this.tag(ModItemTags.AMETHYST_TOOL_MATERIALS)
|
||||
.add(Items.AMETHYST_SHARD);
|
||||
this.tag(ItemTags.HEAD_ARMOR)
|
||||
.add(ModItemRegister.NEOFORGE.get())
|
||||
.add(Items.LEAD);
|
||||
this.tag(ItemTags.MINING_ENCHANTABLE)
|
||||
.add(ModItemRegister.AMETHYST_SHEARS.get());
|
||||
this.tag(ItemTags.VANISHING_ENCHANTABLE)
|
||||
.add(ModItemRegister.AMETHYST_SHEARS.get());
|
||||
this.tag(ItemTags.DURABILITY_ENCHANTABLE)
|
||||
.add(ModItemRegister.AMETHYST_SHEARS.get());
|
||||
this.tag(Tags.Items.TOOLS_SHEAR)
|
||||
.add(ModItemRegister.AMETHYST_SHEARS.get());
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,40 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModLangKeyValue;
|
||||
import com.r3944realms.leashedplayer.utils.Enum.LanguageEnum;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.neoforged.neoforge.common.data.LanguageProvider;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
import static com.r3944realms.leashedplayer.datagen.LanguageAndOtherData.ModLangKeyValue.getLan;
|
||||
|
||||
|
||||
public class ModLanguageProvider extends LanguageProvider {
|
||||
private final LanguageEnum Language;
|
||||
private final Map<String, String> LanKeyMap;
|
||||
private static final List<String> objects = new ArrayList<>();
|
||||
public ModLanguageProvider(PackOutput output, String modId, LanguageEnum Lan) {
|
||||
super(output, modId, Lan.local);
|
||||
this.Language = Lan;
|
||||
LanKeyMap = new HashMap<>();
|
||||
init();
|
||||
}
|
||||
private void init() {
|
||||
for (ModLangKeyValue key : ModLangKeyValue.values()) {
|
||||
addLang(key.getKey(), getLan(Language, key));
|
||||
}
|
||||
}
|
||||
private void addLang(String Key, String value) {
|
||||
if(!objects.contains(Key)) objects.add(Key);
|
||||
LanKeyMap.put(Key, value);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addTranslations() {
|
||||
objects.forEach(key -> add(key,LanKeyMap.get(key)));
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,189 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import com.google.gson.JsonElement;
|
||||
import com.r3944realms.leashedplayer.datagen.generator.ModBlockModelGenerator;
|
||||
import com.r3944realms.leashedplayer.datagen.generator.ModItemModelGenerator;
|
||||
import net.minecraft.client.data.models.ItemModelOutput;
|
||||
import net.minecraft.client.data.models.ModelProvider;
|
||||
import net.minecraft.client.data.models.blockstates.BlockModelDefinitionGenerator;
|
||||
import net.minecraft.client.data.models.model.ItemModelUtils;
|
||||
import net.minecraft.client.data.models.model.ModelInstance;
|
||||
import net.minecraft.client.data.models.model.ModelLocationUtils;
|
||||
import net.minecraft.client.renderer.block.model.BlockModelDefinition;
|
||||
import net.minecraft.client.renderer.item.ClientItem;
|
||||
import net.minecraft.client.renderer.item.ItemModel;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.data.CachedOutput;
|
||||
import net.minecraft.data.DataProvider;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.item.BlockItem;
|
||||
import net.minecraft.world.item.Item;
|
||||
import net.minecraft.world.level.block.Block;
|
||||
import net.neoforged.api.distmarker.Dist;
|
||||
import net.neoforged.api.distmarker.OnlyIn;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.nio.file.Path;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
import java.util.Objects;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.function.BiConsumer;
|
||||
import java.util.function.Consumer;
|
||||
import java.util.function.Function;
|
||||
import java.util.function.Supplier;
|
||||
import java.util.stream.Stream;
|
||||
/**
|
||||
* 借鉴于 @author baguchi
|
||||
* */
|
||||
public class ModModelDataProvider extends ModelProvider {
|
||||
private final PackOutput.PathProvider blockStatePathProvider;
|
||||
private final PackOutput.PathProvider itemInfoPathProvider;
|
||||
private final PackOutput.PathProvider modelPathProvider;
|
||||
public ModModelDataProvider(PackOutput packOutput, String modId) {
|
||||
super(packOutput, modId);
|
||||
this.blockStatePathProvider = packOutput.createPathProvider(PackOutput.Target.RESOURCE_PACK, "blockstates");
|
||||
this.itemInfoPathProvider = packOutput.createPathProvider(PackOutput.Target.RESOURCE_PACK, "items");
|
||||
this.modelPathProvider = packOutput.createPathProvider(PackOutput.Target.RESOURCE_PACK, "models");
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull CompletableFuture<?> run(@NotNull CachedOutput cachedOutput) {
|
||||
|
||||
ItemInfoCollector itemModelOutput = new ItemInfoCollector(this::getKnownItems);
|
||||
BlockStateGeneratorCollector blockModelOutput = new BlockStateGeneratorCollector(this::getKnownBlocks);
|
||||
SimpleModelCollector modelOutput = new SimpleModelCollector();
|
||||
this.registerModels(new ModBlockModelGenerator(blockModelOutput, itemModelOutput, modelOutput), new ModItemModelGenerator(itemModelOutput, modelOutput));
|
||||
blockModelOutput.validate();
|
||||
itemModelOutput.finalizeAndValidate();
|
||||
return CompletableFuture.allOf(blockModelOutput.save(cachedOutput, this.blockStatePathProvider), modelOutput.save(cachedOutput, this.modelPathProvider), itemModelOutput.save(cachedOutput, this.itemInfoPathProvider));
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
static class ItemInfoCollector implements ItemModelOutput {
|
||||
private final Map<Item, ClientItem> itemInfos;
|
||||
private final Map<Item, Item> copies;
|
||||
private final Supplier<Stream<? extends Holder<Item>>> knownItems;
|
||||
|
||||
public ItemInfoCollector(Supplier<Stream<? extends Holder<Item>>> knownItems) {
|
||||
this.itemInfos = new HashMap<>();
|
||||
this.copies = new HashMap<>();
|
||||
this.knownItems = knownItems;
|
||||
}
|
||||
|
||||
|
||||
public void accept(@NotNull Item item, ItemModel.@NotNull Unbaked model) {
|
||||
this.register(item, new ClientItem(model, ClientItem.Properties.DEFAULT));
|
||||
}
|
||||
|
||||
public void register(@NotNull Item item, @NotNull ClientItem clientItem) {
|
||||
ClientItem clientitem = this.itemInfos.put(item, clientItem);
|
||||
if (clientitem != null) {
|
||||
throw new IllegalStateException("Duplicate item model definition for " + item);
|
||||
}
|
||||
}
|
||||
|
||||
public void copy(@NotNull Item item, @NotNull Item copyItem) {
|
||||
this.copies.put(copyItem, item);
|
||||
}
|
||||
|
||||
public void finalizeAndValidate() {
|
||||
(this.knownItems.get()).map(Holder::value).forEach((item) -> {
|
||||
if (!this.copies.containsKey(item) && item instanceof BlockItem blockitem) {
|
||||
if (!this.itemInfos.containsKey(blockitem)) {
|
||||
ResourceLocation resourcelocation = ModelLocationUtils.getModelLocation(blockitem.getBlock());
|
||||
this.accept(blockitem, ItemModelUtils.plainModel(resourcelocation));
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
this.copies.forEach((item, item1) -> {
|
||||
ClientItem clientitem = this.itemInfos.get(item1);
|
||||
if (clientitem == null) {
|
||||
String item1Name = String.valueOf(item1);
|
||||
throw new IllegalStateException("Missing donor: " + item1Name + " -> " + item);
|
||||
} else {
|
||||
this.register(item, clientitem);
|
||||
}
|
||||
});
|
||||
List<ResourceLocation> list = (this.knownItems.get()).filter((holder) -> !this.itemInfos.containsKey(holder.value())).map((holder) -> holder.unwrapKey().orElseThrow().location()).toList();
|
||||
|
||||
if (!list.isEmpty()) {
|
||||
LOGGER.warn("Missing item model definitions for: {}", list);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<?> save(CachedOutput cachedOutput, PackOutput.PathProvider pathProvider) {
|
||||
return DataProvider.saveAll(cachedOutput, ClientItem.CODEC, (item) -> pathProvider.json(item.builtInRegistryHolder().key().location()), this.itemInfos);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
static class SimpleModelCollector implements BiConsumer<ResourceLocation, ModelInstance> {
|
||||
private final Map<ResourceLocation, ModelInstance> models = new HashMap<>();
|
||||
|
||||
SimpleModelCollector() {
|
||||
}
|
||||
|
||||
public void accept(ResourceLocation resourceLocation, ModelInstance modelInstance) {
|
||||
Supplier<JsonElement> supplier = this.models.put(resourceLocation, modelInstance);
|
||||
if (supplier != null) {
|
||||
throw new IllegalStateException("Duplicate model definition for " + resourceLocation);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<?> save(CachedOutput cachedOutput, PackOutput.PathProvider pathProvider) {
|
||||
Objects.requireNonNull(pathProvider);
|
||||
return saveAll(cachedOutput, pathProvider::json, this.models);
|
||||
}
|
||||
|
||||
static <T> CompletableFuture<?> saveAll(CachedOutput cachedOutput, Function<T, Path> tPathFunction, Map<T, ? extends Supplier<JsonElement>> tMap) {
|
||||
return DataProvider.saveAll(cachedOutput, Supplier::get, tPathFunction, tMap);
|
||||
}
|
||||
}
|
||||
|
||||
@OnlyIn(Dist.CLIENT)
|
||||
static class BlockStateGeneratorCollector implements Consumer<BlockModelDefinitionGenerator> {
|
||||
private final Map<Block, BlockModelDefinitionGenerator> generators = new HashMap<>();
|
||||
private final Supplier<Stream<? extends Holder<Block>>> knownBlocks;
|
||||
|
||||
public BlockStateGeneratorCollector(Supplier<Stream<? extends Holder<Block>>> knownBlocks) {
|
||||
this.knownBlocks = knownBlocks;
|
||||
}
|
||||
|
||||
@Deprecated // Neo: Provided for vanilla/multi-loader compatibility. Use constructor with Supplier parameter.
|
||||
public BlockStateGeneratorCollector() {
|
||||
this(BuiltInRegistries.BLOCK::listElements);
|
||||
}
|
||||
|
||||
public void accept(BlockModelDefinitionGenerator p_405192_) {
|
||||
Block block = p_405192_.block();
|
||||
BlockModelDefinitionGenerator blockmodeldefinitiongenerator = this.generators.put(block, p_405192_);
|
||||
if (blockmodeldefinitiongenerator != null) {
|
||||
throw new IllegalStateException("Duplicate blockstate definition for " + block);
|
||||
}
|
||||
}
|
||||
|
||||
public void validate() {
|
||||
Stream<? extends Holder<Block>> stream = knownBlocks.get();
|
||||
List<ResourceLocation> list = stream.filter(p_386843_ -> !this.generators.containsKey(p_386843_.value()))
|
||||
.map(p_386823_ -> p_386823_.unwrapKey().orElseThrow().location())
|
||||
.toList();
|
||||
if (!list.isEmpty()) {
|
||||
throw new IllegalStateException("Missing blockstate definitions for: " + list);
|
||||
}
|
||||
}
|
||||
|
||||
public CompletableFuture<?> save(CachedOutput output, PackOutput.PathProvider pathProvider) {
|
||||
Map<Block, BlockModelDefinition> map = Maps.transformValues(this.generators, BlockModelDefinitionGenerator::create);
|
||||
Function<Block, Path> function = p_387598_ -> pathProvider.json(p_387598_.builtInRegistryHolder().key().location());
|
||||
return DataProvider.saveAll(output, BlockModelDefinition.CODEC, function, map);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModPaintingVariants;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.tags.PaintingVariantTagsProvider;
|
||||
import net.minecraft.tags.PaintingVariantTags;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ModPaintingVariantTagsProvider extends PaintingVariantTagsProvider {
|
||||
public ModPaintingVariantTagsProvider(PackOutput pOutput, CompletableFuture<HolderLookup.Provider> pProvider, String modId) {
|
||||
super(pOutput, pProvider, modId);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void addTags(HolderLookup.@NotNull Provider pProvider) {
|
||||
this.tag(PaintingVariantTags.PLACEABLE)
|
||||
.add(ModPaintingVariants.GROUP_PHOTO);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,72 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.items.ModItemRegister;
|
||||
import com.r3944realms.leashedplayer.content.items.repcipe.TippedLeashRopeArrowRecipe;
|
||||
import net.minecraft.core.HolderLookup;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.minecraft.data.recipes.RecipeCategory;
|
||||
import net.minecraft.data.recipes.RecipeOutput;
|
||||
import net.minecraft.data.recipes.RecipeProvider;
|
||||
import net.minecraft.data.recipes.SpecialRecipeBuilder;
|
||||
import net.minecraft.world.item.Items;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class ModRecipeProvider extends RecipeProvider {
|
||||
public ModRecipeProvider(HolderLookup.Provider registries, RecipeOutput output) {
|
||||
super(registries, output);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void buildRecipes() {
|
||||
this.shapeless(RecipeCategory.MISC, ModItemRegister.LEASH_ROPE_ARROW.get(), 1)
|
||||
.requires(Items.LEAD)
|
||||
.requires(Items.ARROW)
|
||||
.unlockedBy("has_lead",has(Items.LEAD))
|
||||
.save(this.output);
|
||||
this.shapeless(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
|
||||
.requires(Items.LEAD)
|
||||
.requires(Items.SPECTRAL_ARROW)
|
||||
.unlockedBy("has_lead",has(Items.LEAD))
|
||||
.unlockedBy("has_spectral_arrow",has(Items.SPECTRAL_ARROW))
|
||||
.save(this.output);
|
||||
this.shaped(RecipeCategory.MISC, ModItemRegister.SPECTRAL_LEASH_ROPE_ARROW.get(),1)
|
||||
.pattern(" $ ")
|
||||
.pattern("$#$")
|
||||
.pattern(" $ ")
|
||||
.define('#', ModItemRegister.LEASH_ROPE_ARROW.get())
|
||||
.define('$', Items.GLOWSTONE_DUST)
|
||||
.unlockedBy("has_lead",has(Items.LEAD))
|
||||
.unlockedBy("has_glowstone_dust",has(Items.GLOWSTONE_DUST))
|
||||
.save(this.output,"leash_rope_arrow_shape");
|
||||
this.shaped(RecipeCategory.MISC, ModItemRegister.AMETHYST_SHEARS.get(),1)
|
||||
.pattern("#%")
|
||||
.pattern("%#")
|
||||
.define('#', Items.AMETHYST_SHARD)
|
||||
.define('%', Items.STICK)
|
||||
.unlockedBy("has_amethyst_shard",has(Items.AMETHYST_SHARD))
|
||||
.save(this.output);
|
||||
SpecialRecipeBuilder.special(TippedLeashRopeArrowRecipe.TippedLeashRopeArrowARecipe::new).save(this.output, "tipped_leash_rope_arrow_a");
|
||||
SpecialRecipeBuilder.special(TippedLeashRopeArrowRecipe.TippedLeashRopeArrowBRecipe::new).save(this.output, "tipped_leash_rope_arrow_b");
|
||||
}
|
||||
public static class Runner extends RecipeProvider.Runner {
|
||||
|
||||
public Runner(PackOutput pPackOutput, CompletableFuture<HolderLookup.Provider> providerCompletableFuture) {
|
||||
super(pPackOutput, providerCompletableFuture);
|
||||
}
|
||||
|
||||
@Override
|
||||
@NotNull
|
||||
public RecipeProvider createRecipeProvider(HolderLookup.@NotNull Provider provider, @NotNull RecipeOutput output) {
|
||||
return new ModRecipeProvider(provider, output);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getName() {
|
||||
return "LeashedPlayer Recipes";
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider;
|
||||
|
||||
|
||||
import com.r3944realms.leashedplayer.content.sounds.ModSoundRegister;
|
||||
import net.minecraft.data.PackOutput;
|
||||
import net.neoforged.neoforge.common.data.SoundDefinition;
|
||||
import net.neoforged.neoforge.common.data.SoundDefinitionsProvider;
|
||||
|
||||
public class ModSoundDefinitionsProvider extends SoundDefinitionsProvider {
|
||||
/**
|
||||
* Creates a new instance of this data provider.
|
||||
*
|
||||
* @param output The {@linkplain PackOutput} instance provided by the data generator.
|
||||
* @param modId The mod ID of the current mod.
|
||||
*/
|
||||
public ModSoundDefinitionsProvider(PackOutput output, String modId) {
|
||||
super(output, modId);
|
||||
}
|
||||
|
||||
public SoundDefinition getSoundDefinition(String subTitle, SoundDefinition.Sound... sounds) {
|
||||
return SoundDefinition.definition().subtitle(subTitle).with(sounds);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerSounds() {
|
||||
add(
|
||||
ModSoundRegister.FOX_MUSIC,
|
||||
getSoundDefinition(
|
||||
ModSoundRegister.getSubTitleTranslateKey("what_does_the_fox_say"),
|
||||
sound(ModSoundRegister.RL_FOX_MUSIC, SoundDefinition.SoundType.SOUND)
|
||||
)
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider.attributes;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.sounds.ModSoundRegister;
|
||||
import net.minecraft.Util;
|
||||
import net.minecraft.core.Holder;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.worldgen.BootstrapContext;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.sounds.SoundEvent;
|
||||
import net.minecraft.world.item.JukeboxSong;
|
||||
|
||||
public class ModJukeboxSongs {
|
||||
public static ResourceKey<JukeboxSong> FOX_MUSIC = create("what_does_the_fox_say");
|
||||
|
||||
public static void bootstrap(BootstrapContext<JukeboxSong> pContext) {
|
||||
JukeboxSongBootstrap(pContext);
|
||||
}
|
||||
|
||||
public static void JukeboxSongBootstrap(BootstrapContext<JukeboxSong> pContext) {
|
||||
register(pContext, FOX_MUSIC, ModSoundRegister.FOX_MUSIC, 121, 15);
|
||||
|
||||
}
|
||||
|
||||
private static void register(
|
||||
BootstrapContext<JukeboxSong> pContext, ResourceKey<JukeboxSong> pKey, Holder<SoundEvent> pSoundEvent, int pLengthInSeconds, int pComparatorOutput
|
||||
) {
|
||||
pContext.register(
|
||||
pKey,
|
||||
new JukeboxSong(pSoundEvent, Component.translatable(Util.makeDescriptionId("jukebox_song", pKey.location())), (float)pLengthInSeconds, pComparatorOutput)
|
||||
);
|
||||
}
|
||||
private static ResourceKey<JukeboxSong> create(String pName) {
|
||||
return ResourceKey.create(Registries.JUKEBOX_SONG, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, pName));
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.r3944realms.leashedplayer.datagen.provider.attributes;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.core.registries.Registries;
|
||||
import net.minecraft.data.worldgen.BootstrapContext;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.resources.ResourceKey;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.decoration.PaintingVariant;
|
||||
|
||||
import java.util.Optional;
|
||||
|
||||
public class ModPaintingVariants {
|
||||
public static final ResourceKey<PaintingVariant> GROUP_PHOTO = create("group_photo");
|
||||
|
||||
public static void bootstrap(BootstrapContext<PaintingVariant> pContext) {
|
||||
PaintingVariantBootstrap(pContext);
|
||||
}
|
||||
public static void PaintingVariantBootstrap(BootstrapContext<PaintingVariant> pContext) {
|
||||
ModPaintingVariants.register(pContext, ModPaintingVariants.GROUP_PHOTO, 4, 3, Component.translatable(ModPaintingVariants.getPaintingVariantTitleKey(ModPaintingVariants.GROUP_PHOTO)), Component.translatable(ModPaintingVariants.getPaintingVariantAuthorKey(ModPaintingVariants.GROUP_PHOTO)));
|
||||
}
|
||||
private static void register(BootstrapContext<PaintingVariant> pContext, ResourceKey<PaintingVariant> pKey, int pWidth, int pHeight, Component title, Component author) {
|
||||
pContext.register(pKey, new PaintingVariant(pWidth, pHeight, pKey.location(), Optional.of(title), Optional.of(author)));
|
||||
}
|
||||
|
||||
private static ResourceKey<PaintingVariant> create(String pName) {
|
||||
return ResourceKey.create(Registries.PAINTING_VARIANT, ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID, pName));
|
||||
}
|
||||
|
||||
public static String getPaintingVariantTitleKey(ResourceKey<PaintingVariant> pKey) {
|
||||
return "painting." + pKey.location().getNamespace() + "." + pKey.location().getPath() + ".title";
|
||||
}
|
||||
|
||||
public static String getPaintingVariantAuthorKey(ResourceKey<PaintingVariant> pKey) {
|
||||
return "painting." + pKey.location().getNamespace() + "." + pKey.location().getPath() + ".author";
|
||||
}
|
||||
|
||||
public static String getPaintingVariantTitleKey(String pName) {
|
||||
return "painting." + LeashedPlayer.MOD_ID + "." + pName + ".title";
|
||||
}
|
||||
|
||||
public static String getPaintingVariantAuthorKey(String pName) {
|
||||
return "painting." + LeashedPlayer.MOD_ID + "." + pName + ".author";
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,25 @@
|
|||
package com.r3944realms.leashedplayer.extend;
|
||||
|
||||
import com.mojang.serialization.Codec;
|
||||
import net.minecraft.util.StringRepresentable;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public enum CrossbowItem$ChargeTypeExtend implements StringRepresentable {
|
||||
NONE("none"),
|
||||
ARROW("arrow"),
|
||||
ROCKET("rocket"),
|
||||
LEASH_ROPE_ARROW("leash_rope_arrow"),
|
||||
;
|
||||
|
||||
public static final Codec<CrossbowItem$ChargeTypeExtend> CODEC = StringRepresentable.fromEnum(CrossbowItem$ChargeTypeExtend::values);
|
||||
private final String name;
|
||||
|
||||
CrossbowItem$ChargeTypeExtend(String name) {
|
||||
this.name = name;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NotNull String getSerializedName() {
|
||||
return this.name;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,53 @@
|
|||
package com.r3944realms.leashedplayer.mixin;
|
||||
|
||||
import org.objectweb.asm.tree.ClassNode;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin;
|
||||
import org.spongepowered.asm.mixin.extensibility.IMixinInfo;
|
||||
|
||||
import java.util.List;
|
||||
import java.util.Set;
|
||||
|
||||
public class MixinPlugin implements IMixinConfigPlugin {
|
||||
@Override
|
||||
public void onLoad(String mixinPackage) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getRefMapperConfig() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean shouldApplyMixin(String targetClassName, String mixinClassName) {
|
||||
// 检查当前是否在数据生成阶段
|
||||
// 根据需要添加逻辑来控制特定Mixin类的应用
|
||||
boolean isRegister = mixinClassName.split("com\\.r3944realms\\.leashedplayer\\.mixin\\.")[1].split("\\.")[0].equals("registry");
|
||||
if (isRegister) {
|
||||
return isDataGeneration();
|
||||
}
|
||||
return true; // 其他Mixin类默认应用
|
||||
}
|
||||
|
||||
private boolean isDataGeneration() {
|
||||
// 使用你的逻辑来检查是否在数据生成阶段
|
||||
String environment = System.getProperty("gradle.task");
|
||||
return "runData".equals(environment);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void acceptTargets(Set<String> myTargets, Set<String> otherTargets) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getMixins() {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) {
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
package com.r3944realms.leashedplayer.mixin.both;
|
||||
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Redirect;
|
||||
|
||||
@Mixin(Entity.class)
|
||||
public abstract class MixinEntity {
|
||||
@Shadow public abstract void igniteForSeconds(float pSeconds);
|
||||
|
||||
@Shadow public abstract Level level();
|
||||
|
||||
/**
|
||||
* 这里重定向,当实体类实现了{@link PlayerLeashable}接口时,<br/>
|
||||
* 阻止原版的{@link Leashable}中 的tickLeash方法调用,将其<br/>
|
||||
* 我们需自己实现相关的逻辑
|
||||
* @param entity 实体
|
||||
* @param <E> 实体类型
|
||||
*/
|
||||
@Redirect(
|
||||
method = "baseTick",
|
||||
at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/Leashable;tickLeash(Lnet/minecraft/server/level/ServerLevel;Lnet/minecraft/world/entity/Entity;)V")
|
||||
)
|
||||
<E extends Entity & Leashable> void checkAndCancelIfTure(ServerLevel f, E entity) {
|
||||
if(!(entity instanceof PlayerLeashable) && level() instanceof ServerLevel serverLevel_) {
|
||||
Leashable.tickLeash(serverLevel_, entity);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,48 @@
|
|||
package com.r3944realms.leashedplayer.mixin.both;
|
||||
|
||||
import net.minecraft.util.Mth;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.level.Level;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
//OpenJDK21 JIT 激进的优化将TickHeadTurnAssign优化成死循环了
|
||||
|
||||
/**
|
||||
* 保证 while 循环的条件永远不成立的
|
||||
* @author ustc-zzzz
|
||||
*/
|
||||
@Mixin(LivingEntity.class)
|
||||
public abstract class MixinLivingEntity extends Entity {
|
||||
@Shadow
|
||||
public float yBodyRot;
|
||||
@Shadow
|
||||
public float yBodyRotO;
|
||||
|
||||
@Shadow
|
||||
public float yHeadRot;
|
||||
@Shadow
|
||||
public float yHeadRotO;
|
||||
|
||||
public MixinLivingEntity(EntityType<?> type, Level level) {
|
||||
super(type, level);
|
||||
}
|
||||
|
||||
@Inject(
|
||||
method = "tick()V",
|
||||
at = @At(value = "INVOKE_ASSIGN", target = "Lnet/minecraft/world/entity/LivingEntity;tickHeadTurn(F)V")
|
||||
)
|
||||
public void onTickHeadTurnAssign(CallbackInfo ignored) {
|
||||
var yRot = this.getYRot();
|
||||
this.yRotO = yRot - Mth.wrapDegrees(yRot - this.yRotO);
|
||||
this.yBodyRotO = this.yBodyRot - Mth.wrapDegrees(this.yBodyRot - this.yBodyRotO);
|
||||
var xRot = this.getXRot();
|
||||
this.xRotO = xRot - Mth.wrapDegrees(xRot - this.xRotO);
|
||||
this.yHeadRotO = this.yHeadRot - Mth.wrapDegrees(this.yHeadRot - this.yHeadRotO);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,326 @@
|
|||
package com.r3944realms.leashedplayer.mixin.both;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
|
||||
import com.r3944realms.leashedplayer.content.entities.LeashRopeArrow;
|
||||
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import com.r3944realms.leashedplayer.utils.Logger;
|
||||
import net.minecraft.nbt.CompoundTag;
|
||||
import net.minecraft.network.syncher.EntityDataAccessor;
|
||||
import net.minecraft.network.syncher.EntityDataSerializers;
|
||||
import net.minecraft.network.syncher.SynchedEntityData;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.LivingEntity;
|
||||
import net.minecraft.world.entity.ai.attributes.Attributes;
|
||||
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
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 javax.annotation.Nullable;
|
||||
import java.util.Objects;
|
||||
import java.util.function.Consumer;
|
||||
|
||||
@Mixin(Player.class)
|
||||
public abstract class MixinPlayer extends LivingEntity implements PlayerLeashable, ILivingEntityExtension {
|
||||
|
||||
@Unique
|
||||
protected int Pl$LeashKeepTick;//保存状态,当超过断裂绳长时若LeashKeepTick大于0,则不断裂
|
||||
|
||||
@Unique
|
||||
@Nullable
|
||||
private LeashData Pl$LeashData;//Data
|
||||
|
||||
@SuppressWarnings("WrongEntityDataParameterClass")
|
||||
@Unique//客户端与服务器端的实体同步数据
|
||||
private static final EntityDataAccessor<CompoundTag> Pl$LEASH_DATA = SynchedEntityData.defineId(Player.class, EntityDataSerializers.COMPOUND_TAG);
|
||||
|
||||
@Unique
|
||||
@SuppressWarnings("WrongEntityDataParameterClass")
|
||||
private static final EntityDataAccessor<Float> DATA_ENTITY_LEASH_LENGTH = SynchedEntityData.defineId(Player.class, EntityDataSerializers.FLOAT);
|
||||
|
||||
@SuppressWarnings("AddedMixinMembersNamePattern")
|
||||
@Override
|
||||
public float getLeashLength() {
|
||||
return this.entityData.get(DATA_ENTITY_LEASH_LENGTH);
|
||||
}
|
||||
@SuppressWarnings("AddedMixinMembersNamePattern")
|
||||
@Override
|
||||
public void setLeashLength(float length) {
|
||||
this.entityData.set(DATA_ENTITY_LEASH_LENGTH, length);
|
||||
}
|
||||
|
||||
@SuppressWarnings("AddedMixinMembersNamePattern")
|
||||
@Override
|
||||
public void setKeepLeashTick(int keepTick) {
|
||||
this.Pl$LeashKeepTick = Math.max(keepTick, 0);
|
||||
}
|
||||
@SuppressWarnings("AddedMixinMembersNamePattern")
|
||||
@Override
|
||||
public int getKeepLeashTick() {
|
||||
return this.Pl$LeashKeepTick;
|
||||
}
|
||||
|
||||
|
||||
protected MixinPlayer(EntityType<? extends LivingEntity> pEntityType, Level pLevel) {
|
||||
super(pEntityType, pLevel);
|
||||
}
|
||||
|
||||
@Inject(method = {"tick"}, at = {@At("HEAD")})
|
||||
private void tickForLeash(CallbackInfo ci) {
|
||||
if(!this.level().isClientSide) {
|
||||
Pl$tickLeash();//服务器端每tick任务
|
||||
}
|
||||
PlayerLeashable playerLeashable = this;
|
||||
Entity leashHolder = playerLeashable.getLeashHolder();
|
||||
if(leashHolder != null ) {
|
||||
//存在则更新
|
||||
Pl$UpdateLeash(leashHolder, (Entity) playerLeashable);
|
||||
try {
|
||||
Objects.requireNonNull(this.getAttribute(Attributes.STEP_HEIGHT)).setBaseValue(1.25f);
|
||||
} catch (Exception e) {
|
||||
Logger.logger.error(e.getMessage());
|
||||
}
|
||||
} else {
|
||||
try {
|
||||
Objects.requireNonNull(this.getAttribute(Attributes.STEP_HEIGHT)).setBaseValue(0.6f);
|
||||
} catch (Exception e) {
|
||||
Logger.logger.error(e.getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
@Unique
|
||||
private static void Pl$UpdateLeash(Entity holderEntity, Entity restrainedEntity) {
|
||||
if (holderEntity == null || holderEntity.level() != restrainedEntity.level()) {
|
||||
return;
|
||||
}
|
||||
|
||||
float leashLength = LeashCommand.MIN_VALUE;
|
||||
if (restrainedEntity instanceof ILivingEntityExtension iEntity) {
|
||||
// 获取绳长
|
||||
float leashLengthFormValue = iEntity.getLeashLength();
|
||||
leashLength = leashLengthFormValue > LeashCommand.MIN_VALUE ? leashLengthFormValue : LeashCommand.MIN_VALUE;
|
||||
}
|
||||
|
||||
// 两者距离
|
||||
float distance = holderEntity.distanceTo(restrainedEntity);
|
||||
Entity applyMovementEntity = restrainedEntity.isPassenger() ? restrainedEntity.getVehicle() : restrainedEntity;
|
||||
|
||||
// 仅当距离大于绳长时施加拉力
|
||||
if (applyMovementEntity != null && distance > leashLength) {
|
||||
// 计算朝向持有者的拉力方向
|
||||
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
|
||||
double dY = (holderEntity.getY() - applyMovementEntity.getY()) / (double) distance;
|
||||
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
|
||||
|
||||
// 拉力大小,距离越远拉力越强,但施加一个最大限制
|
||||
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
|
||||
applyMovementEntity.setDeltaMovement(
|
||||
applyMovementEntity.getDeltaMovement().add(
|
||||
dX * pullStrength,
|
||||
dY * pullStrength,
|
||||
dZ * pullStrength
|
||||
)
|
||||
);
|
||||
|
||||
// 控制速度不要过快,避免偏激移动
|
||||
Whimsy$Brake(applyMovementEntity, entity -> {
|
||||
Vec3 deltaMovement = entity.getDeltaMovement();
|
||||
entity.setDeltaMovement(
|
||||
Math.min(Math.abs(deltaMovement.x), 1.0) * Math.signum(deltaMovement.x),
|
||||
Math.min(Math.abs(deltaMovement.y), 1.0) * Math.signum(deltaMovement.y),
|
||||
Math.min(Math.abs(deltaMovement.z), 1.0) * Math.signum(deltaMovement.z)
|
||||
);
|
||||
entity.hurtMarked = true;
|
||||
});
|
||||
}
|
||||
|
||||
// 降低坠落伤害
|
||||
restrainedEntity.checkSlowFallDistance();
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* 刹车(
|
||||
* @param pEntity 刹车的实体
|
||||
* @param pMaxX X方向的最大动量
|
||||
* @param pMaxY Y方向的最大动量
|
||||
* @param pMaxZ Z方向的最大动量
|
||||
*/
|
||||
@Unique
|
||||
private static void Whimsy$Brake(Entity pEntity, double pMaxX, double pMaxY, double pMaxZ) {
|
||||
Vec3 deltaMovement = pEntity.getDeltaMovement();
|
||||
double dX = Math.abs(deltaMovement.x) > pMaxX ? 0 : deltaMovement.x;
|
||||
double dY = Math.abs(deltaMovement.y) > pMaxY ? 0 : deltaMovement.y;
|
||||
double dZ = Math.abs(deltaMovement.z) > pMaxZ ? 0 : deltaMovement.z;
|
||||
pEntity.setDeltaMovement(dX, dY,dZ);
|
||||
pEntity.hurtMarked = true;
|
||||
}
|
||||
/**
|
||||
* 刹车(
|
||||
* @param pEntity 刹车的实体
|
||||
* @param pOpt 自定义规则
|
||||
*/
|
||||
@Unique
|
||||
private static void Whimsy$Brake(Entity pEntity, @Nullable Consumer<Entity> pOpt) {
|
||||
Consumer<Entity> consumer = pOpt;
|
||||
if(pOpt == null) {
|
||||
consumer = entity -> {
|
||||
Vec3 deltaMovement = entity.getDeltaMovement();
|
||||
double dX = Math.abs(deltaMovement.x) > 1 ? 0 : deltaMovement.x;
|
||||
double dY = Math.abs(deltaMovement.y) > 1 ? 0 : deltaMovement.y;
|
||||
double dZ = Math.abs(deltaMovement.z) > 1 ? 0 : deltaMovement.z;
|
||||
entity.setDeltaMovement(dX, dY,dZ);
|
||||
entity.hurtMarked = true;
|
||||
};
|
||||
}
|
||||
consumer.accept(pEntity);
|
||||
}
|
||||
@Unique
|
||||
protected void Pl$tickLeash() {
|
||||
if(this.Pl$LeashData == null) return;//没有Data直接退出
|
||||
ILivingEntityExtension self = this;
|
||||
int keepLeashTick = self.getKeepLeashTick();
|
||||
|
||||
//info -> Holder整理
|
||||
Pl$RestoreLeashFormSave();
|
||||
//默认值设为
|
||||
float leashLength = LeashCommand.MIN_VALUE;
|
||||
Entity entity = this.Pl$LeashData.leashHolder;
|
||||
//保存数据
|
||||
saveLeashData(Pl$LeashData);
|
||||
ILivingEntityExtension iEntityExtension = this;//获取设定值
|
||||
float leashLengthSelf = iEntityExtension.getLeashLength();
|
||||
leashLength = leashLengthSelf > LeashCommand.MIN_VALUE ? leashLengthSelf : LeashCommand.MIN_VALUE;
|
||||
if (entity != null) {
|
||||
double breakDistanceTime = (entity instanceof LeashRopeArrow) ? LeashedPlayer.M1() * LeashedPlayer.M2() : LeashedPlayer.M1();
|
||||
if(!isAlive() || !entity.isAlive() ||( distanceTo(entity) > Math.max(leashLength * breakDistanceTime, LeashCommand.MIN_VALUE * breakDistanceTime) && keepLeashTick == 0)){
|
||||
//玩家死亡 或 持有者不存在 或 距离大于设定值的 breakDistanceTime 倍且keepTick <=0(长度的 breakDistanceTime 倍若低于 LeashCommand.MIN_VALUE 格,则选 LeashCommand.MIN_VALUE 格) ,
|
||||
// 则取消拴绳关系,并掉落拴绳
|
||||
boolean shouldDrop = !(entity instanceof LeashRopeArrow);
|
||||
Leashable.dropLeash((Entity & Leashable) this, true, shouldDrop);
|
||||
} else if(distanceTo(entity) > leashLength * 0.65f * breakDistanceTime && entity.onGround()) {
|
||||
//大于eashLength * 0.65f * breakDistanceTime 倍绳长且在地面则会让其跳跃(在<1.25格阻拦情况下,跳跃阻拦//TODO:待擴展
|
||||
Entity applyMovementEntity = this.isPassenger() ? this.getVehicle() : this;
|
||||
if(applyMovementEntity instanceof LivingEntity applyMovementLivingEntity) {
|
||||
applyMovementLivingEntity.jumpFromGround();
|
||||
}
|
||||
}
|
||||
}
|
||||
if(keepLeashTick > 0) {//keepTick--
|
||||
self.setKeepLeashTick(keepLeashTick - 1);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Entity getLeashHolder() {
|
||||
if (Pl$LeashData == null) return null;
|
||||
if (Pl$LeashData.leashHolder == null && Pl$LeashData.delayedLeashHolderId != 0 ) {
|
||||
Pl$LeashData.leashHolder = this.level().getEntity(Pl$LeashData.delayedLeashHolderId);
|
||||
}
|
||||
return Pl$LeashData.leashHolder;
|
||||
}
|
||||
|
||||
/**
|
||||
* 数据整理 -> 如果Pl$LeashData非null,最终Pl$LeashData的leashHolder将不为null
|
||||
*/
|
||||
@Unique
|
||||
private void Pl$RestoreLeashFormSave() {
|
||||
assert this.Pl$LeashData != null;
|
||||
if(!(this.level() instanceof ServerLevel)) {
|
||||
//非服务器端退出
|
||||
return;
|
||||
}
|
||||
|
||||
if(this.Pl$LeashData.delayedLeashInfo == null) {
|
||||
//delayedLeashInfo无数据
|
||||
if(Pl$LeashData.leashHolder != null) {//且LeashHolder不为null,则直接用它
|
||||
setLeashedTo(Pl$LeashData.leashHolder, true);
|
||||
return;
|
||||
}
|
||||
return;
|
||||
|
||||
}
|
||||
if(this.Pl$LeashData.delayedLeashInfo.left().isPresent()) {
|
||||
//如果有实体的UUID(一般是LivingEntity),则在服务器其通过UUID来查找实体
|
||||
Entity entity = ((ServerLevel) this.level()).getEntity(this.Pl$LeashData.delayedLeashInfo.left().get());
|
||||
if(entity != null) {
|
||||
setLeashedTo(entity, true);
|
||||
}
|
||||
} else if(this.Pl$LeashData.delayedLeashInfo.right().isPresent()) {
|
||||
//如果有实体的坐标(一般就是拴绳结),在服务器端获取拴绳结实体(通过给定坐标和维度获取)
|
||||
setLeashedTo(LeashFenceKnotEntity.getOrCreateKnot(this.level(), this.Pl$LeashData.delayedLeashInfo.right().get()), true);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@org.jetbrains.annotations.Nullable
|
||||
@Override
|
||||
public LeashData getLeashData() {
|
||||
return Pl$LeashData;
|
||||
}
|
||||
@SuppressWarnings("AddedMixinMembersNamePattern")
|
||||
@Override
|
||||
@Nullable
|
||||
public LeashData getLeashDataFromEntityData() {
|
||||
CompoundTag compoundTag = this.entityData.get(Pl$LEASH_DATA);
|
||||
return compoundTag.read("Pl$LeashData", Leashable.LeashData.CODEC).orElse(null);
|
||||
}
|
||||
@Override
|
||||
public void setLeashData(@org.jetbrains.annotations.Nullable Leashable.LeashData pLeashData) {
|
||||
this.Pl$LeashData = pLeashData;
|
||||
saveLeashData(pLeashData);
|
||||
}
|
||||
@SuppressWarnings("AddedMixinMembersNamePattern")
|
||||
@Unique
|
||||
private void saveLeashData(@org.jetbrains.annotations.Nullable LeashData pLeashData) {
|
||||
CompoundTag compoundTag = new CompoundTag();
|
||||
this.writeLeashData(compoundTag, pLeashData);
|
||||
|
||||
this.entityData.set(Pl$LEASH_DATA, compoundTag);
|
||||
}
|
||||
@SuppressWarnings("AddedMixinMembersNamePattern")
|
||||
@Override
|
||||
public boolean canBeLeashedInstantly(Player player) {
|
||||
return !isLeashed();
|
||||
}
|
||||
@Inject(
|
||||
method = {"defineSynchedData"}, at = {@At("TAIL")}
|
||||
)
|
||||
//定义Client/Server player 同步数据
|
||||
private void defineSyncData (SynchedEntityData.Builder pBuilder, CallbackInfo ci) {
|
||||
CompoundTag leashCompoundTag = new CompoundTag();
|
||||
this.writeLeashData(leashCompoundTag, null);
|
||||
pBuilder.define(Pl$LEASH_DATA, leashCompoundTag);
|
||||
pBuilder.define(DATA_ENTITY_LEASH_LENGTH, 5.0F);
|
||||
}
|
||||
@Inject(
|
||||
method = {"addAdditionalSaveData"}, at = {@At("RETURN")}
|
||||
)//数据保存
|
||||
private void addSaveData(CompoundTag pCompound, CallbackInfo ci) {
|
||||
CompoundTag pLeashTag = new CompoundTag();
|
||||
writeLeashData(pLeashTag, Pl$LeashData);
|
||||
pCompound.put("Pl$LeashData", pLeashTag);
|
||||
this.entityData.set(Pl$LEASH_DATA, pLeashTag);
|
||||
pCompound.putFloat("LeashLength", getLeashLength());
|
||||
}
|
||||
@Inject(
|
||||
method = {"readAdditionalSaveData"}, at = {@At("RETURN")}
|
||||
)//数据读取
|
||||
private void readSaveData(CompoundTag pCompound, CallbackInfo ci) {
|
||||
Leashable.LeashData leashable$leashdata = pCompound.read("Pl$LeashData", Leashable.LeashData.CODEC).orElse(null);
|
||||
if (this.getLeashData() != null && leashable$leashdata == null) {
|
||||
this.removeLeash();
|
||||
}
|
||||
this.setLeashData(leashable$leashdata);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,20 @@
|
|||
package com.r3944realms.leashedplayer.mixin.client;
|
||||
|
||||
import com.r3944realms.leashedplayer.client.renderer.item.properties.conditionalRange.ConditionalRangeItemModelProperties;
|
||||
import net.minecraft.client.ClientBootstrap;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(ClientBootstrap.class)
|
||||
public class MixinClientBootstrap {
|
||||
@Inject(method = "bootstrap", at = @At(
|
||||
value = "INVOKE",
|
||||
target = "Lnet/minecraft/client/renderer/item/properties/numeric/RangeSelectItemModelProperties;bootstrap()V",
|
||||
shift = At.Shift.AFTER)
|
||||
)
|
||||
private static void bootstrap(CallbackInfo ci) {
|
||||
ConditionalRangeItemModelProperties.bootstrap();
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,45 @@
|
|||
package com.r3944realms.leashedplayer.mixin.client;
|
||||
|
||||
import com.mojang.blaze3d.resource.GraphicsResourceAllocator;
|
||||
import com.mojang.blaze3d.vertex.PoseStack;
|
||||
import com.r3944realms.leashedplayer.client.renderer.LeashRendererUtil;
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.client.DeltaTracker;
|
||||
import net.minecraft.client.multiplayer.ClientLevel;
|
||||
import net.minecraft.client.renderer.GameRenderer;
|
||||
import net.minecraft.client.renderer.LevelRenderer;
|
||||
import net.minecraft.client.renderer.MultiBufferSource;
|
||||
import net.minecraft.client.renderer.RenderBuffers;
|
||||
import org.joml.Matrix4f;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
|
||||
|
||||
@Mixin(LevelRenderer.class)
|
||||
public abstract class MixinLevelRenderer {
|
||||
@Shadow
|
||||
@Nullable
|
||||
private ClientLevel level;
|
||||
|
||||
@Shadow @Final private RenderBuffers renderBuffers;
|
||||
|
||||
@Inject(
|
||||
method = {"renderLevel"},
|
||||
at = @At(value = "HEAD")
|
||||
)
|
||||
private void renderLevel(GraphicsResourceAllocator graphicsResourceAllocator, DeltaTracker deltaTracker, boolean renderBlockOutline, Camera camera, GameRenderer gameRenderer, Matrix4f frustumMatrix, Matrix4f projectionMatrix, CallbackInfo ci) {
|
||||
assert this.level != null;
|
||||
PoseStack poseStack = new PoseStack();
|
||||
MultiBufferSource.BufferSource multibuffersource$buffersource = this.renderBuffers.bufferSource();
|
||||
LeashRendererUtil.levelRenderLeash(level, camera, poseStack, multibuffersource$buffersource);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
|
|
@ -0,0 +1,39 @@
|
|||
package com.r3944realms.leashedplayer.mixin.client;
|
||||
|
||||
import com.r3944realms.leashedplayer.client.renderer.PlayerLeashState;
|
||||
import com.r3944realms.leashedplayer.client.renderer.PlayerSlotItemLayerState;
|
||||
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
|
||||
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
|
||||
@SuppressWarnings({"AddedMixinMembersNamePattern"})
|
||||
@Mixin(PlayerRenderState.class)
|
||||
public class MixinPlayerRenderState implements IPlayerRenderStateExtension {
|
||||
@Unique
|
||||
@Nullable
|
||||
private PlayerLeashState playerLeashState;
|
||||
@Unique
|
||||
private PlayerSlotItemLayerState playerSlotItemLayerState;
|
||||
@Override
|
||||
public @Nullable PlayerLeashState getPlayerLeashState() {
|
||||
return playerLeashState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerLeashState(@Nullable PlayerLeashState playerRenderState) {
|
||||
this.playerLeashState = playerRenderState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlayerSlotItemLayerState getPlayerSlotItemLayerState() {
|
||||
return playerSlotItemLayerState;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void setPlayerSlotItemLayerState(PlayerSlotItemLayerState playerRenderState) {
|
||||
this.playerSlotItemLayerState = playerRenderState;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,30 @@
|
|||
package com.r3944realms.leashedplayer.mixin.client;
|
||||
|
||||
import com.r3944realms.leashedplayer.client.renderer.LeashRendererUtil;
|
||||
import com.r3944realms.leashedplayer.client.renderer.PlayerSlotItemLayerState;
|
||||
import com.r3944realms.leashedplayer.modInterface.IPlayerRenderStateExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.IPlayerRendererExtension;
|
||||
import net.minecraft.client.model.PlayerModel;
|
||||
import net.minecraft.client.player.AbstractClientPlayer;
|
||||
import net.minecraft.client.renderer.entity.EntityRendererProvider;
|
||||
import net.minecraft.client.renderer.entity.LivingEntityRenderer;
|
||||
import net.minecraft.client.renderer.entity.player.PlayerRenderer;
|
||||
import net.minecraft.client.renderer.entity.state.PlayerRenderState;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PlayerRenderer.class)
|
||||
public abstract class MixinPlayerRenderer extends LivingEntityRenderer<AbstractClientPlayer, PlayerRenderState, PlayerModel> implements IPlayerRendererExtension {
|
||||
public MixinPlayerRenderer(EntityRendererProvider.Context pContext, PlayerModel pModel, float pShadowRadius) {
|
||||
super(pContext, pModel, pShadowRadius);
|
||||
}
|
||||
@Inject(method = {"extractRenderState(Lnet/minecraft/client/player/AbstractClientPlayer;Lnet/minecraft/client/renderer/entity/state/PlayerRenderState;F)V"}, at = @At("TAIL"))
|
||||
public void extractRenderState(AbstractClientPlayer abstractClientPlayer, PlayerRenderState playerRenderState, float partTicks, CallbackInfo ci) {
|
||||
LeashRendererUtil.createPlayerLeashState(abstractClientPlayer, (IPlayerRenderStateExtension) playerRenderState, partTicks);
|
||||
((IPlayerRenderStateExtension)playerRenderState).setPlayerSlotItemLayerState(new PlayerSlotItemLayerState(abstractClientPlayer));
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,16 @@
|
|||
package com.r3944realms.leashedplayer.mixin.item;
|
||||
|
||||
import net.minecraft.world.inventory.ArmorSlot;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
@Mixin(ArmorSlot.class)
|
||||
public class MixinArmorSlotMixin {
|
||||
@Inject(method = "mayPlace", at = @At("RETURN"), cancellable = true)
|
||||
public void allowItemEquipping(ItemStack stack, CallbackInfoReturnable<Boolean> cir) {
|
||||
cir.setReturnValue(true);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,57 @@
|
|||
package com.r3944realms.leashedplayer.mixin.item;
|
||||
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.item.ItemStack;
|
||||
import net.minecraft.world.item.LeadItem;
|
||||
import net.minecraft.world.level.Level;
|
||||
import net.minecraft.world.level.gameevent.GameEvent;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
@Mixin(LeadItem.class)
|
||||
public class MixinLeadItem {
|
||||
/**
|
||||
* 拴住自己的逻辑
|
||||
*/
|
||||
@Inject(
|
||||
method = {"bindPlayerMobs"},
|
||||
at = @At("HEAD"),
|
||||
cancellable = true)
|
||||
private static void selfLeash(Player pPlayer, Level pLevel, BlockPos pPos, CallbackInfoReturnable<InteractionResult> cir) {
|
||||
List<Leashable> list = LeadItem.leashableInArea(pLevel, pPos, p_353025_ -> p_353025_.getLeashHolder() == pPlayer);
|
||||
if (list.isEmpty()) {
|
||||
ItemStack mainHandItem = pPlayer.getMainHandItem();
|
||||
if (!(mainHandItem.getItem() instanceof LeadItem )) {
|
||||
return;
|
||||
}
|
||||
//非创造模式减少,防止刷物品
|
||||
if(!pPlayer.isCreative()) mainHandItem.shrink(1);
|
||||
//自己
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) pPlayer, (ServerLevel) pLevel);
|
||||
PlayerLeashable playerLeashable = (PlayerLeashable) pPlayer;
|
||||
if(leashDataEntity != null) {
|
||||
Leashable.dropLeash((Entity & Leashable) playerLeashable, true, true);
|
||||
}
|
||||
//获取拴绳结实体
|
||||
LeashFenceKnotEntity leashfenceknotentity = LeashFenceKnotEntity.getOrCreateKnot(pLevel, pPos);
|
||||
//播放绳结被放置的声音
|
||||
leashfenceknotentity.playPlacementSound();
|
||||
//将自己与拴绳结绑定LeashData
|
||||
playerLeashable.setLeashedTo(leashfenceknotentity, true);
|
||||
pLevel.gameEvent(GameEvent.BLOCK_ATTACH, pPos, GameEvent.Context.of(pPlayer));
|
||||
cir.setReturnValue(InteractionResult.SUCCESS);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,18 @@
|
|||
package com.r3944realms.leashedplayer.mixin.registry;
|
||||
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModJukeboxSongs;
|
||||
import net.minecraft.data.worldgen.BootstrapContext;
|
||||
import net.minecraft.world.item.JukeboxSong;
|
||||
import net.minecraft.world.item.JukeboxSongs;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(JukeboxSongs.class)
|
||||
public interface MixinJukeboxSongs {
|
||||
@Inject(method = {"bootstrap"}, at = @At("TAIL"))
|
||||
private static void bootstrap(BootstrapContext<JukeboxSong> pContext, CallbackInfo ci) {
|
||||
ModJukeboxSongs.JukeboxSongBootstrap(pContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,19 @@
|
|||
package com.r3944realms.leashedplayer.mixin.registry;
|
||||
|
||||
|
||||
import com.r3944realms.leashedplayer.datagen.provider.attributes.ModPaintingVariants;
|
||||
import net.minecraft.data.worldgen.BootstrapContext;
|
||||
import net.minecraft.world.entity.decoration.PaintingVariant;
|
||||
import net.minecraft.world.entity.decoration.PaintingVariants;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
|
||||
@Mixin(PaintingVariants.class)
|
||||
public class MixinPaintingVariants {
|
||||
@Inject(method = {"bootstrap"}, at = @At("TAIL"))
|
||||
private static void bootstrap(BootstrapContext<PaintingVariant> pContext , CallbackInfo ci) {
|
||||
ModPaintingVariants.PaintingVariantBootstrap(pContext);
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,60 @@
|
|||
package com.r3944realms.leashedplayer.mixin.server;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.gamerules.GameruleRegistry;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.Server.TeleportWithLeashedPlayers;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.server.network.ServerGamePacketListenerImpl;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.PositionMoveRotation;
|
||||
import net.minecraft.world.entity.Relative;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.Unique;
|
||||
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.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.r3944realms.leashedplayer.utils.Logger.logger;
|
||||
@Mixin(ServerGamePacketListenerImpl.class)
|
||||
public class MixinServerGamePacketListenerImpl {
|
||||
|
||||
@Shadow
|
||||
public ServerPlayer player;
|
||||
@Unique
|
||||
private List<Entity> Pl$LeashPlayers = new ArrayList<>();
|
||||
@Inject(method = {"teleport(Lnet/minecraft/world/entity/PositionMoveRotation;Ljava/util/Set;)V"}, at = {@At("HEAD")})
|
||||
private void teleportHead(PositionMoveRotation positionMoveRotation, Set<Relative> pRelativeSet, CallbackInfo ci) {
|
||||
try {
|
||||
//獲取Holder
|
||||
this.Pl$LeashPlayers = ((PlayerLeashable)this.player).getLeashHolder() != null ? Collections.emptyList() : Objects.requireNonNull(this.player.getServer()).getPlayerList().getPlayers().stream().filter(serverPlayer -> (serverPlayer instanceof PlayerLeashable) && ((PlayerLeashable)serverPlayer).getLeashHolder() == this.player && player != serverPlayer).collect(Collectors.toList());
|
||||
} catch (Exception e) {
|
||||
logger.error("Internal Error:",e);
|
||||
}
|
||||
}
|
||||
@Inject(method = {"teleport(Lnet/minecraft/world/entity/PositionMoveRotation;Ljava/util/Set;)V"}, at = {@At("TAIL")})
|
||||
private void teleportTail(PositionMoveRotation moveRotation, Set<Relative> pRelativeSet, CallbackInfo ci) {
|
||||
if(GameruleRegistry.getGameruleBoolValue(this.player.serverLevel(), TeleportWithLeashedPlayers.ID)) {
|
||||
for (Entity Pl$LeashPlayer : this.Pl$LeashPlayers) {
|
||||
if(Pl$LeashPlayer instanceof ServerPlayer) {
|
||||
if(Pl$LeashPlayer instanceof PlayerLeashable playerLeashable) {
|
||||
Leashable.dropLeash((Entity & Leashable) playerLeashable, false,false);
|
||||
if(((ServerPlayer) playerLeashable).serverLevel() == this.player.serverLevel()) {
|
||||
((ServerPlayer) playerLeashable).connection.teleport(moveRotation, pRelativeSet);
|
||||
} else {
|
||||
Vec3 vec3 = moveRotation.deltaMovement();
|
||||
((ServerPlayer) playerLeashable).teleportTo(this.player.serverLevel(), vec3.x, vec3.y, vec3.z, pRelativeSet, moveRotation.yRot(), moveRotation.yRot(),false);
|
||||
((ServerPlayer) playerLeashable).stopRiding();
|
||||
}
|
||||
playerLeashable.setLeashedTo(this.player, true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,28 @@
|
|||
package com.r3944realms.leashedplayer.modInterface;
|
||||
|
||||
public interface ILivingEntityExtension {
|
||||
/**
|
||||
* 获取拴绳的长度
|
||||
* @return length 拴绳的长度(Float)
|
||||
*/
|
||||
float getLeashLength();
|
||||
|
||||
/**
|
||||
* 设置拴绳的长度
|
||||
* @param length 拴绳的长度(Float)
|
||||
*/
|
||||
void setLeashLength(float length);
|
||||
|
||||
/**
|
||||
* 设置超出断裂长度后等待时间,如果时间到仍超出则会执行断裂操作
|
||||
* @apiNote 该为服务器方法,只能在服务器端调用,切勿在客户端线程调用
|
||||
* @param keepTick 等待tick(int)
|
||||
*/
|
||||
void setKeepLeashTick(int keepTick);
|
||||
/**
|
||||
* 获取超出断裂长度后等待时间,如果时间到仍超出则会执行断裂操作
|
||||
* @apiNote 该为服务器方法,只能在服务器端调用,切勿在客户端线程调用
|
||||
* @return keepTick 等待tick(int)
|
||||
*/
|
||||
int getKeepLeashTick();
|
||||
}
|
||||
|
|
@ -0,0 +1,11 @@
|
|||
package com.r3944realms.leashedplayer.modInterface;
|
||||
|
||||
import com.r3944realms.leashedplayer.client.renderer.PlayerLeashState;
|
||||
import com.r3944realms.leashedplayer.client.renderer.PlayerSlotItemLayerState;
|
||||
|
||||
public interface IPlayerRenderStateExtension {
|
||||
PlayerLeashState getPlayerLeashState();
|
||||
void setPlayerLeashState(PlayerLeashState playerRenderState);
|
||||
PlayerSlotItemLayerState getPlayerSlotItemLayerState();
|
||||
void setPlayerSlotItemLayerState(PlayerSlotItemLayerState playerRenderState);
|
||||
}
|
||||
|
|
@ -0,0 +1,24 @@
|
|||
package com.r3944realms.leashedplayer.modInterface;
|
||||
|
||||
import net.minecraft.client.Camera;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
|
||||
public interface IPlayerRendererExtension {
|
||||
default <E extends net. minecraft. world. entity. Entity> void renderLeashForCamera(
|
||||
Camera pCamera,
|
||||
float pPartialTick,
|
||||
com.mojang.blaze3d.vertex.PoseStack pPoseStack,
|
||||
net.minecraft.client.renderer.MultiBufferSource pBufferSource,
|
||||
E pLeashHolder
|
||||
) {
|
||||
renderLeashForCamera(pCamera, pPartialTick, pPoseStack, pBufferSource, pLeashHolder, Vec3.ZERO);
|
||||
}
|
||||
<E extends net. minecraft. world. entity. Entity> void renderLeashForCamera(
|
||||
Camera pCamera,
|
||||
float pPartialTick,
|
||||
com.mojang.blaze3d.vertex.PoseStack pPoseStack,
|
||||
net.minecraft.client.renderer.MultiBufferSource pBufferSource,
|
||||
E pLeashHolder,
|
||||
Vec3 holderOffset
|
||||
);
|
||||
}
|
||||
|
|
@ -0,0 +1,225 @@
|
|||
package com.r3944realms.leashedplayer.modInterface;
|
||||
|
||||
import com.r3944realms.leashedplayer.content.commands.LeashCommand;
|
||||
import com.r3944realms.leashedplayer.content.criteriaTriggers.ModCriteriaTriggers;
|
||||
import com.r3944realms.leashedplayer.utils.Util;
|
||||
import net.minecraft.core.BlockPos;
|
||||
import net.minecraft.network.protocol.game.ClientboundSetEntityLinkPacket;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.Leashable;
|
||||
import net.minecraft.world.entity.decoration.LeashFenceKnotEntity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.annotation.Nullable;
|
||||
import java.util.Optional;
|
||||
import java.util.UUID;
|
||||
|
||||
public interface PlayerLeashable extends Leashable {
|
||||
|
||||
/**
|
||||
* 获取拴绳的持有者实体 可能不存在
|
||||
*/
|
||||
@Nullable
|
||||
Entity getLeashHolder();
|
||||
|
||||
/**
|
||||
* 获取拴绳的持有者数据 (从EntityData中获取
|
||||
*/
|
||||
LeashData getLeashDataFromEntityData();
|
||||
|
||||
/**
|
||||
* 是否立即可被拴住
|
||||
*/
|
||||
boolean canBeLeashedInstantly(Player player);
|
||||
|
||||
/**
|
||||
* 设置栓绳数据
|
||||
* @param pLeashHolder 拴绳持有者
|
||||
* @param pBroadcastPacket 是否广播包
|
||||
*/
|
||||
default void setLeashedTo(@NotNull Entity pLeashHolder, boolean pBroadcastPacket) {
|
||||
setLeashedTo((Entity & Leashable)this, pLeashHolder, pBroadcastPacket);
|
||||
if(this instanceof ServerPlayer) {
|
||||
ModCriteriaTriggers.LEASH_PLAYER_TRIGGER.get().trigger((ServerPlayer) this, pLeashHolder);
|
||||
}
|
||||
}
|
||||
static <E extends Entity & Leashable> void setLeashedTo(E pEntity, Entity pLeashHolder, boolean pBroadcastPacket) {
|
||||
LeashData leashable$leashdata = pEntity.getLeashData();
|
||||
if (leashable$leashdata == null) {
|
||||
leashable$leashdata = new LeashData(pLeashHolder);
|
||||
pEntity.setLeashData(leashable$leashdata);
|
||||
} else {
|
||||
leashable$leashdata.setLeashHolder(pLeashHolder);
|
||||
}
|
||||
|
||||
if (pBroadcastPacket && pEntity.level() instanceof ServerLevel serverlevel) {
|
||||
serverlevel.getChunkSource().broadcast(pEntity, new ClientboundSetEntityLinkPacket(pEntity, pLeashHolder));
|
||||
}
|
||||
//这边覆写去掉了乘坐相关的逻辑,即乘坐状态下也可以正常被栓住,不影响其乘坐状态
|
||||
|
||||
}
|
||||
static void legacyElasticRangeLeashBehaviour(Entity holderEntity, Entity restrainedEntity) {
|
||||
float leashLength = LeashCommand.MIN_VALUE;
|
||||
if (restrainedEntity instanceof ILivingEntityExtension iEntity) {
|
||||
// 获取绳长
|
||||
float leashLengthFormValue = iEntity.getLeashLength();
|
||||
leashLength = leashLengthFormValue > LeashCommand.MIN_VALUE ? leashLengthFormValue : LeashCommand.MIN_VALUE;
|
||||
}
|
||||
|
||||
// 两者距离
|
||||
float distance = holderEntity.distanceTo(restrainedEntity);
|
||||
Entity applyMovementEntity = restrainedEntity.isPassenger() ? restrainedEntity.getVehicle() : restrainedEntity;
|
||||
// 仅当距离大于绳长时施加拉力
|
||||
if (applyMovementEntity != null && distance > leashLength) {
|
||||
MethodA(holderEntity, applyMovementEntity, distance, leashLength);
|
||||
// 控制速度不要过快,避免偏激移动
|
||||
Util.MovementBrake(applyMovementEntity, entity -> {
|
||||
Vec3 deltaMovement = entity.getDeltaMovement();
|
||||
entity.setDeltaMovement(
|
||||
Math.min(Math.abs(deltaMovement.x), 1.0) * Math.signum(deltaMovement.x),
|
||||
Math.min(Math.abs(deltaMovement.y), 1.0) * Math.signum(deltaMovement.y),
|
||||
Math.min(Math.abs(deltaMovement.z), 1.0) * Math.signum(deltaMovement.z)
|
||||
);
|
||||
entity.hurtMarked = true;
|
||||
});
|
||||
}
|
||||
}
|
||||
private static void MethodA(Entity holderEntity, Entity applyMovementEntity, float distance, float leashLength) {
|
||||
// 计算朝向持有者的拉力方向
|
||||
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
|
||||
double dY = (holderEntity.getY() - applyMovementEntity.getY()) / (double) distance;
|
||||
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
|
||||
|
||||
// 拉力大小,距离越远拉力越强,但施加一个最大限制
|
||||
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
|
||||
applyMovementEntity.setDeltaMovement(
|
||||
applyMovementEntity.getDeltaMovement().add(
|
||||
dX * pullStrength,
|
||||
dY * pullStrength,
|
||||
dZ * pullStrength
|
||||
)
|
||||
);
|
||||
}
|
||||
private static void MethodB(Entity holderEntity, Entity applyMovementEntity, float distance, float leashLength) {
|
||||
// 计算朝向持有者的拉力方向
|
||||
double dX = (holderEntity.getX() - applyMovementEntity.getX()) / (double) distance;
|
||||
double dZ = (holderEntity.getZ() - applyMovementEntity.getZ()) / (double) distance;
|
||||
|
||||
// 稳定点的目标高度
|
||||
double targetY = holderEntity.getY() + 1.0; // 根据需要调整目标高度
|
||||
double currentY = applyMovementEntity.getY();
|
||||
double heightDifference = targetY - currentY;
|
||||
|
||||
// 控制垂直方向的拉力
|
||||
double dY = heightDifference > 0.5 ? 0.1 : (heightDifference < -0.5 ? -0.1 : 0);
|
||||
|
||||
// 拉力大小,距离越远拉力越强,但施加一个最大限制
|
||||
double pullStrength = Math.min((distance - leashLength) * 0.1, 1.0); // 限制最大拉力
|
||||
applyMovementEntity.setDeltaMovement(
|
||||
applyMovementEntity.getDeltaMovement().add(
|
||||
dX * pullStrength,
|
||||
dY,
|
||||
dZ * pullStrength
|
||||
)
|
||||
);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Entity getLeashDataEntity(@NotNull ServerPlayer serverPlayer , @NotNull ServerLevel serverLevel) {
|
||||
LeashData leashDataFromEntityData = ((PlayerLeashable) serverPlayer).getLeashDataFromEntityData();
|
||||
if (leashDataFromEntityData != null) {
|
||||
return getLeashDataEntity(leashDataFromEntityData, serverLevel);
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
|
||||
static Entity getLeashDataEntityOrThrown(@NotNull ServerPlayer serverPlayer ,@NotNull ServerLevel serverLevel) throws Exception {
|
||||
Entity leashedEntity = getLeashDataEntity(serverPlayer, serverLevel);
|
||||
if(leashedEntity == null) throw new Exception("invalid");
|
||||
else return leashedEntity;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
static Entity getLeashDataEntity(@NotNull Leashable.LeashData leashDataFromEntityData, @NotNull ServerLevel level) {
|
||||
if(leashDataFromEntityData.delayedLeashInfo != null) {
|
||||
Optional<UUID> UUID = leashDataFromEntityData.delayedLeashInfo.left();
|
||||
Optional<BlockPos> BlockPos = leashDataFromEntityData.delayedLeashInfo.right();
|
||||
if (UUID.isPresent()) {
|
||||
return level.getEntity(UUID.get());
|
||||
} else return BlockPos.map(pos -> LeashFenceKnotEntity.getOrCreateKnot(level, pos)).orElse(null);
|
||||
}
|
||||
else if(leashDataFromEntityData.leashHolder != null) {
|
||||
return leashDataFromEntityData.leashHolder;
|
||||
}
|
||||
else if(leashDataFromEntityData.delayedLeashHolderId != 0) {
|
||||
return level.getEntity(leashDataFromEntityData.delayedLeashHolderId);
|
||||
}
|
||||
else return null;
|
||||
}
|
||||
|
||||
static Entity getLeashDataEntityOrThrown(@NotNull Leashable.LeashData leashDataFromEntityData, @NotNull ServerLevel level) throws Exception {
|
||||
if(leashDataFromEntityData.delayedLeashInfo != null) {
|
||||
Optional<UUID> UUID = leashDataFromEntityData.delayedLeashInfo.left();
|
||||
Optional<BlockPos> BlockPos = leashDataFromEntityData.delayedLeashInfo.right();
|
||||
if (UUID.isPresent()) {
|
||||
return level.getEntity(UUID.get());
|
||||
} else if(BlockPos.isPresent()) {
|
||||
return LeashFenceKnotEntity.getOrCreateKnot(level, BlockPos.get());
|
||||
} else {
|
||||
throw new Exception("invalid delayedLeashInfo");
|
||||
}
|
||||
}
|
||||
else if(leashDataFromEntityData.leashHolder != null) {
|
||||
return leashDataFromEntityData.leashHolder;
|
||||
}
|
||||
else if(leashDataFromEntityData.delayedLeashHolderId != 0) {
|
||||
Entity entity = level.getEntity(leashDataFromEntityData.delayedLeashHolderId);
|
||||
if(entity == null) {
|
||||
throw new Exception("Not found Entity. maybe the pId is invalid");
|
||||
}
|
||||
return entity;
|
||||
}
|
||||
else {
|
||||
throw new Exception("invalid leash data");
|
||||
}
|
||||
}
|
||||
static boolean isLeashFenceKnotEntityExisted(ServerLevel pLevel, BlockPos pPos) {
|
||||
int i = pPos.getX();
|
||||
int j = pPos.getY();
|
||||
int k = pPos.getZ();
|
||||
|
||||
for (LeashFenceKnotEntity leashfenceknotentity : pLevel.getEntitiesOfClass(
|
||||
LeashFenceKnotEntity.class, new AABB((double)i - 1.0, (double)j - 1.0, (double)k - 1.0, (double)i + 1.0, (double)j + 1.0, (double)k + 1.0)
|
||||
)) {
|
||||
if (leashfenceknotentity.getPos().equals(pPos)) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
@Nullable
|
||||
static Entity getLeashFenceKnotEntity(ServerLevel pLevel, BlockPos pPos) {
|
||||
int i = pPos.getX();
|
||||
int j = pPos.getY();
|
||||
int k = pPos.getZ();
|
||||
|
||||
for (LeashFenceKnotEntity leashfenceknotentity : pLevel.getEntitiesOfClass(
|
||||
LeashFenceKnotEntity.class, new AABB((double)i - 1.0, (double)j - 1.0, (double)k - 1.0, (double)i + 1.0, (double)j + 1.0, (double)k + 1.0)
|
||||
)) {
|
||||
if (leashfenceknotentity.getPos().equals(pPos)) {
|
||||
return leashfenceknotentity;
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
static Entity createLeashKnotFence(ServerLevel pLevel, BlockPos pPos) {
|
||||
LeashFenceKnotEntity leashfenceknotentity = new LeashFenceKnotEntity(pLevel, pPos);
|
||||
pLevel.addFreshEntity(leashfenceknotentity);
|
||||
return leashfenceknotentity;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,35 @@
|
|||
package com.r3944realms.leashedplayer.network;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.network.client.UpdatePlayerMovement;
|
||||
import com.r3944realms.leashedplayer.network.server.DecreaseLeashRopeLength;
|
||||
import com.r3944realms.leashedplayer.network.server.IncreaseLeashRopeLength;
|
||||
import net.neoforged.bus.api.SubscribeEvent;
|
||||
import net.neoforged.fml.common.EventBusSubscriber;
|
||||
import net.neoforged.neoforge.network.event.RegisterPayloadHandlersEvent;
|
||||
import net.neoforged.neoforge.network.registration.PayloadRegistrar;
|
||||
|
||||
@EventBusSubscriber(modid = LeashedPlayer.MOD_ID, bus = EventBusSubscriber.Bus.MOD)
|
||||
public class LeashedPlayerNetwork {
|
||||
|
||||
@SubscribeEvent
|
||||
public static void registerPackets(RegisterPayloadHandlersEvent event) {
|
||||
PayloadRegistrar registrar = event.registrar(LeashedPlayer.MOD_ID);
|
||||
registrar.playToClient(
|
||||
UpdatePlayerMovement.TYPE,
|
||||
UpdatePlayerMovement.STREAM_CODEC,
|
||||
UpdatePlayerMovement::handle
|
||||
);
|
||||
registrar.playToServer(
|
||||
IncreaseLeashRopeLength.TYPE,
|
||||
IncreaseLeashRopeLength.STREAM_CODEC,
|
||||
IncreaseLeashRopeLength::handle
|
||||
);
|
||||
registrar.playToServer(
|
||||
DecreaseLeashRopeLength.TYPE,
|
||||
DecreaseLeashRopeLength.STREAM_CODEC,
|
||||
DecreaseLeashRopeLength::handle
|
||||
);
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,31 @@
|
|||
package com.r3944realms.leashedplayer.network.client;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.content.gamerules.GameRules;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public record BooleanGameRuleValueChangeData(String gamerule_id, boolean value) implements IGameRuleValueChangeData {
|
||||
public static Type<BooleanGameRuleValueChangeData> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID,"bool_gamerule_value_change"));
|
||||
public static final StreamCodec<FriendlyByteBuf, BooleanGameRuleValueChangeData> STREAM_CODEC =
|
||||
StreamCodec.composite(
|
||||
ByteBufCodecs.STRING_UTF8, BooleanGameRuleValueChangeData::gamerule_id,
|
||||
ByteBufCodecs.BOOL, BooleanGameRuleValueChangeData::value,
|
||||
BooleanGameRuleValueChangeData::new
|
||||
);
|
||||
|
||||
public void handle(IPayloadContext context) {
|
||||
context.enqueueWork(() -> {
|
||||
GameRules.gamerulesBooleanValuesClient.put(gamerule_id, value);
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public @NotNull Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
|
|
@ -0,0 +1,10 @@
|
|||
package com.r3944realms.leashedplayer.network.client;
|
||||
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public interface IGameRuleValueChangeData extends CustomPacketPayload {
|
||||
@Override
|
||||
@NotNull
|
||||
Type<? extends CustomPacketPayload> type();
|
||||
}
|
||||
|
|
@ -0,0 +1,55 @@
|
|||
package com.r3944realms.leashedplayer.network.client;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
/**
|
||||
* @author qyl27
|
||||
* @param operation
|
||||
* @param x
|
||||
* @param y
|
||||
* @param z
|
||||
*/
|
||||
public record UpdatePlayerMovement(Operation operation, double x, double y, double z) implements CustomPacketPayload {
|
||||
public static final Type<UpdatePlayerMovement> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID,"update_player_movement"));
|
||||
@Override
|
||||
public @NotNull Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
public static final StreamCodec<FriendlyByteBuf, UpdatePlayerMovement> STREAM_CODEC =
|
||||
StreamCodec.composite(
|
||||
NeoForgeStreamCodecs.enumCodec(Operation.class), UpdatePlayerMovement::operation,
|
||||
ByteBufCodecs.DOUBLE, UpdatePlayerMovement::x,
|
||||
ByteBufCodecs.DOUBLE, UpdatePlayerMovement::y,
|
||||
ByteBufCodecs.DOUBLE, UpdatePlayerMovement::z,
|
||||
UpdatePlayerMovement::new
|
||||
);
|
||||
public void handle(IPayloadContext context) {
|
||||
context.enqueueWork(() -> {
|
||||
Player player = context.player();
|
||||
switch (operation) {
|
||||
case ADD -> player.addDeltaMovement(new Vec3(x, y, z));
|
||||
case SET -> player.setDeltaMovement(new Vec3(x, y, z));
|
||||
case MULTIPLY -> player.addDeltaMovement(player.getDeltaMovement().multiply(x, y, z));
|
||||
}
|
||||
}
|
||||
|
||||
);
|
||||
}
|
||||
public enum Operation {
|
||||
SET,
|
||||
ADD,
|
||||
MULTIPLY
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
|
@ -0,0 +1,8 @@
|
|||
package com.r3944realms.leashedplayer.network.server;
|
||||
|
||||
public enum Code {
|
||||
OTHER_ST,
|
||||
OTHER_WE,
|
||||
SELF;
|
||||
public static final String LEASH_LENGTH_FAILED_SET = "leashedplayer.leash_rope.length.failed";
|
||||
}
|
||||
|
|
@ -0,0 +1,61 @@
|
|||
package com.r3944realms.leashedplayer.network.server;
|
||||
|
||||
import com.r3944realms.leashedplayer.LeashedPlayer;
|
||||
import com.r3944realms.leashedplayer.modInterface.ILivingEntityExtension;
|
||||
import com.r3944realms.leashedplayer.modInterface.PlayerLeashable;
|
||||
import net.minecraft.network.FriendlyByteBuf;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.network.codec.ByteBufCodecs;
|
||||
import net.minecraft.network.codec.StreamCodec;
|
||||
import net.minecraft.network.protocol.common.custom.CustomPacketPayload;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.player.Player;
|
||||
import net.neoforged.neoforge.network.codec.NeoForgeStreamCodecs;
|
||||
import net.neoforged.neoforge.network.handling.IPayloadContext;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public record DecreaseLeashRopeLength(Code code, String playerUUID) implements CustomPacketPayload {
|
||||
public static final Type<DecreaseLeashRopeLength> TYPE = new Type<>(ResourceLocation.fromNamespaceAndPath(LeashedPlayer.MOD_ID,"sub_leash_rope_length"));
|
||||
public static final StreamCodec<FriendlyByteBuf, DecreaseLeashRopeLength> STREAM_CODEC =
|
||||
StreamCodec.composite(
|
||||
NeoForgeStreamCodecs.enumCodec(Code.class), DecreaseLeashRopeLength::code,
|
||||
ByteBufCodecs.STRING_UTF8, DecreaseLeashRopeLength::playerUUID,
|
||||
DecreaseLeashRopeLength::new
|
||||
);
|
||||
public static final String DECREASE_LEASH_ROPE_LENGTH = "leashedplayer.leash_rope.length.decrease",
|
||||
DECREASE_SELF_LEASH_ROPE_LENGTH = DECREASE_LEASH_ROPE_LENGTH + ".self";
|
||||
|
||||
public void handle(IPayloadContext context) {
|
||||
context.enqueueWork(() -> {
|
||||
Player player = context.player();
|
||||
ServerLevel level = (ServerLevel) player.level();
|
||||
Player playerByUUID = level.getPlayerByUUID(UUID.fromString(playerUUID));
|
||||
if (playerByUUID != null) {
|
||||
ILivingEntityExtension entityExtension = (ILivingEntityExtension) playerByUUID;
|
||||
Entity leashDataEntity = PlayerLeashable.getLeashDataEntity((ServerPlayer) playerByUUID, level);
|
||||
if ((leashDataEntity != null && code == Code.OTHER_ST && leashDataEntity == player ) || (leashDataEntity != null && code == Code.OTHER_ST)) {
|
||||
float newValue = Math.max(Math.min(entityExtension.getLeashLength() - 1, LeashedPlayer.M4()), LeashedPlayer.M3());
|
||||
entityExtension.setLeashLength(newValue);
|
||||
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(DECREASE_SELF_LEASH_ROPE_LENGTH, newValue), true);
|
||||
((ServerPlayer) player).sendSystemMessage(Component.translatable(DECREASE_LEASH_ROPE_LENGTH, playerByUUID.getDisplayName(), newValue), true);
|
||||
} else if (code == Code.SELF) {
|
||||
float newValue = Math.max(Math.min(entityExtension.getLeashLength() - 1, LeashedPlayer.M4()), LeashedPlayer.M3());
|
||||
entityExtension.setLeashLength(newValue);
|
||||
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(DECREASE_SELF_LEASH_ROPE_LENGTH, newValue), true);
|
||||
} else {
|
||||
((ServerPlayer) playerByUUID).sendSystemMessage(Component.translatable(Code.LEASH_LENGTH_FAILED_SET), true);
|
||||
((ServerPlayer) player).sendSystemMessage(Component.translatable(Code.LEASH_LENGTH_FAILED_SET), true);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
@Override
|
||||
public @NotNull Type<? extends CustomPacketPayload> type() {
|
||||
return TYPE;
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user