diff --git a/CHANGELOG.md b/CHANGELOG.md index e69de29..4e91b19 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -0,0 +1,4 @@ +- Added some extra operator commands. +- Added a "time to full" display to the refueling state. +- Made interior lights pickblockable, keeping their order state. +- Renamed "Floppy" to "Floppy Disk". \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index eb63122..acf3f26 100644 --- a/gradle.properties +++ b/gradle.properties @@ -15,7 +15,7 @@ curseforge_id=972910 github_repo=enjarai/mini-tardis # Mod Properties -mod_version=1.0.0 +mod_version=1.0.1 maven_group=dev.enjarai archives_base_name=mini_tardis diff --git a/src/main/java/dev/enjarai/minitardis/block/InteriorDoorBlock.java b/src/main/java/dev/enjarai/minitardis/block/InteriorDoorBlock.java index 2263beb..0feefe1 100644 --- a/src/main/java/dev/enjarai/minitardis/block/InteriorDoorBlock.java +++ b/src/main/java/dev/enjarai/minitardis/block/InteriorDoorBlock.java @@ -89,7 +89,7 @@ public BlockState getStateForNeighborUpdate(BlockState state, Direction directio public ActionResult onUse(BlockState state, World world, BlockPos pos, PlayerEntity player, Hand hand, BlockHitResult hit) { // TODO uncomment when polymer fixes theā„¢ // if (hit.getSide() == state.get(FACING)) { - getTardis(world).ifPresent(tardis -> tardis.teleportEntityOut(player)); + getTardis(world).ifPresent(tardis -> tardis.teleportEntityOut(player, state.get(HALF) == DoubleBlockHalf.UPPER ? pos.down() : pos)); return ActionResult.SUCCESS; // } // return super.onUse(state, world, pos, player, hand, hit); diff --git a/src/main/java/dev/enjarai/minitardis/block/InteriorLightBlock.java b/src/main/java/dev/enjarai/minitardis/block/InteriorLightBlock.java index 7ed1565..d461f15 100644 --- a/src/main/java/dev/enjarai/minitardis/block/InteriorLightBlock.java +++ b/src/main/java/dev/enjarai/minitardis/block/InteriorLightBlock.java @@ -1,12 +1,20 @@ package dev.enjarai.minitardis.block; +import dev.enjarai.minitardis.MiniTardis; +import dev.enjarai.minitardis.util.PerhapsPolymerBlock; +import eu.pb4.polymer.blocks.api.PolymerTexturedBlock; import eu.pb4.polymer.core.api.block.PolymerBlock; +import eu.pb4.polymer.core.api.utils.PolymerClientDecoded; +import eu.pb4.polymer.core.api.utils.PolymerKeepModel; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.Blocks; import net.minecraft.block.RedstoneLampBlock; import net.minecraft.entity.player.PlayerEntity; import net.minecraft.item.ItemPlacementContext; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.server.world.ServerWorld; import net.minecraft.sound.SoundCategory; import net.minecraft.sound.SoundEvents; @@ -23,7 +31,7 @@ import org.jetbrains.annotations.Nullable; @SuppressWarnings("deprecation") -public class InteriorLightBlock extends RedstoneLampBlock implements PolymerBlock, TardisAware { +public class InteriorLightBlock extends RedstoneLampBlock implements PerhapsPolymerBlock, TardisAware { public static final IntProperty ORDER = IntProperty.of("order", 0, 12); public InteriorLightBlock(Settings settings) { @@ -37,6 +45,20 @@ public BlockState getPlacementState(ItemPlacementContext ctx) { return getDefaultState(); } + @Override + public ItemStack getPickStack(BlockView world, BlockPos pos, BlockState state) { + var stack = super.getPickStack(world, pos, state); + + var order = state.get(ORDER); + if (order != 0) { + NbtCompound nbtCompound = new NbtCompound(); + nbtCompound.putString(ORDER.getName(), String.valueOf(order)); + stack.setSubNbt("BlockStateTag", nbtCompound); + } + + return stack; + } + @Override public void neighborUpdate(BlockState state, World world, BlockPos pos, Block sourceBlock, BlockPos sourcePos, boolean notify) { } @@ -92,12 +114,12 @@ public boolean emitsRedstonePower(BlockState state) { } @Override - public Block getPolymerBlock(BlockState state) { + public Block getPerhapsPolymerBlock(BlockState state) { return Blocks.REDSTONE_LAMP; } @Override - public BlockState getPolymerBlockState(BlockState state) { + public BlockState getPerhapsPolymerBlockState(BlockState state) { return getPolymerBlock(state).getStateWithProperties(state); } } diff --git a/src/main/java/dev/enjarai/minitardis/command/TardisCommand.java b/src/main/java/dev/enjarai/minitardis/command/TardisCommand.java index 4b741e4..e8096b7 100644 --- a/src/main/java/dev/enjarai/minitardis/command/TardisCommand.java +++ b/src/main/java/dev/enjarai/minitardis/command/TardisCommand.java @@ -4,10 +4,12 @@ import com.mojang.brigadier.context.CommandContext; import com.mojang.brigadier.suggestion.Suggestions; import com.mojang.brigadier.suggestion.SuggestionsBuilder; +import dev.enjarai.minitardis.block.TardisAware; import dev.enjarai.minitardis.component.TardisLocation; import dev.enjarai.minitardis.component.ModComponents; import dev.enjarai.minitardis.component.Tardis; import dev.enjarai.minitardis.component.TardisHolder; +import dev.enjarai.minitardis.component.flight.FlightState; import dev.enjarai.minitardis.component.screen.app.ScreenApp; import dev.enjarai.minitardis.component.screen.app.ScreenAppType; import dev.enjarai.minitardis.item.FloppyItem; @@ -19,11 +21,15 @@ import net.minecraft.server.command.CommandManager; import net.minecraft.server.command.ServerCommandSource; import net.minecraft.text.Text; +import net.minecraft.util.Identifier; import net.minecraft.util.math.BlockPos; import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Objects; +import java.util.Optional; import java.util.UUID; import java.util.concurrent.CompletableFuture; import java.util.function.Supplier; @@ -63,6 +69,25 @@ public static void register(CommandDispatcher dispatcher) { ) ) ) + .then(CommandManager.literal("refuel") + .executes(context -> refuel(context, null)) + .then(CommandManager.argument("tardis", UuidArgumentType.uuid()) + .suggests(TardisCommand::suggestTardii) + .executes(context -> refuel(context, UuidArgumentType.getUuid(context, "tardis"))) + ) + ) + .then(CommandManager.literal("state") + .then(CommandManager.literal("set") + .then(CommandManager.argument("state", IdentifierArgumentType.identifier()) + .suggests(TardisCommand::suggestStates) + .executes(context -> setState(context, IdentifierArgumentType.getIdentifier(context, "state"), null)) + .then(CommandManager.argument("tardis", UuidArgumentType.uuid()) + .suggests(TardisCommand::suggestTardii) + .executes(context -> setState(context, IdentifierArgumentType.getIdentifier(context, "state"), UuidArgumentType.getUuid(context, "tardis"))) + ) + ) + ) + ) ); } @@ -88,6 +113,21 @@ private static int toggleDoor(CommandContext context, UUID return 1; } + private static int refuel(CommandContext context, @Nullable UUID uuid) { + var tardis = uuid == null ? getTardis(context.getSource().getWorld()) : getHolder(context).getTardis(uuid); + tardis.ifPresent(t -> t.addOrDrainFuel(1000)); + return 1; + } + + private static int setState(CommandContext context, Identifier stateId, @Nullable UUID uuid) { + if (FlightState.CONSTRUCTORS.containsKey(stateId)) { + var state = FlightState.CONSTRUCTORS.get(stateId); + var tardis = uuid == null ? getTardis(context.getSource().getWorld()) : getHolder(context).getTardis(uuid); + tardis.ifPresent(t -> t.forceSetState(state.get())); + } + return 1; + } + private static CompletableFuture suggestTardii(CommandContext context, SuggestionsBuilder builder) { return CommandSource.suggestMatching( ModComponents.TARDIS_HOLDER.get(context.getSource().getServer().getSaveProperties()) @@ -98,6 +138,14 @@ private static CompletableFuture suggestTardii(CommandContext suggestStates(CommandContext context, SuggestionsBuilder builder) { + return CommandSource.suggestMatching( + FlightState.CONSTRUCTORS.keySet().stream() + .map(Identifier::toString), + builder + ); + } + private static int installApps(CommandContext context, List apps) { var player = context.getSource().getPlayer(); if (player == null) return 0; @@ -117,4 +165,8 @@ private static int installApps(CommandContext context, List private static TardisHolder getHolder(CommandContext context) { return ModComponents.TARDIS_HOLDER.get(context.getSource().getServer().getSaveProperties()); } + + private static Optional getTardis(World world) { + return world.getComponent(ModComponents.TARDIS_REFERENCE).getTardis(); + } } diff --git a/src/main/java/dev/enjarai/minitardis/component/Tardis.java b/src/main/java/dev/enjarai/minitardis/component/Tardis.java index d55da97..b8d972b 100644 --- a/src/main/java/dev/enjarai/minitardis/component/Tardis.java +++ b/src/main/java/dev/enjarai/minitardis/component/Tardis.java @@ -266,9 +266,9 @@ public void teleportEntityIn(Entity entity) { break; } else { targetPos = world.getPointOfInterestStorage().getInSquare( - poi -> poi.value().equals(ModBlocks.INTERIOR_DOOR_POI), INTERIOR_CENTER, + poi -> poi.value().equals(ModBlocks.INTERIOR_DOOR_POI), interiorDoorPosition, 64, PointOfInterestStorage.OccupationStatus.ANY - ).findAny().map(PointOfInterest::getPos).orElse(INTERIOR_CENTER); + ).findAny().map(PointOfInterest::getPos).orElse(interiorDoorPosition); interiorDoorState = world.getBlockState(targetPos); } } while (interiorDoorState.isOf(ModBlocks.INTERIOR_DOOR)); @@ -283,7 +283,7 @@ public void teleportEntityIn(Entity entity) { } } - public void teleportEntityOut(Entity entity) { + public void teleportEntityOut(Entity entity, BlockPos doorPos) { if (state.isSolid(this)) { currentLocation.ifLeft(location -> { var world = location.getWorld(holder.getServer()); @@ -296,6 +296,8 @@ public void teleportEntityOut(Entity entity) { blockEntity = world.getBlockEntity(pos); } + interiorDoorPosition = doorPos; + if (blockEntity instanceof TardisExteriorBlockEntity exteriorEntity && this.equals(exteriorEntity.getLinkedTardis())) { var facing = exteriorEntity.getCachedState().get(TardisExteriorBlock.FACING); var exitPos = pos.add(facing.getVector()); @@ -404,6 +406,12 @@ public boolean suggestStateTransition(FlightState newState) { return accepted; } + public void forceSetState(FlightState newState) { + state.complete(this); + state = newState; + newState.init(this); + } + public FlightState getState() { return state; } diff --git a/src/main/java/dev/enjarai/minitardis/component/flight/FlightState.java b/src/main/java/dev/enjarai/minitardis/component/flight/FlightState.java index 572045a..1fb89f4 100644 --- a/src/main/java/dev/enjarai/minitardis/component/flight/FlightState.java +++ b/src/main/java/dev/enjarai/minitardis/component/flight/FlightState.java @@ -13,6 +13,7 @@ import net.minecraft.util.Identifier; import java.util.Map; +import java.util.function.Supplier; public interface FlightState { Map> ALL = Map.ofEntries( @@ -29,6 +30,15 @@ public interface FlightState { Map.entry(CrashedState.ID, CrashedState.CODEC), Map.entry(SuspendedFlightState.ID, SuspendedFlightState.CODEC) ); + Map> CONSTRUCTORS = Map.of( + LandedState.ID, LandedState::new, + RefuelingState.ID, RefuelingState::new, + DriftingState.ID, DriftingState::new, + DisabledState.ID, DisabledState::new, + BootingUpState.ID, BootingUpState::new, + CrashedState.ID, CrashedState::new, + SuspendedFlightState.ID, SuspendedFlightState::new + ); Codec CODEC = Identifier.CODEC.dispatch(FlightState::id, ALL::get); /** diff --git a/src/main/java/dev/enjarai/minitardis/component/screen/app/StatusApp.java b/src/main/java/dev/enjarai/minitardis/component/screen/app/StatusApp.java index 343d16a..279cedb 100644 --- a/src/main/java/dev/enjarai/minitardis/component/screen/app/StatusApp.java +++ b/src/main/java/dev/enjarai/minitardis/component/screen/app/StatusApp.java @@ -15,12 +15,16 @@ import net.minecraft.server.network.ServerPlayerEntity; import net.minecraft.sound.SoundEvents; import net.minecraft.util.ClickType; +import net.minecraft.util.math.random.LocalRandom; +import net.minecraft.util.math.random.Random; import java.util.Arrays; public class StatusApp implements ScreenApp { public static final Codec CODEC = Codec.unit(StatusApp::new); + private Random etaRandom = new LocalRandom(0); + @Override public AppView getView(TardisControl controls) { return new AppView() { @@ -69,6 +73,17 @@ public void draw(ScreenBlockEntity blockEntity, DrawableCanvas canvas) { DefaultFonts.VANILLA.drawText(canvas, "ER: " + state.getDistance(), 8, 41, 8, CanvasColor.WHITE_HIGH); }); + tardis.getState(RefuelingState.class).ifPresent(state -> { + etaRandom.setSeed(tardis.getInteriorWorld().getTime() / 40); + + var seconds = 1000 - tardis.getFuel() * etaRandom.nextBetween(95, 105) / 100; + var minutes = seconds / 60; + seconds %= 60; + + DefaultFonts.VANILLA.drawText(canvas, "Time to full:", 8, 24, 8, CanvasColor.LIGHT_GRAY_HIGH); + DefaultFonts.VANILLA.drawText(canvas, "%d:%02d".formatted(minutes, seconds), 8, 35, 8, CanvasColor.WHITE_HIGH); + }); + var random = blockEntity.drawRandom; var state = tardis.getState(); var isSolid = state.isSolid(tardis); diff --git a/src/main/java/dev/enjarai/minitardis/item/InteriorLightItem.java b/src/main/java/dev/enjarai/minitardis/item/InteriorLightItem.java new file mode 100644 index 0000000..c9d1d6e --- /dev/null +++ b/src/main/java/dev/enjarai/minitardis/item/InteriorLightItem.java @@ -0,0 +1,34 @@ +package dev.enjarai.minitardis.item; + +import net.minecraft.block.Block; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtElement; +import net.minecraft.text.Style; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import net.minecraft.world.World; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +import static dev.enjarai.minitardis.block.InteriorLightBlock.ORDER; + +public class InteriorLightItem extends TooltipPolymerBlockItem { + public InteriorLightItem(Block block, Settings settings, Item virtualItem) { + super(block, settings, virtualItem); + } + + @Override + public void appendTooltip(ItemStack stack, @Nullable World world, List tooltip, TooltipContext context) { + var stateNbt = stack.getSubNbt("BlockStateTag"); + if (stateNbt != null && stateNbt.contains(ORDER.getName(), NbtElement.STRING_TYPE)) { + var order = stateNbt.getString(ORDER.getName()); + tooltip.add(Text.translatable("block.mini_tardis.interior_light.tooltip.order", order).fillStyle(Style.EMPTY.withColor(Formatting.GRAY))); + tooltip.add(Text.empty()); + } + + super.appendTooltip(stack, world, tooltip, context); + } +} diff --git a/src/main/java/dev/enjarai/minitardis/item/ModItems.java b/src/main/java/dev/enjarai/minitardis/item/ModItems.java index b12a490..59564d5 100644 --- a/src/main/java/dev/enjarai/minitardis/item/ModItems.java +++ b/src/main/java/dev/enjarai/minitardis/item/ModItems.java @@ -14,6 +14,7 @@ import net.minecraft.item.Item; import net.minecraft.item.ItemGroup; import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; import net.minecraft.registry.Registries; import net.minecraft.registry.Registry; import net.minecraft.registry.RegistryKey; @@ -30,20 +31,24 @@ public class ModItems { new FabricItemSettings().maxCount(1).equipmentSlot((stack) -> EquipmentSlot.HEAD))); public static final FloppyItem FLOPPY = register("floppy", new FloppyItem(new FabricItemSettings().maxCount(1))); public static final TardisPlatingItem TARDIS_PLATING = register("tardis_plating", new TardisPlatingItem(new FabricItemSettings())); + public static final InteriorLightItem INTERIOR_LIGHT = register("interior_light", + new InteriorLightItem(ModBlocks.INTERIOR_LIGHT, new FabricItemSettings(), Items.REDSTONE_LAMP)); public static void load() { ModBlocks.ITEM_BLOCKS.forEach((block, modelData) -> { var id = Registries.BLOCK.getId(block); - if (modelData.isPresent()) { - Registry.register(Registries.ITEM, id, new TooltipPolymerBlockItem(block, new FabricItemSettings(), modelData.get().item()) { - @Override - public int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player) { - return modelData.get().value(); - } - }); - } else if (block instanceof PolymerBlock polymerBlock) { - var polymerItem = polymerBlock.getPolymerBlock(block.getDefaultState()).asItem(); - Registry.register(Registries.ITEM, id, new TooltipPolymerBlockItem(block, new FabricItemSettings(), polymerItem)); + if (!Registries.ITEM.containsId(id)) { + if (modelData.isPresent()) { + Registry.register(Registries.ITEM, id, new TooltipPolymerBlockItem(block, new FabricItemSettings(), modelData.get().item()) { + @Override + public int getPolymerCustomModelData(ItemStack itemStack, @Nullable ServerPlayerEntity player) { + return modelData.get().value(); + } + }); + } else if (block instanceof PolymerBlock polymerBlock) { + var polymerItem = polymerBlock.getPolymerBlock(block.getDefaultState()).asItem(); + Registry.register(Registries.ITEM, id, new TooltipPolymerBlockItem(block, new FabricItemSettings(), polymerItem)); + } } }); diff --git a/src/main/resources/assets/mini_tardis/blockstates/interior_light.json b/src/main/resources/assets/mini_tardis/blockstates/interior_light.json new file mode 100644 index 0000000..bbd9d93 --- /dev/null +++ b/src/main/resources/assets/mini_tardis/blockstates/interior_light.json @@ -0,0 +1,10 @@ +{ + "variants": { + "lit=false": { + "model": "minecraft:block/redstone_lamp" + }, + "lit=true": { + "model": "minecraft:block/redstone_lamp_on" + } + } +} \ No newline at end of file diff --git a/src/main/resources/assets/mini_tardis/lang/en_us.json b/src/main/resources/assets/mini_tardis/lang/en_us.json index 52a4795..36831f2 100644 --- a/src/main/resources/assets/mini_tardis/lang/en_us.json +++ b/src/main/resources/assets/mini_tardis/lang/en_us.json @@ -41,13 +41,14 @@ "block.mini_tardis.refuel_toggle.tooltip": "Toggles refueling mode.", "block.mini_tardis.interior_light": "Interior Light", "block.mini_tardis.interior_light.tooltip": "Turns on and emits a redstone signal based on your Tardis' state.", + "block.mini_tardis.interior_light.tooltip.order": "Order: %s", "block.mini_tardis.power_coupling": "Power Coupling", "block.mini_tardis.power_coupling.tooltip": "Can be used to completely turn off your Tardis.", "block.mini_tardis.makeshift_engine": "Makeshift Tardis Engine", "block.mini_tardis.makeshift_engine.tooltip": "Can be used to build a makeshift Tardis, letting you temporarily enter the time vortex.", "item.mini_tardis.fez": "Fez", - "item.mini_tardis.floppy": "Floppy", + "item.mini_tardis.floppy": "Floppy Disk", "mini_tardis.item_group": "Mini Tardis" } \ No newline at end of file diff --git a/src/main/resources/data/mini_tardis/lang/en_us.json b/src/main/resources/data/mini_tardis/lang/en_us.json index 690eb67..0991fec 100644 --- a/src/main/resources/data/mini_tardis/lang/en_us.json +++ b/src/main/resources/data/mini_tardis/lang/en_us.json @@ -31,13 +31,14 @@ "block.mini_tardis.refuel_toggle.tooltip": "Toggles refueling mode.", "block.mini_tardis.interior_light": "Interior Light", "block.mini_tardis.interior_light.tooltip": "Turns on and emits a redstone signal based on your Tardis' state.", + "block.mini_tardis.interior_light.tooltip.order": "Order: %s", "block.mini_tardis.power_coupling": "Power Coupling", "block.mini_tardis.power_coupling.tooltip": "Can be used to completely turn off your Tardis.", "block.mini_tardis.makeshift_engine": "Makeshift Tardis Engine", "block.mini_tardis.makeshift_engine.tooltip": "Can be used to build a makeshift Tardis, letting you temporarily enter the time vortex.", "item.mini_tardis.fez": "Fez", - "item.mini_tardis.floppy": "Floppy", + "item.mini_tardis.floppy": "Floppy Disk", "mini_tardis.item_group": "Mini Tardis",