Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Starbies on shoulders #1151

Draft
wants to merge 12 commits into
base: 1.20
Choose a base branch
from
5 changes: 5 additions & 0 deletions src/main/java/com/hollingsworth/arsnouveau/ArsNouveau.java
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package com.hollingsworth.arsnouveau;

import com.hollingsworth.arsnouveau.api.ArsNouveauAPI;
import com.hollingsworth.arsnouveau.api.registry.CasterTomeRegistry;
import com.hollingsworth.arsnouveau.api.registry.RitualRegistry;
import com.hollingsworth.arsnouveau.api.ritual.DispenserRitualBehavior;
Expand Down Expand Up @@ -44,6 +45,7 @@
import net.minecraftforge.fml.event.lifecycle.InterModEnqueueEvent;
import net.minecraftforge.fml.javafmlmod.FMLJavaModLoadingContext;

import java.util.List;


@Mod(ArsNouveau.MODID)
Expand Down Expand Up @@ -127,6 +129,9 @@ public void postModLoadEvent(final FMLLoadCompleteEvent event) {
DispenserBlock.registerBehavior(tablet, new DispenserRitualBehavior());
}

ArsNouveauAPI.shoulderRiders.addAll(List.of("ars_nouveau:starbuncle",
"ars_nouveau:drygmy"
));
});
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@
import java.util.List;
import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.CopyOnWriteArrayList;

/**
* Main class of the Ars Nouveau API.
Expand All @@ -40,6 +41,9 @@ public class ArsNouveauAPI {

private Set<RecipeType<? extends IEnchantingRecipe>> enchantingRecipeTypes = ConcurrentHashMap.newKeySet();

public static List<String> shoulderRiders = new CopyOnWriteArrayList<>();


/**
* Validator to use when crafting a spell in the spell book.
*/
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
package com.hollingsworth.arsnouveau.client.renderer.layer;

import com.hollingsworth.arsnouveau.common.entity.MagicalBuddyMob;
import com.mojang.blaze3d.vertex.PoseStack;
import net.minecraft.client.model.PlayerModel;
import net.minecraft.client.renderer.MultiBufferSource;
import net.minecraft.client.renderer.entity.EntityRenderDispatcher;
import net.minecraft.client.renderer.entity.EntityRendererProvider;
import net.minecraft.client.renderer.entity.RenderLayerParent;
import net.minecraft.client.renderer.entity.layers.RenderLayer;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.player.Player;

public class GeoShoulderLayer<T extends Player> extends RenderLayer<T, PlayerModel<T>> {

private final EntityRenderDispatcher entityRenderer;

public GeoShoulderLayer(RenderLayerParent<T, PlayerModel<T>> pRenderer, EntityRendererProvider.Context pContext) {
super(pRenderer);
entityRenderer = pContext.getEntityRenderDispatcher();
}

@Override

public void render(PoseStack pMatrixStack, MultiBufferSource pBuffer, int pPackedLight, T pLivingEntity, float pLimbSwing, float pLimbSwingAmount, float pPartialTicks, float pAgeInTicks, float pNetHeadYaw, float pHeadPitch) {
this.render(pMatrixStack, pBuffer, pPackedLight, pLivingEntity, pPartialTicks, true);
this.render(pMatrixStack, pBuffer, pPackedLight, pLivingEntity, pPartialTicks, false);
}

public void render(PoseStack pPoseStack, MultiBufferSource pBuffer, int pPackedLight, Player pLivingEntity, float pPartialTick, boolean pLeftShoulder) {
CompoundTag compoundtag = pLeftShoulder ? pLivingEntity.getShoulderEntityLeft() : pLivingEntity.getShoulderEntityRight();

EntityType.byString(compoundtag.getString("id")).filter(entityType -> entityType.getBaseClass().isAssignableFrom(MagicalBuddyMob.class)).ifPresent(
entityType -> {
var dummy = entityType.create(pLivingEntity.level);
if (dummy instanceof MagicalBuddyMob buddy) {
dummy.load(compoundtag);
pPoseStack.pushPose();
buddy.adjustShoulderPosition(pPoseStack, pLeftShoulder, pLivingEntity);
this.entityRenderer.render(dummy, 0.0D, 0.0D, 0.0D, 0.0F, 0, pPoseStack, pBuffer, pPackedLight);
pPoseStack.popPose();
}
}
);
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@
import com.hollingsworth.arsnouveau.api.ANFakePlayer;
import com.hollingsworth.arsnouveau.api.client.ITooltipProvider;
import com.hollingsworth.arsnouveau.api.client.IVariantColorProvider;
import com.hollingsworth.arsnouveau.api.entity.IDispellable;
import com.hollingsworth.arsnouveau.api.util.NBTUtil;
import com.hollingsworth.arsnouveau.api.util.SummonUtil;
import com.hollingsworth.arsnouveau.client.ClientInfo;
Expand Down Expand Up @@ -50,22 +49,19 @@
import net.minecraft.world.level.Level;
import net.minecraft.world.phys.Vec3;
import net.minecraftforge.common.Tags;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.core.animation.AnimatableManager;
import software.bernie.geckolib.core.animation.AnimationController;
import software.bernie.geckolib.core.animation.AnimationState;
import software.bernie.geckolib.core.animation.RawAnimation;
import software.bernie.geckolib.core.object.PlayState;
import software.bernie.geckolib.util.GeckoLibUtil;

import javax.annotation.Nullable;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.List;

public class EntityDrygmy extends PathfinderMob implements GeoEntity, ITooltipProvider, IDispellable, IVariantColorProvider<EntityDrygmy> {
public class EntityDrygmy extends MagicalBuddyMob implements ITooltipProvider, IVariantColorProvider<EntityDrygmy> {

public static final EntityDataAccessor<Boolean> CHANNELING = SynchedEntityData.defineId(EntityDrygmy.class, EntityDataSerializers.BOOLEAN);
public static final EntityDataAccessor<Boolean> TAMED = SynchedEntityData.defineId(EntityDrygmy.class, EntityDataSerializers.BOOLEAN);
Expand All @@ -77,7 +73,6 @@ public class EntityDrygmy extends PathfinderMob implements GeoEntity, ITooltipPr
public int channelCooldown;
private boolean setBehaviors;
public BlockPos homePos;
public int tamingTime;
public static String[] COLORS = {"brown", "cyan", "orange"};

@Override
Expand All @@ -102,11 +97,6 @@ public EntityDrygmy(Level world, boolean tamed) {
return (DrygmyTile) level.getBlockEntity(homePos);
}

@Override
public boolean hurt(DamageSource pSource, float pAmount) {
return SummonUtil.canSummonTakeDamage(pSource) && super.hurt(pSource, pAmount);
}

@Override
public void die(DamageSource source) {
if (!level.isClientSide && isTamed()) {
Expand Down Expand Up @@ -312,13 +302,6 @@ private PlayState idlePredicate(AnimationState<?> event) {
return PlayState.CONTINUE;
}

AnimatableInstanceCache factory = GeckoLibUtil.createInstanceCache(this);

@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return factory;
}

@Override
public void addAdditionalSaveData(CompoundTag tag) {
super.addAdditionalSaveData(tag);
Expand Down
43 changes: 27 additions & 16 deletions src/main/java/com/hollingsworth/arsnouveau/common/entity/Lily.java
Original file line number Diff line number Diff line change
Expand Up @@ -12,15 +12,20 @@
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.SoundEvent;
import net.minecraft.sounds.SoundEvents;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.*;
import net.minecraft.world.entity.AgeableMob;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.entity.Mob;
import net.minecraft.world.entity.ai.attributes.AttributeSupplier;
import net.minecraft.world.entity.ai.attributes.Attributes;
import net.minecraft.world.entity.ai.goal.*;
import net.minecraft.world.entity.animal.ShoulderRidingEntity;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
Expand All @@ -39,19 +44,19 @@

import java.util.UUID;

public class Lily extends TamableAnimal implements GeoEntity, IDispellable {
public class Lily extends ShoulderRidingEntity implements GeoEntity, IDispellable {
// Owner UUID to Lily UUID
public static BiMap<UUID, UUID> ownerLilyMap = HashBiMap.create();

private static final EntityDataAccessor<Boolean> SIT = SynchedEntityData.defineId(Lily.class, EntityDataSerializers.BOOLEAN);
private static final EntityDataAccessor<Boolean> WAG = SynchedEntityData.defineId(Lily.class, EntityDataSerializers.BOOLEAN);
public int wagTicks;

public Lily(EntityType<? extends TamableAnimal> pEntityType, Level pLevel) {
public Lily(EntityType<? extends ShoulderRidingEntity> pEntityType, Level pLevel) {
super(pEntityType, pLevel);
}

public Lily(Level level){
public Lily(Level level) {
this(ModEntities.LILY.get(), level);
}

Expand All @@ -73,6 +78,10 @@ public InteractionResult mobInteract(Player pPlayer, InteractionHand pHand) {
return InteractionResult.CONSUME;
}
if (this.isOwnedBy(pPlayer)) {
if (pPlayer.isShiftKeyDown() && pPlayer instanceof ServerPlayer sp) {
this.setEntityOnShoulder(sp);
return InteractionResult.SUCCESS;
}
this.setOrderedToSit(!this.isOrderedToSit());
this.jumping = false;
this.navigation.stop();
Expand All @@ -86,13 +95,13 @@ public InteractionResult mobInteract(Player pPlayer, InteractionHand pHand) {
public void tick() {
super.tick();
SummonUtil.healOverTime(this);
if(!level.isClientSide){
if(level.getGameTime() % 20 == 0 && !ownerLilyMap.containsValue(this.getUUID())){
if (!level.isClientSide) {
if (level.getGameTime() % 20 == 0 && !ownerLilyMap.containsValue(this.getUUID())) {
this.remove(RemovalReason.DISCARDED);
}
if( wagTicks > 0 && isWagging()){
if (wagTicks > 0 && isWagging()) {
wagTicks--;
if(wagTicks <= 0){
if (wagTicks <= 0) {
setWagging(false);
}
}
Expand Down Expand Up @@ -155,7 +164,7 @@ protected SoundEvent getDeathSound() {

@Override
public boolean hurt(DamageSource pSource, float pAmount) {
if(!(pSource.getEntity() instanceof Player)){
if (!(pSource.getEntity() instanceof Player)) {
return false;
}
return super.hurt(pSource, pAmount);
Expand Down Expand Up @@ -195,53 +204,55 @@ public boolean isLookingAtMe(Player pPlayer) {
@Override
public void registerControllers(AnimatableManager.ControllerRegistrar data) {
data.add(new AnimationController(this, "walk", 1, (event) -> {
if(event.isMoving()){
if (event.isMoving()) {
event.getController().setAnimation(RawAnimation.begin().thenPlay("run"));
return PlayState.CONTINUE;
}
return PlayState.STOP;
}));
data.add(new AnimationController(this, "idle", 1, (event) -> {
if(!event.isMoving() && !this.isWagging()){
if (!event.isMoving() && !this.isWagging()) {
event.getController().setAnimation(RawAnimation.begin().thenPlay("idle"));
return PlayState.CONTINUE;
}
return PlayState.STOP;
}));
data.add(new AnimationController(this, "idle_wag", 1, (event) -> {
if(!event.isMoving() && this.isWagging()){
if (!event.isMoving() && this.isWagging()) {
event.getController().setAnimation(RawAnimation.begin().thenPlay("idle_wagging"));
return PlayState.CONTINUE;
}
return PlayState.STOP;
}));

data.add(new AnimationController(this, "rest", 1, (event) -> {
if(!event.isMoving() && this.isOrderedToSit() && !this.isWagging()){
if (!event.isMoving() && this.isOrderedToSit() && !this.isWagging()) {
event.getController().setAnimation(RawAnimation.begin().thenPlay("resting"));
return PlayState.CONTINUE;
}
return PlayState.STOP;
}));

data.add(new AnimationController(this, "rest_wag", 1, (event) -> {
if(!event.isMoving() && this.isOrderedToSit() && this.isWagging()){
if (!event.isMoving() && this.isOrderedToSit() && this.isWagging()) {
event.getController().setAnimation(RawAnimation.begin().thenPlay("resting_wagging"));
return PlayState.CONTINUE;
}
return PlayState.STOP;
}));

}

AnimatableInstanceCache factory = GeckoLibUtil.createInstanceCache(this);

@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return factory;
}

@Override
public boolean onDispel(@NotNull LivingEntity caster) {
if(caster.getUUID().equals(this.getOwnerUUID())) {
if (caster.getUUID().equals(this.getOwnerUUID())) {
this.remove(RemovalReason.DISCARDED);
return true;
}
Expand All @@ -251,7 +262,7 @@ public boolean onDispel(@NotNull LivingEntity caster) {
@Override
public void load(CompoundTag pCompound) {
super.load(pCompound);
if(!ownerLilyMap.containsKey(this.getOwnerUUID())) {
if (!ownerLilyMap.containsKey(this.getOwnerUUID())) {
Lily.ownerLilyMap.put(this.getOwnerUUID(), this.getUUID());
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
package com.hollingsworth.arsnouveau.common.entity;

import com.hollingsworth.arsnouveau.api.entity.IDispellable;
import com.hollingsworth.arsnouveau.api.util.SummonUtil;
import com.mojang.blaze3d.vertex.PoseStack;
import com.mojang.math.Axis;
import net.minecraft.nbt.CompoundTag;
import net.minecraft.server.level.ServerPlayer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.InteractionResult;
import net.minecraft.world.damagesource.DamageSource;
import net.minecraft.world.entity.EntityType;
import net.minecraft.world.entity.PathfinderMob;
import net.minecraft.world.entity.player.Player;
import net.minecraft.world.level.Level;
import net.minecraftforge.api.distmarker.Dist;
import net.minecraftforge.api.distmarker.OnlyIn;
import software.bernie.geckolib.animatable.GeoEntity;
import software.bernie.geckolib.core.animatable.instance.AnimatableInstanceCache;
import software.bernie.geckolib.util.GeckoLibUtil;

public abstract class MagicalBuddyMob extends PathfinderMob implements GeoEntity, IDispellable {


public int tamingTime;
AnimatableInstanceCache manager = GeckoLibUtil.createInstanceCache(this);

protected MagicalBuddyMob(EntityType<? extends PathfinderMob> pEntityType, Level pLevel) {
super(pEntityType, pLevel);
}

@OnlyIn(Dist.CLIENT)
/*
* The matrixStack is already ready to be transformed, no need of push/pop.
*
*/
public void adjustShoulderPosition(PoseStack pMatrixStack, boolean pLeftShoulder, Player pLivingEntity) {
pMatrixStack.translate(pLeftShoulder ? 0.4F : -0.4F, pLivingEntity.isCrouching() ? +.2F : 0F, 0.0F);
pMatrixStack.mulPose(Axis.XP.rotationDegrees(180.0F));

this.yHeadRot = pLivingEntity.yHeadRot;
this.yHeadRotO = pLivingEntity.yHeadRot;

}

public void setEntityOnShoulder(ServerPlayer pPlayer) {
CompoundTag compoundtag = new CompoundTag();
var id = this.getEncodeId();
if (id == null) return;
compoundtag.putString("id", id);
this.saveWithoutId(compoundtag);
if (pPlayer.setEntityOnShoulder(compoundtag)) {
this.discard();
}
}


@Override
protected InteractionResult mobInteract(Player pPlayer, InteractionHand pHand) {
if (pPlayer instanceof ServerPlayer sp && sp.getItemInHand(InteractionHand.MAIN_HAND).isEmpty() && sp.isShiftKeyDown()) {
this.setEntityOnShoulder(sp);
return InteractionResult.SUCCESS;
}

return super.mobInteract(pPlayer, pHand);
}

@Override
public boolean hurt(DamageSource pSource, float pAmount) {
return SummonUtil.canSummonTakeDamage(pSource) && super.hurt(pSource, pAmount);
}

@Override
public AnimatableInstanceCache getAnimatableInstanceCache() {
return manager;
}
}
Loading