diff --git a/changelog.md b/changelog.md index 09dff3c8..6072c39b 100644 --- a/changelog.md +++ b/changelog.md @@ -24,6 +24,7 @@ - Bug fix: TARDIS does not take Valkyrien Skies ships into account when computing travel distance. - Bug fix: TARDIS does not automatically try to land on ships. - Bug fix: Flickering when spectating TARDIS exterior on a Valkyrien Skies ship. +- Bug fix: Grown Tardis Item crashes the game if Valkyrien Skies is installed. - Bug fix: Immersive Portals portal is not rotated correctly when door is on a Valkyrien Skies ship. - Bug fix: Fixes Console Textures having left over prefabs diff --git a/common/src/main/java/whocraft/tardis_refined/command/sub/CreateCommand.java b/common/src/main/java/whocraft/tardis_refined/command/sub/CreateCommand.java index ab84ae2e..ee396e53 100644 --- a/common/src/main/java/whocraft/tardis_refined/command/sub/CreateCommand.java +++ b/common/src/main/java/whocraft/tardis_refined/command/sub/CreateCommand.java @@ -52,9 +52,10 @@ private static int createTardis(CommandContext context) thro context.getSource().sendSystemMessage(Component.translatable(ModMessages.CMD_CREATE_TARDIS_IN_PROGRESS, tardisId)); - if (TardisHelper.createTardis(pos, level, generatedLevelKey, shellTheme, desktopTheme, Direction.NORTH, true)) { - context.getSource().sendSystemMessage(Component.translatable(ModMessages.CMD_CREATE_TARDIS_SUCCESS, tardisId)); - } + TardisHelper.createTardis( + pos, level, generatedLevelKey, shellTheme, desktopTheme, Direction.NORTH, true, + () -> context.getSource().sendSystemMessage(Component.translatable(ModMessages.CMD_CREATE_TARDIS_SUCCESS, tardisId)), () -> {} + ); return Command.SINGLE_SUCCESS; } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java index f4ca16c3..95c4c81b 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ShellBaseBlockEntity.java @@ -1,9 +1,12 @@ package whocraft.tardis_refined.common.blockentity.shell; +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.core.registries.Registries; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.resources.ResourceKey; @@ -23,31 +26,42 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.properties.BlockSetType; import whocraft.tardis_refined.TardisRefined; +import whocraft.tardis_refined.api.event.ShellChangeSources; import whocraft.tardis_refined.common.block.shell.ShellBaseBlock; import whocraft.tardis_refined.common.capability.tardis.TardisLevelOperator; import whocraft.tardis_refined.common.capability.tardis.upgrades.UpgradeHandler; import whocraft.tardis_refined.common.dimension.DimensionHandler; import whocraft.tardis_refined.common.tardis.TardisNavLocation; import whocraft.tardis_refined.common.tardis.manager.AestheticHandler; +import whocraft.tardis_refined.common.tardis.manager.TardisExteriorManager; +import whocraft.tardis_refined.common.tardis.manager.TardisInteriorManager; import whocraft.tardis_refined.common.tardis.manager.TardisPilotingManager; +import whocraft.tardis_refined.common.tardis.themes.DesktopTheme; import whocraft.tardis_refined.common.util.DimensionUtil; import whocraft.tardis_refined.common.util.PlayerUtil; import whocraft.tardis_refined.compat.ModCompatChecker; import whocraft.tardis_refined.compat.portals.ImmersivePortals; import whocraft.tardis_refined.constants.ModMessages; import whocraft.tardis_refined.constants.NbtConstants; +import whocraft.tardis_refined.patterns.ShellPatterns; import whocraft.tardis_refined.registry.TRUpgrades; import java.util.Optional; +import java.util.OptionalLong; import java.util.concurrent.atomic.AtomicBoolean; public abstract class ShellBaseBlockEntity extends BlockEntity implements ExteriorShell, BlockEntityTicker { + private static final String SETUP_DATA = "setup_data"; + public AnimationState liveliness = new AnimationState(); protected ResourceKey TARDIS_ID; private boolean hasPotentialToBeRemoved = false; private boolean placedByOtherMod = false; // We don't serialize this by design, because other mods might still create duplicates. + private SetupState setupData = null; + private OptionalLong setupTick = OptionalLong.empty(); // This is just to prevent a ConcurrentModicationException, should not be serialized. + public ShellBaseBlockEntity(BlockEntityType blockEntityType, BlockPos blockPos, BlockState blockState) { super(blockEntityType, blockPos, blockState); } @@ -76,6 +90,11 @@ public void load(CompoundTag pTag) { if (pTag.contains(NbtConstants.TARDIS_ID)) this.TARDIS_ID = ResourceKey.create(Registries.DIMENSION, new ResourceLocation(pTag.getString(NbtConstants.TARDIS_ID))); updateCurrentLocation(); + if (pTag.contains(SETUP_DATA)) { + SetupState.CODEC.parse(NbtOps.INSTANCE, pTag.get(SETUP_DATA)).result().ifPresent(setupData -> { + this.setupData = setupData; + }); + } } @Override @@ -103,14 +122,19 @@ public CompoundTag getUpdateTag() { @Override protected void saveAdditional(CompoundTag pTag) { + if (setupData != null) { + pTag.put(SETUP_DATA, SetupState.CODEC.encodeStart(NbtOps.INSTANCE, setupData).result().orElseThrow()); + } + super.saveAdditional(pTag); if (this.TARDIS_ID == null) { - TardisRefined.LOGGER.error("Error in saveAdditional: null Tardis ID (Invalid block or not terraformed yet?) [" + this.getBlockPos().toShortString() + "]"); + if (setupData == null) { + TardisRefined.LOGGER.error("Error in saveAdditional: null Tardis ID (Invalid block or not terraformed yet?) [" + this.getBlockPos().toShortString() + "]"); + } return; } - super.saveAdditional(pTag); - if (this.TARDIS_ID != null) - pTag.putString(NbtConstants.TARDIS_ID, TARDIS_ID.location().toString()); + + pTag.putString(NbtConstants.TARDIS_ID, TARDIS_ID.location().toString()); } @Override @@ -125,6 +149,65 @@ public boolean shouldSetup() { return false; } + private void setUpTardis( + BlockState blockState, Level level, BlockPos blockPos, + ResourceKey generatedLevelKey, ResourceLocation shellTheme, DesktopTheme desktopTheme, boolean openEye, + Runnable onSuccess, Runnable onFail + ) { + if (shouldSetup() && level instanceof ServerLevel serverLevel) { + + AtomicBoolean generated = new AtomicBoolean(false); + + //Set the shell with this level + setTardisId(generatedLevelKey); + + //Create the Level on demand which will create our capability + ServerLevel interior = DimensionHandler.getOrCreateInterior(serverLevel, getTardisId().location()); + + TardisLevelOperator.get(interior).ifPresent(tardisLevelOperator -> { + TardisInteriorManager intManager = tardisLevelOperator.getInteriorManager(); + TardisExteriorManager extManager = tardisLevelOperator.getExteriorManager(); + TardisPilotingManager pilotManager = tardisLevelOperator.getPilotingManager(); + if (!tardisLevelOperator.hasInitiallyGenerated()) { + intManager.generateDesktop(desktopTheme); + tardisLevelOperator.getProgressionManager().addDiscoveredLevel(serverLevel.dimension()); + Direction direction = blockState.getValue(ShellBaseBlock.FACING).getOpposite(); + TardisNavLocation navLocation = new TardisNavLocation(blockPos, direction, serverLevel); + pilotManager.setCurrentLocation(navLocation); + pilotManager.setTargetLocation(navLocation); + pilotManager.setFuel(pilotManager.getMaximumFuel()); + tardisLevelOperator.setInitiallyGenerated(true); + tardisLevelOperator.setTardisState(TardisLevelOperator.STATE_EYE_OF_HARMONY); + intManager.openTheEye(openEye); + serverLevel.setBlock(blockPos, blockState.setValue(ShellBaseBlock.OPEN, true), Block.UPDATE_ALL); + generated.set(true); + tardisLevelOperator.setShellTheme(shellTheme, ShellPatterns.getPatternsForTheme(shellTheme).get(0).id(), ShellChangeSources.ROOT_TO_TARDIS); + tardisLevelOperator.setOrUpdateExteriorBlock(navLocation, Optional.of(blockState), false, ShellChangeSources.ROOT_TO_TARDIS); + } + }); + + if (generated.get()) { + onSuccess.run(); + } else { + onFail.run(); + } + } + } + + public void setUpTardisOnNextTickIfNecessary( + ResourceKey generatedLevelKey, ResourceLocation shellTheme, DesktopTheme desktopTheme, boolean openEye, + Runnable onSuccess, Runnable onFail + ) { + if (ModCompatChecker.valkyrienSkies()) { + setupData = new SetupState(generatedLevelKey, shellTheme, desktopTheme, openEye, onSuccess, onFail); + } else { + setUpTardis( + getBlockState(), getLevel(), getBlockPos(), generatedLevelKey, shellTheme, desktopTheme, openEye, + onSuccess, onFail + ); + } + } + @Override public void onAttemptEnter(BlockState blockState, Level level, BlockPos externalShellPos, Entity entity) { if (!entity.level().isClientSide() && level instanceof ServerLevel serverLevel) { @@ -164,6 +247,20 @@ public void onAttemptEnter(BlockState blockState, Level level, BlockPos external @Override public void tick(Level level, BlockPos blockPos, BlockState blockState, ShellBaseBlockEntity blockEntity) { if (!level.isClientSide) { + if (setupData != null) { + if (setupTick.isEmpty() || setupTick.getAsLong() != level.getGameTime()) { + RootedShellBlockEntity.setUpOnNextTick = true; + setupTick = OptionalLong.of(level.getGameTime()+1); + return; + } + setUpTardis( + blockState, level, blockPos, setupData.generatedLevelKey, setupData.shellTheme, setupData.desktopTheme, + setupData.openEye, setupData.onSuccess, setupData.onFail + ); + setupData = null; + setupTick = OptionalLong.empty(); + } + ResourceKey tardisId = getTardisId(); if (tardisId == null) return; ServerLevel tardisLevel = DimensionUtil.getLevel(tardisId); @@ -264,4 +361,26 @@ public boolean isInvalidTardis(TardisLevelOperator tardisLevelOperator) { return hasPotentialToBeRemoved && !myPosition.equals(currentLocation) && !myPosition.equals(wantedDestination); } + + public record SetupState( + ResourceKey generatedLevelKey, ResourceLocation shellTheme, DesktopTheme desktopTheme, boolean openEye, + Runnable onSuccess, Runnable onFail // We can't serialize onSuccess and onFail in a good way. + ) { + + public SetupState( + ResourceKey generatedLevelKey, ResourceLocation shellTheme, + DesktopTheme desktopTheme, boolean openEye + ) { + this(generatedLevelKey, shellTheme, desktopTheme, openEye, () -> {}, () -> {}); + } + + public static final Codec CODEC = RecordCodecBuilder.create( + instance -> instance.group( + Level.RESOURCE_KEY_CODEC.fieldOf("interior_dimension").forGetter(SetupState::generatedLevelKey), + ResourceLocation.CODEC.fieldOf("shell_theme").forGetter(SetupState::shellTheme), + DesktopTheme.getCodec().fieldOf("desktop_theme").forGetter(SetupState::desktopTheme), + Codec.BOOL.fieldOf("open_eye").forGetter(SetupState::openEye) + ).apply(instance, SetupState::new) + ); + } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/items/TardisItem.java b/common/src/main/java/whocraft/tardis_refined/common/items/TardisItem.java index c2c48fef..aeabf19a 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/items/TardisItem.java +++ b/common/src/main/java/whocraft/tardis_refined/common/items/TardisItem.java @@ -77,9 +77,10 @@ public InteractionResult useOn(UseOnContext context) { MutableComponent tardisId = TardisHelper.createTardisIdComponent(generatedLevelKey.location()); server.sendSystemMessage(Component.translatable(ModMessages.CMD_CREATE_TARDIS_IN_PROGRESS, tardisId)); - if (TardisHelper.createTardis(pos, serverLevel, generatedLevelKey, shellTheme, desktopTheme, playerFacing, false)) { - server.sendSystemMessage(Component.translatable(ModMessages.CMD_CREATE_TARDIS_SUCCESS, tardisId)); - } + TardisHelper.createTardis( + pos, serverLevel, generatedLevelKey, shellTheme, desktopTheme, playerFacing, false, + () -> server.sendSystemMessage(Component.translatable(ModMessages.CMD_CREATE_TARDIS_SUCCESS, tardisId)), () -> {} + ); return super.useOn(context); } diff --git a/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java b/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java index cd309815..5e2e202d 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java +++ b/common/src/main/java/whocraft/tardis_refined/common/util/TardisHelper.java @@ -20,30 +20,21 @@ import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec2; import net.minecraft.world.phys.Vec3; -import whocraft.tardis_refined.api.event.ShellChangeSources; import whocraft.tardis_refined.api.event.TardisCommonEvents; import whocraft.tardis_refined.common.block.shell.GlobalShellBlock; -import whocraft.tardis_refined.common.block.shell.ShellBaseBlock; import whocraft.tardis_refined.common.blockentity.shell.GlobalShellBlockEntity; import whocraft.tardis_refined.common.capability.tardis.TardisLevelOperator; -import whocraft.tardis_refined.common.dimension.DimensionHandler; import whocraft.tardis_refined.common.dimension.TardisTeleportData; import whocraft.tardis_refined.common.tardis.TardisArchitectureHandler; import whocraft.tardis_refined.common.tardis.TardisNavLocation; -import whocraft.tardis_refined.common.tardis.manager.TardisExteriorManager; -import whocraft.tardis_refined.common.tardis.manager.TardisInteriorManager; -import whocraft.tardis_refined.common.tardis.manager.TardisPilotingManager; import whocraft.tardis_refined.common.tardis.themes.DesktopTheme; import whocraft.tardis_refined.compat.ModCompatChecker; import whocraft.tardis_refined.compat.valkyrienskies.VSHelper; import whocraft.tardis_refined.mixin.EndDragonFightAccessor; -import whocraft.tardis_refined.patterns.ShellPatterns; import whocraft.tardis_refined.registry.TRBlockRegistry; import whocraft.tardis_refined.registry.TRDimensionTypes; import java.util.List; -import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; import static whocraft.tardis_refined.common.block.shell.ShellBaseBlock.LOCKED; import static whocraft.tardis_refined.constants.TardisDimensionConstants.ARS_TREE_CORNER_A; @@ -89,9 +80,19 @@ public static boolean isInArsArea(BlockPos blockPos) { return blockPos.getX() >= minX && blockPos.getX() <= maxX && blockPos.getY() >= minY && blockPos.getY() <= maxY && blockPos.getZ() >= minZ && blockPos.getZ() <= maxZ; } - public static boolean createTardis(BlockPos blockPos, ServerLevel serverLevel, ResourceKey generatedLevelKey, ResourceLocation shellTheme, DesktopTheme desktopTheme, Direction facing, Boolean openEye) { + public static boolean createTardis( + BlockPos blockPos, ServerLevel serverLevel, ResourceKey generatedLevelKey, ResourceLocation shellTheme, + DesktopTheme desktopTheme, Direction facing, Boolean openEye + ) { + createTardis(blockPos, serverLevel, generatedLevelKey, shellTheme, desktopTheme, facing, openEye, () -> {}, () -> {}); + return true; + } - AtomicBoolean generated = new AtomicBoolean(false); + // Warning, onSuccess and onFail are not always guaranteed to run. Don't use them for anything important. + public static void createTardis( + BlockPos blockPos, ServerLevel serverLevel, ResourceKey generatedLevelKey, ResourceLocation shellTheme, + DesktopTheme desktopTheme, Direction facing, boolean openEye, Runnable onSuccess, Runnable onFail + ) { //Set global shell block BlockState targetBlockState = TRBlockRegistry.GLOBAL_SHELL_BLOCK.get().defaultBlockState().setValue(GlobalShellBlock.FACING, facing).setValue(GlobalShellBlock.REGEN, false).setValue(LOCKED, false).setValue(GlobalShellBlock.WATERLOGGED, serverLevel.getBlockState(blockPos).getFluidState().getType() == Fluids.WATER); @@ -99,40 +100,8 @@ public static boolean createTardis(BlockPos blockPos, ServerLevel serverLevel, R serverLevel.setBlock(blockPos, targetBlockState, Block.UPDATE_ALL); if (serverLevel.getBlockEntity(blockPos) instanceof GlobalShellBlockEntity shellBaseBlockEntity) { - if (shellBaseBlockEntity.shouldSetup()) { - - //Set the shell with this level - shellBaseBlockEntity.setTardisId(generatedLevelKey); - - //Create the Level on demand which will create our capability - ServerLevel interior = DimensionHandler.getOrCreateInterior(serverLevel, shellBaseBlockEntity.getTardisId().location()); - - TardisLevelOperator.get(interior).ifPresent(tardisLevelOperator -> { - TardisInteriorManager intManager = tardisLevelOperator.getInteriorManager(); - TardisExteriorManager extManager = tardisLevelOperator.getExteriorManager(); - TardisPilotingManager pilotManager = tardisLevelOperator.getPilotingManager(); - if (!tardisLevelOperator.hasInitiallyGenerated()) { - intManager.generateDesktop(desktopTheme); - tardisLevelOperator.getProgressionManager().addDiscoveredLevel(serverLevel.dimension()); - Direction direction = targetBlockState.getValue(ShellBaseBlock.FACING).getOpposite(); - TardisNavLocation navLocation = new TardisNavLocation(blockPos, direction, serverLevel); - pilotManager.setCurrentLocation(navLocation); - pilotManager.setTargetLocation(navLocation); - pilotManager.setFuel(pilotManager.getMaximumFuel()); - tardisLevelOperator.setInitiallyGenerated(true); - tardisLevelOperator.setTardisState(TardisLevelOperator.STATE_EYE_OF_HARMONY); - intManager.openTheEye(openEye); - serverLevel.setBlock(blockPos, targetBlockState.setValue(ShellBaseBlock.OPEN, true), Block.UPDATE_ALL); - generated.set(true); - tardisLevelOperator.setShellTheme(shellTheme, ShellPatterns.getPatternsForTheme(shellTheme).get(0).id(), ShellChangeSources.ROOT_TO_TARDIS); - tardisLevelOperator.setOrUpdateExteriorBlock(navLocation, Optional.of(targetBlockState), false, ShellChangeSources.ROOT_TO_TARDIS); - } - }); - - return generated.get(); - } + shellBaseBlockEntity.setUpTardisOnNextTickIfNecessary(generatedLevelKey, shellTheme, desktopTheme, openEye, onSuccess, onFail); } - return false; }