216 lines
7.9 KiB
Java
216 lines
7.9 KiB
Java
package at.petrak.hexcasting.common.entities;
|
|
|
|
import at.petrak.hexcasting.client.render.HexPatternPoints;
|
|
import at.petrak.hexcasting.api.casting.math.HexPattern;
|
|
import at.petrak.hexcasting.api.utils.HexUtils;
|
|
import at.petrak.hexcasting.api.utils.NBTHelper;
|
|
import at.petrak.hexcasting.client.render.RenderLib;
|
|
import at.petrak.hexcasting.common.items.storage.ItemScroll;
|
|
import at.petrak.hexcasting.common.lib.HexItems;
|
|
import at.petrak.hexcasting.common.lib.HexSounds;
|
|
import at.petrak.hexcasting.common.msgs.MsgNewWallScrollS2C;
|
|
import at.petrak.hexcasting.common.msgs.MsgRecalcWallScrollDisplayS2C;
|
|
import at.petrak.hexcasting.xplat.IXplatAbstractions;
|
|
import net.minecraft.core.BlockPos;
|
|
import net.minecraft.core.Direction;
|
|
import net.minecraft.nbt.CompoundTag;
|
|
import net.minecraft.network.protocol.Packet;
|
|
import net.minecraft.network.protocol.game.ClientboundAddEntityPacket;
|
|
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.sounds.SoundEvents;
|
|
import net.minecraft.sounds.SoundSource;
|
|
import net.minecraft.world.InteractionHand;
|
|
import net.minecraft.world.InteractionResult;
|
|
import net.minecraft.world.entity.Entity;
|
|
import net.minecraft.world.entity.EntityType;
|
|
import net.minecraft.world.entity.decoration.HangingEntity;
|
|
import net.minecraft.world.entity.player.Player;
|
|
import net.minecraft.world.item.ItemStack;
|
|
import net.minecraft.world.level.GameRules;
|
|
import net.minecraft.world.level.Level;
|
|
import net.minecraft.world.phys.Vec3;
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
public class EntityWallScroll extends HangingEntity {
|
|
private static final EntityDataAccessor<Boolean> SHOWS_STROKE_ORDER = SynchedEntityData.defineId(
|
|
EntityWallScroll.class,
|
|
EntityDataSerializers.BOOLEAN);
|
|
|
|
public ItemStack scroll;
|
|
public HexPattern pattern;
|
|
public boolean isAncient;
|
|
public int blockSize;
|
|
// Client-side only!
|
|
public HexPatternPoints points;
|
|
|
|
public EntityWallScroll(EntityType<? extends EntityWallScroll> type, Level world) {
|
|
super(type, world);
|
|
}
|
|
|
|
public EntityWallScroll(Level world, BlockPos pos, Direction dir, ItemStack scroll, boolean showStrokeOrder,
|
|
int blockSize) {
|
|
super(HexEntities.WALL_SCROLL, world, pos);
|
|
this.setDirection(dir);
|
|
this.blockSize = blockSize;
|
|
|
|
this.entityData.set(SHOWS_STROKE_ORDER, showStrokeOrder);
|
|
this.scroll = scroll;
|
|
this.recalculateDisplay();
|
|
this.recalculateBoundingBox();
|
|
}
|
|
|
|
public void recalculateDisplay() {
|
|
CompoundTag patternTag = NBTHelper.getCompound(scroll, ItemScroll.TAG_PATTERN);
|
|
if (patternTag != null) {
|
|
this.pattern = HexPattern.fromNBT(patternTag);
|
|
if (this.level.isClientSide) {
|
|
var pair = RenderLib.getCenteredPattern(pattern, 128f / 3 * blockSize, 128f / 3 * blockSize,
|
|
16f / 3 * blockSize);
|
|
var dots = pair.getSecond();
|
|
var readOffset = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_READABILITY_OFFSET : 0f;
|
|
var lastProp = this.getShowsStrokeOrder() ? RenderLib.DEFAULT_LAST_SEGMENT_LEN_PROP : 1f;
|
|
var zappyPoints = RenderLib.makeZappy(dots, RenderLib.findDupIndices(pattern.positions()), 10, 0.4f,
|
|
0f, 0f, readOffset, lastProp, this.getId());
|
|
points = new HexPatternPoints(zappyPoints);
|
|
}
|
|
|
|
this.isAncient = NBTHelper.hasString(scroll, ItemScroll.TAG_OP_ID);
|
|
} else {
|
|
this.pattern = null;
|
|
this.points = null;
|
|
this.isAncient = false;
|
|
}
|
|
}
|
|
|
|
@Override
|
|
protected void defineSynchedData() {
|
|
super.defineSynchedData();
|
|
this.entityData.define(SHOWS_STROKE_ORDER, false);
|
|
}
|
|
|
|
public boolean getShowsStrokeOrder() {
|
|
return this.entityData.get(SHOWS_STROKE_ORDER);
|
|
}
|
|
|
|
public void setShowsStrokeOrder(boolean b) {
|
|
this.entityData.set(SHOWS_STROKE_ORDER, b);
|
|
}
|
|
|
|
@Override
|
|
public int getWidth() {
|
|
return 16 * blockSize;
|
|
}
|
|
|
|
@Override
|
|
public int getHeight() {
|
|
return 16 * blockSize;
|
|
}
|
|
|
|
@Override
|
|
public void dropItem(@Nullable Entity pBrokenEntity) {
|
|
if (this.level.getGameRules().getBoolean(GameRules.RULE_DOENTITYDROPS)) {
|
|
this.playSound(SoundEvents.PAINTING_BREAK, 1.0F, 1.0F);
|
|
if (pBrokenEntity instanceof Player player) {
|
|
if (player.getAbilities().instabuild) {
|
|
return;
|
|
}
|
|
}
|
|
|
|
this.spawnAtLocation(this.scroll);
|
|
}
|
|
}
|
|
|
|
@Override
|
|
public InteractionResult interactAt(Player pPlayer, Vec3 pVec, InteractionHand pHand) {
|
|
var handStack = pPlayer.getItemInHand(pHand);
|
|
if (handStack.is(HexItems.AMETHYST_DUST) && !this.getShowsStrokeOrder()) {
|
|
if (!pPlayer.getAbilities().instabuild) {
|
|
handStack.shrink(1);
|
|
}
|
|
this.setShowsStrokeOrder(true);
|
|
|
|
pPlayer.level.playSound(pPlayer, this, HexSounds.SCROLL_DUST, SoundSource.PLAYERS, 1f, 1f);
|
|
|
|
if (pPlayer.getLevel() instanceof ServerLevel slevel) {
|
|
IXplatAbstractions.INSTANCE.sendPacketNear(this.position(), 32.0, slevel,
|
|
new MsgRecalcWallScrollDisplayS2C(this.getId(), true));
|
|
} else {
|
|
// Beat the packet roundtrip to the punch to get a quicker visual
|
|
this.recalculateDisplay();
|
|
}
|
|
return InteractionResult.SUCCESS;
|
|
}
|
|
return super.interactAt(pPlayer, pVec, pHand);
|
|
}
|
|
|
|
@Override
|
|
public void playPlacementSound() {
|
|
this.playSound(SoundEvents.PAINTING_PLACE, 1.0F, 1.0F);
|
|
}
|
|
|
|
@Override
|
|
public Packet<?> getAddEntityPacket() {
|
|
return IXplatAbstractions.INSTANCE.toVanillaClientboundPacket(
|
|
new MsgNewWallScrollS2C(new ClientboundAddEntityPacket(this),
|
|
pos, direction, scroll, getShowsStrokeOrder(), blockSize));
|
|
}
|
|
|
|
public void readSpawnData(BlockPos pos, Direction dir, ItemStack scrollItem,
|
|
boolean showsStrokeOrder, int blockSize) {
|
|
this.pos = pos;
|
|
this.scroll = scrollItem;
|
|
this.blockSize = blockSize;
|
|
|
|
this.setDirection(dir);
|
|
this.setShowsStrokeOrder(showsStrokeOrder);
|
|
|
|
this.recalculateDisplay();
|
|
this.recalculateBoundingBox();
|
|
}
|
|
|
|
@Override
|
|
public void addAdditionalSaveData(CompoundTag tag) {
|
|
tag.putByte("direction", (byte) this.direction.ordinal());
|
|
tag.put("scroll", HexUtils.serializeToNBT(this.scroll));
|
|
tag.putBoolean("showsStrokeOrder", this.getShowsStrokeOrder());
|
|
tag.putInt("blockSize", this.blockSize);
|
|
super.addAdditionalSaveData(tag);
|
|
}
|
|
|
|
@Override
|
|
public void readAdditionalSaveData(CompoundTag tag) {
|
|
this.direction = Direction.values()[tag.getByte("direction")];
|
|
this.scroll = ItemStack.of(tag.getCompound("scroll"));
|
|
this.blockSize = tag.getInt("blockSize");
|
|
|
|
this.setDirection(this.direction);
|
|
this.setShowsStrokeOrder(tag.getBoolean("showsStrokeOrder"));
|
|
|
|
this.recalculateDisplay();
|
|
this.recalculateBoundingBox();
|
|
|
|
super.readAdditionalSaveData(tag);
|
|
}
|
|
|
|
@Override
|
|
public void moveTo(double pX, double pY, double pZ, float pYaw, float pPitch) {
|
|
this.setPos(pX, pY, pZ);
|
|
}
|
|
|
|
@Override
|
|
public void lerpTo(double pX, double pY, double pZ, float pYaw, float pPitch, int pPosRotationIncrements,
|
|
boolean pTeleport) {
|
|
BlockPos blockpos = this.pos.offset(pX - this.getX(), pY - this.getY(), pZ - this.getZ());
|
|
this.setPos(blockpos.getX(), blockpos.getY(), blockpos.getZ());
|
|
}
|
|
|
|
@Nullable
|
|
@Override
|
|
public ItemStack getPickResult() {
|
|
return this.scroll.copy();
|
|
}
|
|
}
|