diff --git a/build.gradle b/build.gradle index 06d2b5f..21bd3f3 100644 --- a/build.gradle +++ b/build.gradle @@ -130,8 +130,10 @@ tasks.withType(JavaCompile) { processResources { inputs.property("version", project.version) + setDuplicatesStrategy(DuplicatesStrategy.EXCLUDE) from("LICENSE") + exclude(".cache") filesMatching("fabric.mod.json") { expand("version": project.version) diff --git a/gradle.properties b/gradle.properties index 16af42b..b1bde0a 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,7 +1,7 @@ minecraft_version=1.18.2 -loader_version=0.13.3 -ae2_version=11.0.0 -botania_version=431-FABRIC-SNAPSHOT +loader_version=0.14.8 +ae2_version=11.1.4 +botania_version=434-FABRIC-SNAPSHOT # Temp fix for Spotless / Remove Unused Imports: # https://github.com/diffplug/spotless/issues/834 diff --git a/src/main/java/appbot/ABBlocks.java b/src/main/java/appbot/ABBlocks.java new file mode 100644 index 0000000..ad53b6a --- /dev/null +++ b/src/main/java/appbot/ABBlocks.java @@ -0,0 +1,20 @@ +package appbot; + +import static appbot.AppliedBotanics.id; + +import net.minecraft.core.Registry; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.state.BlockBehaviour; + +import appbot.block.FluixPool; +import vazkii.botania.common.block.ModBlocks; +import vazkii.botania.common.block.mana.BlockPool; + +public class ABBlocks { + + public static final Block FLUIX_MANA_POOL = Registry.register(Registry.BLOCK, id("fluix_mana_pool"), + new FluixPool(BlockPool.Variant.FABULOUS, BlockBehaviour.Properties.copy(ModBlocks.fabulousPool))); + + public static void register() { + } +} diff --git a/src/main/java/appbot/ABItems.java b/src/main/java/appbot/ABItems.java index 05905f8..b6ff6a8 100644 --- a/src/main/java/appbot/ABItems.java +++ b/src/main/java/appbot/ABItems.java @@ -6,14 +6,12 @@ import net.minecraft.Util; import net.minecraft.core.Registry; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.item.CreativeModeTab; -import net.minecraft.world.item.Item; -import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.Rarity; +import net.minecraft.world.item.*; import net.minecraft.world.level.block.entity.BlockEntity; import appbot.ae2.ManaKeyType; import appbot.ae2.ManaP2PTunnelPart; +import vazkii.botania.common.item.ModItems; import appeng.api.client.StorageCellModels; import appeng.api.implementations.blockentities.IChestOrDrive; @@ -42,6 +40,9 @@ private static Item.Properties properties() { return new Item.Properties().tab(CREATIVE_TAB); } + public static final Item FLUIX_MANA_POOL = Registry.register(Registry.ITEM, id("fluix_mana_pool"), + new BlockItem(ABBlocks.FLUIX_MANA_POOL, ModItems.defaultBuilder().tab(CREATIVE_TAB))); + public static final Item MANA_CELL_HOUSING = Registry.register(Registry.ITEM, id("mana_cell_housing"), new Item(properties())); diff --git a/src/main/java/appbot/AppliedBotanics.java b/src/main/java/appbot/AppliedBotanics.java index dd492ca..af85f04 100644 --- a/src/main/java/appbot/AppliedBotanics.java +++ b/src/main/java/appbot/AppliedBotanics.java @@ -8,10 +8,12 @@ import vazkii.botania.common.integration.corporea.CorporeaNodeDetectors; import appeng.api.behaviors.ContainerItemStrategy; +import appeng.api.behaviors.GenericInternalInventory; import appeng.api.behaviors.GenericSlotCapacities; import appeng.api.features.P2PTunnelAttunement; import appeng.api.inventories.PartApiLookup; import appeng.api.stacks.AEKeyTypes; +import appeng.helpers.externalstorage.GenericStackInvStorage; import appeng.parts.automation.FabricExternalStorageStrategy; import appeng.parts.automation.StackWorldBehaviors; @@ -26,11 +28,21 @@ static ResourceLocation id(String path) { static void initialize() { ABMenus.register(); + ABBlocks.register(); ABItems.register(); AEKeyTypes.register(ManaKeyType.TYPE); PartApiLookup.register(Apis.BLOCK, (part, context) -> part.getExposedApi(), ManaP2PTunnelPart.class); + Apis.BLOCK.registerFallback((world, pos, state, blockEntity, direction) -> { + // Fall back to generic inv + var genericInv = GenericInternalInventory.SIDED.find(world, pos, state, blockEntity, direction); + if (genericInv != null) { + return new GenericStackInvStorage<>(ManaVariantConversion.INSTANCE, ManaKeyType.TYPE, genericInv); + } + return null; + }); + StackWorldBehaviors.registerImportStrategy(ManaKeyType.TYPE, (level, fromPos, fromSide) -> Reflect .newStorageImportStrategy(Apis.BLOCK, ManaVariantConversion.INSTANCE, level, fromPos, fromSide)); StackWorldBehaviors.registerExportStrategy(ManaKeyType.TYPE, (level, fromPos, fromSide) -> Reflect diff --git a/src/main/java/appbot/block/FluixPool.java b/src/main/java/appbot/block/FluixPool.java new file mode 100644 index 0000000..bfbcb45 --- /dev/null +++ b/src/main/java/appbot/block/FluixPool.java @@ -0,0 +1,22 @@ +package appbot.block; + +import org.jetbrains.annotations.NotNull; + +import net.minecraft.core.BlockPos; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +import vazkii.botania.common.block.mana.BlockPool; + +public class FluixPool extends BlockPool { + + public FluixPool(Variant v, Properties builder) { + super(v, builder); + } + + @NotNull + @Override + public BlockEntity newBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) { + return new FluixPoolBlockEntity(pos, state); + } +} diff --git a/src/main/java/appbot/block/FluixPoolBlockEntity.java b/src/main/java/appbot/block/FluixPoolBlockEntity.java new file mode 100644 index 0000000..db78686 --- /dev/null +++ b/src/main/java/appbot/block/FluixPoolBlockEntity.java @@ -0,0 +1,240 @@ +package appbot.block; + +import java.util.ArrayList; +import java.util.EnumSet; +import java.util.List; + +import com.google.common.primitives.Ints; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerChunkEvents; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.world.level.block.state.BlockState; + +import appbot.ABBlocks; +import appbot.ae2.ManaKey; +import vazkii.botania.common.block.tile.mana.TilePool; + +import appeng.api.config.Actionable; +import appeng.api.networking.*; +import appeng.api.networking.security.IActionSource; +import appeng.api.storage.StorageHelper; +import appeng.api.util.AECableType; +import appeng.hooks.ticking.TickHandler; +import appeng.me.helpers.BlockEntityNodeListener; +import appeng.me.helpers.IGridConnectedBlockEntity; + +public class FluixPoolBlockEntity extends TilePool implements IInWorldGridNodeHost, IGridConnectedBlockEntity { + + static { + /* + * We need to defer actually unloading tile entities until the end of the tick, after the chunk has been saved + * to disk. The CHUNK_UNLOAD event runs before the chunk has been saved, and if we disconnect nodes at that + * point, the saved data will be missing information from the node (such as the player id). + * + * From DeferredBlockEntityUnloader + */ + ServerChunkEvents.CHUNK_UNLOAD.register((serverWorld, worldChunk) -> { + List entitiesToRemove = new ArrayList<>(); + + for (var value : worldChunk.getBlockEntities().values()) { + if (value instanceof FluixPoolBlockEntity fluixPoolBlockEntity) { + entitiesToRemove.add(fluixPoolBlockEntity); + } + } + + if (!entitiesToRemove.isEmpty()) { + TickHandler.instance().addCallable(serverWorld, (world) -> { + for (var blockEntity : entitiesToRemove) { + blockEntity.onChunkUnloaded(); + } + }); + } + }); + } + + private final Accessor mana = (Accessor) this; + private final IManagedGridNode mainNode = GridHelper.createManagedNode(this, BlockEntityNodeListener.INSTANCE) + .setFlags(GridFlags.REQUIRE_CHANNEL) + .setVisualRepresentation(ABBlocks.FLUIX_MANA_POOL) + .setInWorldNode(true) + .setExposedOnSides(EnumSet.complementOf(EnumSet.of(Direction.UP))) + .setTagName("proxy"); + private final IActionSource actionSource = IActionSource.ofMachine(mainNode::getNode); + + public FluixPoolBlockEntity(@NotNull BlockPos pos, @NotNull BlockState state) { + super(pos, state); + } + + @Override + public boolean isFull() { + var grid = getMainNode().getGrid(); + + if (grid == null || !getMainNode().isActive()) { + return true; + } + + return grid.getStorageService().getInventory().extract(ManaKey.KEY, 1, Actionable.SIMULATE, actionSource) == 0; + } + + @Override + public void receiveMana(int mana) { + var grid = getMainNode().getGrid(); + + if (grid == null || !getMainNode().isActive()) { + return; + } + + var storage = grid.getStorageService().getInventory(); + var changed = false; + + if (mana > 0) { + changed = StorageHelper.poweredInsert(grid.getEnergyService(), storage, ManaKey.KEY, mana, + actionSource) != 0; + } else if (mana < 0) { + changed = StorageHelper.poweredExtraction(grid.getEnergyService(), storage, ManaKey.KEY, -mana, + actionSource) != 0; + } + + if (changed) { + setChanged(); + markDispatchable(); + } + } + + @Override + public int getCurrentMana() { + var grid = getMainNode().getGrid(); + + if (grid == null) { + return mana.getMana(); + } + + if (!getMainNode().isActive()) { + return 0; + } + + return (int) grid.getStorageService().getInventory().extract(ManaKey.KEY, Integer.MAX_VALUE, + Actionable.SIMULATE, actionSource); + } + + public void recalculateManaCap() { + var grid = getMainNode().getGrid(); + + if (grid == null) { + return; + } + + var oldMana = mana.getMana(); + var oldManaCap = manaCap; + + if (getMainNode().isActive()) { + var storage = grid.getStorageService().getInventory(); + mana.setMana( + Ints.saturatedCast( + storage.extract(ManaKey.KEY, Integer.MAX_VALUE, Actionable.SIMULATE, actionSource))); + manaCap = Ints + .saturatedCast(storage.extract(ManaKey.KEY, Integer.MAX_VALUE, Actionable.SIMULATE, actionSource) + + storage.insert(ManaKey.KEY, Integer.MAX_VALUE, Actionable.SIMULATE, actionSource)); + } else { + mana.setMana(0); + manaCap = 0; + } + + if (oldMana != mana.getMana() || oldManaCap != manaCap) { + setChanged(); + markDispatchable(); + } + } + + @Override + public void saveAdditional(CompoundTag tag) { + super.saveAdditional(tag); + this.getMainNode().saveToNBT(tag); + } + + @Override + public void load(@NotNull CompoundTag tag) { + super.load(tag); + this.getMainNode().loadFromNBT(tag); + } + + @Nullable + @Override + public IGridNode getGridNode(Direction dir) { + var node = this.getMainNode().getNode(); + return node != null && node.isExposedOnSide(dir) ? node : null; + } + + @Override + public AECableType getCableConnectionType(Direction dir) { + return AECableType.SMART; + } + + @Override + public IManagedGridNode getMainNode() { + return mainNode; + } + + @Override + public void securityBreak() { + this.level.destroyBlock(this.worldPosition, true); + } + + @Override + public void saveChanges() { + if (this.level == null) { + return; + } + + // Clientside is marked immediately as dirty as there is no queue processing + // Serverside is only queued once per tick to avoid costly operations + // TODO: Evaluate if this is still necessary + if (this.level.isClientSide) { + this.setChanged(); + } else { + this.level.blockEntityChanged(this.worldPosition); + if (!this.setChangedQueued) { + TickHandler.instance().addCallable(null, this::setChangedAtEndOfTick); + this.setChangedQueued = true; + } + } + } + + private boolean setChangedQueued = false; + + private void setChangedAtEndOfTick() { + this.setChanged(); + this.setChangedQueued = false; + } + + public void onChunkUnloaded() { + this.getMainNode().destroy(); + } + + public void onReady() { + this.getMainNode().create(getLevel(), getBlockPos()); + } + + @Override + public void setRemoved() { + super.setRemoved(); + this.getMainNode().destroy(); + } + + @Override + public void clearRemoved() { + super.clearRemoved(); + GridHelper.onFirstTick(this, FluixPoolBlockEntity::onReady); + } + + public interface Accessor { + int getMana(); + + void setMana(int mana); + } +} diff --git a/src/main/java/appbot/block/package-info.java b/src/main/java/appbot/block/package-info.java new file mode 100644 index 0000000..27eed08 --- /dev/null +++ b/src/main/java/appbot/block/package-info.java @@ -0,0 +1,7 @@ +@ParametersAreNonnullByDefault +@MethodsReturnNonnullByDefault +package appbot.block; + +import javax.annotation.ParametersAreNonnullByDefault; + +import net.minecraft.MethodsReturnNonnullByDefault; diff --git a/src/main/java/appbot/data/ModelProvider.java b/src/main/java/appbot/data/ModelProvider.java index b2c7cd2..06fb4f6 100644 --- a/src/main/java/appbot/data/ModelProvider.java +++ b/src/main/java/appbot/data/ModelProvider.java @@ -2,7 +2,6 @@ import static appbot.AppliedBotanics.id; -import java.lang.reflect.Field; import java.util.Locale; import java.util.Optional; import java.util.function.BiConsumer; @@ -17,6 +16,7 @@ import net.minecraft.data.models.model.*; import net.minecraft.resources.ResourceLocation; +import appbot.ABBlocks; import appbot.ABItems; import vazkii.botania.common.block.ModBlocks; @@ -46,6 +46,8 @@ public ModelProvider(FabricDataGenerator dataGenerator) { @Override public void generateBlockStateModels(BlockModelGenerators generator) { + generator.blockStateOutput.accept(BlockModelGenerators.createSimpleBlock(ABBlocks.FLUIX_MANA_POOL, + id("block/fluix_mana_pool"))); } @Override @@ -77,7 +79,7 @@ public void generateItemModels(ItemModelGenerators generator) { private static BiConsumer> output(ItemModelGenerators generator) { try { - Field output = ItemModelGenerators.class.getDeclaredField("output"); + var output = ItemModelGenerators.class.getDeclaredField("output"); output.setAccessible(true); return (BiConsumer>) output.get(generator); } catch (Throwable throwable) { diff --git a/src/main/java/appbot/data/RecipeProvider.java b/src/main/java/appbot/data/RecipeProvider.java index ef9f015..8e658c2 100644 --- a/src/main/java/appbot/data/RecipeProvider.java +++ b/src/main/java/appbot/data/RecipeProvider.java @@ -11,6 +11,7 @@ import appbot.ABItems; import appbot.AppliedBotanics; +import vazkii.botania.common.block.ModBlocks; import vazkii.botania.common.item.ModItems; import appeng.core.definitions.AEBlocks; @@ -24,6 +25,12 @@ public RecipeProvider(FabricDataGenerator dataGenerator) { @Override protected void generateRecipes(Consumer exporter) { + ShapelessRecipeBuilder.shapeless(ABItems.FLUIX_MANA_POOL) + .requires(ModBlocks.fabulousPool) + .requires(AEBlocks.INTERFACE) + .unlockedBy("has_interface", has(AEBlocks.INTERFACE)) + .save(exporter, AppliedBotanics.id("fluix_mana_pool")); + ShapedRecipeBuilder.shaped(ABItems.MANA_CELL_HOUSING) .pattern("QSQ") .pattern("S S") diff --git a/src/main/java/appbot/mixins/ModTilesMixin.java b/src/main/java/appbot/mixins/ModTilesMixin.java new file mode 100644 index 0000000..4d4c108 --- /dev/null +++ b/src/main/java/appbot/mixins/ModTilesMixin.java @@ -0,0 +1,54 @@ +package appbot.mixins; + +import static vazkii.botania.common.lib.ResourceLocationHelper.prefix; + +import java.util.function.BiFunction; + +import org.apache.commons.lang3.ArrayUtils; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.ModifyArg; + +import net.minecraft.core.BlockPos; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; + +import appbot.ABBlocks; +import appbot.block.FluixPoolBlockEntity; +import vazkii.botania.common.block.tile.ModTiles; +import vazkii.botania.common.lib.LibBlockNames; + +@Mixin(ModTiles.class) +public class ModTilesMixin { + + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lvazkii/botania/common/block/tile/ModTiles;type(Lnet/minecraft/resources/ResourceLocation;Ljava/util/function/BiFunction;[Lnet/minecraft/world/level/block/Block;)Lnet/minecraft/world/level/block/entity/BlockEntityType;"), index = 1) + private static BiFunction injectConstructor(ResourceLocation id, + BiFunction func, + Block... blocks) { + if (id.equals(prefix(LibBlockNames.POOL))) { + return (blockPos, blockState) -> { + if (blockState.is(ABBlocks.FLUIX_MANA_POOL)) { + // noinspection unchecked + return (T) new FluixPoolBlockEntity(blockPos, blockState); + } else { + return func.apply(blockPos, blockState); + } + }; + } + + return func; + } + + @SuppressWarnings("InvalidInjectorMethodSignature") + @ModifyArg(method = "", at = @At(value = "INVOKE", target = "Lvazkii/botania/common/block/tile/ModTiles;type(Lnet/minecraft/resources/ResourceLocation;Ljava/util/function/BiFunction;[Lnet/minecraft/world/level/block/Block;)Lnet/minecraft/world/level/block/entity/BlockEntityType;"), index = 2) + private static Block[] add(ResourceLocation id, BiFunction func, + Block... blocks) { + if (id.equals(prefix(LibBlockNames.POOL))) { + blocks = ArrayUtils.add(blocks, ABBlocks.FLUIX_MANA_POOL); + } + + return blocks; + } +} diff --git a/src/main/java/appbot/mixins/TilePoolMixin.java b/src/main/java/appbot/mixins/TilePoolMixin.java new file mode 100644 index 0000000..44652a2 --- /dev/null +++ b/src/main/java/appbot/mixins/TilePoolMixin.java @@ -0,0 +1,40 @@ +package appbot.mixins; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.Redirect; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import appbot.block.FluixPoolBlockEntity; +import vazkii.botania.common.block.tile.mana.TilePool; + +@Mixin(value = TilePool.class, remap = false) +public class TilePoolMixin implements FluixPoolBlockEntity.Accessor { + + @Shadow + private int mana; + + @Inject(method = "initManaCapAndNetwork", at = @At(value = "FIELD", target = "Lvazkii/botania/common/block/tile/mana/TilePool;manaCap:I", shift = At.Shift.AFTER)) + private void recalculateManaCap(CallbackInfo callbackInfo) { + if ((Object) this instanceof FluixPoolBlockEntity fluixPoolBlockEntity) { + fluixPoolBlockEntity.recalculateManaCap(); + } + } + + @Redirect(method = "writePacketNBT", at = @At(value = "FIELD", target = "Lvazkii/botania/common/block/tile/mana/TilePool;mana:I")) + private int getMana(TilePool instance) { + return instance.getCurrentMana(); + } + + @Override + public int getMana() { + return mana; + } + + @Override + public void setMana(int mana) { + this.mana = mana; + } +} diff --git a/src/main/java/appbot/mixins/WailaModuleMixin.java b/src/main/java/appbot/mixins/WailaModuleMixin.java new file mode 100644 index 0000000..0ea03b6 --- /dev/null +++ b/src/main/java/appbot/mixins/WailaModuleMixin.java @@ -0,0 +1,24 @@ +package appbot.mixins; + +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; + +import appbot.block.FluixPoolBlockEntity; +import mcp.mobius.waila.api.IRegistrar; +import mcp.mobius.waila.api.TooltipPosition; + +import appeng.integration.modules.waila.BlockEntityDataProvider; +import appeng.integration.modules.waila.WailaModule; + +@Mixin(value = WailaModule.class, remap = false) +public class WailaModuleMixin { + + @Inject(method = "register", at = @At("RETURN")) + private void register(IRegistrar registrar, CallbackInfo callbackInfo) { + var blockEntityProvider = new BlockEntityDataProvider(); + registrar.addComponent(blockEntityProvider, TooltipPosition.BODY, FluixPoolBlockEntity.class); + registrar.addBlockData(blockEntityProvider, FluixPoolBlockEntity.class); + } +} diff --git a/src/main/resources/appbot.mixins.json b/src/main/resources/appbot.mixins.json index 7feab8a..62c171d 100644 --- a/src/main/resources/appbot.mixins.json +++ b/src/main/resources/appbot.mixins.json @@ -3,7 +3,7 @@ "minVersion": "0.8", "package": "appbot.mixins", "compatibilityLevel": "JAVA_17", - "mixins": [], + "mixins": ["ModTilesMixin", "TilePoolMixin", "WailaModuleMixin"], "injectors": { "defaultRequire": 1 } diff --git a/src/main/resources/assets/appbot/lang/en_us.json b/src/main/resources/assets/appbot/lang/en_us.json index cf2e268..d769bc2 100644 --- a/src/main/resources/assets/appbot/lang/en_us.json +++ b/src/main/resources/assets/appbot/lang/en_us.json @@ -3,6 +3,8 @@ "itemGroup.appbot.tab": "Applied Botanics", + "block.appbot.fluix_mana_pool": "Fluix Mana Pool", + "item.appbot.mana_cell_housing": "ME Mana Cell Housing", "item.appbot.creative_mana_cell": "Creative ME Mana Cell", @@ -18,5 +20,11 @@ "item.appbot.portable_mana_storage_cell_64k": "64k Portable Mana Cell", "item.appbot.portable_mana_storage_cell_256k": "256k Portable Mana Cell", - "item.appbot.mana_p2p_tunnel": "Mana P2P Tunnel" + "appbot.entry.fluix_mana_pool": "Fluix Mana Pool", + "appbot.page.fluix_mana_pool0": "The $(item)Fluix Mana Pool$(0) operates on $(thing)Mana$(0) from the attached ME system", + "appbot.page.fluix_mana_pool1": "this isn't so bad", + + "appbot.entry.mana_drives": "Mana Drives", + "appbot.page.mana_drives0": "Ever wanted to throw magic under the bus and go numerical? shame on you", + "appbot.page.mana_drives1": "just what vazkii never wanted" } diff --git a/src/main/resources/assets/appbot/models/block/fluix_mana_pool.json b/src/main/resources/assets/appbot/models/block/fluix_mana_pool.json new file mode 100644 index 0000000..40e4f19 --- /dev/null +++ b/src/main/resources/assets/appbot/models/block/fluix_mana_pool.json @@ -0,0 +1,177 @@ +{ + "credit": "Made with Blockbench", + "parent": "minecraft:block/block", + "textures": { + "main": "appbot:block/fluixpool", + "inside": "appbot:block/fluixpoolinside", + "greebles": "appbot:block/fluixpoolgreebles", + "particle": "#main" + }, + "elements": [ + { + "name": "base", + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": { "uv": [0, 0, 16, 1], "texture": "#main" }, + "east": { "uv": [0, 0, 16, 1], "texture": "#main" }, + "south": { "uv": [0, 0, 16, 1], "texture": "#main" }, + "west": { "uv": [0, 0, 16, 1], "texture": "#main" }, + "up": { "uv": [0, 0, 16, 16], "texture": "#inside" }, + "down": { "uv": [0, 0, 16, 16], "texture": "#main" } + } + }, + { + "name": "side", + "from": [0, 1, 15], + "to": [16, 8, 16], + "faces": { + "north": { "uv": [0, 8, 16, 15], "texture": "#greebles" }, + "east": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "south": { "uv": [0, 8, 16, 15], "texture": "#main" }, + "west": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "up": { "uv": [0, 7, 16, 8], "texture": "#main" }, + "down": { "uv": [0, 0, 16, 1], "texture": "#main" } + } + }, + { + "name": "side", + "from": [0, 1, 0], + "to": [16, 8, 1], + "faces": { + "north": { "uv": [0, 8, 16, 15], "texture": "#main" }, + "east": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "south": { "uv": [0, 8, 16, 15], "texture": "#greebles" }, + "west": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "up": { "uv": [0, 7, 16, 8], "rotation": 180, "texture": "#main" }, + "down": { "uv": [0, 0, 16, 1], "rotation": 180, "texture": "#main" } + } + }, + { + "name": "side", + "from": [0, 1, 1], + "to": [1, 8, 15], + "faces": { + "north": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "east": { "uv": [1, 8, 15, 15], "texture": "#greebles" }, + "south": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "west": { "uv": [1, 8, 15, 15], "texture": "#main" }, + "up": { "uv": [1, 7, 15, 8], "rotation": 90, "texture": "#main" }, + "down": { "uv": [1, 0, 15, 1], "rotation": 270, "texture": "#main" } + } + }, + { + "name": "side", + "from": [15, 1, 1], + "to": [16, 8, 15], + "faces": { + "north": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "east": { "uv": [1, 8, 15, 15], "texture": "#main" }, + "south": { "uv": [0, 0, 1, 7], "texture": "#main" }, + "west": { "uv": [1, 8, 15, 15], "texture": "#greebles" }, + "up": { "uv": [1, 7, 15, 8], "rotation": 270, "texture": "#main" }, + "down": { "uv": [1, 0, 15, 1], "rotation": 90, "texture": "#main" } + } + }, + { + "name": "CableConnector", + "from": [5, 5, 0], + "to": [11, 11, 2], + "faces": { + "north": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "east": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "south": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "west": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "up": { "uv": [5, 4, 11, 6], "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "texture": "#greebles" } + } + }, + { + "name": "CableConnector", + "from": [0, 5, 5], + "to": [2, 11, 11], + "faces": { + "north": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "east": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "south": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "west": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "up": { "uv": [5, 4, 11, 6], "rotation": 270, "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "rotation": 90, "texture": "#greebles" } + } + }, + { + "name": "CableConnector", + "from": [14, 5, 5], + "to": [16, 11, 11], + "faces": { + "north": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "east": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "south": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "west": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "up": { "uv": [5, 4, 11, 6], "rotation": 90, "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "rotation": 270, "texture": "#greebles" } + } + }, + { + "name": "CableConnector", + "from": [5, 5, 14], + "to": [11, 11, 16], + "faces": { + "north": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "east": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "south": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "west": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "up": { "uv": [5, 4, 11, 6], "rotation": 180, "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "rotation": 180, "texture": "#greebles" } + } + }, + { + "name": "FluixNode", + "from": [5, 1, 5], + "to": [11, 2, 11], + "faces": { + "north": { "uv": [5, 5, 11, 6], "texture": "#inside" }, + "east": { "uv": [5, 5, 6, 11], "rotation": 90, "texture": "#inside" }, + "south": { "uv": [5, 10, 11, 11], "texture": "#inside" }, + "west": { "uv": [5, 5, 6, 11], "rotation": 90, "texture": "#inside" }, + "up": { "uv": [5, 5, 11, 11], "texture": "#inside" }, + "down": { "uv": [5, 5, 11, 11], "texture": "#inside" } + } + } + ], + "display": { + "thirdperson_righthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "thirdperson_lefthand": { + "rotation": [75, 45, 0], + "translation": [0, 2.5, 0], + "scale": [0.375, 0.375, 0.375] + }, + "firstperson_righthand": { + "rotation": [0, 45, 0], + "scale": [0.4, 0.4, 0.4] + }, + "firstperson_lefthand": { + "rotation": [0, 225, 0], + "scale": [0.4, 0.4, 0.4] + }, + "ground": { + "translation": [0, 3, 0], + "scale": [0.25, 0.25, 0.25] + }, + "gui": { + "rotation": [30, 225, 0], + "scale": [0.625, 0.625, 0.625] + }, + "head": { + "rotation": [0, 180, 0], + "translation": [0, 13, 7] + }, + "fixed": { + "scale": [0.5, 0.5, 0.5] + } + } +} diff --git a/src/main/resources/assets/appbot/models/block/fluix_mana_pool_full.json b/src/main/resources/assets/appbot/models/block/fluix_mana_pool_full.json new file mode 100644 index 0000000..eda12bd --- /dev/null +++ b/src/main/resources/assets/appbot/models/block/fluix_mana_pool_full.json @@ -0,0 +1,172 @@ +{ + "credit": "Made with Blockbench", + "parent": "minecraft:block/block", + "textures": { + "main": "appbot:block/fluixpool", + "inside": "appbot:block/fluixpoolinside", + "greebles": "appbot:block/fluixpoolgreebles", + "liquid": "botania:block/mana_water", + "particle": "#main" + }, + "elements": [ + { + "name": "basePlate", + "from": [0, 0, 0], + "to": [16, 1, 16], + "faces": { + "north": { "uv": [0, 15, 16, 16], "texture": "#main", "tintindex": 0 }, + "east": { "uv": [0, 15, 16, 16], "texture": "#main", "tintindex": 0 }, + "south": { "uv": [0, 15, 16, 16], "texture": "#main", "tintindex": 0 }, + "west": { "uv": [0, 15, 16, 16], "texture": "#main", "tintindex": 0 }, + "up": { "uv": [0, 0, 16, 16], "texture": "#inside", "tintindex": 0 }, + "down": { + "uv": [0, 0, 16, 16], + "texture": "#main", + "cullface": "down", + "tintindex": 0 + } + } + }, + { + "name": "side", + "from": [0, 1, 15], + "to": [16, 8, 16], + "faces": { + "north": { + "uv": [0, 8, 16, 15], + "texture": "#greebles", + "tintindex": 0 + }, + "east": { "uv": [0, 8, 1, 15], "texture": "#main", "tintindex": 0 }, + "south": { "uv": [0, 8, 16, 15], "texture": "#main", "tintindex": 0 }, + "west": { "uv": [15, 8, 16, 15], "texture": "#main", "tintindex": 0 }, + "up": { "uv": [0, 8, 16, 9], "texture": "#main", "tintindex": 0 }, + "down": { "uv": [0, 0, 16, 1], "texture": "#main", "tintindex": 0 } + } + }, + { + "name": "side", + "from": [0, 1, 0], + "to": [16, 8, 1], + "faces": { + "north": { "uv": [0, 8, 16, 15], "texture": "#main", "tintindex": 0 }, + "east": { "uv": [15, 8, 16, 15], "texture": "#main", "tintindex": 0 }, + "south": { + "uv": [0, 8, 16, 15], + "texture": "#greebles", + "tintindex": 0 + }, + "west": { "uv": [0, 8, 1, 15], "texture": "#main", "tintindex": 0 }, + "up": { "uv": [0, 8, 16, 9], "texture": "#main", "tintindex": 0 }, + "down": { "uv": [0, 15, 16, 16], "texture": "#main", "tintindex": 0 } + } + }, + { + "name": "side", + "from": [15, 1, 1], + "to": [16, 8, 15], + "faces": { + "north": { "uv": [0, 8, 1, 15], "texture": "#main", "tintindex": 0 }, + "east": { "uv": [1, 8, 15, 15], "texture": "#main", "tintindex": 0 }, + "south": { "uv": [15, 8, 16, 15], "texture": "#main", "tintindex": 0 }, + "west": { + "uv": [1, 8, 15, 15], + "texture": "#greebles", + "tintindex": 0 + }, + "up": { "uv": [8, 1, 9, 15], "texture": "#main", "tintindex": 0 }, + "down": { "uv": [15, 1, 16, 15], "texture": "#main", "tintindex": 0 } + } + }, + { + "name": "side", + "from": [0, 1, 1], + "to": [1, 8, 15], + "faces": { + "north": { "uv": [15, 8, 16, 15], "texture": "#main", "tintindex": 0 }, + "east": { + "uv": [1, 8, 15, 15], + "texture": "#greebles", + "tintindex": 0 + }, + "south": { "uv": [0, 8, 1, 15], "texture": "#main", "tintindex": 0 }, + "west": { "uv": [1, 8, 15, 15], "texture": "#main", "tintindex": 0 }, + "up": { "uv": [7, 1, 8, 15], "texture": "#main", "tintindex": 0 }, + "down": { "uv": [0, 1, 1, 15], "texture": "#main", "tintindex": 0 } + } + }, + { + "name": "CableConnector", + "from": [5, 5, 0], + "to": [11, 11, 2], + "faces": { + "north": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "east": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "south": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "west": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "up": { "uv": [5, 4, 11, 6], "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "texture": "#greebles" } + } + }, + { + "name": "CableConnector", + "from": [0, 5, 5], + "to": [2, 11, 11], + "faces": { + "north": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "east": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "south": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "west": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "up": { "uv": [5, 4, 11, 6], "rotation": 270, "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "rotation": 90, "texture": "#greebles" } + } + }, + { + "name": "CableConnector", + "from": [14, 5, 5], + "to": [16, 11, 11], + "faces": { + "north": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "east": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "south": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "west": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "up": { "uv": [5, 4, 11, 6], "rotation": 90, "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "rotation": 270, "texture": "#greebles" } + } + }, + { + "name": "CableConnector", + "from": [5, 5, 14], + "to": [11, 11, 16], + "faces": { + "north": { "uv": [5, 5, 11, 11], "texture": "#greebles" }, + "east": { "uv": [4, 5, 6, 11], "texture": "#greebles" }, + "south": { "uv": [5, 5, 11, 11], "texture": "#main" }, + "west": { "uv": [6, 5, 4, 11], "texture": "#greebles" }, + "up": { "uv": [5, 4, 11, 6], "rotation": 180, "texture": "#greebles" }, + "down": { "uv": [5, 6, 11, 4], "rotation": 180, "texture": "#greebles" } + } + }, + { + "name": "FluixNode", + "from": [5, 1, 5], + "to": [11, 2, 11], + "faces": { + "north": { "uv": [5, 5, 11, 6], "texture": "#inside" }, + "east": { "uv": [5, 5, 6, 11], "rotation": 90, "texture": "#inside" }, + "south": { "uv": [5, 10, 11, 11], "texture": "#inside" }, + "west": { "uv": [5, 5, 6, 11], "rotation": 90, "texture": "#inside" }, + "up": { "uv": [5, 5, 11, 11], "texture": "#inside" }, + "down": { "uv": [5, 5, 11, 11], "texture": "#inside" } + } + }, + { + "name": "liquid", + "from": [1, 7, 1], + "to": [15, 7.001, 15], + "faces": { + "up": { "uv": [1, 1, 15, 15], "texture": "#liquid" } + } + } + ] +} diff --git a/src/main/resources/assets/appbot/models/item/fluix_mana_pool.json b/src/main/resources/assets/appbot/models/item/fluix_mana_pool.json new file mode 100644 index 0000000..53c352e --- /dev/null +++ b/src/main/resources/assets/appbot/models/item/fluix_mana_pool.json @@ -0,0 +1,11 @@ +{ + "parent": "appbot:block/fluix_mana_pool", + "overrides": [ + { + "predicate": { + "botania:full": 1.0 + }, + "model": "appbot:block/fluix_mana_pool_full" + } + ] +} diff --git a/src/main/resources/assets/appbot/textures/block/fluixpool.png b/src/main/resources/assets/appbot/textures/block/fluixpool.png new file mode 100644 index 0000000..d148f5d Binary files /dev/null and b/src/main/resources/assets/appbot/textures/block/fluixpool.png differ diff --git a/src/main/resources/assets/appbot/textures/block/fluixpoolgreebles.png b/src/main/resources/assets/appbot/textures/block/fluixpoolgreebles.png new file mode 100644 index 0000000..08024ef Binary files /dev/null and b/src/main/resources/assets/appbot/textures/block/fluixpoolgreebles.png differ diff --git a/src/main/resources/assets/appbot/textures/block/fluixpoolinside.png b/src/main/resources/assets/appbot/textures/block/fluixpoolinside.png new file mode 100644 index 0000000..6566faa Binary files /dev/null and b/src/main/resources/assets/appbot/textures/block/fluixpoolinside.png differ diff --git a/src/main/resources/assets/botania/patchouli_books/lexicon/en_us/entries/misc/fluix_mana_pool.json b/src/main/resources/assets/botania/patchouli_books/lexicon/en_us/entries/misc/fluix_mana_pool.json new file mode 100644 index 0000000..ec43a02 --- /dev/null +++ b/src/main/resources/assets/botania/patchouli_books/lexicon/en_us/entries/misc/fluix_mana_pool.json @@ -0,0 +1,18 @@ +{ + "name": "appbot.entry.fluix_mana_pool", + "category": "botania:misc", + "icon": "appbot:fluix_mana_pool", + "entry_color": "aa00", + "advancement": "botania:main/elf_lexicon_pickup", + "pages": [ + { + "type": "text", + "text": "appbot.page.fluix_mana_pool0" + }, + { + "type": "crafting", + "text": "appbot.page.fluix_mana_pool1", + "recipe": "appbot:fluix_mana_pool" + } + ] +} diff --git a/src/main/resources/assets/botania/patchouli_books/lexicon/en_us/entries/misc/mana_drives.json b/src/main/resources/assets/botania/patchouli_books/lexicon/en_us/entries/misc/mana_drives.json new file mode 100644 index 0000000..18edd5e --- /dev/null +++ b/src/main/resources/assets/botania/patchouli_books/lexicon/en_us/entries/misc/mana_drives.json @@ -0,0 +1,38 @@ +{ + "name": "appbot.entry.mana_drives", + "category": "botania:misc", + "icon": "appbot:mana_cell_housing", + "entry_color": "aa00", + "advancement": "botania:main/elf_lexicon_pickup", + "pages": [ + { + "type": "text", + "text": "appbot.page.mana_drives0" + }, + { + "type": "crafting", + "text": "appbot.page.mana_drives1", + "recipe": "appbot:mana_cell_housing" + }, + { + "type": "crafting", + "recipe": "appbot:mana_storage_cell_1k" + }, + { + "type": "crafting", + "recipe": "appbot:mana_storage_cell_4k" + }, + { + "type": "crafting", + "recipe": "appbot:mana_storage_cell_16k" + }, + { + "type": "crafting", + "recipe": "appbot:mana_storage_cell_64k" + }, + { + "type": "crafting", + "recipe": "appbot:mana_storage_cell_256k" + } + ] +}