diff --git a/build.gradle b/build.gradle index 2443df462..bf7a41d24 100644 --- a/build.gradle +++ b/build.gradle @@ -1,6 +1,6 @@ plugins { id "architectury-plugin" version "3.4-SNAPSHOT" - id "dev.architectury.loom" version "1.4+" apply false + id "dev.architectury.loom" version "1.5+" apply false } diff --git a/common/src/main/java/whocraft/tardis_refined/api/event/ShellChangeSource.java b/common/src/main/java/whocraft/tardis_refined/api/event/ShellChangeSource.java new file mode 100644 index 000000000..bf82233d4 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/api/event/ShellChangeSource.java @@ -0,0 +1,21 @@ +package whocraft.tardis_refined.api.event; + +import net.minecraft.resources.ResourceLocation; + +/** Object to identify the source of Shell updates.*/ +public class ShellChangeSource { + + private ResourceLocation id; + + public ShellChangeSource(ResourceLocation id) { + this.id = id; + } + + public ResourceLocation getId() { + return this.id; + } + + public void setId(ResourceLocation id) { + this.id = id; + } +} diff --git a/common/src/main/java/whocraft/tardis_refined/api/event/ShellChangeSources.java b/common/src/main/java/whocraft/tardis_refined/api/event/ShellChangeSources.java new file mode 100644 index 000000000..25b010155 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/api/event/ShellChangeSources.java @@ -0,0 +1,16 @@ +package whocraft.tardis_refined.api.event; + +import net.minecraft.resources.ResourceLocation; +import whocraft.tardis_refined.common.util.MiscHelper; +import whocraft.tardis_refined.common.util.RegistryHelper; + +public class ShellChangeSources { + + public static final ResourceLocation ROOT_TO_TARDIS_ID = RegistryHelper.makeKey("root_to_tardis"); + public static final ResourceLocation GENERIC_UPDATE_ID = RegistryHelper.makeKey("generic_update"); + public static final ResourceLocation REGEN_EXISTING_TARDIS_ID = RegistryHelper.makeKey("regen_existing_tardis"); + + public static final ShellChangeSource ROOT_TO_TARDIS = new ShellChangeSource(ROOT_TO_TARDIS_ID); + public static final ShellChangeSource GENERIC_UPDATE = new ShellChangeSource(GENERIC_UPDATE_ID); + public static final ShellChangeSource REGEN_EXISTING_TARDIS = new ShellChangeSource(REGEN_EXISTING_TARDIS_ID); +} diff --git a/common/src/main/java/whocraft/tardis_refined/api/event/TardisCommonEvents.java b/common/src/main/java/whocraft/tardis_refined/api/event/TardisCommonEvents.java index 5678cbc75..a8f2af8bb 100644 --- a/common/src/main/java/whocraft/tardis_refined/api/event/TardisCommonEvents.java +++ b/common/src/main/java/whocraft/tardis_refined/api/event/TardisCommonEvents.java @@ -44,9 +44,21 @@ public class TardisCommonEvents { } }); - public static final Event SHELL_CHANGE_EVENT = new Event<>(ShellChange.class, listeners -> (tardisLevelOperator, theme, isSetupTardis) -> { + public static final Event DOOR_LOCKED_EVENT = new Event<>(LockDoor.class, listeners -> (tardisLevelOperator) -> { + for(LockDoor listener : listeners) { + listener.onDoorLocked(tardisLevelOperator); + } + }); + + public static final Event DOOR_UNLOCKED_EVENT = new Event<>(UnlockDoor.class, listeners -> (tardisLevelOperator) -> { + for(UnlockDoor listener : listeners) { + listener.onDoorUnlocked(tardisLevelOperator); + } + }); + + public static final Event SHELL_CHANGE_EVENT = new Event<>(ShellChange.class, listeners -> (tardisLevelOperator, theme, shellChangeSource) -> { for (ShellChange listener : listeners) { - listener.onShellChange(tardisLevelOperator, theme, isSetupTardis); + listener.onShellChange(tardisLevelOperator, theme, shellChangeSource); } }); @@ -136,9 +148,35 @@ public interface OpenDoor { void onDoorOpen(TardisLevelOperator tardisLevelOperator); } + /** + * An event that is triggered when the TARDIS Door is locked. + */ + @FunctionalInterface + public interface LockDoor { + /** + * Called when the TARDIS door is locked. + * + * @param tardisLevelOperator The operator of the TARDIS level. + */ + void onDoorLocked(TardisLevelOperator tardisLevelOperator); + } + + /** + * An event that is triggered when the TARDIS Door is unlocked. + */ + @FunctionalInterface + public interface UnlockDoor { + /** + * Called when the TARDIS door is unlocked. + * + * @param tardisLevelOperator The operator of the TARDIS level. + */ + void onDoorUnlocked(TardisLevelOperator tardisLevelOperator); + } + /** - * An event that is triggered when the TARDIS desktp is changed. + * An event that is triggered when the TARDIS desktop is changed. * Note: Only fired once all players have left the dimension */ @FunctionalInterface @@ -177,9 +215,9 @@ public interface ShellChange { * * @param tardisLevelOperator The operator of the TARDIS level. * @param theme The theme the TARDIS changed to. - * @param isSetupTardis if the Shell Change event was caused by a Tardis being setup from a Root Shell to a fully functioning version + * @param shellChangeSource - Finds the source of the Shell Update. E.g. If the Shell Change event was caused by a Tardis being setup from a Root Shell to a fully functioning version */ - void onShellChange(TardisLevelOperator tardisLevelOperator, ResourceLocation theme, boolean isSetupTardis); + void onShellChange(TardisLevelOperator tardisLevelOperator, ResourceLocation theme, ShellChangeSource shellChangeSource); } /** diff --git a/common/src/main/java/whocraft/tardis_refined/client/renderer/blockentity/door/GlobalDoorRenderer.java b/common/src/main/java/whocraft/tardis_refined/client/renderer/blockentity/door/GlobalDoorRenderer.java index ed5eeee94..b6624ac6f 100644 --- a/common/src/main/java/whocraft/tardis_refined/client/renderer/blockentity/door/GlobalDoorRenderer.java +++ b/common/src/main/java/whocraft/tardis_refined/client/renderer/blockentity/door/GlobalDoorRenderer.java @@ -12,6 +12,7 @@ import whocraft.tardis_refined.client.model.blockentity.door.interior.ShellDoorModel; import whocraft.tardis_refined.client.model.blockentity.shell.ShellModelCollection; import whocraft.tardis_refined.common.block.door.GlobalDoorBlock; +import whocraft.tardis_refined.common.block.door.InternalDoorBlock; import whocraft.tardis_refined.common.blockentity.door.GlobalDoorBlockEntity; import whocraft.tardis_refined.compat.ModCompatChecker; import whocraft.tardis_refined.compat.portals.ImmersivePortalsClient; @@ -39,10 +40,10 @@ public void render(GlobalDoorBlockEntity blockEntity, float partialTick, PoseSta poseStack.translate(0.5F, 1.5F, 0.5F); poseStack.mulPose(Axis.ZP.rotationDegrees(180F)); BlockState blockstate = blockEntity.getBlockState(); - float rotation = blockstate.getValue(GlobalDoorBlock.FACING).toYRot(); + float rotation = blockstate.getValue(InternalDoorBlock.FACING).toYRot(); poseStack.mulPose(Axis.YP.rotationDegrees(rotation)); ResourceLocation theme = blockEntity.theme(); - boolean isOpen = blockstate.getValue(GlobalDoorBlock.OPEN); + boolean isOpen = blockstate.getValue(InternalDoorBlock.OPEN); // Render slightly off the wall to prevent z-fighting. poseStack.translate(0, 0, -0.01); diff --git a/common/src/main/java/whocraft/tardis_refined/command/sub/InteriorCommand.java b/common/src/main/java/whocraft/tardis_refined/command/sub/InteriorCommand.java index e0c224a6b..83bbd2f65 100644 --- a/common/src/main/java/whocraft/tardis_refined/command/sub/InteriorCommand.java +++ b/common/src/main/java/whocraft/tardis_refined/command/sub/InteriorCommand.java @@ -58,7 +58,7 @@ private static boolean teleportToInterior(TardisLevelOperator tardisLevelOperato if (tpLevel instanceof ServerLevel finalTpLevel) { if (tardisLevelOperator.getInternalDoor() != null) { BlockPos pos = tardisLevelOperator.getInternalDoor().getDoorPosition(); - pos = pos.relative(tardisLevelOperator.getInternalDoor().getEntryRotation(), 1); + pos = pos.relative(tardisLevelOperator.getInternalDoor().getTeleportRotation(), 1); TRTeleporter.simpleTeleport(entity, finalTpLevel, pos.getX(), pos.getY(), pos.getZ(), entity.getYHeadRot(), entity.getXRot()); return true; } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/RootPlantBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/RootPlantBlock.java index d004d71a1..9a5f3bcdf 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/RootPlantBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/RootPlantBlock.java @@ -156,11 +156,7 @@ public void onPlace(BlockState blockState, Level level, BlockPos blockPos, Block if(level instanceof ServerLevel serverLevel && level.dimensionTypeId() == TRDimensionTypes.TARDIS){ TardisLevelOperator.get(serverLevel).ifPresent(TardisHelper::playCloisterBell); - level.removeBlock(blockPos, false); - ItemEntity item = new ItemEntity(EntityType.ITEM, level); - item.setItem(new ItemStack(TRBlockRegistry.ROOT_PLANT_BLOCK.get())); - item.setPos(blockPos.getX(), blockPos.getY(), blockPos.getZ()); - level.addFreshEntity(item); + serverLevel.destroyBlock(blockPos, true); //Use Level#destroyBlock with boolean flag to TRUE so that it both destroys the block and drops its resources based off its loot table, which is the source of truth. return; } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/console/GlobalConsoleBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/console/GlobalConsoleBlock.java index 1f17cd3db..b4dd204de 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/console/GlobalConsoleBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/console/GlobalConsoleBlock.java @@ -170,50 +170,44 @@ public void animateTick(BlockState blockState, Level level, BlockPos blockPos, R @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult) { - - if (level instanceof ServerLevel serverLevel && level.dimensionTypeId() == TRDimensionTypes.TARDIS) { - - TardisLevelOperator.get(serverLevel).ifPresent(operator -> { - TardisPilotingManager pilotingManager = operator.getPilotingManager(); - - if (serverLevel.getBlockEntity(blockPos) instanceof GlobalConsoleBlockEntity consoleBlockEntity) { - if (pilotingManager.getCurrentConsole() != null) { - if (pilotingManager.getCurrentConsole() != consoleBlockEntity) { - - if (!pilotingManager.isInFlight()) { - pilotingManager.setCurrentConsole(consoleBlockEntity); - - } else { - PlayerUtil.sendMessage(player, ModMessages.CONSOLE_NOT_IN_FLIGHT, true); + if (!player.level().isClientSide()) { + if (level instanceof ServerLevel serverLevel && level.dimensionTypeId() == TRDimensionTypes.TARDIS) { + TardisLevelOperator.get(serverLevel).ifPresent(operator -> { + TardisPilotingManager pilotingManager = operator.getPilotingManager(); + if (serverLevel.getBlockEntity(blockPos) instanceof GlobalConsoleBlockEntity consoleBlockEntity) { + if (pilotingManager.getCurrentConsole() != null) { + if (pilotingManager.getCurrentConsole() != consoleBlockEntity) { + if (!pilotingManager.isInFlight()) { + pilotingManager.setCurrentConsole(consoleBlockEntity); + } else { + PlayerUtil.sendMessage(player, ModMessages.CONSOLE_NOT_IN_FLIGHT, true); + } } - + } else { + pilotingManager.setCurrentConsole(consoleBlockEntity); + consoleBlockEntity.getUpdatePacket(); } - } else { - pilotingManager.setCurrentConsole(consoleBlockEntity); - consoleBlockEntity.getUpdatePacket(); } - } - - }); - - // Creative only: Quickly complete the cooldown. - if (player.isCreative() && player.getItemInHand(interactionHand).getItem() == Items.ICE) { - var operatorOptional = TardisLevelOperator.get(serverLevel); - if (operatorOptional.isPresent()) { - var operator = operatorOptional.get(); - TardisPilotingManager pilotManager = operator.getPilotingManager(); - if (pilotManager.isOnCooldown()) { - pilotManager.endCoolDown(); + }); + // Creative only: Quickly complete the cooldown. + if (player.isCreative() && player.getItemInHand(interactionHand).getItem() == Items.ICE) { + var operatorOptional = TardisLevelOperator.get(serverLevel); + if (operatorOptional.isPresent()) { + var operator = operatorOptional.get(); + TardisPilotingManager pilotManager = operator.getPilotingManager(); - return InteractionResult.CONSUME_PARTIAL; + if (pilotManager.isOnCooldown()) { + pilotManager.endCoolDown(); + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } } - } + } } } - return super.use(blockState, level, blockPos, player, interactionHand, blockHitResult); + return InteractionResult.sidedSuccess(true); //Use InteractionResult.sidedSuccess(true) for client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/device/AntiGravityBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/device/AntiGravityBlock.java index 99bd8d758..fb500763f 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/device/AntiGravityBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/device/AntiGravityBlock.java @@ -59,7 +59,7 @@ public InteractionResult use(BlockState blockState, Level level, BlockPos blockP player.swing(interactionHand, true); level.setBlockAndUpdate(blockPos, blockState.setValue(SPACE, newSpace)); - return super.use(blockState, level, blockPos, player, interactionHand, blockHitResult); + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. } return super.use(blockState, level, blockPos, player, interactionHand, blockHitResult); } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/device/ArtronPillarBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/device/ArtronPillarBlock.java index 6a8b226de..bdf8da099 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/device/ArtronPillarBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/device/ArtronPillarBlock.java @@ -29,8 +29,8 @@ public void onPlace(BlockState blockState, Level level, BlockPos blockPos, Block super.onPlace(blockState, level, blockPos, blockState2, bl); if (level.getBlockState(blockPos.below()).getBlock() == TRBlockRegistry.ARTRON_PILLAR_PORT.get()) { - level.setBlock(blockPos, blockState.setValue(ACTIVE, true), 3); - level.playSound(null, blockPos, TRSoundRegistry.ARTRON_PILLAR.get(), SoundSource.BLOCKS, 100, 1 + (level.getRandom().nextFloat() * 0.25f)); + level.setBlock(blockPos, blockState.setValue(ACTIVE, true), Block.UPDATE_ALL); + level.playSound(null, blockPos, TRSoundRegistry.ARTRON_PILLAR_ACTIVE.get(), SoundSource.BLOCKS, 100, 1 + (level.getRandom().nextFloat() * 0.25f)); } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/device/AstralManipulatorBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/device/AstralManipulatorBlock.java index 1c6469990..bbc00b37d 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/device/AstralManipulatorBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/device/AstralManipulatorBlock.java @@ -64,7 +64,7 @@ public InteractionResult use(BlockState blockState, Level level, BlockPos blockP if (itemStack == ItemStack.EMPTY) { astralManipulatorBlockEntity.clearDisplay(); - return InteractionResult.CONSUME; + return InteractionResult.sidedSuccess(false); } else { if (itemStack.getItem() instanceof ScrewdriverItem) { diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/device/ConsoleConfigurationBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/device/ConsoleConfigurationBlock.java index 5ecce8ce9..84043314c 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/device/ConsoleConfigurationBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/device/ConsoleConfigurationBlock.java @@ -89,30 +89,33 @@ public InteractionResult use(BlockState blockState, Level level, BlockPos blockP return InteractionResult.PASS; } + if (!player.level().isClientSide()) { - var offset = blockState.getValue(FACING).getNormal(); - BlockPos consolePos = blockPos.offset(offset); + var offset = blockState.getValue(FACING).getNormal(); + BlockPos consolePos = blockPos.offset(offset); - if (player.getMainHandItem().getItem() == TRItemRegistry.PATTERN_MANIPULATOR.get()) { - this.changePattern(level, blockPos, consolePos, player); - return InteractionResult.SUCCESS; - } + if (player.getMainHandItem().getItem() == TRItemRegistry.PATTERN_MANIPULATOR.get()) { + this.changePattern(level, blockPos, consolePos, player); + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } - if (level instanceof ServerLevel serverLevel) { - TardisLevelOperator.get(serverLevel).ifPresent(operator -> { - if (!operator.getPilotingManager().isInFlight()) { - if (player.isShiftKeyDown()) { //If we are destroying the console block - this.removeGlobalConsoleBlock(consolePos, level); + if (level instanceof ServerLevel serverLevel) { + TardisLevelOperator.get(serverLevel).ifPresent(operator -> { + if (!operator.getPilotingManager().isInFlight()) { + if (player.isShiftKeyDown()) { //If we are destroying the console block + this.removeGlobalConsoleBlock(consolePos, level); + } else { + this.changeConsoleTheme(level, blockPos, consolePos); + } } else { - this.changeConsoleTheme(level, blockPos, consolePos); + PlayerUtil.sendMessage(player, Component.translatable(ModMessages.CONSOLE_CONFIGURATION_NOT_IN_FLIGHT), true); } - } else { - PlayerUtil.sendMessage(player, Component.translatable(ModMessages.CONSOLE_CONFIGURATION_NOT_IN_FLIGHT), true); - } - }); + }); + } + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. } - return InteractionResult.SUCCESS; + return InteractionResult.sidedSuccess(true); //Use InteractionResult.sidedSuccess(true) for client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. } /** diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/device/CorridorTeleporterBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/device/CorridorTeleporterBlock.java index 8ee62403c..f5ccaca40 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/device/CorridorTeleporterBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/device/CorridorTeleporterBlock.java @@ -4,19 +4,15 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.particles.ParticleTypes; import net.minecraft.server.level.ServerLevel; -import net.minecraft.util.RandomSource; import net.minecraft.world.entity.Entity; import net.minecraft.world.level.BlockGetter; import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.BaseEntityBlock; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.EntityBlock; -import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; -import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; import net.minecraft.world.phys.shapes.BooleanOp; import net.minecraft.world.phys.shapes.CollisionContext; @@ -25,12 +21,7 @@ import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import whocraft.tardis_refined.common.blockentity.device.CorridorTeleporterBlockEntity; -import whocraft.tardis_refined.common.blockentity.life.EyeBlockEntity; -import whocraft.tardis_refined.common.tardis.ExteriorShell; import whocraft.tardis_refined.common.util.ClientHelper; -import whocraft.tardis_refined.common.util.TRTeleporter; -import whocraft.tardis_refined.registry.TRBlockEntityRegistry; -import whocraft.tardis_refined.registry.TRDimensionTypes; public class CorridorTeleporterBlock extends Block implements EntityBlock { diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/device/LandingPad.java b/common/src/main/java/whocraft/tardis_refined/common/block/device/LandingPad.java index 822ceb9b2..2672359f7 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/device/LandingPad.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/device/LandingPad.java @@ -61,50 +61,52 @@ public BlockState getStateForPlacement(@NotNull BlockPlaceContext context) { @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult) { - if (level instanceof ServerLevel serverLevel) { - ItemStack itemStack = player.getItemInHand(interactionHand); - if (itemStack.getItem() instanceof KeyItem) { - var keyChain = KeyItem.getKeychain(itemStack); - if (!keyChain.isEmpty()) { - ResourceKey dimension = KeyItem.getKeychain(itemStack).get(0); + if (!player.level().isClientSide()) { + if (level instanceof ServerLevel serverLevel) { + ItemStack itemStack = player.getItemInHand(interactionHand); + if (itemStack.getItem() instanceof KeyItem) { + var keyChain = KeyItem.getKeychain(itemStack); + if (!keyChain.isEmpty()) { + ResourceKey dimension = KeyItem.getKeychain(itemStack).get(0); - if (serverLevel.isEmptyBlock(blockPos.above()) && DimensionUtil.isAllowedDimension(level.dimension())) { - var tardisLevel = Platform.getServer().getLevel(dimension); + if (serverLevel.isEmptyBlock(blockPos.above()) && DimensionUtil.isAllowedDimension(level.dimension())) { + var tardisLevel = Platform.getServer().getLevel(dimension); - var operatorOptional = TardisLevelOperator.get(tardisLevel); - if (operatorOptional.isEmpty()) { - return InteractionResult.PASS; - } - - var operator = operatorOptional.get(); - TardisPilotingManager pilotManager = operator.getPilotingManager(); - UpgradeHandler upgradeHandler = operator.getUpgradeHandler(); + var operatorOptional = TardisLevelOperator.get(tardisLevel); + if (operatorOptional.isEmpty()) { + return InteractionResult.PASS; + } - if (TRUpgrades.LANDING_PAD.get().isUnlocked(upgradeHandler) && pilotManager.beginFlight(true, null) && !pilotManager.isOnCooldown()) { - pilotManager.setTargetLocation(new TardisNavLocation(blockPos.above(), player.getDirection().getOpposite(), serverLevel)); - serverLevel.playSound(null, blockPos, SoundEvents.PLAYER_LEVELUP, SoundSource.BLOCKS, 1f, 1f); - PlayerUtil.sendMessage(player, Component.translatable(ModMessages.TARDIS_IS_ON_THE_WAY), true); - return super.use(blockState, level, blockPos, player, interactionHand, blockHitResult); - } else { + var operator = operatorOptional.get(); + TardisPilotingManager pilotManager = operator.getPilotingManager(); + UpgradeHandler upgradeHandler = operator.getUpgradeHandler(); - if (TRUpgrades.LANDING_PAD.get().isUnlocked(upgradeHandler)) { - PlayerUtil.sendMessage(player, Component.translatable(ModMessages.LANDING_PAD_TRANSIENT), true); - serverLevel.playSound(null, blockPos, SoundEvents.NOTE_BLOCK_BIT.value(), SoundSource.BLOCKS, 100, (float) (0.1 + (serverLevel.getRandom().nextFloat() * 0.25))); + if (TRUpgrades.LANDING_PAD.get().isUnlocked(upgradeHandler) && pilotManager.beginFlight(true, null) && !pilotManager.isOnCooldown()) { + pilotManager.setTargetLocation(new TardisNavLocation(blockPos.above(), player.getDirection().getOpposite(), serverLevel)); + serverLevel.playSound(null, blockPos, SoundEvents.PLAYER_LEVELUP, SoundSource.BLOCKS, 1f, 1f); + PlayerUtil.sendMessage(player, Component.translatable(ModMessages.TARDIS_IS_ON_THE_WAY), true); + return InteractionResult.PASS; } else { - serverLevel.playSound(null, blockPos, SoundEvents.FURNACE_FIRE_CRACKLE, SoundSource.BLOCKS, 1f, 1f); - PlayerUtil.sendMessage(player, Component.translatable(ModMessages.LANDING_PAD_NOT_UNLOCKED), true); - } - return super.use(blockState, level, blockPos, player, interactionHand, blockHitResult); + if (TRUpgrades.LANDING_PAD.get().isUnlocked(upgradeHandler)) { + PlayerUtil.sendMessage(player, Component.translatable(ModMessages.LANDING_PAD_TRANSIENT), true); + serverLevel.playSound(null, blockPos, SoundEvents.NOTE_BLOCK_BIT.value(), SoundSource.BLOCKS, 100, (float) (0.1 + (serverLevel.getRandom().nextFloat() * 0.25))); + } else { + serverLevel.playSound(null, blockPos, SoundEvents.FURNACE_FIRE_CRACKLE, SoundSource.BLOCKS, 1f, 1f); + PlayerUtil.sendMessage(player, Component.translatable(ModMessages.LANDING_PAD_NOT_UNLOCKED), true); + } + + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } } - } - serverLevel.playSound(null, blockPos, SoundEvents.NOTE_BLOCK_BIT.value(), SoundSource.BLOCKS, 100, (float) (0.1 + (serverLevel.getRandom().nextFloat() * 0.25))); + serverLevel.playSound(null, blockPos, SoundEvents.NOTE_BLOCK_BIT.value(), SoundSource.BLOCKS, 100, (float) (0.1 + (serverLevel.getRandom().nextFloat() * 0.25))); + } } } } - return super.use(blockState, level, blockPos, player, interactionHand, blockHitResult); + return InteractionResult.PASS; } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java index 24552ed35..7bf8b5267 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/door/GlobalDoorBlock.java @@ -32,7 +32,7 @@ public class GlobalDoorBlock extends InternalDoorBlock{ public GlobalDoorBlock(Properties properties) { super(properties); - this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(OPEN, true)); + this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(OPEN, true).setValue(LOCKED, false)); } @Nullable @@ -71,17 +71,19 @@ public BlockState getStateForPlacement(@NotNull BlockPlaceContext blockPlaceCont @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult) { if (interactionHand == InteractionHand.MAIN_HAND) { - if (level instanceof ServerLevel serverLevel) { - if (TardisLevelOperator.get(serverLevel).isPresent()) { - if (serverLevel.getBlockEntity(blockPos) instanceof GlobalDoorBlockEntity entity) { - entity.onRightClick(blockState, entity, player); - return InteractionResult.SUCCESS; + if (!player.level().isClientSide()) { + if (level instanceof ServerLevel serverLevel) { + if (TardisLevelOperator.get(serverLevel).isPresent()) { + if (serverLevel.getBlockEntity(blockPos) instanceof GlobalDoorBlockEntity entity) { + entity.onRightClick(blockState, entity, player); + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } } } } } - return InteractionResult.SUCCESS; + return InteractionResult.sidedSuccess(true); //Use InteractionResult.sidedSuccess(true) for client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. } @Override diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java index 0aeb21d10..e792d228e 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/door/InternalDoorBlock.java @@ -32,13 +32,16 @@ public class InternalDoorBlock extends BaseEntityBlock { public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; public static final BooleanProperty OPEN = BooleanProperty.create("open"); + /** This is this door instance's understanding of if it is locked or not. + *
This is needed to account for when multiple internal doors are in a Tardis, and the player is locking a different door*/ + public static final BooleanProperty LOCKED = BooleanProperty.create("locked"); protected static final VoxelShape COLLISION = Block.box(0, 0, 0, 16, 32, 16); protected static BlockEntity blockEntity; public InternalDoorBlock(Properties properties) { super(properties); - this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(OPEN, false)); + this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(OPEN, false).setValue(LOCKED, false)); } @Override @@ -77,13 +80,13 @@ public BlockEntity getDoorBlockEntity(){ @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { super.createBlockStateDefinition(builder); - builder.add(OPEN, FACING); + builder.add(OPEN, FACING, LOCKED); } @Override public BlockState getStateForPlacement(@NotNull BlockPlaceContext blockPlaceContext) { BlockState state = super.getStateForPlacement(blockPlaceContext); - return state.setValue(FACING, blockPlaceContext.getHorizontalDirection()).setValue(OPEN, false); + return state.setValue(FACING, blockPlaceContext.getHorizontalDirection()).setValue(OPEN, false).setValue(LOCKED, false); } @Override diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/door/RootShellDoorBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/door/RootShellDoorBlock.java index 0f86082da..336379ffc 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/door/RootShellDoorBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/door/RootShellDoorBlock.java @@ -27,7 +27,7 @@ public class RootShellDoorBlock extends GlobalDoorBlock { public RootShellDoorBlock(Properties properties) { super(properties); - this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(OPEN, true)); + this.registerDefaultState(this.stateDefinition.any().setValue(FACING, Direction.NORTH).setValue(OPEN, true).setValue(LOCKED, false)); } @Nullable diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/shell/GlobalShellBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/shell/GlobalShellBlock.java index b62fd1d74..375485bf7 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/shell/GlobalShellBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/shell/GlobalShellBlock.java @@ -83,23 +83,25 @@ public BlockEntityTicker getTicker(Level level, Block if (t instanceof ShellBaseBlockEntity shellBaseBlockEntity) { shellBaseBlockEntity.tick(level1, blockPos, blockState, shellBaseBlockEntity); } - }; } + }; + } @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult) { + if (!player.level().isClientSide()) { + if (level instanceof ServerLevel serverLevel) { - if (level instanceof ServerLevel serverLevel) { + if (blockHitResult.getDirection().getOpposite() == blockState.getValue(FACING)) { + if (serverLevel.getBlockEntity(blockPos) instanceof GlobalShellBlockEntity entity) { + ItemStack itemStack = player.getItemInHand(interactionHand); + entity.onRightClick(blockState, itemStack, level, blockPos, player); + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } - if (blockHitResult.getDirection().getOpposite() == blockState.getValue(FACING)) { - if (serverLevel.getBlockEntity(blockPos) instanceof GlobalShellBlockEntity entity) { - ItemStack itemStack = player.getItemInHand(interactionHand); - entity.onRightClick(blockState, itemStack, level, blockPos, player); - return InteractionResult.SUCCESS; } - } } - return InteractionResult.SUCCESS; + return InteractionResult.sidedSuccess(true); //Use InteractionResult.sidedSuccess(true) for client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/shell/RootedShellBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/shell/RootedShellBlock.java index fe36483ca..48f396190 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/shell/RootedShellBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/shell/RootedShellBlock.java @@ -49,41 +49,36 @@ public RootedShellBlock(BlockBehaviour.Properties properties) { @Override public InteractionResult use(BlockState blockState, Level level, BlockPos blockPos, Player player, InteractionHand interactionHand, BlockHitResult blockHitResult) { - - if(!player.getMainHandItem().is(Items.SHEARS)) { - - if (!blockState.getValue(OPEN)) { - PlayerUtil.sendMessage(player, Component.translatable(ModMessages.ROOT_PLANT_CUT_OPEN), true); - level.playSound(player, blockPos, SoundEvents.AZALEA_LEAVES_HIT, SoundSource.BLOCKS, 1, 0.75f + level.getRandom().nextFloat()); - return InteractionResult.SUCCESS; + if (!player.level().isClientSide()){ + if(!player.getMainHandItem().is(Items.SHEARS)) { + if (!blockState.getValue(OPEN)) { //If there are roots covering the entrance, tell the player + PlayerUtil.sendMessage(player, Component.translatable(ModMessages.ROOT_PLANT_CUT_OPEN), true); + level.playSound(player, blockPos, SoundEvents.AZALEA_LEAVES_HIT, SoundSource.BLOCKS, 1, 0.75f + level.getRandom().nextFloat()); + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for serverside side. Stops hand swinging twice. If InteractionResult = SUCCESS then the hand swing packet is sent twice. + } + return InteractionResult.FAIL; //Return fail result if the entrance is now opened, so that we don't play the message and exit this method early. } + //From now one, we assume that the player is holding a vanilla Shears item in their main hand. We will try to generate the Tardis dimension if it doesn't exist, then open the root shell door + this.setUpTardis(blockState, level, blockPos); - return InteractionResult.FAIL; - } - - - - this.setUpTardis(blockState, level, blockPos); - - if (player != null) { - - player.getMainHandItem().hurtAndBreak(1, player, arg2 -> arg2.broadcastBreakEvent(interactionHand)); - level.playSound(player, player.blockPosition(), SoundEvents.GROWING_PLANT_CROP, SoundSource.BLOCKS, 1.0f, 1.0f); - level.playSound(player, player.blockPosition(), SoundEvents.SLIME_JUMP, SoundSource.BLOCKS, 1.0f, 1.0f); + //Logic to play sounds if the player tries to break the root plant for additional sound design + if (player != null) { + player.getMainHandItem().hurtAndBreak(1, player, entity -> entity.broadcastBreakEvent(interactionHand)); + level.playSound(player, player.blockPosition(), SoundEvents.GROWING_PLANT_CROP, SoundSource.BLOCKS, 1.0f, 1.0f); + level.playSound(player, player.blockPosition(), SoundEvents.SLIME_JUMP, SoundSource.BLOCKS, 1.0f, 1.0f); + } + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for serverside side. Stops hand swinging twice. If InteractionResult = SUCCESS then the hand swing packet is sent twice. } - - - return InteractionResult.SUCCESS; //Prevents processing the ShellBaseBlockEntity generating another UUID and causing a second dimension to be created + return InteractionResult.sidedSuccess(true); //Use InteractionResult.sidedSuccess(true) which returns InteractionResult.SUCCESS, which prevents the ShellBaseBlockEntity generating another UUID and causing a second dimension to be created. } - + /** Generate the dimension and opens the Root Shell assuming that the player is holding the vanilla Shears item */ private boolean setUpTardis(BlockState blockState, Level level, BlockPos blockPos){ if (level instanceof ServerLevel serverLevel) { if (level.getBlockEntity(blockPos) instanceof ShellBaseBlockEntity shellBaseBlockEntity) { if (shellBaseBlockEntity.shouldSetup()){ - //Create a Level Key with a randomised UUID ResourceKey generatedLevelKey = ResourceKey.create(Registries.DIMENSION, new ResourceLocation(TardisRefined.MODID, UUID.randomUUID().toString())); @@ -97,10 +92,21 @@ private boolean setUpTardis(BlockState blockState, Level level, BlockPos blockPo if (!tardisLevelOperator.hasInitiallyGenerated()) { tardisLevelOperator.setupInitialCave(serverLevel, blockState, blockPos); } + //After we setup the data and desktop, open the doors. + tardisLevelOperator.setDoorClosed(false); + serverLevel.playSound(null, blockPos, SoundEvents.SHEEP_SHEAR, SoundSource.BLOCKS, 1, 1); }); return true; } + else { + if (TardisLevelOperator.get(serverLevel).isPresent()){ + TardisLevelOperator tardisLevelOperator = TardisLevelOperator.get(serverLevel).get(); + //Always open the root shell doors when this method is called to ensure that the player isn't softlocked by the early return of InteractionResult that occurs if the player isn't using shears. + tardisLevelOperator.setDoorClosed(false); + return true; + } + } } } return false; diff --git a/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java b/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java index 059a924e8..9f042684b 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java +++ b/common/src/main/java/whocraft/tardis_refined/common/block/shell/ShellBaseBlock.java @@ -23,11 +23,9 @@ import net.minecraft.world.phys.shapes.VoxelShape; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import whocraft.tardis_refined.common.tardis.ExteriorShell; +import whocraft.tardis_refined.common.blockentity.shell.ExteriorShell; import whocraft.tardis_refined.common.util.TRTeleporter; -import java.util.List; - public abstract class ShellBaseBlock extends BaseEntityBlock implements SimpleWaterloggedBlock, Fallable { public static final DirectionProperty FACING = HorizontalDirectionalBlock.FACING; diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/TardisDoorProperties.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/TardisDoorProperties.java new file mode 100644 index 000000000..a5e778fe0 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/TardisDoorProperties.java @@ -0,0 +1,36 @@ +package whocraft.tardis_refined.common.blockentity; + +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.server.level.ServerEntity; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.state.BlockState; + +public interface TardisDoorProperties { + + boolean isOpen(); + /** Source of truth logic for setting this Door to be opened/closed. */ + void setClosed(boolean closeDoor); + BlockPos getDoorPosition(); + + /** Get the position which we want the player to land at when it is arrived at the door block, for teleportation purposes. + * @implNote This should be the opposite facing of the door block*/ + BlockPos getTeleportPosition(); + + /** Get the direction which we want the player to face when it is arrived at the door block, for teleportation purposes. + * @implNote This should be the opposite facing of the door block*/ + Direction getTeleportRotation(); + + /** The true facing of the door based off its blockstate*/ + Direction getRotation(); + + void onEntityExit(ServerEntity entity); + /** Sets the internal door to be locked*/ + void setLocked(boolean locked); + /** Determines if this particular door block thinks it is locked or not. + *
When multiple internal doors are placed inside a Tardis dimension, and the player interacts on a door that is not the main door, the TardisExteriorManager may still be tracking the previous door's data + *
Hence the ExteriorManager will need to check this door's local value.*/ + boolean locked(); + void onAttemptEnter(BlockState blockState, Level level, BlockPos doorPos, Entity entity); +} diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java index 491534cc0..51fff2df8 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/AbstractDoorBlockEntity.java @@ -5,6 +5,7 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvent; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.Entity; @@ -13,6 +14,7 @@ import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.properties.BlockSetType; import whocraft.tardis_refined.common.block.door.GlobalDoorBlock; import whocraft.tardis_refined.common.block.door.InternalDoorBlock; import whocraft.tardis_refined.common.block.shell.ShellBaseBlock; @@ -23,8 +25,6 @@ import java.util.UUID; public class AbstractDoorBlockEntity extends BlockEntity implements TardisInternalDoor { - - private boolean isLocked = false; private String uuid_id; private boolean isMainDoor = false; @@ -37,7 +37,7 @@ public AbstractDoorBlockEntity(BlockEntityType blockEntityType, BlockPos bloc @Override public boolean isMainDoor() { - return isMainDoor; + return this.isMainDoor; } @Override @@ -62,12 +62,12 @@ public boolean isOpen() { } @Override - public void setClosed(boolean state) { + public void setClosed(boolean closeDoor) { BlockState blockState = this.getLevel().getBlockState(getDoorPosition()); if (blockState.getBlock() instanceof InternalDoorBlock){ Level currentLevel = getLevel(); - currentLevel.setBlock(getDoorPosition(), blockState.setValue(GlobalDoorBlock.OPEN, !state), Block.UPDATE_CLIENTS); - currentLevel.playSound(null, getDoorPosition(), isLocked ? SoundEvents.IRON_DOOR_CLOSE : SoundEvents.IRON_DOOR_OPEN, SoundSource.BLOCKS, 1, isLocked ? 1.4F : 1F); + currentLevel.setBlock(getDoorPosition(), blockState.setValue(GlobalDoorBlock.OPEN, !closeDoor), Block.UPDATE_ALL); + this.playDoorCloseSound(closeDoor); this.setChanged(); } } @@ -78,19 +78,19 @@ public BlockPos getDoorPosition() { } @Override - public BlockPos getEntryPosition() { + public BlockPos getTeleportPosition() { Direction direction = this.getBlockState().getValue(InternalDoorBlock.FACING); return this.getBlockPos().offset(direction.getOpposite().getNormal()); } @Override - public Direction getEntryRotation() { + public Direction getTeleportRotation() { return this.getBlockState().getValue(InternalDoorBlock.FACING).getOpposite(); } @Override - public Direction getDoorRotation() { + public Direction getRotation() { return this.getBlockState().getValue(InternalDoorBlock.FACING); } @@ -101,13 +101,18 @@ public void onEntityExit(ServerEntity entity) { @Override public void setLocked(boolean locked) { - this.isLocked = locked; - this.setChanged(); + BlockState blockState = this.getLevel().getBlockState(getDoorPosition()); + if (blockState.getBlock() instanceof InternalDoorBlock){ + Level currentLevel = getLevel(); + currentLevel.setBlock(this.getDoorPosition(), blockState.setValue(InternalDoorBlock.LOCKED, locked), Block.UPDATE_ALL); + this.playDoorLockedSound(locked); + this.setChanged(); + } } @Override public boolean locked() { - return isLocked; + return this.getBlockState().getValue(InternalDoorBlock.LOCKED); } public TardisLevelOperator getOperator() { @@ -129,7 +134,6 @@ protected void saveAdditional(CompoundTag compoundTag) { compoundTag.putBoolean(NbtConstants.DOOR_IS_MAIN_DOOR, this.isMainDoor); compoundTag.putString(NbtConstants.DOOR_ID, this.uuid_id); - compoundTag.putBoolean(NbtConstants.DOOR_IS_LOCKED, this.isLocked); } @Override @@ -137,7 +141,6 @@ public void load(CompoundTag compoundTag) { super.load(compoundTag); this.isMainDoor = compoundTag.getBoolean(NbtConstants.DOOR_IS_MAIN_DOOR); this.uuid_id = compoundTag.getString(NbtConstants.DOOR_ID); - this.isLocked = compoundTag.getBoolean(NbtConstants.DOOR_IS_LOCKED); } @Override @@ -151,4 +154,15 @@ public void onAttemptEnter(BlockState blockState, Level level, BlockPos doorPos, } } + public void playDoorCloseSound(boolean closeDoor){ + Level currentLevel = getLevel(); + currentLevel.playSound(null, this.getDoorPosition(), closeDoor ? SoundEvents.IRON_DOOR_CLOSE : SoundEvents.IRON_DOOR_OPEN, SoundSource.BLOCKS, 1, closeDoor ? 1.4F : 1F); + this.setChanged(); + } + + public void playDoorLockedSound(boolean lockDoor){ + Level currentLevel = getLevel(); + currentLevel.playSound(null, this.getDoorPosition(), lockDoor ? BlockSetType.IRON.doorClose() : BlockSetType.IRON.doorOpen(), SoundSource.BLOCKS, 1, lockDoor ? 1.4F : 1F); + } + } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/GlobalDoorBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/GlobalDoorBlockEntity.java index 52b41bb3f..919ac5d3b 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/GlobalDoorBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/GlobalDoorBlockEntity.java @@ -7,12 +7,14 @@ import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; -import whocraft.tardis_refined.common.block.door.GlobalDoorBlock; import whocraft.tardis_refined.common.capability.TardisLevelOperator; +import whocraft.tardis_refined.patterns.sound.ConfiguredSound; import whocraft.tardis_refined.common.tardis.themes.ShellTheme; import whocraft.tardis_refined.constants.NbtConstants; import whocraft.tardis_refined.patterns.ShellPattern; @@ -115,18 +117,43 @@ public void onRightClick(BlockState blockState, TardisInternalDoor door, Player // we know that in this instance the serverlevel has a capability. TardisLevelOperator.get(serverLevel).ifPresent(cap -> { if (cap.getInternalDoor() != door) { - cap.setInternalDoor(door); + cap.setInternalDoor(door); //Set the main door and also tell this door block that it is the main door. } if(player.isShiftKeyDown() && !cap.getPilotingManager().isInFlight()) { - cap.getExteriorManager().setLocked(!door.locked()); - door.setLocked(!door.locked()); - cap.setDoorClosed(true); + /*When multiple internal doors are in a Tardis, and the player is locking a different door, use the door block's data to update the Tardis' data */ + cap.setDoorLocked(!door.locked()); //Tell the Tardis that the door is locked + if (door.locked()) + cap.setDoorClosed(true); //Tell the Tardis that the door should be closed only if the door is being locked return; } if (!cap.getPilotingManager().isInFlight() && !door.locked()) { - cap.setDoorClosed(blockState.getValue(GlobalDoorBlock.OPEN)); + cap.setDoorClosed(door.isOpen()); //Tell the Tardis that the door should be closed if currently open, and should be open if currently closed. } }); } } + + @Override + public void playDoorCloseSound(boolean closeDoor) { + ShellPattern pattern = this.pattern(); + if (pattern != null){ + Level currentLevel = this.getLevel(); + ConfiguredSound configuredSound = pattern.soundProfile().getDoorClose(); + if (configuredSound != null){ + currentLevel.playSound(null, this.getBlockPos(), configuredSound.getSoundEvent(), SoundSource.BLOCKS, configuredSound.getPitch(), configuredSound.getVolume()); + } + } + } + + @Override + public void playDoorLockedSound(boolean lockDoor) { + ShellPattern pattern = this.pattern(); + if (pattern != null){ + Level currentLevel = this.getLevel(); + ConfiguredSound configuredSound = pattern.soundProfile().getDoorLocked(); + if (configuredSound != null){ + currentLevel.playSound(null, this.getBlockPos(), configuredSound.getSoundEvent(), SoundSource.BLOCKS, configuredSound.getPitch(), configuredSound.getVolume()); + } + } + } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/RootShellDoorBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/RootShellDoorBlockEntity.java index 9df0444a9..d14902397 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/RootShellDoorBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/RootShellDoorBlockEntity.java @@ -18,7 +18,16 @@ public void onBlockPlaced() { @Override public boolean isOpen() { - return true; + return true; //This needs to be always true so that it matches the visual look of the door having a "hole" to teleport the player through } + @Override + public void playDoorCloseSound(boolean closeDoor) { + //Leave blank + } + + @Override + public void playDoorLockedSound(boolean lockDoor) { + //Leave blank + } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java index 98d837cfa..36767ed8d 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/door/TardisInternalDoor.java @@ -1,15 +1,8 @@ package whocraft.tardis_refined.common.blockentity.door; -import net.minecraft.core.BlockPos; -import net.minecraft.core.Direction; -import net.minecraft.server.level.ServerEntity; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; +import whocraft.tardis_refined.common.blockentity.TardisDoorProperties; -import java.util.UUID; - -public interface TardisInternalDoor { +public interface TardisInternalDoor extends TardisDoorProperties { boolean isMainDoor(); void onSetMainDoor(boolean isMainDoor); @@ -17,22 +10,4 @@ public interface TardisInternalDoor { String getID(); void setID(String id); - boolean isOpen(); - void setClosed(boolean state); - - BlockPos getDoorPosition(); - - BlockPos getEntryPosition(); - Direction getEntryRotation(); - - /** The true facing of the internal door based off its blockstate*/ - Direction getDoorRotation(); - - void onEntityExit(ServerEntity entity); - - void setLocked(boolean locked); - - boolean locked(); - void onAttemptEnter(BlockState blockState, Level level, BlockPos doorPos, Entity entity); - } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ExteriorShell.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ExteriorShell.java new file mode 100644 index 000000000..ddc2ffe3c --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/ExteriorShell.java @@ -0,0 +1,19 @@ +package whocraft.tardis_refined.common.blockentity.shell; + +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.level.Level; +import whocraft.tardis_refined.common.blockentity.TardisDoorProperties; +import whocraft.tardis_refined.common.tardis.themes.DesktopTheme; + +public interface ExteriorShell extends TardisDoorProperties { + + DesktopTheme getAssociatedTheme(); + + ResourceKey getTardisId(); + + void setTardisId(ResourceKey levelKey); + + + + +} diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/GlobalShellBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/GlobalShellBlockEntity.java index 2e05745c1..d858b6515 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/GlobalShellBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/GlobalShellBlockEntity.java @@ -17,13 +17,13 @@ import net.minecraft.world.level.block.state.BlockState; import whocraft.tardis_refined.common.block.shell.GlobalShellBlock; import whocraft.tardis_refined.common.block.shell.ShellBaseBlock; -import whocraft.tardis_refined.common.blockentity.door.TardisInternalDoor; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.dimension.DimensionHandler; import whocraft.tardis_refined.common.items.KeyItem; import whocraft.tardis_refined.common.tardis.manager.AestheticHandler; import whocraft.tardis_refined.common.tardis.manager.TardisExteriorManager; import whocraft.tardis_refined.common.tardis.manager.TardisPilotingManager; +import whocraft.tardis_refined.patterns.sound.ConfiguredSound; import whocraft.tardis_refined.common.tardis.themes.ShellTheme; import whocraft.tardis_refined.common.util.PlayerUtil; import whocraft.tardis_refined.compat.portals.ImmersivePortals; @@ -34,7 +34,6 @@ import whocraft.tardis_refined.registry.TRBlockEntityRegistry; import java.util.Optional; -import java.util.concurrent.atomic.AtomicBoolean; public class GlobalShellBlockEntity extends ShellBaseBlockEntity { @@ -112,7 +111,7 @@ protected void saveAdditional(CompoundTag pTag) { public boolean onRightClick(BlockState blockState, ItemStack stack, Level level, BlockPos blockPos, Player player) { - // We do not want interactions if the TARDIS is in Flight + // We do not want interactions if the TARDIS is regenerating itself if (blockState.getValue(ShellBaseBlock.REGEN)) { return false; } @@ -126,15 +125,14 @@ public boolean onRightClick(BlockState blockState, ItemStack stack, Level level, TardisPilotingManager tardisPilotingManager = tardisLevelOperator.getPilotingManager(); AestheticHandler aestheticHandler = tardisLevelOperator.getAestheticHandler(); TardisExteriorManager exteriorManager = tardisLevelOperator.getExteriorManager(); - TardisInternalDoor internalDoor = tardisLevelOperator.getInternalDoor(); - // We do not want interactions in Flight + // We do not want interactions if the Tardis is still taking off or landing if (tardisPilotingManager.isInFlight()) return false; // Shearing the TARDIS if (stack.is(Items.SHEARS) && aestheticHandler.getShellTheme() == ShellTheme.HALF_BAKED.getId()) { aestheticHandler.setShellTheme(ShellTheme.FACTORY.getId(), ShellPatterns.DEFAULT.id(), tardisPilotingManager.getCurrentLocation()); - level.playSound(null, blockPos, SoundEvents.SHEEP_SHEAR, SoundSource.BLOCKS, 1, 1); + level.playSound(null, blockPos, SoundEvents.GROWING_PLANT_CROP, SoundSource.BLOCKS, 1, 1); spawnCoralItems(); return true; } @@ -142,16 +140,15 @@ public boolean onRightClick(BlockState blockState, ItemStack stack, Level level, boolean validKey = KeyItem.keychainContains(stack, TARDIS_ID); if (validKey) { boolean locked = !exteriorManager.locked(); - exteriorManager.setLocked(locked); - internalDoor.setLocked(locked); + tardisLevelOperator.setDoorLocked(locked); tardisLevelOperator.setDoorClosed(locked); PlayerUtil.sendMessage(player, Component.translatable(locked ? ModMessages.DOOR_LOCKED : ModMessages.DOOR_UNLOCKED), true); return true; } - if(!exteriorManager.locked()){ - level.setBlock(blockPos, blockState.cycle(GlobalShellBlock.OPEN), Block.UPDATE_ALL); - tardisLevelOperator.setDoorClosed(blockState.getValue(GlobalShellBlock.OPEN)); + if(!exteriorManager.locked()){ //If the Tardis thinks it is not locked, open this shell's door + level.setBlock(blockPos, blockState.cycle(GlobalShellBlock.OPEN), Block.UPDATE_ALL); //Cycle the door to open/closed + tardisLevelOperator.setDoorClosed(blockState.getValue(GlobalShellBlock.OPEN)); //Now update both the internal door and re-update the external shell for good measure too. return true; } } @@ -161,7 +158,7 @@ public boolean onRightClick(BlockState blockState, ItemStack stack, Level level, public void sendUpdates() { level.updateNeighbourForOutputSignal(worldPosition, getBlockState().getBlock()); - level.sendBlockUpdated(worldPosition, level.getBlockState(worldPosition), level.getBlockState(worldPosition), 3); + level.sendBlockUpdated(worldPosition, level.getBlockState(worldPosition), level.getBlockState(worldPosition), Block.UPDATE_ALL); setChanged(); } @@ -174,4 +171,28 @@ public void spawnCoralItems() { Containers.dropItemStack(level, currentPos.getX(), currentPos.getY(), currentPos.getZ() , coralItem); } } + + @Override + public void playDoorCloseSound(boolean closeDoor) { + ShellPattern pattern = this.pattern(); + if (pattern != null){ + Level currentLevel = this.getLevel(); + ConfiguredSound configuredSound = pattern.soundProfile().getDoorClose(); + if (configuredSound != null){ + currentLevel.playSound(null, this.getBlockPos(), configuredSound.getSoundEvent(), SoundSource.BLOCKS, configuredSound.getPitch(), configuredSound.getVolume()); + } + } + } + + @Override + public void playDoorLockedSound(boolean lockDoor) { + ShellPattern pattern = this.pattern(); + if (pattern != null){ + Level currentLevel = this.getLevel(); + ConfiguredSound configuredSound = pattern.soundProfile().getDoorLocked(); + if (configuredSound != null){ + currentLevel.playSound(null, this.getBlockPos(), configuredSound.getSoundEvent(), SoundSource.BLOCKS, configuredSound.getPitch(), configuredSound.getVolume()); + } + } + } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/RootedShellBlockEntity.java b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/RootedShellBlockEntity.java index 4aedb7f7f..0d6bb59bb 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/RootedShellBlockEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/blockentity/shell/RootedShellBlockEntity.java @@ -15,4 +15,14 @@ public RootedShellBlockEntity(BlockPos blockPos, BlockState blockState) { public DesktopTheme getAssociatedTheme() { return TardisDesktops.DEFAULT_OVERGROWN_THEME; } + + @Override + public void playDoorCloseSound(boolean closeDoor) { + //Leave blank + } + + @Override + public void playDoorLockedSound(boolean lockDoor) { + //Leave blank + } } 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 2e4c92272..d8eebc5fd 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 @@ -8,7 +8,10 @@ import net.minecraft.network.protocol.game.ClientboundBlockEntityDataPacket; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.level.ServerEntity; import net.minecraft.server.level.ServerLevel; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.AnimationState; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Player; @@ -18,13 +21,14 @@ import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; 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.common.block.door.InternalDoorBlock; import whocraft.tardis_refined.common.block.shell.ShellBaseBlock; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.capability.upgrades.UpgradeHandler; import whocraft.tardis_refined.registry.TRUpgrades; import whocraft.tardis_refined.common.dimension.DimensionHandler; -import whocraft.tardis_refined.common.tardis.ExteriorShell; import whocraft.tardis_refined.common.tardis.TardisDesktops; import whocraft.tardis_refined.common.tardis.TardisNavLocation; import whocraft.tardis_refined.common.tardis.manager.TardisPilotingManager; @@ -74,7 +78,7 @@ public CompoundTag getUpdateTag() { @Override protected void saveAdditional(CompoundTag pTag) { if (this.TARDIS_ID == null) { - TardisRefined.LOGGER.error("Error in saveAdditional: null Tardis ID (could this be an invalid block?) [" + this.getBlockPos().toShortString() + "]"); + TardisRefined.LOGGER.error("Error in saveAdditional: null Tardis ID (Invalid block or not terraformed yet?) [" + this.getBlockPos().toShortString() + "]"); return; } @@ -99,7 +103,7 @@ public boolean shouldSetup() { public void onAttemptEnter(BlockState blockState, Level level, BlockPos externalShellPos, Entity entity) { if (!entity.level().isClientSide() && level instanceof ServerLevel serverLevel) { if (this.TARDIS_ID == null) { - TardisRefined.LOGGER.error("Error in onAttemptEnter: null Tardis ID (could this be an invalid block?) [" + externalShellPos.toShortString() + "]"); + TardisRefined.LOGGER.error("Error in onAttemptEnter: null Tardis ID (Invalid block or not terraformed yet?) [" + externalShellPos.toShortString() + "]"); return; } ServerLevel interior = DimensionHandler.getOrCreateInterior(serverLevel, this.TARDIS_ID.location()); @@ -129,12 +133,6 @@ public void onAttemptEnter(BlockState blockState, Level level, BlockPos external } - @Override - public BlockPos getExitPosition() { - Direction direction = getBlockState().getValue(ShellBaseBlock.FACING); - return this.getBlockPos().offset(direction.getOpposite().getNormal()); - } - @Override public DesktopTheme getAssociatedTheme() { return TardisDesktops.FACTORY_THEME; @@ -171,4 +169,72 @@ public void tick(Level level, BlockPos blockPos, BlockState blockState, ShellBas }); } } + + @Override + public boolean isOpen() { + return this.getBlockState().getValue(ShellBaseBlock.OPEN); + } + + @Override + public void setClosed(boolean closeDoor) { + BlockPos blockPos = this.getBlockPos(); + BlockState blockState = this.getLevel().getBlockState(blockPos); + if (blockState.getBlock() instanceof ShellBaseBlock shellBaseBlock){ + this.getLevel().setBlock(blockPos, blockState.setValue(ShellBaseBlock.OPEN, !closeDoor), Block.UPDATE_ALL); + this.playDoorCloseSound(closeDoor); + this.setChanged(); + } + } + + @Override + public void onEntityExit(ServerEntity entity) { + + } + + @Override + public void setLocked(boolean locked) { + BlockState blockState = this.getLevel().getBlockState(this.getBlockPos()); + if (blockState.getBlock() instanceof ShellBaseBlock shellBaseBlock){ + this.getLevel().setBlock(this.getBlockPos(), blockState.setValue(ShellBaseBlock.LOCKED, locked), Block.UPDATE_ALL); + this.playDoorLockedSound(locked); + this.setChanged(); + } + } + + @Override + public boolean locked() { + return this.getBlockState().getValue(ShellBaseBlock.LOCKED); + } + + @Override + public BlockPos getTeleportPosition() { + Direction direction = getBlockState().getValue(ShellBaseBlock.FACING); + return this.getBlockPos().offset(direction.getOpposite().getNormal()); + } + + @Override + public Direction getRotation() { + return this.getBlockState().getValue(ShellBaseBlock.FACING); + } + + @Override + public Direction getTeleportRotation() { + return this.getBlockState().getValue(ShellBaseBlock.FACING).getOpposite(); + } + + @Override + public BlockPos getDoorPosition() { + return this.getBlockPos(); + } + + public void playDoorCloseSound(boolean closeDoor){ + Level currentLevel = getLevel(); + currentLevel.playSound(null, this.getBlockPos(), closeDoor ? SoundEvents.IRON_DOOR_CLOSE : SoundEvents.IRON_DOOR_OPEN, SoundSource.BLOCKS, 1, closeDoor ? 1.4F : 1F); + this.setChanged(); + } + + public void playDoorLockedSound(boolean lockDoor){ + Level currentLevel = getLevel(); + currentLevel.playSound(null, this.getBlockPos(), lockDoor ? BlockSetType.IRON.doorClose() : BlockSetType.IRON.doorOpen(), SoundSource.BLOCKS, 1, lockDoor ? 1.4F : 1F); + } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/capability/TardisLevelOperator.java b/common/src/main/java/whocraft/tardis_refined/common/capability/TardisLevelOperator.java index 2b4ad49c6..233f02089 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/capability/TardisLevelOperator.java +++ b/common/src/main/java/whocraft/tardis_refined/common/capability/TardisLevelOperator.java @@ -5,36 +5,50 @@ import net.minecraft.core.Direction; import net.minecraft.nbt.CompoundTag; import net.minecraft.nbt.NbtUtils; +import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.material.Fluids; +import whocraft.tardis_refined.api.event.ShellChangeSource; +import whocraft.tardis_refined.api.event.ShellChangeSources; import whocraft.tardis_refined.api.event.TardisCommonEvents; import whocraft.tardis_refined.client.TardisClientData; +import whocraft.tardis_refined.common.block.shell.GlobalShellBlock; import whocraft.tardis_refined.common.block.shell.ShellBaseBlock; import whocraft.tardis_refined.common.blockentity.door.RootShellDoorBlockEntity; import whocraft.tardis_refined.common.blockentity.door.TardisInternalDoor; +import whocraft.tardis_refined.common.blockentity.shell.GlobalShellBlockEntity; import whocraft.tardis_refined.common.capability.upgrades.UpgradeHandler; import whocraft.tardis_refined.common.hum.TardisHums; -import whocraft.tardis_refined.common.tardis.ExteriorShell; +import whocraft.tardis_refined.common.blockentity.shell.ExteriorShell; import whocraft.tardis_refined.common.tardis.TardisArchitectureHandler; import whocraft.tardis_refined.common.tardis.TardisDesktops; import whocraft.tardis_refined.common.tardis.TardisNavLocation; import whocraft.tardis_refined.common.tardis.manager.*; +import whocraft.tardis_refined.common.tardis.themes.ShellTheme; import whocraft.tardis_refined.common.util.TardisHelper; import whocraft.tardis_refined.compat.ModCompatChecker; import whocraft.tardis_refined.compat.portals.ImmersivePortals; import whocraft.tardis_refined.constants.NbtConstants; +import whocraft.tardis_refined.patterns.ShellPattern; +import whocraft.tardis_refined.patterns.ShellPatterns; +import whocraft.tardis_refined.registry.TRBlockRegistry; import java.util.Optional; import java.util.UUID; import static whocraft.tardis_refined.common.block.shell.ShellBaseBlock.OPEN; +import static whocraft.tardis_refined.common.block.shell.ShellBaseBlock.REGEN; -public class TardisLevelOperator { +public class TardisLevelOperator{ private final Level level; + private final ResourceKey levelKey; private boolean hasInitiallyGenerated = false; private TardisInternalDoor internalDoor = null; @@ -58,6 +72,7 @@ public class TardisLevelOperator { public TardisLevelOperator(Level level) { this.level = level; + this.levelKey = level.dimension(); this.exteriorManager = new TardisExteriorManager(this); this.interiorManager = new TardisInteriorManager(this); this.pilotingManager = new TardisPilotingManager(this); @@ -135,14 +150,18 @@ public void deserializeNBT(CompoundTag tag) { } public Level getLevel() { - return level; + return this.level; + } + + public ResourceKey getLevelKey() { + return this.levelKey; } public void tick(ServerLevel level) { if (interiorManager != null) { interiorManager.tick(level);} if (pilotingManager != null) { pilotingManager.tick(level);} - if (flightDanceManager != null) { flightDanceManager.tick();} + if (flightDanceManager != null) { flightDanceManager.tick(level);} var shouldSync = level.getGameTime() % 40 == 0; @@ -181,8 +200,8 @@ public boolean enterTardis(Entity entity, BlockPos externalShellPos, ServerLevel if (this.level instanceof ServerLevel targetServerLevel) { - BlockPos targetPosition = internalDoor != null ? internalDoor.getEntryPosition() : TardisArchitectureHandler.DESKTOP_CENTER_POS.above(); - Direction doorDirection = internalDoor != null ? internalDoor.getDoorRotation() : entity.getDirection(); + BlockPos targetPosition = internalDoor != null ? internalDoor.getTeleportPosition() : TardisArchitectureHandler.DESKTOP_CENTER_POS.above(); + Direction doorDirection = internalDoor != null ? internalDoor.getTeleportRotation() : entity.getDirection(); TardisNavLocation sourceLocation = new TardisNavLocation(externalShellPos, shellDirection, shellLevel); TardisNavLocation targetLocation = new TardisNavLocation(targetPosition, doorDirection, targetServerLevel); @@ -220,51 +239,215 @@ public boolean exitTardis(Entity entity, ServerLevel doorLevel, BlockPos doorPos if (this.pilotingManager.getCurrentLocation() != null) { - TardisNavLocation targetLocation = this.pilotingManager.getCurrentLocation(); - BlockPos exteriorPos = targetLocation.getPosition(); - ServerLevel targetLevel = targetLocation.getLevel(); - Direction exteriorDirection = targetLocation.getDirection().getOpposite(); + TardisNavLocation currentLocation = this.pilotingManager.getCurrentLocation(); + BlockPos exteriorPos = currentLocation.getPosition(); + ServerLevel targetLevel = currentLocation.getLevel(); + Direction targetDirection = currentLocation.getDirection().getOpposite(); BlockPos teleportPos = exteriorPos; if (targetLevel.getBlockEntity(exteriorPos) instanceof ExteriorShell exteriorShell) { - teleportPos = exteriorShell.getExitPosition(); + teleportPos = exteriorShell.getTeleportPosition(); + targetDirection = exteriorShell.getTeleportRotation(); //Use the exterior shell's facing instead of the target direction to cover a case where the direction is changed as the player exits } TardisNavLocation sourceLocation = new TardisNavLocation(doorPos, doorDirection, doorLevel); - TardisNavLocation destinationLocation = new TardisNavLocation(teleportPos, exteriorDirection, targetLevel); + TardisNavLocation destinationLocation = new TardisNavLocation(teleportPos, targetDirection, targetLevel); TardisHelper.teleportEntityTardis(this, entity, sourceLocation, destinationLocation, false); + return true; + } + + return false; + } + + public void forceEjectAllPlayers(){ + for (Player player : this.level.players()){ + if (player instanceof ServerPlayer serverPlayer){ + this.forceEjectPlayer(serverPlayer); + } + } + } + + /** Helper to automatically teleport the player to the Tardis' current location + *
Used for emergency eject feature or to prevent players from remaining in the Tardis during desktop generaton*/ + public boolean forceEjectPlayer(ServerPlayer player){ + if (player != null) { + TardisNavLocation location = this.getPilotingManager().getCurrentLocation(); + return this.exitTardis(player, location.getLevel(), location.getPosition(), location.getDirection(), true); + } + return false; + } + + /** Unified logic to update blockstates and data + * + * @param startRegen - True if we should mark the Tardis is regenerating itself. + * @return True if successfully triggered, false if failed + */ + public boolean triggerRegenState(boolean startRegen) { + + TardisPilotingManager pilotingManager = this.getPilotingManager(); + if (pilotingManager == null) { + return false; + } + + TardisNavLocation currentPosition = this.getPilotingManager().getCurrentLocation(); + if(currentPosition == null) return false; + BlockPos currentBlockPos = currentPosition.getPosition(); + ServerLevel currentLevel = currentPosition.getLevel(); + + BlockState state = currentLevel.getBlockState(currentBlockPos); + if (currentLevel == null) return false; + if (state.getBlock() instanceof ShellBaseBlock shellBaseBlock && state.hasProperty(REGEN)) { //Check if this is our shell block and that its type has a Regen block state + if (startRegen) //Only close the door if we are starting the regeneration process. Otherwise, don't update the door. + this.setDoorClosed(true); //Set the door closed. Must call this instead of simply updating the blockstate because this way we update the internal door too. + this.setDoorLocked(startRegen); //Set the exterior shell door to be locked. + + //Fetch a new instance of the Blockstate after we have applied the door closing and locking updates above. + //This is needed to ensure the LOCKED and OPEN blockstate properties on the Shell block are being kept. + BlockState blockStateAfterDoorUpdates = currentLevel.getBlockState(currentBlockPos); + + //Extra sanity check to ensure the player didn't rapidly replace the block at this position with another block. + //Unlikely, but you never know what players are capable of. + if (blockStateAfterDoorUpdates.hasProperty(ShellBaseBlock.REGEN)){ + BlockState updatedBlockState = blockStateAfterDoorUpdates.setValue(ShellBaseBlock.REGEN, startRegen); //Set the block to be in a regenerating state + if (this.getTardisState() == STATE_CAVE || this.getTardisState() == STATE_TERRAFORMED_NO_EYE){ //If either in a cave state or terraformed without an activated eye of harmony, assume we are transforming from root shell to half baked Tardis + //If starting regen for a root shell, update, but do not, create a new blockstate instance + //We only want to create a new blockstate instance when generation is finished so that a new GlobalShellBlockEntity instance can be placed with the half-baked theme applied + //The logic to handle whether to use the passed in blockstate is being handled in setOrUpdateExteriorBlock + this.setOrUpdateExteriorBlock(currentPosition, Optional.of(updatedBlockState), startRegen, ShellChangeSources.ROOT_TO_TARDIS); + } + else { + this.setOrUpdateExteriorBlock(currentPosition, Optional.of(updatedBlockState), startRegen, ShellChangeSources.REGEN_EXISTING_TARDIS); + } + return true; + } + } + return false; + } + /** Convenience method to use when we are going to update the exterior block but we are not setting up a new Tardis + * @param location - location of the block we are updating + * @param targetBlockState - Only leave this empty if we are landing the Tardis after finishing flight, otherwise provide a value to indicate we are updating specific data on an existing Tardis shell. + * @implNote You must call this after calling {@link TardisLevelOperator#setShellTheme(ResourceLocation, ResourceLocation, ShellChangeSource)} + * */ + public void setOrUpdateExteriorBlock(TardisNavLocation location, Optional targetBlockState){ + setOrUpdateExteriorBlock(location, targetBlockState, false, ShellChangeSources.GENERIC_UPDATE); + } + + /** Common logic to set or update the exterior shell block. This is needed to ensure we preserve data on the exterior shell such as Shell Patterns. + * @implNote If we have updated the ShellTheme but haven't updated the Exterior data yet, you must call this after calling {@link TardisLevelOperator#setShellTheme(ResourceLocation, ResourceLocation, ShellChangeSource)} + * @param location - target position we are performing block updates on. + * @param overridingBlockState - Pass in an updated exterior shell blockstate with the data you want to include. Only leave this empty if we are landing the Tardis after finishing flight, otherwise provide a value to indicate we are updating specific data on an existing Tardis shell. + * @param startingRegen - If we are starting or finishing the regenerating of the Tardis. e.g. During Desktop generation. + * @param shellChangeSource - Source of the shell update. If the Shell Change event was caused by a Tardis being setup from a Root Shell to a fully functioning version. + */ + public void setOrUpdateExteriorBlock(TardisNavLocation location, Optional overridingBlockState, boolean startingRegen, ShellChangeSource shellChangeSource){ + AestheticHandler aestheticHandler = this.getAestheticHandler(); + ResourceLocation theme = (aestheticHandler.getShellTheme() != null) ? aestheticHandler.getShellTheme() : ShellTheme.HALF_BAKED.getId(); + ShellTheme shellTheme = ShellTheme.getShellTheme(theme); + ShellPattern shellPattern = aestheticHandler.getShellTheme() != null ? aestheticHandler.shellPattern() : null; + + ServerLevel targetLevel = location.getLevel(); + BlockPos targetLocation = location.getPosition(); + + //In the below logic, we will check if we need to update the existing blockstate. Otherwise, utilise a new blockstate instance of the exterior block + + //New instance of an exterior block created if we need to use it, such as for when the Tardis starts landing after flight, or finishing the root shell to half baked terraforming + //Do not update the REGEN, OPEN or LOCKED property, because that should be manually called when player interacts with the door, or during events the Tardis triggers such as regenerating desktop, or the DoorControl + BlockState newExteriorBlock = TRBlockRegistry.GLOBAL_SHELL_BLOCK.get().defaultBlockState().setValue(ShellBaseBlock.FACING, location.getDirection().getOpposite()) + .setValue(ShellBaseBlock.REGEN, false) + .setValue(ShellBaseBlock.WATERLOGGED, location.getLevel().getBlockState(targetLocation).getFluidState().getType() == Fluids.WATER); + + //If the Tardis is landing after a flight or we are setting up a Tardis for the first time, utilise a new blockstate. + //Otherwise, simply update the values of the passed-in blockstate so that we don't need to change things we don't want. + BlockState selectedBlockState; + if (shellChangeSource == ShellChangeSources.ROOT_TO_TARDIS){ + //If starting regen for a root shell, update, but do not, create a new blockstate instance + //We only want to create a new blockstate instance when generation is finished so that a new GlobalShellBlockEntity instance can be placed with the half-baked theme applied + selectedBlockState = startingRegen ? overridingBlockState.orElse(newExteriorBlock) : newExteriorBlock; } + else { + //Otherwise, if we are regenerating a Tardis that is fully terraformed and eye of harmony is activated, use the passed in blockstate for specific data updates, or if the provided blockstate is NULL, use the new exterior shell instance + selectedBlockState = overridingBlockState.orElse(newExteriorBlock); + } + + //Update the FACING and WATERLOGGED blockstate property on the Shell block. + //Do not update the REGEN, OPEN or LOCKED property, because that should be manually called when player interacts with the door, or during events the Tardis triggers such as regenerating desktop, or the DoorControl + BlockState updatedBlockState = selectedBlockState.setValue(ShellBaseBlock.FACING, location.getDirection().getOpposite()) + .setValue(ShellBaseBlock.WATERLOGGED, location.getLevel().getBlockState(targetLocation).getFluidState().getType() == Fluids.WATER); + + if (updatedBlockState.hasProperty(GlobalShellBlock.LIT) && shellTheme != null){ //Special logic to account for RootedShellBlock not having the LIT blockstate property + updatedBlockState.setValue(GlobalShellBlock.LIT, shellTheme.producesLight()); + } + - return true; + //Place the exterior block + targetLevel.setBlock(targetLocation, updatedBlockState, Block.UPDATE_ALL); + //Copy over important data points such as patterns, and update the internal doors + //TODO: Implement a system that allows updating of specific Tardis data, so that we don't need to update the theme and patterns when we don't need to. + if (theme != null && shellPattern != null) + this.setShellTheme(theme, shellPattern.getThemeId(), shellChangeSource); + + targetLevel.sendBlockUpdated(targetLocation, updatedBlockState, updatedBlockState, Block.UPDATE_CLIENTS); } + /** Unified logic to close or open a door + *
Updates both internal door and exterior shell door OPEN state + *
Fires the CloseDoor/OpenDoor events*/ public void setDoorClosed(boolean closeDoor) { TardisInternalDoor intDoor = getInternalDoor(); - + //Closed the internal door if (intDoor != null) { intDoor.setClosed(closeDoor); } + //Close the exterior shell door + if (this.pilotingManager != null) { + if (this.pilotingManager.getCurrentLocation() != null) { + this.exteriorManager.setDoorClosed(closeDoor); + } + } + + //After closing/opening both exterior and interior doors, fire the events if (closeDoor) { TardisCommonEvents.DOOR_CLOSED_EVENT.invoker().onDoorClosed(this); } else { TardisCommonEvents.DOOR_OPENED_EVENT.invoker().onDoorOpen(this); } + } + /** Unified logic to lock or unlock a door + *
Updates both internal door and exterior shell door LOCK state + *
Fires the LockDoor/UnlockDoor events*/ + public void setDoorLocked(boolean lockDoor) { + TardisInternalDoor intDoor = getInternalDoor(); + + if (intDoor != null) { + intDoor.setLocked(lockDoor); + } + if (this.pilotingManager != null) { if (this.pilotingManager.getCurrentLocation() != null) { - this.exteriorManager.setDoorClosed(closeDoor); + if (this.exteriorManager != null){ + this.exteriorManager.setLocked(lockDoor); + } } } + //After locking/unlocking both exterior and interior doors, fire the events + if (lockDoor) { + TardisCommonEvents.DOOR_LOCKED_EVENT.invoker().onDoorLocked(this); + } else { + TardisCommonEvents.DOOR_UNLOCKED_EVENT.invoker().onDoorUnlocked(this); + } + } - public void setShellTheme(ResourceLocation theme, ResourceLocation shellPattern, boolean setupTardis) { - this.getAestheticHandler().setShellTheme(theme, shellPattern, setupTardis, this.getPilotingManager().getCurrentLocation()); - tardisClientData.setShellTheme(theme); + /** Unified logic to update the Tardis' ShellTheme and Pattern, as well as the exterior and internal doors*/ + public void setShellTheme(ResourceLocation shellTheme, ResourceLocation shellPattern, ShellChangeSource shellChangeSource) { + this.getAestheticHandler().setShellTheme(shellTheme, shellPattern, this.getPilotingManager().getCurrentLocation()); + tardisClientData.setShellTheme(shellTheme); tardisClientData.setShellPattern(aestheticHandler.shellPattern().id()); tardisClientData.sync(); - TardisCommonEvents.SHELL_CHANGE_EVENT.invoker().onShellChange(this, theme, setupTardis); + TardisCommonEvents.SHELL_CHANGE_EVENT.invoker().onShellChange(this, shellTheme, shellChangeSource); } /** @@ -280,6 +463,9 @@ public void setInternalDoor(TardisInternalDoor door) { if (door != null) //If the new door value is not null this.internalDoor.onSetMainDoor(true); } + /** Sets up data and prepares the desktop theme for when the Tardis is generating for the first time. + *
DO NOT update the exterior/internal doors here, because door updating logic is unified in {@link TardisLevelOperator#triggerRegenState(boolean)} + *
We do not need to open the Tardis doors here because it is always being called in {@link whocraft.tardis_refined.common.block.shell.RootedShellBlock}*/ public void setupInitialCave(ServerLevel shellServerLevel, BlockState shellBlockState, BlockPos shellBlockPos) { this.interiorManager.generateDesktop(TardisDesktops.DEFAULT_OVERGROWN_THEME); @@ -288,8 +474,6 @@ public void setupInitialCave(ServerLevel shellServerLevel, BlockState shellBlock this.pilotingManager.setCurrentLocation(navLocation); this.pilotingManager.setTargetLocation(navLocation); - shellServerLevel.setBlock(shellBlockPos, shellBlockState.setValue(OPEN, true), Block.UPDATE_ALL); - this.setInitiallyGenerated(true); this.setTardisState(TardisLevelOperator.STATE_CAVE); this.interiorManager.setHumEntry(TardisHums.CAVE); diff --git a/common/src/main/java/whocraft/tardis_refined/common/dimension/DimensionHandler.java b/common/src/main/java/whocraft/tardis_refined/common/dimension/DimensionHandler.java index 20b61661c..63cd0c392 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/dimension/DimensionHandler.java +++ b/common/src/main/java/whocraft/tardis_refined/common/dimension/DimensionHandler.java @@ -14,6 +14,7 @@ import net.minecraft.world.level.dimension.LevelStem; import net.minecraft.world.level.storage.LevelStorageSource; import whocraft.tardis_refined.TardisRefined; +import whocraft.tardis_refined.common.util.RegistryHelper; import whocraft.tardis_refined.common.world.ChunkGenerators; import whocraft.tardis_refined.common.world.chunk.TardisChunkGenerator; import whocraft.tardis_refined.compat.ModCompatChecker; @@ -22,6 +23,7 @@ import whocraft.tardis_refined.registry.TRDimensionTypes; import javax.annotation.Nullable; +import java.awt.*; import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -109,7 +111,16 @@ public static void loadLevels(ServerLevel serverLevel) { JsonObject jsonObject = TardisRefined.GSON.fromJson(reader, JsonObject.class); for (JsonElement dimension : jsonObject.get("tardis_dimensions").getAsJsonArray()) { TardisRefined.LOGGER.info("Attempting to load {}", dimension.getAsString()); - DimensionHandler.getOrCreateInterior(serverLevel, new ResourceLocation(dimension.getAsString())); + ResourceLocation id = new ResourceLocation(dimension.getAsString()); + ResourceKey levelKey = ResourceKey.create(Registries.DIMENSION, id); + if (getExistingLevel(serverLevel, levelKey) == null) { + TardisRefined.LOGGER.warn("Level {} not found! Creating new level instance", dimension.getAsString()); + if(DimensionHandler.getOrCreateInterior(serverLevel, id) != null) + TardisRefined.LOGGER.warn("Successfully created and loaded new level {}", dimension.getAsString()); + } + else{ + TardisRefined.LOGGER.info("Successfully loaded existing level {}", dimension.getAsString()); + } } } catch (IOException e) { diff --git a/common/src/main/java/whocraft/tardis_refined/common/entity/ControlEntity.java b/common/src/main/java/whocraft/tardis_refined/common/entity/ControlEntity.java index 6c8b0224f..d6b5c6577 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/entity/ControlEntity.java +++ b/common/src/main/java/whocraft/tardis_refined/common/entity/ControlEntity.java @@ -36,7 +36,7 @@ import whocraft.tardis_refined.common.tardis.control.ship.MonitorControl; import whocraft.tardis_refined.common.tardis.manager.FlightDanceManager; import whocraft.tardis_refined.common.tardis.themes.ConsoleTheme; -import whocraft.tardis_refined.common.tardis.themes.console.sound.PitchedSound; +import whocraft.tardis_refined.patterns.sound.ConfiguredSound; import whocraft.tardis_refined.common.util.ClientHelper; import whocraft.tardis_refined.common.util.LevelHelper; import whocraft.tardis_refined.common.util.MiscHelper; @@ -47,7 +47,9 @@ public class ControlEntity extends Entity { - public static int TotalControlHealth = 10; + /** The total amount of control alignment health points before a control will start causing the Tardis to crash. + *
This name comes from a time when the terminology wasn't finalised, and a more traditional "health" system was being used. */ + private int totalControlHealth = 10; private ControlSpecification controlSpecification; private ConsoleTheme consoleTheme; @@ -58,12 +60,19 @@ public ControlEntity(EntityType entityTypeIn, Level level) { super(entityTypeIn, level); } + /** Flag to determine if this Control can continue to become more mis-aligned and thus lose "health". + *
This name comes from a time when the terminology wasn't finalised, and a more traditional "health" system was being used. + *
True - if able to keep being mis-aligned, False if cannot be further mis-aligned*/ private static final EntityDataAccessor TICKING_DOWN = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.BOOLEAN); + /** Flag to determine if this Control is far too mis-aligned and is considered "dead". + *
This name comes from a time when the terminology wasn't finalised, and a more traditional "health" system was being used. */ private static final EntityDataAccessor IS_DEAD = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.BOOLEAN); + /** Attribute to determine how far this Control is mis-aligned. + *
This name comes from a time when the terminology wasn't finalised, and a more traditional "health" system was being used. */ private static final EntityDataAccessor CONTROL_HEALTH = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.INT); private static final EntityDataAccessor SHOW_PARTICLE = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.BOOLEAN); - private static final EntityDataAccessor SCALE_WIDTH = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.FLOAT); - private static final EntityDataAccessor SCALE_HEIGHT = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.FLOAT); + private static final EntityDataAccessor SIZE_WIDTH = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.FLOAT); + private static final EntityDataAccessor SIZE_HEIGHT = SynchedEntityData.defineId(ControlEntity.class, EntityDataSerializers.FLOAT); public ControlEntity(Level level) { super(TREntityRegistry.CONTROL_ENTITY.get(), level); @@ -101,8 +110,8 @@ public void assignControlData(ConsoleTheme theme, ControlSpecification specifica * Sets the Entity size to an EntityDataAccessor which gets synced to the client next time it updates */ protected void setSizeData(float width, float height) { - this.getEntityData().set(SCALE_WIDTH, width); - this.getEntityData().set(SCALE_HEIGHT, height); + this.getEntityData().set(SIZE_WIDTH, width); + this.getEntityData().set(SIZE_HEIGHT, height); } /** @@ -123,8 +132,8 @@ public ConsoleTheme consoleTheme() { @Override public EntityDimensions getDimensions(Pose pose) { - if (this.getEntityData().get(SCALE_WIDTH) != null && this.getEntityData().get(SCALE_HEIGHT) != null) { - return EntityDimensions.scalable(this.getEntityData().get(SCALE_WIDTH), this.getEntityData().get(SCALE_HEIGHT)); + if (this.getEntityData().get(SIZE_WIDTH) != null && this.getEntityData().get(SIZE_HEIGHT) != null) { + return EntityDimensions.scalable(this.getEntityData().get(SIZE_WIDTH), this.getEntityData().get(SIZE_HEIGHT)); } return super.getDimensions(pose); } @@ -138,10 +147,14 @@ public Component getName() { return Component.translatable(this.controlSpecification.control().getTranslationKey()); } - public void setTickingDown(FlightDanceManager manager) { + /** Tell the Tardis that the control is currently continuing to be misaligned + * @param manager + * @return true if can continue to become more misaligned, false if already too misaligned. + */ + public boolean setTickingDown(FlightDanceManager manager) { if (this.getEntityData().get(IS_DEAD)) { - return; + return false; } this.entityData.set(TICKING_DOWN, true); @@ -149,6 +162,7 @@ public void setTickingDown(FlightDanceManager manager) { this.level().playSound(null, this.blockPosition(), SoundEvents.ARROW_HIT, SoundSource.BLOCKS, 0.5f, 2f); this.setCustomName(Component.translatable("!")); + return true; } @Override @@ -156,15 +170,15 @@ protected void defineSynchedData() { getEntityData().define(SHOW_PARTICLE, false); getEntityData().define(TICKING_DOWN, false); getEntityData().define(IS_DEAD, false); - getEntityData().define(SCALE_WIDTH, 1F); - getEntityData().define(SCALE_HEIGHT, 1F); + getEntityData().define(SIZE_WIDTH, 1F); + getEntityData().define(SIZE_HEIGHT, 1F); getEntityData().define(CONTROL_HEALTH, 10); } @Override public void onSyncedDataUpdated(EntityDataAccessor entityDataAccessor) { - this.setSizeAndUpdate(this.getEntityData().get(SCALE_WIDTH), this.getEntityData().get(SCALE_HEIGHT)); + this.setSizeAndUpdate(this.getEntityData().get(SIZE_WIDTH), this.getEntityData().get(SIZE_HEIGHT)); } @@ -173,8 +187,8 @@ public boolean save(CompoundTag compound) { if (consoleBlockPos != null) { compound.put(NbtConstants.CONSOLE_POS, NbtUtils.writeBlockPos(this.consoleBlockPos)); } - compound.putFloat(NbtConstants.CONTROL_SIZE_WIDTH, this.getEntityData().get(SCALE_WIDTH)); - compound.putFloat(NbtConstants.CONTROL_SIZE_HEIGHT, this.getEntityData().get(SCALE_HEIGHT)); + compound.putFloat(NbtConstants.CONTROL_SIZE_WIDTH, this.getEntityData().get(SIZE_WIDTH)); + compound.putFloat(NbtConstants.CONTROL_SIZE_HEIGHT, this.getEntityData().get(SIZE_HEIGHT)); return super.save(compound); } @@ -205,8 +219,8 @@ protected void addAdditionalSaveData(CompoundTag compound) { compound.put(NbtConstants.CONSOLE_POS, NbtUtils.writeBlockPos(this.consoleBlockPos)); } - compound.putFloat(NbtConstants.CONTROL_SIZE_WIDTH, this.getEntityData().get(SCALE_WIDTH)); - compound.putFloat(NbtConstants.CONTROL_SIZE_HEIGHT, this.getEntityData().get(SCALE_HEIGHT)); + compound.putFloat(NbtConstants.CONTROL_SIZE_WIDTH, this.getEntityData().get(SIZE_WIDTH)); + compound.putFloat(NbtConstants.CONTROL_SIZE_HEIGHT, this.getEntityData().get(SIZE_HEIGHT)); } @@ -219,19 +233,21 @@ public Packet getAddEntityPacket() { public boolean hurt(DamageSource damageSource, float f) { if (damageSource.getDirectEntity() instanceof Player player) { //Using getDirectEntity can allow for players to indirectly interact with controls, such as through primed TNT if (this.level() instanceof ServerLevel serverLevel) { - - if (entityData.get(IS_DEAD)) { - return false; - } - - if (this.entityData.get(TICKING_DOWN)) { - realignControl(); - } else { - handleLeftClick(player, serverLevel); + if(!player.level().isClientSide()) { + if (entityData.get(IS_DEAD)) { + return false; + } + if (this.entityData.get(TICKING_DOWN)) { + this.realignControl(); + //Return early here because we want the player to re-align the control, but not actually activate the control's original function. + //e.g. If Randomiser control is re-aligned we shouldn't actually tell the Tardis to randomise its coordinates. + return true; + } else { + if (handleLeftClick(player, serverLevel)) { + return true; + } + } } - - - return true; } } return super.hurt(damageSource, f); @@ -239,40 +255,45 @@ public boolean hurt(DamageSource damageSource, float f) { @Override public InteractionResult interactAt(Player player, Vec3 hitPos, InteractionHand interactionHand) { - if (interactionHand != InteractionHand.MAIN_HAND || !(this.level() instanceof ServerLevel serverLevel)) { - return InteractionResult.FAIL; - } - - if (player.getMainHandItem().getItem() == Items.COMMAND_BLOCK_MINECART) { - this.handleControlSizeAndPositionAdjustment(player); - return InteractionResult.SUCCESS; - } + if (this.level() instanceof ServerLevel serverLevel) { + if (!player.level().isClientSide()) { + if (player.getMainHandItem().getItem() == Items.COMMAND_BLOCK_MINECART) { + this.handleControlSizeAndPositionAdjustment(player); + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } - if (entityData.get(IS_DEAD)) { - return InteractionResult.FAIL; - } + if (entityData.get(IS_DEAD)) { + return InteractionResult.FAIL; + } - if (this.entityData.get(TICKING_DOWN)) { - realignControl(); - return InteractionResult.SUCCESS; - } else { - this.handleRightClick(player, serverLevel, interactionHand); + if (this.entityData.get(TICKING_DOWN)) { + this.realignControl(); + //Return an InteractionResult here because we want the player to re-align the control, but not actually activate the control's original function. + //e.g. If Randomiser control is re-aligned we shouldn't actually tell the Tardis to randomise its coordinates. + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } else { + if (this.handleRightClick(player, serverLevel, interactionHand)) { + //Return an InteractionResult here because we want to tell the player that the control was correctly interacted with. + return InteractionResult.sidedSuccess(false); //Use InteractionResult.sidedSuccess(false) for non-client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. + } + } + } } - return InteractionResult.SUCCESS; + return InteractionResult.sidedSuccess(true); //Use InteractionResult.sidedSuccess(true) for client side. Stops hand swinging twice. We don't want to use InteractionResult.SUCCESS because the client calls SUCCESS, so the server side calling it too sends the hand swinging packet twice. } public boolean isTickingDown() { return getEntityData().get(TICKING_DOWN); } - + /** Restores the control alignment points to a higher value so that it won't cause the Tardis to crash*/ private void realignControl() { int currentHealth = this.entityData.get(CONTROL_HEALTH); int nextHealth = currentHealth + 2; - if (nextHealth >= TotalControlHealth) { + if (nextHealth >= this.totalControlHealth) { this.entityData.set(TICKING_DOWN, false); - this.entityData.set(CONTROL_HEALTH, TotalControlHealth); + this.entityData.set(CONTROL_HEALTH, totalControlHealth); this.setCustomName(Component.translatable(controlSpecification.control().getTranslationKey())); } else { @@ -367,8 +388,8 @@ private void onClientTick(Level level) { private void handleControlSizeAndPositionAdjustment(Player player) { - float width = this.getEntityData().get(SCALE_WIDTH); - float height = this.getEntityData().get(SCALE_HEIGHT); + float width = this.getEntityData().get(SIZE_WIDTH); + float height = this.getEntityData().get(SIZE_HEIGHT); float incrementAmount = 0.05F; float posIncrementAmount = 0.025F; Item offhandItem = player.getOffhandItem().getItem(); @@ -383,8 +404,8 @@ private void handleControlSizeAndPositionAdjustment(Player player) { double z = this.position().z() - centre.z; TardisRefined.LOGGER.info("Offset: " + x + "F, " + y + "F, " + z + "F"); } - float finalWidth = this.getEntityData().get(SCALE_WIDTH); - float finalHeight = this.getEntityData().get(SCALE_HEIGHT); + float finalWidth = this.getEntityData().get(SIZE_WIDTH); + float finalHeight = this.getEntityData().get(SIZE_HEIGHT); TardisRefined.LOGGER.info("Size (Width, Height): " + finalWidth + "F, " + finalHeight + "F"); } else { if (offhandItem == Items.EMERALD) { //Adjust X @@ -417,27 +438,36 @@ public boolean isDesktopWaitingToGenerate(TardisLevelOperator operator) { return false; } - private void handleLeftClick(Player player, ServerLevel serverLevel) { - TardisLevelOperator.get(serverLevel).ifPresent(cap -> { + private boolean handleLeftClick(Player player, ServerLevel serverLevel) { + if (!TardisLevelOperator.get(serverLevel).isPresent()){ + return false; + } + else { + TardisLevelOperator cap = TardisLevelOperator.get(serverLevel).get(); if (cap.getPilotingManager().getCurrentConsole() == null || cap.getPilotingManager().getCurrentConsole() != getConsoleBlockEntity()) { - cap.getPilotingManager().setCurrentConsole(getConsoleBlockEntity()); + cap.getPilotingManager().setCurrentConsole(this.getConsoleBlockEntity()); } - if (!controlSpecification.control().canUseControl(cap, controlSpecification.control(), this)) - return; - + if (!controlSpecification.control().canUseControl(cap, controlSpecification.control(), this)){ + return false; + } Control control = this.controlSpecification.control(); - boolean successfulUse = control.onLeftClick(cap, consoleTheme, this, player); - PitchedSound playedSound = successfulUse ? control.getSuccessSound(cap, this.consoleTheme, true) : control.getFailSound(cap, this.consoleTheme, true); - control.playControlPitchedSound(cap, this, playedSound); - }); + boolean successfulUse = control.onLeftClick(cap, this.consoleTheme, this, player); + ConfiguredSound playedSound = successfulUse ? control.getSuccessSound(cap, this.consoleTheme, true) : control.getFailSound(cap, this.consoleTheme, true); + control.playControlConfiguredSound(cap, this, playedSound); + return successfulUse; + } } - private void handleRightClick(Player player, ServerLevel serverLevel, InteractionHand interactionHand) { - TardisLevelOperator.get(serverLevel).ifPresent(cap -> { + private boolean handleRightClick(Player player, ServerLevel serverLevel, InteractionHand interactionHand) { + if (!TardisLevelOperator.get(serverLevel).isPresent()){ + return false; + } + else { + TardisLevelOperator cap = TardisLevelOperator.get(serverLevel).get(); if (cap.getPilotingManager().getCurrentConsole() == null || cap.getPilotingManager().getCurrentConsole() != getConsoleBlockEntity()) { cap.getPilotingManager().setCurrentConsole(getConsoleBlockEntity()); @@ -451,19 +481,19 @@ private void handleRightClick(Player player, ServerLevel serverLevel, Interactio DamageSource source = MiscHelper.getDamageSource(serverLevel, DamageTypes.ON_FIRE); player.hurt(source, 0.1F); } - return; + return false; } - if (!controlSpecification.control().canUseControl(cap, controlSpecification.control(), this)) - return; - + if (!controlSpecification.control().canUseControl(cap, controlSpecification.control(), this)) { + return false; + } Control control = this.controlSpecification.control(); boolean successfulUse = control.onRightClick(cap, consoleTheme, this, player); - PitchedSound playedSound = successfulUse ? control.getSuccessSound(cap, this.consoleTheme, false) : control.getFailSound(cap, this.consoleTheme, false); - control.playControlPitchedSound(cap, this, playedSound); - - }); + ConfiguredSound playedSound = successfulUse ? control.getSuccessSound(cap, this.consoleTheme, false) : control.getFailSound(cap, this.consoleTheme, false); + control.playControlConfiguredSound(cap, this, playedSound); + return successfulUse; + } } @@ -502,4 +532,12 @@ public boolean displayFireAnimation() { return false; } + /** Gets the total amount of control alignment health points before a control will start causing the Tardis to crash*/ + public int getTotalControlHealth() { + return this.totalControlHealth; + } + + public void setTotalControlHealth(int totalControlHealth) { + this.totalControlHealth = totalControlHealth; + } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/mixin/MappedRegistryAccessor.java b/common/src/main/java/whocraft/tardis_refined/common/mixin/MappedRegistryAccessor.java new file mode 100644 index 000000000..6e83c4fed --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/common/mixin/MappedRegistryAccessor.java @@ -0,0 +1,13 @@ +package whocraft.tardis_refined.common.mixin; + +import net.minecraft.core.MappedRegistry; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MappedRegistry.class) +public interface MappedRegistryAccessor { + + @Accessor("frozen") + public void setFrozen(boolean frozen); + +} diff --git a/common/src/main/java/whocraft/tardis_refined/common/network/messages/ChangeShellMessage.java b/common/src/main/java/whocraft/tardis_refined/common/network/messages/ChangeShellMessage.java index 2f7349c15..0d5ec6301 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/network/messages/ChangeShellMessage.java +++ b/common/src/main/java/whocraft/tardis_refined/common/network/messages/ChangeShellMessage.java @@ -7,6 +7,7 @@ import net.minecraft.server.level.ServerLevel; import net.minecraft.world.level.Level; import org.jetbrains.annotations.NotNull; +import whocraft.tardis_refined.api.event.ShellChangeSources; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.registry.TRUpgrades; import whocraft.tardis_refined.common.network.MessageC2S; @@ -56,7 +57,7 @@ public void handle(MessageContext context) { Optional level = Optional.ofNullable(context.getPlayer().getServer().levels.get(resourceKey)); level.flatMap(TardisLevelOperator::get).ifPresent(y -> { if(TRUpgrades.CHAMELEON_CIRCUIT_SYSTEM.get().isUnlocked(y.getUpgradeHandler()) && y.getExteriorManager().hasEnoughFuelForShellChange()) { - y.setShellTheme(this.shellTheme, pattern.id(), false); + y.setShellTheme(this.shellTheme, pattern.id(), ShellChangeSources.GENERIC_UPDATE); y.getPilotingManager().removeFuel(y.getExteriorManager().getFuelForShellChange()); } else { PlayerUtil.sendMessage(context.getPlayer(), ModMessages.HARDWARE_OFFLINE, true); diff --git a/common/src/main/java/whocraft/tardis_refined/common/network/messages/EjectPlayerFromConsoleMessage.java b/common/src/main/java/whocraft/tardis_refined/common/network/messages/EjectPlayerFromConsoleMessage.java index 20c4b6449..63d120f14 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/network/messages/EjectPlayerFromConsoleMessage.java +++ b/common/src/main/java/whocraft/tardis_refined/common/network/messages/EjectPlayerFromConsoleMessage.java @@ -49,8 +49,7 @@ public void handle(MessageContext context) { TardisLevelOperator.get(serverLevel).ifPresent(operator -> { if (!operator.getPilotingManager().isInFlight()) { - TardisNavLocation location = operator.getPilotingManager().getCurrentLocation(); - operator.exitTardis(player, location.getLevel(), location.getPosition(), location.getDirection(), true); + operator.forceEjectPlayer(player); } else { PlayerUtil.sendMessage(player, Component.translatable(ModMessages.UI_EJECT_CANNOT_IN_FLIGHT), true); player.playSound(SoundEvents.ITEM_BREAK); diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/ExteriorShell.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/ExteriorShell.java deleted file mode 100644 index 3a70b6faa..000000000 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/ExteriorShell.java +++ /dev/null @@ -1,21 +0,0 @@ -package whocraft.tardis_refined.common.tardis; - -import net.minecraft.core.BlockPos; -import net.minecraft.resources.ResourceKey; -import net.minecraft.world.entity.Entity; -import net.minecraft.world.level.Level; -import net.minecraft.world.level.block.state.BlockState; -import whocraft.tardis_refined.common.tardis.themes.DesktopTheme; - -public interface ExteriorShell { - - BlockPos getExitPosition(); - DesktopTheme getAssociatedTheme(); - - ResourceKey getTardisId(); - - void setTardisId(ResourceKey levelKey); - - void onAttemptEnter(BlockState blockState, Level level, BlockPos externalShellPos, Entity entity); - -} diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/ConsoleControl.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/ConsoleControl.java deleted file mode 100644 index 05606c3cc..000000000 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/ConsoleControl.java +++ /dev/null @@ -1,63 +0,0 @@ -package whocraft.tardis_refined.common.tardis.control; - -import net.minecraft.util.StringRepresentable; -import whocraft.tardis_refined.common.tardis.control.flight.*; -import whocraft.tardis_refined.common.tardis.control.ship.MonitorControl; -import whocraft.tardis_refined.common.tardis.control.ship.ToggleDoorControl; - -import java.util.Locale; - -@Deprecated(forRemoval = true) // Use ControlRegistry instead -public enum ConsoleControl implements StringRepresentable { - - // DON'T MANUALLY UPDATE THE CONSOLE UNITS! UPDATE THE PLUGIN WITH YOUR NEW CONTROL AND GENERATE NEW CONTROL DATA. - - /* - DOOR_TOGGLE("door_toggle", new ToggleDoorControl(), "control.tardis_refined.door_toggle"), - X("x_cord", new CoordinateControl(CoordinateButton.X), "control.tardis_refined.cord_x"), - Y("y_cord", new CoordinateControl(CoordinateButton.Y), "control.tardis_refined.cord_y"), - Z("z_cord", new CoordinateControl(CoordinateButton.Z), "control.tardis_refined.cord_z"), - INCREMENT("increment", new IncrementControl(), "control.tardis_refined.increment"), - ROTATE("rotate", new RotationControl(), "control.tardis_refined.rotate"), - RANDOM("random", new RandomControl(), "control.tardis_refined.random"), - THROTTLE("throttle", new ThrottleControl(), "control.tardis_refined.throttle"), - MONITOR("monitor", new MonitorControl(), "control.tardis_refined.monitor"), - DIMENSION("dimension", new DimensionalControl(), "control.tardis_refined.dimension"), - GENERIC_NO_SHOW("generic_no_show", new GenericControl(), "control.tardis_refined.generic_control"), - READOUT("read_out", new ReadoutControl(), "control.tardis_refined.read_out"), - HANDBRAKE("hand_brake", new HandbrakeControl(), "control.tardis_refined.hand_brake"), - FAST_RETURN("fast_return", new FastReturnControl(), "control.tardis_refined.fast_return") - */; - - private final String id; - private final Control control; - private final String langId; - - ConsoleControl(String id, Control control, String langId) { - this.id = id; - this.control = control; - this.langId = langId; - } - - @Override - public String getSerializedName() { - return this.id; - } - - public Control getControl() { - return control; - } - - public String getTranslationKey() { - return langId; - } - - public static ConsoleControl findOr(String id, ConsoleControl control) { - for (ConsoleControl value : ConsoleControl.values()) { - if (value.name().toLowerCase(Locale.ENGLISH).matches(id.toLowerCase(Locale.ENGLISH))) { - return value; - } - } - return control; - } -} diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/Control.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/Control.java index d99261ba6..b3b3e9569 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/Control.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/Control.java @@ -7,10 +7,13 @@ import net.minecraft.world.entity.player.Player; import whocraft.tardis_refined.api.event.EventResult; import whocraft.tardis_refined.api.event.TardisCommonEvents; +import whocraft.tardis_refined.common.blockentity.console.GlobalConsoleBlockEntity; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.entity.ControlEntity; import whocraft.tardis_refined.common.tardis.themes.ConsoleTheme; -import whocraft.tardis_refined.common.tardis.themes.console.sound.PitchedSound; +import whocraft.tardis_refined.patterns.sound.ConfiguredSound; +import whocraft.tardis_refined.patterns.ConsolePattern; +import whocraft.tardis_refined.patterns.ConsolePatterns; public abstract class Control { protected final ResourceLocation id; @@ -35,15 +38,15 @@ protected Control(ResourceLocation id){ this(id, false); } - private PitchedSound successSound = new PitchedSound(SoundEvents.ARROW_HIT_PLAYER); - private PitchedSound failSound = new PitchedSound(SoundEvents.ITEM_BREAK); + private ConfiguredSound successSound = new ConfiguredSound(SoundEvents.ARROW_HIT_PLAYER); + private ConfiguredSound failSound = new ConfiguredSound(SoundEvents.ITEM_BREAK); public abstract boolean onLeftClick(TardisLevelOperator operator, ConsoleTheme theme, ControlEntity controlEntity, Player player); public abstract boolean onRightClick(TardisLevelOperator operator, ConsoleTheme theme, ControlEntity controlEntity, Player player); /** The sound event to be played when the control fails to activate*/ - public PitchedSound getFailSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick){ + public ConfiguredSound getFailSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick){ return this.failSound; } @@ -51,12 +54,19 @@ public PitchedSound getFailSound(TardisLevelOperator operator, ConsoleTheme them * Directly set the fail sound event to be used in special scenarios * @param failSound */ - public void setFailSound(PitchedSound failSound){ + public void setFailSound(ConfiguredSound failSound){ this.failSound = failSound; } - public PitchedSound getSuccessSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick){ - var pitchedSound = (leftClick) ? theme.getSoundProfile().getGeneric().getLeftClick(): theme.getSoundProfile().getGeneric().getRightClick(); + public ConfiguredSound getSuccessSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick){ + ConsolePattern pattern = ConsolePatterns.DEFAULT; + + GlobalConsoleBlockEntity consoleBlockEntity = operator.getPilotingManager().getCurrentConsole(); + if (consoleBlockEntity != null){ + pattern = consoleBlockEntity.pattern(); + } + + var pitchedSound = (leftClick) ? pattern.soundProfile().getGeneric().leftClick(): pattern.soundProfile().getGeneric().rightClick(); if (pitchedSound != null){ this.successSound = pitchedSound; } @@ -67,20 +77,20 @@ public PitchedSound getSuccessSound(TardisLevelOperator operator, ConsoleTheme t * * @param successSound */ - public void setSuccessSound(PitchedSound successSound){ + public void setSuccessSound(ConfiguredSound successSound){ this.successSound = successSound; } - public void playControlPitchedSound(TardisLevelOperator operator, ControlEntity controlEntity, PitchedSound pitchedSound, SoundSource source, float volume, float pitch, boolean ignorePitch){ + public void playControlConfiguredSound(TardisLevelOperator operator, ControlEntity controlEntity, ConfiguredSound pitchedSound, SoundSource source, float volume, float pitch, boolean ignorePitch){ controlEntity.level().playSound(null, controlEntity.blockPosition(), pitchedSound.getSoundEvent(), source, volume, ignorePitch ? pitch : pitchedSound.getPitch()); } - public void playControlPitchedSound(TardisLevelOperator operator, ControlEntity controlEntity, PitchedSound pitchedSound, float pitch){ - this.playControlPitchedSound(operator, controlEntity, pitchedSound, SoundSource.BLOCKS, 1F, pitch, true); + public void playControlConfiguredSound(TardisLevelOperator operator, ControlEntity controlEntity, ConfiguredSound pitchedSound, float pitch){ + this.playControlConfiguredSound(operator, controlEntity, pitchedSound, SoundSource.BLOCKS, pitchedSound.getVolume(), pitch, true); } - public void playControlPitchedSound(TardisLevelOperator operator, ControlEntity controlEntity, PitchedSound pitchedSound){ - this.playControlPitchedSound(operator, controlEntity, pitchedSound, SoundSource.BLOCKS, 1F, 1F, false); + public void playControlConfiguredSound(TardisLevelOperator operator, ControlEntity controlEntity, ConfiguredSound pitchedSound){ + this.playControlConfiguredSound(operator, controlEntity, pitchedSound, SoundSource.BLOCKS, 1F, 1F, false); } public boolean canUseControl(TardisLevelOperator tardisLevelOperator, Control control, ControlEntity controlEntity){ diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/FastReturnControl.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/FastReturnControl.java index 6a099c080..00617fadd 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/FastReturnControl.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/FastReturnControl.java @@ -3,13 +3,12 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Player; -import whocraft.tardis_refined.TardisRefined; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.entity.ControlEntity; import whocraft.tardis_refined.common.tardis.control.Control; import whocraft.tardis_refined.common.tardis.manager.TardisPilotingManager; import whocraft.tardis_refined.common.tardis.themes.ConsoleTheme; -import whocraft.tardis_refined.common.tardis.themes.console.sound.PitchedSound; +import whocraft.tardis_refined.patterns.sound.ConfiguredSound; public class FastReturnControl extends Control { public FastReturnControl(ResourceLocation id) { @@ -37,7 +36,7 @@ public boolean onRightClick(TardisLevelOperator operator, ConsoleTheme theme, Co return false; } @Override - public PitchedSound getFailSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick) { - return new PitchedSound(SoundEvents.NOTE_BLOCK_BIT.value(), 1F); + public ConfiguredSound getFailSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick) { + return new ConfiguredSound(SoundEvents.NOTE_BLOCK_BIT.value(), 1F); } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/GenericControl.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/GenericControl.java index 70e2b23fd..044da84e8 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/GenericControl.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/GenericControl.java @@ -1,15 +1,11 @@ package whocraft.tardis_refined.common.tardis.control.flight; import net.minecraft.resources.ResourceLocation; -import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Player; -import whocraft.tardis_refined.TardisRefined; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.entity.ControlEntity; import whocraft.tardis_refined.common.tardis.control.Control; -import whocraft.tardis_refined.common.tardis.manager.TardisPilotingManager; import whocraft.tardis_refined.common.tardis.themes.ConsoleTheme; -import whocraft.tardis_refined.common.tardis.themes.console.sound.PitchedSound; public class GenericControl extends Control { public GenericControl(ResourceLocation id) { diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/HandbrakeControl.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/HandbrakeControl.java index b9fae4f0b..3b22a37b0 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/HandbrakeControl.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/flight/HandbrakeControl.java @@ -3,10 +3,8 @@ import net.minecraft.network.chat.Component; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Player; -import whocraft.tardis_refined.TardisRefined; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.entity.ControlEntity; -import whocraft.tardis_refined.common.tardis.TardisNavLocation; import whocraft.tardis_refined.common.tardis.control.Control; import whocraft.tardis_refined.common.tardis.themes.ConsoleTheme; import whocraft.tardis_refined.common.util.PlayerUtil; @@ -40,10 +38,6 @@ public boolean onLeftClick(TardisLevelOperator operator, ConsoleTheme theme, Con @Override public boolean onRightClick(TardisLevelOperator operator, ConsoleTheme theme, ControlEntity controlEntity, Player player) { - - var pitchedSound = theme.getSoundProfile().getThrottleEnable().getRightClick(); - this.setSuccessSound(pitchedSound); - if (operator.getPilotingManager().isInFlight()) { PlayerUtil.sendMessage(player, Component.translatable( ModMessages.HANDBRAKE_WARNING), true); @@ -53,9 +47,5 @@ public boolean onRightClick(TardisLevelOperator operator, ConsoleTheme theme, Co PlayerUtil.sendMessage(player, Component.translatable(operator.getPilotingManager().isHandbrakeOn() ? ModMessages.HANDBRAKE_ENGAGED : ModMessages.HANDBRAKE_DISENGAGED), true); return true; } - - - - } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/ship/ToggleDoorControl.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/ship/ToggleDoorControl.java index 576c192a9..9ef423204 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/control/ship/ToggleDoorControl.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/control/ship/ToggleDoorControl.java @@ -4,12 +4,14 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.sounds.SoundEvents; import net.minecraft.world.entity.player.Player; -import whocraft.tardis_refined.TardisRefined; -import whocraft.tardis_refined.common.block.door.GlobalDoorBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import whocraft.tardis_refined.common.blockentity.door.GlobalDoorBlockEntity; +import whocraft.tardis_refined.common.blockentity.door.TardisInternalDoor; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.entity.ControlEntity; import whocraft.tardis_refined.common.tardis.control.Control; import whocraft.tardis_refined.common.tardis.themes.ConsoleTheme; +import whocraft.tardis_refined.patterns.sound.ConfiguredSound; import whocraft.tardis_refined.common.tardis.themes.console.sound.PitchedSound; import whocraft.tardis_refined.common.util.PlayerUtil; import whocraft.tardis_refined.constants.ModMessages; @@ -29,10 +31,13 @@ public boolean onRightClick(TardisLevelOperator operator, ConsoleTheme theme, Co if(operator.getExteriorManager().locked() || operator.getPilotingManager().isInFlight()) { return false; } - if (!operator.getLevel().getBlockState(operator.getInternalDoor().getDoorPosition()).isAir()){ - var isDoorOpen = operator.getLevel().getBlockState(operator.getInternalDoor().getDoorPosition()).getValue(GlobalDoorBlock.OPEN); - operator.setDoorClosed(isDoorOpen); - return true; + BlockEntity blockEntity = operator.getLevel().getBlockEntity(operator.getInternalDoor().getDoorPosition()); + if (blockEntity != null){ + if (blockEntity instanceof TardisInternalDoor internalDoor){ + var isDoorOpen = internalDoor.isOpen(); + operator.setDoorClosed(isDoorOpen); + return true; + } } } return false; @@ -43,13 +48,11 @@ public boolean onRightClick(TardisLevelOperator operator, ConsoleTheme theme, Co @Override public boolean onLeftClick(TardisLevelOperator operator, ConsoleTheme theme, ControlEntity controlEntity, Player player) { if (!operator.getLevel().isClientSide()) { - if (operator.getInternalDoor() != null) - operator.getInternalDoor().setLocked(!operator.getExteriorManager().locked()); + //Update both internal and exterior shell doors with the value from the exterior manager, which is the Tardis' current data if (operator.getExteriorManager() != null) + operator.setDoorLocked(!operator.getExteriorManager().locked()); operator.getExteriorManager().setLocked(!operator.getExteriorManager().locked()); - PlayerUtil.sendMessage(player, Component.translatable(operator.getExteriorManager().locked() ? ModMessages.DOOR_LOCKED : ModMessages.DOOR_UNLOCKED), true); - operator.setDoorClosed(true); return true; } @@ -57,21 +60,25 @@ public boolean onLeftClick(TardisLevelOperator operator, ConsoleTheme theme, Con } @Override - public PitchedSound getSuccessSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick) { + public ConfiguredSound getSuccessSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick) { if (!operator.getLevel().isClientSide()) { - if (!operator.getLevel().getBlockState(operator.getInternalDoor().getDoorPosition()).isAir()){ - var isDoorOpen = operator.getLevel().getBlockState(operator.getInternalDoor().getDoorPosition()).getValue(GlobalDoorBlock.OPEN); - var pitchedSound = (isDoorOpen) ? theme.getSoundProfile().getDoorClose().getRightClick() : theme.getSoundProfile().getDoorOpen().getRightClick(); - if (pitchedSound != null) { - return pitchedSound; + BlockEntity blockEntity = operator.getLevel().getBlockEntity(operator.getInternalDoor().getDoorPosition()); + if (blockEntity != null){ + if (blockEntity instanceof GlobalDoorBlockEntity internalDoor){ + var isDoorOpen = internalDoor.isOpen(); + var pitchedSound = (isDoorOpen) ? internalDoor.pattern().soundProfile().getDoorClose() : internalDoor.pattern().soundProfile().getDoorOpen(); + if (pitchedSound != null) { + return pitchedSound; + } } + } } return super.getSuccessSound(operator, theme, leftClick); } @Override - public PitchedSound getFailSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick) { - return new PitchedSound(SoundEvents.NOTE_BLOCK_BIT.value()); + public ConfiguredSound getFailSound(TardisLevelOperator operator, ConsoleTheme theme, boolean leftClick) { + return new ConfiguredSound(SoundEvents.NOTE_BLOCK_BIT.value()); } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/AestheticHandler.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/AestheticHandler.java index 320cdcc9d..fe2c87f98 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/AestheticHandler.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/AestheticHandler.java @@ -5,23 +5,15 @@ import net.minecraft.nbt.CompoundTag; import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; -import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.state.BlockState; -import whocraft.tardis_refined.common.block.door.RootShellDoorBlock; -import whocraft.tardis_refined.common.block.shell.GlobalShellBlock; -import whocraft.tardis_refined.common.block.shell.RootedShellBlock; import whocraft.tardis_refined.common.blockentity.door.GlobalDoorBlockEntity; import whocraft.tardis_refined.common.blockentity.shell.GlobalShellBlockEntity; import whocraft.tardis_refined.common.capability.TardisLevelOperator; -import whocraft.tardis_refined.common.hum.HumEntry; -import whocraft.tardis_refined.common.hum.TardisHums; import whocraft.tardis_refined.common.tardis.TardisNavLocation; import whocraft.tardis_refined.common.tardis.themes.ShellTheme; import whocraft.tardis_refined.constants.NbtConstants; import whocraft.tardis_refined.patterns.ShellPattern; import whocraft.tardis_refined.patterns.ShellPatterns; -import whocraft.tardis_refined.registry.TRBlockRegistry; // #PimpMyTimeship public class AestheticHandler extends BaseHandler { @@ -31,7 +23,6 @@ public class AestheticHandler extends BaseHandler { // Shell private ResourceLocation shellTheme = ShellTheme.HALF_BAKED.getId(); private ShellPattern shellPattern = ShellPatterns.DEFAULT; - private HumEntry currentHum = TardisHums.getDefaultHum(); public AestheticHandler(TardisLevelOperator tardisLevelOperator) { @@ -55,95 +46,40 @@ public ResourceLocation getShellTheme() { return shellTheme; } - /** - * Set the theme ID for the Exterior Shell Block assuming that the Tardis is NOT being transformed from a Root Shell - * - * @param theme - */ - public void setShellTheme(ResourceLocation theme, ResourceLocation shellPattern, TardisNavLocation tardisNavLocation) { - this.setShellTheme(theme, shellPattern, false, tardisNavLocation); - } /** * Sets the shell theme ID for the Exterior Shell Block * - * @param theme - the Shell Theme ID + * @param theme - the Shell Theme ID * @param shellPattern - the Shell Theme Pattern - * @param setupTardis - if the reason for setting the theme was because the Tardis is being converted from a Root Shell to a fully functioning one. True if that is the case. */ - public void setShellTheme(ResourceLocation theme, ResourceLocation shellPattern, boolean setupTardis, TardisNavLocation tardisNavLocation) { - setShellPattern(ShellPatterns.getPatternOrDefault(theme, shellPattern)); - - if (tardisNavLocation == null) return; - + public boolean setShellTheme(ResourceLocation theme, ResourceLocation shellPattern, TardisNavLocation tardisNavLocation) { + this.setShellPattern(ShellPatterns.getPatternOrDefault(theme, shellPattern)); this.shellTheme = theme; + if (tardisNavLocation == null) + return false; + BlockPos lastKnownLocationPosition = tardisNavLocation.getPosition(); ServerLevel lastKnownLocationLevel = tardisNavLocation.getLevel(); - BlockState state = lastKnownLocationLevel.getBlockState(lastKnownLocationPosition); - - - if (setupTardis) { - if (state.getBlock() instanceof RootedShellBlock) { - // If the block at the last known location was originally a Root Shell Block (i.e. transforming to a proper Tardis), - // Create a new Global Shell Block instance and copy over all attributes from the existing shell - lastKnownLocationLevel.setBlock(lastKnownLocationPosition, TRBlockRegistry.GLOBAL_SHELL_BLOCK.get().defaultBlockState().setValue(GlobalShellBlock.OPEN, state.getValue(RootedShellBlock.OPEN)).setValue(GlobalShellBlock.FACING, state.getValue(RootedShellBlock.FACING)).setValue(GlobalShellBlock.REGEN, false), Block.UPDATE_ALL_IMMEDIATE); - - //Copy over important data such as Tardis ID - - updateShellBlock(theme, shellPattern, lastKnownLocationLevel, lastKnownLocationPosition); - updateInteriorDoors(theme, shellPattern); - - } - return; - } - - - // Check if its our default global shell. - if (state.getBlock() instanceof GlobalShellBlock globalShellBlock) { - - ShellTheme shellTheme = ShellTheme.getShellTheme(theme); - boolean shouldProduceLight = shellTheme.producesLight(); - - lastKnownLocationLevel.setBlock(lastKnownLocationPosition, state.setValue(GlobalShellBlock.REGEN, false).setValue(GlobalShellBlock.LIT, shouldProduceLight), Block.UPDATE_CLIENTS); - - // Update Exterior (We should make this a method tbh) - updateShellBlock(theme, shellPattern, lastKnownLocationLevel, lastKnownLocationPosition); - updateInteriorDoors(theme, shellPattern); - } + //Copy over important data such as Tardis ID to the internal door and exterior shell + updateShellBlock(theme, shellPattern, lastKnownLocationLevel, lastKnownLocationPosition); + updateInteriorDoors(theme, shellPattern); + return true; } - public void updateInteriorDoors(ResourceLocation theme, ResourceLocation shellPattern) { + private void updateInteriorDoors(ResourceLocation theme, ResourceLocation shellPattern) { if (tardisOperator.getInternalDoor() != null) { BlockPos internalDoorPos = tardisOperator.getInternalDoor().getDoorPosition(); - BlockState state = tardisOperator.getLevel().getBlockState(internalDoorPos); BlockEntity blockEntity = tardisOperator.getLevel().getBlockEntity(internalDoorPos); - if (state.getBlock() instanceof RootShellDoorBlock) { - // If the block at the last known location was originally a Root Shell Door (i.e. transforming to a proper Tardis), - // Create a new Global Shell Door instance and copy over all attributes from the existing shell - tardisOperator.getLevel().setBlock(internalDoorPos, - TRBlockRegistry.GLOBAL_SHELL_BLOCK.get().defaultBlockState().setValue(GlobalShellBlock.OPEN, state.getValue(RootedShellBlock.OPEN)) - .setValue(GlobalShellBlock.FACING, state.getValue(RootedShellBlock.FACING)), 2); - - var potentialDoor = tardisOperator.getLevel().getBlockEntity(internalDoorPos); - if (potentialDoor instanceof GlobalDoorBlockEntity doorBlockEntity) { - doorBlockEntity.setShellTheme(theme); - doorBlockEntity.setPattern(ShellPatterns.getPatternOrDefault(shellTheme, shellPattern)); - tardisOperator.setInternalDoor(doorBlockEntity); - doorBlockEntity.sendUpdates(); - } - } else { - // Check if its our default global shell. - if (blockEntity instanceof GlobalDoorBlockEntity doorBlockEntity) { - doorBlockEntity.setShellTheme(theme); - doorBlockEntity.setPattern(ShellPatterns.getPatternOrDefault(shellTheme, shellPattern)); - doorBlockEntity.sendUpdates(); - } + if (blockEntity instanceof GlobalDoorBlockEntity doorBlockEntity) { + doorBlockEntity.setShellTheme(theme); + doorBlockEntity.setPattern(ShellPatterns.getPatternOrDefault(shellTheme, shellPattern)); + tardisOperator.setInternalDoor(doorBlockEntity); + doorBlockEntity.sendUpdates(); } - - } } @@ -158,11 +94,6 @@ private void updateShellBlock(ResourceLocation theme, ResourceLocation shellPatt } } - @Override - public void tick() { - - } - @Override public CompoundTag saveData(CompoundTag baseTag) { CompoundTag aestheticTag = new CompoundTag(); diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/BaseHandler.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/BaseHandler.java index f98aed6de..b55465bfc 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/BaseHandler.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/BaseHandler.java @@ -2,9 +2,9 @@ import net.minecraft.nbt.CompoundTag; +/** Common template object to allow for saving of data*/ public abstract class BaseHandler { - public abstract void tick(); abstract CompoundTag saveData(CompoundTag tag); abstract void loadData(CompoundTag tag); } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/FlightDanceManager.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/FlightDanceManager.java index 837c2be83..34b6e53c5 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/FlightDanceManager.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/FlightDanceManager.java @@ -1,6 +1,7 @@ package whocraft.tardis_refined.common.tardis.manager; import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.level.ServerLevel; import whocraft.tardis_refined.common.blockentity.console.GlobalConsoleBlockEntity; import whocraft.tardis_refined.common.capability.TardisLevelOperator; import whocraft.tardis_refined.common.entity.ControlEntity; @@ -9,7 +10,7 @@ import java.util.ArrayList; import java.util.List; -public class FlightDanceManager extends BaseHandler { +public class FlightDanceManager extends TickableHandler { private TardisLevelOperator operator; @@ -49,10 +50,10 @@ public void startFlightDance(GlobalConsoleBlockEntity controllerConsole) { } @Override - public void tick() { + public void tick(ServerLevel operatorLevel) { if (this.weAreDancing) { - if (this.operator.getLevel().getGameTime() % (1 * 20) == 0) { - this.onDanceTick(); + if (operatorLevel.getGameTime() % (1 * 20) == 0) { + this.onDanceTick(operatorLevel); } } } @@ -75,7 +76,7 @@ public void stopDancing() { } // A dance tick that runs every 20 ticks. - private void onDanceTick() { + private void onDanceTick(ServerLevel operatorLevel) { if (damagedControlCount >= 5) { this.stopDancing(); @@ -84,7 +85,7 @@ private void onDanceTick() { } int chance = 20 - this.operator.getPilotingManager().getThrottleStage() * 2; - if (this.operator.getLevel().random.nextInt(chance) == 0) { + if (operatorLevel.random.nextInt(chance) == 0) { this.triggerNextEvent(); } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisExteriorManager.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisExteriorManager.java index 7c49b1226..1bb07e292 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisExteriorManager.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisExteriorManager.java @@ -5,19 +5,19 @@ import net.minecraft.resources.ResourceLocation; import net.minecraft.server.level.ServerLevel; import net.minecraft.sounds.SoundEvent; -import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.level.ChunkPos; import net.minecraft.world.level.Level; import net.minecraft.world.level.block.Block; -import net.minecraft.world.level.block.Blocks; +import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluids; import whocraft.tardis_refined.common.block.shell.GlobalShellBlock; import whocraft.tardis_refined.common.block.shell.ShellBaseBlock; +import whocraft.tardis_refined.common.blockentity.door.AbstractDoorBlockEntity; import whocraft.tardis_refined.common.blockentity.shell.GlobalShellBlockEntity; import whocraft.tardis_refined.common.capability.TardisLevelOperator; -import whocraft.tardis_refined.common.tardis.ExteriorShell; +import whocraft.tardis_refined.common.blockentity.shell.ExteriorShell; import whocraft.tardis_refined.common.tardis.TardisNavLocation; import whocraft.tardis_refined.common.tardis.themes.ShellTheme; import whocraft.tardis_refined.constants.NbtConstants; @@ -27,7 +27,6 @@ import java.util.Optional; import static whocraft.tardis_refined.common.block.shell.ShellBaseBlock.LOCKED; -import static whocraft.tardis_refined.common.block.shell.ShellBaseBlock.REGEN; /** * External Shell data. @@ -36,11 +35,11 @@ public class TardisExteriorManager extends BaseHandler { private double fuelForShellChange = 15; // Amount of fuel required to change the shell private final TardisLevelOperator operator; - + /** Determine if the Tardis's doors, no matter the external shell or internal door, should be locked*/ public boolean locked() { return this.locked; } - + /** Update the external shell block's locked property so that players cannot enter it without a synced Key item*/ public void setLocked(boolean locked) { TardisPilotingManager pilotingManager = this.operator.getPilotingManager(); @@ -56,10 +55,10 @@ public void setLocked(boolean locked) { TardisNavLocation currentLocation = pilotingManager.getCurrentLocation(); Level level = currentLocation.getLevel(); BlockPos extPos = currentLocation.getPosition(); - if (level.getBlockState(extPos) != null) { - BlockState extState = level.getBlockState(extPos); - if (extState.getBlock() instanceof GlobalShellBlock shellBlock) { - level.setBlock(extPos, extState.setValue(LOCKED, locked), Block.UPDATE_ALL); + if (level.getBlockEntity(extPos) != null) { + BlockEntity extShellBlockEntity = level.getBlockEntity(extPos); + if (extShellBlockEntity instanceof ExteriorShell exteriorShell) { + exteriorShell.setLocked(locked); } } } @@ -88,10 +87,6 @@ public TardisExteriorManager(TardisLevelOperator operator) { this.operator = operator; } - @Override - public void tick() { - - } @Override public CompoundTag saveData(CompoundTag tag) { @@ -119,12 +114,8 @@ public void playSoundAtShell(SoundEvent event, SoundSource source, float volume, } - - public void setDoorClosed(boolean closed) { - - if (this.locked) { - closed = true; //If the exterior thinks the door is already locked, then this means we should automatically close the door too. - } + /** Sets the Exterior Shell to be opened or closed*/ + public void setDoorClosed(boolean closeDoor) { TardisNavLocation currentPosition = this.operator.getPilotingManager().getCurrentLocation(); @@ -132,31 +123,9 @@ public void setDoorClosed(boolean closed) { ServerLevel lastKnownLocationLevel = currentPosition.getLevel(); // Get the exterior block. - BlockState state = lastKnownLocationLevel.getBlockState(currentPosition.getPosition()); - if (state.hasProperty(ShellBaseBlock.OPEN)) { - lastKnownLocationLevel.setBlock(currentPosition.getPosition(), state.setValue(ShellBaseBlock.OPEN, !closed), 2); - playSoundAtShell(closed ? SoundEvents.IRON_DOOR_CLOSE : SoundEvents.IRON_DOOR_OPEN, SoundSource.BLOCKS, 1, closed ? 1.4F : 1F); - } - } - - - public void triggerShellRegenState(boolean startRegen) { - - TardisPilotingManager pilotingManager = this.operator.getPilotingManager(); - if (pilotingManager == null) { - return; - } - - TardisNavLocation currentPosition = this.operator.getPilotingManager().getCurrentLocation(); - if(currentPosition == null) return; - BlockPos lastKnownLocationPosition = currentPosition.getPosition(); - ServerLevel lastKnownLocationLevel = currentPosition.getLevel(); - - BlockState state = lastKnownLocationLevel.getBlockState(lastKnownLocationPosition); - if (lastKnownLocationLevel == null) return; - if (state.getBlock() instanceof ShellBaseBlock shellBaseBlock && state.hasProperty(REGEN)) { //Check if this is our shell block and that its type has a Regen block state - BlockState updatedBlockState = state.setValue(ShellBaseBlock.REGEN, startRegen); - this.setOrUpdateExteriorBlock(this.operator, currentPosition, Optional.of(updatedBlockState), !startRegen); + BlockEntity blockEntity = lastKnownLocationLevel.getBlockEntity(currentPosition.getPosition()); + if (blockEntity instanceof ExteriorShell exteriorShell) { + exteriorShell.setClosed(closeDoor); } } @@ -177,7 +146,7 @@ public void removeExteriorBlock() { lastKnownLocationLevel.setChunkForced(chunkPos.x, chunkPos.z, true); //Set chunk to be force loaded to properly remove block //Remove block if (lastKnownLocationLevel.getBlockState(lastKnownLocationPosition).getBlock() instanceof GlobalShellBlock shellBlock) { - lastKnownLocationLevel.destroyBlock(lastKnownLocationPosition, false); //Set block to air with drop items flag to false + lastKnownLocationLevel.removeBlock(lastKnownLocationPosition, false); //Set block to air with drop items flag to false } //Un-force load chunk lastKnownLocationLevel.setChunkForced(chunkPos.x, chunkPos.z, false); //Set chunk to not be force loaded after we remove the block @@ -192,7 +161,7 @@ public void startLanding(TardisLevelOperator operator, TardisNavLocation locatio //Force load target chunk targetLevel.setChunkForced(chunkPos.x, chunkPos.z, true); //Set chunk to be force loaded to properly place block - this.setOrUpdateExteriorBlock(operator, location, Optional.empty(), true); + this.placeExteriorBlockForLanding(location); //Un-force load target chunk targetLevel.setChunkForced(chunkPos.x, chunkPos.z, false); //Set chunk to be not be force loaded after we place the block @@ -200,41 +169,9 @@ public void startLanding(TardisLevelOperator operator, TardisNavLocation locatio this.isLanding = true; } - /** Common logic to set or update the exterior shell block. This is needed to ensure we preserve data on the exterior shell such as Shell Patterns*/ - public void setOrUpdateExteriorBlock(TardisLevelOperator operator, TardisNavLocation location, Optional targetBlockState, boolean placeNewBlock){ - AestheticHandler aestheticHandler = operator.getAestheticHandler(); - ResourceLocation theme = (aestheticHandler.getShellTheme() != null) ? aestheticHandler.getShellTheme() : ShellTheme.HALF_BAKED.getId(); - ShellTheme shellTheme = ShellTheme.getShellTheme(theme); - ShellPattern shellPattern = aestheticHandler.getShellTheme() != null ? aestheticHandler.shellPattern() : null; - - ServerLevel targetLevel = location.getLevel(); - BlockPos lastKnownLocationPosition = location.getPosition(); - - BlockState newExteriorBlock = TRBlockRegistry.GLOBAL_SHELL_BLOCK.get().defaultBlockState() - .setValue(GlobalShellBlock.FACING, location.getDirection().getOpposite()) - .setValue(GlobalShellBlock.REGEN, false) - .setValue(LOCKED, operator.getExteriorManager().locked) - .setValue(GlobalShellBlock.LIT, shellTheme.producesLight()) - .setValue(GlobalShellBlock.WATERLOGGED, location.getLevel().getBlockState(location.getPosition()).getFluidState().getType() == Fluids.WATER); - - //If the supplied blockstate somehow doesn't have a value, provide a fallback value by using a recreated blockstate - BlockState finalBlockstate = placeNewBlock ? newExteriorBlock : (targetBlockState.orElse(newExteriorBlock)); - - //Place the exterior block - targetLevel.setBlock(lastKnownLocationPosition, finalBlockstate, Block.UPDATE_ALL); - //Copy over important data points - if (targetLevel.getBlockEntity(lastKnownLocationPosition) instanceof GlobalShellBlockEntity globalShell) { - globalShell.setTardisId(operator.getLevel().dimension()); //DO NOT set the target dimension, otherwise the TARDIS_ID on the exterior will never be correct and key locking features will be broken - globalShell.setShellTheme(theme); - - if (shellPattern != null) { - globalShell.setPattern(shellPattern); - } - - globalShell.sendUpdates(); - - targetLevel.sendBlockUpdated(lastKnownLocationPosition, finalBlockstate, finalBlockstate, Block.UPDATE_CLIENTS); - } + /** Convenience method to place the exterior block when the Tardis is landing */ + public void placeExteriorBlockForLanding(TardisNavLocation location){ + this.operator.setOrUpdateExteriorBlock(location, Optional.empty()); } @@ -251,7 +188,7 @@ public boolean isExitLocationSafe() { BlockPos lastKnownLocationPosition = currentPosition.getPosition(); ServerLevel lastKnownLocationLevel = currentPosition.getLevel(); if (lastKnownLocationLevel.getBlockEntity(lastKnownLocationPosition) instanceof ExteriorShell shellBaseBlockEntity) { - BlockPos landingArea = shellBaseBlockEntity.getExitPosition(); + BlockPos landingArea = shellBaseBlockEntity.getTeleportPosition(); if (lastKnownLocationLevel.getBlockState(landingArea).isAir()) { return lastKnownLocationLevel.getBlockState(landingArea.above()).isAir(); } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisInteriorManager.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisInteriorManager.java index c5e1a6587..de1ff0a63 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisInteriorManager.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisInteriorManager.java @@ -39,7 +39,7 @@ import java.util.ArrayList; import java.util.List; -public class TardisInteriorManager extends BaseHandler { +public class TardisInteriorManager extends TickableHandler { private final TardisLevelOperator operator; private boolean isWaitingToGenerate = false; private boolean isGeneratingDesktop = false; @@ -65,14 +65,14 @@ public class TardisInteriorManager extends BaseHandler { private double fuelForIntChange = 100; // The amount of fuel required to change interior - public DesktopTheme preparedTheme() { - return preparedTheme; - } - public TardisInteriorManager(TardisLevelOperator operator) { this.operator = operator; } + public DesktopTheme preparedTheme() { + return preparedTheme; + } + public boolean isGeneratingDesktop() { return this.isGeneratingDesktop; } @@ -95,11 +95,12 @@ public ProtectedZone[] unbreakableZones() { return new ProtectedZone[]{ctrlRoomAirlck, hubAirlck, arsRoom}; } - + /** Gets the @{@link DesktopTheme} which is currently used by this Tardis*/ public DesktopTheme currentTheme() { - return currentTheme; + return this.currentTheme; } - + /** Updates the current @{@link DesktopTheme}. + * @implNote Should only be used when we are preparing to start a Desktop change*/ public TardisInteriorManager setCurrentTheme(DesktopTheme currentTheme) { this.currentTheme = currentTheme; return this; @@ -109,9 +110,12 @@ public boolean isCave() { return currentTheme == TardisDesktops.DEFAULT_OVERGROWN_THEME; } - @Override - public void tick() { + public HumEntry getHumEntry() { + return humEntry; + } + public void setHumEntry(HumEntry humEntry) { + this.humEntry = humEntry; } @Override @@ -154,15 +158,7 @@ public void loadData(CompoundTag tag) { } } - - public HumEntry getHumEntry() { - return humEntry; - } - - public void setHumEntry(HumEntry humEntry) { - this.humEntry = humEntry; - } - + @Override public void tick(ServerLevel level) { RandomSource rand = level.getRandom(); @@ -181,41 +177,7 @@ public void tick(ServerLevel level) { return; } - if (this.isWaitingToGenerate) { - if (level.random.nextInt(30) == 0) { - level.playSound(null, TardisArchitectureHandler.DESKTOP_CENTER_POS, SoundEvents.FIRE_AMBIENT, SoundSource.BLOCKS, 5.0F + level.random.nextFloat(), level.random.nextFloat() * 0.7F + 0.3F); - } - - if (level.random.nextInt(100) == 0) { - level.playSound(null, TardisArchitectureHandler.DESKTOP_CENTER_POS, SoundEvents.BEACON_POWER_SELECT, SoundSource.BLOCKS, 15.0F + level.random.nextFloat(), 0.1f); - } - - if (level.players().isEmpty()) { - exteriorManager.triggerShellRegenState(true); - operator.setDoorClosed(true); - TardisCommonEvents.DESKTOP_CHANGE_EVENT.invoker().onDesktopChange(operator); - generateDesktop(this.preparedTheme); - - this.isWaitingToGenerate = false; - this.isGeneratingDesktop = true; - } - } - - if (this.isGeneratingDesktop) { - - if (!level.isClientSide()) { - interiorGenerationCooldown--; - } - - if (interiorGenerationCooldown == 0) { - exteriorManager.triggerShellRegenState(false); - this.isGeneratingDesktop = false; - } - - if (level.getGameTime() % 60 == 0) { - exteriorManager.playSoundAtShell(SoundEvents.BEACON_POWER_SELECT, SoundSource.BLOCKS, 1.0F + operator.getLevel().getRandom().nextFloat(), 0.1f); - } - } + this.handleDesktopGeneration(level); /// Airlock Logic @@ -377,11 +339,62 @@ public boolean isInAirlock(LivingEntity livingEntity) { return airlock.contains(livingEntity) || corridor.contains(livingEntity); } + public void setCorridorAirlockCenter(BlockPos center) { + this.corridorAirlockCenter = center; + } + + public BlockPos getCorridorAirlockCenter() { + return this.corridorAirlockCenter; + } + + /** Master logic that schedules the desktop preparation, generation and aesthetic effects in one place + *
Should be called in the {@link TardisInteriorManager#tick()}*/ + public void handleDesktopGeneration(ServerLevel level){ + if (this.isWaitingToGenerate) { + if (level.random.nextInt(30) == 0) { + level.playSound(null, TardisArchitectureHandler.DESKTOP_CENTER_POS, SoundEvents.FIRE_AMBIENT, SoundSource.BLOCKS, 5.0F + level.random.nextFloat(), level.random.nextFloat() * 0.7F + 0.3F); + } + + if (level.random.nextInt(100) == 0) { + level.playSound(null, TardisArchitectureHandler.DESKTOP_CENTER_POS, SoundEvents.BEACON_POWER_SELECT, SoundSource.BLOCKS, 15.0F + level.random.nextFloat(), 0.1f); + } + //This check doesn't actually work for players that respawn, login or teleport to the Tardis dimension when the Tardis is waiting to generate because our tick method is being called at the start of the server tick. + //To mitigate the problem where players become stuck inside the stone and suffocate to death, we call TardisLevelOperator#ejectPlayer in the relevant Events. + if (level.players().isEmpty()) { + if (this.operator.triggerRegenState(true)){ //Make sure we actually triggered the regen state before thinking we are good to go + this.operator.forceEjectAllPlayers(); //Teleport all players to the exterior in case they still remain. + TardisCommonEvents.DESKTOP_CHANGE_EVENT.invoker().onDesktopChange(operator); + this.generateDesktop(this.preparedTheme); //During desktop generation, if the state is still the initial cave state, we will update it to terraformed but no eye activated + + this.isWaitingToGenerate = false; + this.isGeneratingDesktop = true; + } + } + } + + if (this.isGeneratingDesktop) { + + if (!level.isClientSide()) { + interiorGenerationCooldown--; + } + + if (interiorGenerationCooldown == 0) { + if (this.operator.triggerRegenState(false)) //Make sure we actually triggered the regen state before saying we are good to go. + this.isGeneratingDesktop = false; + } + + if (level.getGameTime() % 60 == 0) { + this.operator.getExteriorManager().playSoundAtShell(SoundEvents.BEACON_POWER_SELECT, SoundSource.BLOCKS, 1.0F + operator.getLevel().getRandom().nextFloat(), 0.1f); + } + } + } + + /** Performs the desktop generation tasks such as block removal and placement tasks*/ public void generateDesktop(DesktopTheme theme) { if (operator.getLevel() instanceof ServerLevel serverLevel) { - if (this.operator.getTardisState() == TardisLevelOperator.STATE_CAVE) { + if (this.operator.getTardisState() == TardisLevelOperator.STATE_CAVE) { //If transforming from root shell to half baked Tardis, set the state to terraformed but no eye activated this.operator.setTardisState(TardisLevelOperator.STATE_TERRAFORMED_NO_EYE); } @@ -400,14 +413,7 @@ public void generateDesktop(DesktopTheme theme) { } } - public void setCorridorAirlockCenter(BlockPos center) { - this.corridorAirlockCenter = center; - } - - public BlockPos getCorridorAirlockCenter() { - return this.corridorAirlockCenter; - } - + /** Prepares the Tardis for desktop generation but doesn't actually start it. Handles cooldowns etc.*/ public void prepareDesktop(DesktopTheme theme) { this.preparedTheme = theme; this.isWaitingToGenerate = true; diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisPilotingManager.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisPilotingManager.java index be7b075ec..e2bf3f0e2 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisPilotingManager.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisPilotingManager.java @@ -27,6 +27,8 @@ import whocraft.tardis_refined.common.capability.upgrades.SpeedUpgrade; import whocraft.tardis_refined.common.capability.upgrades.Upgrade; import whocraft.tardis_refined.common.capability.upgrades.UpgradeHandler; +import whocraft.tardis_refined.common.util.LevelHelper; +import whocraft.tardis_refined.registry.TRUpgrades; import whocraft.tardis_refined.common.tardis.TardisArchitectureHandler; import whocraft.tardis_refined.common.tardis.TardisNavLocation; import whocraft.tardis_refined.common.util.PlayerUtil; @@ -39,7 +41,7 @@ import java.util.*; -public class TardisPilotingManager extends BaseHandler { +public class TardisPilotingManager extends TickableHandler { // CONSTANTS private static final int TICKS_LANDING_MAX = 9 * 20; @@ -134,11 +136,6 @@ public void loadData(CompoundTag tag) { } } - @Override - public void tick() { - - } - @Override public CompoundTag saveData(CompoundTag tag) { tag.putBoolean(NbtConstants.CONTROL_IS_IN_FLIGHT, this.isInFlight); @@ -180,13 +177,12 @@ public CompoundTag saveData(CompoundTag tag) { return tag; } - - public void tick(Level level) { + @Override + public void tick(ServerLevel level) { if (targetLocation == null) { - var location = currentLocation; - if (targetLocation != null) { - this.targetLocation = location; + if (this.currentLocation != null) { //If the target location is somehow null and the current location isn't null, set target location to the current location + this.targetLocation = currentLocation; } else { this.targetLocation = TardisNavLocation.ORIGIN; } @@ -220,7 +216,7 @@ public void tick(Level level) { } - private void onFlightTick(Level level) { + private void onFlightTick(ServerLevel level) { // Don't continue the flight if the throttle isn't active!!! if (this.throttleStage != 0 || this.autoLand) { @@ -237,7 +233,7 @@ private void onFlightTick(Level level) { // If this tick was enough to push us over. if (distanceCovered >= flightDistance) { - if (distanceCovered >= flightDistance && this.currentConsole != null) { + if (this.currentConsole != null) { level.playSound(null, currentConsole.getBlockPos(), TRSoundRegistry.DESTINATION_DING.get(), SoundSource.AMBIENT, 10f, 1f); this.operator.getFlightDanceManager().stopDancing(); } @@ -330,89 +326,144 @@ public boolean preloadFastReturn() { public TardisNavLocation findClosestValidPosition(TardisNavLocation location) { ServerLevel level = location.getLevel(); + BlockPos position = location.getPosition(); + Direction direction = location.getDirection(); + + ChunkPos chunkPos = level.getChunk(position).getPos(); var maxBuildHeight = level.getMaxBuildHeight(); var minHeight = level.getMinBuildHeight(); - return findValidLocationInColumn(location, level, minHeight, maxBuildHeight); - } + List solutionsInRow = new ArrayList<>(); - private TardisNavLocation findValidLocationInColumn(TardisNavLocation location, ServerLevel level, int minHeight, int maxBuildHeight) { + //Force load chunk to search positions + level.setChunkForced(chunkPos.x, chunkPos.z, true); - ChunkPos chunkPos = level.getChunk(location.getPosition()).getPos(); - //Force load chunk - level.setChunkForced(chunkPos.x, chunkPos.z, true); //Set chunk to be force loaded to properly remove block + //Set the default location to 0,0,0 at the target level. DO NOT set this to null else we cause a game crash + TardisNavLocation closest = new TardisNavLocation(BlockPos.ZERO, Direction.NORTH, level); - // Fetch the row of blocks and filter them all out to air. - List blockColumn = getBlockPosColumn(location.getPosition(), minHeight, maxBuildHeight); - List filteredForAir = blockColumn.stream().filter(x -> isLegalLandingBlock(level, x)).toList(); - List filteredForNonAir = blockColumn.stream().filter(x -> !isLegalLandingBlock(level, x)).toList(); + //First manually check if the exact target position can allow us to place the Tardis + if (this.canPlaceTardis(location) && this.isExitPositionSafe(location)) { + solutionsInRow.add(location); + } - List solutionsInRow = new ArrayList<>(); - for (BlockPos airPos : filteredForAir) { + // If the exact target location was a valid area, let's set it as the final position to use for landing, no extra searching needed. + if (!solutionsInRow.isEmpty()) { + closest = location; + } + else{ - // Ignore any higher scans above the roof. - if (level.dimension() == Level.NETHER && airPos.getY() > 125) { - continue; + //If the exact target location isn't valid, check blocks in the vertical column + List nextValidLocations = this.findValidLocationInColumn(level, position, direction, minHeight, maxBuildHeight); + if (!nextValidLocations.isEmpty()){ + solutionsInRow.addAll(nextValidLocations); } + else { + //If the vertical column is not valid, let's check the surrounding area at the same y level. + List surroundingPositionsSameYLevel = LevelHelper.getBlockPosInRadius(position, 1, true, false); + for (BlockPos directionOffset : surroundingPositionsSameYLevel) { + TardisNavLocation nextLocation = new TardisNavLocation(directionOffset, location.getDirection(), location.getLevel()); + if (this.canPlaceTardis(nextLocation) && this.isExitPositionSafe(nextLocation)) { + solutionsInRow.add(nextLocation); + } + } - BlockPos below = airPos.below(); - BlockPos above = airPos.above(); - - // Does this position have the space for a TARDIS? - if (filteredForNonAir.contains(below) && filteredForAir.contains(above)) { - - // Can we find a rotation for the TARDIS? - - // Check front - Direction[] directions = new Direction[]{location.getDirection(), location.getDirection().getOpposite(), Direction.NORTH, Direction.SOUTH, Direction.EAST, Direction.WEST}; + //If the surrounding areas also aren't suitable, search vertically in the original location as well as surrounding areas + //This is a much more expensive search so ideally we don't want to do this. + if (solutionsInRow.isEmpty()) { - for (Direction direction : directions) { - BlockPos directionOffset = BlockPos.of(BlockPos.offset(airPos.asLong(), direction)); - // Check that the column in the direction is empty and doesn't have a drop. - if (isLegalLandingBlock(level, directionOffset)) { - if (isLegalLandingBlock(level, directionOffset.above()) && !isLegalLandingBlock(level, directionOffset.below()) && !isLegalLandingBlock(level, directionOffset.below(2))) { - solutionsInRow.add(new TardisNavLocation(airPos, direction, location.getLevel())); + List surroundingPositionsForColumn = LevelHelper.getBlockPosInRadius(position, 1, true, true); + for(BlockPos pos : surroundingPositionsForColumn){ + List surroundingColumn = this.findValidLocationInColumn(level, pos, direction, minHeight, maxBuildHeight); + if (!surroundingColumn.isEmpty()){ + solutionsInRow.addAll(surroundingColumn); } } } - } + + //Now after we have searched all possible solutions, find the closest solution. + closest = this.findClosestValidPositionFromTarget(solutionsInRow, location); + } + //Unforce chunk after we are done searching + level.setChunkForced(chunkPos.x, chunkPos.z, false); + + return closest; + } + + private List findValidLocationInColumn(TardisNavLocation location, int minHeight, int maxBuildHeight) { + return this.findValidLocationInColumn(location.getLevel(), location.getPosition(), location.getDirection(), minHeight, maxBuildHeight); + } - // We have all solutions. Let's find the closest. + /** Within all Y level positions for a given position, search for valid landing positions + * @param level - target Level we are trying to land in + * @param position - the original position we are searching vertically in + * @param direction - the direction we are landing at + * @param minHeight - minimum height to search upwards from + * @param maxBuildHeight - the maximum height to search under + * @return + */ + private List findValidLocationInColumn(ServerLevel level, BlockPos position, Direction direction, int minHeight, int maxBuildHeight) { + List solutionsInRow = new ArrayList<>(); - if (solutionsInRow.size() > 0) { + // Fetch the row of blocks and filter them all out to air. + List blockColumn = this.getBlockPosColumn(position, minHeight, maxBuildHeight); + List filteredForAir = blockColumn.stream().filter(x -> isLegalLandingBlock(level, x)).toList(); + List filteredForNonAir = blockColumn.stream().filter(x -> !isLegalLandingBlock(level, x)).toList(); - TardisNavLocation closest = null; - int distance = Integer.MAX_VALUE; + //Out of all the positions which are considered empty spaces (air), check if each position allows for the Tardis exterior to be placed and the area outside the door is safe + for (BlockPos airPos : filteredForAir) { - for (TardisNavLocation potentialLocation : solutionsInRow) { - int distanceBetween = Math.abs(potentialLocation.getPosition().distManhattan(location.getPosition())); - if (distanceBetween < distance) { - distance = distanceBetween; - closest = potentialLocation; - } + // Ignore any higher scans above the nether roof. + if (level.dimension() == Level.NETHER && airPos.getY() > 125) { + continue; } - return closest; - - } else { + BlockPos below = airPos.below(); + BlockPos above = airPos.above(); - BlockPos directionOffset = BlockPos.of(BlockPos.offset(location.getPosition().asLong(), location.getDirection())); - TardisNavLocation nextLocation = new TardisNavLocation(directionOffset, location.getDirection(), location.getLevel()); - return findValidLocationInColumn(nextLocation, level, minHeight, maxBuildHeight); + // Check if this position have the space for a TARDIS. + if (filteredForNonAir.contains(below) && filteredForAir.contains(above)) { + // Check if the exit position allows an entity to be teleported without suffocating or falling. + if (this.canPlaceTardis(level, airPos) && this.isExitPositionSafe(level, airPos, direction)) { + solutionsInRow.add(new TardisNavLocation(airPos, direction, level)); + } + } + } + return solutionsInRow; + } + + /** Finds the closest valid position out of a list of possible solutions, from the original intended landing location*/ + private TardisNavLocation findClosestValidPositionFromTarget(List validPositions, TardisNavLocation targetLocation){ + int distance = Integer.MAX_VALUE; + TardisNavLocation intendedLocation = targetLocation; + TardisNavLocation closestSolution = new TardisNavLocation(BlockPos.ZERO, Direction.NORTH, intendedLocation.getLevel()); + for (TardisNavLocation potentialLocation : validPositions) { + int distanceBetween = Math.abs(potentialLocation.getPosition().distManhattan(intendedLocation.getPosition())); + if (distanceBetween < distance) { + distance = distanceBetween; + closestSolution = potentialLocation; + } } + return closestSolution; } - private List getBlockPosColumn(BlockPos referencePoint, int bottomLevel, int topLevel) { + /** + * Gets a list of block positions in the same y level as the reference point + * @param referencePoint - the position to search vertically in + * @param min - The minimum Y value to search upwards from + * @param max - The maximum Y value to search downwards from (this max value is included in the search) + * @return + */ + private List getBlockPosColumn(BlockPos referencePoint, int min, int max) { List positions = new ArrayList<>(); - for (int i = bottomLevel; i <= topLevel; i++) { + for (int i = min; i <= max; i++) { positions.add(new BlockPos(referencePoint.getX(), i, referencePoint.getZ())); } @@ -423,10 +474,38 @@ private List getBlockPosColumn(BlockPos referencePoint, int bottomLeve /** * Check if the block at the target position is a valid block to land inside. * **/ - public boolean isLegalLandingBlock(ServerLevel level, BlockPos pos) { + private boolean isLegalLandingBlock(ServerLevel level, BlockPos pos) { BlockState state = level.getBlockState(pos); // Can land in air or override any block that can be marked as "replaceable" such as snow, tall grass etc. - return state.isAir() || (state.canBeReplaced() && state.getFluidState().isEmpty()); + return state.isAir() || (state.canBeReplaced() && state.getFluidState().isEmpty() && !state.isCollisionShapeFullBlock(level, pos)); + } + + private boolean isExitPositionSafe(TardisNavLocation location){ + return this.isExitPositionSafe(location.getLevel(), location.getPosition(), location.getDirection()); + } + + private boolean isExitPositionSafe(ServerLevel level, BlockPos pos, Direction offsetDirection){ + BlockPos exitPosition = pos.offset(offsetDirection.getNormal()); //Check the block that is facing away from the doors. + if (this.isLegalLandingBlock(level, exitPosition.above()) + && this.isLegalLandingBlock(level, exitPosition) //If there is a 2 block space for the entity to be placed at + && !this.isLegalLandingBlock(level, exitPosition.below()) //If there is a solid block beneath the exit position for the entity to stand on + ) { + return true; + } + return false; + } + + /** If there is a 2 block vertical space for the exterior to be placed at, and the block below the exterior is solid*/ + private boolean canPlaceTardis(TardisNavLocation location){ + ServerLevel targetLevel = location.getLevel(); + BlockPos pos = location.getPosition(); + boolean isBelowNetherRoof = (targetLevel.dimension() == Level.NETHER && pos.getY() <= 125); + return isBelowNetherRoof && this.isLegalLandingBlock(targetLevel, pos) && isLegalLandingBlock(targetLevel, pos.above()) && !isLegalLandingBlock(targetLevel, pos.below()); + } + + /** If there is a 2 block vertical space for the exterior to be placed at, and the block below the exterior is solid*/ + private boolean canPlaceTardis(ServerLevel level, BlockPos pos){ + return this.isLegalLandingBlock(level, pos) && isLegalLandingBlock(level, pos.above()) && !isLegalLandingBlock(level, pos.below()); } /** @@ -481,8 +560,9 @@ public boolean beginFlight(boolean autoLand, Optional this.fastReturnLocation = new TardisNavLocation(this.getCurrentLocation().getPosition(), this.getCurrentLocation().getDirection(), this.getCurrentLocation().getLevel()); - TardisNavLocation targetPosition = this.operator.getPilotingManager().getTargetLocation(); - TardisNavLocation lastKnownLocation = this.fastReturnLocation; + TardisNavLocation targetPosition = this.getTargetLocation(); + TardisNavLocation lastKnownLocation = new TardisNavLocation(this.getCurrentLocation().getPosition(), this.getCurrentLocation().getDirection(), this.getCurrentLocation().getLevel()); + this.flightDistance = calculateFlightDistance(lastKnownLocation, targetPosition); @@ -575,10 +655,6 @@ public boolean endFlight(boolean forceFlightEnd) { currentLocation = location; - if(currentConsole != null) { - level.playSound(null, currentConsole.getBlockPos(), TRSoundRegistry.DESTINATION_DING.get(), SoundSource.AMBIENT, 10f, 1f); - } - exteriorManager.startLanding(operator, location); exteriorManager.playSoundAtShell(TRSoundRegistry.TARDIS_LAND.get(), SoundSource.BLOCKS, 1, 1); @@ -883,13 +959,13 @@ public void setCurrentConsole(GlobalConsoleBlockEntity newConsole) { ResourceLocation oldTheme = consoleBlockEntity.theme(); ConsolePattern oldPattern = consoleBlockEntity.pattern(); - level.setBlock(this.currentConsole.getBlockPos(), this.currentConsole.getBlockState().setValue(GlobalConsoleBlock.POWERED, true), Block.UPDATE_ALL); - GlobalConsoleBlockEntity updated = (GlobalConsoleBlockEntity) level.getBlockEntity(this.currentConsole.getBlockPos()); + level.setBlock(this.currentConsoleBlockPos, this.currentConsole.getBlockState().setValue(GlobalConsoleBlock.POWERED, true), Block.UPDATE_ALL); + GlobalConsoleBlockEntity updated = (GlobalConsoleBlockEntity) level.getBlockEntity(this.currentConsoleBlockPos); updated.setConsoleTheme(oldTheme); updated.setPattern(oldPattern); updated.sendUpdates(); - level.playSound(null, this.currentConsole.getBlockPos(), TRSoundRegistry.CONSOLE_POWER_ON.get(), SoundSource.BLOCKS, 2f, 1f); + level.playSound(null, this.currentConsoleBlockPos, TRSoundRegistry.CONSOLE_POWER_ON.get(), SoundSource.BLOCKS, 2f, 1f); } } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisWaypointManager.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisWaypointManager.java index 15f4d7d7f..fdb0f94f3 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisWaypointManager.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TardisWaypointManager.java @@ -43,10 +43,6 @@ public TardisWaypoint getWaypointById(UUID id) { return waypoint.orElse(null); } - @Override - public void tick() { - - } @Override public CompoundTag saveData(CompoundTag compoundTag) { ListTag waypointsList = new ListTag(); diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TickableHandler.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TickableHandler.java new file mode 100644 index 000000000..e24d56120 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/manager/TickableHandler.java @@ -0,0 +1,20 @@ +package whocraft.tardis_refined.common.tardis.manager; + +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.level.Level; + +/** Tickable version of the BaseHandler*/ +public abstract class TickableHandler extends BaseHandler{ + /** Method that is run every tick. This can happen on both server and client side + *
Make sure to check your logic for if you need */ + public void tick(Level level){} + + public void tick(){} + + /** Method that is run every tick. + * @implNote Use this if we need to run logic on the server side and use the TardisLevelOperator's ServerLevel. + * + * @param operatorLevel - The ServerLevel used by the TardisLevelOperator + */ + public abstract void tick(ServerLevel operatorLevel); +} diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ConsoleTheme.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ConsoleTheme.java index ee50e37b6..0506d8178 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ConsoleTheme.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ConsoleTheme.java @@ -8,7 +8,7 @@ import whocraft.tardis_refined.TardisRefined; import whocraft.tardis_refined.common.tardis.control.ControlSpecification; import whocraft.tardis_refined.common.tardis.themes.console.*; -import whocraft.tardis_refined.common.tardis.themes.console.sound.ConsoleSoundProfile; +import whocraft.tardis_refined.patterns.sound.ConsoleSoundProfile; import whocraft.tardis_refined.registry.DeferredRegistry; import whocraft.tardis_refined.registry.RegistrySupplierHolder; @@ -46,10 +46,6 @@ public ControlSpecification[] getControlSpecificationList() { return consoleThemeDetails.getControlSpecification(); } - public ConsoleSoundProfile getSoundProfile() { - return consoleThemeDetails.getSoundProfile(); - } - private static RegistrySupplierHolder registerConsoleTheme(String id, ConsoleThemeDetails themeDetails){ return CONSOLE_THEME_DEFERRED_REGISTRY.registerHolder(id, () -> new ConsoleTheme(new ResourceLocation(TardisRefined.MODID, id), themeDetails)); diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/DesktopTheme.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/DesktopTheme.java index 0eae4b3db..146241257 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/DesktopTheme.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/DesktopTheme.java @@ -30,7 +30,7 @@ public class DesktopTheme { *
The display name is set to the identifier using a standard String Text Component. * @param id * @param structureLocation - * @implNote NOTE: Users must also add a PNG display image under assets/tardis_refined/textures/ui/desktops/ + * @implNote NOTE: Users must also add a PNG display image under assets/tardis_refined/textures/gui/desktops/ */ public DesktopTheme(String id, String structureLocation) { this(new ResourceLocation(TardisRefined.MODID, id), new ResourceLocation(TardisRefined.MODID, structureLocation), TardisRefined.GSON.toJson(Component.literal(MiscHelper.getCleanName(id)).setStyle(Style.EMPTY.withColor(ChatFormatting.GOLD)))); diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ShellTheme.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ShellTheme.java index 7c43a0568..7ada0c2f0 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ShellTheme.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/ShellTheme.java @@ -57,22 +57,25 @@ public static ResourceLocation getKey(ShellTheme shellTheme){ private ResourceLocation translationKey; private boolean producesLight; - public ShellTheme(ResourceLocation translationKey) { - this.translationKey = translationKey; - } + public ShellTheme(ResourceLocation translationKey, boolean producesLight) { this.translationKey = translationKey; this.producesLight = producesLight; } + public ShellTheme(ResourceLocation translationKey) { + this(translationKey, false); + } + private static RegistrySupplierHolder registerShellTheme(String id){ - return SHELL_THEME_DEFERRED_REGISTRY.registerHolder(id, () -> new ShellTheme(new ResourceLocation(TardisRefined.MODID, id))); + return SHELL_THEME_DEFERRED_REGISTRY.registerHolder(id, () -> new ShellTheme(new ResourceLocation(TardisRefined.MODID, id), false)); } private static RegistrySupplierHolder registerShellTheme(String id, boolean producesLight){ return SHELL_THEME_DEFERRED_REGISTRY.registerHolder(id, () -> new ShellTheme(new ResourceLocation(TardisRefined.MODID, id), producesLight)); } + @Override public String getTranslationKey() { return Util.makeDescriptionId("shell", this.translationKey); @@ -87,4 +90,6 @@ public boolean producesLight() { return producesLight; } + + } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/ConsoleThemeDetails.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/ConsoleThemeDetails.java index 7d64a59d5..edf30ae60 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/ConsoleThemeDetails.java +++ b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/ConsoleThemeDetails.java @@ -1,19 +1,11 @@ package whocraft.tardis_refined.common.tardis.themes.console; import whocraft.tardis_refined.common.tardis.control.ControlSpecification; -import whocraft.tardis_refined.common.tardis.themes.console.sound.ConsoleSoundProfile; -import whocraft.tardis_refined.common.tardis.themes.console.sound.GenericConsoleSoundProfile; public abstract class ConsoleThemeDetails { - ConsoleSoundProfile soundProfile = new GenericConsoleSoundProfile(); - public ControlSpecification[] getControlSpecification() { return null; } - public ConsoleSoundProfile getSoundProfile() { - return soundProfile; - } - } diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/ConsoleSound.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/ConsoleSound.java deleted file mode 100644 index 27d26cddf..000000000 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/ConsoleSound.java +++ /dev/null @@ -1,32 +0,0 @@ -package whocraft.tardis_refined.common.tardis.themes.console.sound; - -import javax.annotation.Nullable; - - -/** - * Sound for a specific action, featuring left, right and failure presses. - **/ -public class ConsoleSound { - - private final PitchedSound leftClick; - private final PitchedSound rightClick; - - /** - * Datatype for referencing a sound event for how a player would interact with a control. - * @param leftClick the sound event fired when a control is left-clicked.; - * @param rightClick the sound event fired when a control is right-clicked; - * */ - public ConsoleSound(@Nullable PitchedSound leftClick, @Nullable PitchedSound rightClick) { - this.leftClick = leftClick; - this.rightClick = rightClick; - } - - public PitchedSound getLeftClick() { - return leftClick; - } - - - public PitchedSound getRightClick() { - return rightClick; - } -} diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/ConsoleSoundProfile.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/ConsoleSoundProfile.java deleted file mode 100644 index f822601c2..000000000 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/ConsoleSoundProfile.java +++ /dev/null @@ -1,78 +0,0 @@ -package whocraft.tardis_refined.common.tardis.themes.console.sound; - -public abstract class ConsoleSoundProfile { - - private ConsoleSound throttleEnable; - private ConsoleSound throttleDisable; - private ConsoleSound handbrakeEnable; - private ConsoleSound handbrakeDisable; - private ConsoleSound doorOpen; - private ConsoleSound doorClose; - private ConsoleSound doorLocked; - private ConsoleSound generic; - - - public ConsoleSound getThrottleEnable() { - return throttleEnable; - } - - public void setThrottleEnable(ConsoleSound throttleEnable) { - this.throttleEnable = throttleEnable; - } - - public ConsoleSound getThrottleDisable() { - return throttleDisable; - } - - public void setThrottleDisable(ConsoleSound throttleDisable) { - this.throttleDisable = throttleDisable; - } - - public ConsoleSound getHandbrakeEnable() { - return handbrakeEnable; - } - - public void setHandbrakeEnable(ConsoleSound handbrakeEnable) { - this.handbrakeEnable = handbrakeEnable; - } - - public ConsoleSound getHandbrakeDisable() { - return handbrakeDisable; - } - - public void setHandbrakeDisable(ConsoleSound handbrakeDisable) { - this.handbrakeDisable = handbrakeDisable; - } - - public ConsoleSound getDoorOpen() { - return doorOpen; - } - - public void setDoorOpen(ConsoleSound doorOpen) { - this.doorOpen = doorOpen; - } - - public ConsoleSound getDoorClose() { - return doorClose; - } - - public void setDoorClose(ConsoleSound doorClose) { - this.doorClose = doorClose; - } - - public ConsoleSound getDoorLocked() { - return doorLocked; - } - - public void setDoorLocked(ConsoleSound doorLocked) { this.doorLocked = doorLocked;} - - public ConsoleSound getGeneric() { - return generic; - } - - public void setGeneric(ConsoleSound generic) { - this.generic = generic; - } -} - - diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/GenericConsoleSoundProfile.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/GenericConsoleSoundProfile.java deleted file mode 100644 index 0eca6ea88..000000000 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/GenericConsoleSoundProfile.java +++ /dev/null @@ -1,17 +0,0 @@ -package whocraft.tardis_refined.common.tardis.themes.console.sound; - -import net.minecraft.sounds.SoundEvents; - -public class GenericConsoleSoundProfile extends ConsoleSoundProfile { - - public GenericConsoleSoundProfile() { - setThrottleEnable(new ConsoleSound(null, new PitchedSound(SoundEvents.LEVER_CLICK, 0.6f))); - setThrottleDisable(new ConsoleSound(null, new PitchedSound(SoundEvents.LEVER_CLICK, 0.5f))); - setHandbrakeEnable(new ConsoleSound(null, new PitchedSound(SoundEvents.LEVER_CLICK, 0.6f))); - setHandbrakeDisable(new ConsoleSound(null, new PitchedSound(SoundEvents.LEVER_CLICK, 0.5f))); - setDoorOpen(new ConsoleSound(null, new PitchedSound(SoundEvents.LEVER_CLICK, 0.6f))); - setDoorClose(new ConsoleSound(null, new PitchedSound(SoundEvents.LEVER_CLICK, 0.5f))); - setGeneric(new ConsoleSound(new PitchedSound(SoundEvents.STONE_BUTTON_CLICK_ON, 0.95f), new PitchedSound(SoundEvents.STONE_BUTTON_CLICK_ON, 1.1f))); - } - -} diff --git a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/PitchedSound.java b/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/PitchedSound.java deleted file mode 100644 index 872e61229..000000000 --- a/common/src/main/java/whocraft/tardis_refined/common/tardis/themes/console/sound/PitchedSound.java +++ /dev/null @@ -1,30 +0,0 @@ -package whocraft.tardis_refined.common.tardis.themes.console.sound; - -import net.minecraft.sounds.SoundEvent; - - -/** - * A small link between a SoundEvent and intended pitch to play. - **/ -public class PitchedSound { - - private final SoundEvent soundEvent; - private final float pitch; - - public PitchedSound(SoundEvent event, float pitch) { - this.soundEvent = event; - this.pitch = pitch; - } - - public PitchedSound(SoundEvent event){ - this(event, 1F); - } - - public SoundEvent getSoundEvent() { - return soundEvent; - } - - public float getPitch() { - return pitch; - } -} diff --git a/common/src/main/java/whocraft/tardis_refined/common/util/LevelHelper.java b/common/src/main/java/whocraft/tardis_refined/common/util/LevelHelper.java index d9f039aeb..a020a3877 100644 --- a/common/src/main/java/whocraft/tardis_refined/common/util/LevelHelper.java +++ b/common/src/main/java/whocraft/tardis_refined/common/util/LevelHelper.java @@ -4,6 +4,9 @@ import net.minecraft.core.Direction; import net.minecraft.world.phys.Vec3; +import java.util.ArrayList; +import java.util.List; + /** Helpers related to levels **/ public class LevelHelper { @@ -28,5 +31,36 @@ public static float getAngleFromDirection(Direction dir) { } } + /** + * Gets a list of block positions for every direction + * @param referencePoint - Position to use for searching + * @param radius - Radius around the reference point to search for. + * @param interCardinal - if we need to include intercardinal directions such as (North-East, South-East etc.) + * @param includeReferencePoint - if we should include the reference point as part of the list too. + * @return + */ + public static List getBlockPosInRadius(BlockPos referencePoint, int radius, boolean interCardinal, boolean includeReferencePoint){ + List posList = new ArrayList<>(); + + //Add all horizontal directions, with the option of adding any intercardinal directions (North-East, South-East etc.) + List horizontalDirections = new ArrayList<>(); + horizontalDirections.addAll(Direction.Plane.HORIZONTAL.stream().toList()); + + for (Direction dir : horizontalDirections){ + BlockPos offsettedPos = referencePoint.relative(dir, radius); + posList.add(offsettedPos); + if (interCardinal) { + BlockPos interCardinalPos = offsettedPos.offset(dir.getClockWise().getNormal()); + posList.add(interCardinalPos); + } + } + + //If we want to include the original reference point, add it as well. + if(includeReferencePoint) + posList.add(referencePoint); + + return posList; + } + } 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 38bb164d2..876568a5e 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 @@ -5,7 +5,9 @@ import net.minecraft.network.chat.MutableComponent; import net.minecraft.resources.ResourceKey; import net.minecraft.resources.ResourceLocation; +import net.minecraft.server.TickTask; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.sounds.SoundEvents; import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.Entity; @@ -15,6 +17,8 @@ import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.material.Fluids; import net.minecraft.world.phys.Vec3; +import whocraft.tardis_refined.api.event.ShellChangeSource; +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; @@ -29,11 +33,11 @@ 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.patterns.ShellPattern; import whocraft.tardis_refined.patterns.ShellPatterns; import whocraft.tardis_refined.registry.TRBlockRegistry; import whocraft.tardis_refined.registry.TRDimensionTypes; +import java.util.Optional; import java.util.concurrent.atomic.AtomicBoolean; import static whocraft.tardis_refined.common.block.shell.ShellBaseBlock.LOCKED; @@ -79,8 +83,7 @@ public static boolean createTardis(BlockPos blockPos, ServerLevel serverLevel, R //Set the shell with this level shellBaseBlockEntity.setTardisId(generatedLevelKey); - shellBaseBlockEntity.setShellTheme(shellTheme); - shellBaseBlockEntity.setPattern(ShellPatterns.getPatternsForTheme(shellTheme).get(0)); + //Create the Level on demand which will create our capability ServerLevel interior = DimensionHandler.getOrCreateInterior(serverLevel, shellBaseBlockEntity.getTardisId().location()); @@ -100,6 +103,8 @@ public static boolean createTardis(BlockPos blockPos, ServerLevel serverLevel, R intManager.openTheEye(true); 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); } }); @@ -123,7 +128,7 @@ public static boolean teleportEntityTardis(TardisLevelOperator cap, Entity entit BlockPos destinationPos = destinationLocation.getPosition(); ServerLevel destinationLevel = destinationLocation.getLevel(); - Direction destinationDirection = destinationLocation.getDirection().getOpposite(); //Use the opposite facing of the destination so that when teleported, the entity faces away from the doorway + Direction destinationDirection = destinationLocation.getDirection(); //Do not use the opposite facing of the destination, we will handle the correct facing outside of this method. Direction sourceDirection = sourceLocation.getDirection(); @@ -186,4 +191,26 @@ public static boolean hasTheEndBeenCompleted(ServerLevel serverLevel) { return false; } + /** Common logic that we should apply to players if they happen to teleport to, respawn, or login to a Tardis + *
Ejecting players that happen to login to a Tardis dimension whilst the Tardis is still generating a desktop, we don't want them to suffocate*/ + public static void handlePlayerJoinWorldEvents(ServerPlayer serverPlayer){ + if (serverPlayer != null){ + if (serverPlayer.serverLevel() != null){ + ServerLevel playerLevel = serverPlayer.serverLevel(); + if(TardisLevelOperator.get(playerLevel).isPresent()){ + TardisLevelOperator cap = TardisLevelOperator.get(playerLevel).get(); + + //Handle ejecting players if they login to a Tardis dimension where the Tardis is in progress of generating a desktop + if (cap.getInteriorManager().isGeneratingDesktop()){ + //Delay the force ejecting to account for the chunk not being fully loaded, which can happen in the player change dimension event. + playerLevel.getServer().tell(new TickTask(10, () -> + cap.forceEjectPlayer(serverPlayer) + )); + } + + } + } + } + } + } diff --git a/common/src/main/java/whocraft/tardis_refined/compat/portals/ImmersivePortals.java b/common/src/main/java/whocraft/tardis_refined/compat/portals/ImmersivePortals.java index 03dff9e7f..9b0425654 100644 --- a/common/src/main/java/whocraft/tardis_refined/compat/portals/ImmersivePortals.java +++ b/common/src/main/java/whocraft/tardis_refined/compat/portals/ImmersivePortals.java @@ -287,7 +287,7 @@ public static void createPortals(TardisLevelOperator operator) { TardisNavLocation location = pilotingManager.getCurrentLocation(); - BlockPos entryPositionBPos = door.getEntryPosition(); + BlockPos entryPositionBPos = door.getTeleportPosition(); Vec3 entryPosition = new Vec3(entryPositionBPos.getX() + 0.5, entryPositionBPos.getY() + 1, entryPositionBPos.getZ() + 0.5); BlockPos exteriorEntryBPos = location.getPosition(); Vec3 exteriorEntryPosition = new Vec3(exteriorEntryBPos.getX() + 0.5, exteriorEntryBPos.getY() + 1, exteriorEntryBPos.getZ() + 0.5); @@ -307,14 +307,14 @@ public static void createPortals(TardisLevelOperator operator) { case NORTH -> exteriorEntryPosition = exteriorEntryPosition.add(exteriorDoor.north()); } - switch (door.getEntryRotation()) { + switch (door.getTeleportRotation()) { case EAST -> entryPosition = entryPosition.add(interiorDoor.east()); case SOUTH -> entryPosition = entryPosition.add(interiorDoor.south()); case WEST -> entryPosition = entryPosition.add(interiorDoor.west()); case NORTH -> entryPosition = entryPosition.add(interiorDoor.north()); } DQuaternion extQuat = DQuaternion.rotationByDegrees(new Vec3(0, -1, 0), location.getDirection().toYRot()); - DQuaternion interiorQuat = DQuaternion.rotationByDegrees(new Vec3(0, -1, 0), door.getEntryRotation().toYRot()); + DQuaternion interiorQuat = DQuaternion.rotationByDegrees(new Vec3(0, -1, 0), door.getTeleportRotation().toYRot()); BOTIPortalEntity exteriorPortal = createPortal(location.getLevel(), exteriorEntryPosition, entryPosition, operatorLevel.dimension(), extQuat); BOTIPortalEntity interiorPortal = createDestPortal(exteriorPortal, entryPosition, ImmersivePortals.BOTI_PORTAL.get(), interiorQuat); diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePattern.java b/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePattern.java index 1fc2f7d23..c7fd4dda5 100644 --- a/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePattern.java +++ b/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePattern.java @@ -4,6 +4,7 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.resources.ResourceLocation; import whocraft.tardis_refined.TardisRefined; +import whocraft.tardis_refined.patterns.sound.ConsoleSoundProfile; public class ConsolePattern extends BasePattern { @@ -11,24 +12,28 @@ public class ConsolePattern extends BasePattern { return instance.group( ResourceLocation.CODEC.fieldOf("id").forGetter(ConsolePattern::id), Codec.STRING.orElse("Placeholder").fieldOf("name_component").forGetter(BasePattern::name), - PatternTexture.getCodec().fieldOf("texture_definition").forGetter(ConsolePattern::patternTexture) + PatternTexture.getCodec().fieldOf("texture_definition").forGetter(ConsolePattern::patternTexture), + ConsoleSoundProfile.CODEC.fieldOf("sound_profile").forGetter(ConsolePattern::soundProfile) ).apply(instance, ConsolePattern::new); }); private final PatternTexture patternTexture; + private final ConsoleSoundProfile consoleSoundProfile; - public ConsolePattern(String identifier, PatternTexture textureDefinition) { - this(new ResourceLocation(TardisRefined.MODID, identifier), textureDefinition); + public ConsolePattern(String identifier, PatternTexture textureDefinition, ConsoleSoundProfile consoleSoundProfile) { + this(new ResourceLocation(TardisRefined.MODID, identifier), textureDefinition, consoleSoundProfile); } - public ConsolePattern(ResourceLocation identifier, PatternTexture textureDefinition) { + public ConsolePattern(ResourceLocation identifier, PatternTexture textureDefinition, ConsoleSoundProfile consoleSoundProfile) { super(identifier); this.patternTexture = textureDefinition; + this.consoleSoundProfile = consoleSoundProfile; } - public ConsolePattern(ResourceLocation identifier, String name, PatternTexture textureDefinition) { + public ConsolePattern(ResourceLocation identifier, String name, PatternTexture textureDefinition, ConsoleSoundProfile consoleSoundProfile) { super(identifier, name); this.patternTexture = textureDefinition; + this.consoleSoundProfile = consoleSoundProfile; } public PatternTexture patternTexture(){ @@ -43,6 +48,10 @@ public ResourceLocation emissiveTexture(){ return this.patternTexture.emissiveTexture(); } + public ConsoleSoundProfile soundProfile() { + return this.consoleSoundProfile; + } + @Override public Codec getCodec() { return CODEC; diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePatterns.java b/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePatterns.java index 99996c68b..c58f2f27b 100644 --- a/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePatterns.java +++ b/common/src/main/java/whocraft/tardis_refined/patterns/ConsolePatterns.java @@ -6,6 +6,8 @@ import whocraft.tardis_refined.common.tardis.themes.ShellTheme; import whocraft.tardis_refined.common.util.Platform; import whocraft.tardis_refined.constants.ResourceConstants; +import whocraft.tardis_refined.patterns.sound.ConsoleSoundProfile; +import whocraft.tardis_refined.patterns.sound.TRConsoleSoundProfiles; import java.util.*; @@ -18,7 +20,7 @@ public class ConsolePatterns{ private static Map> DEFAULT_PATTERNS = new HashMap(); - public static final ConsolePattern DEFAULT = (ConsolePattern) new ConsolePattern(ResourceConstants.DEFAULT_PATTERN_ID, new PatternTexture(createConsolePatternTextureLocation(ConsoleTheme.FACTORY.getId(), ConsoleTheme.FACTORY.getId().getPath() + "_console"), true)).setThemeId(ConsoleTheme.FACTORY.getId()); + public static final ConsolePattern DEFAULT = (ConsolePattern) new ConsolePattern(ResourceConstants.DEFAULT_PATTERN_ID, new PatternTexture(createConsolePatternTextureLocation(ConsoleTheme.FACTORY.getId(), ConsoleTheme.FACTORY.getId().getPath() + "_console"), true), TRConsoleSoundProfiles.DEFAULT_SOUND_PROFILE).setThemeId(ConsoleTheme.FACTORY.getId()); public static PatternReloadListener getReloadListener(){ return PATTERNS; @@ -98,15 +100,19 @@ public static ConsolePattern next(List patterns, ConsolePattern return patterns.get(prevIndex + 1); } + private static ConsolePattern addDefaultPattern(ResourceLocation themeId, String patternId, String textureName, boolean hasEmissiveTexture) { + return addDefaultPattern(themeId, patternId, textureName, hasEmissiveTexture, TRConsoleSoundProfiles.DEFAULT_SOUND_PROFILE); + } + /** Constructs and a {@link ConsolePattern}, then adds it to a {@link ConsolePatternCollection}, which is assigned to a {@link ConsoleTheme}. *
The {@link ConsolePatternCollection} is then added to an internal default map *
Also assigns the {@link ConsolePattern} its parent {@link ConsoleTheme}'s ID * @implSpec INTERNAL USE ONLY * */ - private static ConsolePattern addDefaultPattern(ResourceLocation themeId, String patternId, String textureName, boolean hasEmissiveTexture) { + private static ConsolePattern addDefaultPattern(ResourceLocation themeId, String patternId, String textureName, boolean hasEmissiveTexture, ConsoleSoundProfile soundProfile) { List consolePatternList; - ConsolePattern pattern = (ConsolePattern) new ConsolePattern(patternId, new PatternTexture(createConsolePatternTextureLocation(themeId,textureName), hasEmissiveTexture)).setThemeId(themeId); + ConsolePattern pattern = (ConsolePattern) new ConsolePattern(patternId, new PatternTexture(createConsolePatternTextureLocation(themeId,textureName), hasEmissiveTexture), soundProfile).setThemeId(themeId); if (DEFAULT_PATTERNS.containsKey(themeId)) { consolePatternList = DEFAULT_PATTERNS.get(themeId); diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/PatternResourceConstants.java b/common/src/main/java/whocraft/tardis_refined/patterns/PatternResourceConstants.java new file mode 100644 index 000000000..8af79a386 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/patterns/PatternResourceConstants.java @@ -0,0 +1,22 @@ +package whocraft.tardis_refined.patterns; + +import net.minecraft.resources.ResourceLocation; +import whocraft.tardis_refined.common.util.RegistryHelper; + +public class PatternResourceConstants { + + public static ResourceLocation DOOR_OPEN_KEY = RegistryHelper.makeKey("door_open"); + public static ResourceLocation DOOR_CLOSE_KEY = RegistryHelper.makeKey("door_close"); + public static ResourceLocation DOOR_LOCK_KEY = RegistryHelper.makeKey("door_lock"); + public static ResourceLocation DOOR_UNLOCK_KEY = RegistryHelper.makeKey("door_unlock"); + + + + public static ResourceLocation GENERIC_CONSOLE_KEY = RegistryHelper.makeKey("generic_console"); + + public static ResourceLocation THROTTLE_ENABLE_KEY = RegistryHelper.makeKey("throttle_enable"); + public static ResourceLocation THROTTLE_DISABLE_KEY = RegistryHelper.makeKey("throttle_disable"); + public static ResourceLocation HANDBRAKE_ENABLE_KEY = RegistryHelper.makeKey("handbrake_enable"); + public static ResourceLocation HANDBRAKE_DISABLE_KEY = RegistryHelper.makeKey("handbrake_disable"); + +} diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/ShellPattern.java b/common/src/main/java/whocraft/tardis_refined/patterns/ShellPattern.java index 7e26c5619..277c7bcb5 100644 --- a/common/src/main/java/whocraft/tardis_refined/patterns/ShellPattern.java +++ b/common/src/main/java/whocraft/tardis_refined/patterns/ShellPattern.java @@ -3,7 +3,8 @@ import com.mojang.serialization.Codec; import com.mojang.serialization.codecs.RecordCodecBuilder; import net.minecraft.resources.ResourceLocation; -import whocraft.tardis_refined.TardisRefined; +import whocraft.tardis_refined.common.util.RegistryHelper; +import whocraft.tardis_refined.patterns.sound.ShellSoundProfile; public class ShellPattern extends BasePattern { @@ -12,27 +13,32 @@ public class ShellPattern extends BasePattern { ResourceLocation.CODEC.fieldOf("id").forGetter(ShellPattern::id), Codec.STRING.orElse("Placeholder").fieldOf("name_component").forGetter(ShellPattern::name), PatternTexture.getCodec().fieldOf("exterior").forGetter(ShellPattern::exteriorDoorTexture), - PatternTexture.getCodec().fieldOf("interior").forGetter(ShellPattern::interiorDoorTexture) + PatternTexture.getCodec().fieldOf("interior").forGetter(ShellPattern::interiorDoorTexture), + ShellSoundProfile.CODEC.fieldOf("sound_profile").forGetter(ShellPattern::soundProfile) ).apply(instance, ShellPattern::new); }); private final PatternTexture interiorDoorTexture; private final PatternTexture exteriorDoorTexture; - public ShellPattern(String identifier, PatternTexture exteriorDoorTexture, PatternTexture interiorDoorTexture) { - this(new ResourceLocation(TardisRefined.MODID,identifier), exteriorDoorTexture, interiorDoorTexture); + private final ShellSoundProfile shellSoundProfile; + + public ShellPattern(String identifier, PatternTexture exteriorDoorTexture, PatternTexture interiorDoorTexture, ShellSoundProfile shellSoundProfile) { + this(RegistryHelper.makeKey(identifier), exteriorDoorTexture, interiorDoorTexture, shellSoundProfile); } - public ShellPattern(ResourceLocation identifier, PatternTexture exteriorDoorTexture, PatternTexture interiorDoorTexture) { + public ShellPattern(ResourceLocation identifier, PatternTexture exteriorDoorTexture, PatternTexture interiorDoorTexture, ShellSoundProfile shellSoundProfile) { super(identifier); this.exteriorDoorTexture = exteriorDoorTexture; this.interiorDoorTexture = interiorDoorTexture; + this.shellSoundProfile = shellSoundProfile; } - public ShellPattern(ResourceLocation identifier, String name, PatternTexture exteriorDoorTexture, PatternTexture interiorDoorTexture) { + public ShellPattern(ResourceLocation identifier, String name, PatternTexture exteriorDoorTexture, PatternTexture interiorDoorTexture, ShellSoundProfile shellSoundProfile) { super(identifier, name); this.exteriorDoorTexture = exteriorDoorTexture; this.interiorDoorTexture = interiorDoorTexture; + this.shellSoundProfile = shellSoundProfile; } public PatternTexture exteriorDoorTexture(){return this.exteriorDoorTexture;} @@ -43,4 +49,8 @@ public ShellPattern(ResourceLocation identifier, String name, PatternTexture ext public Codec getCodec() { return CODEC; } + + public ShellSoundProfile soundProfile(){ + return this.shellSoundProfile; + } } diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/ShellPatterns.java b/common/src/main/java/whocraft/tardis_refined/patterns/ShellPatterns.java index 392284b18..6ebc6760d 100644 --- a/common/src/main/java/whocraft/tardis_refined/patterns/ShellPatterns.java +++ b/common/src/main/java/whocraft/tardis_refined/patterns/ShellPatterns.java @@ -6,6 +6,8 @@ import whocraft.tardis_refined.common.tardis.themes.ShellTheme; import whocraft.tardis_refined.common.util.Platform; import whocraft.tardis_refined.constants.ResourceConstants; +import whocraft.tardis_refined.patterns.sound.ShellSoundProfile; +import whocraft.tardis_refined.patterns.sound.TRShellSoundProfiles; import java.util.*; @@ -15,8 +17,8 @@ public class ShellPatterns { private static Map> DEFAULT_PATTERNS = new HashMap(); - public static final ShellPattern DEFAULT = (ShellPattern) new ShellPattern(ResourceConstants.DEFAULT_PATTERN_ID.getPath(), new PatternTexture(exteriorTextureLocation(ShellTheme.FACTORY.getId(), ShellTheme.FACTORY.getId().getPath()), false) - , new PatternTexture(interiorTextureLocation(ShellTheme.FACTORY.getId(), ShellTheme.FACTORY.getId().getPath()), false)).setThemeId(ConsoleTheme.FACTORY.getId()); + public static final ShellPattern DEFAULT = (ShellPattern) new ShellPattern(ResourceConstants.DEFAULT_PATTERN_ID, new PatternTexture(exteriorTextureLocation(ShellTheme.FACTORY.getId(), ShellTheme.FACTORY.getId().getPath()), false) + , new PatternTexture(interiorTextureLocation(ShellTheme.FACTORY.getId(), ShellTheme.FACTORY.getId().getPath()), false), TRShellSoundProfiles.DEFAULT_SOUND_PROFILE).setThemeId(ConsoleTheme.FACTORY.getId()); public static PatternReloadListener getReloadListener(){ return PATTERNS; @@ -122,8 +124,12 @@ public static ShellPattern addDefaultPattern(ResourceLocation themeId, ShellPatt } public static ShellPattern addDefaultPattern(ResourceLocation themeId, String patternName, boolean hasEmissiveTexture) { + return addDefaultPattern(themeId, patternName, hasEmissiveTexture, TRShellSoundProfiles.DEFAULT_SOUND_PROFILE); + } + + public static ShellPattern addDefaultPattern(ResourceLocation themeId, String patternName, boolean hasEmissiveTexture, ShellSoundProfile soundProfile) { ShellPattern pattern = (ShellPattern) new ShellPattern(patternName, new PatternTexture(exteriorTextureLocation(themeId, patternName), hasEmissiveTexture) - , new PatternTexture(interiorTextureLocation(themeId, patternName), hasEmissiveTexture)).setThemeId(themeId); + , new PatternTexture(interiorTextureLocation(themeId, patternName), hasEmissiveTexture), soundProfile).setThemeId(themeId); return addDefaultPattern(themeId, pattern); } @@ -165,9 +171,11 @@ public static Map> registerDefaultPatterns( for (ResourceLocation shellTheme : ShellTheme.SHELL_THEME_REGISTRY.keySet()) { boolean hasDefaultEmission = shellTheme == ShellTheme.MYSTIC.getId() || shellTheme == ShellTheme.NUKA.getId() || shellTheme == ShellTheme.PAGODA.getId() || shellTheme == ShellTheme.PHONE_BOOTH.getId() || shellTheme == ShellTheme.POLICE_BOX.getId() || shellTheme == ShellTheme.VENDING.getId(); String textureName = shellTheme.getPath(); + ShellSoundProfile soundProfile = TRShellSoundProfiles.defaultSoundProfilesByTheme().getOrDefault(shellTheme, TRShellSoundProfiles.DEFAULT_SOUND_PROFILE); + //Use an overload version of the method for default shells because the texture files were named based on shell theme name - ShellPattern pattern = new ShellPattern(ResourceConstants.DEFAULT_PATTERN_ID.getPath(), new PatternTexture(exteriorTextureLocation(shellTheme, textureName), hasDefaultEmission) - , new PatternTexture(interiorTextureLocation(shellTheme, textureName), hasDefaultEmission)); + ShellPattern pattern = new ShellPattern(ResourceConstants.DEFAULT_PATTERN_ID, new PatternTexture(exteriorTextureLocation(shellTheme, textureName), hasDefaultEmission) + , new PatternTexture(interiorTextureLocation(shellTheme, textureName), hasDefaultEmission), soundProfile); addDefaultPattern(shellTheme, pattern); } diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConfiguredSound.java b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConfiguredSound.java new file mode 100644 index 000000000..9b57cfaeb --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConfiguredSound.java @@ -0,0 +1,57 @@ +package whocraft.tardis_refined.patterns.sound; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvent; + +/** + * An abstraction over the SoundEvent object which allows datapacks to define and intended pitch and volume to play. + **/ +public class ConfiguredSound { + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> { + return instance.group( + SoundEvent.DIRECT_CODEC.fieldOf("sound_event").forGetter(ConfiguredSound::getSoundEvent), + Codec.FLOAT.fieldOf("pitch").forGetter(ConfiguredSound::getPitch), + Codec.FLOAT.fieldOf("volume").forGetter(ConfiguredSound::getVolume) + ).apply(instance, ConfiguredSound::new); + }); + + private final SoundEvent soundEvent; + private final float pitch; + + private final float volume; + + + /** Constructor for data driven entries*/ + public ConfiguredSound(SoundEvent soundEvent, float pitch, float volume) { + this.soundEvent = soundEvent; + this.pitch = pitch; + this.volume = volume; + } + + public ConfiguredSound(SoundEvent soundEvent, float pitch){ + this(soundEvent, pitch, 1F); + } + + public ConfiguredSound(SoundEvent event){ + this(event, 1F, 1F); + } + + public SoundEvent getSoundEvent() { + return this.soundEvent; + } + + public ResourceLocation getSoundEventKey() { + return this.soundEvent.getLocation(); + } + + public float getPitch() { + return pitch; + } + + public float getVolume() { + return this.volume; + } +} diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConsoleSound.java b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConsoleSound.java new file mode 100644 index 000000000..9e1d6539c --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConsoleSound.java @@ -0,0 +1,32 @@ +package whocraft.tardis_refined.patterns.sound; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; + +import javax.annotation.Nullable; + + +/** + * Sound for a specific action, featuring left, right and failure presses. + **/ +public record ConsoleSound(ConfiguredSound leftClick, ConfiguredSound rightClick) { + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> { + return instance.group( + ConfiguredSound.CODEC.fieldOf("left_click").forGetter(ConsoleSound::leftClick), + ConfiguredSound.CODEC.fieldOf("right_click").forGetter(ConsoleSound::rightClick) + ).apply(instance, ConsoleSound::new); + }); + + + /** + * Datatype for referencing a sound event for how a player would interact with a control. + * + * @param leftClick the sound event fired when a control is left-clicked.; + * @param rightClick the sound event fired when a control is right-clicked; + */ + public ConsoleSound(@Nullable ConfiguredSound leftClick, @Nullable ConfiguredSound rightClick) { + this.leftClick = leftClick; + this.rightClick = rightClick; + } +} diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConsoleSoundProfile.java b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConsoleSoundProfile.java new file mode 100644 index 000000000..0cc29d818 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ConsoleSoundProfile.java @@ -0,0 +1,85 @@ +package whocraft.tardis_refined.patterns.sound; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.mojang.serialization.codecs.UnboundedMapCodec; +import net.minecraft.resources.ResourceLocation; +import whocraft.tardis_refined.patterns.PatternResourceConstants; + +import java.util.HashMap; +import java.util.Map; +/** An object that allows for grouping of sounds to play in a specific Tardis interaction event + *
In this case, the controls on the console will look at the console's pattern */ +public class ConsoleSoundProfile { + + protected Map consoleSoundEntries = new HashMap<>(); + + private static final UnboundedMapCodec UNBOUNDED_MAP_CODEC = Codec.unboundedMap(ResourceLocation.CODEC, ConsoleSound.CODEC); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> { + return instance.group( + ConsoleSoundProfile.UNBOUNDED_MAP_CODEC.fieldOf("sounds").forGetter(ConsoleSoundProfile::getSoundEntries) + ).apply(instance, ConsoleSoundProfile::new); + }); + + + public ConsoleSoundProfile(Map consoleSoundEntries){ + this.consoleSoundEntries = consoleSoundEntries; + } + + public ConsoleSoundProfile(){ + this(new HashMap<>()); + } + + public Map getSoundEntries() { + return consoleSoundEntries; + } + + public ConsoleSound getThrottleEnable() { + return this.consoleSoundEntries.get(PatternResourceConstants.THROTTLE_ENABLE_KEY); + } + + public ConsoleSoundProfile setThrottleEnable(ConsoleSound throttleEnable) { + this.consoleSoundEntries.put(PatternResourceConstants.THROTTLE_ENABLE_KEY, throttleEnable); + return this; + } + + public ConsoleSound getThrottleDisable() { + return this.consoleSoundEntries.get(PatternResourceConstants.THROTTLE_DISABLE_KEY); + } + + public ConsoleSoundProfile setThrottleDisable(ConsoleSound throttleDisable) { + this.consoleSoundEntries.put(PatternResourceConstants.THROTTLE_DISABLE_KEY, throttleDisable); + return this; + } + + public ConsoleSound getHandbrakeEnable() { + return this.consoleSoundEntries.get(PatternResourceConstants.HANDBRAKE_ENABLE_KEY); + } + + public ConsoleSoundProfile setHandbrakeEnable(ConsoleSound handbrakeEnable) { + this.consoleSoundEntries.put(PatternResourceConstants.HANDBRAKE_ENABLE_KEY, handbrakeEnable); + return this; + } + + public ConsoleSound getHandbrakeDisable() { + return this.consoleSoundEntries.get(PatternResourceConstants.HANDBRAKE_DISABLE_KEY); + } + + public ConsoleSoundProfile setHandbrakeDisable(ConsoleSound handbrakeDisable) { + this.consoleSoundEntries.put(PatternResourceConstants.HANDBRAKE_DISABLE_KEY, handbrakeDisable); + return this; + } + + public ConsoleSound getGeneric() { + return this.consoleSoundEntries.get(PatternResourceConstants.GENERIC_CONSOLE_KEY); + } + + public ConsoleSoundProfile setGeneric(ConsoleSound generic) { + this.consoleSoundEntries.put(PatternResourceConstants.GENERIC_CONSOLE_KEY, generic); + return this; + } + + + +} diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/sound/ShellSoundProfile.java b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ShellSoundProfile.java new file mode 100644 index 000000000..d2e26882b --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/patterns/sound/ShellSoundProfile.java @@ -0,0 +1,73 @@ +package whocraft.tardis_refined.patterns.sound; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import com.mojang.serialization.codecs.UnboundedMapCodec; +import net.minecraft.resources.ResourceLocation; +import whocraft.tardis_refined.patterns.PatternResourceConstants; + +import java.util.HashMap; +import java.util.Map; +/** An object that allows for grouping of sounds to play in a specific Tardis interaction event + *
In this case, the Exterior Shell and Internal Door will play a sound based on the pattern*/ +public class ShellSoundProfile { + + protected Map shellSoundEntries = new HashMap<>(); + + private static final UnboundedMapCodec UNBOUNDED_MAP_CODEC = Codec.unboundedMap(ResourceLocation.CODEC, ConfiguredSound.CODEC); + + public static final Codec CODEC = RecordCodecBuilder.create(instance -> { + return instance.group( + ShellSoundProfile.UNBOUNDED_MAP_CODEC.fieldOf("sounds").forGetter(ShellSoundProfile::getSoundEntries) + ).apply(instance, ShellSoundProfile::new); + }); + + + public ShellSoundProfile(Map shellSoundEntries){ + this.shellSoundEntries = shellSoundEntries; + } + + public ShellSoundProfile(){ + this(new HashMap<>()); + } + + public Map getSoundEntries() { + return shellSoundEntries; + } + + public ConfiguredSound getDoorOpen() { + return this.shellSoundEntries.get(PatternResourceConstants.DOOR_OPEN_KEY); + } + + public ShellSoundProfile setDoorOpen(ConfiguredSound doorOpen) { + this.shellSoundEntries.put(PatternResourceConstants.DOOR_OPEN_KEY, doorOpen); + return this; + } + + public ConfiguredSound getDoorClose() { + return this.shellSoundEntries.get(PatternResourceConstants.DOOR_CLOSE_KEY); + } + + public ShellSoundProfile setDoorClose(ConfiguredSound doorClose) { + this.shellSoundEntries.put(PatternResourceConstants.DOOR_CLOSE_KEY, doorClose); + return this; + } + + public ConfiguredSound getDoorLocked() { + return this.shellSoundEntries.get(PatternResourceConstants.DOOR_LOCK_KEY); + } + + public ShellSoundProfile setDoorLocked(ConfiguredSound doorLocked) { + this.shellSoundEntries.put(PatternResourceConstants.DOOR_LOCK_KEY, doorLocked); + return this; + } + + public ConfiguredSound getDoorUnlocked() { + return this.shellSoundEntries.get(PatternResourceConstants.DOOR_UNLOCK_KEY); + } + + public ShellSoundProfile setDoorUnlocked(ConfiguredSound doorUnlocked) { + this.shellSoundEntries.put(PatternResourceConstants.DOOR_UNLOCK_KEY, doorUnlocked); + return this; + } +} diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/sound/TRConsoleSoundProfiles.java b/common/src/main/java/whocraft/tardis_refined/patterns/sound/TRConsoleSoundProfiles.java new file mode 100644 index 000000000..baf5276c2 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/patterns/sound/TRConsoleSoundProfiles.java @@ -0,0 +1,21 @@ +package whocraft.tardis_refined.patterns.sound; + +import net.minecraft.sounds.SoundEvents; + +public class TRConsoleSoundProfiles { + + public static ConfiguredSound EMPTY_SOUND = new ConfiguredSound(SoundEvents.EMPTY, 1f, 0F); + public static ConfiguredSound DEFAULT_LEFT_CLICK = new ConfiguredSound(SoundEvents.STONE_BUTTON_CLICK_ON, 0.95f, 1F); + public static ConfiguredSound DEFAULT_RIGHT_CLICK = new ConfiguredSound(SoundEvents.STONE_BUTTON_CLICK_ON, 1.1f, 1F); + public static ConfiguredSound DEFAULT_FLIGHT_CONTROL_ENABLE = new ConfiguredSound(SoundEvents.LEVER_CLICK, 0.6f, 1F); + public static ConfiguredSound DEFAULT_FLIGHT_CONTROL_DISABLE = new ConfiguredSound(SoundEvents.LEVER_CLICK, 0.5f, 1F); + + + public static ConsoleSoundProfile DEFAULT_SOUND_PROFILE = new ConsoleSoundProfile() + .setGeneric(new ConsoleSound(DEFAULT_LEFT_CLICK, DEFAULT_RIGHT_CLICK)) + .setHandbrakeEnable(new ConsoleSound(EMPTY_SOUND, DEFAULT_FLIGHT_CONTROL_ENABLE)) + .setHandbrakeDisable(new ConsoleSound(EMPTY_SOUND, DEFAULT_FLIGHT_CONTROL_DISABLE)) + .setThrottleEnable(new ConsoleSound(EMPTY_SOUND, DEFAULT_FLIGHT_CONTROL_ENABLE)) + .setThrottleDisable(new ConsoleSound(EMPTY_SOUND, DEFAULT_FLIGHT_CONTROL_DISABLE)); + +} diff --git a/common/src/main/java/whocraft/tardis_refined/patterns/sound/TRShellSoundProfiles.java b/common/src/main/java/whocraft/tardis_refined/patterns/sound/TRShellSoundProfiles.java new file mode 100644 index 000000000..4ca4c6923 --- /dev/null +++ b/common/src/main/java/whocraft/tardis_refined/patterns/sound/TRShellSoundProfiles.java @@ -0,0 +1,73 @@ +package whocraft.tardis_refined.patterns.sound; + +import net.minecraft.resources.ResourceLocation; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.level.block.state.properties.BlockSetType; +import whocraft.tardis_refined.common.tardis.themes.ShellTheme; + +import java.util.HashMap; +import java.util.Map; + +public class TRShellSoundProfiles { + + public static ConfiguredSound DEFAULT_DOOR_OPEN = new ConfiguredSound(BlockSetType.IRON.doorOpen(), 1F, 1F); + public static ConfiguredSound DEFAULT_DOOR_CLOSE = new ConfiguredSound(BlockSetType.IRON.doorClose(), 1F, 1.4F); + public static ConfiguredSound DEFAULT_DOOR_LOCK = new ConfiguredSound(BlockSetType.IRON.trapdoorClose(), 1F, 1.4F); + public static ConfiguredSound DEFAULT_DOOR_UNLOCK = new ConfiguredSound(BlockSetType.IRON.trapdoorOpen(), 1F, 1F); + + public static Map DEFAULT_PATTERN_SOUND_PROFILES = new HashMap<>(); + + public static Map defaultSoundProfilesByTheme(){ + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.HALF_BAKED.getId(), HALF_BAKED_SOUND_PROFILE); + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.BRIEFCASE.getId(), DEFAULT_SOUND_PROFILE); + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.PHONE_BOOTH.getId(), SPRUCE_SOUND_PROFILE); + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.BIG_BEN.getId(), OAK_SOUND_PROFILE); + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.GROWTH.getId(), HALF_BAKED_SOUND_PROFILE); + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.DRIFTER.getId(), WOOL_SOUND_PROFILE); + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.PAGODA.getId(), BAMBOO_SOUND_PROFILE); + DEFAULT_PATTERN_SOUND_PROFILES.put(ShellTheme.PATHFINDER.getId(), SPRUCE_SOUND_PROFILE); + return DEFAULT_PATTERN_SOUND_PROFILES; + } + + public static ShellSoundProfile DEFAULT_SOUND_PROFILE = new ShellSoundProfile() + .setDoorOpen(DEFAULT_DOOR_OPEN) + .setDoorClose(DEFAULT_DOOR_CLOSE) + .setDoorLocked(DEFAULT_DOOR_LOCK) + .setDoorUnlocked(DEFAULT_DOOR_UNLOCK); + + public static ShellSoundProfile HALF_BAKED_SOUND_PROFILE = new ShellSoundProfile() + .setDoorOpen(DEFAULT_DOOR_OPEN) + .setDoorClose(DEFAULT_DOOR_CLOSE) + .setDoorLocked(new ConfiguredSound(SoundEvents.WEEPING_VINES_PLACE, 1F, 1.4F)) + .setDoorUnlocked(new ConfiguredSound(SoundEvents.WEEPING_VINES_BREAK, 1F, 1.4F)); + + public static ShellSoundProfile WOOL_SOUND_PROFILE = new ShellSoundProfile() + .setDoorOpen(new ConfiguredSound(SoundEvents.WOOL_PLACE, 1F, 1F)) + .setDoorClose(new ConfiguredSound(SoundEvents.WOOL_BREAK, 1F, 1.4F)) + .setDoorLocked(DEFAULT_DOOR_LOCK) + .setDoorUnlocked(DEFAULT_DOOR_UNLOCK); + + public static ShellSoundProfile OAK_SOUND_PROFILE = new ShellSoundProfile() + .setDoorOpen(new ConfiguredSound(BlockSetType.OAK.doorOpen(), 1F, 1F)) + .setDoorClose(new ConfiguredSound(BlockSetType.OAK.doorClose(), 1F, 1.4F)) + .setDoorLocked(new ConfiguredSound(BlockSetType.OAK.trapdoorClose(), 1F, 1.4F)) + .setDoorUnlocked(new ConfiguredSound(BlockSetType.OAK.trapdoorOpen(), 1F, 1F)); + + public static ShellSoundProfile DARK_OAK_SOUND_PROFILE = new ShellSoundProfile() + .setDoorOpen(new ConfiguredSound(BlockSetType.DARK_OAK.doorOpen(), 1F, 1F)) + .setDoorClose(new ConfiguredSound(BlockSetType.DARK_OAK.doorClose(), 1F, 1.4F)) + .setDoorLocked(new ConfiguredSound(BlockSetType.DARK_OAK.trapdoorClose(), 1F, 1.4F)) + .setDoorUnlocked(new ConfiguredSound(BlockSetType.DARK_OAK.trapdoorOpen(), 1F, 1F)); + + public static ShellSoundProfile SPRUCE_SOUND_PROFILE = new ShellSoundProfile() + .setDoorOpen(new ConfiguredSound(BlockSetType.SPRUCE.doorOpen(), 1F, 1F)) + .setDoorClose(new ConfiguredSound(BlockSetType.SPRUCE.doorClose(), 1F, 1.4F)) + .setDoorLocked(new ConfiguredSound(BlockSetType.SPRUCE.trapdoorClose(), 1F, 1.4F)) + .setDoorUnlocked(new ConfiguredSound(BlockSetType.SPRUCE.trapdoorOpen(), 1F, 1F)); + + public static ShellSoundProfile BAMBOO_SOUND_PROFILE = new ShellSoundProfile() + .setDoorOpen(new ConfiguredSound(BlockSetType.BAMBOO.doorOpen(), 1F, 1F)) + .setDoorClose(new ConfiguredSound(BlockSetType.BAMBOO.doorClose(), 1F, 1.4F)) + .setDoorLocked(new ConfiguredSound(BlockSetType.BAMBOO.trapdoorClose(), 1F, 1.4F)) + .setDoorUnlocked(new ConfiguredSound(BlockSetType.BAMBOO.trapdoorOpen(), 1F, 1F)); +} diff --git a/common/src/main/java/whocraft/tardis_refined/registry/TRSoundRegistry.java b/common/src/main/java/whocraft/tardis_refined/registry/TRSoundRegistry.java index 25a3d3de3..bab62f7dc 100644 --- a/common/src/main/java/whocraft/tardis_refined/registry/TRSoundRegistry.java +++ b/common/src/main/java/whocraft/tardis_refined/registry/TRSoundRegistry.java @@ -25,7 +25,7 @@ public class TRSoundRegistry { public static final RegistrySupplier CONSOLE_POWER_ON = setUpSound("console_power_on"); public static final RegistrySupplier INTERIOR_VOICE = setUpSound("interior_voice"); public static final RegistrySupplier LOW_FUEL = setUpSound("low_fuel"); - public static final RegistrySupplier ARTRON_PILLAR = setUpSound("artron_pillar_active"); + public static final RegistrySupplier ARTRON_PILLAR_ACTIVE = setUpSound("artron_pillar_active"); public static final RegistrySupplier CORRIDOR_TELEPORTER = setUpSound("corridor_teleporter"); public static final RegistrySupplier CORRIDOR_TELEPORTER_SUCCESS = setUpSound("corridor_teleporter_success"); diff --git a/common/src/main/resources/tardis_refined-common.mixins.json b/common/src/main/resources/tardis_refined-common.mixins.json index 93afdcfa9..f00d11afd 100644 --- a/common/src/main/resources/tardis_refined-common.mixins.json +++ b/common/src/main/resources/tardis_refined-common.mixins.json @@ -6,7 +6,8 @@ "mixins": [ "EndDragonFightAccessor", "MinecraftServerStorageAccessor", - "PlayerEntityMixin" + "PlayerEntityMixin", + "MappedRegistryAccessor" ], "client": [ "FogRendererMixin", diff --git a/fabric/src/main/java/whocraft/tardis_refined/common/dimension/fabric/DimensionHandlerImpl.java b/fabric/src/main/java/whocraft/tardis_refined/common/dimension/fabric/DimensionHandlerImpl.java index 5d80295af..9ad9bfdda 100644 --- a/fabric/src/main/java/whocraft/tardis_refined/common/dimension/fabric/DimensionHandlerImpl.java +++ b/fabric/src/main/java/whocraft/tardis_refined/common/dimension/fabric/DimensionHandlerImpl.java @@ -1,12 +1,13 @@ package whocraft.tardis_refined.common.dimension.fabric; import com.google.common.collect.ImmutableList; -import com.google.gson.JsonElement; -import com.google.gson.JsonObject; +import com.mojang.serialization.Lifecycle; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerWorldEvents; import net.minecraft.core.BlockPos; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; -import net.minecraft.resources.ResourceLocation; import net.minecraft.server.MinecraftServer; import net.minecraft.server.level.ServerChunkCache; import net.minecraft.server.level.ServerLevel; @@ -22,16 +23,12 @@ import net.minecraft.world.level.storage.DerivedLevelData; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.WorldData; -import whocraft.tardis_refined.TardisRefined; import whocraft.tardis_refined.common.dimension.DimensionHandler; +import whocraft.tardis_refined.common.mixin.MappedRegistryAccessor; import whocraft.tardis_refined.common.network.messages.sync.SyncLevelListMessage; import whocraft.tardis_refined.compat.ModCompatChecker; import whocraft.tardis_refined.compat.portals.ImmersivePortals; -import java.io.File; -import java.io.IOException; -import java.io.Reader; -import java.nio.file.Files; import java.util.concurrent.Executor; import java.util.function.BiFunction; @@ -62,6 +59,17 @@ public static ServerLevel createDimension(Level level, ResourceKey id) { WorldData serverConfig = server.getWorldData(); DerivedLevelData derivedWorldInfo = new DerivedLevelData(serverConfig, serverConfig.overworldData()); + //Actually register our dimension + Registry dimensionRegistry = server.registryAccess().registryOrThrow(Registries.LEVEL_STEM); + if (dimensionRegistry instanceof MappedRegistry writableRegistry) { + MappedRegistryAccessor accessor = (MappedRegistryAccessor)writableRegistry; + accessor.setFrozen(false); //Must unfreeze registry to allow our dimension to persist + writableRegistry.register(dimensionKey, dimension, Lifecycle.stable()); + } + else { + throw new IllegalStateException(String.format("Unable to register dimension %s -- dimension registry not writable", dimensionKey.location())); + } + // now we have everything we need to create the world instance ServerLevel newLevel = new ServerLevel( server, @@ -86,9 +94,11 @@ public static ServerLevel createDimension(Level level, ResourceKey id) { server.levels.put(id, newLevel); + ServerWorldEvents.LOAD.invoker().onWorldLoad(server, newLevel); new SyncLevelListMessage(newLevel.dimension(), true).sendToAll(); + BlockPos blockPos = new BlockPos(0, 0, 0); ChunkPos chunkPos = new ChunkPos(blockPos); chunkListener.updateSpawnPos(chunkPos); diff --git a/fabric/src/main/java/whocraft/tardis_refined/fabric/events/ModEvents.java b/fabric/src/main/java/whocraft/tardis_refined/fabric/events/ModEvents.java index 3cf5cf18f..34ab95f89 100644 --- a/fabric/src/main/java/whocraft/tardis_refined/fabric/events/ModEvents.java +++ b/fabric/src/main/java/whocraft/tardis_refined/fabric/events/ModEvents.java @@ -4,11 +4,15 @@ import net.fabricmc.fabric.api.client.rendering.v1.ColorProviderRegistry; import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback; +import net.fabricmc.fabric.api.entity.event.v1.ServerEntityWorldChangeEvents; +import net.fabricmc.fabric.api.entity.event.v1.ServerPlayerEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents; import net.fabricmc.fabric.api.event.lifecycle.v1.ServerTickEvents; import net.fabricmc.fabric.api.event.player.PlayerBlockBreakEvents; -import net.minecraft.server.MinecraftServer; +import net.fabricmc.fabric.api.networking.v1.ServerPlayConnectionEvents; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.world.entity.EntityEvent; import net.minecraft.world.level.Level; import whocraft.tardis_refined.ControlGroupCheckers; import whocraft.tardis_refined.client.GravityOverlay; @@ -16,11 +20,11 @@ import whocraft.tardis_refined.client.TardisClientLogic; import whocraft.tardis_refined.command.TardisRefinedCommand; import whocraft.tardis_refined.common.capability.TardisLevelOperator; -import whocraft.tardis_refined.common.crafting.astral_manipulator.ManipulatorRecipes; import whocraft.tardis_refined.common.dimension.DimensionHandler; import whocraft.tardis_refined.common.dimension.TardisTeleportData; import whocraft.tardis_refined.common.dimension.fabric.DimensionHandlerImpl; import whocraft.tardis_refined.common.util.MiscHelper; +import whocraft.tardis_refined.common.util.TardisHelper; import whocraft.tardis_refined.compat.ModCompatChecker; import whocraft.tardis_refined.compat.portals.ImmersivePortals; import whocraft.tardis_refined.registry.TRDimensionTypes; @@ -61,6 +65,23 @@ public static void addCommonEvents() { CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> TardisRefinedCommand.register(dispatcher)); + + ServerPlayConnectionEvents.JOIN.register((handler, sender, server) -> { + ServerPlayer serverPlayer = handler.getPlayer(); + TardisHelper.handlePlayerJoinWorldEvents(serverPlayer); + }); + + ServerPlayerEvents.AFTER_RESPAWN.register((oldPlayer, newPlayer, alive) -> { + if (newPlayer != null){ + TardisHelper.handlePlayerJoinWorldEvents(newPlayer); + } + }); + + ServerEntityWorldChangeEvents.AFTER_PLAYER_CHANGE_WORLD.register((player, origin, destination) -> { + if (player != null){ + TardisHelper.handlePlayerJoinWorldEvents(player); + } + }); } public static void addClientEvents() { diff --git a/forge/src/main/java/whocraft/tardis_refined/common/data/ConsolePatternProvider.java b/forge/src/main/java/whocraft/tardis_refined/common/data/ConsolePatternProvider.java index 223c73002..475883a8b 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/data/ConsolePatternProvider.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/data/ConsolePatternProvider.java @@ -64,9 +64,8 @@ public CompletableFuture run(CachedOutput arg) { }).orThrow().getAsJsonObject(); Path output = getPath(patternCollection.themeId()); futures.add(DataProvider.saveStable(arg, currentPatternCollection, output)); - ; } catch (Exception exception) { - TardisRefined.LOGGER.debug("Issue writing ConsolePatternCollection {}! Error: {}", entry.getValue().themeId(), exception.getMessage()); + TardisRefined.LOGGER.error("Issue writing ConsolePatternCollection {}! Error: {}", entry.getValue().themeId(), exception.getMessage()); } }); } diff --git a/forge/src/main/java/whocraft/tardis_refined/common/data/DesktopProvider.java b/forge/src/main/java/whocraft/tardis_refined/common/data/DesktopProvider.java index f656f75dd..de6b8a781 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/data/DesktopProvider.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/data/DesktopProvider.java @@ -60,7 +60,7 @@ public CompletableFuture run(CachedOutput arg) { String outputPath = "data/" + desktop.getIdentifier().getNamespace() + "/" + TardisDesktops.getReloadListener().getFolderName() + "/" + desktop.getIdentifier().getPath().replace("/", "_") + ".json"; futures.add(DataProvider.saveStable(arg, currentDesktop, generator.getPackOutput().getOutputFolder().resolve(outputPath))); } catch (Exception exception) { - TardisRefined.LOGGER.debug("Issue writing Desktop {}! Error: {}", entry.getValue().getIdentifier(), exception.getMessage()); + TardisRefined.LOGGER.error("Issue writing Desktop {}! Error: {}", entry.getValue().getIdentifier(), exception.getMessage()); } }); } diff --git a/forge/src/main/java/whocraft/tardis_refined/common/data/HumProvider.java b/forge/src/main/java/whocraft/tardis_refined/common/data/HumProvider.java index ec6b773ec..8bc382123 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/data/HumProvider.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/data/HumProvider.java @@ -72,7 +72,7 @@ public CompletableFuture run(CachedOutput arg) { String outputPath = "data/" + hum.getIdentifier().getNamespace() + "/" + TardisHums.getReloadListener().getFolderName() + "/" + hum.getIdentifier().getPath().replace("/", "_") + ".json"; futures.add(DataProvider.saveStable(arg, currentHum, generator.getPackOutput().getOutputFolder().resolve(outputPath))); } catch (Exception exception) { - TardisRefined.LOGGER.debug("Issue writing Hum {}! Error: {}", hum.getIdentifier(), exception.getMessage()); + TardisRefined.LOGGER.error("Issue writing Hum {}! Error: {}", hum.getIdentifier(), exception.getMessage()); } }); } diff --git a/forge/src/main/java/whocraft/tardis_refined/common/data/LangProviderEnglish.java b/forge/src/main/java/whocraft/tardis_refined/common/data/LangProviderEnglish.java index bf6c1e98b..84e392662 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/data/LangProviderEnglish.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/data/LangProviderEnglish.java @@ -43,7 +43,7 @@ protected void addTranslations() { addSound(TRSoundRegistry.FLIGHT_FAIL_START.get(), "Failing TARDIS groans"); addSound(TRSoundRegistry.CONSOLE_POWER_ON.get(), "Console power on"); addSound(TRSoundRegistry.INTERIOR_VOICE.get(), "...?"); - addSound(TRSoundRegistry.ARTRON_PILLAR.get(), "Artron pillar activated"); + addSound(TRSoundRegistry.ARTRON_PILLAR_ACTIVE.get(), "Artron pillar activated"); addSound(TRSoundRegistry.CORRIDOR_TELEPORTER.get(), "Teleporter building up"); addSound(TRSoundRegistry.CORRIDOR_TELEPORTER_SUCCESS.get(), "Teleporter used"); addSound(TRSoundRegistry.SCREWDRIVER_CONNECT.get(), "Screwdriver connected position"); diff --git a/forge/src/main/java/whocraft/tardis_refined/common/data/ManipulatorRecipeProvider.java b/forge/src/main/java/whocraft/tardis_refined/common/data/ManipulatorRecipeProvider.java index 1c1a1b0ea..833289b48 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/data/ManipulatorRecipeProvider.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/data/ManipulatorRecipeProvider.java @@ -67,7 +67,7 @@ public CompletableFuture run(CachedOutput arg) { String outputPath = "data/" + recipe.getId().getNamespace() + "/" + "recipes/astral_manipulator" + "/" + recipe.getId().getPath().replace("/", "_") + ".json"; futures.add(DataProvider.saveStable(arg, currentRecipe, generator.getPackOutput().getOutputFolder().resolve(outputPath))); } catch (Exception exception) { - TardisRefined.LOGGER.debug("Issue writing ManipulatorRecipe {}! Error: {}", entry.getValue().getId(), exception.getMessage()); + TardisRefined.LOGGER.error("Issue writing ManipulatorRecipe {}! Error: {}", entry.getValue().getId(), exception.getMessage()); } }); } diff --git a/forge/src/main/java/whocraft/tardis_refined/common/data/ShellPatternProvider.java b/forge/src/main/java/whocraft/tardis_refined/common/data/ShellPatternProvider.java index 3f3e802d9..0a63ae581 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/data/ShellPatternProvider.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/data/ShellPatternProvider.java @@ -66,7 +66,7 @@ public CompletableFuture run(CachedOutput arg) { Path output = getPath(patternCollection.themeId()); futures.add(DataProvider.saveStable(arg, currentPatternCollection, output)); } catch (Exception exception) { - TardisRefined.LOGGER.debug("Issue writing ShellPatternCollection {}! Error: {}", patternCollection.themeId(), exception.getMessage()); + TardisRefined.LOGGER.error("Issue writing ShellPatternCollection {}! Error: {}", patternCollection.themeId(), exception.getMessage()); } }); } diff --git a/forge/src/main/java/whocraft/tardis_refined/common/data/SoundProvider.java b/forge/src/main/java/whocraft/tardis_refined/common/data/SoundProvider.java index 9f79fbef7..b981d49fc 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/data/SoundProvider.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/data/SoundProvider.java @@ -46,7 +46,7 @@ public void registerSounds() { add(TRSoundRegistry.GRAVITY_TUNNEL.get(), basicSound("gravity_tunnel", new ResourceLocation(TardisRefined.MODID, "gravity_tunnel"))); add(TRSoundRegistry.INTERIOR_VOICE.get(), basicSound("interior_voice", new ResourceLocation(TardisRefined.MODID, "tardis/ambience/w1"), new ResourceLocation(TardisRefined.MODID, "tardis/ambience/w2"), new ResourceLocation(TardisRefined.MODID, "tardis/ambience/w3"), new ResourceLocation(TardisRefined.MODID, "tardis/ambience/w4"))); add(TRSoundRegistry.LOW_FUEL.get(), basicSound("low_fuel", new ResourceLocation(TardisRefined.MODID, "tardis/low_fuel"))); - add(TRSoundRegistry.ARTRON_PILLAR.get(), basicSound("artron_pillar", new ResourceLocation(TardisRefined.MODID, "blocks/artron_pillar_active"))); + add(TRSoundRegistry.ARTRON_PILLAR_ACTIVE.get(), basicSound("artron_pillar", new ResourceLocation(TardisRefined.MODID, "blocks/artron_pillar_active"))); add(TRSoundRegistry.CORRIDOR_TELEPORTER.get(), basicSound("corridor_teleporter", new ResourceLocation(TardisRefined.MODID, "blocks/corridor_teleporter"))); add(TRSoundRegistry.CORRIDOR_TELEPORTER_SUCCESS.get(), basicSound("corridor_teleporter_success", new ResourceLocation(TardisRefined.MODID, "blocks/corridor_teleporter_success"))); } diff --git a/forge/src/main/java/whocraft/tardis_refined/common/dimension/neoforge/DimensionHandlerImpl.java b/forge/src/main/java/whocraft/tardis_refined/common/dimension/neoforge/DimensionHandlerImpl.java index 49b1aaa3a..848eab152 100644 --- a/forge/src/main/java/whocraft/tardis_refined/common/dimension/neoforge/DimensionHandlerImpl.java +++ b/forge/src/main/java/whocraft/tardis_refined/common/dimension/neoforge/DimensionHandlerImpl.java @@ -3,7 +3,10 @@ import com.google.common.collect.ImmutableList; import com.google.gson.JsonObject; import com.google.gson.JsonPrimitive; +import com.mojang.serialization.Lifecycle; import net.minecraft.core.BlockPos; +import net.minecraft.core.MappedRegistry; +import net.minecraft.core.Registry; import net.minecraft.core.registries.Registries; import net.minecraft.resources.ResourceKey; import net.minecraft.server.MinecraftServer; @@ -21,6 +24,8 @@ import net.minecraft.world.level.storage.DerivedLevelData; import net.minecraft.world.level.storage.LevelStorageSource; import net.minecraft.world.level.storage.WorldData; +import net.neoforged.neoforge.common.NeoForge; +import net.neoforged.neoforge.event.level.LevelEvent; import whocraft.tardis_refined.TardisRefined; import whocraft.tardis_refined.common.dimension.DimensionHandler; import whocraft.tardis_refined.common.network.messages.sync.SyncLevelListMessage; @@ -57,6 +62,16 @@ public static ServerLevel createDimension(Level level, ResourceKey id) { WorldData serverConfig = server.getWorldData(); DerivedLevelData derivedWorldInfo = new DerivedLevelData(serverConfig, serverConfig.overworldData()); + //Actually register our dimension + Registry dimensionRegistry = server.registryAccess().registryOrThrow(Registries.LEVEL_STEM); + if (dimensionRegistry instanceof MappedRegistry writableRegistry) { + writableRegistry.unfreeze(); //Must unfreeze registry to allow our dimension to persist. This Neoforge method is deprecated so we may need to use an Accessor Mixin in the future. + writableRegistry.register(dimensionKey, dimension, Lifecycle.stable()); + } + else { + throw new IllegalStateException(String.format("Unable to register dimension %s -- dimension registry not writable", dimensionKey.location())); + } + // now we have everything we need to create the world instance ServerLevel newLevel = new ServerLevel( server, @@ -83,6 +98,8 @@ public static ServerLevel createDimension(Level level, ResourceKey id) { server.markWorldsDirty(); + NeoForge.EVENT_BUS.post(new LevelEvent.Load(newLevel)); + new SyncLevelListMessage(newLevel.dimension(), true).sendToAll(); BlockPos blockPos = new BlockPos(0, 0, 0); diff --git a/forge/src/main/java/whocraft/tardis_refined/neoforge/CommonBus.java b/forge/src/main/java/whocraft/tardis_refined/neoforge/CommonBus.java index d91b0a7db..9ad346eb5 100644 --- a/forge/src/main/java/whocraft/tardis_refined/neoforge/CommonBus.java +++ b/forge/src/main/java/whocraft/tardis_refined/neoforge/CommonBus.java @@ -1,6 +1,7 @@ package whocraft.tardis_refined.neoforge; import net.minecraft.server.level.ServerLevel; +import net.minecraft.server.level.ServerPlayer; import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.Level; import net.neoforged.bus.api.SubscribeEvent; @@ -9,17 +10,18 @@ import net.neoforged.neoforge.event.RegisterCommandsEvent; import net.neoforged.neoforge.event.TickEvent; import net.neoforged.neoforge.event.entity.living.LivingDestroyBlockEvent; +import net.neoforged.neoforge.event.entity.player.PlayerEvent; import net.neoforged.neoforge.event.level.BlockEvent; import net.neoforged.neoforge.event.server.ServerStartedEvent; import whocraft.tardis_refined.ControlGroupCheckers; import whocraft.tardis_refined.TardisRefined; import whocraft.tardis_refined.command.TardisRefinedCommand; -import whocraft.tardis_refined.common.crafting.astral_manipulator.ManipulatorRecipes; import whocraft.tardis_refined.common.dimension.DimensionHandler; import whocraft.tardis_refined.common.dimension.TardisTeleportData; import whocraft.tardis_refined.common.hum.TardisHums; import whocraft.tardis_refined.common.tardis.TardisDesktops; import whocraft.tardis_refined.common.util.MiscHelper; +import whocraft.tardis_refined.common.util.TardisHelper; import whocraft.tardis_refined.patterns.ConsolePatterns; import whocraft.tardis_refined.patterns.ShellPatterns; @@ -79,4 +81,28 @@ public static void onEntityBlockBreak(LivingDestroyBlockEvent event) { event.setCanceled(MiscHelper.shouldCancelBreaking(event.getEntity().level(), event.getEntity(), event.getPos(), event.getState())); } + @SubscribeEvent + public static void onPlayerJoin(PlayerEvent.PlayerLoggedInEvent event) { + if (event.getEntity() instanceof ServerPlayer serverPlayer) { + if (serverPlayer != null) + TardisHelper.handlePlayerJoinWorldEvents(serverPlayer); + } + } + + @SubscribeEvent + public static void onPlayerRespawn(PlayerEvent.PlayerRespawnEvent event) { + if (event.getEntity() instanceof ServerPlayer serverPlayer) { + if (serverPlayer != null) + TardisHelper.handlePlayerJoinWorldEvents(serverPlayer); + } + } + + @SubscribeEvent + public static void onPlayerChangeDimension(PlayerEvent.PlayerChangedDimensionEvent event) { + if (event.getEntity() instanceof ServerPlayer serverPlayer) { + if (serverPlayer != null) + TardisHelper.handlePlayerJoinWorldEvents(serverPlayer); + } + } + } \ No newline at end of file