Skip to content

Commit 01afb3d

Browse files
committed
Model stuff
1 parent 28fc8dc commit 01afb3d

4 files changed

Lines changed: 114 additions & 25 deletions

File tree

build.gradle.kts

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArt
2727
dependencies {
2828
paperweightDevelopmentBundle("de.erethon.papyrus", "dev-bundle", papyrusVersion)
2929

30-
compileOnly("de.erethon", "Daedalus", "1.3")
30+
compileOnly("de.erethon", "Daedalus", "1.4-SNAPSHOT")
3131

3232
compileOnly("de.erethon.hephaestus:Hephaestus:1.0.4-SNAPSHOT")
3333
compileOnly("de.erethon.questsxl:QuestsXL:1.0.5-SNAPSHOT")

src/main/java/de/erethon/aether/creature/AetherBaseMob.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -736,7 +736,7 @@ public boolean isPersistenceRequired() {
736736
return data.isPersistent();
737737
}
738738

739-
private void onLoad() {
739+
protected void onLoad() {
740740
if (data.getQXLSection() != null) {
741741
holder = AetherHolder.loadFromConfigSection(data.getQXLSection(), this);
742742
if (holder != null) {

src/main/java/de/erethon/aether/creature/AetherPlayer.java

Lines changed: 14 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,16 +3,16 @@
33
import com.destroystokyo.paper.profile.CraftPlayerProfile;
44
import com.destroystokyo.paper.profile.ProfileProperty;
55
import com.magmaguy.freeminecraftmodels.utils.DataMappings;
6-
import de.erethon.aether.Aether;
76
import de.erethon.aether.tools.NMSUtils;
8-
import net.minecraft.network.chat.Component;
97
import net.minecraft.network.protocol.Packet;
108
import net.minecraft.network.protocol.game.ClientGamePacketListener;
119
import net.minecraft.network.syncher.EntityDataAccessor;
1210
import net.minecraft.server.level.ServerEntity;
11+
import net.minecraft.server.level.ServerLevel;
1312
import net.minecraft.server.level.ServerPlayer;
14-
import net.minecraft.server.network.ServerPlayerConnection;
1513
import net.minecraft.util.Mth;
14+
import net.minecraft.world.InteractionHand;
15+
import net.minecraft.world.entity.Avatar;
1616
import net.minecraft.world.entity.Entity;
1717
import net.minecraft.world.entity.EntityType;
1818
import net.minecraft.world.entity.Mob;
@@ -31,6 +31,7 @@ public class AetherPlayer extends AetherBaseMob {
3131

3232
private static EntityDataAccessor<ResolvableProfile> DATA_PLAYER_PROFILE = null;
3333
private static EntityDataAccessor<Optional<net.minecraft.network.chat.Component>> DATA_DESCRIPTION = null;
34+
private static EntityDataAccessor<Byte> DATA_PLAYER_MAIN_HAND = null;
3435

3536
public AetherPlayer(EntityType<? extends Mob> type, Level world) {
3637
super(type, world);
@@ -53,9 +54,13 @@ protected void onFirstSpawn() {
5354
if (DATA_DESCRIPTION == null) {
5455
DATA_DESCRIPTION = DataMappings.getAccessor(Mannequin.class, "DATA_DESCRIPTION");
5556
}
57+
if (DATA_PLAYER_MAIN_HAND == null) {
58+
DATA_PLAYER_MAIN_HAND = DataMappings.getAccessor(Avatar.class, "DATA_PLAYER_MAIN_HAND");
59+
}
5660
getEntityData().set(DATA_PLAYER_MODE_CUSTOMISATION, ALL_LAYERS);
5761
getEntityData().set(DATA_PLAYER_PROFILE, getResolvableProfile());
5862
getEntityData().set(DATA_DESCRIPTION, Optional.empty());
63+
getEntityData().set(DATA_PLAYER_MAIN_HAND, (byte) 1); // Right hand
5964
}
6065

6166
@Override
@@ -69,6 +74,12 @@ public void startSeenByPlayer(ServerPlayer serverPlayer) {
6974
return NMSUtils.getAddEntityPacketWithType(this, EntityType.MANNEQUIN);
7075
}
7176

77+
@Override
78+
public boolean doHurtTarget(ServerLevel level, Entity target) {
79+
swing(InteractionHand.MAIN_HAND, false);
80+
return super.doHurtTarget(level, target);
81+
}
82+
7283
@Override
7384
public void setNoAi(boolean noAi) {
7485
}
Lines changed: 98 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1,17 +1,40 @@
11
package de.erethon.aether.creature;
22

3-
import com.magmaguy.freeminecraftmodels.customentity.DynamicEntity;
3+
import com.magmaguy.freeminecraftmodels.animation.AnimationStateType;
4+
import com.magmaguy.freeminecraftmodels.customentity.ModeledEntity;
45
import com.magmaguy.freeminecraftmodels.utils.DataMappings;
56
import de.erethon.aether.Aether;
6-
import net.minecraft.server.level.ServerPlayer;
7+
import de.erethon.hecate.Hecate;
8+
import de.erethon.hecate.ui.EntityStatusDisplay;
9+
import de.erethon.papyrus.CraftPDamageType;
10+
import net.minecraft.server.level.ServerLevel;
11+
import net.minecraft.world.damagesource.DamageSource;
12+
import net.minecraft.world.entity.Entity;
713
import net.minecraft.world.entity.EntityType;
814
import net.minecraft.world.entity.Mob;
15+
import net.minecraft.world.entity.ai.attributes.Attributes;
916
import net.minecraft.world.level.Level;
17+
import org.bukkit.Location;
18+
import org.bukkit.NamespacedKey;
1019
import org.bukkit.World;
20+
import org.bukkit.entity.TextDisplay;
21+
import org.bukkit.event.entity.EntityRemoveEvent;
22+
import org.bukkit.persistence.PersistentDataType;
23+
import org.jetbrains.annotations.Nullable;
1124

1225
public class ModelledMob extends AetherBaseMob {
1326

14-
private DynamicEntity model;
27+
private static final NamespacedKey MARKER_KEY = new NamespacedKey("erethon", "no_nametag");
28+
29+
private ModeledEntity model;
30+
31+
private EntityStatusDisplay display;
32+
private TextDisplay healthDisplay;
33+
private TextDisplay nameTag;
34+
private TextDisplay statusDisplay;
35+
private double hitboxHeight;
36+
37+
private AnimationStateType currentMovementState = AnimationStateType.IDLE;
1538

1639
public ModelledMob(EntityType<? extends Mob> type, Level world) {
1740
super(type, world);
@@ -23,53 +46,108 @@ public ModelledMob(NPCData data, World world, Integer overrideLevel) {
2346

2447
public ModelledMob(NPCData data, World world) {
2548
super(data, world);
26-
displayType = EntityType.PILLAGER; // Hardcode this for now
49+
displayType = EntityType.PIG; // Hardcode this for now
2750
String id = data.cfg.getString("modelId");
2851
if (id == null) {
2952
Aether.addException("ModelledMob " + data.getID(), "Missing modelId", "Add a modelId or remove the ModelledMob base class", null);
3053
return;
3154
}
3255
entityData = DataMappings.getSynchedEntityData(displayType);
33-
this.model = DynamicEntity.create(id, getBukkitLivingEntity());
34-
setInvisible(true);
56+
this.model = new ModeledEntity(id, getBukkitEntity().getLocation());
57+
hitboxHeight = model.getSkeletonBlueprint().getHitbox().getHeight();
58+
getBukkitEntity().setVisibleByDefault(false);
59+
getBukkitEntity().getPersistentDataContainer().set(MARKER_KEY, PersistentDataType.BOOLEAN, true);
60+
onLoad();
61+
onFirstSpawn();
3562
}
3663

3764
@Override
3865
public void addToWorld() {
3966
super.addToWorld();
67+
model.spawn(getBukkitEntity());
68+
model.setUnderlyingEntity(getBukkitEntity());
69+
Hecate hecate = Hecate.getInstance();
70+
display = new EntityStatusDisplay(getBukkitLivingEntity());
71+
healthDisplay = display.healthDisplay;
72+
nameTag = display.entityNameTag;
73+
statusDisplay = display.statusDisplay;
74+
if (healthDisplay == null || nameTag == null || statusDisplay == null) {
75+
return;
76+
}
77+
hecate.getStatusDisplayManager().addStatusDisplay(getBukkitLivingEntity(), display);
78+
// We will handle positioning ourselves to account for the entity changes
79+
getBukkitEntity().removePassenger(nameTag);
80+
getBukkitEntity().removePassenger(healthDisplay);
81+
getBukkitEntity().removePassenger(statusDisplay);
82+
healthDisplay.setTeleportDuration(1);
83+
statusDisplay.setTeleportDuration(1);
84+
nameTag.setTeleportDuration(1);
4085
}
4186

42-
private void syncSkeletonWithEntity() {
43-
if (isDeadOrDying()) return;
44-
model.getSkeleton().setCurrentHeadPitch(getBukkitLivingEntity().getEyeLocation().getPitch());
45-
model.getSkeleton().setCurrentHeadYaw(getBukkitLivingEntity().getEyeLocation().getYaw());
87+
@Override
88+
public boolean hurtServer(ServerLevel level, DamageSource source, float amount, CraftPDamageType type) {
89+
model.getSkeleton().tint();
90+
return super.hurtServer(level, source, amount, type);
4691
}
4792

4893
@Override
49-
public void startSeenByPlayer(ServerPlayer serverPlayer) {
50-
super.startSeenByPlayer(serverPlayer);
51-
refreshEntityData(serverPlayer);
94+
public boolean doHurtTarget(ServerLevel level, Entity target) {
95+
if (model.hasAnimation("attack")) {
96+
model.playAnimation("attack", false, false);
97+
}
98+
return super.doHurtTarget(level, target);
5299
}
53100

54101
@Override
55-
public void stopSeenByPlayer(ServerPlayer serverPlayer) {
56-
super.stopSeenByPlayer(serverPlayer);
102+
public void die(DamageSource damageSource) {
103+
super.die(damageSource);
104+
if (model.hasAnimation("death")) {
105+
model.removeWithDeathAnimation();
106+
} else {
107+
model.removeWithMinimizedAnimation();
108+
}
109+
}
110+
111+
@Override
112+
public void onRemoval(RemovalReason reason) {
113+
super.onRemoval(reason);
114+
model.setMarkForRemoval(true);
115+
}
116+
117+
private void syncSkeletonWithEntity() {
118+
if (isDeadOrDying()) return;
119+
model.getSkeleton().setCurrentHeadPitch(getBukkitLivingEntity().getEyeLocation().getPitch());
120+
model.getSkeleton().setCurrentHeadYaw(getBukkitLivingEntity().getEyeLocation().getYaw());
57121
}
58122

59123
@Override
60124
protected void onFirstSpawn() {
125+
super.onFirstSpawn();
61126
setInvisible(true);
62127
}
63128

64129
@Override
65130
public void tick() {
66131
super.tick();
67132
syncSkeletonWithEntity();
68-
}
133+
model.tick();
134+
// Determine movement state based on velocity
135+
boolean isMoving = getDeltaMovement().horizontalDistanceSqr() > 0.0001 && !isDeadOrDying();
136+
AnimationStateType targetState = isMoving ? AnimationStateType.WALK : AnimationStateType.IDLE;
69137

70-
@Override
71-
public void remove(RemovalReason reason) {
72-
super.remove(reason);
73-
model.remove();
138+
if (targetState != currentMovementState) {
139+
model.getAnimationComponent().playAnimation(targetState.name().toLowerCase(), false, true);
140+
currentMovementState = targetState;
141+
}
142+
if (nameTag == null || healthDisplay == null || statusDisplay == null) {
143+
return;
144+
}
145+
// Update displays
146+
Location loc = getBukkitEntity().getLocation().add(0, hitboxHeight + 0.18f, 0);
147+
loc.setPitch(0);
148+
loc.setYaw(0);
149+
nameTag.teleport(loc);
150+
healthDisplay.teleport(loc);
151+
statusDisplay.teleport(loc);
74152
}
75153
}

0 commit comments

Comments
 (0)