2021-11-09 17:29:55 +01:00
|
|
|
package com.minelittlepony.unicopia.entity;
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
import org.jetbrains.annotations.Nullable;
|
|
|
|
|
2021-11-09 17:29:55 +01:00
|
|
|
import com.minelittlepony.unicopia.EquinePredicates;
|
2021-11-12 23:05:42 +01:00
|
|
|
import com.minelittlepony.unicopia.container.SpellbookScreenHandler;
|
2022-09-11 12:22:06 +02:00
|
|
|
import com.minelittlepony.unicopia.container.SpellbookState;
|
2021-11-09 17:29:55 +01:00
|
|
|
import com.minelittlepony.unicopia.item.UItems;
|
2022-09-11 12:22:06 +02:00
|
|
|
import com.minelittlepony.unicopia.network.Channel;
|
|
|
|
import com.minelittlepony.unicopia.network.MsgSpellbookStateChanged;
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2022-09-11 12:22:06 +02:00
|
|
|
import net.fabricmc.fabric.api.screenhandler.v1.ExtendedScreenHandlerFactory;
|
2021-11-09 20:42:01 +01:00
|
|
|
import net.fabricmc.fabric.api.util.TriState;
|
2021-11-09 17:29:55 +01:00
|
|
|
import net.minecraft.entity.Entity;
|
|
|
|
import net.minecraft.entity.EntityType;
|
|
|
|
import net.minecraft.entity.damage.DamageSource;
|
|
|
|
import net.minecraft.entity.data.DataTracker;
|
|
|
|
import net.minecraft.entity.data.TrackedData;
|
|
|
|
import net.minecraft.entity.data.TrackedDataHandlerRegistry;
|
|
|
|
import net.minecraft.entity.mob.MobEntity;
|
|
|
|
import net.minecraft.entity.player.PlayerEntity;
|
2022-09-11 12:22:06 +02:00
|
|
|
import net.minecraft.entity.player.PlayerInventory;
|
2021-11-09 17:29:55 +01:00
|
|
|
import net.minecraft.item.ItemStack;
|
|
|
|
import net.minecraft.nbt.NbtCompound;
|
2022-09-11 12:22:06 +02:00
|
|
|
import net.minecraft.network.PacketByteBuf;
|
2021-11-09 17:29:55 +01:00
|
|
|
import net.minecraft.particle.ParticleTypes;
|
2022-09-11 12:22:06 +02:00
|
|
|
import net.minecraft.screen.*;
|
|
|
|
import net.minecraft.server.network.ServerPlayerEntity;
|
2021-11-09 17:29:55 +01:00
|
|
|
import net.minecraft.sound.BlockSoundGroup;
|
|
|
|
import net.minecraft.sound.SoundCategory;
|
|
|
|
import net.minecraft.sound.SoundEvents;
|
2022-09-11 12:22:06 +02:00
|
|
|
import net.minecraft.text.Text;
|
2021-11-09 17:29:55 +01:00
|
|
|
import net.minecraft.util.ActionResult;
|
|
|
|
import net.minecraft.util.Hand;
|
|
|
|
import net.minecraft.util.math.Vec3d;
|
|
|
|
import net.minecraft.world.GameRules;
|
|
|
|
import net.minecraft.world.World;
|
|
|
|
|
|
|
|
public class SpellbookEntity extends MobEntity {
|
2021-11-09 20:42:01 +01:00
|
|
|
private static final TrackedData<Boolean> AWAKE = DataTracker.registerData(SpellbookEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
|
|
|
private static final TrackedData<Boolean> BORED = DataTracker.registerData(SpellbookEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
|
|
|
private static final TrackedData<Byte> LOCKED = DataTracker.registerData(SpellbookEntity.class, TrackedDataHandlerRegistry.BYTE);
|
2021-11-09 17:29:55 +01:00
|
|
|
private static final TrackedData<Boolean> ALTERED = DataTracker.registerData(SpellbookEntity.class, TrackedDataHandlerRegistry.BOOLEAN);
|
2021-11-09 20:42:01 +01:00
|
|
|
|
|
|
|
private static final int TICKS_TO_SLEEP = 2000;
|
|
|
|
|
|
|
|
private int activeTicks = TICKS_TO_SLEEP;
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2022-09-11 12:22:06 +02:00
|
|
|
private final SpellbookState state = new SpellbookState();
|
|
|
|
|
2021-11-09 17:29:55 +01:00
|
|
|
public SpellbookEntity(EntityType<SpellbookEntity> type, World world) {
|
|
|
|
super(type, world);
|
|
|
|
setPersistent();
|
2021-11-09 20:42:01 +01:00
|
|
|
setAltered(world.random.nextInt(3) == 0);
|
2022-09-11 12:22:06 +02:00
|
|
|
if (!world.isClient) {
|
|
|
|
state.setSynchronizer(state -> {
|
|
|
|
getWorld().getPlayers().forEach(player -> {
|
|
|
|
if (player instanceof ServerPlayerEntity recipient
|
|
|
|
&& player.currentScreenHandler instanceof SpellbookScreenHandler book
|
|
|
|
&& getUuid().equals(book.entityId)) {
|
|
|
|
Channel.SERVER_SPELLBOOK_UPDATE.send(recipient, new MsgSpellbookStateChanged<>(player.currentScreenHandler.syncId, state));
|
|
|
|
}
|
|
|
|
});
|
|
|
|
});
|
|
|
|
}
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
protected void initDataTracker() {
|
|
|
|
super.initDataTracker();
|
2021-11-09 20:42:01 +01:00
|
|
|
dataTracker.startTracking(AWAKE, true);
|
|
|
|
dataTracker.startTracking(BORED, false);
|
|
|
|
dataTracker.startTracking(LOCKED, (byte)1);
|
2021-11-09 17:29:55 +01:00
|
|
|
dataTracker.startTracking(ALTERED, false);
|
|
|
|
}
|
|
|
|
|
2022-09-11 12:22:06 +02:00
|
|
|
public SpellbookState getSpellbookState() {
|
|
|
|
return state;
|
|
|
|
}
|
|
|
|
|
2021-11-09 17:29:55 +01:00
|
|
|
@Override
|
|
|
|
public ItemStack getPickBlockStack() {
|
2022-09-11 12:22:06 +02:00
|
|
|
ItemStack stack = UItems.SPELLBOOK.getDefaultStack();
|
|
|
|
stack.getOrCreateNbt().put("spellbookState", state.toNBT());
|
|
|
|
return stack;
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean isPushable() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean doesRenderOnFire() {
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
public boolean isAltered() {
|
2021-11-09 17:29:55 +01:00
|
|
|
return dataTracker.get(ALTERED);
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
public void setAltered(boolean altered) {
|
|
|
|
dataTracker.set(ALTERED, altered);
|
|
|
|
}
|
|
|
|
|
|
|
|
protected void setLocked(TriState closed) {
|
|
|
|
dataTracker.set(LOCKED, (byte)closed.ordinal());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Nullable
|
|
|
|
protected TriState isLocked() {
|
|
|
|
return TriState.values()[Math.abs(dataTracker.get(LOCKED)) % 3];
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
public boolean isOpen() {
|
|
|
|
return isLocked().orElse(isAwake()) && !isBored();
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
public boolean isAwake() {
|
|
|
|
return dataTracker.get(AWAKE);
|
|
|
|
}
|
|
|
|
|
|
|
|
public void setAwake(boolean awake) {
|
|
|
|
if (awake != isAwake()) {
|
|
|
|
dataTracker.set(AWAKE, awake);
|
|
|
|
}
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
public boolean isBored() {
|
|
|
|
return dataTracker.get(BORED);
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
public void setBored(boolean bored) {
|
|
|
|
activeTicks = TICKS_TO_SLEEP;
|
|
|
|
if (bored != isBored()) {
|
|
|
|
dataTracker.set(BORED, bored);
|
|
|
|
}
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void tick() {
|
2021-11-09 20:42:01 +01:00
|
|
|
boolean awake = isAwake();
|
|
|
|
jumping = awake && isTouchingWater();
|
2021-11-09 17:29:55 +01:00
|
|
|
super.tick();
|
2021-11-09 20:42:01 +01:00
|
|
|
|
|
|
|
if (world.isClient && isOpen()) {
|
2021-11-09 17:29:55 +01:00
|
|
|
for (int offX = -2; offX <= 1; ++offX) {
|
|
|
|
for (int offZ = -2; offZ <= 1; ++offZ) {
|
|
|
|
if (offX > -1 && offX < 1 && offZ == -1) {
|
|
|
|
offZ = 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (random.nextInt(320) == 0) {
|
|
|
|
for (int offY = 0; offY <= 1; ++offY) {
|
|
|
|
world.addParticle(ParticleTypes.ENCHANT,
|
|
|
|
getX(), getY(), getZ(),
|
|
|
|
offX/2F + random.nextFloat(),
|
|
|
|
offY/2F - random.nextFloat() + 0.5f,
|
|
|
|
offZ/2F + random.nextFloat()
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
if (awake) {
|
|
|
|
world.getOtherEntities(this, getBoundingBox().expand(2), EquinePredicates.PLAYER_UNICORN.and(e -> e instanceof PlayerEntity)).stream().findFirst().ifPresent(player -> {
|
|
|
|
setBored(false);
|
|
|
|
if (isOpen()) {
|
|
|
|
Vec3d diff = player.getPos().subtract(getPos());
|
|
|
|
double yaw = Math.atan2(diff.z, diff.x) * 180D / Math.PI - 90;
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
setHeadYaw((float)yaw);
|
|
|
|
setBodyYaw((float)yaw);
|
|
|
|
}
|
2021-11-09 17:29:55 +01:00
|
|
|
});
|
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
if (!world.isClient) {
|
|
|
|
if (activeTicks > 0 && --activeTicks <= 0) {
|
|
|
|
setBored(true);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
if (!world.isClient && world.random.nextInt(30) == 0) {
|
|
|
|
float celest = world.getSkyAngle(1) * 4;
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
boolean daytime = celest > 3 || celest < 1;
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
setAwake(daytime);
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
if (daytime != awake && daytime == isLocked().orElse(daytime)) {
|
|
|
|
setLocked(TriState.DEFAULT);
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public boolean damage(DamageSource source, float amount) {
|
|
|
|
if (!world.isClient) {
|
|
|
|
remove(Entity.RemovalReason.KILLED);
|
|
|
|
|
|
|
|
BlockSoundGroup sound = BlockSoundGroup.WOOD;
|
|
|
|
|
|
|
|
world.playSound(getX(), getY(), getZ(), sound.getBreakSound(), SoundCategory.BLOCKS, sound.getVolume(), sound.getPitch(), true);
|
|
|
|
|
|
|
|
if (world.getGameRules().getBoolean(GameRules.DO_TILE_DROPS)) {
|
2022-09-11 12:22:06 +02:00
|
|
|
dropStack(getPickBlockStack(), 1);
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ActionResult interactAt(PlayerEntity player, Vec3d vec, Hand hand) {
|
|
|
|
if (player.isSneaking()) {
|
2021-11-09 20:42:01 +01:00
|
|
|
setBored(false);
|
|
|
|
setAwake(!isOpen());
|
|
|
|
setLocked(TriState.of(isAwake()));
|
2021-11-10 18:26:25 +01:00
|
|
|
player.playSound(SoundEvents.ITEM_BOOK_PAGE_TURN, 2, 1);
|
2021-11-09 17:29:55 +01:00
|
|
|
return ActionResult.SUCCESS;
|
|
|
|
}
|
|
|
|
|
2022-09-21 22:58:29 +02:00
|
|
|
if (isOpen()) {
|
2021-11-09 20:42:01 +01:00
|
|
|
setBored(false);
|
2022-09-11 12:22:06 +02:00
|
|
|
player.openHandledScreen(new ExtendedScreenHandlerFactory() {
|
|
|
|
@Override
|
|
|
|
public Text getDisplayName() {
|
|
|
|
return SpellbookEntity.this.getDisplayName();
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public ScreenHandler createMenu(int syncId, PlayerInventory inv, PlayerEntity player) {
|
|
|
|
return new SpellbookScreenHandler(syncId, inv, ScreenHandlerContext.create(world, getBlockPos()), state, getUuid());
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void writeScreenOpeningData(ServerPlayerEntity player, PacketByteBuf buf) {
|
|
|
|
state.toPacket(buf);
|
|
|
|
}
|
|
|
|
});
|
2021-11-10 18:26:25 +01:00
|
|
|
player.playSound(SoundEvents.ITEM_BOOK_PAGE_TURN, 2, 1);
|
2021-11-09 17:29:55 +01:00
|
|
|
return ActionResult.SUCCESS;
|
|
|
|
}
|
|
|
|
|
|
|
|
return ActionResult.PASS;
|
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void readCustomDataFromNbt(NbtCompound compound) {
|
|
|
|
super.readCustomDataFromNbt(compound);
|
2021-11-09 20:42:01 +01:00
|
|
|
setAwake(compound.getBoolean("awake"));
|
|
|
|
setBored(compound.getBoolean("bored"));
|
|
|
|
setAltered(compound.getBoolean("altered"));
|
|
|
|
setLocked(compound.contains("locked") ? TriState.of(compound.getBoolean("locked")) : TriState.DEFAULT);
|
2022-09-11 12:22:06 +02:00
|
|
|
|
|
|
|
state.fromNBT(compound.getCompound("spellbookState"));
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
@Override
|
|
|
|
public void writeCustomDataToNbt(NbtCompound compound) {
|
|
|
|
super.writeCustomDataToNbt(compound);
|
2021-11-09 20:42:01 +01:00
|
|
|
compound.putBoolean("awake", isAwake());
|
|
|
|
compound.putBoolean("bored", isBored());
|
|
|
|
compound.putBoolean("altered", isAltered());
|
2021-11-09 17:29:55 +01:00
|
|
|
|
2021-11-09 20:42:01 +01:00
|
|
|
TriState locked = isLocked();
|
|
|
|
if (locked != TriState.DEFAULT) {
|
|
|
|
compound.putBoolean("locked", locked.get());
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
2022-09-11 12:22:06 +02:00
|
|
|
|
|
|
|
compound.put("spellbookState", state.toNBT());
|
2021-11-09 17:29:55 +01:00
|
|
|
}
|
|
|
|
}
|