Enjoy a little Polymer by the Poolside

- Bath Tire and Beach Ball entities are now working with Polymer!
This commit is contained in:
Martin Prokoph
2024-07-30 23:59:57 +02:00
parent ec91269fd0
commit 3af6b9fa9c
7 changed files with 180 additions and 19 deletions

View File

@@ -1,5 +1,8 @@
package eu.midnightdust.motschen.decorative.entity;
import eu.midnightdust.motschen.decorative.polymer.entity.ItemDisplayBasedEntity;
import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.entity.Entity;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.mob.MobEntity;
@@ -14,10 +17,12 @@ import net.minecraft.util.Hand;
import net.minecraft.util.Identifier;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.joml.Vector3f;
public class BathTireEntity extends MobEntity {
public class BathTireEntity extends MobEntity implements ItemDisplayBasedEntity {
public BathTireEntity(EntityType<? extends BathTireEntity> entityType, World world) {
super(entityType, world);
this.onCreated(this);
}
@Override
@@ -26,7 +31,7 @@ public class BathTireEntity extends MobEntity {
if (player.isSneaking()) {
this.remove(RemovalReason.DISCARDED);
System.out.println(Identifier.tryParse(this.getType().getUntranslatedName()));
player.setStackInHand(hand, new ItemStack(Registries.ITEM.get(Identifier.tryParse("decorative:" + this.getType().getUntranslatedName()))));
player.setStackInHand(hand, getItemStackForType());
return ActionResult.SUCCESS;
}
else if (!player.isSneaking()) {
@@ -57,4 +62,25 @@ public class BathTireEntity extends MobEntity {
public boolean canWalkOnFluid(FluidState fluid) {
return true;
}
private ItemStack getItemStackForType() {
return new ItemStack(Registries.ITEM.get(Identifier.tryParse("decorative:" + this.getType().getUntranslatedName())));
}
// Polymer
@Override
public ItemStack getVisualItemStack() {
return getItemStackForType();
}
@Override
public void setItemDisplayProperties(ItemDisplayElement display) {
display.setInvisible(false);
display.setModelTransformation(ModelTransformationMode.HEAD);
display.setTeleportDuration(3);
display.setScale(new Vector3f(1f));
display.setTranslation(new Vector3f(0, 0.4f, 0));
}
@Override
public Vec3d getClientSidePosition(Vec3d vec3d) {
return vec3d.add(0, -1.5d, 0);
}
}

View File

@@ -1,6 +1,9 @@
package eu.midnightdust.motschen.decorative.entity;
import eu.midnightdust.motschen.decorative.init.Pool;
import eu.midnightdust.motschen.decorative.polymer.entity.ItemDisplayBasedEntity;
import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.mob.MobEntity;
import net.minecraft.entity.player.PlayerEntity;
@@ -12,10 +15,12 @@ import net.minecraft.util.ActionResult;
import net.minecraft.util.Hand;
import net.minecraft.util.math.Vec3d;
import net.minecraft.world.World;
import org.joml.Vector3f;
public class BeachBallEntity extends MobEntity {
public class BeachBallEntity extends MobEntity implements ItemDisplayBasedEntity {
public BeachBallEntity(EntityType<? extends BeachBallEntity> entityType, World world) {
super(entityType, world);
this.onCreated(this);
}
@Override
@@ -41,4 +46,25 @@ public class BeachBallEntity extends MobEntity {
public boolean canWalkOnFluid(FluidState fluid) {
return true;
}
// Polymer
@Override
public ItemStack getVisualItemStack() {
return new ItemStack(Pool.BEACH_BALL_ITEM);
}
@Override
public void setItemDisplayProperties(ItemDisplayElement display) {
display.setInvisible(false);
display.setModelTransformation(ModelTransformationMode.HEAD);
display.setTeleportDuration(3);
display.setScale(new Vector3f(1f));
display.setTranslation(new Vector3f(0, -0.4f, 0));
}
@Override
public Vec3d getClientSidePosition(Vec3d vec3d) {
return vec3d.add(0, 0.25d, 0);
}
@Override
public boolean isSmall() {
return true;
}
}

View File

@@ -2,14 +2,12 @@ package eu.midnightdust.motschen.decorative.item;
import eu.pb4.factorytools.api.item.AutoModeledPolymerItem;
import net.minecraft.block.FluidBlock;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.SpawnReason;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.Item;
import net.minecraft.item.ItemStack;
import net.minecraft.item.Items;
import net.minecraft.nbt.NbtCompound;
import net.minecraft.server.world.ServerWorld;
import net.minecraft.stat.Stats;
import net.minecraft.util.Hand;
@@ -21,7 +19,7 @@ import net.minecraft.world.RaycastContext;
import net.minecraft.world.World;
public class BathTireItem extends Item implements AutoModeledPolymerItem {
private final EntityType<?> type;
public final EntityType<?> type;
public BathTireItem(EntityType<?> type, Item.Settings settings) {
super(settings);
@@ -41,8 +39,7 @@ public class BathTireItem extends Item implements AutoModeledPolymerItem {
if (!(world.getBlockState(blockPos).getBlock() instanceof FluidBlock)) {
return TypedActionResult.pass(itemStack);
} else if (world.canPlayerModifyAt(user, blockPos) && user.canPlaceOn(blockPos, hitResult.getSide(), itemStack)) {
EntityType<?> entityType = this.getEntityType(itemStack.getComponents().get(DataComponentTypes.ENTITY_DATA).copyNbt());
if (entityType.spawnFromItemStack((ServerWorld) world, itemStack, user, blockPos.up(1), SpawnReason.SPAWN_EGG, false, false) == null) {
if (this.type.spawnFromItemStack((ServerWorld) world, itemStack, user, blockPos.up(1), SpawnReason.SPAWN_EGG, false, false) == null) {
return TypedActionResult.pass(itemStack);
} else {
if (!user.getAbilities().creativeMode) {
@@ -58,17 +55,6 @@ public class BathTireItem extends Item implements AutoModeledPolymerItem {
}
}
public EntityType<?> getEntityType(NbtCompound tag) {
if (tag != null && tag.contains("EntityTag", 10)) {
NbtCompound compoundTag = tag.getCompound("EntityTag");
if (compoundTag.contains("id", 8)) {
return EntityType.get(compoundTag.getString("id")).orElse(this.type);
}
}
return this.type;
}
@Override
public Item getPolymerItem() {
return Items.DRIED_KELP;

View File

@@ -0,0 +1,14 @@
package eu.midnightdust.motschen.decorative.mixin;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.entity.decoration.ArmorStandEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.gen.Accessor;
@Mixin(ArmorStandEntity.class)
public interface ArmorStandEntityAccessor {
@Accessor
static TrackedData<Byte> getARMOR_STAND_FLAGS() {
throw new RuntimeException();
}
}

View File

@@ -0,0 +1,94 @@
package eu.midnightdust.motschen.decorative.polymer.entity;
import eu.midnightdust.motschen.decorative.mixin.ArmorStandEntityAccessor;
import eu.pb4.polymer.core.api.entity.PolymerEntity;
import eu.pb4.polymer.virtualentity.api.ElementHolder;
import eu.pb4.polymer.virtualentity.api.VirtualEntityUtils;
import eu.pb4.polymer.virtualentity.api.attachment.EntityAttachment;
import eu.pb4.polymer.virtualentity.api.elements.ItemDisplayElement;
import eu.pb4.polymer.virtualentity.api.tracker.EntityTrackedData;
import net.minecraft.client.render.model.json.ModelTransformationMode;
import net.minecraft.entity.EntityType;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.data.DataTracker;
import net.minecraft.entity.data.TrackedData;
import net.minecraft.item.ItemStack;
import net.minecraft.server.network.ServerPlayerEntity;
import org.joml.Vector3f;
import java.util.List;
import java.util.WeakHashMap;
public interface ItemDisplayBasedEntity extends PolymerEntity {
WeakHashMap<LivingEntity, ItemDisplayElement> DISPLAY_ELEMENTS = new WeakHashMap<>();
ItemStack getVisualItemStack();
// This needs to be called on entity init
default void onCreated(LivingEntity entity) {
ElementHolder holder = new ElementHolder();
ItemDisplayElement display = initDisplayEntity();
holder.addElement(display);
DISPLAY_ELEMENTS.put(entity, display);
EntityAttachment.of(holder, entity);
VirtualEntityUtils.addVirtualPassenger(entity, display.getEntityId());
}
default ItemDisplayElement initDisplayEntity() {
ItemDisplayElement display = new ItemDisplayElement(getVisualItemStack());
setItemDisplayProperties(display);
return display;
}
default void setItemDisplayProperties(ItemDisplayElement display) {
display.setInvisible(false);
display.setModelTransformation(ModelTransformationMode.HEAD);
display.setTeleportDuration(3);
display.setScale(new Vector3f(1f));
}
default boolean isSmall() {
return false;
}
@Override
default float getClientSideYaw(float yaw) {
if (DISPLAY_ELEMENTS.containsKey((LivingEntity) this)) {
DISPLAY_ELEMENTS.get((LivingEntity) this).setYaw(yaw);
}
return yaw;
}
@Override
default float getClientSidePitch(float pitch) {
if (DISPLAY_ELEMENTS.containsKey((LivingEntity) this)) {
DISPLAY_ELEMENTS.get((LivingEntity) this).setPitch(pitch);
}
return pitch;
}
@Override
default EntityType<?> getPolymerEntityType(ServerPlayerEntity player) {
return EntityType.ARMOR_STAND;
}
@Override
default void modifyRawTrackedData(List<DataTracker.SerializedEntry<?>> data, ServerPlayerEntity player, boolean initial) {
setInvisible(data, true);
if (isSmall()) data.add(DataTracker.SerializedEntry.of(ArmorStandEntityAccessor.getARMOR_STAND_FLAGS(), (byte) (0b00000011)));
}
static void setInvisible(List<DataTracker.SerializedEntry<?>> data, boolean invisible) {
setFlag(data, EntityTrackedData.FLAGS, EntityTrackedData.INVISIBLE_FLAG_INDEX, invisible);
}
static void setFlag(List<DataTracker.SerializedEntry<?>> data, TrackedData<Byte> type, int index, boolean value) {
// More elegant code that doesn't work somehow
//var flagsData = data.stream().filter(serializedEntry -> serializedEntry.handler().equals(type.dataType())).findFirst();
//byte b = flagsData.isEmpty() ? 0 : (byte) flagsData.get().value();
//flagsData.ifPresent(data::remove);
byte b = 0;
if (value) {
data.add(DataTracker.SerializedEntry.of(type, (byte) (b | 1 << index)));
} else {
data.add(DataTracker.SerializedEntry.of(type, (byte) (b & ~(1 << index))));
}
}
}

View File

@@ -0,0 +1,11 @@
{
"required": true,
"package": "eu.midnightdust.motschen.decorative.mixin",
"compatibilityLevel": "JAVA_21",
"mixins": [
"ArmorStandEntityAccessor"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -28,6 +28,10 @@
]
},
"mixins": [
"decorative.mixins.json"
],
"depends": {
"fabric": "*",
"midnightlib": "*"