diff --git a/common/src/main/java/juuxel/adorn/AdornCommon.java b/common/src/main/java/juuxel/adorn/AdornCommon.java new file mode 100644 index 000000000..1263f6a87 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/AdornCommon.java @@ -0,0 +1,11 @@ +package juuxel.adorn; + +import net.minecraft.util.Identifier; + +public final class AdornCommon { + public static final String NAMESPACE = "adorn"; + + public static Identifier id(String path) { + return new Identifier(NAMESPACE, path); + } +} diff --git a/common/src/main/java/juuxel/adorn/block/AdornBlocks.java b/common/src/main/java/juuxel/adorn/block/AdornBlocks.java index 216d434e6..ff35fd5a7 100644 --- a/common/src/main/java/juuxel/adorn/block/AdornBlocks.java +++ b/common/src/main/java/juuxel/adorn/block/AdornBlocks.java @@ -8,7 +8,7 @@ import juuxel.adorn.lib.registry.RegistrarFactory; import juuxel.adorn.lib.registry.RegistryHelper; import juuxel.adorn.platform.PlatformBridges; -import juuxel.adorn.util.ExtensionsKt; +import juuxel.adorn.util.AdornUtil; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.Blocks; @@ -29,7 +29,7 @@ public final class AdornBlocks { public static final Registrar ITEMS = RegistrarFactory.get().create(RegistryKeys.ITEM); private static final RegistryHelper HELPER = new RegistryHelper(BLOCKS, ITEMS); - public static final Registered> SOFAS = ExtensionsKt.associateLazily( + public static final Registered> SOFAS = AdornUtil.associateLazily( DyeColor.values(), color -> HELPER.registerBlock( color.asString() + "_sofa", @@ -54,7 +54,7 @@ public final class AdornBlocks { public static final Registered SOULFUL_PRISMARINE_CHIMNEY = HELPER.registerBlock("soulful_prismarine_chimney", () -> new PrismarineChimneyBlock.WithColumn(false, AbstractChimneyBlock.createBlockSettings(MapColor.CYAN, 1.5f))); - public static final Registered> TABLE_LAMPS = ExtensionsKt.associateLazily( + public static final Registered> TABLE_LAMPS = AdornUtil.associateLazily( DyeColor.values(), color -> HELPER.registerBlock(color.asString() + "_table_lamp", () -> new TableLampBlock(TableLampBlock.createBlockSettings(color))) ); @@ -80,7 +80,7 @@ public final class AdornBlocks { )); public static final Registered CRATE = HELPER.registerBlock("crate", - () -> new Block(ExtensionsKt.copySettingsSafely(Blocks.OAK_PLANKS))); + () -> new Block(AdornUtil.copySettingsSafely(Blocks.OAK_PLANKS))); public static final Registered APPLE_CRATE = registerCrate("apple_crate"); public static final Registered WHEAT_CRATE = registerCrate("wheat_crate"); public static final Registered CARROT_CRATE = registerCrate("carrot_crate"); @@ -119,7 +119,7 @@ public final class AdornBlocks { public static final Registered CANDLELIT_LANTERN = HELPER.registerBlock("candlelit_lantern", () -> new CandlelitLanternBlock(CandlelitLanternBlock.createBlockSettings())); - public static final Registered> DYED_CANDLELIT_LANTERNS = ExtensionsKt.associateLazily( + public static final Registered> DYED_CANDLELIT_LANTERNS = AdornUtil.associateLazily( DyeColor.values(), color -> HELPER.registerBlock( color.asString() + "_candlelit_lantern", @@ -176,6 +176,6 @@ public static void init() { } private static Registered registerCrate(String name) { - return HELPER.registerBlock(name, () -> new Item.Settings().recipeRemainder(CRATE.get().asItem()), () -> new Block(ExtensionsKt.copySettingsSafely(CRATE.get()))); + return HELPER.registerBlock(name, () -> new Item.Settings().recipeRemainder(CRATE.get().asItem()), () -> new Block(AdornUtil.copySettingsSafely(CRATE.get()))); } } diff --git a/common/src/main/java/juuxel/adorn/block/BenchBlock.java b/common/src/main/java/juuxel/adorn/block/BenchBlock.java index 7eea1d324..0e241919b 100644 --- a/common/src/main/java/juuxel/adorn/block/BenchBlock.java +++ b/common/src/main/java/juuxel/adorn/block/BenchBlock.java @@ -4,7 +4,7 @@ import it.unimi.dsi.fastutil.bytes.Byte2ObjectMap; import juuxel.adorn.block.variant.BlockVariant; import juuxel.adorn.lib.AdornStats; -import juuxel.adorn.util.ExtensionsKt; +import juuxel.adorn.util.AdornUtil; import juuxel.adorn.util.Shapes; import net.minecraft.block.Block; import net.minecraft.block.BlockState; @@ -46,8 +46,8 @@ public final class BenchBlock extends SeatBlock implements Waterloggable, BlockW for (var axis : new Direction.Axis[] { Direction.Axis.X, Direction.Axis.Z }) { var topShape = axis == Direction.Axis.X ? X_TOP_SHAPE : Z_TOP_SHAPE; - var negativeLeg = legShapes.get(ExtensionsKt.getDirection(axis, Direction.AxisDirection.NEGATIVE)); - var positiveLeg = legShapes.get(ExtensionsKt.getDirection(axis, Direction.AxisDirection.POSITIVE)); + var negativeLeg = legShapes.get(Direction.from(axis, Direction.AxisDirection.NEGATIVE)); + var positiveLeg = legShapes.get(Direction.from(axis, Direction.AxisDirection.POSITIVE)); for (var connectedN : booleans) { for (var connectedP : booleans) { @@ -80,7 +80,7 @@ public BenchBlock(BlockVariant variant) { @Override public BlockState getPlacementState(ItemPlacementContext ctx) { var state = getDefaultState() - .with(AXIS, ExtensionsKt.turnHorizontally(ctx.getHorizontalPlayerFacing().getAxis())) + .with(AXIS, AdornUtil.turnHorizontally(ctx.getHorizontalPlayerFacing().getAxis())) .with(WATERLOGGED, ctx.getWorld().getFluidState(ctx.getBlockPos()).getFluid() == Fluids.WATER); return updateConnections(ctx.getWorld(), ctx.getBlockPos(), state); } @@ -125,7 +125,7 @@ public BlockState rotate(BlockState state, BlockRotation rotation) { return switch (rotation) { case COUNTERCLOCKWISE_90: case CLOCKWISE_90: - yield state.with(AXIS, ExtensionsKt.turnHorizontally(state.get(AXIS))); + yield state.with(AXIS, AdornUtil.turnHorizontally(state.get(AXIS))); default: yield state; }; diff --git a/common/src/main/java/juuxel/adorn/block/TradingStationBlock.java b/common/src/main/java/juuxel/adorn/block/TradingStationBlock.java index 2b6ecaa55..16b3162ea 100644 --- a/common/src/main/java/juuxel/adorn/block/TradingStationBlock.java +++ b/common/src/main/java/juuxel/adorn/block/TradingStationBlock.java @@ -5,7 +5,7 @@ import juuxel.adorn.criterion.AdornCriteria; import juuxel.adorn.lib.AdornGameRules; import juuxel.adorn.lib.AdornStats; -import juuxel.adorn.util.NbtExtensionsKt; +import juuxel.adorn.util.NbtUtil; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.BlockWithEntity; @@ -161,7 +161,7 @@ public void appendTooltip(ItemStack stack, @Nullable BlockView world, List var nbt = stack.getSubNbt(BlockItem.BLOCK_ENTITY_TAG_KEY); if (nbt != null && nbt.contains(TradingStationBlockEntity.NBT_TRADING_OWNER)) { - var owner = NbtExtensionsKt.getText(nbt, TradingStationBlockEntity.NBT_TRADING_OWNER_NAME); + var owner = NbtUtil.getText(nbt, TradingStationBlockEntity.NBT_TRADING_OWNER_NAME); if (owner == null) owner = TradingStationBlockEntity.UNKNOWN_OWNER; tooltip.add(Text.translatable(OWNER_DESCRIPTION, owner.copy().formatted(Formatting.WHITE)).formatted(Formatting.GREEN)); } diff --git a/common/src/main/java/juuxel/adorn/block/entity/DrawerBlockEntity.java b/common/src/main/java/juuxel/adorn/block/entity/DrawerBlockEntity.java index 14e0af814..5a2ac5b0d 100644 --- a/common/src/main/java/juuxel/adorn/block/entity/DrawerBlockEntity.java +++ b/common/src/main/java/juuxel/adorn/block/entity/DrawerBlockEntity.java @@ -2,7 +2,7 @@ import juuxel.adorn.block.AdornBlockEntities; import juuxel.adorn.menu.DrawerMenu; -import juuxel.adorn.util.ExtensionsKt; +import juuxel.adorn.util.AdornUtil; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.menu.Menu; @@ -15,6 +15,6 @@ public DrawerBlockEntity(BlockPos pos, BlockState state) { @Override protected Menu createMenu(int syncId, PlayerInventory inv) { - return new DrawerMenu(syncId, inv, this, ExtensionsKt.menuContextOf(this)); + return new DrawerMenu(syncId, inv, this, AdornUtil.menuContextOf(this)); } } diff --git a/common/src/main/java/juuxel/adorn/block/entity/KitchenCupboardBlockEntity.java b/common/src/main/java/juuxel/adorn/block/entity/KitchenCupboardBlockEntity.java index ca5de153b..bf4a074a4 100644 --- a/common/src/main/java/juuxel/adorn/block/entity/KitchenCupboardBlockEntity.java +++ b/common/src/main/java/juuxel/adorn/block/entity/KitchenCupboardBlockEntity.java @@ -2,7 +2,7 @@ import juuxel.adorn.block.AdornBlockEntities; import juuxel.adorn.menu.KitchenCupboardMenu; -import juuxel.adorn.util.ExtensionsKt; +import juuxel.adorn.util.AdornUtil; import net.minecraft.block.BlockState; import net.minecraft.entity.player.PlayerInventory; import net.minecraft.menu.Menu; @@ -15,6 +15,6 @@ public KitchenCupboardBlockEntity(BlockPos pos, BlockState state) { @Override protected Menu createMenu(int syncId, PlayerInventory inv) { - return new KitchenCupboardMenu(syncId, inv, this, ExtensionsKt.menuContextOf(this)); + return new KitchenCupboardMenu(syncId, inv, this, AdornUtil.menuContextOf(this)); } } diff --git a/common/src/main/java/juuxel/adorn/block/entity/TradingStationBlockEntity.java b/common/src/main/java/juuxel/adorn/block/entity/TradingStationBlockEntity.java index d6782c23b..6fcf55462 100644 --- a/common/src/main/java/juuxel/adorn/block/entity/TradingStationBlockEntity.java +++ b/common/src/main/java/juuxel/adorn/block/entity/TradingStationBlockEntity.java @@ -3,9 +3,9 @@ import juuxel.adorn.block.AdornBlockEntities; import juuxel.adorn.menu.TradingStationMenu; import juuxel.adorn.trading.Trade; -import juuxel.adorn.util.ExtensionsKt; +import juuxel.adorn.util.AdornUtil; import juuxel.adorn.util.InventoryComponent; -import juuxel.adorn.util.NbtExtensionsKt; +import juuxel.adorn.util.NbtUtil; import net.minecraft.block.BlockState; import net.minecraft.block.entity.BlockEntity; import net.minecraft.entity.player.PlayerEntity; @@ -67,7 +67,7 @@ public boolean isOwner(PlayerEntity player) { @Override public Menu createMenu(int syncId, PlayerInventory playerInventory, PlayerEntity player) { - return new TradingStationMenu(syncId, playerInventory, ExtensionsKt.menuContextOf(this)); + return new TradingStationMenu(syncId, playerInventory, AdornUtil.menuContextOf(this)); } @Override @@ -102,11 +102,9 @@ public void readNbt(NbtCompound nbt) { if (nbt.containsUuid(NBT_TRADING_OWNER)) { owner = nbt.getUuid(NBT_TRADING_OWNER); - } else if (NbtExtensionsKt.containsOldUuid(nbt, NBT_TRADING_OWNER)) { - owner = NbtExtensionsKt.getOldUuid(nbt, NBT_TRADING_OWNER); } - ownerName = Objects.requireNonNullElse(NbtExtensionsKt.getText(nbt, NBT_TRADING_OWNER_NAME), UNKNOWN_OWNER); + ownerName = Objects.requireNonNullElse(NbtUtil.getText(nbt, NBT_TRADING_OWNER_NAME), UNKNOWN_OWNER); trade.readNbt(nbt.getCompound(NBT_TRADE)); storage.readNbt(nbt.getCompound(NBT_STORAGE)); } @@ -119,7 +117,7 @@ protected void writeNbt(NbtCompound nbt) { nbt.putUuid(NBT_TRADING_OWNER, owner); } - NbtExtensionsKt.putText(nbt, NBT_TRADING_OWNER_NAME, ownerName); + NbtUtil.putText(nbt, NBT_TRADING_OWNER_NAME, ownerName); nbt.put(NBT_TRADE, trade.writeNbt(new NbtCompound())); nbt.put(NBT_STORAGE, storage.writeNbt(new NbtCompound())); diff --git a/common/src/main/java/juuxel/adorn/block/variant/BlockVariant.java b/common/src/main/java/juuxel/adorn/block/variant/BlockVariant.java index f76475791..66358dc02 100644 --- a/common/src/main/java/juuxel/adorn/block/variant/BlockVariant.java +++ b/common/src/main/java/juuxel/adorn/block/variant/BlockVariant.java @@ -1,6 +1,6 @@ package juuxel.adorn.block.variant; -import juuxel.adorn.util.ExtensionsKt; +import juuxel.adorn.util.AdornUtil; import net.minecraft.block.AbstractBlock; import net.minecraft.block.Block; import net.minecraft.block.Blocks; @@ -102,7 +102,7 @@ public String name() { @Override public AbstractBlock.Settings createSettings() { - return ExtensionsKt.copySettingsSafely(base); + return AdornUtil.copySettingsSafely(base); } }; } @@ -114,14 +114,14 @@ static BlockVariant wool(DyeColor color) { record Wood(String name) implements BlockVariant { @Override public AbstractBlock.Settings createSettings() { - return ExtensionsKt.copySettingsSafely(Blocks.OAK_PLANKS); + return AdornUtil.copySettingsSafely(Blocks.OAK_PLANKS); } } record Stone(String name) implements BlockVariant { @Override public AbstractBlock.Settings createSettings() { - return ExtensionsKt.copySettingsSafely(Blocks.COBBLESTONE); + return AdornUtil.copySettingsSafely(Blocks.COBBLESTONE); } } } diff --git a/common/src/main/java/juuxel/adorn/client/gui/screen/BrewerScreen.java b/common/src/main/java/juuxel/adorn/client/gui/screen/BrewerScreen.java index aff2eb221..0fdd625e2 100644 --- a/common/src/main/java/juuxel/adorn/client/gui/screen/BrewerScreen.java +++ b/common/src/main/java/juuxel/adorn/client/gui/screen/BrewerScreen.java @@ -7,7 +7,7 @@ import juuxel.adorn.fluid.FluidReference; import juuxel.adorn.fluid.FluidVolume; import juuxel.adorn.menu.BrewerMenu; -import juuxel.adorn.util.ColorsKt; +import juuxel.adorn.util.Colors; import juuxel.adorn.util.Logging; import net.minecraft.client.MinecraftClient; import net.minecraft.client.gui.DrawContext; @@ -107,7 +107,7 @@ public static void drawFluid(DrawContext context, int x, int y, FluidReference f return; } - var color = ColorsKt.color(bridge.getColor(fluid)); + var color = Colors.color(bridge.getColor(fluid)); var height = FLUID_AREA_HEIGHT * (float) (fluid.getAmount() / (BrewerBlockEntity.FLUID_CAPACITY_IN_BUCKETS * fluid.getUnit().getBucketVolume())); var fluidY = 0; diff --git a/common/src/main/java/juuxel/adorn/client/gui/screen/GuideBookScreen.java b/common/src/main/java/juuxel/adorn/client/gui/screen/GuideBookScreen.java index 85140ccc5..97a10eb75 100644 --- a/common/src/main/java/juuxel/adorn/client/gui/screen/GuideBookScreen.java +++ b/common/src/main/java/juuxel/adorn/client/gui/screen/GuideBookScreen.java @@ -12,7 +12,7 @@ import juuxel.adorn.client.gui.widget.ScrollEnvelope; import juuxel.adorn.client.gui.widget.SizedElement; import juuxel.adorn.client.gui.widget.TickingElement; -import juuxel.adorn.util.CollectionsKt; +import juuxel.adorn.util.CollectionUtil; import juuxel.adorn.util.Colors; import juuxel.adorn.util.animation.AnimationEngine; import net.minecraft.client.gui.DrawContext; @@ -207,7 +207,7 @@ private BookPageTitle(int x, int y, Page page) { this.x = x; this.y = y; this.wrappedTitleLines = textRenderer.wrapLines(page.title().copy().styled(style -> style.withBold(true)), PAGE_TITLE_WIDTH); - this.icons = CollectionsKt.interleave(page.icons().stream().map(Page.Icon::createStacks).toList()); + this.icons = CollectionUtil.interleave(page.icons().stream().map(Page.Icon::createStacks).toList()); } @Override diff --git a/common/src/main/java/juuxel/adorn/client/gui/widget/ScrollEnvelope.java b/common/src/main/java/juuxel/adorn/client/gui/widget/ScrollEnvelope.java index 43e677310..a489bf24c 100644 --- a/common/src/main/java/juuxel/adorn/client/gui/widget/ScrollEnvelope.java +++ b/common/src/main/java/juuxel/adorn/client/gui/widget/ScrollEnvelope.java @@ -1,7 +1,6 @@ package juuxel.adorn.client.gui.widget; import juuxel.adorn.util.Colors; -import juuxel.adorn.util.ColorsKt; import juuxel.adorn.util.animation.AnimatedProperty; import juuxel.adorn.util.animation.AnimatedPropertyWrapper; import juuxel.adorn.util.animation.AnimationEngine; @@ -15,11 +14,11 @@ public final class ScrollEnvelope extends ScissorEnvelope { private static final double SHADOW_THRESHOLD = 1.0; private static final int GRADIENT_HEIGHT = 5; private static final int SCROLLING_SPEED = 20; - private static final int GRADIENT_COLOR = ColorsKt.color(0x000000, 0.2f); + private static final int GRADIENT_COLOR = Colors.color(0x000000, 0.2f); private static final int SCROLLING_TRACK_MARGIN = 2; private static final int SCROLLING_TRACK_WIDTH = 4; - private static final int SCROLL_THUMB_COLOR_INACTIVE = ColorsKt.color(0x000000, 0.2f); - private static final int SCROLL_THUMB_COLOR_ACTIVE = ColorsKt.color(0x000000, 0.6f); + private static final int SCROLL_THUMB_COLOR_INACTIVE = Colors.color(0x000000, 0.2f); + private static final int SCROLL_THUMB_COLOR_ACTIVE = Colors.color(0x000000, 0.6f); private final SizedElement element; private double offset = 0.0; diff --git a/common/src/main/java/juuxel/adorn/client/renderer/TradingStationRenderer.java b/common/src/main/java/juuxel/adorn/client/renderer/TradingStationRenderer.java index 142bcf1d7..a188d9087 100644 --- a/common/src/main/java/juuxel/adorn/client/renderer/TradingStationRenderer.java +++ b/common/src/main/java/juuxel/adorn/client/renderer/TradingStationRenderer.java @@ -3,8 +3,7 @@ import juuxel.adorn.block.entity.TradingStationBlockEntity; import juuxel.adorn.config.ConfigManager; import juuxel.adorn.util.Colors; -import juuxel.adorn.util.ColorsKt; -import juuxel.adorn.util.ExtensionsKt; +import juuxel.adorn.util.AdornUtil; import net.minecraft.block.entity.BlockEntity; import net.minecraft.client.MinecraftClient; import net.minecraft.client.font.TextRenderer; @@ -56,8 +55,8 @@ public void render(TradingStationBlockEntity be, float tickDelta, MatrixStack ma Text label1 = Text.translatable(OWNER_LABEL, be.getOwnerName().copy().formatted(Formatting.GOLD)); renderLabel(be, label1, 0.0, 0.9, 0.0, 12, matrices, vertexConsumers, light); if (!be.getTrade().isEmpty()) { - Text label2 = Text.translatable(SELLING_LABEL, ExtensionsKt.toTextWithCount(be.getTrade().getSelling())); - Text label3 = Text.translatable(PRICE_LABEL, ExtensionsKt.toTextWithCount(be.getTrade().getPrice())); + Text label2 = Text.translatable(SELLING_LABEL, AdornUtil.toTextWithCount(be.getTrade().getSelling())); + Text label3 = Text.translatable(PRICE_LABEL, AdornUtil.toTextWithCount(be.getTrade().getPrice())); renderLabel(be, label2, 0.0, 0.9 - 0.25, 0.0, 12, matrices, vertexConsumers, light); renderLabel(be, label3, 0.0, 0.9 - 0.5, 0.0, 12, matrices, vertexConsumers, light); } @@ -79,7 +78,7 @@ private void renderLabel( var positionMatrix = matrices.peek().getPositionMatrix(); float opacity = MinecraftClient.getInstance().options.getTextBackgroundOpacity(0.25f); - int backgroundColor = ColorsKt.color(0x000000, opacity); + int backgroundColor = Colors.color(0x000000, opacity); var textX = -textRenderer.getWidth(label) * 0.5f; textRenderer.draw(label, textX, 0f, Colors.WHITE, false, positionMatrix, vertexConsumers, TextRenderer.TextLayerType.NORMAL, backgroundColor, light); diff --git a/common/src/main/java/juuxel/adorn/client/resources/ColorManager.java b/common/src/main/java/juuxel/adorn/client/resources/ColorManager.java index ed191d578..12737e6a6 100644 --- a/common/src/main/java/juuxel/adorn/client/resources/ColorManager.java +++ b/common/src/main/java/juuxel/adorn/client/resources/ColorManager.java @@ -9,7 +9,6 @@ import com.mojang.serialization.codecs.RecordCodecBuilder; import juuxel.adorn.AdornCommon; import juuxel.adorn.util.Colors; -import juuxel.adorn.util.ColorsKt; import juuxel.adorn.util.Logging; import net.minecraft.resource.ResourceFinder; import net.minecraft.resource.ResourceManager; @@ -98,7 +97,7 @@ private static DataResult parseHexColor(String str) { var colorStr = str.substring(1); return DataResult.success(switch (colorStr.length()) { - case 6 -> ColorsKt.color(Integer.parseInt(colorStr, 16)); + case 6 -> Colors.color(Integer.parseInt(colorStr, 16)); case 8 -> Integer.parseInt(colorStr, 16); default -> throw new MatchException("Mismatching color length: " + colorStr.length(), null); }); diff --git a/common/src/main/java/juuxel/adorn/entity/SeatEntity.java b/common/src/main/java/juuxel/adorn/entity/SeatEntity.java index 51f0ad165..524b3d828 100644 --- a/common/src/main/java/juuxel/adorn/entity/SeatEntity.java +++ b/common/src/main/java/juuxel/adorn/entity/SeatEntity.java @@ -2,7 +2,7 @@ import juuxel.adorn.block.SeatBlock; import juuxel.adorn.platform.PlatformBridges; -import juuxel.adorn.util.NbtExtensionsKt; +import juuxel.adorn.util.NbtUtil; import net.minecraft.entity.Entity; import net.minecraft.entity.EntityDimensions; import net.minecraft.entity.EntityType; @@ -85,12 +85,12 @@ protected void initDataTracker() { @Override protected void readCustomDataFromNbt(NbtCompound nbt) { - seatPos = NbtExtensionsKt.getBlockPos(nbt, NBT_SEAT_POS); + seatPos = NbtUtil.getBlockPos(nbt, NBT_SEAT_POS); } @Override protected void writeCustomDataToNbt(NbtCompound nbt) { - NbtExtensionsKt.putBlockPos(nbt, NBT_SEAT_POS, seatPos); + NbtUtil.putBlockPos(nbt, NBT_SEAT_POS, seatPos); } @Override diff --git a/common/src/main/java/juuxel/adorn/item/TradingStationItem.java b/common/src/main/java/juuxel/adorn/item/TradingStationItem.java index 874f5ba46..c2e9d4e76 100644 --- a/common/src/main/java/juuxel/adorn/item/TradingStationItem.java +++ b/common/src/main/java/juuxel/adorn/item/TradingStationItem.java @@ -2,7 +2,7 @@ import juuxel.adorn.block.entity.TradingStationBlockEntity; import juuxel.adorn.trading.Trade; -import juuxel.adorn.util.NbtExtensionsKt; +import juuxel.adorn.util.NbtUtil; import net.minecraft.block.Block; import net.minecraft.client.item.TooltipData; import net.minecraft.item.ItemStack; @@ -24,7 +24,7 @@ public boolean canBeNested() { public Optional getTooltipData(ItemStack stack) { var nbt = stack.getSubNbt(BLOCK_ENTITY_TAG_KEY); if (nbt != null) { - var tradeNbt = NbtExtensionsKt.getCompoundOrNull(nbt, TradingStationBlockEntity.NBT_TRADE); + var tradeNbt = NbtUtil.getCompoundOrNull(nbt, TradingStationBlockEntity.NBT_TRADE); if (tradeNbt != null) { var trade = Trade.fromNbt(tradeNbt); if (!trade.isFullyEmpty()) { diff --git a/common/src/main/java/juuxel/adorn/item/WateringCanItem.java b/common/src/main/java/juuxel/adorn/item/WateringCanItem.java index 333628140..1f662cd12 100644 --- a/common/src/main/java/juuxel/adorn/item/WateringCanItem.java +++ b/common/src/main/java/juuxel/adorn/item/WateringCanItem.java @@ -4,7 +4,7 @@ import juuxel.adorn.fluid.StepMaximum; import juuxel.adorn.lib.AdornSounds; import juuxel.adorn.platform.FluidBridge; -import juuxel.adorn.util.ColorsKt; +import juuxel.adorn.util.Colors; import net.minecraft.block.Block; import net.minecraft.block.BlockState; import net.minecraft.block.FarmlandBlock; @@ -188,7 +188,7 @@ public int getItemBarColor(ItemStack stack) { // To: 0.4f, 1f ); - return ColorsKt.color(rg, rg, 1f); + return Colors.color(rg, rg, 1f); } @Override diff --git a/common/src/main/java/juuxel/adorn/loot/CheckTradingStationOwnerLootFunction.java b/common/src/main/java/juuxel/adorn/loot/CheckTradingStationOwnerLootFunction.java index ab88345ad..98f619e8b 100644 --- a/common/src/main/java/juuxel/adorn/loot/CheckTradingStationOwnerLootFunction.java +++ b/common/src/main/java/juuxel/adorn/loot/CheckTradingStationOwnerLootFunction.java @@ -5,7 +5,7 @@ import juuxel.adorn.block.entity.TradingStationBlockEntity; import juuxel.adorn.trading.Trade; import juuxel.adorn.util.InventoryComponent; -import juuxel.adorn.util.NbtExtensionsKt; +import juuxel.adorn.util.NbtUtil; import net.minecraft.item.BlockItem; import net.minecraft.item.ItemStack; import net.minecraft.loot.context.LootContext; @@ -35,14 +35,14 @@ public ItemStack apply(ItemStack stack, LootContext lootContext) { } private boolean hasTrade(NbtCompound nbt) { - var tradeNbt = NbtExtensionsKt.getCompoundOrNull(nbt, TradingStationBlockEntity.NBT_TRADE); + var tradeNbt = NbtUtil.getCompoundOrNull(nbt, TradingStationBlockEntity.NBT_TRADE); if (tradeNbt == null) return false; var trade = Trade.fromNbt(tradeNbt); return !trade.isFullyEmpty(); } private boolean hasStorage(NbtCompound nbt) { - var storageNbt = NbtExtensionsKt.getCompoundOrNull(nbt, TradingStationBlockEntity.NBT_STORAGE); + var storageNbt = NbtUtil.getCompoundOrNull(nbt, TradingStationBlockEntity.NBT_STORAGE); if (storageNbt == null) return false; var inventory = new InventoryComponent(TradingStationBlockEntity.STORAGE_SIZE); inventory.readNbt(storageNbt); diff --git a/common/src/main/java/juuxel/adorn/util/AdornUtil.java b/common/src/main/java/juuxel/adorn/util/AdornUtil.java new file mode 100644 index 000000000..b23c2c908 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/AdornUtil.java @@ -0,0 +1,78 @@ +package juuxel.adorn.util; + +import com.google.common.base.Suppliers; +import juuxel.adorn.lib.registry.Registered; +import net.minecraft.block.AbstractBlock; +import net.minecraft.block.Block; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.menu.MenuContext; +import net.minecraft.registry.Registries; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.math.Direction; +import org.slf4j.Logger; + +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public final class AdornUtil { + private static final Logger LOGGER = Logging.logger(); + + public static MutableText toTextWithCount(ItemStack stack) { + return Text.translatable("text.adorn.item_stack_with_count", stack.getCount(), stack.toHoverableText()); + } + + public static AbstractBlock.Settings copySettingsSafely(Block block) { + var settings = AbstractBlock.Settings.create(); + caughtProperty(block, "mapColor", () -> settings.mapColor(block.getDefaultMapColor())); + caughtProperty(block, "luminance", () -> { + int luminance = block.getDefaultState().getLuminance(); + settings.luminance(state -> luminance); + }); + caughtProperty(block, "hardness", () -> settings.hardness(block.getDefaultState().getHardness(null, null))); + caughtProperty(block, "resistance", () -> settings.resistance(block.getBlastResistance())); + caughtProperty(block, "velocityMultiplier", () -> settings.velocityMultiplier(block.getVelocityMultiplier())); + caughtProperty(block, "jumpVelocityMultiplier", () -> settings.jumpVelocityMultiplier(block.getJumpVelocityMultiplier())); + caughtProperty(block, "slipperiness", () -> settings.slipperiness(block.getSlipperiness())); + caughtProperty(block, "soundGroup", () -> settings.sounds(block.getDefaultState().getSoundGroup())); + return settings; + } + + private static void caughtProperty(Block block, String name, Runnable fn) { + try { + fn.run(); + } catch (Exception e) { + LOGGER.warn("[Adorn] Could not get block property {} from {}", name, Registries.BLOCK.getId(block), e); + } + } + + public static Direction.Axis turnHorizontally(Direction.Axis axis) { + return switch (axis) { + case X -> Direction.Axis.Z; + case Z -> Direction.Axis.X; + case Y -> Direction.Axis.Y; + }; + } + + public static Registered> associateLazily(K[] keys, Function> mapper) { + List> values = new ArrayList<>(); + for (K key : keys) { + values.add(mapper.apply(key)); + } + var map = Suppliers.memoize( + () -> IntStream.range(0, keys.length) + .boxed() + .collect(Collectors.toMap(index -> keys[index], index -> values.get(index).get())) + ); + return map::get; + } + + public static MenuContext menuContextOf(BlockEntity blockEntity) { + return MenuContext.create(blockEntity.getWorld(), blockEntity.getPos()); + } +} diff --git a/common/src/main/java/juuxel/adorn/util/CollectionUtil.java b/common/src/main/java/juuxel/adorn/util/CollectionUtil.java new file mode 100644 index 000000000..bc36b33da --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/CollectionUtil.java @@ -0,0 +1,46 @@ +package juuxel.adorn.util; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.ToIntFunction; + +public final class CollectionUtil { + /** + * Interleaves elements of all lists. + * + *

For example, if this method is passed the list {@code [[a, b, c], [A, B, C, D]]}, + * the expected output is {@code [a, A, b, B, c, C, D]}. + */ + public static List interleave(List> lists) { + var size = sumOf(lists, List::size); + var maxSize = maxOf(lists, List::size); + List output = new ArrayList<>(size); + + for (int i = 0; i < maxSize; i++) { + for (var list : lists) { + if (i < list.size()) { + output.add(list.get(i)); + } + } + } + + return output; + } + + public static int sumOf(Iterable ts, ToIntFunction getter) { + int sum = 0; + for (T t : ts) { + sum += getter.applyAsInt(t); + } + return sum; + } + + public static int maxOf(Iterable ts, ToIntFunction getter) { + int max = Integer.MIN_VALUE; + for (T t : ts) { + var current = getter.applyAsInt(t); + if (current > max) max = current; + } + return max; + } +} diff --git a/common/src/main/java/juuxel/adorn/util/Colors.java b/common/src/main/java/juuxel/adorn/util/Colors.java new file mode 100644 index 000000000..2e3d37819 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/Colors.java @@ -0,0 +1,48 @@ +package juuxel.adorn.util; + +public final class Colors { + public static final int BLACK = 0xFF_000000; + public static final int WHITE = 0xFF_FFFFFF; + public static final int SCREEN_TEXT = 0xFF_404040; + public static final int TRANSPARENT = 0x00_000000; + + public static int color(int rgb) { + return color(rgb, 0xFF); + } + + public static int color(int rgb, int alpha) { + return alpha << 24 | rgb; + } + + public static int color(int rgb, float alpha) { + return color(rgb, (int) (alpha * 255f)); + } + + public static int color(float red, float green, float blue) { + return color(red, green, blue, 1f); + } + + public static int color(float red, float green, float blue, float alpha) { + return color((int) (red * 255f), (int) (green * 255f), (int) (blue * 255f), (int) (alpha * 255f)); + } + + public static int color(int red, int green, int blue, int alpha) { + return (alpha & 0xFF) << 24 | (red & 0xFF) << 16 | (green & 0xFF) << 8 | blue & 0xFF; + } + + public static float redOf(int argb) { + return ((argb >> 16) & 0xFF) / 255f; + } + + public static float greenOf(int argb) { + return ((argb >> 8) & 0xFF) / 255f; + } + + public static float blueOf(int argb) { + return (argb & 0xFF) / 255f; + } + + public static float alphaOf(int argb) { + return ((argb >> 24) & 0xFF) / 255f; + } +} diff --git a/common/src/main/java/juuxel/adorn/util/Displayable.java b/common/src/main/java/juuxel/adorn/util/Displayable.java new file mode 100644 index 000000000..cdab22ca9 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/Displayable.java @@ -0,0 +1,7 @@ +package juuxel.adorn.util; + +import net.minecraft.text.Text; + +public interface Displayable { + Text getDisplayName(); +} diff --git a/common/src/main/java/juuxel/adorn/util/InventoryComponent.java b/common/src/main/java/juuxel/adorn/util/InventoryComponent.java new file mode 100644 index 000000000..980d5d7ee --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/InventoryComponent.java @@ -0,0 +1,206 @@ +package juuxel.adorn.util; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.InventoryChangedListener; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.util.collection.DefaultedList; + +import java.util.ArrayList; +import java.util.List; +import java.util.Objects; + +public class InventoryComponent implements Inventory, NbtConvertible { + private final int size; + private final List listeners = new ArrayList<>(); + private final DefaultedList items; + + public InventoryComponent(int size) { + this.size = size; + items = DefaultedList.ofSize(size, ItemStack.EMPTY); + } + + private InventoryComponent(DefaultedList items) { + this(items.size()); + for (int i = 0; i < items.size(); i++) { + this.items.set(i, items.get(i)); + } + } + + /** + * Creates a copy of this inventory, not retaining any listeners. + */ + public InventoryComponent copy() { + return new InventoryComponent(items); + } + + /** + * Checks if the stack can be extracted from this inventory. Ignores NBT, durability and tags. + */ + public boolean canExtract(ItemStack stack) { + int remainingAmount = stack.getCount(); + + for (var invStack : items) { + if (ItemStack.areItemsEqual(invStack, stack)) { + remainingAmount -= invStack.getCount(); + if (remainingAmount <= 0) return true; + } + } + + return false; + } + + /** + * Tries to remove the stack from this inventory. Ignores tags. + * + * @return {@code true} if extracted + */ + public boolean tryExtract(ItemStack stack) { + int remainingAmount = stack.getCount(); + + for (var invStack : items) { + if (ItemStack.areItemsEqual(invStack, stack) && Objects.equals(invStack.getNbt(), stack.getNbt())) { + int invStackAmount = invStack.getCount(); + invStack.decrement(Math.min(invStackAmount, remainingAmount)); + remainingAmount -= invStackAmount; + if (remainingAmount <= 0) return true; + } + } + + return false; + } + + /** + * Checks if the stack can be inserted to this inventory. Ignores tags. + */ + public boolean canInsert(ItemStack stack) { + int remainingAmount = stack.getCount(); + + for (var invStack : items) { + if (ItemStack.areItemsEqual(invStack, stack) && invStack.getCount() < invStack.getMaxCount() && Objects.equals(stack.getNbt(), invStack.getNbt())) { + int insertionAmount = Math.min(invStack.getMaxCount() - invStack.getCount(), remainingAmount); + remainingAmount -= insertionAmount; + if (remainingAmount <= 0) return true; + } else if (invStack.isEmpty()) { + return true; + } + } + + return false; + } + + /** + * Tries to insert the stack to this inventory. Ignores tags. + * + * @return {@code true} if inserted + */ + public boolean tryInsert(ItemStack stack) { + int remainingAmount = stack.getCount(); + + for (int slot = 0; slot < items.size(); slot++) { + var invStack = items.get(slot); + if (ItemStack.areItemsEqual(invStack, stack) && invStack.getCount() < invStack.getMaxCount() && Objects.equals(invStack.getNbt(), stack.getNbt())) { + int insertionAmount = Math.min(invStack.getMaxCount() - invStack.getCount(), remainingAmount); + remainingAmount -= insertionAmount; + invStack.increment(insertionAmount); + if (remainingAmount <= 0) return true; + } else if (invStack.isEmpty()) { + items.set(slot, stack.copy()); + return true; + } + } + + return false; + } + + /** + * Gets the count of items with the same item and NBT as the stack. + * Ignores the stack's count. + */ + public int getAmountWithNbt(ItemStack stack) { + return CollectionUtil.sumOf(items, it -> stack.getItem() == it.getItem() && Objects.equals(stack.getNbt(), it.getNbt()) ? it.getCount() : 0); + } + + // ----- + // NBT + // ----- + + @Override + public NbtCompound writeNbt(NbtCompound nbt) { + Inventories.writeNbt(nbt, items); + return nbt; + } + + @Override + public void readNbt(NbtCompound nbt) { + Inventories.readNbt(nbt, items); + } + + // ------------------------------- + // Inventory management/transfer + // ------------------------------- + + @Override + public ItemStack getStack(int slot) { + return items.get(slot); + } + + @Override + public void clear() { + items.clear(); + markDirty(); + } + + @Override + public void setStack(int slot, ItemStack stack) { + items.set(slot, stack); + } + + @Override + public ItemStack removeStack(int slot) { + return Inventories.removeStack(items, slot); + } + + @Override + public boolean canPlayerUse(PlayerEntity player) { + return true; + } + + @Override + public int size() { + return size; + } + + @Override + public ItemStack removeStack(int slot, int count) { + var stack = Inventories.splitStack(items, slot, count); + if (!stack.isEmpty()) markDirty(); + return stack; + } + + @Override + public boolean isEmpty() { + for (var stack : items) { + if (!stack.isEmpty()) return false; + } + + return true; + } + + // ----------- + // Listeners + // ----------- + + @Override + public void markDirty() { + for (var listener : listeners) { + listener.onInventoryChanged(this); + } + } + + public void addListener(InventoryChangedListener listener) { + listeners.add(listener); + } +} diff --git a/common/src/main/java/juuxel/adorn/util/Logging.java b/common/src/main/java/juuxel/adorn/util/Logging.java new file mode 100644 index 000000000..227718b06 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/Logging.java @@ -0,0 +1,27 @@ +package juuxel.adorn.util; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public final class Logging { + private static final StackWalker STACK_WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE); + + /** + * Gets a logger for the calling class. + * + *

If called from a nested class, returns a logger + * for the outermost class in the nest. + */ + public static Logger logger() { + var caller = STACK_WALKER.getCallerClass(); + + // Locate the outermost class. + var next = caller.getEnclosingClass(); + while (next != null) { + caller = next; + next = caller.getEnclosingClass(); + } + + return LoggerFactory.getLogger(caller); + } +} diff --git a/common/src/main/java/juuxel/adorn/util/MoreCodecs.java b/common/src/main/java/juuxel/adorn/util/MoreCodecs.java new file mode 100644 index 000000000..44231e817 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/MoreCodecs.java @@ -0,0 +1,32 @@ +package juuxel.adorn.util; + +import com.mojang.datafixers.util.Pair; +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.DynamicOps; +import com.mojang.serialization.JsonOps; +import net.minecraft.text.Text; + +public final class MoreCodecs { + public static final Codec TEXT = new Codec<>() { + @Override + public DataResult encode(Text input, DynamicOps ops, T prefix) { + var json = Text.Serialization.toJsonTree(input); + var converted = Dynamic.convert(JsonOps.INSTANCE, ops, json); + return ops.mergeToPrimitive(prefix, converted); + } + + @Override + public DataResult> decode(DynamicOps ops, T input) { + var json = Dynamic.convert(ops, JsonOps.INSTANCE, input); + var text = Text.Serialization.fromJsonTree(json); + return text != null ? DataResult.success(Pair.of(text, ops.empty())) : DataResult.error(() -> "Could not decode text " + json); + } + + @Override + public String toString() { + return "Text"; + } + }; +} diff --git a/common/src/main/java/juuxel/adorn/util/NbtConvertible.java b/common/src/main/java/juuxel/adorn/util/NbtConvertible.java new file mode 100644 index 000000000..f4d450f8b --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/NbtConvertible.java @@ -0,0 +1,8 @@ +package juuxel.adorn.util; + +import net.minecraft.nbt.NbtCompound; + +public interface NbtConvertible { + void readNbt(NbtCompound nbt); + NbtCompound writeNbt(NbtCompound nbt); +} diff --git a/common/src/main/java/juuxel/adorn/util/NbtUtil.java b/common/src/main/java/juuxel/adorn/util/NbtUtil.java new file mode 100644 index 000000000..d08464921 --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/NbtUtil.java @@ -0,0 +1,42 @@ +package juuxel.adorn.util; + +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; +import net.minecraft.nbt.NbtCompound; +import net.minecraft.nbt.NbtElement; +import net.minecraft.nbt.NbtOps; +import net.minecraft.text.Text; +import net.minecraft.util.math.BlockPos; +import org.jetbrains.annotations.Nullable; + +public final class NbtUtil { + public static void putText(NbtCompound nbt, String name, Text text) { + nbt.put(name, Dynamic.convert(JsonOps.INSTANCE, NbtOps.INSTANCE, Text.Serialization.toJsonTree(text))); + } + + public static @Nullable Text getText(NbtCompound nbt, String name) { + var tag = nbt.get(name); + if (tag == null) return null; + + return Text.Serialization.fromJsonTree( + Dynamic.convert( + NbtOps.INSTANCE, + JsonOps.INSTANCE, + tag + ) + ); + } + + public static BlockPos getBlockPos(NbtCompound nbt, String key) { + int[] coords = nbt.getIntArray(key); + return new BlockPos(coords[0], coords[1], coords[2]); + } + + public static void putBlockPos(NbtCompound nbt, String key, BlockPos pos) { + nbt.putIntArray(key, new int[] { pos.getX(), pos.getY(), pos.getZ() }); + } + + public static @Nullable NbtCompound getCompoundOrNull(NbtCompound nbt, String key) { + return nbt.contains(key, NbtElement.COMPOUND_TYPE) ? nbt.getCompound(key) : null; + } +} diff --git a/common/src/main/java/juuxel/adorn/util/PropertyRef.java b/common/src/main/java/juuxel/adorn/util/PropertyRef.java new file mode 100644 index 000000000..f2d9d9d7c --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/PropertyRef.java @@ -0,0 +1,52 @@ +package juuxel.adorn.util; + +import java.lang.invoke.MethodHandles; + +/** + * Reference to a mutable property. + */ +public interface PropertyRef { + String getName(); + T get(); + void set(T value); + + static PropertyRef ofField(Object owner, String fieldName) { + try { + var field = owner.getClass().getField(fieldName); + field.setAccessible(true); + + var name = field.getName(); + var lookup = MethodHandles.lookup(); + var getter = lookup.unreflectGetter(field); + var setter = lookup.unreflectSetter(field); + + return new PropertyRef<>() { + @Override + public String getName() { + return name; + } + + @SuppressWarnings("unchecked") + @Override + public T get() { + try { + return (T) getter.invoke(owner); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + + @Override + public void set(T value) { + try { + setter.invoke(owner, value); + } catch (Throwable e) { + throw new RuntimeException(e); + } + } + }; + } catch (ReflectiveOperationException e) { + throw new RuntimeException(e); + } + } +} diff --git a/common/src/main/java/juuxel/adorn/util/Shapes.java b/common/src/main/java/juuxel/adorn/util/Shapes.java new file mode 100644 index 000000000..a04da0a0a --- /dev/null +++ b/common/src/main/java/juuxel/adorn/util/Shapes.java @@ -0,0 +1,71 @@ +package juuxel.adorn.util; + +import net.minecraft.block.Block; +import net.minecraft.util.math.Direction; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; + +import java.util.Arrays; +import java.util.EnumMap; +import java.util.Map; +import java.util.function.Function; +import java.util.stream.Collectors; + +public final class Shapes { + /** + * Creates a map of horizontal cuboid VoxelShape rotations from the provided coordinates for east. + * + *

The coordinates are specified like in a model json or {@code createCuboidShape}: + * {@code { from: ([x0], [y0], [z0]), to: ([x1], [y1], [z1]) }} + * + * @deprecated Use north instead: {@code buildShapeRotationsFromNorth(z0, y0, 16 - x1, z1, y1, 16 - x0)} + */ + @Deprecated + public static Map buildShapeRotations(int x0, int y0, int z0, int x1, int y1, int z1) { + return buildShapeRotationsFromNorth(z0, y0, 16 - x1, z1, y1, 16 - x0); + } + + /** + * Creates a map of horizontal cuboid VoxelShape rotations from the provided coordinates for north. + * + *

The coordinates are specified like in a model json or {@code createCuboidShape}: + * {@code { from: ([x0], [y0], [z0]), to: ([x1], [y1], [z1]) }} + */ + public static Map buildShapeRotationsFromNorth(int x0, int y0, int z0, int x1, int y1, int z1) { + Map result = new EnumMap<>(Direction.class); + result.put(Direction.NORTH, Block.createCuboidShape(x0, y0, z0, x1, y1, z1)); + result.put(Direction.SOUTH, Block.createCuboidShape(16.0 - x1, y0, 16.0 - z1, 16.0 - x0, y1, 16.0 - z0)); + result.put(Direction.EAST, Block.createCuboidShape(16.0 - z1, y0, x0, 16.0 - z0, y1, x1)); + result.put(Direction.WEST, Block.createCuboidShape(z0, y0, 16.0 - x1, z1, y1, 16.0 - x0)); + return result; + } + + /** + * Merges the shape maps together. + */ + @SafeVarargs + public static Map mergeShapeMaps(Map... maps) { + return new EnumMap<>( + Direction.Type.HORIZONTAL.stream().collect(Collectors.toMap( + Function.identity(), + direction -> Arrays.stream(maps) + .map(map -> { + var shape = map.get(direction); + if (shape == null) throw new IllegalArgumentException("Map is missing shape for " + direction); + return shape; + }) + .reduce(VoxelShapes::union) + .orElseThrow() + )) + ); + } + + /** + * Merges the shape into the shape map. + */ + public static Map mergeIntoShapeMap(Map map, VoxelShape shape) { + var result = new EnumMap(Direction.class); + map.forEach((direction, existing) -> result.put(direction, VoxelShapes.union(existing, shape))); + return result; + } +} diff --git a/common/src/main/java/juuxel/adorn/util/animation/Interpolator.java b/common/src/main/java/juuxel/adorn/util/animation/Interpolator.java index a96870952..b0db2491e 100644 --- a/common/src/main/java/juuxel/adorn/util/animation/Interpolator.java +++ b/common/src/main/java/juuxel/adorn/util/animation/Interpolator.java @@ -1,7 +1,6 @@ package juuxel.adorn.util.animation; import juuxel.adorn.util.Colors; -import juuxel.adorn.util.ColorsKt; import net.minecraft.util.math.MathHelper; @FunctionalInterface @@ -13,7 +12,7 @@ public interface Interpolator { float red = FLOAT.interpolate(delta, Colors.redOf(from), Colors.redOf(to)); float green = FLOAT.interpolate(delta, Colors.greenOf(from), Colors.greenOf(to)); float blue = FLOAT.interpolate(delta, Colors.blueOf(from), Colors.blueOf(to)); - return ColorsKt.color(red, green, blue, alpha); + return Colors.color(red, green, blue, alpha); }; T interpolate(float delta, T from, T to); diff --git a/common/src/main/kotlin/juuxel/adorn/AdornCommon.kt b/common/src/main/kotlin/juuxel/adorn/AdornCommon.kt deleted file mode 100644 index 33f4b6b55..000000000 --- a/common/src/main/kotlin/juuxel/adorn/AdornCommon.kt +++ /dev/null @@ -1,10 +0,0 @@ -package juuxel.adorn - -import net.minecraft.util.Identifier - -object AdornCommon { - const val NAMESPACE = "adorn" - - @JvmStatic - fun id(path: String) = Identifier(NAMESPACE, path) -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/Collections.kt b/common/src/main/kotlin/juuxel/adorn/util/Collections.kt deleted file mode 100644 index 884427bd3..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/Collections.kt +++ /dev/null @@ -1,28 +0,0 @@ -package juuxel.adorn.util - -import java.util.EnumMap - -inline fun , V> enumMapOf(vararg pairs: Pair): EnumMap = - EnumMap(K::class.java).apply { putAll(pairs) } - -/** - * Interleaves elements of all [lists]. - * - * For example, if this method is passed the list `[[a, b, c], [A, B, C, D]]`, - * the expected output is `[a, A, b, B, c, C, D]`. - */ -fun interleave(lists: List>): List { - val size = lists.sumOf { it.size } - val maxSize = lists.maxOf { it.size } - val output = ArrayList(size) - - for (i in 0 until maxSize) { - for (list in lists) { - if (i in list.indices) { - output += list[i] - } - } - } - - return output -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/Colors.kt b/common/src/main/kotlin/juuxel/adorn/util/Colors.kt deleted file mode 100644 index 74327ba7c..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/Colors.kt +++ /dev/null @@ -1,40 +0,0 @@ -package juuxel.adorn.util - -@JvmOverloads -fun color(rgb: Int, alpha: Int = 0xFF) = - alpha shl 24 or rgb - -fun color(rgb: Int, alpha: Float) = color(rgb, (alpha * 255f).toInt()) - -@JvmOverloads -fun color(red: Float, green: Float, blue: Float, alpha: Float = 1f): Int = - color((red * 255f).toInt(), (green * 255f).toInt(), (blue * 255f).toInt(), (alpha * 255f).toInt()) - -fun color(red: Int, green: Int, blue: Int, alpha: Int = 0xFF): Int = - ((alpha and 0xFF) shl 24) or ((red and 0xFF) shl 16) or ((green and 0xFF) shl 8) or (blue and 0xFF) - -object Colors { - @JvmField - val BLACK = color(0x000000) - - @JvmField - val WHITE = color(0xFFFFFF) - - @JvmField - val SCREEN_TEXT = color(0x404040) - - @JvmField - val TRANSPARENT = color(0x000000, alpha = 0) - - @JvmStatic - fun redOf(argb: Int): Float = ((argb shr 16) and 0xFF) / 255f - - @JvmStatic - fun greenOf(argb: Int): Float = ((argb shr 8) and 0xFF) / 255f - - @JvmStatic - fun blueOf(argb: Int): Float = (argb and 0xFF) / 255f - - @JvmStatic - fun alphaOf(argb: Int): Float = ((argb shr 24) and 0xFF) / 255f -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/Displayable.kt b/common/src/main/kotlin/juuxel/adorn/util/Displayable.kt deleted file mode 100644 index 50314f06e..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/Displayable.kt +++ /dev/null @@ -1,7 +0,0 @@ -package juuxel.adorn.util - -import net.minecraft.text.Text - -interface Displayable { - val displayName: Text -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/Extensions.kt b/common/src/main/kotlin/juuxel/adorn/util/Extensions.kt deleted file mode 100644 index 6a1d42370..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/Extensions.kt +++ /dev/null @@ -1,100 +0,0 @@ -package juuxel.adorn.util - -import juuxel.adorn.lib.registry.Registered -import net.minecraft.block.AbstractBlock -import net.minecraft.block.Block -import net.minecraft.block.entity.BlockEntity -import net.minecraft.item.ItemStack -import net.minecraft.menu.MenuContext -import net.minecraft.registry.Registries -import net.minecraft.text.MutableText -import net.minecraft.text.Text -import net.minecraft.util.math.BlockPos -import net.minecraft.util.math.Direction -import net.minecraft.world.World - -private val LOGGER = logger() - -fun ItemStack.toTextWithCount(): MutableText = - Text.translatable("text.adorn.item_stack_with_count", count, toHoverableText()) - -/** - * Gets the squared distance of this block entity to ([x], [y], [z]). - * - * Used to be in vanilla but was removed. - */ -fun BlockEntity.getSquaredDistance(x: Double, y: Double, z: Double): Double { - val xd = pos.x + 0.5 - x - val yd = pos.y + 0.5 - y - val zd = pos.z + 0.5 - z - return xd * xd + yd * yd + zd * zd -} - -/** - * Creates a safe copy of this block's settings. - * - * The safe copy does not have lambdas that reference this block directly. - * Instead, the default state is used for the various lambdas. - */ -fun Block.copySettingsSafely(): AbstractBlock.Settings { - val settings = AbstractBlock.Settings.create() - caughtProperty(this, "mapColor") { settings.mapColor(defaultMapColor) } - caughtProperty(this, "luminance") { settings.luminance { defaultState.luminance } } - caughtProperty(this, "hardness") { settings.hardness(defaultState.getHardness(null, null)) } - caughtProperty(this, "resistance") { settings.resistance(blastResistance) } - caughtProperty(this, "velocityMultiplier") { settings.velocityMultiplier(velocityMultiplier) } - caughtProperty(this, "jumpVelocityMultiplier") { settings.jumpVelocityMultiplier(jumpVelocityMultiplier) } - caughtProperty(this, "slipperiness") { settings.slipperiness(slipperiness) } - caughtProperty(this, "soundGroup") { settings.sounds(defaultState.soundGroup) } - return settings -} - -private inline fun caughtProperty(block: Block, name: String, fn: () -> Unit) { - try { - fn() - } catch (e: Exception) { - LOGGER.warn("[Adorn] Could not get block property {} from {}", name, Registries.BLOCK.getId(block), e) - } -} - -fun Direction.Axis.turnHorizontally(): Direction.Axis = - when (this) { - Direction.Axis.X -> Direction.Axis.Z - Direction.Axis.Z -> Direction.Axis.X - Direction.Axis.Y -> Direction.Axis.Y - } - -fun Direction.Axis.getDirection(axisDirection: Direction.AxisDirection): Direction = - when (axisDirection) { - Direction.AxisDirection.POSITIVE -> when (this) { - Direction.Axis.X -> Direction.EAST - Direction.Axis.Y -> Direction.UP - Direction.Axis.Z -> Direction.SOUTH - } - - Direction.AxisDirection.NEGATIVE -> when (this) { - Direction.Axis.X -> Direction.WEST - Direction.Axis.Y -> Direction.DOWN - Direction.Axis.Z -> Direction.NORTH - } - } - -fun Array.associateLazily(mapper: (K) -> Registered): Registered> { - val pairs = map { it to mapper(it) } - val map = lazy { pairs.associate { (key, value) -> key to value.get() } } - return Registered(map::value) -} - -/** - * Gets the block entity located at this context's position. - */ -fun MenuContext.getBlockEntity(): BlockEntity? = - get { world: World, pos: BlockPos -> world.getBlockEntity(pos) } - .orElse(null) - -/** - * Creates a menu context in the world and at the position of the [blockEntity]. - * In a way, the inverse operation to [getBlockEntity]. - */ -fun menuContextOf(blockEntity: BlockEntity): MenuContext = - MenuContext.create(blockEntity.world, blockEntity.pos) diff --git a/common/src/main/kotlin/juuxel/adorn/util/InventoryComponent.kt b/common/src/main/kotlin/juuxel/adorn/util/InventoryComponent.kt deleted file mode 100644 index 2d06abebe..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/InventoryComponent.kt +++ /dev/null @@ -1,171 +0,0 @@ -package juuxel.adorn.util - -import net.minecraft.entity.player.PlayerEntity -import net.minecraft.inventory.Inventories -import net.minecraft.inventory.Inventory -import net.minecraft.inventory.InventoryChangedListener -import net.minecraft.item.ItemStack -import net.minecraft.nbt.NbtCompound -import net.minecraft.util.collection.DefaultedList -import kotlin.math.min - -open class InventoryComponent(private val invSize: Int) : Inventory, NbtConvertible { - private val listeners: MutableList = ArrayList() - private val items: DefaultedList = DefaultedList.ofSize(invSize, ItemStack.EMPTY) - - private constructor(items: DefaultedList) : this(items.size) { - for ((i, item) in items.withIndex()) { - this.items[i] = item - } - } - - /** - * Creates a copy of this inventory, not retaining any listeners. - */ - fun copy(): InventoryComponent = InventoryComponent(items) - - /** - * Checks if the [stack] can be extracted from this inventory. Ignores NBT, durability and tags. - */ - fun canExtract(stack: ItemStack): Boolean { - var remainingAmount = stack.count - - for (invStack in items) { - if (ItemStack.areItemsEqual(invStack, stack)) { - remainingAmount -= invStack.count - if (remainingAmount <= 0) return true - } - } - - return false - } - - /** - * Tries to remove the [stack] from this inventory. Ignores tags. - * - * @return `true` if extracted - */ - fun tryExtract(stack: ItemStack): Boolean { - var remainingAmount = stack.count - - for (invStack in items) { - if (ItemStack.areItemsEqual(invStack, stack) && invStack.nbt == stack.nbt) { - val invStackAmount = invStack.count - invStack.decrement(min(invStackAmount, remainingAmount)) - remainingAmount -= invStackAmount - if (remainingAmount <= 0) return true - } - } - - return false - } - - /** - * Checks if the [stack] can be inserted to this inventory. Ignores tags. - */ - fun canInsert(stack: ItemStack): Boolean { - var remainingAmount = stack.count - - for (invStack in items) { - if (ItemStack.areItemsEqual(invStack, stack) && invStack.count < invStack.maxCount && stack.nbt == invStack.nbt) { - val insertionAmount = min(invStack.maxCount - invStack.count, remainingAmount) - remainingAmount -= insertionAmount - if (remainingAmount <= 0) return true - } else if (invStack.isEmpty) { - return true - } - } - - return false - } - - /** - * Tries to insert the [stack] to this inventory. Ignores tags. - * - * @return `true` if inserted - */ - fun tryInsert(stack: ItemStack): Boolean { - var remainingAmount = stack.count - - for ((slot, invStack) in items.withIndex()) { - if (ItemStack.areItemsEqual(invStack, stack) && invStack.count < invStack.maxCount && invStack.nbt == stack.nbt) { - val insertionAmount = min(invStack.maxCount - invStack.count, remainingAmount) - remainingAmount -= insertionAmount - invStack.increment(insertionAmount) - if (remainingAmount <= 0) return true - } else if (invStack.isEmpty) { - items[slot] = stack.copy() - return true - } - } - - return false - } - - /** - * Gets the count of items with the same item and NBT as the [stack]. - * Ignores the stack's count. - */ - fun getAmountWithNbt(stack: ItemStack): Int = items.sumOf { - if (stack.item == it.item && stack.nbt == it.nbt) { - it.count - } else { - 0 - } - } - - // ----- - // NBT - // ----- - - override fun writeNbt(nbt: NbtCompound): NbtCompound = nbt.apply { - Inventories.writeNbt(nbt, items) - } - - override fun readNbt(nbt: NbtCompound) { - Inventories.readNbt(nbt, items) - } - - // ------------------------------- - // Inventory management/transfer - // ------------------------------- - - override fun getStack(slot: Int) = items[slot] - - override fun clear() { - items.clear() - markDirty() - } - - override fun setStack(slot: Int, stack: ItemStack) { - items[slot] = stack - } - - override fun removeStack(slot: Int) = - Inventories.removeStack(items, slot) - - override fun canPlayerUse(player: PlayerEntity?) = true - - override fun size() = invSize - - override fun removeStack(slot: Int, count: Int) = - Inventories.splitStack(items, slot, count).also { - if (!it.isEmpty) { - markDirty() - } - } - - override fun isEmpty(): Boolean = items.all { it.isEmpty } - - // ----------- - // Listeners - // ----------- - - override fun markDirty() { - listeners.forEach { it.onInventoryChanged(this) } - } - - fun addListener(listener: InventoryChangedListener) { - listeners += listener - } -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/Logging.kt b/common/src/main/kotlin/juuxel/adorn/util/Logging.kt deleted file mode 100644 index 786a905c5..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/Logging.kt +++ /dev/null @@ -1,30 +0,0 @@ -@file:JvmName("Logging") - -package juuxel.adorn.util - -import org.slf4j.Logger -import org.slf4j.LoggerFactory - -private val STACK_WALKER = StackWalker.getInstance(StackWalker.Option.RETAIN_CLASS_REFERENCE) - -/** - * Gets a logger for the calling class. - * - * If called from a nested class, returns a logger - * for the outermost class in the nest. - * - * If called from a top-level property initialiser, - * returns a logger for the enclosing file. - */ -fun logger(): Logger { - var caller = STACK_WALKER.getCallerClass() - - // Locate the outermost class. - var next = caller.enclosingClass - while (next != null) { - caller = next - next = caller.enclosingClass - } - - return LoggerFactory.getLogger(caller) -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/MoreCodecs.kt b/common/src/main/kotlin/juuxel/adorn/util/MoreCodecs.kt deleted file mode 100644 index 26b3b445d..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/MoreCodecs.kt +++ /dev/null @@ -1,33 +0,0 @@ -package juuxel.adorn.util - -import com.mojang.datafixers.util.Pair -import com.mojang.serialization.Codec -import com.mojang.serialization.DataResult -import com.mojang.serialization.Dynamic -import com.mojang.serialization.DynamicOps -import com.mojang.serialization.JsonOps -import net.minecraft.text.Text - -object MoreCodecs { - @JvmField - val TEXT: Codec = object : Codec { - override fun encode(input: Text, ops: DynamicOps, prefix: T): DataResult { - val json = Text.Serialization.toJsonTree(input) - val converted = Dynamic.convert(JsonOps.INSTANCE, ops, json) - return ops.mergeToPrimitive(prefix, converted) - } - - override fun decode(ops: DynamicOps, input: T): DataResult> { - val json = Dynamic.convert(ops, JsonOps.INSTANCE, input) - val text = Text.Serialization.fromJsonTree(json) - - return if (text != null) { - DataResult.success(Pair.of(text, ops.empty())) - } else { - DataResult.error { "Could not decode text $json" } - } - } - - override fun toString(): String = "Text" - } -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/NbtConvertible.kt b/common/src/main/kotlin/juuxel/adorn/util/NbtConvertible.kt deleted file mode 100644 index 1789485ed..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/NbtConvertible.kt +++ /dev/null @@ -1,8 +0,0 @@ -package juuxel.adorn.util - -import net.minecraft.nbt.NbtCompound - -interface NbtConvertible { - fun readNbt(nbt: NbtCompound) - fun writeNbt(nbt: NbtCompound): NbtCompound -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/NbtExtensions.kt b/common/src/main/kotlin/juuxel/adorn/util/NbtExtensions.kt deleted file mode 100644 index cd9b203e0..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/NbtExtensions.kt +++ /dev/null @@ -1,54 +0,0 @@ -package juuxel.adorn.util - -import com.mojang.serialization.Dynamic -import com.mojang.serialization.JsonOps -import net.minecraft.nbt.NbtCompound -import net.minecraft.nbt.NbtElement -import net.minecraft.nbt.NbtOps -import net.minecraft.text.Text -import net.minecraft.util.math.BlockPos -import java.util.UUID - -fun NbtCompound.putText(name: String, textComponent: Text) = - put( - name, - Dynamic.convert( - JsonOps.INSTANCE, - NbtOps.INSTANCE, - Text.Serialization.toJsonTree(textComponent) - ) - ) - -fun NbtCompound.getText(name: String): Text? { - val tag = get(name) ?: return null - - return Text.Serialization.fromJsonTree( - Dynamic.convert( - NbtOps.INSTANCE, - JsonOps.INSTANCE, - tag - ) - ) -} - -fun NbtCompound.containsOldUuid(key: String): Boolean = - contains("${key}Most") && contains("${key}Least") - -fun NbtCompound.getOldUuid(key: String): UUID = - UUID(getLong("${key}Most"), getLong("${key}Least")) - -fun NbtCompound.getBlockPos(key: String): BlockPos { - val (x, y, z) = getIntArray(key) - return BlockPos(x, y, z) -} - -fun NbtCompound.putBlockPos(key: String, pos: BlockPos) { - putIntArray(key, intArrayOf(pos.x, pos.y, pos.z)) -} - -fun NbtCompound.getCompoundOrNull(key: String): NbtCompound? = - if (contains(key, NbtElement.COMPOUND_TYPE.toInt())) { - getCompound(key) - } else { - null - } diff --git a/common/src/main/kotlin/juuxel/adorn/util/PropertyRef.kt b/common/src/main/kotlin/juuxel/adorn/util/PropertyRef.kt deleted file mode 100644 index d581cd733..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/PropertyRef.kt +++ /dev/null @@ -1,48 +0,0 @@ -package juuxel.adorn.util - -import java.lang.invoke.MethodHandles -import kotlin.reflect.KProperty - -/** - * Reference to a mutable property. - */ -interface PropertyRef { - val name: String - fun get(): T - fun set(value: T) - - companion object { - /** - * Creates a reflected property reference for a field of the [owner]. - */ - @JvmStatic - fun ofField(owner: Any, fieldName: String): PropertyRef { - val field = owner::class.java.getField(fieldName) - field.isAccessible = true - - val name = field.name - val lookup = MethodHandles.lookup() - val getter = lookup.unreflectGetter(field) - val setter = lookup.unreflectSetter(field) - - return object : PropertyRef { - override val name = name - - @Suppress("UNCHECKED_CAST") - override fun get(): T = - getter.invoke(owner) as T - - override fun set(value: T) { - setter.invoke(owner, value) - } - } - } - } -} - -/** - * Creates a reflected property reference for a [JvmField] property of `this` object. - */ -inline fun O.ref(finder: (O) -> KProperty): PropertyRef { - return PropertyRef.ofField(this, finder(this).name) -} diff --git a/common/src/main/kotlin/juuxel/adorn/util/Shapes.kt b/common/src/main/kotlin/juuxel/adorn/util/Shapes.kt deleted file mode 100644 index b30a4a7c0..000000000 --- a/common/src/main/kotlin/juuxel/adorn/util/Shapes.kt +++ /dev/null @@ -1,77 +0,0 @@ -@file:JvmName("Shapes") - -package juuxel.adorn.util - -import net.minecraft.block.Block.createCuboidShape -import net.minecraft.util.math.Direction -import net.minecraft.util.shape.VoxelShape -import net.minecraft.util.shape.VoxelShapes -import java.util.EnumMap - -/** - * Creates a map of horizontal cuboid VoxelShape rotations from the provided coordinates for **east**. - * - * The coordinates are specified like in a model json or [createCuboidShape]: - * { from: ([x0], [y0], [z0]), to: ([x1], [y1], [z1]) } - */ -@Deprecated( - "Use north instead", - ReplaceWith( - "buildShapeRotationsFromNorth(z0, y0, 16 - x1, z1, y1, 16 - x0)", - "juuxel.adorn.util.buildShapeRotationsFromNorth" - ) -) -fun buildShapeRotations(x0: Int, y0: Int, z0: Int, x1: Int, y1: Int, z1: Int): MutableMap = - buildShapeRotationsFromNorth( - z0, y0, 16 - x1, - z1, y1, 16 - x0 - ) - -/** - * Creates a map of horizontal cuboid VoxelShape rotations from the provided coordinates for **north**. - * - * The coordinates are specified like in a model json or [createCuboidShape]: - * { from: ([x0], [y0], [z0]), to: ([x1], [y1], [z1]) } - */ -fun buildShapeRotationsFromNorth(x0: Int, y0: Int, z0: Int, x1: Int, y1: Int, z1: Int): MutableMap = - enumMapOf( - Direction.NORTH to createCuboidShape( - x0.toDouble(), y0.toDouble(), z0.toDouble(), - x1.toDouble(), y1.toDouble(), z1.toDouble() - ), - - Direction.SOUTH to createCuboidShape( - 16.0 - x1, y0.toDouble(), 16.0 - z1, - 16.0 - x0, y1.toDouble(), 16.0 - z0 - ), - - Direction.EAST to createCuboidShape( - 16.0 - z1, y0.toDouble(), x0.toDouble(), - 16.0 - z0, y1.toDouble(), x1.toDouble() - ), - - Direction.WEST to createCuboidShape( - z0.toDouble(), y0.toDouble(), 16.0 - x1, - z1.toDouble(), y1.toDouble(), 16.0 - x0 - ) - ) - -/** - * Merges the [shape maps][maps] together. - */ -fun mergeShapeMaps(vararg maps: Map): Map { - fun Map.getShape(direction: Direction) = - getOrElse(direction) { throw IllegalArgumentException("Map is missing shape for $direction!") } - - return EnumMap( - Direction.Type.HORIZONTAL.associateWith { direction -> - maps.map { it.getShape(direction) }.reduce { a, b -> VoxelShapes.union(a, b) }.simplify() - } - ) -} - -/** - * Merges the [shape] into the [shape map][map]. - */ -fun mergeIntoShapeMap(map: Map, shape: VoxelShape): Map = - EnumMap(map.mapValues { (_, it) -> VoxelShapes.union(it, shape) })