diff --git a/build.gradle b/build.gradle index 200165ad..64a45117 100644 --- a/build.gradle +++ b/build.gradle @@ -202,6 +202,9 @@ dependencies { annotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" testAnnotationProcessor "org.spongepowered:mixin:${mixin_version}:processor" + implementation "org.projectlombok:lombok:1.18.34" + annotationProcessor "org.projectlombok:lombok:1.18.34" + // implementation files('libs/Mixed-Arithmetic-Logic-Interpreter-1.0.0.jar') minecraftLibrary ('org.lwjgl:lwjgl-yoga:3.3.1') { diff --git a/src/generated/resources/assets/kasuga_lib/blockstates/test/example_fluid.json b/src/generated/resources/assets/kasuga_lib/blockstates/test/example_fluid.json index f41e09ee..4402d471 100644 --- a/src/generated/resources/assets/kasuga_lib/blockstates/test/example_fluid.json +++ b/src/generated/resources/assets/kasuga_lib/blockstates/test/example_fluid.json @@ -1,20 +1,52 @@ { "variants": { - "level=0": {}, - "level=1": {}, - "level=2": {}, - "level=3": {}, - "level=4": {}, - "level=5": {}, - "level=6": {}, - "level=7": {}, - "level=8": {}, - "level=9": {}, - "level=10": {}, - "level=11": {}, - "level=12": {}, - "level=13": {}, - "level=14": {}, - "level=15": {} + "level=0": { + "model": "minecraft:block/air" + }, + "level=1": { + "model": "minecraft:block/air" + }, + "level=2": { + "model": "minecraft:block/air" + }, + "level=3": { + "model": "minecraft:block/air" + }, + "level=4": { + "model": "minecraft:block/air" + }, + "level=5": { + "model": "minecraft:block/air" + }, + "level=6": { + "model": "minecraft:block/air" + }, + "level=7": { + "model": "minecraft:block/air" + }, + "level=8": { + "model": "minecraft:block/air" + }, + "level=9": { + "model": "minecraft:block/air" + }, + "level=10": { + "model": "minecraft:block/air" + }, + "level=11": { + "model": "minecraft:block/air" + }, + "level=12": { + "model": "minecraft:block/air" + }, + "level=13": { + "model": "minecraft:block/air" + }, + "level=14": { + "model": "minecraft:block/air" + }, + "level=15": { + "model": "minecraft:block/air" + } } } \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/lang/en_us.json b/src/generated/resources/assets/kasuga_lib/lang/en_us.json index 8f3ea331..505de4e3 100644 --- a/src/generated/resources/assets/kasuga_lib/lang/en_us.json +++ b/src/generated/resources/assets/kasuga_lib/lang/en_us.json @@ -1,4 +1,5 @@ { "tips.block": "--------------------------------------=== all blocks ===--------------------------------------", - "block.kasuga_lib.green_apple": "Green Apple" + "block.kasuga_lib.green_apple": "Green Apple", + "item.kasuga_lib.example_fluid_bucket": "Example Fluid Bucket" } \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/lang/zh_cn.json b/src/generated/resources/assets/kasuga_lib/lang/zh_cn.json index 4af27226..5dddf969 100644 --- a/src/generated/resources/assets/kasuga_lib/lang/zh_cn.json +++ b/src/generated/resources/assets/kasuga_lib/lang/zh_cn.json @@ -1,4 +1,5 @@ { "tips.block": "--------------------------------------=== 方块 ===--------------------------------------", - "block.kasuga_lib.green_apple": "绿色林檎" + "block.kasuga_lib.green_apple": "绿色林檎", + "item.kasuga_lib.example_fluid_bucket": "范例液体桶" } \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/models/item/example_fluid_bucket.json b/src/generated/resources/assets/kasuga_lib/models/item/example_fluid_bucket.json new file mode 100644 index 00000000..c3366a36 --- /dev/null +++ b/src/generated/resources/assets/kasuga_lib/models/item/example_fluid_bucket.json @@ -0,0 +1,6 @@ +{ + "parent": "item/generated", + "textures": { + "layer0": "kasuga_lib:item/example_fluid_bucket" + } +} \ No newline at end of file diff --git a/src/generated/resources/assets/kasuga_lib/textures/item/example_fluid_bucket.png b/src/generated/resources/assets/kasuga_lib/textures/item/example_fluid_bucket.png new file mode 100644 index 00000000..c1b15c1f Binary files /dev/null and b/src/generated/resources/assets/kasuga_lib/textures/item/example_fluid_bucket.png differ diff --git a/src/generated/resources/data/forge/tags/fluids/example_fluid.json b/src/generated/resources/data/forge/tags/fluids/example_fluid.json new file mode 100644 index 00000000..f6e36e98 --- /dev/null +++ b/src/generated/resources/data/forge/tags/fluids/example_fluid.json @@ -0,0 +1,6 @@ +{ + "values": [ + "kasuga_lib:example_fluid_still", + "kasuga_lib:example_fluid_flow" + ] +} \ No newline at end of file diff --git a/src/main/java/kasuga/lib/core/base/BucketItem.java b/src/main/java/kasuga/lib/core/base/BucketItem.java new file mode 100644 index 00000000..5b242aa5 --- /dev/null +++ b/src/main/java/kasuga/lib/core/base/BucketItem.java @@ -0,0 +1,169 @@ +package kasuga.lib.core.base; + +import kasuga.lib.core.util.LazyRecomputable; +import net.minecraft.advancements.CriteriaTriggers; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.core.particles.ParticleTypes; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.sounds.SoundSource; +import net.minecraft.stats.Stats; +import net.minecraft.tags.FluidTags; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResultHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.ItemUtils; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.BucketPickup; +import net.minecraft.world.level.block.LiquidBlockContainer; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.gameevent.GameEvent; +import net.minecraft.world.level.material.FlowingFluid; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.material.Material; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.HitResult; +import net.minecraftforge.common.SoundActions; +import net.minecraftforge.event.ForgeEventFactory; +import net.minecraftforge.fluids.FluidStack; +import net.minecraftforge.fluids.FluidUtil; + +import javax.annotation.Nullable; +import java.util.Optional; +import java.util.function.Supplier; + +public class BucketItem extends net.minecraft.world.item.BucketItem { + + private final LazyRecomputable fluidSupplier; + + public BucketItem(Supplier supplier, Properties builder) { + super(supplier, builder); + fluidSupplier = LazyRecomputable.of(supplier::get); + } + + public InteractionResultHolder use(Level pLevel, Player pPlayer, InteractionHand pHand) { + Fluid content = fluidSupplier.get(); + ItemStack itemstack = pPlayer.getItemInHand(pHand); + BlockHitResult blockhitresult = getPlayerPOVHitResult(pLevel, pPlayer, content == Fluids.EMPTY ? net.minecraft.world.level.ClipContext.Fluid.SOURCE_ONLY : net.minecraft.world.level.ClipContext.Fluid.NONE); + InteractionResultHolder ret = ForgeEventFactory.onBucketUse(pPlayer, pLevel, itemstack, blockhitresult); + if (ret != null) { + return ret; + } else if (blockhitresult.getType() == HitResult.Type.MISS) { + return InteractionResultHolder.pass(itemstack); + } else if (blockhitresult.getType() != HitResult.Type.BLOCK) { + return InteractionResultHolder.pass(itemstack); + } else { + BlockPos blockpos = blockhitresult.getBlockPos(); + Direction direction = blockhitresult.getDirection(); + BlockPos blockpos1 = blockpos.relative(direction); + if (pLevel.mayInteract(pPlayer, blockpos) && pPlayer.mayUseItemAt(blockpos1, direction, itemstack)) { + BlockState blockstate1; + if (content == Fluids.EMPTY) { + blockstate1 = pLevel.getBlockState(blockpos); + if (blockstate1.getBlock() instanceof BucketPickup) { + BucketPickup bucketpickup = (BucketPickup)blockstate1.getBlock(); + ItemStack itemstack1 = bucketpickup.pickupBlock(pLevel, blockpos, blockstate1); + if (!itemstack1.isEmpty()) { + pPlayer.awardStat(Stats.ITEM_USED.get(this)); + bucketpickup.getPickupSound(blockstate1).ifPresent((p_150709_) -> { + pPlayer.playSound(p_150709_, 1.0F, 1.0F); + }); + pLevel.gameEvent(pPlayer, GameEvent.FLUID_PICKUP, blockpos); + ItemStack itemstack2 = ItemUtils.createFilledResult(itemstack, pPlayer, itemstack1); + if (!pLevel.isClientSide) { + CriteriaTriggers.FILLED_BUCKET.trigger((ServerPlayer)pPlayer, itemstack1); + } + + return InteractionResultHolder.sidedSuccess(itemstack2, pLevel.isClientSide()); + } + } + + return InteractionResultHolder.fail(itemstack); + } else { + blockstate1 = pLevel.getBlockState(blockpos); + BlockPos blockpos2 = this.canBlockContainFluid(pLevel, blockpos, blockstate1) ? blockpos : blockpos1; + if (this.emptyContents(pPlayer, pLevel, blockpos2, blockhitresult, itemstack)) { + this.checkExtraContent(pPlayer, pLevel, itemstack, blockpos2); + if (pPlayer instanceof ServerPlayer) { + CriteriaTriggers.PLACED_BLOCK.trigger((ServerPlayer)pPlayer, blockpos2, itemstack); + } + + pPlayer.awardStat(Stats.ITEM_USED.get(this)); + return InteractionResultHolder.sidedSuccess(getEmptySuccessItem(itemstack, pPlayer), pLevel.isClientSide()); + } else { + return InteractionResultHolder.fail(itemstack); + } + } + } else { + return InteractionResultHolder.fail(itemstack); + } + } + } + + public boolean emptyContents(@Nullable Player p_150716_, Level p_150717_, BlockPos p_150718_, @Nullable BlockHitResult p_150719_, @Nullable ItemStack container) { + Fluid content = fluidSupplier.get(); + if (!(content instanceof FlowingFluid)) { + return false; + } else { + BlockState blockstate = p_150717_.getBlockState(p_150718_); + Block block = blockstate.getBlock(); + Material material = blockstate.getMaterial(); + boolean flag = blockstate.canBeReplaced(content); + boolean flag1 = blockstate.isAir() || flag || block instanceof LiquidBlockContainer && ((LiquidBlockContainer)block).canPlaceLiquid(p_150717_, p_150718_, blockstate, content); + Optional containedFluidStack = Optional.ofNullable(container).flatMap(FluidUtil::getFluidContained); + if (!flag1) { + return p_150719_ != null && this.emptyContents(p_150716_, p_150717_, p_150719_.getBlockPos().relative(p_150719_.getDirection()), (BlockHitResult)null, container); + } else if (containedFluidStack.isPresent() && content.getFluidType().isVaporizedOnPlacement(p_150717_, p_150718_, (FluidStack)containedFluidStack.get())) { + content.getFluidType().onVaporize(p_150716_, p_150717_, p_150718_, (FluidStack)containedFluidStack.get()); + return true; + } else if (p_150717_.dimensionType().ultraWarm() && content.is(FluidTags.WATER)) { + int i = p_150718_.getX(); + int j = p_150718_.getY(); + int k = p_150718_.getZ(); + p_150717_.playSound(p_150716_, p_150718_, SoundEvents.FIRE_EXTINGUISH, SoundSource.BLOCKS, 0.5F, 2.6F + (p_150717_.random.nextFloat() - p_150717_.random.nextFloat()) * 0.8F); + + for(int l = 0; l < 8; ++l) { + p_150717_.addParticle(ParticleTypes.LARGE_SMOKE, (double)i + Math.random(), (double)j + Math.random(), (double)k + Math.random(), 0.0, 0.0, 0.0); + } + + return true; + } else if (block instanceof LiquidBlockContainer && ((LiquidBlockContainer)block).canPlaceLiquid(p_150717_, p_150718_, blockstate, content)) { + ((LiquidBlockContainer)block).placeLiquid(p_150717_, p_150718_, blockstate, ((FlowingFluid)content).getSource(false)); + this.playEmptySound(p_150716_, p_150717_, p_150718_); + return true; + } else { + if (!p_150717_.isClientSide && flag && !material.isLiquid()) { + p_150717_.destroyBlock(p_150718_, true); + } + + if (!p_150717_.setBlock(p_150718_, content.defaultFluidState().createLegacyBlock(), 11) && !blockstate.getFluidState().isSource()) { + return false; + } else { + this.playEmptySound(p_150716_, p_150717_, p_150718_); + return true; + } + } + } + } + + protected void playEmptySound(@Nullable Player pPlayer, LevelAccessor pLevel, BlockPos pPos) { + Fluid content = fluidSupplier.get(); + SoundEvent soundevent = content.getFluidType().getSound(pPlayer, pLevel, pPos, SoundActions.BUCKET_EMPTY); + if (soundevent == null) { + soundevent = content.is(FluidTags.LAVA) ? SoundEvents.BUCKET_EMPTY_LAVA : SoundEvents.BUCKET_EMPTY; + } + + pLevel.playSound(pPlayer, pPos, soundevent, SoundSource.BLOCKS, 1.0F, 1.0F); + pLevel.gameEvent(pPlayer, GameEvent.FLUID_PLACE, pPos); + } + + protected boolean canBlockContainFluid(Level worldIn, BlockPos posIn, BlockState blockstate) { + return blockstate.getBlock() instanceof LiquidBlockContainer && ((LiquidBlockContainer)blockstate.getBlock()).canPlaceLiquid(worldIn, posIn, blockstate, fluidSupplier.get()); + } +} diff --git a/src/main/java/kasuga/lib/core/client/frontend/dom/nodes/DomNode.java b/src/main/java/kasuga/lib/core/client/frontend/dom/nodes/DomNode.java index 9f27f269..954987bf 100644 --- a/src/main/java/kasuga/lib/core/client/frontend/dom/nodes/DomNode.java +++ b/src/main/java/kasuga/lib/core/client/frontend/dom/nodes/DomNode.java @@ -28,6 +28,13 @@ public DomNode(T context) { this.domContext = context; } + public boolean addChildBefore(DomNode child, DomNode before){ + int index = children.indexOf(before); + if(index == -1) + return false; + return addChildAt(index,child); + } + public boolean addChildAt(int i, DomNode child){ if(child.parent != null) return false; diff --git a/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java b/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java index c898b764..0aa6f130 100644 --- a/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java +++ b/src/main/java/kasuga/lib/core/client/frontend/gui/nodes/GuiDomNode.java @@ -69,18 +69,34 @@ public LayoutContext getLayoutManager() { protected BackgroundRenderer background = new BackgroundRenderer(); + @HostAccess.Export + @Override + public boolean addChildBefore(DomNode child, DomNode before) { + this.domContext.queueDuringRender(()->{ + int index = children.indexOf(before); + if(index == -1) + return; + addChildInstant(index, child); + }); + return true; + } + @HostAccess.Export @Override public boolean addChildAt(int i, DomNode child) { this.domContext.queueDuringRender(()->{ - if(child instanceof GuiDomNode domNode) - getLayoutManager().addChild(i,domNode.getLayoutManager()); - styles.notifyUpdate(); - super.addChildAt(i,child); + addChildInstant(i, child); }); return true; } + protected void addChildInstant(int i, DomNode child){ + if(child instanceof GuiDomNode domNode) + getLayoutManager().addChild(i,domNode.getLayoutManager()); + styles.notifyUpdate(); + super.addChildAt(i,child); + } + @HostAccess.Export @Override public boolean removeChild(DomNode child) { diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/AllConversionPairs.java b/src/main/java/kasuga/lib/core/util/nbt_json/AllConversionPairs.java new file mode 100644 index 00000000..19050195 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/AllConversionPairs.java @@ -0,0 +1,31 @@ +package kasuga.lib.core.util.nbt_json; + +import com.google.gson.JsonElement; +import kasuga.lib.core.util.nbt_json.collection.ByteArrayPair; +import kasuga.lib.core.util.nbt_json.collection.IntArrayPair; +import kasuga.lib.core.util.nbt_json.collection.LongArrayPair; +import kasuga.lib.core.util.nbt_json.primitive.BooleanPair; +import kasuga.lib.core.util.nbt_json.primitive.StringPair; +import kasuga.lib.core.util.nbt_json.primitive.numeric.*; +import net.minecraft.nbt.*; + +public class AllConversionPairs { + + public static final BooleanPair BOOLEAN_PAIR = new BooleanPair(); + public static final StringPair STRING_PAIR = new StringPair(); + public static final BytePair BYTE_PAIR = new BytePair(); + public static final DoublePair DOUBLE_PAIR = new DoublePair(); + public static final FloatPair FLOAT_PAIR = new FloatPair(); + public static final IntPair INT_PAIR = new IntPair(); + public static final LongPair LONG_PAIR = new LongPair(); + public static final ShortPair SHORT_PAIR = new ShortPair(); + public static final ByteArrayPair BYTE_ARRAY_PAIR = new ByteArrayPair(); + public static final IntArrayPair INT_ARRAY_PAIR = new IntArrayPair(); + public static final LongArrayPair LONG_ARRAY_PAIR = new LongArrayPair(); + + public static final Converter CONVERTER = new Converter(); + + static { + CONVERTER.addDefaultConversions(); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/CompoundPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/CompoundPair.java new file mode 100644 index 00000000..6465b1f1 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/CompoundPair.java @@ -0,0 +1,41 @@ +package kasuga.lib.core.util.nbt_json; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import lombok.Getter; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +@Getter +public class CompoundPair extends ConversionPair { + + public final Converter converter; + + public CompoundPair(Converter converter) { + super("compound", CompoundTag.class, JsonObject.class); + this.converter = converter; + } + + @Override + public JsonObject convert(@NotNull CompoundTag nbt, String path) throws NoAvailableConversionException { + JsonObject object = new JsonObject(); + for (String key : nbt.getAllKeys()) { + Tag tag = nbt.get(key); + object.add(key, (JsonElement) converter.innerConvert(tag, path + "." + key)); + } + return object; + } + + @Override + public CompoundTag convert(@NotNull JsonObject json, String path) throws NoAvailableConversionException { + CompoundTag nbt = new CompoundTag(); + for (Map.Entry entry : json.entrySet()) { + nbt.put(entry.getKey(), (Tag) converter.innerConvert(entry.getValue(), + path + "." + entry.getKey())); + } + return nbt; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/ConversionPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/ConversionPair.java new file mode 100644 index 00000000..05d197ae --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/ConversionPair.java @@ -0,0 +1,32 @@ +package kasuga.lib.core.util.nbt_json; + +import com.google.gson.JsonElement; +import lombok.Getter; +import net.minecraft.nbt.Tag; +import org.checkerframework.checker.nullness.qual.NonNull; + +@Getter +public abstract class ConversionPair { + + public final Class tagClazz; + public final Class jsonClazz; + public final String identifier; + + public ConversionPair(String identifier, Class tagClazz, Class jsonClazz) { + this.tagClazz = tagClazz; + this.jsonClazz = jsonClazz; + this.identifier = identifier; + } + + public boolean match(Tag tag) { + return tagClazz.isInstance(tag); + } + + public boolean match(JsonElement element) { + return jsonClazz.isInstance(element); + } + + public abstract K convert(@NonNull T nbt, String path) throws NoAvailableConversionException; + + public abstract T convert(@NonNull K json, String path) throws NoAvailableConversionException; +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/Converter.java b/src/main/java/kasuga/lib/core/util/nbt_json/Converter.java new file mode 100644 index 00000000..e04a1f79 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/Converter.java @@ -0,0 +1,205 @@ +package kasuga.lib.core.util.nbt_json; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonPrimitive; +import kasuga.lib.KasugaLib; +import lombok.Getter; +import lombok.Setter; +import net.minecraft.nbt.*; +import org.checkerframework.checker.nullness.qual.NonNull; + +import javax.annotation.Nullable; +import java.util.HashMap; +import java.util.Map; + +import static kasuga.lib.core.util.nbt_json.AllConversionPairs.*; + +@Getter +public class Converter { + + private final HashMap pairs; + + @Setter + private ConverterSelector globalSelector; + + private final HashMap pathSelectors; + + private final HashMap selectors; + + public Converter() { + pairs = new HashMap<>(); + selectors = new HashMap<>(); + pathSelectors = new HashMap<>(); + } + + public Converter(final ConversionPair... pairs) { + this(); + for (ConversionPair pair : pairs) this.pairs.put(pair.identifier, pair); + } + + public void addDefaultConversions() { + this.addConversion(BOOLEAN_PAIR); + this.addConversion(STRING_PAIR); + this.addConversion(BYTE_PAIR); + this.addConversion(DOUBLE_PAIR); + this.addConversion(FLOAT_PAIR); + this.addConversion(INT_PAIR); + this.addConversion(LONG_PAIR); + this.addConversion(SHORT_PAIR); + this.addConversion(BYTE_ARRAY_PAIR); + this.addConversion(INT_ARRAY_PAIR); + this.addConversion(LONG_ARRAY_PAIR); + this.addConversion(new CompoundPair(this)); + } + + public void markAs(String path, String identifier) { + pathSelectors.put(path, (a, b, c, d, e) -> pairs.get(identifier)); + } + + public void addConversion(final ConversionPair pair) { + this.pairs.put(pair.identifier, pair); + } + + public void addSelector(final ConversionPair pair, final ConverterSelector selector) { + selectors.put(pair, selector); + } + + public void addPathSelector(final String path, final ConverterSelector selector) { + pathSelectors.put(path, selector); + } + + public ConversionPair getPair(final String identifier) { + return pairs.getOrDefault(identifier, null); + } + + public ConverterSelector getSelector(final ConversionPair pair) { + return selectors.getOrDefault(pair, null); + } + + public boolean hasGlobalSelector() { + return globalSelector != null; + } + + public @NonNull JsonElement convert(@NonNull Tag tag) throws NoAvailableConversionException { + return (JsonElement) innerConvert(tag, "root"); + } + + public @NonNull Tag convert(@NonNull JsonElement element) throws NoAvailableConversionException { + return (Tag) innerConvert(element, "root"); + } + + public @NonNull JsonElement safeConvert(@NonNull Tag tag) { + return (JsonElement) safeInnerConvert(tag, "root"); + } + + public @NonNull Tag safeConvert(@NonNull JsonElement element) { + return (Tag) safeInnerConvert(element, "root"); + } + + protected @NonNull Object safeInnerConvert(Object input, String path) { + try { + return innerConvert(input, path); + } catch (NoAvailableConversionException e) { + KasugaLib.MAIN_LOGGER.debug("Error in nbt convert: ", e); + if (input instanceof Tag) return new JsonObject(); + return new CompoundTag(); + } + } + + @SuppressWarnings("unchecked") + protected @NonNull Object innerConvert(Object input, String path) throws NoAvailableConversionException { + boolean flag = input instanceof Tag; + Direction direction = flag ? Direction.NBT_TO_JSON : Direction.JSON_TO_NBT; + Tag tag = flag ? (Tag) input: null; + JsonElement element = !flag ? (JsonElement) input : null; + + ConversionPair pair = null; + for (Map.Entry entry : pathSelectors.entrySet()) { + if (entry.getKey().equals(path)) { + ConversionPair cache = entry.getValue().select(this, tag, element, path, direction); + if (flag ? cache.match(tag) : cache.match(element)) { + pair = cache; + break; + } + } + } + + if (pair == null) { + for (Map.Entry entry : selectors.entrySet()) { + if (entry.getKey().match(tag)) { + pair = entry.getValue().select(this, tag, element, path, direction); + break; + } + } + } + + if (globalSelector != null && pair == null) { + pair = globalSelector.select(this, tag, element, path, direction); + } + + if (pair == null) { + if (flag || !(element.isJsonPrimitive() || element.isJsonArray())) { + for (Map.Entry entry : pairs.entrySet()) { + if (flag ? entry.getValue().match(tag) : entry.getValue().match(element)) { + pair = entry.getValue(); + break; + } + } + } else { + if (element.isJsonPrimitive()) { + if (getPair("str").match(element)) + pair = getPair("str"); + else if (getPair("bool").match(element)) + pair = getPair("bool"); + else if (getPair("int").match(element)) + pair = getPair("int"); + else if (getPair("short").match(element)) + pair = getPair("short"); + else if (getPair("long").match(element)) + pair = getPair("long"); + else if (getPair("float").match(element)) + pair = getPair("float"); + else if (getPair("double").match(element)) + pair = getPair("double"); + } else { + JsonArray array = new JsonArray(); + if (array.isEmpty()) { + return new ListTag(); + } + JsonElement element1 = array.get(0); + if (element1.isJsonPrimitive()) { + JsonPrimitive primitive = element1.getAsJsonPrimitive(); + if (getPair("int").match(primitive)) + pair = getPair("int_array"); + else if (getPair("long").match(primitive)) + pair = getPair("long_array"); + else if (getPair("byte").match(primitive)) + pair = getPair("byte_array"); + } else { + ListTag listTag = new ListTag(); + for (JsonElement inner : array) { + listTag.add((Tag) innerConvert(inner, path)); + } + return listTag; + } + } + } + } + + if (pair == null) throw new NoAvailableConversionException(tag.getClass(), path); + return flag ? pair.convert(tag, path) : pair.convert(element, path); + } + + public interface ConverterSelector { + + ConversionPair select(Converter self, @Nullable Tag nbt, + @Nullable JsonElement json, String path, Direction direction); + } + + public enum Direction { + JSON_TO_NBT, + NBT_TO_JSON; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/ListIsEmptyException.java b/src/main/java/kasuga/lib/core/util/nbt_json/ListIsEmptyException.java new file mode 100644 index 00000000..8d66a77e --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/ListIsEmptyException.java @@ -0,0 +1,20 @@ +package kasuga.lib.core.util.nbt_json; + +import net.minecraft.nbt.Tag; + +public class ListIsEmptyException extends Exception { + + public final String path; + + public final Tag tag; + + public ListIsEmptyException(Tag tag, String path) { + this.tag = tag; + this.path = path; + } + + @Override + public String getMessage() { + return "Lists in template NBT should not be empty! Found empty list at nbt path: " + path; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/NoAvailableConversionException.java b/src/main/java/kasuga/lib/core/util/nbt_json/NoAvailableConversionException.java new file mode 100644 index 00000000..d454d28e --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/NoAvailableConversionException.java @@ -0,0 +1,20 @@ +package kasuga.lib.core.util.nbt_json; + +import net.minecraft.nbt.Tag; + +public class NoAvailableConversionException extends Exception { + + public final String path; + public final Class clazz; + + public NoAvailableConversionException(Class clazz, String path) { + super(); + this.clazz = clazz; + this.path = path; + } + + @Override + public String getMessage() { + return "No available conversion pair for " + clazz.getName() + " at " + path; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/TemplateConverter.java b/src/main/java/kasuga/lib/core/util/nbt_json/TemplateConverter.java new file mode 100644 index 00000000..ab9f0691 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/TemplateConverter.java @@ -0,0 +1,106 @@ +package kasuga.lib.core.util.nbt_json; + +import kasuga.lib.core.util.nbt_json.collection.ListPair; +import lombok.Getter; +import net.minecraft.nbt.*; + +import java.io.IOException; +import java.util.HashSet; +import java.util.List; + +@Getter +public class TemplateConverter extends Converter { + + private final Tag template; + + private final HashSet boolTags; + + public TemplateConverter(Tag template) { + this.template = template; + boolTags = new HashSet<>(); + } + + public void markAsBoolTag(String... path) { + boolTags.addAll(List.of(path)); + } + + public boolean isMarkedAsBoolTag(String path) { + return boolTags.contains(path); + } + + public void compile() throws ListIsEmptyException, NoAvailableConversionException { + updateSelector(template, "root"); + } + + public boolean safeCompile() { + return safeUpdateSelector(template, "root"); + } + + private void updateSelector(Tag tag, String path) + throws ListIsEmptyException, NoAvailableConversionException { + if (tag instanceof CompoundTag) { + updateCompoundSelector((CompoundTag) tag, path); + return; + } + ConversionPair pair = getPair(tag, path); + addPathSelector(path, (self, nbt, json, path1, direction) -> pair); + } + + private boolean safeUpdateSelector(Tag tag, String path) { + try { + updateSelector(tag, path); + return true; + } catch (Exception e) { + e.printStackTrace(); + // Kuayue.LOGGER.debug("Failed to update nbt template selector", e); + return false; + } + } + + private void updateCompoundSelector(CompoundTag nbt, String path) + throws ListIsEmptyException, NoAvailableConversionException { + for (String key : nbt.getAllKeys()) { + updateSelector(nbt.get(key), path + "." + key); + } + } + + private ConversionPair getPair(Tag tag, String path) + throws ListIsEmptyException, NoAvailableConversionException { + ConversionPair result = null; + result = getPrimitivePair(tag, path); + if (result != null) return result; + result = getCollectionPair(tag, path); + if (result != null) return result; + throw new NoAvailableConversionException(tag.getClass(), path); + } + + private ConversionPair getPrimitivePair(Tag tag, String path) { + if (tag instanceof StringTag) {return getPair("str");} + if (tag instanceof IntTag) {return getPair("int");} + if (tag instanceof LongTag) {return getPair("long");} + if (tag instanceof DoubleTag) {return getPair("double");} + if (tag instanceof FloatTag) {return getPair("float");} + if (tag instanceof ShortTag) {return getPair("short");} + if (tag instanceof ByteTag) { + if (isMarkedAsBoolTag(path)) return getPair("bool"); + return getPair("byte"); + } + return null; + } + + private ConversionPair getCollectionPair(Tag tag, String path) + throws ListIsEmptyException, NoAvailableConversionException { + if (tag instanceof IntArrayTag) {return getPair("int_array");} + if (tag instanceof LongArrayTag) {return getPair("long_array");} + if (tag instanceof ByteArrayTag) {return getPair("byte_array");} + if (tag instanceof ListTag lTag) { + if (lTag.isEmpty()) { + throw new ListIsEmptyException(tag, path); + } + Tag t = lTag.get(0); + ConversionPair pair = getPair(t, path); + return new ListPair(pair); + } + return null; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/collection/ByteArrayPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/collection/ByteArrayPair.java new file mode 100644 index 00000000..fc757385 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/collection/ByteArrayPair.java @@ -0,0 +1,30 @@ +package kasuga.lib.core.util.nbt_json.collection; + +import com.google.gson.JsonArray; +import net.minecraft.nbt.ByteArrayTag; +import net.minecraft.nbt.ByteTag; +import org.jetbrains.annotations.NotNull; + +public class ByteArrayPair extends CollectionPair { + + + public ByteArrayPair() { + super("byte_array", ByteArrayTag.class, ByteTag.class); + } + + @Override + public JsonArray convert(@NotNull ByteArrayTag nbt, String path) { + JsonArray array = new JsonArray(); + nbt.forEach(content -> array.add(content.getAsByte())); + return array; + } + + @Override + public ByteArrayTag convert(@NotNull JsonArray json, String path) { + byte[] result = new byte[json.size()]; + for (int i = 0; i < json.size(); i++) { + result[i] = json.get(i).getAsByte(); + } + return new ByteArrayTag(result); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/collection/CollectionPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/collection/CollectionPair.java new file mode 100644 index 00000000..32ae132d --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/collection/CollectionPair.java @@ -0,0 +1,20 @@ +package kasuga.lib.core.util.nbt_json.collection; + +import com.google.gson.JsonArray; +import kasuga.lib.core.util.nbt_json.ConversionPair; +import lombok.Getter; +import net.minecraft.nbt.CollectionTag; +import net.minecraft.nbt.Tag; + +import java.util.Collection; + +@Getter +public abstract class CollectionPair> extends ConversionPair { + + public final Class contentClazz; + + public CollectionPair(String identifier, Class tagClazz, Class contentClazz) { + super(identifier, tagClazz, JsonArray.class); + this.contentClazz = contentClazz; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/collection/IntArrayPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/collection/IntArrayPair.java new file mode 100644 index 00000000..91ea7513 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/collection/IntArrayPair.java @@ -0,0 +1,29 @@ +package kasuga.lib.core.util.nbt_json.collection; + +import com.google.gson.JsonArray; +import net.minecraft.nbt.IntArrayTag; +import net.minecraft.nbt.IntTag; +import org.jetbrains.annotations.NotNull; + +public class IntArrayPair extends CollectionPair { + + public IntArrayPair() { + super("int_array", IntArrayTag.class, IntTag.class); + } + + @Override + public JsonArray convert(@NotNull IntArrayTag nbt, String path) { + JsonArray array = new JsonArray(); + nbt.forEach(content -> array.add(content.getAsInt())); + return array; + } + + @Override + public IntArrayTag convert(@NotNull JsonArray json, String path) { + int[] result = new int[json.size()]; + for (int i = 0; i < result.length; i++) { + result[i] = json.get(i).getAsInt(); + } + return new IntArrayTag(result); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/collection/ListPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/collection/ListPair.java new file mode 100644 index 00000000..0a43480f --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/collection/ListPair.java @@ -0,0 +1,60 @@ +package kasuga.lib.core.util.nbt_json.collection; + +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import kasuga.lib.core.util.nbt_json.ConversionPair; +import kasuga.lib.core.util.nbt_json.NoAvailableConversionException; +import lombok.Getter; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.Tag; +import org.jetbrains.annotations.NotNull; + +@Getter +public class ListPair extends CollectionPair { + + private final ConversionPair pair; + + public ListPair(ConversionPair pair) { + super("list", ListTag.class, Tag.class); + this.pair = pair; + } + + @Override + public boolean match(Tag tag) { + if (!super.match(tag)) return false; + ListTag list = (ListTag) tag; + for (Tag t : list) { + if (!pair.match(t)) return false; + } + return true; + } + + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + JsonArray array = element.getAsJsonArray(); + for (JsonElement e : array) { + if (!pair.match(e)) return false; + } + return true; + } + + @Override + @SuppressWarnings(value = "unchecked") + public JsonArray convert(@NotNull ListTag nbt, String path) throws NoAvailableConversionException { + JsonArray array = new JsonArray(); + for (Tag content : nbt) { + array.add(pair.convert(content, path)); + } + return array; + } + + @Override + @SuppressWarnings(value = "unchecked") + public ListTag convert(@NotNull JsonArray json, String path) throws NoAvailableConversionException { + ListTag listTag = new ListTag(); + for (JsonElement e : json) { + listTag.add(pair.convert(e, path)); + } + return listTag; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/collection/LongArrayPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/collection/LongArrayPair.java new file mode 100644 index 00000000..853826a8 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/collection/LongArrayPair.java @@ -0,0 +1,29 @@ +package kasuga.lib.core.util.nbt_json.collection; + +import com.google.gson.JsonArray; +import net.minecraft.nbt.LongArrayTag; +import net.minecraft.nbt.LongTag; +import net.minecraft.nbt.ShortTag; +import org.jetbrains.annotations.NotNull; + +public class LongArrayPair extends CollectionPair { + + public LongArrayPair() { + super("long_array", LongArrayTag.class, LongTag.class); + } + + @Override + public JsonArray convert(@NotNull LongArrayTag nbt, String path) { + JsonArray array = new JsonArray(); + nbt.forEach(content -> array.add(content.getAsLong())); + return array; + } + + @Override + public LongArrayTag convert(@NotNull JsonArray json, String path) { + long[] array = new long[json.size()]; + for (int i = 0; i < array.length; ++i) + array[i] = json.get(i).getAsLong(); + return new LongArrayTag(array); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/BooleanPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/BooleanPair.java new file mode 100644 index 00000000..95df368c --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/BooleanPair.java @@ -0,0 +1,30 @@ +package kasuga.lib.core.util.nbt_json.primitive; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.ByteTag; +import org.jetbrains.annotations.NotNull; + +public class BooleanPair extends PrimitivePair { + + public BooleanPair() { + super("bool", ByteTag.class, Boolean.class); + } + + @Override + public boolean match(JsonElement element) { + if(!super.match(element)) return false; + JsonPrimitive primitive = element.getAsJsonPrimitive(); + return primitive.isBoolean(); + } + + @Override + public JsonPrimitive convert(@NotNull ByteTag nbt, String path) { + return new JsonPrimitive(nbt.getAsByte() != 0); + } + + @Override + public ByteTag convert(@NotNull JsonPrimitive json, String path) { + return ByteTag.valueOf(json.getAsBoolean()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/PrimitivePair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/PrimitivePair.java new file mode 100644 index 00000000..5a925eb4 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/PrimitivePair.java @@ -0,0 +1,17 @@ +package kasuga.lib.core.util.nbt_json.primitive; + +import com.google.gson.JsonPrimitive; +import kasuga.lib.core.util.nbt_json.ConversionPair; +import lombok.Getter; +import net.minecraft.nbt.Tag; + +@Getter +public abstract class PrimitivePair extends ConversionPair { + + public final Class primitiveType; + + public PrimitivePair(String identifier, Class tagClazz, Class primitiveClazz) { + super(identifier, tagClazz, JsonPrimitive.class); + this.primitiveType = primitiveClazz; + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/StringPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/StringPair.java new file mode 100644 index 00000000..ab861edd --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/StringPair.java @@ -0,0 +1,31 @@ +package kasuga.lib.core.util.nbt_json.primitive; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.StringTag; +import net.minecraft.nbt.Tag; +import org.jetbrains.annotations.NotNull; + +public class StringPair extends PrimitivePair { + + public StringPair() { + super("str", StringTag.class, String.class); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + JsonPrimitive primitive = element.getAsJsonPrimitive(); + return primitive.isString(); + } + + @Override + public JsonPrimitive convert(@NotNull StringTag nbt, String path) { + return new JsonPrimitive(nbt.toString()); + } + + @Override + public StringTag convert(@NotNull JsonPrimitive json, String path) { + return StringTag.valueOf(json.getAsString()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/BytePair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/BytePair.java new file mode 100644 index 00000000..0a722067 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/BytePair.java @@ -0,0 +1,33 @@ +package kasuga.lib.core.util.nbt_json.primitive.numeric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.ByteTag; +import org.jetbrains.annotations.NotNull; + +public class BytePair extends NumericPair { + + public BytePair() { + super("byte", ByteTag.class, Byte.class); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + String str = element.getAsString(); + Number number = element.getAsNumber(); + return !str.contains(".") && + number.shortValue() > -129 && + number.shortValue() < 128; + } + + @Override + public JsonPrimitive convert(@NotNull ByteTag nbt, String path) { + return new JsonPrimitive(nbt.getAsByte()); + } + + @Override + public ByteTag convert(@NotNull JsonPrimitive json, String path) { + return ByteTag.valueOf(json.getAsByte()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/DoublePair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/DoublePair.java new file mode 100644 index 00000000..11ce939b --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/DoublePair.java @@ -0,0 +1,30 @@ +package kasuga.lib.core.util.nbt_json.primitive.numeric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.DoubleTag; +import net.minecraft.nbt.Tag; +import org.jetbrains.annotations.NotNull; + +public class DoublePair extends NumericPair { + public DoublePair() { + super("double", DoubleTag.class, Double.class); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + String str = element.getAsString(); + return str.contains("."); + } + + @Override + public JsonPrimitive convert(@NotNull DoubleTag nbt, String path) { + return new JsonPrimitive(nbt.getAsDouble()); + } + + @Override + public DoubleTag convert(@NotNull JsonPrimitive json, String path) { + return DoubleTag.valueOf(json.getAsDouble()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/FloatPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/FloatPair.java new file mode 100644 index 00000000..db8af58e --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/FloatPair.java @@ -0,0 +1,30 @@ +package kasuga.lib.core.util.nbt_json.primitive.numeric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.FloatTag; +import org.jetbrains.annotations.NotNull; + +public class FloatPair extends NumericPair { + + public FloatPair() { + super("float", FloatTag.class, Float.class); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + String str = element.getAsString(); + return str.contains("."); + } + + @Override + public JsonPrimitive convert(@NotNull FloatTag nbt, String path) { + return new JsonPrimitive(nbt.getAsFloat()); + } + + @Override + public FloatTag convert(@NotNull JsonPrimitive json, String path) { + return FloatTag.valueOf(json.getAsFloat()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/IntPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/IntPair.java new file mode 100644 index 00000000..0bbdd0ea --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/IntPair.java @@ -0,0 +1,31 @@ +package kasuga.lib.core.util.nbt_json.primitive.numeric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.IntTag; +import org.jetbrains.annotations.NotNull; + +public class IntPair extends NumericPair { + + public IntPair() { + super("int", IntTag.class, Integer.class); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + String str = element.getAsString(); + Number number = element.getAsNumber(); + return !str.contains(".") && number.longValue() == number.intValue(); + } + + @Override + public JsonPrimitive convert(@NotNull IntTag nbt, String path) { + return new JsonPrimitive(nbt.getAsInt()); + } + + @Override + public IntTag convert(@NotNull JsonPrimitive json, String path) { + return IntTag.valueOf(json.getAsInt()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/LongPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/LongPair.java new file mode 100644 index 00000000..3f8f66ec --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/LongPair.java @@ -0,0 +1,31 @@ +package kasuga.lib.core.util.nbt_json.primitive.numeric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.LongTag; +import org.jetbrains.annotations.NotNull; + +public class LongPair extends NumericPair { + + public LongPair() { + super("long", LongTag.class, Long.class); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + String str = element.getAsString(); + Number number = element.getAsNumber(); + return !str.contains(".") && number.longValue() != number.intValue(); + } + + @Override + public JsonPrimitive convert(@NotNull LongTag nbt, String path) { + return new JsonPrimitive(nbt.getAsLong()); + } + + @Override + public LongTag convert(@NotNull JsonPrimitive json, String path) { + return LongTag.valueOf(json.getAsLong()); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/NumericPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/NumericPair.java new file mode 100644 index 00000000..727553e4 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/NumericPair.java @@ -0,0 +1,20 @@ +package kasuga.lib.core.util.nbt_json.primitive.numeric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import kasuga.lib.core.util.nbt_json.primitive.PrimitivePair; +import net.minecraft.nbt.NumericTag; + +public abstract class NumericPair extends PrimitivePair { + + public NumericPair(String identifier, Class tagClazz, Class primitiveClazz) { + super(identifier, tagClazz, primitiveClazz); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + JsonPrimitive primitive = element.getAsJsonPrimitive(); + return primitive.isNumber(); + } +} diff --git a/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/ShortPair.java b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/ShortPair.java new file mode 100644 index 00000000..2c3e7382 --- /dev/null +++ b/src/main/java/kasuga/lib/core/util/nbt_json/primitive/numeric/ShortPair.java @@ -0,0 +1,33 @@ +package kasuga.lib.core.util.nbt_json.primitive.numeric; + +import com.google.gson.JsonElement; +import com.google.gson.JsonPrimitive; +import net.minecraft.nbt.ShortTag; +import org.jetbrains.annotations.NotNull; + +public class ShortPair extends NumericPair { + + public ShortPair() { + super("short", ShortTag.class, Short.class); + } + + @Override + public boolean match(JsonElement element) { + if (!super.match(element)) return false; + String str = element.getAsString(); + Number number = element.getAsNumber(); + return !str.contains(".") && + number.intValue() < 32768 && + number.intValue() > -32769; + } + + @Override + public JsonPrimitive convert(@NotNull ShortTag nbt, String path) { + return new JsonPrimitive(nbt.getAsShort()); + } + + @Override + public ShortTag convert(@NotNull JsonPrimitive json, String path) { + return ShortTag.valueOf(json.getAsShort()); + } +} diff --git a/src/main/java/kasuga/lib/example_env/AllExampleElements.java b/src/main/java/kasuga/lib/example_env/AllExampleElements.java index 26300c86..30debf1e 100644 --- a/src/main/java/kasuga/lib/example_env/AllExampleElements.java +++ b/src/main/java/kasuga/lib/example_env/AllExampleElements.java @@ -1,11 +1,14 @@ package kasuga.lib.example_env; import kasuga.lib.KasugaLib; +import kasuga.lib.core.base.BucketItem; import kasuga.lib.core.menu.base.GuiBinding; import kasuga.lib.core.menu.base.GuiMenu; import kasuga.lib.core.menu.base.GuiMenuRegistry; import kasuga.lib.core.menu.base.GuiMenuType; import kasuga.lib.core.util.Envs; +import kasuga.lib.example_env.block.fluid.ExampleFluid; +import kasuga.lib.example_env.block.fluid.ExampleFluidBlock; import kasuga.lib.example_env.block.green_apple.GreenAppleBlock; import kasuga.lib.example_env.block.green_apple.GreenAppleItem; import kasuga.lib.example_env.block.green_apple.GreenAppleTile; @@ -117,16 +120,16 @@ public class AllExampleElements { */ - /* + public static final FluidReg exampleFluid = new FluidReg("example_fluid") .still(ExampleFluid::new, "block/fluid/water_still") - .flow(ExampleFluid::new, "block/fluid/water_flow") + .flow(ExampleFluid.Flowing::new, "block/fluid/water_flow") + .numericProperties(1, 8, 3, 10) .overlayTexPath("block/fluid/water_overlay") .bucketItem(BucketItem::new) .blockType(ExampleFluidBlock::new) - .submit(testRegistry); - - */ + .tab(tab) + .submit(REGISTRY); public static final MenuReg apple = new MenuReg("green_apple_screen") diff --git a/src/main/java/kasuga/lib/example_env/block/fluid/ExampleFluid.java b/src/main/java/kasuga/lib/example_env/block/fluid/ExampleFluid.java new file mode 100644 index 00000000..a7f5c925 --- /dev/null +++ b/src/main/java/kasuga/lib/example_env/block/fluid/ExampleFluid.java @@ -0,0 +1,48 @@ +package kasuga.lib.example_env.block.fluid; + +import kasuga.lib.registrations.common.FluidReg; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.material.FlowingFluid; +import net.minecraft.world.level.material.Fluid; +import net.minecraft.world.level.material.FluidState; +import net.minecraftforge.common.extensions.IForgeFluid; +import net.minecraftforge.fluids.FluidType; +import net.minecraftforge.fluids.ForgeFlowingFluid; +import net.minecraftforge.registries.RegistryObject; +import org.jetbrains.annotations.NotNull; + +public class ExampleFluid extends ForgeFlowingFluid { + + + public ExampleFluid(Properties properties) { + super(properties); + } + + @Override + protected void createFluidStateDefinition(StateDefinition.Builder pBuilder) { + super.createFluidStateDefinition(pBuilder.add(LEVEL)); + } + + @Override + public boolean isSource(FluidState fluidState) { + return true; + } + + @Override + public int getAmount(@NotNull FluidState fluidState) { + return isSource(fluidState) ? 8 : (Integer) fluidState.getValue(LEVEL); + } + + public static class Flowing extends ExampleFluid { + + public Flowing(Properties properties) { + super(properties); + } + + @Override + public boolean isSource(FluidState fluidState) { + return false; + } + } +} diff --git a/src/main/java/kasuga/lib/example_env/block/fluid/ExampleFluidBlock.java b/src/main/java/kasuga/lib/example_env/block/fluid/ExampleFluidBlock.java new file mode 100644 index 00000000..c69b0113 --- /dev/null +++ b/src/main/java/kasuga/lib/example_env/block/fluid/ExampleFluidBlock.java @@ -0,0 +1,26 @@ +package kasuga.lib.example_env.block.fluid; + +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.LiquidBlock; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.material.FlowingFluid; +import net.minecraftforge.fluids.ForgeFlowingFluid; +import net.minecraftforge.fluids.IFluidBlock; +import org.jetbrains.annotations.Nullable; + +import java.util.function.Supplier; + +public class ExampleFluidBlock extends LiquidBlock { + + public ExampleFluidBlock(Supplier supplier, Properties properties) { + super(supplier, properties); + } + + @Override + public @Nullable BlockState getStateForPlacement(BlockPlaceContext pContext) { + return super.getStateForPlacement(pContext).setValue(LEVEL, 8); + } +} diff --git a/src/main/java/kasuga/lib/registrations/TagReg.java b/src/main/java/kasuga/lib/registrations/TagReg.java index 3ce8b444..d0782e8c 100644 --- a/src/main/java/kasuga/lib/registrations/TagReg.java +++ b/src/main/java/kasuga/lib/registrations/TagReg.java @@ -13,9 +13,22 @@ public abstract class TagReg extends Reg { public ResourceLocation location = null; - public TagReg(String registrationKey) { + + public final String otherNamespace; + public final String path; + + public TagReg(String registrationKey, String path) { + super(registrationKey); + otherNamespace = null; + this.path = path; + } + + public TagReg(String namespace, String registrationKey, String path) { super(registrationKey); + otherNamespace = namespace; + this.path = path; } + public abstract TagKey tag(); /** diff --git a/src/main/java/kasuga/lib/registrations/common/BlockTagReg.java b/src/main/java/kasuga/lib/registrations/common/BlockTagReg.java index 64ff7e90..41e31154 100644 --- a/src/main/java/kasuga/lib/registrations/common/BlockTagReg.java +++ b/src/main/java/kasuga/lib/registrations/common/BlockTagReg.java @@ -15,7 +15,6 @@ */ public class BlockTagReg extends TagReg { TagKey tag = null; - private final String path; /** * Use this to create a new block tag registration. @@ -23,14 +22,19 @@ public class BlockTagReg extends TagReg { * @param path the path of your tag file. Root folder is namespace:tag (It's usually under the "resource/data" folder) */ public BlockTagReg(String registrationKey, String path) { - super(registrationKey); - this.path = path; + super(registrationKey, path); + } + + public BlockTagReg(String namespace, String registrationKey, String path) { + super(namespace ,registrationKey, path); } @Override @Mandatory public BlockTagReg submit(SimpleRegistry registry) { - location = new ResourceLocation(registry.namespace, path); + location = otherNamespace == null ? + new ResourceLocation(registry.namespace, path) : + new ResourceLocation(otherNamespace, path); tag = BlockTags.create(location); return this; } diff --git a/src/main/java/kasuga/lib/registrations/common/BucketItemReg.java b/src/main/java/kasuga/lib/registrations/common/BucketItemReg.java index b9e076b5..4c57a6cc 100644 --- a/src/main/java/kasuga/lib/registrations/common/BucketItemReg.java +++ b/src/main/java/kasuga/lib/registrations/common/BucketItemReg.java @@ -113,7 +113,7 @@ public BucketItemReg fluidType(Supplier fluid) { * @return self. */ @Mandatory - public BucketItemReg itemType(BucketBuilder builder) { + public BucketItemReg itemType(BucketBuilder builder) { this.builder = (BucketBuilder) builder; return this; } diff --git a/src/main/java/kasuga/lib/registrations/common/CommandReg.java b/src/main/java/kasuga/lib/registrations/common/CommandReg.java index 84547d38..e42155c2 100644 --- a/src/main/java/kasuga/lib/registrations/common/CommandReg.java +++ b/src/main/java/kasuga/lib/registrations/common/CommandReg.java @@ -56,7 +56,7 @@ public CommandReg(String registrationKey) { * @return The Reg itself */ public CommandReg addLiteral(String string, boolean isOptional) { - System.out.println(tree.leaves.size()); + // System.out.println(tree.leaves.size()); tree.addLiteral(isOptional, string); if(this.optionalStartFlag && !isOptional){ throw new IllegalArgumentException(); diff --git a/src/main/java/kasuga/lib/registrations/common/FluidReg.java b/src/main/java/kasuga/lib/registrations/common/FluidReg.java index c59d1b15..57471b05 100644 --- a/src/main/java/kasuga/lib/registrations/common/FluidReg.java +++ b/src/main/java/kasuga/lib/registrations/common/FluidReg.java @@ -38,7 +38,7 @@ public class FluidReg extends Reg { private final FluidType.Properties properties; private ForgeFlowingFluid.Properties fluidProp = null; private FluidBuilder stillBuilder = null, flowingBuilder = null; - private PropertyBuilder propertyBuilder = null; + private final ArrayList propertyBuilders; private BucketItemReg itemReg = null; private final ArrayList builders; private FluidBlockReg block; @@ -49,6 +49,7 @@ public class FluidReg extends Reg { private MenuReg menuReg = null; private int tintColor = 0xffffff; boolean registerItem = false, registerBlock = false, registerMenu = false; + private final FluidTagReg tag; /** * Create a fluid registration. @@ -59,6 +60,8 @@ public FluidReg(String registrationKey) { properties = FluidType.Properties.create(); builders = new ArrayList<>(); block = new FluidBlockReg<>(registrationKey); + propertyBuilders = new ArrayList<>(); + tag = new FluidTagReg("forge", registrationKey, "fluids/" + registrationKey); } /** @@ -89,6 +92,29 @@ public FluidReg flow(FluidBuilder builder, String flowingTexPath return this; } + public FluidReg decreasePreBlock(int decrease) { + return this.fluidProperty(prop -> prop.levelDecreasePerBlock(decrease)); + } + + public FluidReg slopeFindDistance(int distance) { + return this.fluidProperty(prop -> prop.slopeFindDistance(distance)); + } + + public FluidReg explosionResistance(float resistance) { + return this.fluidProperty(prop -> prop.explosionResistance(resistance)); + } + + public FluidReg tickRate(int tickRate) { + return this.fluidProperty(prop -> prop.tickRate(tickRate)); + } + + public FluidReg numericProperties(int decrease, int distance, int tickRate, float resistance) { + return decreasePreBlock(decrease) + .slopeFindDistance(distance) + .tickRate(tickRate) + .explosionResistance(resistance); + } + /** * Your fluid must has a fluid block, pass your fluid-block's constructor lambda here. * @param builder The constructor lambda of your fluid block. @@ -97,12 +123,14 @@ public FluidReg flow(FluidBuilder builder, String flowingTexPath @Mandatory public FluidReg blockType(FluidBlockReg.FluidBlockBuilder builder) { block.blockType(builder); + builders.add(prop -> prop.block(block::getBlock)); registerBlock = true; return this; } public FluidReg blockType(FluidBlockReg reg) { block = reg; + builders.add(prop -> prop.block(block::getBlock)); registerBlock = false; return this; } @@ -124,9 +152,15 @@ public FluidReg type(FluidType type) { * @return self. */ @Mandatory - public FluidReg bucketItem(BucketBuilder builder) { - itemReg = new BucketItemReg(registrationKey + ".bucket"); - itemReg.itemType((BucketItemReg.BucketBuilder) builder); + public FluidReg bucketItem(BucketItemReg.BucketBuilder builder) { + return bucketItem(registrationKey + "_bucket", builder); + } + + public FluidReg bucketItem(String itemRegistrationKey, + BucketItemReg.BucketBuilder builder) { + itemReg = new BucketItemReg(itemRegistrationKey); + itemReg.itemType(builder); + itemReg.fluidType(this::stillFluid); registerItem = true; return this; } @@ -315,7 +349,7 @@ public FluidReg overlayTexPath(String path) { */ @Optional public FluidReg typeProperty(PropertyBuilder builder) { - this.propertyBuilder = builder; + this.propertyBuilders.add(builder); return this; } @@ -339,9 +373,8 @@ public FluidReg fluidProperty(FluidPropertyBuilder builder) { @Override public FluidReg submit(SimpleRegistry registry) { properties.descriptionId(registrationKey); - if(propertyBuilder != null) { - propertyBuilder.build(properties); - } + + propertyBuilders.forEach(b -> b.build(properties)); if (flowingBuilder == null) { crashOnNotPresent(ForgeFlowingFluid.class, "flow", "submit"); } @@ -364,6 +397,7 @@ public FluidReg submit(SimpleRegistry registry) { if(!registry.hasMenuCache(this.toString())) registry.cacheMenuIn(menuReg); } + tag.submit(registry); return this; } @@ -459,6 +493,6 @@ public interface FluidPropertyBuilder { } public interface BucketBuilder { - T build(ForgeFlowingFluid fluid, Item.Properties properties); + T build(Supplier fluid, Item.Properties properties); } } diff --git a/src/main/java/kasuga/lib/registrations/common/FluidTagReg.java b/src/main/java/kasuga/lib/registrations/common/FluidTagReg.java new file mode 100644 index 00000000..333030f6 --- /dev/null +++ b/src/main/java/kasuga/lib/registrations/common/FluidTagReg.java @@ -0,0 +1,46 @@ +package kasuga.lib.registrations.common; + +import kasuga.lib.registrations.Reg; +import kasuga.lib.registrations.TagReg; +import kasuga.lib.registrations.registry.SimpleRegistry; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.tags.FluidTags; +import net.minecraft.tags.ItemTags; +import net.minecraft.tags.TagKey; +import net.minecraft.world.level.material.Fluid; + +public class FluidTagReg extends TagReg { + + private TagKey tagKey; + + private final String path; + + public FluidTagReg(String registrationKey, String path) { + super(registrationKey, path); + this.path = path; + } + + public FluidTagReg(String namespace, String registrationKey, String path) { + super(namespace, registrationKey, path); + this.path = path; + } + + @Override + public TagKey tag() { + return tagKey; + } + + @Override + public Reg submit(SimpleRegistry registry) { + location = otherNamespace == null ? + new ResourceLocation(registry.namespace, path) : + new ResourceLocation(otherNamespace, path); + tagKey = FluidTags.create(location); + return this; + } + + @Override + public String getIdentifier() { + return "fluid_tag"; + } +} diff --git a/src/main/java/kasuga/lib/registrations/common/ItemTagReg.java b/src/main/java/kasuga/lib/registrations/common/ItemTagReg.java index 3fbe7148..b314c021 100644 --- a/src/main/java/kasuga/lib/registrations/common/ItemTagReg.java +++ b/src/main/java/kasuga/lib/registrations/common/ItemTagReg.java @@ -16,7 +16,6 @@ */ public class ItemTagReg extends TagReg { TagKey tag = null; - private final String path; /** * Create a item tag reg. @@ -24,8 +23,11 @@ public class ItemTagReg extends TagReg { * @param path the resource location path of your item. */ public ItemTagReg(String registrationKey, String path) { - super(registrationKey); - this.path = path; + super(registrationKey, path); + } + + public ItemTagReg(String namespace, String registrationKey, String path) { + super(namespace, registrationKey, path); } /** @@ -36,7 +38,9 @@ public ItemTagReg(String registrationKey, String path) { @Override @Mandatory public ItemTagReg submit(SimpleRegistry registry) { - location = new ResourceLocation(registry.namespace, path); + location = otherNamespace == null ? + new ResourceLocation(registry.namespace, path) : + new ResourceLocation(otherNamespace, path); tag = ItemTags.create(location); return this; }