diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index a999eb2a0..9cbb2b681 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -4,7 +4,7 @@ jobs: build: runs-on: ubuntu-20.04 container: - image: openjdk:15-jdk + image: openjdk:16-jdk options: --user root steps: - uses: actions/checkout@v2 @@ -17,14 +17,14 @@ jobs: token: ${{ secrets.github_token }} prefix: ${{ github.ref }} - - run: ./gradlew build publish --stacktrace - env: - MAVEN_URL: ${{ secrets.MAVEN_URL }} - MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} - MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} - SIGNING_KEY: ${{ secrets.SIGNING_KEY }} - SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} - CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} +# - run: ./gradlew build publish --stacktrace +# env: +# MAVEN_URL: ${{ secrets.MAVEN_URL }} +# MAVEN_USERNAME: ${{ secrets.MAVEN_USERNAME }} +# MAVEN_PASSWORD: ${{ secrets.MAVEN_PASSWORD }} +# SIGNING_KEY: ${{ secrets.SIGNING_KEY }} +# SIGNING_PASSWORD: ${{ secrets.SIGNING_PASSWORD }} +# CROWDIN_KEY: ${{ secrets.CROWDIN_KEY }} - name: Upload artifacts uses: actions/upload-artifact@v2 diff --git a/.github/workflows/check.yml b/.github/workflows/check.yml index a4caad3ed..a45480ed6 100644 --- a/.github/workflows/check.yml +++ b/.github/workflows/check.yml @@ -4,7 +4,7 @@ jobs: build: runs-on: ubuntu-20.04 container: - image: openjdk:15-jdk + image: openjdk:16-jdk options: --user root steps: - uses: actions/checkout@v2 diff --git a/.github/workflows/release.yml b/.github/workflows/release.yml index fff039a26..f78edf973 100644 --- a/.github/workflows/release.yml +++ b/.github/workflows/release.yml @@ -10,7 +10,7 @@ jobs: build: runs-on: ubuntu-20.04 container: - image: openjdk:15-jdk + image: openjdk:16-jdk options: --user root steps: - uses: actions/checkout@v2 diff --git a/.gitignore b/.gitignore index 8381c244b..94961a481 100644 --- a/.gitignore +++ b/.gitignore @@ -29,4 +29,7 @@ java_pid2412.hprof /buildSrc/.gradle/ /buildSrc/build/ /src/main/resources/package-lock.json -/src/main/resources/node_modules/ \ No newline at end of file +/src/main/resources/node_modules/ + +/RebornCore/.gradle +/RebornCore/build \ No newline at end of file diff --git a/RebornCore/build.gradle b/RebornCore/build.gradle new file mode 100644 index 000000000..3abcd9254 --- /dev/null +++ b/RebornCore/build.gradle @@ -0,0 +1 @@ +group = 'RebornCore' \ No newline at end of file diff --git a/RebornCore/src/main/java/io/github/cottonmc/libcd/api/CustomOutputRecipe.java b/RebornCore/src/main/java/io/github/cottonmc/libcd/api/CustomOutputRecipe.java new file mode 100644 index 000000000..6588e5b71 --- /dev/null +++ b/RebornCore/src/main/java/io/github/cottonmc/libcd/api/CustomOutputRecipe.java @@ -0,0 +1,37 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package io.github.cottonmc.libcd.api; + +import net.minecraft.item.Item; + +import java.util.Collection; + +/** + * A recipe that has output behavior that cannot be described by just the Recipe#getOutput() method. + * Used for RecipeTweaker remove-by-output code. + */ +public interface CustomOutputRecipe { + Collection getOutputItems(); +} diff --git a/RebornCore/src/main/java/reborncore/Distribution.java b/RebornCore/src/main/java/reborncore/Distribution.java new file mode 100644 index 000000000..26042ab70 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/Distribution.java @@ -0,0 +1,40 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore; + +import net.fabricmc.api.EnvType; + +public enum Distribution { + UNIVERSAL, + CLIENT, + SERVER; + + public boolean isInvalid() { + if (this == UNIVERSAL) { + return false; + } + return RebornCore.getSide() == EnvType.CLIENT && this == CLIENT; + } +} diff --git a/RebornCore/src/main/java/reborncore/RebornCore.java b/RebornCore/src/main/java/reborncore/RebornCore.java new file mode 100644 index 000000000..49a1b02de --- /dev/null +++ b/RebornCore/src/main/java/reborncore/RebornCore.java @@ -0,0 +1,129 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.lifecycle.v1.ServerBlockEntityEvents; +import net.fabricmc.fabric.api.event.world.WorldTickCallback; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.util.Identifier; +import org.apache.logging.log4j.LogManager; +import org.apache.logging.log4j.Logger; +import reborncore.api.ToolManager; +import reborncore.api.blockentity.UnloadHandler; +import reborncore.common.RebornCoreCommands; +import reborncore.common.RebornCoreConfig; +import reborncore.common.blocks.BlockWrenchEventHandler; +import reborncore.common.config.Configuration; +import reborncore.common.crafting.ingredient.IngredientManager; +import reborncore.common.fluid.RebornFluidManager; +import reborncore.common.misc.ModSounds; +import reborncore.common.misc.RebornCoreTags; +import reborncore.common.multiblock.MultiblockRegistry; +import reborncore.common.network.ServerBoundPackets; +import reborncore.common.powerSystem.PowerSystem; +import reborncore.common.util.CalenderUtils; +import reborncore.common.util.GenericWrenchHelper; + +import java.io.File; +import java.util.function.Supplier; + +public class RebornCore implements ModInitializer { + + public static final String MOD_NAME = "Reborn Core"; + public static final String MOD_ID = "reborncore"; + public static final String MOD_VERSION = "@MODVERSION@"; + public static final String WEB_URL = "https://files.modmuss50.me/"; + + public static final Logger LOGGER = LogManager.getFormatterLogger(MOD_ID); + public static File configDir; + + public static boolean LOADED = false; + + public RebornCore() { + + } + + @Override + public void onInitialize() { + new Configuration(RebornCoreConfig.class, MOD_ID); + PowerSystem.init(); + CalenderUtils.loadCalender(); //Done early as some features need this + + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("ic2:wrench"), true)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("forestry:wrench"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("actuallyadditions:item_laser_wrench"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("thermalfoundation:wrench"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("charset:wrench"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("teslacorelib:wrench"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("rftools:smartwrench"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("intergrateddynamics:smartwrench"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("correlated:weldthrower"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("chiselsandbits:wrench_wood"), false)); + ToolManager.INSTANCE.customToolHandlerList.add(new GenericWrenchHelper(new Identifier("redstonearsenal:tool.wrench_flux"), false)); + + ModSounds.setup(); + BlockWrenchEventHandler.setup(); + + /* + This is a generic multiblock tick handler. If you are using this code on your + own, you will need to register this with the Forge TickRegistry on both the + client AND server sides. Note that different types of ticks run on different + parts of the system. CLIENT ticks only run on the client, at the start/end of + each game loop. SERVER and WORLD ticks only run on the server. WORLDLOAD + ticks run only on the server, and only when worlds are loaded. + */ + WorldTickCallback.EVENT.register(MultiblockRegistry::tickStart); + + // packets + ServerBoundPackets.init(); + + IngredientManager.setup(); + RebornFluidManager.setupBucketMap(); + + RebornCoreCommands.setup(); + + RebornCoreTags.WATER_EXPLOSION_ITEM.toString(); + + /* register UnloadHandler */ + ServerBlockEntityEvents.BLOCK_ENTITY_UNLOAD.register((blockEntity, world) -> { + if (blockEntity instanceof UnloadHandler) ((UnloadHandler) blockEntity).onUnload(); + }); + + LOGGER.info("Reborn core is done for now, now to let other mods have their turn..."); + LOADED = true; + } + + public static EnvType getSide() { + return FabricLoader.getInstance().getEnvironmentType(); + } + + public static void clientOnly(Supplier runnable){ + if(FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT){ + runnable.get().run(); + } + } +} diff --git a/RebornCore/src/main/java/reborncore/RebornCoreClient.java b/RebornCore/src/main/java/reborncore/RebornCoreClient.java new file mode 100644 index 000000000..0315c9250 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/RebornCoreClient.java @@ -0,0 +1,57 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore; + +import net.fabricmc.api.ClientModInitializer; +import net.fabricmc.fabric.api.client.event.lifecycle.v1.ClientBlockEntityEvents; +import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; +import net.minecraft.client.texture.SpriteAtlasTexture; +import reborncore.api.blockentity.UnloadHandler; +import reborncore.client.HolidayRenderManager; +import reborncore.client.IconSupplier; +import reborncore.client.ItemStackRenderer; +import reborncore.client.StackToolTipHandler; +import reborncore.common.fluid.RebornFluidRenderManager; +import reborncore.common.network.ClientBoundPacketHandlers; + +public class RebornCoreClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + RebornFluidRenderManager.setupClient(); + HolidayRenderManager.setupClient(); + ClientSpriteRegistryCallback.event(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).register(IconSupplier::registerSprites); + ClientBoundPacketHandlers.init(); + HudRenderCallback.EVENT.register(new ItemStackRenderer()); + ItemTooltipCallback.EVENT.register(new StackToolTipHandler()); + + /* register UnloadHandler */ + ClientBlockEntityEvents.BLOCK_ENTITY_UNLOAD.register((blockEntity, world) -> { + if (blockEntity instanceof UnloadHandler) ((UnloadHandler) blockEntity).onUnload(); + }); + } +} diff --git a/RebornCore/src/main/java/reborncore/RebornRegistry.java b/RebornCore/src/main/java/reborncore/RebornRegistry.java new file mode 100644 index 000000000..3be543b2b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/RebornRegistry.java @@ -0,0 +1,135 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore; + +import net.minecraft.block.Block; +import net.minecraft.item.BlockItem; +import net.minecraft.item.Item; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import org.apache.commons.lang3.Validate; + +import java.util.HashMap; +import java.util.function.Function; + +/** + * Created by Gigabit101 on 16/08/2016. + */ +public class RebornRegistry { + //public static LootManager.InnerPool lp = new LootManager.InnerPool(); + + //Yeah, this is horrible + private static final HashMap objIdentMap = new HashMap<>(); + + /** + * Registers Block and BlockItem in vanilla registries + * + * @param block Block Block to register + * @param builder Item.Settings Settings builder for BlockItem + * @param name Identifier Registry name for block and item + */ + public static void registerBlock(Block block, Item.Settings builder, Identifier name) { + Registry.register(Registry.BLOCK, name, block); + BlockItem itemBlock = new BlockItem(block, builder); + Registry.register(Registry.ITEM, name, itemBlock); + } + + public static void registerBlock(Block block, Function blockItemFunction, Identifier name) { + Registry.register(Registry.BLOCK, name, block); + BlockItem itemBlock = blockItemFunction.apply(block); + Registry.register(Registry.ITEM, name, itemBlock); + } + + /** + * Registers Block and BlockItem in vanilla registries. + * Block should have registered identifier in RebornRegistry via {@link #registerIdent registerIdent} method + * + * @param block Block Block to register + * @param itemGroup Item.Settings Settings builder for BlockItem + */ + public static void registerBlock(Block block, Item.Settings itemGroup) { + Validate.isTrue(objIdentMap.containsKey(block)); + registerBlock(block, itemGroup, objIdentMap.get(block)); + } + + public static void registerBlock(Block block, Function blockItemFunction){ + Validate.isTrue(objIdentMap.containsKey(block)); + registerBlock(block, blockItemFunction, objIdentMap.get(block)); + } + + /** + * Register only Block, without BlockItem in vanilla registries + * Block should have registered identifier in RebornRegistry via {@link #registerIdent registerIdent} method + * @param block Block Block to register + */ + public static void registerBlockNoItem(Block block) { + Validate.isTrue(objIdentMap.containsKey(block)); + Registry.register(Registry.BLOCK, objIdentMap.get(block), block); + } + + + /** + * Register Item in vanilla registries + * + * @param item Item Item to register + * @param name Identifier Registry name for item + */ + public static void registerItem(Item item, Identifier name) { + Registry.register(Registry.ITEM, name, item); + } + + /** + * Register Item in vanilla registries + * Item should have registered identifier in RebornRegistry via {@link #registerIdent registerIdent} method + * + * @param item Item Item to register + */ + public static void registerItem(Item item){ + Validate.isTrue(objIdentMap.containsKey(item)); + registerItem(item, objIdentMap.get(item)); + } + + /** + * Registers Identifier in internal RebornCore map + * + * @param object Object Item, Block or whatever to be put into map + * @param identifier Identifier Registry name for object + */ + public static void registerIdent(Object object, Identifier identifier){ + objIdentMap.put(object, identifier); + } + + //eg: RebornRegistry.addLoot(Items.NETHER_STAR, 0.95, LootTableList.CHESTS_VILLAGE_BLACKSMITH); + //eg: RebornRegistry.addLoot(Items.DIAMOND, 1.95, LootTableList.ENTITIES_COW); + + public static void addLoot(Item item, double chance, Identifier list) { + // lp.addItem(LootManager.createLootEntry(item, chance, list)); + } + + public static void addLoot(Item item, int minSize, int maxSize, double chance, Identifier list) { + // lp.addItem(LootManager.createLootEntry(item, minSize, maxSize, chance, list)); + } + +} diff --git a/RebornCore/src/main/java/reborncore/api/ICustomToolHandler.java b/RebornCore/src/main/java/reborncore/api/ICustomToolHandler.java new file mode 100644 index 000000000..65741085e --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/ICustomToolHandler.java @@ -0,0 +1,33 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api; + +import net.minecraft.item.ItemStack; + +public interface ICustomToolHandler extends IToolHandler { + + boolean canHandleTool(ItemStack stack); + +} diff --git a/RebornCore/src/main/java/reborncore/api/IListInfoProvider.java b/RebornCore/src/main/java/reborncore/api/IListInfoProvider.java new file mode 100644 index 000000000..05d306b42 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/IListInfoProvider.java @@ -0,0 +1,35 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api; + +import net.minecraft.text.Text; + +import java.util.List; + +public interface IListInfoProvider { + + void addInfo(List info, boolean isReal, boolean hasData); + +} diff --git a/RebornCore/src/main/java/reborncore/api/IToolDrop.java b/RebornCore/src/main/java/reborncore/api/IToolDrop.java new file mode 100644 index 000000000..ddf0440a2 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/IToolDrop.java @@ -0,0 +1,33 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; + +public interface IToolDrop { + + ItemStack getToolDrop(PlayerEntity p0); +} diff --git a/RebornCore/src/main/java/reborncore/api/IToolHandler.java b/RebornCore/src/main/java/reborncore/api/IToolHandler.java new file mode 100644 index 000000000..d3f6aaeb4 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/IToolHandler.java @@ -0,0 +1,51 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; + +/** + * Added onto an item + */ +public interface IToolHandler { + + /** + * Called when a machine is actived with the item that has IToolHandler on it + * + * @param stack the held itemstack + * @param pos the pos of the block + * @param world the world of the block + * @param player the player that actived the block + * @param side the side that the player actived + * @param damage if the tool should be damged, or power taken + * @return If the tool can handle being actived on the block, return false when the tool is broken or out of power for example. + */ + boolean handleTool(ItemStack stack, BlockPos pos, World world, PlayerEntity player, Direction side, boolean damage); + +} diff --git a/RebornCore/src/main/java/reborncore/api/ToolManager.java b/RebornCore/src/main/java/reborncore/api/ToolManager.java new file mode 100644 index 000000000..1a5e2e59a --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/ToolManager.java @@ -0,0 +1,72 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; + +import java.util.ArrayList; +import java.util.List; + +public class ToolManager implements ICustomToolHandler { + + public static final ToolManager INSTANCE = new ToolManager(); + public List customToolHandlerList = new ArrayList<>(); + + @Override + public boolean handleTool(ItemStack stack, BlockPos pos, World world, PlayerEntity player, Direction side, boolean damage) { + if (stack == null || stack.isEmpty()) { + return false; + } + if (stack.getItem() instanceof IToolHandler) { + return ((IToolHandler) stack.getItem()).handleTool(stack, pos, world, player, side, damage); + } + for (ICustomToolHandler customToolHandler : customToolHandlerList) { + if (customToolHandler.canHandleTool(stack)) { + return customToolHandler.handleTool(stack, pos, world, player, side, damage); + } + } + return false; + } + + @Override + public boolean canHandleTool(ItemStack stack) { + if (stack == null || stack.isEmpty()) { + return false; + } + if (stack.getItem() instanceof IToolHandler) { + return true; + } + for (ICustomToolHandler customToolHandler : customToolHandlerList) { + if (customToolHandler.canHandleTool(stack)) { + return true; + } + } + return false; + } +} diff --git a/RebornCore/src/main/java/reborncore/api/blockentity/IMachineGuiHandler.java b/RebornCore/src/main/java/reborncore/api/blockentity/IMachineGuiHandler.java new file mode 100644 index 000000000..21fe2033b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/blockentity/IMachineGuiHandler.java @@ -0,0 +1,35 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.blockentity; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public interface IMachineGuiHandler { + + void open(PlayerEntity player, BlockPos pos, World world); + +} diff --git a/RebornCore/src/main/java/reborncore/api/blockentity/IUpgrade.java b/RebornCore/src/main/java/reborncore/api/blockentity/IUpgrade.java new file mode 100644 index 000000000..27b76ccf1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/blockentity/IUpgrade.java @@ -0,0 +1,48 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.blockentity; + +import net.minecraft.item.ItemStack; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.recipes.IUpgradeHandler; + +/** + * Added to an item to say that it is a valid behavior + */ +public interface IUpgrade { + + void process( + @NotNull MachineBaseBlockEntity machineBase, + @Nullable + IUpgradeHandler handler, + @NotNull + ItemStack stack); + + default boolean isValidForInventory(IUpgradeable upgradeable, ItemStack stack) { + return true; + } +} diff --git a/RebornCore/src/main/java/reborncore/api/blockentity/IUpgradeable.java b/RebornCore/src/main/java/reborncore/api/blockentity/IUpgradeable.java new file mode 100644 index 000000000..84538497c --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/blockentity/IUpgradeable.java @@ -0,0 +1,44 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.blockentity; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; + +public interface IUpgradeable { + + default boolean canBeUpgraded() { + return true; + } + + Inventory getUpgradeInvetory(); + + int getUpgradeSlotCount(); + + default boolean isUpgradeValid(IUpgrade upgrade, ItemStack stack) { + return true; + } + +} diff --git a/RebornCore/src/main/java/reborncore/api/blockentity/InventoryProvider.java b/RebornCore/src/main/java/reborncore/api/blockentity/InventoryProvider.java new file mode 100644 index 000000000..068ab4668 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/blockentity/InventoryProvider.java @@ -0,0 +1,33 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.blockentity; + +import net.minecraft.inventory.Inventory; + +public interface InventoryProvider { + + Inventory getInventory(); + +} diff --git a/RebornCore/src/main/java/reborncore/api/blockentity/UnloadHandler.java b/RebornCore/src/main/java/reborncore/api/blockentity/UnloadHandler.java new file mode 100644 index 000000000..916af8c55 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/blockentity/UnloadHandler.java @@ -0,0 +1,31 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.blockentity; + +public interface UnloadHandler { + + void onUnload(); + +} diff --git a/RebornCore/src/main/java/reborncore/api/events/ApplyArmorToDamageCallback.java b/RebornCore/src/main/java/reborncore/api/events/ApplyArmorToDamageCallback.java new file mode 100644 index 000000000..0ac2dea1e --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/events/ApplyArmorToDamageCallback.java @@ -0,0 +1,53 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.events; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerEntity; + +public interface ApplyArmorToDamageCallback { + + Event EVENT = EventFactory.createArrayBacked(ApplyArmorToDamageCallback.class, + (listeners) -> (player, damageSource, amount) -> { + float damageAmount = amount; + for (ApplyArmorToDamageCallback listener : listeners){ + damageAmount = listener.applyArmorToDamage(player, damageSource, damageAmount); + } + return damageAmount; + }); + + /** + * Apply armor to amount of damage inflicted. Decreases it in most cases unless armor should increase damage inflicted. + * Event is called after damage is being reduced by armor already and before damage reduction from enchants. + * + * @param player PlayerEntity Player being damaged + * @param source DamageSource Type of damage + * @param amount float Current amount of damage + * @return float Amount of damage after reduction + */ + float applyArmorToDamage(PlayerEntity player, DamageSource source, float amount); +} diff --git a/RebornCore/src/main/java/reborncore/api/events/ItemCraftCallback.java b/RebornCore/src/main/java/reborncore/api/events/ItemCraftCallback.java new file mode 100644 index 000000000..f2b675e73 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/events/ItemCraftCallback.java @@ -0,0 +1,44 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.events; + +import net.fabricmc.fabric.api.event.Event; +import net.fabricmc.fabric.api.event.EventFactory; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; + + +public interface ItemCraftCallback { + + Event EVENT = EventFactory.createArrayBacked(ItemCraftCallback.class, (listeners) -> (stack, craftingInventory, playerEntity) -> { + for (ItemCraftCallback callback : listeners) { + callback.onCraft(stack, craftingInventory, playerEntity); + } + }); + + void onCraft(ItemStack stack, CraftingInventory craftingInventory, PlayerEntity playerEntity); + +} diff --git a/RebornCore/src/main/java/reborncore/api/items/ArmorFovHandler.java b/RebornCore/src/main/java/reborncore/api/items/ArmorFovHandler.java new file mode 100644 index 000000000..36dfa6eb9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/items/ArmorFovHandler.java @@ -0,0 +1,33 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.items; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; + +public interface ArmorFovHandler { + + float changeFov(float old, ItemStack stack, PlayerEntity playerEntity); +} diff --git a/RebornCore/src/main/java/reborncore/api/items/ArmorRemoveHandler.java b/RebornCore/src/main/java/reborncore/api/items/ArmorRemoveHandler.java new file mode 100644 index 000000000..b6504d9b0 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/items/ArmorRemoveHandler.java @@ -0,0 +1,33 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.items; + +import net.minecraft.entity.player.PlayerEntity; + +public interface ArmorRemoveHandler { + + void onRemoved(PlayerEntity playerEntity); + +} diff --git a/RebornCore/src/main/java/reborncore/api/items/ArmorTickable.java b/RebornCore/src/main/java/reborncore/api/items/ArmorTickable.java new file mode 100644 index 000000000..620050c2d --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/items/ArmorTickable.java @@ -0,0 +1,33 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.items; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; + +public interface ArmorTickable { + + void tickArmor(ItemStack stack, PlayerEntity playerEntity); +} diff --git a/RebornCore/src/main/java/reborncore/api/items/InventoryBase.java b/RebornCore/src/main/java/reborncore/api/items/InventoryBase.java new file mode 100644 index 000000000..0e8ac0df7 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/items/InventoryBase.java @@ -0,0 +1,113 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.items; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventories; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; +import net.minecraft.util.collection.DefaultedList; + +public abstract class InventoryBase implements Inventory { + + private final int size; + private DefaultedList stacks; + + public InventoryBase(int size) { + this.size = size; + stacks = DefaultedList.ofSize(size, ItemStack.EMPTY); + } + + public Tag serializeNBT() { + CompoundTag tag = new CompoundTag(); + Inventories.toTag(tag, stacks); + return tag; + } + + public void deserializeNBT(CompoundTag tag) { + stacks = DefaultedList.ofSize(size, ItemStack.EMPTY); + Inventories.fromTag(tag, stacks); + } + + @Override + public int size() { + return size; + } + + @Override + public boolean isEmpty() { + return stacks.stream().allMatch(ItemStack::isEmpty); + } + + @Override + public ItemStack getStack(int i) { + return stacks.get(i); + } + + @Override + public ItemStack removeStack(int i, int i1) { + ItemStack stack = Inventories.splitStack(stacks, i, i1); + if (!stack.isEmpty()) { + this.markDirty(); + } + return stack; + } + + @Override + public ItemStack removeStack(int i) { + return Inventories.removeStack(stacks, i); + } + + @Override + public void setStack(int i, ItemStack itemStack) { + stacks.set(i, itemStack); + if (itemStack.getCount() > this.getMaxCountPerStack()) { + itemStack.setCount(this.getMaxCountPerStack()); + } + + this.markDirty(); + } + + @Override + public void markDirty() { + //Stuff happens in the super methods + } + + @Override + public boolean canPlayerUse(PlayerEntity playerEntity) { + return true; + } + + @Override + public void clear() { + stacks.clear(); + } + + public DefaultedList getStacks() { + return stacks; + } +} diff --git a/RebornCore/src/main/java/reborncore/api/items/InventoryUtils.java b/RebornCore/src/main/java/reborncore/api/items/InventoryUtils.java new file mode 100644 index 000000000..0fbfdf3a4 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/items/InventoryUtils.java @@ -0,0 +1,129 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.items; + +import net.minecraft.block.*; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.ChestBlockEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import reborncore.common.util.ItemUtils; + +import org.jetbrains.annotations.Nullable; + +public class InventoryUtils { + + public static ItemStack insertItemStacked(Inventory inventory, ItemStack input, boolean simulate) { + ItemStack stack = input.copy(); + for (int i = 0; i < inventory.size(); i++) { + ItemStack targetStack = inventory.getStack(i); + + //Nice and simple, insert the item into a blank slot + if (targetStack.isEmpty()) { + if (!simulate) { + inventory.setStack(i, stack); + } + return ItemStack.EMPTY; + } else if (ItemUtils.isItemEqual(stack, targetStack, true, false)) { + int freeStackSpace = targetStack.getMaxCount() - targetStack.getCount(); + if (freeStackSpace > 0) { + int transferAmount = Math.min(freeStackSpace, input.getCount()); + if (!simulate) { + targetStack.increment(transferAmount); + } + stack.decrement(transferAmount); + } + } + } + return stack; + } + + public static ItemStack insertItem(ItemStack input, Inventory inventory, Direction direction) { + ItemStack stack = input.copy(); + + if (inventory instanceof SidedInventory) { + SidedInventory sidedInventory = (SidedInventory) inventory; + for (int slot : sidedInventory.getAvailableSlots(direction)) { + if (sidedInventory.canInsert(slot, stack, direction)) { + stack = insertIntoInv(sidedInventory, slot, stack); + if (stack.isEmpty()) { + break; + } + } + } + return stack; + } else { + for (int i = 0; i < inventory.size() & !stack.isEmpty(); i++) { + if (inventory.isValid(i, stack)) { + stack = insertIntoInv(inventory, i, stack); + } + } + } + return stack; + } + + @Nullable + public static Inventory getInventoryAt(World world, BlockPos blockPos) { + Inventory inventory = null; + BlockState blockState = world.getBlockState(blockPos); + Block block = blockState.getBlock(); + if (block instanceof InventoryProvider) { + inventory = ((InventoryProvider) block).getInventory(blockState, world, blockPos); + } else if (block instanceof BlockEntityProvider) { + BlockEntity blockEntity = world.getBlockEntity(blockPos); + if (blockEntity instanceof Inventory) { + inventory = (Inventory) blockEntity; + if (inventory instanceof ChestBlockEntity && block instanceof ChestBlock) { + inventory = ChestBlock.getInventory((ChestBlock) block, blockState, world, blockPos, true); + } + } + } + return inventory; + } + + private static ItemStack insertIntoInv(Inventory inventory, int slot, ItemStack input) { + ItemStack targetStack = inventory.getStack(slot); + ItemStack stack = input.copy(); + + //Nice and simple, insert the item into a blank slot + if (targetStack.isEmpty()) { + inventory.setStack(slot, stack); + return ItemStack.EMPTY; + } else if (ItemUtils.isItemEqual(stack, targetStack, true, false)) { + int freeStackSpace = targetStack.getMaxCount() - targetStack.getCount(); + if (freeStackSpace > 0) { + int transferAmount = Math.min(freeStackSpace, stack.getCount()); + targetStack.increment(transferAmount); + stack.decrement(transferAmount); + } + } + + return stack; + } +} diff --git a/RebornCore/src/main/java/reborncore/api/items/ItemStackModifiers.java b/RebornCore/src/main/java/reborncore/api/items/ItemStackModifiers.java new file mode 100644 index 000000000..2f238fdb7 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/items/ItemStackModifiers.java @@ -0,0 +1,37 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.items; + +import com.google.common.collect.Multimap; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.attribute.EntityAttribute; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.item.ItemStack; + +public interface ItemStackModifiers { + + void getAttributeModifiers(EquipmentSlot slot, ItemStack stack, Multimap builder); + +} diff --git a/RebornCore/src/main/java/reborncore/api/recipe/IRecipeCrafterProvider.java b/RebornCore/src/main/java/reborncore/api/recipe/IRecipeCrafterProvider.java new file mode 100644 index 000000000..1397a7cf6 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/api/recipe/IRecipeCrafterProvider.java @@ -0,0 +1,58 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.api.recipe; + +import net.minecraft.item.ItemStack; +import reborncore.common.blockentity.SlotConfiguration; +import reborncore.common.crafting.RebornRecipe; +import reborncore.common.recipes.RecipeCrafter; + +/** + * Created by modmuss50 on 11/04/2016. + */ +public interface IRecipeCrafterProvider extends SlotConfiguration.SlotFilter { + + RecipeCrafter getRecipeCrafter(); + + default boolean canCraft(RebornRecipe rebornRecipe) { + return true; + } + + @Override + default boolean isStackValid(int slotID, ItemStack stack) { + if (getRecipeCrafter() == null) { + return false; + } + return getRecipeCrafter().isStackValidInput(stack); + } + + @Override + default int[] getInputSlots() { + if (getRecipeCrafter() == null) { + return new int[]{}; + } + return getRecipeCrafter().inputSlots; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/ClientChunkManager.java b/RebornCore/src/main/java/reborncore/client/ClientChunkManager.java new file mode 100644 index 000000000..86beb39f7 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/ClientChunkManager.java @@ -0,0 +1,106 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.util.math.BlockPos; +import reborncore.common.chunkloading.ChunkLoaderManager; +import reborncore.common.network.NetworkManager; +import reborncore.common.network.ServerBoundPackets; + +import java.util.ArrayList; +import java.util.List; + +@Environment(EnvType.CLIENT) +public class ClientChunkManager { + + private static final List loadedChunks = new ArrayList<>(); + + public static void setLoadedChunks(List chunks) { + loadedChunks.clear(); + loadedChunks.addAll(chunks); + } + + public static void toggleLoadedChunks(BlockPos chunkLoader) { + if (loadedChunks.size() == 0) { + NetworkManager.sendToServer(ServerBoundPackets.requestChunkloaderChunks(chunkLoader)); + } else { + loadedChunks.clear(); + } + } + + public static boolean hasChunksForLoader(BlockPos pos) { + return loadedChunks.stream() + .filter(loadedChunk -> loadedChunk.getChunkLoader().equals(pos)) + .anyMatch(loadedChunk -> loadedChunk.getWorld().equals(ChunkLoaderManager.getWorldName(MinecraftClient.getInstance().world))); + } + + public static void render(MatrixStack matrices, VertexConsumerProvider vertexConsumers, double x, double y, double z) { + if (loadedChunks.size() == 0) { + return; + } + final MinecraftClient minecraftClient = MinecraftClient.getInstance(); + + RenderSystem.enableDepthTest(); + RenderSystem.shadeModel(7425); + RenderSystem.enableAlphaTest(); + RenderSystem.defaultAlphaFunc(); + + final Tessellator tessellator = Tessellator.getInstance(); + final BufferBuilder bufferBuilder = tessellator.getBuffer(); + + RenderSystem.disableTexture(); + RenderSystem.disableBlend(); + RenderSystem.lineWidth(5.0F); + + bufferBuilder.begin(3, VertexFormats.POSITION_COLOR); + + loadedChunks.stream() + .filter(loadedChunk -> loadedChunk.getWorld().equals(ChunkLoaderManager.getWorldName(minecraftClient.world))) + .forEach(loadedChunk -> { + double chunkX = (double) loadedChunk.getChunk().getStartX() - x; + double chunkY = (double) loadedChunk.getChunk().getStartZ() - z; + + bufferBuilder.vertex(chunkX + 8, 0.0D - y, chunkY + 8).color(1.0F, 0.0F, 0.0F, 0.0F).next(); + bufferBuilder.vertex(chunkX + 8, 0.0D - y, chunkY + 8).color(1.0F, 0.0F, 0.0F, 0.5F).next(); + bufferBuilder.vertex(chunkX + 8, 256.0D - y, chunkY + 8).color(1.0F, 0.0F, 0.0F, 0.5F).next(); + bufferBuilder.vertex(chunkX + 8, 256.0D - y, chunkY + 8).color(1.0F, 0.0F, 0.0F, 0.0F).next(); + }); + + tessellator.draw(); + RenderSystem.lineWidth(1.0F); + RenderSystem.enableBlend(); + RenderSystem.enableTexture(); + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/HolidayRenderManager.java b/RebornCore/src/main/java/reborncore/client/HolidayRenderManager.java new file mode 100644 index 000000000..618ad2b11 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/HolidayRenderManager.java @@ -0,0 +1,84 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client; + +import net.fabricmc.fabric.api.client.rendereregistry.v1.LivingEntityFeatureRendererRegistrationCallback; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.entity.LivingEntityRenderer; +import net.minecraft.client.render.entity.feature.FeatureRenderer; +import net.minecraft.client.render.entity.feature.FeatureRendererContext; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.render.entity.model.PlayerEntityModel; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Vector3f; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.Identifier; +import reborncore.common.RebornCoreConfig; +import reborncore.common.util.CalenderUtils; + +/** + * Created by Mark on 27/11/2016. + */ +public class HolidayRenderManager { + + public static void setupClient() { + if (CalenderUtils.christmas && RebornCoreConfig.easterEggs) { + LivingEntityFeatureRendererRegistrationCallback.EVENT.register((entityType, entityRenderer, registrationHelper) -> { + if (entityRenderer.getModel() instanceof PlayerEntityModel) { + registrationHelper.register(new LayerRender(entityRenderer)); + } + }); + } + } + + private static final ModelSantaHat santaHat = new ModelSantaHat(); + private static final Identifier TEXTURE = new Identifier("reborncore", "textures/models/santa_hat.png"); + + public static class LayerRender > extends FeatureRenderer { + + public LayerRender(FeatureRendererContext context) { + super(context); + } + + @Override + public void render(MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int i, T player, float limbAngle, float limbDistance, float tickDelta, float animationProgress, float headYaw, float headPitch) { + MinecraftClient.getInstance().getTextureManager().bindTexture(TEXTURE); + VertexConsumer vertexConsumer = vertexConsumerProvider.getBuffer(RenderLayer.getEntitySolid(TEXTURE)); + matrixStack.push(); + + float yaw = player.prevYaw + (player.yaw - player.prevYaw) * tickDelta - (player.prevBodyYaw + (player.bodyYaw - player.prevBodyYaw) * tickDelta); + float pitch = player.prevPitch + (player.pitch - player.prevPitch) * tickDelta; + + matrixStack.multiply(Vector3f.POSITIVE_Y.getDegreesQuaternion(yaw)); + matrixStack.multiply(Vector3f.POSITIVE_X.getDegreesQuaternion(pitch)); + santaHat.render(matrixStack, vertexConsumer, i, LivingEntityRenderer.getOverlay(player, 0.0F), 1F, 1F, 1F, 1F); + matrixStack.pop(); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/IconSupplier.java b/RebornCore/src/main/java/reborncore/client/IconSupplier.java new file mode 100644 index 000000000..10f2c6975 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/IconSupplier.java @@ -0,0 +1,48 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.util.Identifier; +import reborncore.RebornCore; + +public class IconSupplier { + + public static Identifier armour_head_id = new Identifier(RebornCore.MOD_ID, "gui/slot_sprites/armour_head"); + public static Identifier armour_chest_id = new Identifier(RebornCore.MOD_ID, "gui/slot_sprites/armour_chest"); + public static Identifier armour_legs_id = new Identifier(RebornCore.MOD_ID, "gui/slot_sprites/armour_legs"); + public static Identifier armour_feet_id = new Identifier(RebornCore.MOD_ID, "gui/slot_sprites/armour_feet"); + + @Environment(EnvType.CLIENT) + public static void registerSprites(SpriteAtlasTexture atlasTexture, ClientSpriteRegistryCallback.Registry registry) { + registry.register(IconSupplier.armour_head_id); + registry.register(IconSupplier.armour_chest_id); + registry.register(IconSupplier.armour_legs_id); + registry.register(IconSupplier.armour_feet_id); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/ItemStackRenderManager.java b/RebornCore/src/main/java/reborncore/client/ItemStackRenderManager.java new file mode 100644 index 000000000..124f227df --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/ItemStackRenderManager.java @@ -0,0 +1,34 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client; + +import net.minecraft.item.ItemStack; + +import java.util.LinkedList; +import java.util.Queue; + +public class ItemStackRenderManager { + public static final Queue RENDER_QUEUE = new LinkedList<>(); +} diff --git a/RebornCore/src/main/java/reborncore/client/ItemStackRenderer.java b/RebornCore/src/main/java/reborncore/client/ItemStackRenderer.java new file mode 100644 index 000000000..63f1c1846 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/ItemStackRenderer.java @@ -0,0 +1,159 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import net.fabricmc.fabric.api.client.rendering.v1.HudRenderCallback; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gl.Framebuffer; +import net.minecraft.client.render.DiffuseLighting; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import org.apache.commons.io.FileUtils; +import org.lwjgl.opengl.GL11; + +import java.io.File; + +/** + * Initially take from https://github.com/JamiesWhiteShirt/developer-mode/tree/experimental-item-render and then ported to 1.15 + * Thanks 2xsaiko for fixing the lighting + odd issues above + */ +public class ItemStackRenderer implements HudRenderCallback { + + @Override + public void onHudRender(MatrixStack matrixStack, float v) { + if (!ItemStackRenderManager.RENDER_QUEUE.isEmpty()) { + + MinecraftClient.getInstance().textRenderer.draw(matrixStack, "Rendering " + ItemStackRenderManager.RENDER_QUEUE.size() + " items left", 5, 5, -1); + + ItemStack itemStack = ItemStackRenderManager.RENDER_QUEUE.poll(); + export(itemStack, 512, Registry.ITEM.getId(itemStack.getItem())); + } + } + + private void export(ItemStack stack, int size, Identifier identifier) { + File dir = new File(FabricLoader.getInstance().getGameDirectory(), "item_renderer/" + identifier.getNamespace()); + if (!dir.exists()) { + dir.mkdir(); + } + File file = new File(dir, identifier.getPath() + ".png"); + + if (file.exists()) { + file.delete(); + } + + MinecraftClient minecraft = MinecraftClient.getInstance(); + + if (minecraft.getItemRenderer() == null || minecraft.world == null) { + return; + } + + final Framebuffer framebuffer = new Framebuffer(size, size, true, MinecraftClient.IS_SYSTEM_MAC); + framebuffer.setClearColor(0.0F, 0.0F, 0.0F, 0.0F); + framebuffer.clear(MinecraftClient.IS_SYSTEM_MAC); + + framebuffer.beginWrite(true); + + final ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer(); + final BakedModel model = itemRenderer.getHeldItemModel(stack, minecraft.world, minecraft.player); + + RenderSystem.matrixMode(GL11.GL_PROJECTION); + RenderSystem.pushMatrix(); + RenderSystem.loadIdentity(); + RenderSystem.ortho(-1, 1, 1, -1, -100.0, 100.0); + RenderSystem.matrixMode(GL11.GL_MODELVIEW); + RenderSystem.pushMatrix(); + RenderSystem.loadIdentity(); + + { + minecraft.getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE); + minecraft.getTextureManager().getTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).setFilter(false, false); + + RenderSystem.enableRescaleNormal(); + RenderSystem.enableAlphaTest(); + RenderSystem.defaultAlphaFunc(); + RenderSystem.enableBlend(); + RenderSystem.enableDepthTest(); + RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA); + + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + MatrixStack matrixStack = new MatrixStack(); + + matrixStack.scale(2F, -2F, 1F); + + boolean frontLit = !model.isSideLit(); + if (frontLit) { + DiffuseLighting.disableGuiDepthLighting(); + } + + VertexConsumerProvider.Immediate immediate = MinecraftClient.getInstance().getBufferBuilders().getEntityVertexConsumers(); + itemRenderer.renderItem(stack, ModelTransformation.Mode.GUI, false, matrixStack, immediate, 15728880, OverlayTexture.DEFAULT_UV, model); + immediate.draw(); + + RenderSystem.enableDepthTest(); + + if (frontLit) { + DiffuseLighting.enableGuiDepthLighting(); + } + + RenderSystem.disableAlphaTest(); + RenderSystem.disableRescaleNormal(); + } + + RenderSystem.popMatrix(); + RenderSystem.matrixMode(GL11.GL_PROJECTION); + RenderSystem.popMatrix(); + RenderSystem.matrixMode(GL11.GL_MODELVIEW); + + framebuffer.endWrite(); + + + try (NativeImage nativeImage = new NativeImage(size, size, false)) { + GlStateManager.bindTexture(framebuffer.getColorAttachment()); + nativeImage.loadFromTextureImage(0, false); + nativeImage.mirrorVertically(); + + try { + byte[] bytes = nativeImage.getBytes(); + FileUtils.writeByteArrayToFile(file, bytes); + System.out.println("Wrote " + file.getAbsolutePath()); + } catch (Exception e) { + e.printStackTrace(); + } + } + framebuffer.delete(); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/ModelSantaHat.java b/RebornCore/src/main/java/reborncore/client/ModelSantaHat.java new file mode 100644 index 000000000..444812718 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/ModelSantaHat.java @@ -0,0 +1,211 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +// Date: 27/11/2016 17:33:21 +// Template version 1.1 +// Java generated by Techne +// Keep in mind that you still need to fill in some blanks +// - ZeuX + +package reborncore.client; + +import net.minecraft.client.model.ModelPart; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.entity.model.EntityModel; +import net.minecraft.client.util.math.MatrixStack; + +public class ModelSantaHat extends EntityModel { + private final ModelPart hatband1; + private final ModelPart hatband2; + private final ModelPart hatband3; + private final ModelPart hatband4; + private final ModelPart hatbase1; + private final ModelPart hatband5; + private final ModelPart hatband6; + private final ModelPart hatbase2; + private final ModelPart hatextension1; + private final ModelPart hatextension2; + private final ModelPart hatextension3; + private final ModelPart hatextension4; + private final ModelPart hatball1; + private final ModelPart hatball2; + private final ModelPart hatball3; + private final ModelPart hatball4; + private final ModelPart hatball5; + private final ModelPart hatball6; + + public ModelSantaHat() { + textureWidth = 64; + textureHeight = 64; + + hatband1 = new ModelPart(this, 0, 32); + hatband1.addCuboid(-4F, -8F, -5F, 8, 1, 1); + hatband1.setPivot(0F, 0F, 0F); + hatband1.setTextureSize(64, 64); + hatband1.mirror = true; + setRotation(hatband1, 0F, 0F, 0F); + hatband2 = new ModelPart(this, 0, 32); + hatband2.addCuboid(-4F, -8F, 4F, 8, 1, 1); + hatband2.setPivot(0F, 0F, 0F); + hatband2.setTextureSize(64, 64); + hatband2.mirror = true; + setRotation(hatband2, 0F, 0F, 0F); + hatband3 = new ModelPart(this, 0, 34); + hatband3.addCuboid(-5F, -8F, -4F, 1, 1, 8); + hatband3.setPivot(0F, 0F, 0F); + hatband3.setTextureSize(64, 64); + hatband3.mirror = true; + setRotation(hatband3, 0F, 0F, 0F); + hatband4 = new ModelPart(this, 0, 34); + hatband4.addCuboid(4F, -8F, -4F, 1, 1, 8); + hatband4.setPivot(0F, 0F, 0F); + hatband4.setTextureSize(64, 64); + hatband4.mirror = true; + setRotation(hatband4, 0F, 0F, 0F); + hatbase1 = new ModelPart(this, 0, 43); + hatbase1.addCuboid(-4F, -9F, -4F, 8, 1, 8); + hatbase1.setPivot(0F, 0F, 0F); + hatbase1.setTextureSize(64, 64); + hatbase1.mirror = true; + setRotation(hatbase1, 0F, 0F, 0F); + hatband5 = new ModelPart(this, 18, 41); + hatband5.addCuboid(0F, -7F, -5F, 4, 1, 1); + hatband5.setPivot(0F, 0F, 0F); + hatband5.setTextureSize(64, 64); + hatband5.mirror = true; + setRotation(hatband5, 0F, 0F, 0F); + hatband6 = new ModelPart(this, 18, 41); + hatband6.addCuboid(-4F, -7F, 0F, 4, 1, 1); + hatband6.setPivot(0F, 0F, 4F); + hatband6.setTextureSize(64, 64); + hatband6.mirror = true; + setRotation(hatband6, 0F, 0F, 0F); + hatbase2 = new ModelPart(this, 18, 34); + hatbase2.addCuboid(-3F, -10F, -3F, 6, 1, 6); + hatbase2.setPivot(0F, 0F, 0F); + hatbase2.setTextureSize(64, 64); + hatbase2.mirror = true; + setRotation(hatbase2, 0F, 0.1115358F, 0F); + hatextension1 = new ModelPart(this, 0, 52); + hatextension1.addCuboid(-3F, -11F, -2F, 4, 2, 4); + hatextension1.setPivot(0F, 0F, 0F); + hatextension1.setTextureSize(64, 64); + hatextension1.mirror = true; + setRotation(hatextension1, 0F, -0.0371786F, 0.0743572F); + hatextension2 = new ModelPart(this, 16, 52); + hatextension2.addCuboid(-2.4F, -12F, -1.5F, 3, 2, 3); + hatextension2.setPivot(0F, 0F, 0F); + hatextension2.setTextureSize(64, 64); + hatextension2.mirror = true; + setRotation(hatextension2, 0F, 0.0743572F, 0.0743572F); + hatextension3 = new ModelPart(this, 28, 52); + hatextension3.addCuboid(-3.5F, -13F, -1F, 2, 2, 2); + hatextension3.setPivot(0F, 0F, 0F); + hatextension3.setTextureSize(64, 64); + hatextension3.mirror = true; + setRotation(hatextension3, 0F, 0F, 0.2230717F); + hatextension4 = new ModelPart(this, 0, 58); + hatextension4.addCuboid(-13F, -6.6F, -1F, 2, 3, 2); + hatextension4.setPivot(0F, 0F, 0F); + hatextension4.setTextureSize(64, 64); + hatextension4.mirror = true; + setRotation(hatextension4, 0F, 0F, 1.264073F); + hatball1 = new ModelPart(this, 8, 58); + hatball1.addCuboid(2F, -14.4F, -1.001F, 2, 2, 2); + hatball1.setPivot(0F, 0F, 0F); + hatball1.setTextureSize(64, 64); + hatball1.mirror = true; + setRotation(hatball1, 0F, 0F, 0F); + hatball2 = new ModelPart(this, 16, 57); + hatball2.addCuboid(2.5F, -14.8F, -0.5F, 1, 1, 1); + hatball2.setPivot(0F, 0F, 0F); + hatball2.setTextureSize(64, 64); + hatball2.mirror = true; + setRotation(hatball2, 0F, 0F, 0F); + hatball3 = new ModelPart(this, 16, 57); + hatball3.addCuboid(2.5F, -13F, -0.5F, 1, 1, 1); + hatball3.setPivot(0F, 0F, 0F); + hatball3.setTextureSize(64, 64); + hatball3.mirror = true; + setRotation(hatball3, 0F, 0F, 0F); + hatball4 = new ModelPart(this, 16, 57); + hatball4.addCuboid(3.4F, -14F, -0.5F, 1, 1, 1); + hatball4.setPivot(0F, 0F, 0F); + hatball4.setTextureSize(64, 64); + hatball4.mirror = true; + setRotation(hatball4, 0F, 0F, 0F); + hatball5 = new ModelPart(this, 16, 57); + hatball5.addCuboid(2.5F, -14F, 0.4F, 1, 1, 1); + hatball5.setPivot(0F, 0F, 0F); + hatball5.setTextureSize(64, 64); + hatball5.mirror = true; + setRotation(hatball5, 0F, 0F, 0F); + hatball6 = new ModelPart(this, 16, 57); + hatball6.addCuboid(2.5F, -14F, -1.4F, 1, 1, 1); + hatball6.setPivot(0F, 0F, 0F); + hatball6.setTextureSize(64, 64); + hatball6.mirror = true; + setRotation(hatball6, 0F, 0F, 0F); + } + + @Override + public void setAngles(AbstractClientPlayerEntity entity, float limbAngle, float limbDistance, float age, float headYaw, float headPitch) { + + } + + @Override + public void render(MatrixStack matrixStack, VertexConsumer vertexConsumer, int light, int overlay, float r, float g, float b, float f) { + hatband1.render(matrixStack, vertexConsumer, light, overlay); + hatband2.render(matrixStack, vertexConsumer, light, overlay); + hatband3.render(matrixStack, vertexConsumer, light, overlay); + hatband4.render(matrixStack, vertexConsumer, light, overlay); + hatbase1.render(matrixStack, vertexConsumer, light, overlay); + hatband5.render(matrixStack, vertexConsumer, light, overlay); + hatband6.render(matrixStack, vertexConsumer, light, overlay); + hatbase2.render(matrixStack, vertexConsumer, light, overlay); + hatextension1.render(matrixStack, vertexConsumer, light, overlay); + hatextension2.render(matrixStack, vertexConsumer, light, overlay); + hatextension3.render(matrixStack, vertexConsumer, light, overlay); + hatextension4.render(matrixStack, vertexConsumer, light, overlay); + hatball1.render(matrixStack, vertexConsumer, light, overlay); + hatball2.render(matrixStack, vertexConsumer, light, overlay); + hatball3.render(matrixStack, vertexConsumer, light, overlay); + hatball4.render(matrixStack, vertexConsumer, light, overlay); + hatball5.render(matrixStack, vertexConsumer, light, overlay); + hatball6.render(matrixStack, vertexConsumer, light, overlay); + } + + private void setRotation(ModelPart model, float x, float y, float z) { + model.pitch = x; + model.yaw = y; + model.roll = z; + } + + @Override + public void accept(ModelPart modelPart) { + + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/RenderUtil.java b/RebornCore/src/main/java/reborncore/client/RenderUtil.java new file mode 100644 index 000000000..bcb3d9fd1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/RenderUtil.java @@ -0,0 +1,158 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandler; +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.texture.TextureManager; +import net.minecraft.fluid.Fluid; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import org.lwjgl.opengl.GL11; +import reborncore.common.fluid.FluidValue; +import reborncore.common.fluid.container.FluidInstance; +import reborncore.common.util.Tank; + +/** + * Created by Gigabit101 on 08/08/2016. + */ +public class RenderUtil { + public static final Identifier BLOCK_TEX = SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE; + + public static TextureManager engine() { + return MinecraftClient.getInstance().getTextureManager(); + } + + public static void bindBlockTexture() { + engine().bindTexture(BLOCK_TEX); + } + + public static Sprite getStillTexture(FluidInstance fluid) { + if (fluid == null || fluid.getFluid() == null) { + return null; + } + return getStillTexture(fluid.getFluid()); + } + + public static Sprite getSprite(Identifier identifier) { + return MinecraftClient.getInstance().getSpriteAtlas(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).apply(identifier); + } + + public static Sprite getStillTexture(Fluid fluid) { + FluidRenderHandler fluidRenderHandler = FluidRenderHandlerRegistry.INSTANCE.get(fluid); + if (fluidRenderHandler != null) { + return fluidRenderHandler.getFluidSprites(MinecraftClient.getInstance().world, BlockPos.ORIGIN, fluid.getDefaultState())[0]; + } + return null; + } + + public static void renderGuiTank(Tank tank, double x, double y, double zLevel, double width, double height) { + renderGuiTank(tank.getFluidInstance(), tank.getCapacity(), tank.getFluidAmount(), x, y, zLevel, width, height); + } + + public static void renderGuiTank(FluidInstance fluid, FluidValue capacity, FluidValue amount, double x, double y, double zLevel, + double width, double height) { + if (fluid == null || fluid.getFluid() == null || fluid.getAmount().lessThanOrEqual(FluidValue.EMPTY)) { + return; + } + + Sprite icon = getStillTexture(fluid); + if (icon == null) { + return; + } + + int renderAmount = (int) Math.max(Math.min(height, amount.getRawValue() * height / capacity.getRawValue()), 1); + int posY = (int) (y + height - renderAmount); + + RenderUtil.bindBlockTexture(); + int color = 0; + GL11.glColor3ub((byte) (color >> 16 & 0xFF), (byte) (color >> 8 & 0xFF), (byte) (color & 0xFF)); + + RenderSystem.enableBlend(); + for (int i = 0; i < width; i += 16) { + for (int j = 0; j < renderAmount; j += 16) { + int drawWidth = (int) Math.min(width - i, 16); + int drawHeight = Math.min(renderAmount - j, 16); + + int drawX = (int) (x + i); + int drawY = posY + j; + + float minU = icon.getMinU(); + float maxU = icon.getMaxU(); + float minV = icon.getMinV(); + float maxV = icon.getMaxV(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder tes = tessellator.getBuffer(); + tes.begin(GL11.GL_QUADS, VertexFormats.POSITION_TEXTURE_COLOR); + tes.vertex(drawX, drawY + drawHeight, 0).texture(minU, minV + (maxV - minV) * drawHeight / 16F).next(); + tes.vertex(drawX + drawWidth, drawY + drawHeight, 0) + .texture(minU + (maxU - minU) * drawWidth / 16F, minV + (maxV - minV) * drawHeight / 16F) + .next(); + tes.vertex(drawX + drawWidth, drawY, 0).texture(minU + (maxU - minU) * drawWidth / 16F, minV).next(); + tes.vertex(drawX, drawY, 0).texture(minU, minV).next(); + tessellator.draw(); + } + } + RenderSystem.disableBlend(); + } + + public static void drawGradientRect(int zLevel, int left, int top, int right, int bottom, int startColor, int endColor) { + float f = (float) (startColor >> 24 & 255) / 255.0F; + float f1 = (float) (startColor >> 16 & 255) / 255.0F; + float f2 = (float) (startColor >> 8 & 255) / 255.0F; + float f3 = (float) (startColor & 255) / 255.0F; + float f4 = (float) (endColor >> 24 & 255) / 255.0F; + float f5 = (float) (endColor >> 16 & 255) / 255.0F; + float f6 = (float) (endColor >> 8 & 255) / 255.0F; + float f7 = (float) (endColor & 255) / 255.0F; + RenderSystem.disableTexture(); + RenderSystem.enableBlend(); + RenderSystem.disableAlphaTest(); + RenderSystem.blendFuncSeparate(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA, GlStateManager.SrcFactor.ONE, GlStateManager.DstFactor.ZERO); + RenderSystem.shadeModel(7425); + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder vertexbuffer = tessellator.getBuffer(); + vertexbuffer.begin(7, VertexFormats.POSITION_COLOR); + vertexbuffer.vertex(right, top, 0).color(f1, f2, f3, f).next(); + vertexbuffer.vertex(left, top, 0).color(f1, f2, f3, f).next(); + vertexbuffer.vertex(left, bottom, 0).color(f5, f6, f7, f4).next(); + vertexbuffer.vertex(right, bottom, 0).color(f5, f6, f7, f4).next(); + tessellator.draw(); + RenderSystem.shadeModel(7424); + RenderSystem.disableBlend(); + RenderSystem.enableAlphaTest(); + RenderSystem.enableTexture(); + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/StackToolTipHandler.java b/RebornCore/src/main/java/reborncore/client/StackToolTipHandler.java new file mode 100644 index 000000000..3212f977a --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/StackToolTipHandler.java @@ -0,0 +1,134 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client; + +import net.fabricmc.fabric.api.client.item.v1.ItemTooltipCallback; +import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.item.TooltipContext; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.text.LiteralText; +import net.minecraft.text.MutableText; +import net.minecraft.text.Text; +import net.minecraft.util.Formatting; +import reborncore.RebornCore; +import reborncore.api.IListInfoProvider; +import reborncore.common.BaseBlockEntityProvider; +import reborncore.common.powerSystem.PowerSystem; +import reborncore.common.util.StringUtils; +import team.reborn.energy.Energy; +import team.reborn.energy.EnergyHolder; +import team.reborn.energy.EnergySide; + +import java.util.List; + +public class StackToolTipHandler implements ItemTooltipCallback { + + @Override + public void getTooltip(ItemStack itemStack, TooltipContext tooltipContext, List tooltipLines) { + Item item = itemStack.getItem(); + Block block = Block.getBlockFromItem(item); + + if (item instanceof IListInfoProvider) { + ((IListInfoProvider) item).addInfo(tooltipLines, false, false); + } + else if (item instanceof EnergyHolder) { + LiteralText line1 = new LiteralText(PowerSystem.getLocalizedPowerNoSuffix(Energy.of(itemStack).getEnergy())); + line1.append("/"); + line1.append(PowerSystem.getLocalizedPower(Energy.of(itemStack).getMaxStored())); + line1.formatted(Formatting.GOLD); + + tooltipLines.add(1, line1); + + if (Screen.hasShiftDown()) { + int percentage = percentage(Energy.of(itemStack).getEnergy(), Energy.of(itemStack).getMaxStored()); + MutableText line2 = StringUtils.getPercentageText(percentage); + line2.append(" "); + line2.formatted(Formatting.GRAY); + line2.append(I18n.translate("reborncore.gui.tooltip.power_charged")); + tooltipLines.add(2, line2); + + double inputRate = ((EnergyHolder) item).getMaxInput(EnergySide.UNKNOWN); + double outputRate = ((EnergyHolder) item).getMaxOutput(EnergySide.UNKNOWN); + LiteralText line3 = new LiteralText(""); + if (inputRate != 0 && inputRate == outputRate){ + line3.append(I18n.translate("techreborn.tooltip.transferRate")); + line3.append(" : "); + line3.formatted(Formatting.GRAY); + line3.append(PowerSystem.getLocalizedPower(inputRate)); + line3.formatted(Formatting.GOLD); + } + else if(inputRate != 0){ + line3.append(I18n.translate("reborncore.tooltip.energy.inputRate")); + line3.append(" : "); + line3.formatted(Formatting.GRAY); + line3.append(PowerSystem.getLocalizedPower(inputRate)); + line3.formatted(Formatting.GOLD); + } + else if (outputRate !=0){ + line3.append(I18n.translate("reborncore.tooltip.energy.outputRate")); + line3.append(" : "); + line3.formatted(Formatting.GRAY); + line3.append(PowerSystem.getLocalizedPower(outputRate)); + line3.formatted(Formatting.GOLD); + } + tooltipLines.add(3, line3); + } + } + else { + try { + if ((block instanceof BaseBlockEntityProvider)) { + BlockEntity blockEntity = ((BlockEntityProvider) block).createBlockEntity(MinecraftClient.getInstance().world); + boolean hasData = false; + if (itemStack.hasTag() && itemStack.getOrCreateTag().contains("blockEntity_data")) { + CompoundTag blockEntityData = itemStack.getOrCreateTag().getCompound("blockEntity_data"); + if (blockEntity != null) { + blockEntity.fromTag(block.getDefaultState(), blockEntityData); + hasData = true; + tooltipLines.add(new LiteralText(I18n.translate("reborncore.tooltip.has_data")).formatted(Formatting.DARK_GREEN)); + } + } + if (blockEntity instanceof IListInfoProvider) { + ((IListInfoProvider) blockEntity).addInfo(tooltipLines, false, hasData); + } + } + } catch (NullPointerException e) { + RebornCore.LOGGER.debug("Failed to load info for " + itemStack.getName()); + } + } + } + + private int percentage(double CurrentValue, double MaxValue) { + if (CurrentValue == 0) + return 0; + return (int) ((CurrentValue * 100.0f) / MaxValue); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/GuiButtonCustomTexture.java b/RebornCore/src/main/java/reborncore/client/gui/GuiButtonCustomTexture.java new file mode 100644 index 000000000..9b405e570 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/GuiButtonCustomTexture.java @@ -0,0 +1,103 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.render.DiffuseLighting; +import net.minecraft.client.texture.TextureManager; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import org.lwjgl.opengl.GL11; +import reborncore.common.util.Color; + +public class GuiButtonCustomTexture extends ButtonWidget { + public int textureU; + public int textureV; + public String texturename; + public String linkedPage; + public Text name; + public String imageprefix = "techreborn:textures/manual/elements/"; + public int buttonHeight; + public int buttonWidth; + public int buttonU; + public int buttonV; + public int textureH; + public int textureW; + + public GuiButtonCustomTexture(int xPos, int yPos, int u, int v, int buttonWidth, int buttonHeight, + String texturename, String linkedPage, Text name, int buttonU, int buttonV, int textureH, int textureW, ButtonWidget.PressAction pressAction) { + super(xPos, yPos, buttonWidth, buttonHeight, LiteralText.EMPTY, pressAction); + this.textureU = u; + this.textureV = v; + this.texturename = texturename; + this.name = name; + this.linkedPage = linkedPage; + this.buttonHeight = height; + this.buttonWidth = width; + this.buttonU = buttonU; + this.buttonV = buttonV; + this.textureH = textureH; + this.textureW = textureW; + } + + public void drawButton(MatrixStack matrixStack, MinecraftClient mc, int mouseX, int mouseY) { + if (this.visible) { + boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width + && mouseY < this.y + this.height; + mc.getTextureManager().bindTexture(WIDGETS_LOCATION); + int u = textureU; + int v = textureV; + + if (flag) { + u += width; + GL11.glPushMatrix(); + GL11.glColor4f(0f, 0f, 0f, 1f); + this.drawTexture(matrixStack, this.x, this.y, u, v, width, height); + GL11.glPopMatrix(); + } + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glEnable(32826); + DiffuseLighting.enable(); + renderImage(matrixStack, this.x, this.y); + this.drawTextWithShadow(matrixStack, mc.textRenderer, this.name, this.x + 20, this.y + 3, + Color.WHITE.getColor()); + } + } + + public void renderImage(MatrixStack matrixStack, int offsetX, int offsetY) { + TextureManager render = MinecraftClient.getInstance().getTextureManager(); + render.bindTexture(new Identifier(imageprefix + this.texturename + ".png")); + + GL11.glEnable(GL11.GL_BLEND); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + GL11.glColor4f(1F, 1F, 1F, 1F); + drawTexture(matrixStack, offsetX, offsetY, this.buttonU, this.buttonV, this.textureW, this.textureH); + GL11.glDisable(GL11.GL_BLEND); + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/GuiButtonItemTexture.java b/RebornCore/src/main/java/reborncore/client/gui/GuiButtonItemTexture.java new file mode 100644 index 000000000..d71188972 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/GuiButtonItemTexture.java @@ -0,0 +1,83 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.render.DiffuseLighting; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import org.lwjgl.opengl.GL11; +import reborncore.common.util.Color; + +public class GuiButtonItemTexture extends ButtonWidget { + + public int textureU; + public int textureV; + public ItemStack itemstack; + public String LINKED_PAGE; + public Text NAME; + + public GuiButtonItemTexture(int xPos, int yPos, int u, int v, int width, int height, ItemStack stack, + String linkedPage, Text name, ButtonWidget.PressAction pressAction) { + super(xPos, yPos, width, height, LiteralText.EMPTY, pressAction); + textureU = u; + textureV = v; + itemstack = stack; + NAME = name; + this.LINKED_PAGE = linkedPage; + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float ticks) { + if (this.visible) { + MinecraftClient mc = MinecraftClient.getInstance(); + boolean flag = mouseX >= this.x && mouseY >= this.y && mouseX < this.x + this.width + && mouseY < this.y + this.height; + mc.getTextureManager().bindTexture(WIDGETS_LOCATION); + int u = textureU; + int v = textureV; + if (flag) { + u += mc.textRenderer.getWidth(this.NAME) + 25; + v += mc.textRenderer.getWidth(this.NAME) + 25; + GL11.glPushMatrix(); + GL11.glColor4f(0f, 0f, 0f, 1f); + this.drawTexture(matrixStack, this.x, this.y, u, v, mc.textRenderer.getWidth(this.NAME) + 25, height); + GL11.glPopMatrix(); + } + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + GL11.glEnable(32826); + DiffuseLighting.enable(); + ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer(); + itemRenderer.renderGuiItemIcon(itemstack, this.x, this.y); + this.drawTextWithShadow(matrixStack, mc.textRenderer, this.NAME, this.x + 20, this.y + 3, + Color.WHITE.getColor()); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/GuiUtil.java b/RebornCore/src/main/java/reborncore/client/gui/GuiUtil.java new file mode 100644 index 000000000..05b3ef977 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/GuiUtil.java @@ -0,0 +1,50 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui; + +import reborncore.client.RenderUtil; + +public class GuiUtil { + public static void drawTooltipBox(int x, int y, int w, int h) { + int bg = 0xf0100010; + drawGradientRect(x + 1, y, w - 1, 1, bg, bg); + drawGradientRect(x + 1, y + h, w - 1, 1, bg, bg); + drawGradientRect(x + 1, y + 1, w - 1, h - 1, bg, bg);// center + drawGradientRect(x, y + 1, 1, h - 1, bg, bg); + drawGradientRect(x + w, y + 1, 1, h - 1, bg, bg); + int grad1 = 0x505000ff; + int grad2 = 0x5028007F; + drawGradientRect(x + 1, y + 2, 1, h - 3, grad1, grad2); + drawGradientRect(x + w - 1, y + 2, 1, h - 3, grad1, grad2); + + drawGradientRect(x + 1, y + 1, w - 1, 1, grad1, grad1); + drawGradientRect(x + 1, y + h - 1, w - 1, 1, grad2, grad2); + } + + public static void drawGradientRect(int x, int y, int w, int h, int colour1, int colour2) { + RenderUtil.drawGradientRect(0, x, y, x + w, y + h, colour1, colour2); + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/GuiBase.java b/RebornCore/src/main/java/reborncore/client/gui/builder/GuiBase.java new file mode 100644 index 000000000..565ca327b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/GuiBase.java @@ -0,0 +1,459 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.client.gui.widget.AbstractButtonWidget; +import net.minecraft.client.resource.language.I18n; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Util; +import org.lwjgl.glfw.GLFW; +import reborncore.api.blockentity.IUpgradeable; +import reborncore.client.gui.builder.slot.FluidConfigGui; +import reborncore.client.gui.builder.slot.GuiTab; +import reborncore.client.gui.builder.slot.SlotConfigGui; +import reborncore.client.gui.builder.widget.GuiButtonHologram; +import reborncore.client.gui.guibuilder.GuiBuilder; +import reborncore.client.screen.builder.BuiltScreenHandler; +import reborncore.client.screen.builder.slot.PlayerInventorySlot; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +/** + * Created by Prospector + */ + +public class GuiBase extends HandledScreen { + + public static FluidCellProvider fluidCellProvider = fluid -> ItemStack.EMPTY; + public static ItemStack wrenchStack = ItemStack.EMPTY; + + private final List tabBuilders = Util.make(new ArrayList<>(), builders -> { + builders.add(GuiTab.Builder.builder() + .name("reborncore.gui.tooltip.config_slots") + .enabled(guiTab -> guiTab.machine().hasSlotConfig()) + .stack(guiTab -> wrenchStack) + .draw(SlotConfigGui::draw) + .click(SlotConfigGui::mouseClicked) + .mouseReleased(SlotConfigGui::mouseReleased) + .hideGuiElements() + .keyPressed((guiBase, keyCode, scanCode, modifiers) -> { + if (hasControlDown() && keyCode == GLFW.GLFW_KEY_C) { + SlotConfigGui.copyToClipboard(); + return true; + } else if (hasControlDown() && keyCode == GLFW.GLFW_KEY_V) { + SlotConfigGui.pasteFromClipboard(); + return true; + } else if (keyCode == GLFW.GLFW_KEY_ESCAPE && SlotConfigGui.selectedSlot != -1) { + SlotConfigGui.reset(); + return true; + } + return false; + }) + .tips(tips -> { + tips.add("reborncore.gui.slotconfigtip.slot"); + tips.add("reborncore.gui.slotconfigtip.side1"); + tips.add("reborncore.gui.slotconfigtip.side2"); + tips.add("reborncore.gui.slotconfigtip.side3"); + tips.add("reborncore.gui.slotconfigtip.copy1"); + tips.add("reborncore.gui.slotconfigtip.copy2"); + }) + ); + + builders.add(GuiTab.Builder.builder() + .name("reborncore.gui.tooltip.config_fluids") + .enabled(guiTab -> guiTab.machine().showTankConfig()) + .stack(guiTab -> GuiBase.fluidCellProvider.provide(Fluids.LAVA)) + .draw(FluidConfigGui::draw) + .click(FluidConfigGui::mouseClicked) + .mouseReleased(FluidConfigGui::mouseReleased) + .hideGuiElements() + ); + + builders.add(GuiTab.Builder.builder() + .name("reborncore.gui.tooltip.config_redstone") + .stack(guiTab -> new ItemStack(Items.REDSTONE)) + .draw(RedstoneConfigGui::draw) + .click(RedstoneConfigGui::mouseClicked) + ); + }); + + public GuiBuilder builder = new GuiBuilder(); + public BlockEntity be; + @Nullable + public BuiltScreenHandler builtScreenHandler; + private final int xSize = 176; + private final int ySize = 176; + + private GuiTab selectedTab; + private List tabs; + + public boolean upgrades; + + public GuiBase(PlayerEntity player, BlockEntity blockEntity, T screenHandler) { + super(screenHandler, player.inventory, new LiteralText(I18n.translate(blockEntity.getCachedState().getBlock().getTranslationKey()))); + this.be = blockEntity; + this.builtScreenHandler = (BuiltScreenHandler) screenHandler; + selectedTab = null; + populateSlots(); + } + + private void populateSlots() { + tabs = tabBuilders.stream() + .map(builder -> builder.build(getMachine(), this)) + .filter(GuiTab::enabled) + .collect(Collectors.toList()); + } + + public int getScreenWidth() { + return backgroundWidth; + } + + public void drawSlot(MatrixStack matrixStack, int x, int y, Layer layer) { + if (layer == Layer.BACKGROUND) { + x += this.x; + y += this.y; + } + builder.drawSlot(matrixStack, this, x - 1, y - 1); + } + + public void drawOutputSlotBar(MatrixStack matrixStack, int x, int y, int count, Layer layer) { + if (layer == Layer.BACKGROUND) { + x += this.x; + y += this.y; + } + builder.drawOutputSlotBar(matrixStack, this, x - 4, y - 4, count); + } + + public void drawArmourSlots(MatrixStack matrixStack, int x, int y, Layer layer) { + if (layer == Layer.BACKGROUND) { + x += this.x; + y += this.y; + } + builder.drawSlot(matrixStack, this, x - 1, y - 1); + builder.drawSlot(matrixStack, this, x - 1, y - 1 + 18); + builder.drawSlot(matrixStack, this, x - 1, y - 1 + 18 + 18); + builder.drawSlot(matrixStack, this, x - 1, y - 1 + 18 + 18 + 18); + } + + public void drawOutputSlot(MatrixStack matrixStack, int x, int y, Layer layer) { + if (layer == Layer.BACKGROUND) { + x += this.x; + y += this.y; + } + builder.drawOutputSlot(matrixStack, this, x - 5, y - 5); + } + + @Override + public void init() { + super.init(); + if (isConfigEnabled()) { + SlotConfigGui.init(this); + } + if (isConfigEnabled() && getMachine().getTank() != null && getMachine().showTankConfig()) { + FluidConfigGui.init(this); + } + } + + @Override + protected void drawBackground(MatrixStack matrixStack, float lastFrameDuration, int mouseX, int mouseY) { + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + renderBackground(matrixStack); + boolean drawPlayerSlots = selectedTab == null && drawPlayerSlots(); + updateSlotDraw(drawPlayerSlots); + builder.drawDefaultBackground(matrixStack, this, x, y, xSize, ySize); + if (drawPlayerSlots) { + builder.drawPlayerSlots(matrixStack, this, x + backgroundWidth / 2, y + 93, true); + } + if (tryAddUpgrades() && be instanceof IUpgradeable) { + IUpgradeable upgradeable = (IUpgradeable) be; + if (upgradeable.canBeUpgraded()) { + builder.drawUpgrades(matrixStack, this, x - 24, y + 6); + upgrades = true; + } + } + int offset = upgrades ? 86 : 6; + for (GuiTab slot : tabs) { + if (slot.enabled()) { + builder.drawSlotTab(matrixStack, this, x - 24, y + offset, slot.stack()); + offset += 24; + } + } + + final GuiBase gui = this; + getTab().ifPresent(guiTab -> builder.drawSlotConfigTips(matrixStack, gui, x + backgroundWidth / 2, y + 93, mouseX, mouseY, guiTab)); + + } + + private void updateSlotDraw(boolean doDraw) { + if (builtScreenHandler == null) { + return; + } + for (Slot slot : builtScreenHandler.slots) { + if (slot instanceof PlayerInventorySlot) { + ((PlayerInventorySlot) slot).doDraw = doDraw; + } + } + } + + public boolean drawPlayerSlots() { + return true; + } + + public boolean tryAddUpgrades() { + return true; + } + + @Environment(EnvType.CLIENT) + @Override + protected void drawForeground(MatrixStack matrixStack, int mouseX, int mouseY) { + drawTitle(matrixStack); + getTab().ifPresent(guiTab -> guiTab.draw(matrixStack, mouseX, mouseY)); + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { + super.render(matrixStack, mouseX, mouseY, partialTicks); + this.drawMouseoverTooltip(matrixStack, mouseX, mouseY); + } + + @Override + protected void drawMouseoverTooltip(MatrixStack matrixStack, int mouseX, int mouseY) { + if (isPointWithinBounds(-25, 6, 24, 80, mouseX, mouseY) && upgrades + && this.focusedSlot != null && !this.focusedSlot.hasStack()) { + List list = new ArrayList<>(); + list.add(new TranslatableText("reborncore.gui.tooltip.upgrades")); + renderTooltip(matrixStack, list, mouseX, mouseY); + } + int offset = upgrades ? 82 : 0; + for (GuiTab tab : tabs) { + if (isPointWithinBounds(-26, 6 + offset, 24, 23, mouseX, mouseY)) { + renderTooltip(matrixStack, Collections.singletonList(new TranslatableText(tab.name())), mouseX, mouseY); + } + offset += 24; + } + + for (AbstractButtonWidget abstractButtonWidget : buttons) { + if (abstractButtonWidget.isHovered()) { + abstractButtonWidget.renderToolTip(matrixStack, mouseX, mouseY); + break; + } + } + super.drawMouseoverTooltip(matrixStack, mouseX, mouseY); + } + + protected void drawTitle(MatrixStack matrixStack) { + drawCentredText(matrixStack, new TranslatableText(be.getCachedState().getBlock().getTranslationKey()), 6, 4210752, Layer.FOREGROUND); + } + + public void drawCentredText(MatrixStack matrixStack, Text text, int y, int colour, Layer layer) { + drawText(matrixStack, text, (backgroundWidth / 2 - getTextRenderer().getWidth(text) / 2), y, colour, layer); + } + + protected void drawCentredText(MatrixStack matrixStack, Text text, int y, int colour, int modifier, Layer layer) { + drawText(matrixStack, text, (backgroundWidth / 2 - (getTextRenderer().getWidth(text)) / 2) + modifier, y, colour, layer); + } + + public void drawText(MatrixStack matrixStack, Text text, int x, int y, int colour, Layer layer) { + int factorX = 0; + int factorY = 0; + if (layer == Layer.BACKGROUND) { + factorX = this.x; + factorY = this.y; + } + getTextRenderer().draw(matrixStack, text, x + factorX, y + factorY, colour); + RenderSystem.color4f(1, 1, 1, 1); + } + + public GuiButtonHologram addHologramButton(int x, int y, int id, Layer layer) { + GuiButtonHologram buttonHologram = new GuiButtonHologram(x + this.x, y + this.y, this, layer, var1 -> { + }); + addButton(buttonHologram); + return buttonHologram; + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int mouseButton) { + if (getTab().map(guiTab -> guiTab.click(mouseX, mouseY, mouseButton)).orElse(false)) { + return true; + } + return super.mouseClicked(mouseX, mouseY, mouseButton); + } + + // @Override + // protected void mouseClickMove(double mouseX, double mouseY, int clickedMouseButton, long timeSinceLastClick) { + // if (isConfigEnabled() && slotConfigType == SlotConfigType.ITEMS && getMachine().hasSlotConfig()) { + // GuiSlotConfiguration.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick, this); + // } + // if (isConfigEnabled() && slotConfigType == SlotConfigType.FLUIDS && getMachine().showTankConfig()) { + // GuiFluidConfiguration.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick, this); + // } + // super.mouseClickMove(mouseX, mouseY, clickedMouseButton, timeSinceLastClick); + // } + + @Override + public boolean mouseReleased(double mouseX, double mouseY, int state) { + int offset = 0; + if (!upgrades) { + offset = 80; + } + for (GuiTab tab : tabs) { + if (isPointWithinBounds(-26, 84 - offset, 30, 23, mouseX, mouseY)) { + if (selectedTab == tab) { + closeSelectedTab(); + } else { + selectedTab = tab; + } + SlotConfigGui.reset(); + break; + } + offset -= 24; + } + + if (getTab().map(guiTab -> guiTab.mouseReleased(mouseX, mouseY, state)).orElse(false)) { + return true; + } + return super.mouseReleased(mouseX, mouseY, state); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifiers) { + if (getTab().map(guiTab -> guiTab.keyPress(keyCode, scanCode, modifiers)).orElse(false)) { + return true; + } + if (selectedTab != null && keyCode == GLFW.GLFW_KEY_ESCAPE) { + closeSelectedTab(); + return true; + } + return super.keyPressed(keyCode, scanCode, modifiers); + } + + @Override + public void onClose() { + closeSelectedTab(); + super.onClose(); + } + + @Nullable + public MachineBaseBlockEntity getMachine() { + return (MachineBaseBlockEntity) be; + } + + /** + * @param rectX int Top left corner of region + * @param rectY int Top left corner of region + * @param rectWidth int Width of region + * @param rectHeight int Height of region + * @param pointX int Mouse pointer + * @param pointY int Mouse pointer + * @return boolean Returns true if mouse pointer is in region specified + */ + public boolean isPointInRect(int rectX, int rectY, int rectWidth, int rectHeight, double pointX, double pointY) { + return super.isPointWithinBounds(rectX, rectY, rectWidth, rectHeight, pointX, pointY); + } + + public enum Layer { + BACKGROUND, FOREGROUND + } + + public interface FluidCellProvider { + ItemStack provide(Fluid fluid); + } + + public boolean isConfigEnabled() { + return be instanceof MachineBaseBlockEntity && builtScreenHandler != null; + } + + public int getGuiLeft() { + return x; + } + + public int getGuiTop() { + return y; + } + + public MinecraftClient getMinecraft() { + // Just to stop complains from IDEA + if (client == null) { + throw new NullPointerException("Minecraft client is null."); + } + return this.client; + } + + public TextRenderer getTextRenderer() { + return this.textRenderer; + } + + public Optional getTab() { + if (!isConfigEnabled()) { + return Optional.empty(); + } + return Optional.ofNullable(selectedTab); + } + + public boolean isTabOpen() { + return selectedTab != null; + } + + public boolean hideGuiElements() { + return selectedTab != null && selectedTab.hideGuiElements(); + } + + public void closeSelectedTab() { + selectedTab = null; + } + + @Override + protected boolean isClickOutsideBounds(double mouseX, double mouseY, int left, int top, int mouseButton) { + //Expanded the width to allow for the upgrades + return super.isClickOutsideBounds(mouseX + 40, mouseY, left + 40, top, mouseButton); + } + + public List getTabs() { + return tabs; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/RedstoneConfigGui.java b/RebornCore/src/main/java/reborncore/client/gui/builder/RedstoneConfigGui.java new file mode 100644 index 000000000..872d3cce9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/RedstoneConfigGui.java @@ -0,0 +1,103 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder; + +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.network.Packet; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import reborncore.client.RenderUtil; +import reborncore.client.gui.guibuilder.GuiBuilder; +import reborncore.common.blockentity.RedstoneConfiguration; +import reborncore.common.network.IdentifiedPacket; +import reborncore.common.network.NetworkManager; +import reborncore.common.network.ServerBoundPackets; + +import java.util.Locale; + +public class RedstoneConfigGui { + + public static void draw(MatrixStack matrixStack, GuiBase guiBase, int mouseX, int mouseY) { + if (guiBase.getMachine() == null) return; + RedstoneConfiguration configuration = guiBase.getMachine().getRedstoneConfiguration(); + GuiBuilder builder = guiBase.builder; + ItemRenderer itemRenderer = guiBase.getMinecraft().getItemRenderer(); + + int x = 10; + int y = 100; + + int i = 0; + int spread = configuration.getElements().size() == 3 ? 27 : 18; + for (RedstoneConfiguration.Element element : configuration.getElements()) { + itemRenderer.renderInGuiWithOverrides(element.getIcon(), x - 3, y + (i * spread) - 5); + + guiBase.getTextRenderer().draw(matrixStack, new TranslatableText("reborncore.gui.fluidconfig." + element.getName()), x + 15, y + (i * spread), -1); + + boolean hovered = withinBounds(guiBase, mouseX, mouseY, x + 92, y + (i * spread) - 2, 63, 15); + int color = hovered ? 0xFF8b8b8b : 0x668b8b8b; + RenderUtil.drawGradientRect(0, x + 91, y + (i * spread) - 2, x + 93 + 65, y + (i * spread) + 10, color, color); + + Text name = new TranslatableText("reborncore.gui.fluidconfig." + configuration.getState(element).name().toLowerCase(Locale.ROOT)); + guiBase.drawCentredText(matrixStack, name, y + (i * spread), -1, x + 37, GuiBase.Layer.FOREGROUND); + //guiBase.getTextRenderer().drawWithShadow(name, x + 92, y + (i * spread), -1); + i++; + } + + } + + public static boolean mouseClicked(GuiBase guiBase, double mouseX, double mouseY, int mouseButton) { + if (guiBase.getMachine() == null) return false; + RedstoneConfiguration configuration = guiBase.getMachine().getRedstoneConfiguration(); + + int x = 10; + int y = 100; + + int i = 0; + int spread = configuration.getElements().size() == 3 ? 27 : 18; + for (RedstoneConfiguration.Element element : configuration.getElements()) { + if (withinBounds(guiBase, (int) mouseX, (int) mouseY, x + 91, y + (i * spread) - 2, 63, 15)) { + RedstoneConfiguration.State currentState = configuration.getState(element); + int ns = currentState.ordinal() + 1; + if (ns >= RedstoneConfiguration.State.values().length) { + ns = 0; + } + RedstoneConfiguration.State nextState = RedstoneConfiguration.State.values()[ns]; + IdentifiedPacket packet = ServerBoundPackets.createPacketSetRedstoneSate(guiBase.getMachine().getPos(), element, nextState); + NetworkManager.sendToServer(packet); + return true; + } + i++; + } + return false; + } + + private static boolean withinBounds(GuiBase guiBase, int mouseX, int mouseY, int x, int y, int width, int height) { + mouseX -= guiBase.getGuiLeft(); + mouseY -= guiBase.getGuiTop(); + return (mouseX > x && mouseX < x + width) && (mouseY > y && mouseY < y + height); + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/FluidConfigGui.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/FluidConfigGui.java new file mode 100644 index 000000000..3a92362d5 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/FluidConfigGui.java @@ -0,0 +1,145 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot; + +import com.google.common.collect.Lists; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.util.math.MatrixStack; +import reborncore.client.gui.builder.GuiBase; +import reborncore.client.gui.builder.slot.elements.ConfigFluidElement; +import reborncore.client.gui.builder.slot.elements.ElementBase; +import reborncore.client.gui.builder.slot.elements.SlotType; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +import org.jetbrains.annotations.Nullable; +import java.util.Collections; +import java.util.List; + +public class FluidConfigGui { + + static ConfigFluidElement fluidConfigElement; + + public static void init(GuiBase guiBase) { + fluidConfigElement = new ConfigFluidElement(guiBase.getMachine().getTank(), SlotType.NORMAL, 35 - guiBase.getGuiLeft() + 50, 35 - guiBase.getGuiTop() - 25, guiBase); + } + + public static void draw(MatrixStack matrixStack, GuiBase guiBase, int mouseX, int mouseY) { + fluidConfigElement.draw(matrixStack, guiBase); + } + + public static List getVisibleElements() { + return Collections.singletonList(fluidConfigElement); + } + + public static boolean mouseClicked(GuiBase guiBase, double mouseX, double mouseY, int mouseButton) { + if (mouseButton == 0) { + for (ConfigFluidElement configFluidElement : getVisibleElements()) { + for (ElementBase element : configFluidElement.elements) { + if (element.isInRect(guiBase, element.x, element.y, element.getWidth(guiBase.getMachine()), element.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + element.isPressing = true; + boolean action = element.onStartPress(guiBase.getMachine(), guiBase, mouseX, mouseY); + for (ElementBase e : getVisibleElements()) { + if (e != element) { + e.isPressing = false; + } + } + if (action) { + break; + } + } else { + element.isPressing = false; + } + } + } + } + return !getVisibleElements().isEmpty(); + } + + public static void mouseClickMove(double mouseX, double mouseY, int mouseButton, long timeSinceLastClick, GuiBase guiBase) { + if (mouseButton == 0) { + for (ConfigFluidElement configFluidElement : getVisibleElements()) { + for (ElementBase element : configFluidElement.elements) { + if (element.isInRect(guiBase, element.x, element.y, element.getWidth(guiBase.getMachine()), element.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + element.isDragging = true; + boolean action = element.onDrag(guiBase.getMachine(), guiBase, mouseX, mouseY); + for (ElementBase e : getVisibleElements()) { + if (e != element) { + e.isDragging = false; + } + } + if (action) { + break; + } + } else { + element.isDragging = false; + } + } + } + } + } + + public static boolean mouseReleased(GuiBase guiBase, double mouseX, double mouseY, int mouseButton) { + boolean clicked = false; + if (mouseButton == 0) { + for (ConfigFluidElement configFluidElement : getVisibleElements()) { + if (configFluidElement.isInRect(guiBase, configFluidElement.x, configFluidElement.y, configFluidElement.getWidth(guiBase.getMachine()), configFluidElement.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + clicked = true; + } + for (ElementBase element : Lists.reverse(configFluidElement.elements)) { + if (element.isInRect(guiBase, element.x, element.y, element.getWidth(guiBase.getMachine()), element.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + element.isReleasing = true; + boolean action = element.onRelease(guiBase.getMachine(), guiBase, mouseX, mouseY); + for (ElementBase e : getVisibleElements()) { + if (e != element) { + e.isReleasing = false; + } + } + if (action) { + clicked = true; + } + break; + } else { + element.isReleasing = false; + } + } + } + } + return clicked; + } + + @Nullable + private static MachineBaseBlockEntity getMachine() { + if (!(MinecraftClient.getInstance().currentScreen instanceof GuiBase)) { + return null; + } + GuiBase base = (GuiBase) MinecraftClient.getInstance().currentScreen; + if (!(base.be instanceof MachineBaseBlockEntity)) { + return null; + } + MachineBaseBlockEntity machineBase = (MachineBaseBlockEntity) base.be; + return machineBase; + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/GuiTab.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/GuiTab.java new file mode 100644 index 000000000..af68d4f72 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/GuiTab.java @@ -0,0 +1,181 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot; + +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.item.ItemStack; +import org.apache.commons.lang3.Validate; +import reborncore.client.gui.builder.GuiBase; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +import java.util.LinkedList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Function; + +public class GuiTab { + + private final Builder builder; + private final MachineBaseBlockEntity machineBaseBlockEntity; + private final GuiBase guiBase; + + private GuiTab(Builder builder, MachineBaseBlockEntity machineBaseBlockEntity, GuiBase guiBase) { + this.builder = builder; + this.machineBaseBlockEntity = machineBaseBlockEntity; + this.guiBase = guiBase; + } + + public String name() { + return builder.name; + } + + public boolean enabled() { + return builder.enabled.apply(this); + } + + public ItemStack stack() { + return builder.stack.apply(this); + } + + public MachineBaseBlockEntity machine() { + return machineBaseBlockEntity; + } + + public void draw(MatrixStack matrixStack, int x, int y) { + builder.draw.draw(matrixStack, guiBase, x, y); + } + + public boolean click(double mouseX, double mouseY, int mouseButton) { + return builder.click.click(guiBase, mouseX, mouseY, mouseButton); + } + + public boolean mouseReleased(double mouseX, double mouseY, int mouseButton) { + return builder.mouseReleased.mouseReleased(guiBase, mouseX, mouseY, mouseButton); + } + + public boolean keyPress(int keyCode, int scanCode, int modifiers) { + return builder.keyPressed.keyPress(guiBase, keyCode, scanCode, modifiers); + } + + public List getTips() { + List tips = new LinkedList<>(); + builder.tips.accept(tips); + return tips; + } + + public boolean hideGuiElements() { + return builder.hideGuiElements; + } + + public GuiBase gui() { + return guiBase; + } + + public static class Builder { + + private String name; + private Function enabled = (tab) -> true; + private Function stack = (tab) -> ItemStack.EMPTY; + private Draw draw = (matrixStack, gui, x, y) -> { + }; + private Click click = (guiBase, mouseX, mouseY, mouseButton) -> false; + private MouseReleased mouseReleased = (guiBase, mouseX, mouseY, state) -> false; + private KeyPressed keyPressed = (guiBase, keyCode, scanCode, modifiers) -> false; + private Consumer> tips = strings -> { + }; + private boolean hideGuiElements = false; + + public static Builder builder() { + return new Builder(); + } + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder stack(Function function) { + this.stack = function; + return this; + } + + public Builder enabled(Function function) { + this.enabled = function; + return this; + } + + public Builder draw(Draw draw) { + this.draw = draw; + return this; + } + + public Builder click(Click click) { + this.click = click; + return this; + } + + public Builder mouseReleased(MouseReleased mouseReleased) { + this.mouseReleased = mouseReleased; + return this; + } + + public Builder keyPressed(KeyPressed keyPressed) { + this.keyPressed = keyPressed; + return this; + } + + public Builder tips(Consumer> listConsumer) { + this.tips = listConsumer; + return this; + } + + public Builder hideGuiElements() { + hideGuiElements = true; + return this; + } + + public GuiTab build(MachineBaseBlockEntity blockEntity, GuiBase guiBase) { + Validate.notBlank(name, "No name provided"); + return new GuiTab(this, blockEntity, guiBase); + } + + public interface Draw { + void draw(MatrixStack matrixStack, GuiBase guiBase, int mouseX, int mouseY); + } + + public interface Click { + boolean click(GuiBase guiBase, double mouseX, double mouseY, int mouseButton); + } + + public interface MouseReleased { + boolean mouseReleased(GuiBase guiBase, double mouseX, double mouseY, int state); + } + + public interface KeyPressed { + boolean keyPress(GuiBase guiBase, int keyCode, int scanCode, int modifiers); + } + + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/SlotConfigGui.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/SlotConfigGui.java new file mode 100644 index 000000000..0b2f41468 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/SlotConfigGui.java @@ -0,0 +1,233 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.screen.slot.Slot; +import net.minecraft.text.LiteralText; +import net.minecraft.util.Util; +import reborncore.client.gui.GuiUtil; +import reborncore.client.gui.builder.GuiBase; +import reborncore.client.gui.builder.slot.elements.ConfigSlotElement; +import reborncore.client.gui.builder.slot.elements.ElementBase; +import reborncore.client.gui.builder.slot.elements.SlotType; +import reborncore.client.screen.builder.BuiltScreenHandler; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.network.NetworkManager; +import reborncore.common.network.ServerBoundPackets; +import reborncore.common.util.Color; +import reborncore.mixin.common.AccessorSlot; + +import org.jetbrains.annotations.Nullable; +import java.util.Collections; +import java.util.HashMap; +import java.util.List; +import java.util.stream.Collectors; + +public class SlotConfigGui { + + static HashMap slotElementMap = new HashMap<>(); + + public static int selectedSlot = 0; + + public static void reset() { + selectedSlot = -1; + } + + public static void init(GuiBase guiBase) { + reset(); + slotElementMap.clear(); + + BuiltScreenHandler container = guiBase.builtScreenHandler; + for (Slot slot : container.slots) { + if (guiBase.be != slot.inventory) { + continue; + } + AccessorSlot accessorSlot = (AccessorSlot) slot; + ConfigSlotElement slotElement = new ConfigSlotElement(guiBase.getMachine().getOptionalInventory().get(), accessorSlot.getIndex(), SlotType.NORMAL, slot.x - guiBase.getGuiLeft() + 50, slot.y - guiBase.getGuiTop() - 25, guiBase); + slotElementMap.put(accessorSlot.getIndex(), slotElement); + } + + } + + public static void draw(MatrixStack matrixStack, GuiBase guiBase, int mouseX, int mouseY) { + BuiltScreenHandler container = guiBase.builtScreenHandler; + for (Slot slot : container.slots) { + if (guiBase.be != slot.inventory) { + continue; + } + RenderSystem.color3f(255, 0, 0); + Color color = new Color(255, 0, 0, 128); + GuiUtil.drawGradientRect(slot.x - 1, slot.y - 1, 18, 18, color.getColor(), color.getColor()); + RenderSystem.color3f(255, 255, 255); + } + + if (selectedSlot != -1) { + + slotElementMap.get(selectedSlot).draw(matrixStack, guiBase); + } + } + + public static List getVisibleElements() { + if (selectedSlot == -1) { + return Collections.emptyList(); + } + return slotElementMap.values().stream() + .filter(configSlotElement -> configSlotElement.getId() == selectedSlot) + .collect(Collectors.toList()); + } + + public static void copyToClipboard() { + MachineBaseBlockEntity machine = getMachine(); + if (machine == null || machine.getSlotConfiguration() == null) { + return; + } + String json = machine.getSlotConfiguration().toJson(machine.getClass().getCanonicalName()); + MinecraftClient.getInstance().keyboard.setClipboard(json); + MinecraftClient.getInstance().player.sendSystemMessage(new LiteralText("Slot configuration copyied to clipboard"), Util.NIL_UUID); + } + + public static void pasteFromClipboard() { + MachineBaseBlockEntity machine = getMachine(); + if (machine == null || machine.getSlotConfiguration() == null) { + return; + } + String json = MinecraftClient.getInstance().keyboard.getClipboard(); + try { + machine.getSlotConfiguration().readJson(json, machine.getClass().getCanonicalName()); + NetworkManager.sendToServer(ServerBoundPackets.createPacketConfigSave(machine.getPos(), machine.getSlotConfiguration())); + MinecraftClient.getInstance().player.sendSystemMessage(new LiteralText("Slot configuration loaded from clipboard"), Util.NIL_UUID); + } catch (UnsupportedOperationException e) { + MinecraftClient.getInstance().player.sendSystemMessage(new LiteralText(e.getMessage()), Util.NIL_UUID); + } + } + + @Nullable + private static MachineBaseBlockEntity getMachine() { + if (!(MinecraftClient.getInstance().currentScreen instanceof GuiBase)) { + return null; + } + GuiBase base = (GuiBase) MinecraftClient.getInstance().currentScreen; + if (!(base.be instanceof MachineBaseBlockEntity)) { + return null; + } + MachineBaseBlockEntity machineBase = (MachineBaseBlockEntity) base.be; + return machineBase; + } + + public static boolean mouseClicked(GuiBase guiBase, double mouseX, double mouseY, int mouseButton) { + if (mouseButton == 0) { + for (ConfigSlotElement configSlotElement : getVisibleElements()) { + for (ElementBase element : configSlotElement.elements) { + if (element.isInRect(guiBase, element.x, element.y, element.getWidth(guiBase.getMachine()), element.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + element.isPressing = true; + boolean action = element.onStartPress(guiBase.getMachine(), guiBase, mouseX, mouseY); + for (ElementBase e : getVisibleElements()) { + if (e != element) { + e.isPressing = false; + } + } + if (action) { + break; + } + } else { + element.isPressing = false; + } + } + } + } + BuiltScreenHandler screenHandler = guiBase.builtScreenHandler; + + if (getVisibleElements().isEmpty()) { + for (Slot slot : screenHandler.slots) { + if (guiBase.be != slot.inventory) { + continue; + } + if (guiBase.isPointInRect(slot.x, slot.y, 18, 18, mouseX, mouseY)) { + AccessorSlot accessorSlot = (AccessorSlot) slot; + selectedSlot = accessorSlot.getIndex(); + return true; + } + } + } + return !getVisibleElements().isEmpty(); + } + + public static void mouseClickMove(double mouseX, double mouseY, int mouseButton, long timeSinceLastClick, GuiBase guiBase) { + if (mouseButton == 0) { + for (ConfigSlotElement configSlotElement : getVisibleElements()) { + for (ElementBase element : configSlotElement.elements) { + if (element.isInRect(guiBase, element.x, element.y, element.getWidth(guiBase.getMachine()), element.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + element.isDragging = true; + boolean action = element.onDrag(guiBase.getMachine(), guiBase, mouseX, mouseY); + for (ElementBase e : getVisibleElements()) { + if (e != element) { + e.isDragging = false; + } + } + if (action) { + break; + } + } else { + element.isDragging = false; + } + } + } + } + } + + public static boolean mouseReleased(GuiBase guiBase, double mouseX, double mouseY, int mouseButton) { + boolean clicked = false; + if (mouseButton == 0) { + for (ConfigSlotElement configSlotElement : getVisibleElements()) { + if (configSlotElement.isInRect(guiBase, configSlotElement.x, configSlotElement.y, configSlotElement.getWidth(guiBase.getMachine()), configSlotElement.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + clicked = true; + } + for (ElementBase element : Lists.reverse(configSlotElement.elements)) { + if (element.isInRect(guiBase, element.x, element.y, element.getWidth(guiBase.getMachine()), element.getHeight(guiBase.getMachine()), mouseX, mouseY)) { + element.isReleasing = true; + boolean action = element.onRelease(guiBase.getMachine(), guiBase, mouseX, mouseY); + for (ElementBase e : getVisibleElements()) { + if (e != element) { + e.isReleasing = false; + } + } + if (action) { + clicked = true; + } + break; + } else { + element.isReleasing = false; + } + } + } + } + return clicked; + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ButtonElement.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ButtonElement.java new file mode 100644 index 000000000..4e30512c2 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ButtonElement.java @@ -0,0 +1,42 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +public class ButtonElement extends ElementBase { + @SuppressWarnings("unused") + private final Sprite.Button buttonSprite; + + public ButtonElement(int x, int y, Sprite.Button buttonSprite) { + super(x, y, buttonSprite.getNormal()); + this.buttonSprite = buttonSprite; + this.addUpdateAction((gui, element) -> { + if (isHovering) { + element.container.setSprite(0, buttonSprite.getHovered()); + } else { + element.container.setSprite(0, buttonSprite.getNormal()); + } + }); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/CheckBoxElement.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/CheckBoxElement.java new file mode 100644 index 000000000..bca85857a --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/CheckBoxElement.java @@ -0,0 +1,78 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import reborncore.client.gui.builder.GuiBase; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +import java.util.function.Predicate; + +public class CheckBoxElement extends ElementBase { + public Text label; + public String type; + public int labelColor, slotID; + public MachineBaseBlockEntity machineBase; + Predicate ticked; + + private final Sprite.CheckBox checkBoxSprite; + + public CheckBoxElement(Text label, int labelColor, int x, int y, String type, int slotID, Sprite.CheckBox checkBoxSprite, MachineBaseBlockEntity machineBase, Predicate ticked) { + super(x, y, checkBoxSprite.getNormal()); + this.checkBoxSprite = checkBoxSprite; + this.type = type; + this.slotID = slotID; + this.machineBase = machineBase; + this.label = label; + this.labelColor = labelColor; + this.ticked = ticked; + if (ticked.test(this)) { + container.setSprite(0, checkBoxSprite.getTicked()); + } else { + container.setSprite(0, checkBoxSprite.getNormal()); + } + this.addPressAction((element, gui, provider, mouseX, mouseY) -> { + if (ticked.test(this)) { + element.container.setSprite(0, checkBoxSprite.getTicked()); + } else { + element.container.setSprite(0, checkBoxSprite.getNormal()); + } + return true; + }); + } + + @Override + public void draw(MatrixStack matrixStack, GuiBase gui) { + // super.draw(gui); + ISprite sprite = checkBoxSprite.getNormal(); + if (ticked.test(this)) { + sprite = checkBoxSprite.getTicked(); + } + drawSprite(matrixStack, gui, sprite, x, y); + drawText(matrixStack, gui, label, x + checkBoxSprite.getNormal().width + 5, ((y + getHeight(gui.getMachine()) / 2) - (gui.getTextRenderer().fontHeight / 2)), labelColor); + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ConfigFluidElement.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ConfigFluidElement.java new file mode 100644 index 000000000..c82834d11 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ConfigFluidElement.java @@ -0,0 +1,81 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.TranslatableText; +import reborncore.client.gui.builder.GuiBase; +import reborncore.common.util.Tank; + +import java.util.ArrayList; +import java.util.List; + +public class ConfigFluidElement extends ElementBase { + SlotType type; + Tank tank; + public List elements = new ArrayList<>(); + boolean filter = false; + + public ConfigFluidElement(Tank tank, SlotType type, int x, int y, GuiBase gui) { + super(x, y, type.getButtonSprite()); + this.type = type; + this.tank = tank; + + FluidConfigPopupElement popupElement; + + elements.add(popupElement = new FluidConfigPopupElement(x - 22, y - 22, this)); + elements.add(new ButtonElement(x + 37, y - 25, Sprite.EXIT_BUTTON).addReleaseAction((element, gui1, provider, mouseX, mouseY) -> { + gui.closeSelectedTab(); + return true; + })); + + elements.add(new CheckBoxElement(new TranslatableText("reborncore.gui.fluidconfig.pullin"), 0xFFFFFFFF, x - 26, y + 42, "input", 0, Sprite.LIGHT_CHECK_BOX, gui.getMachine(), + checkBoxElement -> checkBoxElement.machineBase.fluidConfiguration.autoInput()).addPressAction((element, gui12, provider, mouseX, mouseY) -> { + popupElement.updateCheckBox((CheckBoxElement) element, "input", gui12); + return true; + })); + elements.add(new CheckBoxElement(new TranslatableText("reborncore.gui.fluidconfig.pumpout"), 0xFFFFFFFF, x - 26, y + 57, "output", 0, Sprite.LIGHT_CHECK_BOX, gui.getMachine(), + checkBoxElement -> checkBoxElement.machineBase.fluidConfiguration.autoOutput()).addPressAction((element, gui13, provider, mouseX, mouseY) -> { + popupElement.updateCheckBox((CheckBoxElement) element, "output", gui13); + return true; + })); + + setWidth(85); + setHeight(105 + (filter ? 15 : 0)); + } + + @Override + public void draw(MatrixStack matrixStack, GuiBase gui) { + super.draw(matrixStack, gui); + if (isHovering) { + drawSprite(matrixStack, gui, type.getButtonHoverOverlay(), x, y); + } + elements.forEach(elementBase -> elementBase.draw(matrixStack, gui)); + } + + public SlotType getType() { + return type; + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ConfigSlotElement.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ConfigSlotElement.java new file mode 100644 index 000000000..9a5fcd273 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ConfigSlotElement.java @@ -0,0 +1,136 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.text.TranslatableText; +import reborncore.client.gui.builder.GuiBase; +import reborncore.client.gui.builder.slot.SlotConfigGui; +import reborncore.client.gui.slots.BaseSlot; +import reborncore.common.blockentity.SlotConfiguration; + +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Objects; + +public class ConfigSlotElement extends ElementBase { + SlotType type; + Inventory inventory; + int id; + public List elements = new ArrayList<>(); + boolean filter = false; + + public ConfigSlotElement(Inventory slotInventory, int slotId, SlotType type, int x, int y, GuiBase gui) { + super(x, y, type.getButtonSprite()); + this.type = type; + this.inventory = slotInventory; + this.id = slotId; + + SlotConfigPopupElement popupElement; + + boolean inputEnabled = gui.builtScreenHandler.slots.stream() + .filter(Objects::nonNull) + .filter(slot -> slot.inventory == inventory) + .filter(slot -> slot instanceof BaseSlot) + .map(slot -> (BaseSlot) slot) + .filter(baseSlot -> baseSlot.getSlotID() == slotId) + .allMatch(BaseSlot::canWorldBlockInsert); + + + elements.add(popupElement = new SlotConfigPopupElement(this.id, x - 22, y - 22, this, inputEnabled)); + elements.add(new ButtonElement(x + 37, y - 25, Sprite.EXIT_BUTTON).addReleaseAction((element, gui1, provider, mouseX, mouseY) -> { + SlotConfigGui.selectedSlot = -1; + gui.closeSelectedTab(); + return true; + })); + + if (inputEnabled) { + elements.add(new CheckBoxElement(new TranslatableText("reborncore.gui.slotconfig.autoinput"), 0xFFFFFFFF, x - 26, y + 42, "input", slotId, Sprite.LIGHT_CHECK_BOX, gui.getMachine(), + checkBoxElement -> checkBoxElement.machineBase.getSlotConfiguration().getSlotDetails(checkBoxElement.slotID).autoInput()).addPressAction((element, gui12, provider, mouseX, mouseY) -> { + popupElement.updateCheckBox((CheckBoxElement) element, "input", gui12); + return true; + })); + } + + elements.add(new CheckBoxElement(new TranslatableText("reborncore.gui.slotconfig.autooutput"), 0xFFFFFFFF, x - 26, y + 57, "output", slotId, Sprite.LIGHT_CHECK_BOX, gui.getMachine(), + checkBoxElement -> checkBoxElement.machineBase.getSlotConfiguration().getSlotDetails(checkBoxElement.slotID).autoOutput()).addPressAction((element, gui13, provider, mouseX, mouseY) -> { + popupElement.updateCheckBox((CheckBoxElement) element, "output", gui13); + return true; + })); + + if (gui.getMachine() instanceof SlotConfiguration.SlotFilter) { + SlotConfiguration.SlotFilter slotFilter = (SlotConfiguration.SlotFilter) gui.getMachine(); + if (Arrays.stream(slotFilter.getInputSlots()).anyMatch(value -> value == slotId)) { + elements.add(new CheckBoxElement(new TranslatableText("reborncore.gui.slotconfig.filter_input"), 0xFFFFFFFF, x - 26, y + 72, "filter", slotId, Sprite.LIGHT_CHECK_BOX, gui.getMachine(), + checkBoxElement -> checkBoxElement.machineBase.getSlotConfiguration().getSlotDetails(checkBoxElement.slotID).filter()).addPressAction((element, gui13, provider, mouseX, mouseY) -> { + popupElement.updateCheckBox((CheckBoxElement) element, "filter", gui13); + return true; + })); + filter = true; + popupElement.filter = true; + } + } + setWidth(85); + setHeight(105 + (filter ? 15 : 0)); + } + + @Override + public void draw(MatrixStack matrixStack, GuiBase gui) { + super.draw(matrixStack, gui); + ItemStack stack = inventory.getStack(id); + int xPos = x + 1 + gui.getGuiLeft(); + int yPos = y + 1 + gui.getGuiTop(); + + RenderSystem.enableDepthTest(); + matrixStack.push(); + RenderSystem.enableBlend(); + RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA); + ItemRenderer renderItem = MinecraftClient.getInstance().getItemRenderer(); + renderItem.renderInGuiWithOverrides(stack, xPos, yPos); + renderItem.renderGuiItemOverlay(gui.getTextRenderer(), stack, xPos, yPos, null); + RenderSystem.disableDepthTest(); + RenderSystem.disableLighting(); + matrixStack.pop(); + if (isHovering) { + drawSprite(matrixStack, gui, type.getButtonHoverOverlay(), x, y); + } + elements.forEach(elementBase -> elementBase.draw(matrixStack, gui)); + } + + public SlotType getType() { + return type; + } + + public int getId() { + return id; + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ElementBase.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ElementBase.java new file mode 100644 index 000000000..fbdade87d --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ElementBase.java @@ -0,0 +1,348 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import com.mojang.blaze3d.platform.GlStateManager; +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import net.minecraft.util.Identifier; +import reborncore.client.RenderUtil; +import reborncore.client.gui.builder.GuiBase; +import reborncore.client.gui.guibuilder.GuiBuilder; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +import java.util.ArrayList; +import java.util.List; + +public class ElementBase { + + public int x; + public int y; + public boolean isHovering = false; + public boolean isDragging = false; + public boolean isPressing = false; + public boolean isReleasing = false; + public boolean startPressLast = false; + public boolean isHoveringLast = false; + public boolean isDraggingLast = false; + public boolean isPressingLast = false; + public boolean isReleasingLast = false; + public List hoverActions = new ArrayList<>(); + public List dragActions = new ArrayList<>(); + public List startPressActions = new ArrayList<>(); + public List pressActions = new ArrayList<>(); + public List releaseActions = new ArrayList<>(); + public SpriteContainer container; + public List updateActions = new ArrayList<>(); + public List buttonUpdate = new ArrayList<>(); + private int width; + private int height; + + public static final Identifier MECH_ELEMENTS = new Identifier("reborncore", "textures/gui/elements.png"); + + public ElementBase(int x, int y, SpriteContainer container) { + this.container = container; + this.x = x; + this.y = y; + } + + public ElementBase(int x, int y, ISprite... sprites) { + this.container = new SpriteContainer(); + for (ISprite sprite : sprites) { + container.addSprite(sprite); + } + this.x = x; + this.y = y; + } + + public ElementBase(int x, int y, int width, int height) { + this.container = new SpriteContainer(); + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public ElementBase(int x, int y, int width, int height, SpriteContainer container) { + this.container = container; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public ElementBase(int x, int y, int width, int height, ISprite... sprites) { + this.container = new SpriteContainer(); + for (ISprite sprite : sprites) { + container.addSprite(sprite); + } + this.x = x; + this.y = y; + this.width = width; + this.height = height; + } + + public SpriteContainer getSpriteContainer() { + return container; + } + + public void adjustDimensions(MachineBaseBlockEntity provider) { + if (container.offsetSprites != null) { + for (OffsetSprite offsetSprite : container.offsetSprites) { + if (offsetSprite.getSprite().getSprite(provider).width + offsetSprite.getOffsetX(provider) > this.width) { + this.width = offsetSprite.getSprite().getSprite(provider).width + offsetSprite.getOffsetX(provider); + } + if (offsetSprite.getSprite().getSprite(provider).height + offsetSprite.getOffsetY(provider) > this.height) { + this.height = offsetSprite.getSprite().getSprite(provider).height + offsetSprite.getOffsetY(provider); + } + } + } + } + + public void draw(MatrixStack matrixStack, GuiBase gui) { + for (OffsetSprite sprite : getSpriteContainer().offsetSprites) { + drawSprite(matrixStack, gui, sprite.getSprite(), x + sprite.getOffsetX(gui.getMachine()), y + sprite.getOffsetY(gui.getMachine())); + } + } + + public void renderUpdate(GuiBase gui) { + isHoveringLast = isHovering; + isPressingLast = isPressing; + isDraggingLast = isDragging; + isReleasingLast = isReleasing; + } + + public void update(GuiBase gui) { + for (UpdateAction action : updateActions) { + action.update(gui, this); + } + } + + public ElementBase addUpdateAction(UpdateAction action) { + updateActions.add(action); + return this; + } + + public ElementBase setWidth(int width) { + this.width = width; + return this; + } + + public ElementBase setHeight(int height) { + this.height = height; + return this; + } + + public int getX() { + return x; + } + + public ElementBase setX(int x) { + this.x = x; + return this; + } + + public int getY() { + return y; + } + + public ElementBase setY(int y) { + this.y = y; + return this; + } + + public int getWidth(MachineBaseBlockEntity provider) { + adjustDimensions(provider); + return width; + } + + public int getHeight(MachineBaseBlockEntity provider) { + adjustDimensions(provider); + return height; + } + + public int getWidth() { + return width; + } + + public int getHeight() { + return height; + } + + public ElementBase addHoverAction(ElementBase.Action action) { + this.hoverActions.add(action); + return this; + } + + public ElementBase addDragAction(ElementBase.Action action) { + this.dragActions.add(action); + return this; + } + + public ElementBase addStartPressAction(ElementBase.Action action) { + this.startPressActions.add(action); + return this; + } + + public ElementBase addPressAction(ElementBase.Action action) { + this.pressActions.add(action); + return this; + } + + public ElementBase addReleaseAction(ElementBase.Action action) { + this.releaseActions.add(action); + return this; + } + + public boolean onHover(MachineBaseBlockEntity provider, GuiBase gui, double mouseX, double mouseY) { + for (ElementBase.Action action : hoverActions) { + action.execute(this, gui, provider, mouseX, mouseY); + } + return !hoverActions.isEmpty(); + } + + public boolean onDrag(MachineBaseBlockEntity provider, GuiBase gui, double mouseX, double mouseY) { + for (ElementBase.Action action : dragActions) { + action.execute(this, gui, provider, mouseX, mouseY); + } + return !dragActions.isEmpty(); + } + + public boolean onStartPress(MachineBaseBlockEntity provider, GuiBase gui, double mouseX, double mouseY) { + for (ElementBase.Action action : startPressActions) { + action.execute(this, gui, provider, mouseX, mouseY); + } + return !startPressActions.isEmpty(); + } + + public boolean onRelease(MachineBaseBlockEntity provider, GuiBase gui, double mouseX, double mouseY) { + for (ElementBase.Action action : releaseActions) { + if (action.execute(this, gui, provider, mouseX, mouseY)) { + return true; + } + } + if (isPressing) { + for (ElementBase.Action action : pressActions) { + action.execute(this, gui, provider, mouseX, mouseY); + } + } + return !releaseActions.isEmpty() || !pressActions.isEmpty(); + } + + public interface Action { + boolean execute(ElementBase element, GuiBase gui, MachineBaseBlockEntity provider, double mouseX, double mouseY); + } + + public interface UpdateAction { + void update(GuiBase gui, ElementBase element); + } + + public void drawRect(GuiBase gui, int x, int y, int width, int height, int colour) { + drawGradientRect(gui, x, y, width, height, colour, colour); + } + + /* + Taken from Gui + */ + public void drawGradientRect(GuiBase gui, int x, int y, int width, int height, int startColor, int endColor) { + x = adjustX(gui, x); + y = adjustY(gui, y); + + int left = x; + int top = y; + int right = x + width; + int bottom = y + height; + + RenderUtil.drawGradientRect(0, left, top, right, bottom, startColor, endColor); + } + + public int adjustX(GuiBase gui, int x) { + return gui.getGuiLeft() + x; + } + + public int adjustY(GuiBase gui, int y) { + return gui.getGuiTop() + y; + } + + public boolean isInRect(GuiBase gui, int x, int y, int xSize, int ySize, double mouseX, double mouseY) { + return gui.isPointInRect(x + gui.getGuiLeft(), y + gui.getGuiTop(), xSize, ySize, mouseX, mouseY); + } + + public void drawText(MatrixStack matrixStack, GuiBase gui, Text text, int x, int y, int color) { + x = adjustX(gui, x); + y = adjustY(gui, y); + gui.getTextRenderer().draw(matrixStack, text, x, y, color); + } + + public void setTextureSheet(Identifier textureLocation) { + MinecraftClient.getInstance().getTextureManager().bindTexture(textureLocation); + } + + public void drawSprite(MatrixStack matrixStack, GuiBase gui, ISprite iSprite, int x, int y) { + Sprite sprite = iSprite.getSprite(gui.getMachine()); + if (sprite != null) { + if (sprite.hasTextureInfo()) { + RenderSystem.color3f(1F, 1F, 1F); + setTextureSheet(sprite.textureLocation); + gui.drawTexture(matrixStack, x + gui.getGuiLeft(), y + gui.getGuiTop(), sprite.x, sprite.y, sprite.width, sprite.height); + } + if (sprite.hasStack()) { + RenderSystem.pushMatrix(); + RenderSystem.enableBlend(); + RenderSystem.blendFunc(GlStateManager.SrcFactor.SRC_ALPHA, GlStateManager.DstFactor.ONE_MINUS_SRC_ALPHA); + + ItemRenderer itemRenderer = MinecraftClient.getInstance().getItemRenderer(); + itemRenderer.renderInGuiWithOverrides(sprite.itemStack, x + gui.getGuiLeft(), y + gui.getGuiTop()); + + RenderSystem.disableLighting(); + RenderSystem.popMatrix(); + } + } + } + + public int getScaledBurnTime(int scale, int burnTime, int totalBurnTime) { + return (int) (((float) burnTime / (float) totalBurnTime) * scale); + } + + public int getPercentage(int MaxValue, int CurrentValue) { + if (CurrentValue == 0) { + return 0; + } + return (int) ((CurrentValue * 100.0f) / MaxValue); + } + + public void drawDefaultBackground(MatrixStack matrixStack, Screen gui, int x, int y, int width, int height) { + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + MinecraftClient.getInstance().getTextureManager().bindTexture(GuiBuilder.defaultTextureSheet); + gui.drawTexture(matrixStack, x, y, 0, 0, width / 2, height / 2); + gui.drawTexture(matrixStack, x + width / 2, y, 150 - width / 2, 0, width / 2, height / 2); + gui.drawTexture(matrixStack, x, y + height / 2, 0, 150 - height / 2, width / 2, height / 2); + gui.drawTexture(matrixStack, x + width / 2, y + height / 2, 150 - width / 2, 150 - height / 2, width / 2, height / 2); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/FluidConfigPopupElement.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/FluidConfigPopupElement.java new file mode 100644 index 000000000..ae9f3263c --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/FluidConfigPopupElement.java @@ -0,0 +1,213 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Vector3f; +import net.minecraft.network.Packet; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Quaternion; +import net.minecraft.world.World; +import reborncore.RebornCore; +import reborncore.client.gui.GuiUtil; +import reborncore.client.gui.builder.GuiBase; +import reborncore.common.blockentity.FluidConfiguration; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.network.IdentifiedPacket; +import reborncore.common.network.NetworkManager; +import reborncore.common.network.ServerBoundPackets; +import reborncore.common.util.Color; +import reborncore.common.util.MachineFacing; + +public class FluidConfigPopupElement extends ElementBase { + public boolean filter = false; + + ConfigFluidElement fluidElement; + double lastMousex, lastMousey; + + public FluidConfigPopupElement(int x, int y, ConfigFluidElement fluidElement) { + super(x, y, Sprite.SLOT_CONFIG_POPUP); + this.fluidElement = fluidElement; + } + + @Override + public void draw(MatrixStack matrixStack, GuiBase gui) { + drawDefaultBackground(matrixStack, gui, adjustX(gui, getX() - 8), adjustY(gui, getY() - 7), 84, 105 + (filter ? 15 : 0)); + super.draw(matrixStack, gui); + + MachineBaseBlockEntity machine = ((MachineBaseBlockEntity) gui.be); + World world = machine.getWorld(); + BlockPos pos = machine.getPos(); + BlockState state = world.getBlockState(pos); + BlockState actualState = state.getBlock().getDefaultState(); + BlockRenderManager dispatcher = MinecraftClient.getInstance().getBlockRenderManager(); + BakedModel model = dispatcher.getModels().getModel(state.getBlock().getDefaultState()); + MinecraftClient.getInstance().getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE); + drawState(gui, world, model, actualState, pos, dispatcher, 4, 23, Vector3f.POSITIVE_Y.getDegreesQuaternion(90F)); //left + drawState(gui, world, model, actualState, pos, dispatcher, 23, 4, Vector3f.NEGATIVE_X.getDegreesQuaternion(90F)); //top + drawState(gui, world, model, actualState, pos, dispatcher, 23, 23, null); //centre + drawState(gui, world, model, actualState, pos, dispatcher, 23, 26, Vector3f.POSITIVE_X.getDegreesQuaternion(90F)); //bottom + drawState(gui, world, model, actualState, pos, dispatcher, 42, 23, Vector3f.POSITIVE_Y.getDegreesQuaternion(90F)); //right + drawState(gui, world, model, actualState, pos, dispatcher, 26, 42, Vector3f.POSITIVE_Y.getDegreesQuaternion(180F)); //back + + drawSateColor(gui.getMachine(), MachineFacing.UP.getFacing(machine), 22, -1, gui); + drawSateColor(gui.getMachine(), MachineFacing.FRONT.getFacing(machine), 22, 18, gui); + drawSateColor(gui.getMachine(), MachineFacing.DOWN.getFacing(machine), 22, 37, gui); + drawSateColor(gui.getMachine(), MachineFacing.RIGHT.getFacing(machine), 41, 18, gui); + drawSateColor(gui.getMachine(), MachineFacing.BACK.getFacing(machine), 41, 37, gui); + drawSateColor(gui.getMachine(), MachineFacing.LEFT.getFacing(machine), 3, 18, gui); + } + + @Override + public boolean onRelease(MachineBaseBlockEntity provider, GuiBase gui, double mouseX, double mouseY) { + if (isInBox(23, 4, 16, 16, mouseX, mouseY, gui)) { + cyleConfig(MachineFacing.UP.getFacing(provider), gui); + } else if (isInBox(23, 23, 16, 16, mouseX, mouseY, gui)) { + cyleConfig(MachineFacing.FRONT.getFacing(provider), gui); + } else if (isInBox(42, 23, 16, 16, mouseX, mouseY, gui)) { + cyleConfig(MachineFacing.RIGHT.getFacing(provider), gui); + } else if (isInBox(4, 23, 16, 16, mouseX, mouseY, gui)) { + cyleConfig(MachineFacing.LEFT.getFacing(provider), gui); + } else if (isInBox(23, 42, 16, 16, mouseX, mouseY, gui)) { + cyleConfig(MachineFacing.DOWN.getFacing(provider), gui); + } else if (isInBox(42, 42, 16, 16, mouseX, mouseY, gui)) { + cyleConfig(MachineFacing.BACK.getFacing(provider), gui); + } else { + return false; + } + return true; + } + + public void cyleConfig(Direction side, GuiBase guiBase) { + FluidConfiguration.FluidConfig config = guiBase.getMachine().fluidConfiguration.getSideDetail(side); + + FluidConfiguration.ExtractConfig fluidIO = config.getIoConfig().getNext(); + FluidConfiguration.FluidConfig newConfig = new FluidConfiguration.FluidConfig(side, fluidIO); + + IdentifiedPacket packetSave = ServerBoundPackets.createPacketFluidConfigSave(guiBase.be.getPos(), newConfig); + NetworkManager.sendToServer(packetSave); + } + + public void updateCheckBox(CheckBoxElement checkBoxElement, String type, GuiBase guiBase) { + FluidConfiguration configHolder = guiBase.getMachine().fluidConfiguration; + boolean input = configHolder.autoInput(); + boolean output = configHolder.autoOutput(); + if (type.equalsIgnoreCase("input")) { + input = !configHolder.autoInput(); + } + if (type.equalsIgnoreCase("output")) { + output = !configHolder.autoOutput(); + } + + IdentifiedPacket packetFluidIOSave = ServerBoundPackets.createPacketFluidIOSave(guiBase.be.getPos(), input, output); + NetworkManager.sendToServer(packetFluidIOSave); + } + + @Override + public boolean onHover(MachineBaseBlockEntity provider, GuiBase gui, double mouseX, double mouseY) { + lastMousex = mouseX; + lastMousey = mouseY; + return super.onHover(provider, gui, mouseX, mouseY); + } + + private void drawSateColor(MachineBaseBlockEntity machineBase, Direction side, int inx, int iny, GuiBase gui) { + iny += 4; + int sx = inx + getX() + gui.getGuiLeft(); + int sy = iny + getY() + gui.getGuiTop(); + FluidConfiguration fluidConfiguration = machineBase.fluidConfiguration; + if (fluidConfiguration == null) { + RebornCore.LOGGER.debug("Humm, this isnt suppoed to happen"); + return; + } + FluidConfiguration.FluidConfig fluidConfig = fluidConfiguration.getSideDetail(side); + Color color; + switch (fluidConfig.getIoConfig()) { + case NONE: + color = new Color(0, 0, 0, 0); + break; + case INPUT: + color = new Color(0, 0, 255, 128); + break; + case OUTPUT: + color = new Color(255, 69, 0, 128); + break; + case ALL: + color = new Color(52, 255, 30, 128); + break; + default: + color = new Color(0, 0, 0, 0); + break; + } + RenderSystem.color3f(255, 255, 255); + GuiUtil.drawGradientRect(sx, sy, 18, 18, color.getColor(), color.getColor()); + RenderSystem.color3f(255, 255, 255); + } + + private boolean isInBox(int rectX, int rectY, int rectWidth, int rectHeight, double pointX, double pointY, GuiBase guiBase) { + rectX += getX(); + rectY += getY(); + return isInRect(guiBase, rectX, rectY, rectWidth, rectHeight, pointX, pointY); + //return (pointX - guiBase.getGuiLeft()) >= rectX - 1 && (pointX - guiBase.getGuiLeft()) < rectX + rectWidth + 1 && (pointY - guiBase.getGuiTop()) >= rectY - 1 && (pointY - guiBase.getGuiTop()) < rectY + rectHeight + 1; + } + + public void drawState(GuiBase gui, + World world, + BakedModel model, + BlockState actualState, + BlockPos pos, + BlockRenderManager dispatcher, + int x, + int y, + Quaternion quaternion) { + + MatrixStack matrixStack = new MatrixStack(); + matrixStack.push(); + matrixStack.translate(8 + gui.getGuiLeft() + this.x + x, 8 + gui.getGuiTop() + this.y + y, 512); + matrixStack.scale(16F, 16F, 16F); + matrixStack.translate(0.5F, 0.5F, 0.5F); + matrixStack.scale(-1, -1, -1); + + if (quaternion != null) { + matrixStack.multiply(quaternion); + } + + VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); + dispatcher.getModelRenderer().render(matrixStack.peek(), immediate.getBuffer(RenderLayer.getSolid()), actualState, model, 1F, 1F, 1F, OverlayTexture.getU(15F), OverlayTexture.DEFAULT_UV); + immediate.draw(); + matrixStack.pop(); + } + +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ISprite.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ISprite.java new file mode 100644 index 000000000..7325b2cae --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/ISprite.java @@ -0,0 +1,31 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import reborncore.common.blockentity.MachineBaseBlockEntity; + +public interface ISprite { + Sprite getSprite(MachineBaseBlockEntity provider); +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/OffsetSprite.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/OffsetSprite.java new file mode 100644 index 000000000..d06a3a4fb --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/OffsetSprite.java @@ -0,0 +1,69 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import reborncore.common.blockentity.MachineBaseBlockEntity; + +public class OffsetSprite { + public ISprite sprite; + public int offsetX = 0; + public int offsetY = 0; + + public OffsetSprite(ISprite sprite, int offsetX, int offsetY) { + this.sprite = sprite; + this.offsetX = offsetX; + this.offsetY = offsetY; + } + + public OffsetSprite(ISprite sprite) { + this.sprite = sprite; + } + + public OffsetSprite(Sprite sprite, MachineBaseBlockEntity provider) { + this.sprite = sprite; + } + + public ISprite getSprite() { + return sprite; + } + + public int getOffsetX(MachineBaseBlockEntity provider) { + return offsetX + sprite.getSprite(provider).offsetX; + } + + public OffsetSprite setOffsetX(int offsetX) { + this.offsetX = offsetX; + return this; + } + + public int getOffsetY(MachineBaseBlockEntity provider) { + return offsetY + sprite.getSprite(provider).offsetY; + } + + public OffsetSprite setOffsetY(int offsetY) { + this.offsetY = offsetY; + return this; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotConfigPopupElement.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotConfigPopupElement.java new file mode 100644 index 000000000..2ff3f4446 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotConfigPopupElement.java @@ -0,0 +1,220 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.block.BlockState; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.OverlayTexture; +import net.minecraft.client.render.RenderLayer; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.model.BakedModel; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.util.math.Vector3f; +import net.minecraft.network.Packet; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.Quaternion; +import net.minecraft.world.World; +import reborncore.RebornCore; +import reborncore.client.gui.GuiUtil; +import reborncore.client.gui.builder.GuiBase; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.blockentity.SlotConfiguration; +import reborncore.common.network.IdentifiedPacket; +import reborncore.common.network.NetworkManager; +import reborncore.common.network.ServerBoundPackets; +import reborncore.common.util.Color; +import reborncore.common.util.MachineFacing; + +public class SlotConfigPopupElement extends ElementBase { + int id; + public boolean filter = false; + + ConfigSlotElement slotElement; + + boolean allowInput = true; + + public SlotConfigPopupElement(int slotId, int x, int y, ConfigSlotElement slotElement, boolean allowInput) { + super(x, y, Sprite.SLOT_CONFIG_POPUP); + this.id = slotId; + this.slotElement = slotElement; + this.allowInput = allowInput; + } + + @Override + public void draw(MatrixStack matrixStack, GuiBase gui) { + drawDefaultBackground(matrixStack, gui, adjustX(gui, getX() - 8), adjustY(gui, getY() - 7), 84, 105 + (filter ? 15 : 0)); + super.draw(matrixStack, gui); + + MachineBaseBlockEntity machine = ((MachineBaseBlockEntity) gui.be); + World world = machine.getWorld(); + BlockPos pos = machine.getPos(); + BlockState state = world.getBlockState(pos); + BlockState actualState = state.getBlock().getDefaultState(); + BlockRenderManager dispatcher = MinecraftClient.getInstance().getBlockRenderManager(); + BakedModel model = dispatcher.getModels().getModel(state.getBlock().getDefaultState()); + MinecraftClient.getInstance().getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE); + drawState(gui, world, model, actualState, pos, dispatcher, 4, 23, Vector3f.POSITIVE_Y.getDegreesQuaternion(90F)); //left + drawState(gui, world, model, actualState, pos, dispatcher, 23, 4, Vector3f.NEGATIVE_X.getDegreesQuaternion(90F)); //top + drawState(gui, world, model, actualState, pos, dispatcher, 23, 23, null); //centre + drawState(gui, world, model, actualState, pos, dispatcher, 23, 26, Vector3f.POSITIVE_X.getDegreesQuaternion(90F)); //bottom + drawState(gui, world, model, actualState, pos, dispatcher, 42, 23, Vector3f.POSITIVE_Y.getDegreesQuaternion(90F)); //right + drawState(gui, world, model, actualState, pos, dispatcher, 26, 42, Vector3f.POSITIVE_Y.getDegreesQuaternion(180F)); //back + + drawSlotSateColor(gui.getMachine(), MachineFacing.UP.getFacing(machine), id, 22, -1, gui); + drawSlotSateColor(gui.getMachine(), MachineFacing.FRONT.getFacing(machine), id, 22, 18, gui); + drawSlotSateColor(gui.getMachine(), MachineFacing.DOWN.getFacing(machine), id, 22, 37, gui); + drawSlotSateColor(gui.getMachine(), MachineFacing.RIGHT.getFacing(machine), id, 41, 18, gui); + drawSlotSateColor(gui.getMachine(), MachineFacing.BACK.getFacing(machine), id, 41, 37, gui); + drawSlotSateColor(gui.getMachine(), MachineFacing.LEFT.getFacing(machine), id, 3, 18, gui); + } + + @Override + public boolean onRelease(MachineBaseBlockEntity provider, GuiBase gui, double mouseX, double mouseY) { + if (isInBox(23, 4, 16, 16, mouseX, mouseY, gui)) { + cyleSlotConfig(MachineFacing.UP.getFacing(provider), gui); + } else if (isInBox(23, 23, 16, 16, mouseX, mouseY, gui)) { + cyleSlotConfig(MachineFacing.FRONT.getFacing(provider), gui); + } else if (isInBox(42, 23, 16, 16, mouseX, mouseY, gui)) { + cyleSlotConfig(MachineFacing.RIGHT.getFacing(provider), gui); + } else if (isInBox(4, 23, 16, 16, mouseX, mouseY, gui)) { + cyleSlotConfig(MachineFacing.LEFT.getFacing(provider), gui); + } else if (isInBox(23, 42, 16, 16, mouseX, mouseY, gui)) { + cyleSlotConfig(MachineFacing.DOWN.getFacing(provider), gui); + } else if (isInBox(42, 42, 16, 16, mouseX, mouseY, gui)) { + cyleSlotConfig(MachineFacing.BACK.getFacing(provider), gui); + } else { + return false; + } + return true; + } + + public void cyleSlotConfig(Direction side, GuiBase guiBase) { + SlotConfiguration.SlotConfig currentSlot = guiBase.getMachine().getSlotConfiguration().getSlotDetails(id).getSideDetail(side); + + //Bit of a mess, in the future have a way to remove config options from this list + SlotConfiguration.ExtractConfig nextConfig = currentSlot.getSlotIO().getIoConfig().getNext(); + if (!allowInput && nextConfig == SlotConfiguration.ExtractConfig.INPUT) { + nextConfig = SlotConfiguration.ExtractConfig.OUTPUT; + } + + SlotConfiguration.SlotIO slotIO = new SlotConfiguration.SlotIO(nextConfig); + SlotConfiguration.SlotConfig newConfig = new SlotConfiguration.SlotConfig(side, slotIO, id); + IdentifiedPacket packetSlotSave = ServerBoundPackets.createPacketSlotSave(guiBase.be.getPos(), newConfig); + NetworkManager.sendToServer(packetSlotSave); + } + + public void updateCheckBox(CheckBoxElement checkBoxElement, String type, GuiBase guiBase) { + SlotConfiguration.SlotConfigHolder configHolder = guiBase.getMachine().getSlotConfiguration().getSlotDetails(id); + boolean input = configHolder.autoInput(); + boolean output = configHolder.autoOutput(); + boolean filter = configHolder.filter(); + if (type.equalsIgnoreCase("input")) { + input = !configHolder.autoInput(); + } + if (type.equalsIgnoreCase("output")) { + output = !configHolder.autoOutput(); + } + if (type.equalsIgnoreCase("filter")) { + filter = !configHolder.filter(); + } + + IdentifiedPacket packetSlotSave = ServerBoundPackets.createPacketIOSave(guiBase.be.getPos(), id, input, output, filter); + NetworkManager.sendToServer(packetSlotSave); + } + + private void drawSlotSateColor(MachineBaseBlockEntity machineBase, Direction side, int slotID, int inx, int iny, GuiBase gui) { + iny += 4; + int sx = inx + getX() + gui.getGuiLeft(); + int sy = iny + getY() + gui.getGuiTop(); + SlotConfiguration.SlotConfigHolder slotConfigHolder = machineBase.getSlotConfiguration().getSlotDetails(slotID); + if (slotConfigHolder == null) { + RebornCore.LOGGER.debug("Humm, this isnt suppoed to happen"); + return; + } + SlotConfiguration.SlotConfig slotConfig = slotConfigHolder.getSideDetail(side); + Color color; + switch (slotConfig.getSlotIO().getIoConfig()) { + case NONE: + color = new Color(0, 0, 0, 0); + break; + case INPUT: + color = new Color(0, 0, 255, 128); + break; + case OUTPUT: + color = new Color(255, 69, 0, 128); + break; + default: + color = new Color(0, 0, 0, 0); + break; + } + RenderSystem.color3f(255, 255, 255); + GuiUtil.drawGradientRect(sx, sy, 18, 18, color.getColor(), color.getColor()); + RenderSystem.color3f(255, 255, 255); + + } + + private boolean isInBox(int rectX, int rectY, int rectWidth, int rectHeight, double pointX, double pointY, GuiBase guiBase) { + rectX += getX(); + rectY += getY(); + return isInRect(guiBase, rectX, rectY, rectWidth, rectHeight, pointX, pointY); + //return (pointX - guiBase.getGuiLeft()) >= rectX - 1 && (pointX - guiBase.getGuiLeft()) < rectX + rectWidth + 1 && (pointY - guiBase.getGuiTop()) >= rectY - 1 && (pointY - guiBase.getGuiTop()) < rectY + rectHeight + 1; + } + + public void drawState(GuiBase gui, + World world, + BakedModel model, + BlockState actualState, + BlockPos pos, + BlockRenderManager dispatcher, + int x, + int y, + Quaternion quaternion) { + + MatrixStack matrixStack = new MatrixStack(); + matrixStack.push(); + matrixStack.translate(8 + gui.getGuiLeft() + this.x + x, 8 + gui.getGuiTop() + this.y + y, 512); + matrixStack.scale(16F, 16F, 16F); + matrixStack.translate(0.5F, 0.5F, 0.5F); + matrixStack.scale(-1, -1, -1); + + if (quaternion != null) { + matrixStack.multiply(quaternion); + } + + VertexConsumerProvider.Immediate immediate = VertexConsumerProvider.immediate(Tessellator.getInstance().getBuffer()); + dispatcher.getModelRenderer().render(matrixStack.peek(), immediate.getBuffer(RenderLayer.getSolid()), actualState, model, 1F, 1F, 1F, OverlayTexture.getU(15F), OverlayTexture.DEFAULT_UV); + immediate.draw(); + matrixStack.pop(); + } + + public void drawState(GuiBase gui, World world, BakedModel model, BlockState actualState, BlockPos pos, BlockRenderManager dispatcher, int x, int y) { + drawState(gui, world, model, actualState, pos, dispatcher, x, y, null); + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotElement.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotElement.java new file mode 100644 index 000000000..ea90ce398 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotElement.java @@ -0,0 +1,62 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import net.minecraft.inventory.Inventory; + +public class SlotElement extends ElementBase { + protected Inventory slotInventory; + protected SlotType type; + int slotId, slotX, slotY; + + public SlotElement(Inventory slotInventory, int slotId, int slotX, int slotY, SlotType type, int x, int y) { + super(x, y, type.getSprite()); + this.type = type; + this.slotInventory = slotInventory; + this.slotId = slotId; + this.slotX = slotX; + this.slotY = slotY; + } + + public SlotType getType() { + return type; + } + + public Inventory getSlotInventory() { + return slotInventory; + } + + public int getSlotId() { + return slotId; + } + + public int getSlotX() { + return slotX; + } + + public int getSlotY() { + return slotY; + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotType.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotType.java new file mode 100644 index 000000000..64748bf1d --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SlotType.java @@ -0,0 +1,69 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +public enum SlotType { + NORMAL(1, 1, Sprite.SLOT_NORMAL, Sprite.BUTTON_SLOT_NORMAL, Sprite.BUTTON_HOVER_OVERLAY_SLOT_NORMAL); + + int slotOffsetX; + int slotOffsetY; + Sprite sprite; + Sprite buttonSprite; + Sprite buttonHoverOverlay; + + SlotType(int slotOffsetX, int slotOffsetY, Sprite sprite, Sprite buttonSprite, Sprite buttonHoverOverlay) { + this.slotOffsetX = slotOffsetX; + this.slotOffsetY = slotOffsetY; + this.sprite = sprite; + this.buttonSprite = buttonSprite; + this.buttonHoverOverlay = buttonHoverOverlay; + } + + SlotType(int slotOffset, Sprite sprite) { + this.slotOffsetX = slotOffset; + this.slotOffsetY = slotOffset; + this.sprite = sprite; + } + + public int getSlotOffsetX() { + return slotOffsetX; + } + + public int getSlotOffsetY() { + return slotOffsetY; + } + + public Sprite getSprite() { + return sprite; + } + + public Sprite getButtonSprite() { + return buttonSprite; + } + + public Sprite getButtonHoverOverlay() { + return buttonHoverOverlay; + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/Sprite.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/Sprite.java new file mode 100644 index 000000000..3db410a6f --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/Sprite.java @@ -0,0 +1,169 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import net.minecraft.block.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.util.Identifier; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +public class Sprite implements ISprite { + public static final Sprite EMPTY = new Sprite(ElementBase.MECH_ELEMENTS, 0, 0, 0, 0); + public static final Sprite SLOT_NORMAL = new Sprite(ElementBase.MECH_ELEMENTS, 0, 0, 18, 18); + public static final Sprite CHARGE_SLOT_ICON = new Sprite(ElementBase.MECH_ELEMENTS, 18, 0, 18, 18); + public static final Sprite DISCHARGE_SLOT_ICON = new Sprite(ElementBase.MECH_ELEMENTS, 36, 0, 18, 18); + public static final Sprite ENERGY_BAR = new Sprite(ElementBase.MECH_ELEMENTS, 0, 18, 12, 40); + public static final Sprite ENERGY_BAR_BACKGROUND = new Sprite(ElementBase.MECH_ELEMENTS, 12, 18, 14, 42); + public static final Sprite TOP_ENERGY_BAR = new Sprite(ElementBase.MECH_ELEMENTS, 0, 215, 167, 2); + public static final Sprite TOP_ENERGY_BAR_BACKGROUND = new Sprite(ElementBase.MECH_ELEMENTS, 0, 217, 169, 3); + public static final Sprite LEFT_TAB = new Sprite(ElementBase.MECH_ELEMENTS, 0, 86, 23, 26); + public static final Sprite LEFT_TAB_SELECTED = new Sprite(ElementBase.MECH_ELEMENTS, 0, 60, 29, 26); + public static final Sprite CONFIGURE_ICON = new Sprite(ElementBase.MECH_ELEMENTS, 26, 18, 16, 16); + public static final Sprite REDSTONE_DISABLED_ICON = new Sprite(new ItemStack(Items.GUNPOWDER)); + public static final Sprite REDSTONE_LOW_ICON = new Sprite(new ItemStack(Items.REDSTONE)); + public static final Sprite REDSTONE_HIGH_ICON = new Sprite(new ItemStack(Blocks.REDSTONE_TORCH)); + public static final Sprite UPGRADE_ICON = new Sprite(ElementBase.MECH_ELEMENTS, 26, 34, 16, 16); + public static final Sprite ENERGY_ICON = new Sprite(ElementBase.MECH_ELEMENTS, 46, 19, 9, 13); + public static final Sprite ENERGY_ICON_EMPTY = new Sprite(ElementBase.MECH_ELEMENTS, 62, 19, 9, 13); + public static final Sprite JEI_ICON = new Sprite(ElementBase.MECH_ELEMENTS, 42, 34, 16, 16); + public static final Sprite BUTTON_SLOT_NORMAL = new Sprite(ElementBase.MECH_ELEMENTS, 54, 0, 18, 18); + public static final Sprite FAKE_SLOT = new Sprite(ElementBase.MECH_ELEMENTS, 72, 0, 18, 18); + public static final Sprite BUTTON_HOVER_OVERLAY_SLOT_NORMAL = new Sprite(ElementBase.MECH_ELEMENTS, 90, 0, 18, 18); + public static final Sprite SLOT_CONFIG_POPUP = new Sprite(ElementBase.MECH_ELEMENTS, 29, 60, 62, 62); + public static final Sprite.Button EXIT_BUTTON = new Sprite.Button(new Sprite(ElementBase.MECH_ELEMENTS, 26, 122, 13, 13), new Sprite(ElementBase.MECH_ELEMENTS, 39, 122, 13, 13)); + public static final Sprite.CheckBox DARK_CHECK_BOX = new Sprite.CheckBox(new Sprite(ElementBase.MECH_ELEMENTS, 74, 18, 13, 13), new Sprite(ElementBase.MECH_ELEMENTS, 87, 18, 16, 13)); + public static final Sprite.CheckBox LIGHT_CHECK_BOX = new Sprite.CheckBox(new Sprite(ElementBase.MECH_ELEMENTS, 74, 31, 13, 13), new Sprite(ElementBase.MECH_ELEMENTS, 87, 31, 16, 13)); + + public final Identifier textureLocation; + public final int x; + public final int y; + public final int width; + public final int height; + public int offsetX = 0; + public int offsetY = 0; + public ItemStack itemStack; + + public Sprite(Identifier textureLocation, int x, int y, int width, int height) { + this.textureLocation = textureLocation; + this.x = x; + this.y = y; + this.width = width; + this.height = height; + this.itemStack = null; + } + + public Sprite(ItemStack stack) { + this.textureLocation = null; + this.x = -1; + this.y = -1; + this.width = -1; + this.height = -1; + this.itemStack = stack; + } + + public boolean hasStack() { + return itemStack != null; + } + + public boolean hasTextureInfo() { + return x >= 0 && y >= 0 && width >= 0 && height >= 0; + } + + public Sprite setOffsetX(int offsetX) { + this.offsetX = offsetX; + return this; + } + + public Sprite setOffsetY(int offsetY) { + this.offsetY = offsetY; + return this; + } + + @Override + public Sprite getSprite(MachineBaseBlockEntity provider) { + return this; + } + + public static class Button { + private final Sprite normal; + private final Sprite hovered; + + public Button(Sprite normal, Sprite hovered) { + this.normal = normal; + this.hovered = hovered; + } + + public Sprite getNormal() { + return normal; + } + + public Sprite getHovered() { + return hovered; + } + } + + public static class ToggleButton { + private final Sprite normal; + private final Sprite hovered; + private final Sprite pressed; + + public ToggleButton(Sprite normal, Sprite hovered, Sprite pressed) { + this.normal = normal; + this.hovered = hovered; + this.pressed = pressed; + } + + public Sprite getNormal() { + return normal; + } + + public Sprite getHovered() { + return hovered; + } + + public Sprite getPressed() { + return pressed; + } + } + + public static class CheckBox { + private final Sprite normal; + private final Sprite ticked; + + public CheckBox(Sprite normal, Sprite ticked) { + this.normal = normal; + this.ticked = ticked; + } + + public Sprite getNormal() { + return normal; + } + + public Sprite getTicked() { + return ticked; + } + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SpriteContainer.java b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SpriteContainer.java new file mode 100644 index 000000000..17fd403d2 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/slot/elements/SpriteContainer.java @@ -0,0 +1,78 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.slot.elements; + +import java.util.ArrayList; +import java.util.List; + +public class SpriteContainer { + public List offsetSprites = new ArrayList<>(); + + public SpriteContainer setSprite(int index, OffsetSprite sprite) { + offsetSprites.set(index, sprite); + return this; + } + + public SpriteContainer setSprite(int index, ISprite sprite, int offsetX, int offsetY) { + if (sprite instanceof Sprite) { + offsetSprites.set(index, new OffsetSprite(sprite).setOffsetX(((Sprite) sprite).offsetX + offsetX).setOffsetY(((Sprite) sprite).offsetY + offsetY)); + } else { + offsetSprites.set(index, new OffsetSprite(sprite, offsetX, offsetY)); + } + return this; + } + + public SpriteContainer setSprite(int index, ISprite sprite) { + if (sprite instanceof Sprite) { + offsetSprites.set(index, new OffsetSprite(sprite).setOffsetX(((Sprite) sprite).offsetX).setOffsetY(((Sprite) sprite).offsetY)); + } else { + offsetSprites.add(index, new OffsetSprite(sprite)); + } + return this; + } + + public SpriteContainer addSprite(OffsetSprite sprite) { + offsetSprites.add(sprite); + return this; + } + + public SpriteContainer addSprite(ISprite sprite, int offsetX, int offsetY) { + if (sprite instanceof Sprite) { + offsetSprites.add(new OffsetSprite(sprite).setOffsetX(((Sprite) sprite).offsetX + offsetX).setOffsetY(((Sprite) sprite).offsetY + offsetY)); + } else { + offsetSprites.add(new OffsetSprite(sprite, offsetX, offsetY)); + } + return this; + } + + public SpriteContainer addSprite(ISprite sprite) { + if (sprite instanceof Sprite) { + offsetSprites.add(new OffsetSprite(sprite).setOffsetX(((Sprite) sprite).offsetX).setOffsetY(((Sprite) sprite).offsetY)); + } else { + offsetSprites.add(new OffsetSprite(sprite)); + } + return this; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonExtended.java b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonExtended.java new file mode 100644 index 000000000..d6ef0f471 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonExtended.java @@ -0,0 +1,56 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.widget; + +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; +import org.apache.logging.log4j.util.TriConsumer; + + +public class GuiButtonExtended extends GuiButtonSimple { + + private TriConsumer clickHandler; + + public GuiButtonExtended(int x, int y, Text buttonText, ButtonWidget.PressAction pressAction) { + super(x, y, 20, 200, buttonText, pressAction); + } + + public GuiButtonExtended(int x, int y, int widthIn, int heightIn, Text buttonText, ButtonWidget.PressAction pressAction) { + super(x, y, widthIn, heightIn, buttonText, pressAction); + } + + public GuiButtonExtended clickHandler(TriConsumer consumer) { + clickHandler = consumer; + return this; + } + + @Override + public void onClick(double mouseX, double mouseY) { + if (clickHandler != null) { + clickHandler.accept(this, mouseX, mouseY); + } + super.onClick(mouseY, mouseY); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonHologram.java b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonHologram.java new file mode 100644 index 000000000..6ef2c482b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonHologram.java @@ -0,0 +1,50 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.widget; + +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import reborncore.client.gui.builder.GuiBase; + +/** + * Created by Prospector + */ +public class GuiButtonHologram extends GuiButtonExtended { + + GuiBase.Layer layer; + GuiBase gui; + + public GuiButtonHologram(int x, int y, GuiBase gui, GuiBase.Layer layer, ButtonWidget.PressAction pressAction) { + super(x, y, 20, 12, LiteralText.EMPTY, pressAction); + this.layer = layer; + this.gui = gui; + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { + + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonSimple.java b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonSimple.java new file mode 100644 index 000000000..c1e0488e1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonSimple.java @@ -0,0 +1,38 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.widget; + +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.text.Text; + +public class GuiButtonSimple extends ButtonWidget { + public GuiButtonSimple(int x, int y, Text buttonText, ButtonWidget.PressAction pressAction) { + super(x, y, 20, 200, buttonText, pressAction); + } + + public GuiButtonSimple(int x, int y, int widthIn, int heightIn, Text buttonText, ButtonWidget.PressAction pressAction) { + super(x, y, widthIn, heightIn, buttonText, pressAction); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonUpDown.java b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonUpDown.java new file mode 100644 index 000000000..4221f5e1d --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/builder/widget/GuiButtonUpDown.java @@ -0,0 +1,74 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.builder.widget; + +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.LiteralText; +import reborncore.client.gui.builder.GuiBase; + +/** + * @author drcrazy + */ +public class GuiButtonUpDown extends GuiButtonExtended { + + GuiBase gui; + UpDownButtonType type; + + public GuiButtonUpDown(int x, int y, GuiBase gui, ButtonWidget.PressAction pressAction, UpDownButtonType type) { + super(x, y, 12, 12, LiteralText.EMPTY, pressAction); + this.gui = gui; + this.type = type; + } + + @Override + public void renderButton(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { + if (gui.hideGuiElements()) return; + gui.getMinecraft().getTextureManager().bindTexture(gui.builder.getResourceLocation()); + switch (type) { + case FASTFORWARD: + gui.drawTexture(matrixStack, x, y, 174, 74, 12, 12); + break; + case FORWARD: + gui.drawTexture(matrixStack, x, y, 174, 86, 12, 12); + break; + case REWIND: + gui.drawTexture(matrixStack, x, y, 174, 98, 12, 12); + break; + case FASTREWIND: + gui.drawTexture(matrixStack, x, y, 174, 110, 12, 12); + break; + default: + break; + } + } + + public enum UpDownButtonType { + FASTFORWARD, + FORWARD, + REWIND, + FASTREWIND + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/componets/BaseTextures.java b/RebornCore/src/main/java/reborncore/client/gui/componets/BaseTextures.java new file mode 100644 index 000000000..43a9ed713 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/componets/BaseTextures.java @@ -0,0 +1,61 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.componets; + +public class BaseTextures { + // + // private static final ResourceLocation baseTexture = new ResourceLocation("reborncore", "textures/gui/base.png"); + // + // public GuiTexture background; + // public GuiTexture slot; + // public GuiTexture burnBase; + // public GuiTexture burnOverlay; + // public GuiTexture powerBase; + // public GuiTexture powerOverlay; + // public GuiTexture progressBase; + // public GuiTexture progressOverlay; + // public GuiTexture tank; + // public GuiTexture tankBase; + // public GuiTexture tankScale; + // public GuiTexture powerBaseOld; + // public GuiTexture powerOverlayOld; + // + // public BaseTextures() + // { + // background = new GuiTexture(baseTexture, 176, 166, 0, 0); + // slot = new GuiTexture(baseTexture, 18, 18, 176, 31); + // burnBase = new GuiTexture(baseTexture, 14, 14, 176, 0); + // burnOverlay = new GuiTexture(baseTexture, 13, 13, 176, 50); + // powerBase = new GuiTexture(baseTexture, 7, 13, 190, 0); + // powerOverlay = new GuiTexture(baseTexture, 7, 13, 197, 0); + // progressBase = new GuiTexture(baseTexture, 22, 15, 200, 14); + // progressOverlay = new GuiTexture(baseTexture, 22, 16, 177, 14); + // tank = new GuiTexture(baseTexture, 20, 55, 176, 63); + // tankBase = new GuiTexture(baseTexture, 20, 55, 196, 63); + // tankScale = new GuiTexture(baseTexture, 20, 55, 216, 63); + // powerBaseOld = new GuiTexture(baseTexture, 32, 17, 224, 13); + // powerOverlayOld = new GuiTexture(baseTexture, 32, 17, 224, 30); + // } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/componets/GuiHiddenButton.java b/RebornCore/src/main/java/reborncore/client/gui/componets/GuiHiddenButton.java new file mode 100644 index 000000000..0dc136c63 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/componets/GuiHiddenButton.java @@ -0,0 +1,70 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.componets; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.gui.widget.ButtonWidget; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.text.Text; +import org.lwjgl.opengl.GL11; + +public class GuiHiddenButton extends ButtonWidget { + + public GuiHiddenButton(int xPosition, int yPosition, Text displayString) { + super(xPosition, yPosition, 0, 0, displayString, var1 -> { + }); + } + + public GuiHiddenButton(int id, int xPosition, int yPosition, int width, int height, Text displayString) { + super(xPosition, yPosition, width, height, displayString, var1 -> { + }); + } + + @Override + public void render(MatrixStack matrixStack, int mouseX, int mouseY, float partialTicks) { + if (this.visible) { + TextRenderer fontrenderer = MinecraftClient.getInstance().textRenderer; + MinecraftClient.getInstance().getTextureManager().bindTexture(WIDGETS_LOCATION); + GL11.glColor4f(1.0F, 1.0F, 1.0F, 1.0F); + this.hovered = mouseX >= this.x && mouseY >= this.y + && mouseX < this.x + this.width && mouseY < this.y + this.height; + GL11.glEnable(GL11.GL_BLEND); + RenderSystem.blendFuncSeparate(770, 771, 1, 0); + GL11.glBlendFunc(GL11.GL_SRC_ALPHA, GL11.GL_ONE_MINUS_SRC_ALPHA); + int l = 14737632; + + if (!this.active) { + l = 10526880; + } else if (this.isHovered()) { + l = 16777120; + } + + this.drawTextWithShadow(matrixStack, fontrenderer, this.getMessage(), this.x + this.width / 2, + this.y + (this.height - 8) / 2, l); + } + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/guibuilder/GuiBuilder.java b/RebornCore/src/main/java/reborncore/client/gui/guibuilder/GuiBuilder.java new file mode 100644 index 000000000..2131b6340 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/guibuilder/GuiBuilder.java @@ -0,0 +1,825 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.guibuilder; + +import com.google.common.collect.Lists; +import com.mojang.blaze3d.systems.RenderSystem; +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.DrawableHelper; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.widget.EntryListWidget; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.VertexFormats; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemStack; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; +import reborncore.api.IListInfoProvider; +import reborncore.client.RenderUtil; +import reborncore.client.gui.builder.GuiBase; +import reborncore.client.gui.builder.slot.GuiTab; +import reborncore.common.fluid.FluidUtil; +import reborncore.common.fluid.FluidValue; +import reborncore.common.fluid.container.FluidInstance; +import reborncore.common.powerSystem.PowerSystem; +import reborncore.common.powerSystem.PowerSystem.EnergySystem; +import reborncore.common.util.StringUtils; + +import java.util.ArrayList; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Created by Gigabit101 on 08/08/2016. + */ +public class GuiBuilder { + public static final Identifier defaultTextureSheet = new Identifier("reborncore", "textures/gui/guielements.png"); + private static final Text SPACE_TEXT = new LiteralText(" "); + static Identifier resourceLocation; + + public GuiBuilder() { + GuiBuilder.resourceLocation = defaultTextureSheet; + } + + public GuiBuilder(Identifier resourceLocation) { + GuiBuilder.resourceLocation = resourceLocation; + } + + public Identifier getResourceLocation() { + return resourceLocation; + } + + public void drawDefaultBackground(MatrixStack matrixStack, Screen gui, int x, int y, int width, int height) { + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + MinecraftClient.getInstance().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 0, 0, width / 2, height / 2); + gui.drawTexture(matrixStack, x + width / 2, y, 150 - width / 2, 0, width / 2, height / 2); + gui.drawTexture(matrixStack, x, y + height / 2, 0, 150 - height / 2, width / 2, height / 2); + gui.drawTexture(matrixStack, x + width / 2, y + height / 2, 150 - width / 2, 150 - height / 2, width / 2, + height / 2); + } + + public void drawPlayerSlots(MatrixStack matrixStack, Screen gui, int posX, int posY, boolean center) { + MinecraftClient.getInstance().getTextureManager().bindTexture(resourceLocation); + + if (center) { + posX -= 81; + } + + for (int y = 0; y < 3; y++) { + for (int x = 0; x < 9; x++) { + gui.drawTexture(matrixStack, posX + x * 18, posY + y * 18, 150, 0, 18, 18); + } + } + + for (int x = 0; x < 9; x++) { + gui.drawTexture(matrixStack, posX + x * 18, posY + 58, 150, 0, 18, 18); + } + } + + public void drawSlot(MatrixStack matrixStack, Screen gui, int posX, int posY) { + MinecraftClient.getInstance().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, posX, posY, 150, 0, 18, 18); + } + + public void drawText(MatrixStack matrixStack, GuiBase gui, Text text, int x, int y, int color) { + gui.getTextRenderer().draw(matrixStack, text, x, y, color); + } + + public void drawProgressBar(MatrixStack matrixStack, GuiBase gui, double progress, int x, int y) { + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 150, 18, 22, 15); + int j = (int) (progress); + if (j > 0) { + gui.drawTexture(matrixStack, x, y, 150, 34, j + 1, 15); + } + } + + public void drawOutputSlot(MatrixStack matrixStack, GuiBase gui, int x, int y) { + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 174, 0, 26, 26); + } + + /** + * Draws button with JEI icon in the given coords. + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place button + * @param y int Top left corner where to place button + * @param layer Layer Layer to draw on + */ + public void drawJEIButton(MatrixStack matrixStack, GuiBase gui, int x, int y, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + if (FabricLoader.getInstance().isModLoaded("jei")) { + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 202, 0, 12, 12); + } + } + + /** + * Draws lock button in either locked or unlocked state + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place button + * @param y int Top left corner where to place button + * @param mouseX int Mouse cursor position to check for tooltip + * @param mouseY int Mouse cursor position to check for tooltip + * @param layer Layer Layer to draw on + * @param locked boolean Set to true if it is in locked state + */ + public void drawLockButton(MatrixStack matrixStack, GuiBase gui, int x, int y, int mouseX, int mouseY, GuiBase.Layer layer, boolean locked) { + if (gui.hideGuiElements()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 174, 26 + (locked ? 12 : 0), 20, 12); + if (gui.isPointInRect(x, y, 20, 12, mouseX, mouseY)) { + List list = new ArrayList<>(); + if (locked) { + list.add(new TranslatableText("reborncore.gui.tooltip.unlock_items")); + } else { + list.add(new TranslatableText("reborncore.gui.tooltip.lock_items")); + } + RenderSystem.pushMatrix(); + gui.renderTooltip(matrixStack, list, mouseX, mouseY); + RenderSystem.popMatrix(); + } + } + + /** + * Draws hologram toggle button + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place button + * @param y int Top left corner where to place button + * @param mouseX int Mouse cursor position to check for tooltip + * @param mouseY int Mouse cursor position to check for tooltip + * @param layer Layer Layer to draw on + */ + public void drawHologramButton(MatrixStack matrixStack, GuiBase gui, int x, int y, int mouseX, int mouseY, GuiBase.Layer layer) { + if (gui.isTabOpen()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + if (gui.getMachine().renderMultiblock) { + gui.drawTexture(matrixStack, x, y, 174, 62, 20, 12); + } else { + gui.drawTexture(matrixStack, x, y, 174, 50, 20, 12); + } + if (gui.isPointInRect(x, y, 20, 12, mouseX, mouseY)) { + List list = new ArrayList<>(); + list.add(new TranslatableText("reborncore.gui.tooltip.hologram")); + RenderSystem.pushMatrix(); + if (layer == GuiBase.Layer.FOREGROUND) { + mouseX -= gui.getGuiLeft(); + mouseY -= gui.getGuiTop(); + } + gui.renderTooltip(matrixStack, list, mouseX, mouseY); + RenderSystem.popMatrix(); + } + } + + /** + * Draws big horizontal bar for heat value + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place bar + * @param y int Top left corner where to place bar + * @param value int Current heat value + * @param max int Maximum heat value + * @param layer Layer Layer to draw on + */ + public void drawBigHeatBar(MatrixStack matrixStack, GuiBase gui, int x, int y, int value, int max, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 26, 218, 114, 18); + if (value != 0) { + int j = (int) ((double) value / (double) max * 106); + if (j < 0) { + j = 0; + } + gui.drawTexture(matrixStack, x + 4, y + 4, 26, 246, j, 10); + + Text text = new LiteralText(String.valueOf(value)) + .append(new TranslatableText("reborncore.gui.heat")); + + gui.drawCentredText(matrixStack, text, y + 5, 0xFFFFFF, layer); + } + } + + /** + * Draws big horizontal blue bar + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place bar + * @param y int Top left corner where to place bar + * @param value int Current value + * @param max int Maximum value + * @param mouseX int Mouse cursor position to check for tooltip + * @param mouseY int Mouse cursor position to check for tooltip + * @param suffix String String to put on the bar and tooltip after percentage value + * @param line2 String String to put into tooltip as a second line + * @param format String Formatted value to put on the bar + * @param layer Layer Layer to draw on + */ + public void drawBigBlueBar(MatrixStack matrixStack, GuiBase gui, int x, int y, int value, int max, int mouseX, int mouseY, String suffix, Text line2, String format, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + int j = (int) ((double) value / (double) max * 106); + if (j < 0) { + j = 0; + } + gui.drawTexture(matrixStack, x + 4, y + 4, 0, 236, j, 10); + if (!suffix.equals("")) { + suffix = " " + suffix; + } + gui.drawCentredText(matrixStack, new LiteralText(format).append(suffix), y + 5, 0xFFFFFF, layer); + if (gui.isPointInRect(x, y, 114, 18, mouseX, mouseY)) { + int percentage = percentage(max, value); + List list = new ArrayList<>(); + + list.add( + new LiteralText(String.valueOf(value)) + .formatted(Formatting.GOLD) + .append("/") + .append(String.valueOf(max)) + .append(suffix) + ); + + list.add( + new LiteralText(String.valueOf(percentage)) + .formatted(StringUtils.getPercentageColour(percentage)) + .append("%") + .append( + new TranslatableText("reborncore.gui.tooltip.dsu_fullness") + .formatted(Formatting.GRAY) + ) + ); + + list.add(line2); + + if (value > max) { + list.add( + new LiteralText("Yo this is storing more than it should be able to") + .formatted(Formatting.GRAY) + ); + list.add( + new LiteralText("prolly a bug") + .formatted(Formatting.GRAY) + ); + list.add( + new LiteralText("pls report and tell how tf you did this") + .formatted(Formatting.GRAY) + ); + } + if (layer == GuiBase.Layer.FOREGROUND) { + mouseX -= gui.getGuiLeft(); + mouseY -= gui.getGuiTop(); + } + gui.renderTooltip(matrixStack, list, mouseX, mouseY); + RenderSystem.disableLighting(); + RenderSystem.color4f(1, 1, 1, 1); + } + } + + public void drawBigBlueBar(MatrixStack matrixStack, GuiBase gui, int x, int y, int value, int max, int mouseX, int mouseY, String suffix, GuiBase.Layer layer) { + drawBigBlueBar(matrixStack, gui, x, y, value, max, mouseX, mouseY, suffix, LiteralText.EMPTY, Integer.toString(value), layer); + + } + + public void drawBigBlueBar(MatrixStack matrixStack, GuiBase gui, int x, int y, int value, int max, int mouseX, int mouseY, GuiBase.Layer layer) { + drawBigBlueBar(matrixStack, gui, x, y, value, max, mouseX, mouseY, "", LiteralText.EMPTY, "", layer); + } + + /** + * Shades GUI and draw gray bar on top of GUI + * + * @param gui GuiBase GUI to draw on + * @param layer Layer Layer to draw on + */ + public void drawMultiblockMissingBar(MatrixStack matrixStack, GuiBase gui, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + int x = 0; + int y = 4; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + RenderSystem.disableLighting(); + RenderSystem.enableDepthTest(); + RenderSystem.colorMask(true, true, true, false); + RenderUtil.drawGradientRect(0, x, y, x + 176, y + 20, 0x000000, 0xC0000000); + RenderUtil.drawGradientRect(0, x, y + 20, x + 176, y + 20 + 48, 0xC0000000, 0xC0000000); + RenderUtil.drawGradientRect(0, x, y + 68, x + 176, y + 70 + 20, 0xC0000000, 0x00000000); + RenderSystem.colorMask(true, true, true, true); + RenderSystem.disableDepthTest(); + gui.drawCentredText(matrixStack, new TranslatableText("reborncore.gui.missingmultiblock"), 43, 0xFFFFFF, layer); + } + + /** + * Draws upgrade slots on the left side of machine GUI. Draws on the background + * level. + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place slots + * @param y int Top left corner where to place slots + */ + public void drawUpgrades(MatrixStack matrixStack, GuiBase gui, int x, int y) { + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 217, 0, 24, 81); + } + + /** + * Draws tab on the left side of machine GUI. Draws on the background level. + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place tab + * @param y int Top left corner where to place tab + * @param stack ItemStack Item to show as tab icon + */ + public void drawSlotTab(MatrixStack matrixStack, GuiBase gui, int x, int y, ItemStack stack) { + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 217, 82, 24, 24); + gui.getMinecraft().getItemRenderer().renderInGuiWithOverrides(stack, x + 5, y + 4); + } + + + /** + * Draws Slot Configuration tips instead of player inventory + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place tips list + * @param y int Top left corner where to place tips list + * @param mouseX int Mouse cursor position + * @param mouseY int Mouse cursor position + */ + public void drawSlotConfigTips(MatrixStack matrixStack, GuiBase gui, int x, int y, int mouseX, int mouseY, GuiTab guiTab) { + List tips = guiTab.getTips().stream() + .map(TranslatableText::new) + .collect(Collectors.toList()); + + TipsListWidget explanation = new TipsListWidget(gui, gui.getScreenWidth() - 14, 54, y, y + 76, 9 + 2, tips); + explanation.setLeftPos(x - 81); + explanation.render(matrixStack, mouseX, mouseY, 1.0f); + RenderSystem.color4f(1, 1, 1, 1); + } + + + private class TipsListWidget extends EntryListWidget { + + public TipsListWidget(GuiBase gui, int width, int height, int top, int bottom, int entryHeight, List tips) { + super(gui.getMinecraft(), width, height, top, bottom, entryHeight); + for (Text tip : tips) { + this.addEntry(new TipsListEntry(tip)); + } + } + + @Override + public int getRowWidth() { + return 162; + } + + @Override + protected void renderBackground(MatrixStack matrixStack) { + + } + + @Override + public void render(MatrixStack matrices, int mouseX, int mouseY, float delta) { + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferBuilder = tessellator.getBuffer(); + this.client.getTextureManager().bindTexture(DrawableHelper.OPTIONS_BACKGROUND_TEXTURE); + RenderSystem.color4f(1.0F, 1.0F, 1.0F, 1.0F); + bufferBuilder.begin(7, VertexFormats.POSITION_TEXTURE_COLOR); + bufferBuilder.vertex(this.left, this.bottom, 0.0D).texture((float) this.left / 32.0F, (float) (this.bottom + (int) this.getScrollAmount()) / 32.0F).color(32, 32, 32, 255).next(); + bufferBuilder.vertex(this.right, this.bottom, 0.0D).texture((float) this.right / 32.0F, (float) (this.bottom + (int) this.getScrollAmount()) / 32.0F).color(32, 32, 32, 255).next(); + bufferBuilder.vertex(this.right, this.top, 0.0D).texture((float) this.right / 32.0F, (float) (this.top + (int) this.getScrollAmount()) / 32.0F).color(32, 32, 32, 255).next(); + bufferBuilder.vertex(this.left, this.top, 0.0D).texture((float) this.left / 32.0F, (float) (this.top + (int) this.getScrollAmount()) / 32.0F).color(32, 32, 32, 255).next(); + tessellator.draw(); + + super.renderList(matrices, this.getRowLeft(), this.top, mouseX, mouseY, delta); + } + + private class TipsListEntry extends EntryListWidget.Entry { + private final Text tip; + + public TipsListEntry(Text tip) { + this.tip = tip; + } + + @Override + public void render(MatrixStack matrixStack, int index, int y, int x, int width, int height, int mouseX, int mouseY, boolean hovering, float delta) { + MinecraftClient.getInstance().textRenderer.drawTrimmed(tip, x, y, width, 11184810); + } + } + } + + //TODO: change to double + /** + * Draws energy output value and icon + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place energy output + * @param y int Top left corner where to place energy output + * @param maxOutput int Energy output value + * @param layer Layer Layer to draw on + */ + public void drawEnergyOutput(MatrixStack matrixStack, GuiBase gui, int x, int y, int maxOutput, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + Text text = new LiteralText(PowerSystem.getLocalizedPowerNoSuffix(maxOutput)) + .append(SPACE_TEXT) + .append(PowerSystem.getDisplayPower().abbreviation) + .append("\t"); + + int width = gui.getTextRenderer().getWidth(text); + gui.drawText(matrixStack, text, x - width - 2, y + 5, 0, layer); + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 150, 91, 16, 16); + } + + /** + * Draws progress arrow in direction specified. + * + * @param gui GuiBase GUI to draw on + * @param progress int Current progress + * @param maxProgress int Maximum progress + * @param x int Top left corner where to place progress arrow + * @param y int Top left corner where to place progress arrow + * @param mouseX int Mouse cursor position to check for tooltip + * @param mouseY int Mouse cursor position to check for tooltip + * @param direction ProgressDirection Direction of progress arrow + * @param layer Layer Layer to draw on + */ + public void drawProgressBar(MatrixStack matrixStack, GuiBase gui, int progress, int maxProgress, int x, int y, int mouseX, int mouseY, ProgressDirection direction, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, direction.x, direction.y, direction.width, direction.height); + int j = (int) ((double) progress / (double) maxProgress * 16); + if (j < 0) { + j = 0; + } + + switch (direction) { + case RIGHT: + gui.drawTexture(matrixStack, x, y, direction.xActive, direction.yActive, j, 10); + break; + case LEFT: + gui.drawTexture(matrixStack, x + 16 - j, y, direction.xActive + 16 - j, direction.yActive, j, 10); + break; + case UP: + gui.drawTexture(matrixStack, x, y + 16 - j, direction.xActive, direction.yActive + 16 - j, 10, j); + break; + case DOWN: + gui.drawTexture(matrixStack, x, y, direction.xActive, direction.yActive, 10, j); + break; + default: + return; + } + + if (gui.isPointInRect(x, y, direction.width, direction.height, mouseX, mouseY)) { + int percentage = percentage(maxProgress, progress); + List list = new ArrayList<>(); + list.add( + new LiteralText(String.valueOf(percentage)) + .formatted(StringUtils.getPercentageColour(percentage)) + .append("%") + ); + if (layer == GuiBase.Layer.FOREGROUND) { + mouseX -= gui.getGuiLeft(); + mouseY -= gui.getGuiTop(); + } + gui.renderTooltip(matrixStack, list, mouseX, mouseY); + RenderSystem.disableLighting(); + RenderSystem.color4f(1, 1, 1, 1); + } + } + + /** + * Draws multi-energy bar + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place energy bar + * @param y int Top left corner where to place energy bar + * @param energyStored int Current amount of energy + * @param maxEnergyStored int Maximum amount of energy + * @param mouseX int Mouse cursor position to check for tooltip + * @param mouseY int Mouse cursor position to check for tooltip + * @param buttonID int Button ID used to switch energy systems + * @param layer Layer Layer to draw on + */ + public void drawMultiEnergyBar(MatrixStack matrixStack, GuiBase gui, int x, int y, int energyStored, int maxEnergyStored, int mouseX, + int mouseY, int buttonID, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + + EnergySystem displayPower = PowerSystem.getDisplayPower(); + MinecraftClient.getInstance().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, displayPower.xBar - 15, displayPower.yBar - 1, 14, 50); + int draw = (int) ((double) energyStored / (double) maxEnergyStored * (48)); + if (energyStored > maxEnergyStored) { + draw = 48; + } + gui.drawTexture(matrixStack, x + 1, y + 49 - draw, displayPower.xBar, 48 + displayPower.yBar - draw, 12, draw); + int percentage = percentage(maxEnergyStored, energyStored); + if (gui.isPointInRect(x + 1, y + 1, 11, 48, mouseX, mouseY)) { + List list = Lists.newArrayList(); + if (Screen.hasShiftDown()) { + list.add( + new LiteralText(PowerSystem.getLocalizedPowerFullNoSuffix(energyStored)) + .formatted(Formatting.GOLD) + .append("/") + .append(PowerSystem.getLocalizedPowerFull(maxEnergyStored)) + ); + } else { + list.add( + new LiteralText(PowerSystem.getLocalizedPowerNoSuffix(energyStored)) + .formatted(Formatting.GOLD) + .append("/") + .append(PowerSystem.getLocalizedPower(maxEnergyStored)) + ); + } + list.add( + StringUtils.getPercentageText(percentage) + .append(SPACE_TEXT) + .append( + new TranslatableText("reborncore.gui.tooltip.power_charged") + .formatted(Formatting.GRAY) + ) + ); + + if (gui.be instanceof IListInfoProvider) { + if (Screen.hasShiftDown()) { + ((IListInfoProvider) gui.be).addInfo(list, true, true); + } else { + list.add(LiteralText.EMPTY); + + list.add( + new LiteralText("Shift") + .formatted(Formatting.BLUE) + .append(SPACE_TEXT) + .formatted(Formatting.GRAY) + .append(new TranslatableText("reborncore.gui.tooltip.power_moreinfo")) + ); + } + } + if (layer == GuiBase.Layer.FOREGROUND) { + mouseX -= gui.getGuiLeft(); + mouseY -= gui.getGuiTop(); + } + gui.renderTooltip(matrixStack, list, mouseX, mouseY); + RenderSystem.disableLighting(); + RenderSystem.color4f(1, 1, 1, 1); + } + } + + /** + * Draws tank and fluid inside it + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner of tank + * @param y int Top left corner of tank + * @param mouseX int Mouse cursor position to check for tooltip + * @param mouseY int Mouse cursor position to check for tooltip + * @param fluid FluidStack Fluid to draw in tank + * @param maxCapacity int Maximum tank capacity + * @param isTankEmpty boolean True if tank is empty + * @param layer Layer Layer to draw on + */ + public void drawTank(MatrixStack matrixStack, GuiBase gui, int x, int y, int mouseX, int mouseY, FluidInstance fluid, FluidValue maxCapacity, boolean isTankEmpty, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + + int percentage = 0; + FluidValue amount = FluidValue.EMPTY; + if (!isTankEmpty) { + amount = fluid.getAmount(); + percentage = percentage(maxCapacity.getRawValue(), amount.getRawValue()); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 194, 26, 22, 56); + if (!isTankEmpty) { + drawFluid(matrixStack, gui, fluid, x + 4, y + 4, 14, 48, maxCapacity.getRawValue()); + } + gui.drawTexture(matrixStack, x + 3, y + 3, 194, 82, 16, 50); + + if (gui.isPointInRect(x, y, 22, 56, mouseX, mouseY)) { + List list = new ArrayList<>(); + if (isTankEmpty) { + list.add(new TranslatableText("reborncore.gui.tooltip.tank_empty").formatted(Formatting.GOLD)); + } else { + list.add( + new LiteralText(String.format("%s / %s", amount, maxCapacity)) + .formatted(Formatting.GOLD) + .append(SPACE_TEXT) + .append(FluidUtil.getFluidName(fluid)) + ); + } + + list.add( + StringUtils.getPercentageText(percentage) + .formatted(Formatting.GRAY) + .append(SPACE_TEXT) + .append(new TranslatableText("reborncore.gui.tooltip.tank_fullness")) + ); + + if (layer == GuiBase.Layer.FOREGROUND) { + mouseX -= gui.getGuiLeft(); + mouseY -= gui.getGuiTop(); + } + gui.renderTooltip(matrixStack, list, mouseX, mouseY); + RenderSystem.disableLighting(); + RenderSystem.color4f(1, 1, 1, 1); + } + } + + /** + * Draws fluid in tank + * + * @param gui GuiBase GUI to draw on + * @param fluid FluidStack Fluid to draw + * @param x int Top left corner of fluid + * @param y int Top left corner of fluid + * @param width int Width of fluid to draw + * @param height int Height of fluid to draw + * @param maxCapacity int Maximum capacity of tank + */ + public void drawFluid(MatrixStack matrixStack, GuiBase gui, FluidInstance fluid, int x, int y, int width, int height, int maxCapacity) { + if (fluid.getFluid() == Fluids.EMPTY) { + return; + } + gui.getMinecraft().getTextureManager().bindTexture(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE); + y += height; + final Sprite sprite = FluidRenderHandlerRegistry.INSTANCE.get(fluid.getFluid()).getFluidSprites(gui.getMachine().getWorld(), gui.getMachine().getPos(), fluid.getFluid().getDefaultState())[0]; + int color = FluidRenderHandlerRegistry.INSTANCE.get(fluid.getFluid()).getFluidColor(gui.getMachine().getWorld(), gui.getMachine().getPos(), fluid.getFluid().getDefaultState()); + + final int drawHeight = (int) (fluid.getAmount().getRawValue() / (maxCapacity * 1F) * height); + final int iconHeight = sprite.getHeight(); + int offsetHeight = drawHeight; + + RenderSystem.color3f((color >> 16 & 255) / 255.0F, (float) (color >> 8 & 255) / 255.0F, (float) (color & 255) / 255.0F); + + int iteration = 0; + while (offsetHeight != 0) { + final int curHeight = offsetHeight < iconHeight ? offsetHeight : iconHeight; + + DrawableHelper.drawSprite(matrixStack, x, y - offsetHeight, 0, width, curHeight, sprite); + offsetHeight -= curHeight; + iteration++; + if (iteration > 50) { + break; + } + } + RenderSystem.color3f(1F, 1F, 1F); + + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + } + + /** + * Draws burning progress, similar to vanilla furnace + * + * @param gui GuiBase GUI to draw on + * @param progress int Current progress + * @param maxProgress int Maximum progress + * @param x int Top left corner where to place burn bar + * @param y int Top left corner where to place burn bar + * @param mouseX int Mouse cursor position to check for tooltip + * @param mouseY int Mouse cursor position to check for tooltip + * @param layer Layer Layer to draw on + */ + public void drawBurnBar(MatrixStack matrixStack, GuiBase gui, int progress, int maxProgress, int x, int y, int mouseX, int mouseY, GuiBase.Layer layer) { + if (gui.hideGuiElements()) return; + if (layer == GuiBase.Layer.BACKGROUND) { + x += gui.getGuiLeft(); + y += gui.getGuiTop(); + } + gui.getMinecraft().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 150, 64, 13, 13); + int j = 13 - (int) ((double) progress / (double) maxProgress * 13); + if (j > 0) { + gui.drawTexture(matrixStack, x, y + j, 150, 51 + j, 13, 13 - j); + + } + if (gui.isPointInRect(x, y, 12, 12, mouseX, mouseY)) { + int percentage = percentage(maxProgress, progress); + List list = new ArrayList<>(); + list.add(StringUtils.getPercentageText(percentage)); + if (layer == GuiBase.Layer.FOREGROUND) { + mouseX -= gui.getGuiLeft(); + mouseY -= gui.getGuiTop(); + } + gui.renderTooltip(matrixStack, list, mouseX, mouseY); + RenderSystem.disableLighting(); + RenderSystem.color4f(1, 1, 1, 1); + } + } + + /** + * Draws bar containing output slots + * + * @param gui GuiBase GUI to draw on + * @param x int Top left corner where to place slots bar + * @param y int Top left corner where to place slots bar + * @param count int Number of output slots + */ + public void drawOutputSlotBar(MatrixStack matrixStack, GuiBase gui, int x, int y, int count) { + MinecraftClient.getInstance().getTextureManager().bindTexture(resourceLocation); + gui.drawTexture(matrixStack, x, y, 150, 122, 3, 26); + x += 3; + for (int i = 1; i <= count; i++) { + gui.drawTexture(matrixStack, x, y, 150 + 3, 122, 20, 26); + x += 20; + } + gui.drawTexture(matrixStack, x, y, 150 + 23, 122, 3, 26); + } + + protected int percentage(int MaxValue, int CurrentValue) { + if (CurrentValue == 0) { + return 0; + } + return (int) ((CurrentValue * 100.0f) / MaxValue); + } + + public enum ProgressDirection { + RIGHT(58, 150, 74, 150, 16, 10), + LEFT(74, 160, 58, 160, 16, 10), + DOWN(78, 170, 88, 170, 10, 16), + UP(58, 170, 68, 170, 10, 16); + public int x; + public int y; + public int xActive; + public int yActive; + public int width; + public int height; + + ProgressDirection(int x, int y, int xActive, int yActive, int width, int height) { + this.x = x; + this.y = y; + this.xActive = xActive; + this.yActive = yActive; + this.width = width; + this.height = height; + } + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/slots/BaseSlot.java b/RebornCore/src/main/java/reborncore/client/gui/slots/BaseSlot.java new file mode 100644 index 000000000..754b1aa6f --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/slots/BaseSlot.java @@ -0,0 +1,66 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.slots; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.Slot; +import reborncore.mixin.common.AccessorSlot; + +import java.util.function.Predicate; + +/** + * Created by modmuss50 on 11/04/2016. + */ +public class BaseSlot extends Slot { + + private Predicate filter = (stack) -> true; + + public BaseSlot(Inventory inventoryIn, int index, int xPosition, int yPosition) { + super(inventoryIn, index, xPosition, yPosition); + } + + public BaseSlot(Inventory inventoryIn, int index, int xPosition, int yPosition, Predicate filter) { + super(inventoryIn, index, xPosition, yPosition); + this.filter = filter; + } + + public boolean canWorldBlockRemove() { + return true; + } + + @Override + public boolean canInsert(ItemStack stack) { + return filter.test(stack); + } + + public boolean canWorldBlockInsert() { + return true; + } + + public int getSlotID() { + return ((AccessorSlot) this).getIndex(); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/slots/SlotCharge.java b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotCharge.java new file mode 100644 index 000000000..b2bcc24f5 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotCharge.java @@ -0,0 +1,48 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.slots; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import team.reborn.energy.Energy; + +/** + * Created by Rushmead + */ +public class SlotCharge extends BaseSlot { + public SlotCharge(Inventory inventoryIn, int index, int xPosition, int yPosition) { + super(inventoryIn, index, xPosition, yPosition); + } + + @Override + public boolean canInsert(ItemStack stack) { + return Energy.valid(stack); + } + + @Override + public boolean canWorldBlockRemove() { + return false; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFake.java b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFake.java new file mode 100644 index 000000000..5e72e922b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFake.java @@ -0,0 +1,68 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.slots; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; + +public class SlotFake extends BaseSlot { + + public boolean mCanInsertItem; + public boolean mCanStackItem; + public int mMaxStacksize = 127; + + public SlotFake(Inventory itemHandler, int par2, int par3, int par4, boolean aCanInsertItem, + boolean aCanStackItem, int aMaxStacksize) { + super(itemHandler, par2, par3, par4); + this.mCanInsertItem = aCanInsertItem; + this.mCanStackItem = aCanStackItem; + this.mMaxStacksize = aMaxStacksize; + } + + @Override + public boolean canInsert(ItemStack par1ItemStack) { + return this.mCanInsertItem; + } + + @Override + public int getMaxItemCount() { + return this.mMaxStacksize; + } + + @Override + public boolean hasStack() { + return false; + } + + @Override + public ItemStack takeStack(int par1) { + return !this.mCanStackItem ? ItemStack.EMPTY : super.takeStack(par1); + } + + @Override + public boolean canWorldBlockRemove() { + return false; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFilteredVoid.java b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFilteredVoid.java new file mode 100644 index 000000000..bd1a628fa --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFilteredVoid.java @@ -0,0 +1,63 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.slots; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; + +import java.util.ArrayList; +import java.util.List; + +public class SlotFilteredVoid extends BaseSlot { + + private final List filter = new ArrayList(); + + public SlotFilteredVoid(Inventory itemHandler, int id, int x, int y) { + super(itemHandler, id, x, y); + } + + public SlotFilteredVoid(Inventory itemHandler, int id, int x, int y, ItemStack[] filterList) { + super(itemHandler, id, x, y); + for (ItemStack itemStack : filterList) { + this.filter.add(itemStack); + } + } + + @Override + public boolean canInsert(ItemStack stack) { + for (ItemStack itemStack : filter) { + if (itemStack.getItem().equals(stack.getItem())) { + return false; + } + } + + return super.canInsert(stack); + } + + @Override + public void setStack(ItemStack arg0) { + + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFluid.java b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFluid.java new file mode 100644 index 000000000..4fd9ff374 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotFluid.java @@ -0,0 +1,42 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.slots; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import reborncore.common.fluid.FluidUtil; + +public class SlotFluid extends BaseSlot { + public SlotFluid(Inventory p_i1824_1_, int p_i1824_2_, int p_i1824_3_, int p_i1824_4_) { + super(p_i1824_1_, p_i1824_2_, p_i1824_3_, p_i1824_4_); + } + + @Override + public boolean canInsert(ItemStack stack) { + + return FluidUtil.getFluidHandler(stack) != null; + + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/slots/SlotInput.java b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotInput.java new file mode 100644 index 000000000..bb813d9c5 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotInput.java @@ -0,0 +1,50 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.slots; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; + +public class SlotInput extends BaseSlot { + + public SlotInput(Inventory itemHandler, int par2, int par3, int par4) { + super(itemHandler, par2, par3, par4); + } + + @Override + public boolean canInsert(ItemStack par1ItemStack) { + return true; + } + + @Override + public int getMaxItemCount() { + return 64; + } + + @Override + public boolean canWorldBlockRemove() { + return false; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/gui/slots/SlotOutput.java b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotOutput.java new file mode 100644 index 000000000..3dfd4d263 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/gui/slots/SlotOutput.java @@ -0,0 +1,55 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.gui.slots; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; + +public class SlotOutput extends BaseSlot { + + public SlotOutput(Inventory itemHandler, int par2, int par3, int par4) { + super(itemHandler, par2, par3, par4); + } + + @Override + public boolean canInsert(ItemStack par1ItemStack) { + return false; + } + + @Override + public int getMaxItemCount() { + return 64; + } + + @Override + public boolean canWorldBlockRemove() { + return true; + } + + @Override + public boolean canWorldBlockInsert() { + return false; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/multiblock/MultiblockComponent.java b/RebornCore/src/main/java/reborncore/client/multiblock/MultiblockComponent.java new file mode 100644 index 000000000..1ceed613f --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/multiblock/MultiblockComponent.java @@ -0,0 +1,65 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +/** + * This class was created by . It's distributed as + * part of the Botania Mod. Get the Source Code in github: + * https://github.com/Vazkii/Botania + *

+ * Botania is Open Source and distributed under the + * Botania License: http://botaniamod.net/license.php + */ + +package reborncore.client.multiblock; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.math.BlockPos; + +public class MultiblockComponent { + + public BlockPos relPos; + public final BlockState state; + + public MultiblockComponent(BlockPos relPos, BlockState state) { + this.relPos = relPos; + this.state = state; + } + + public BlockPos getRelativePosition() { + return relPos; + } + + public Block getBlock() { + return state.getBlock(); + } + + public BlockState getState() { + return state; + } + + public MultiblockComponent copy() { + return new MultiblockComponent(relPos, state); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/multiblock/MultiblockRenderer.java b/RebornCore/src/main/java/reborncore/client/multiblock/MultiblockRenderer.java new file mode 100644 index 000000000..0f990d813 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/multiblock/MultiblockRenderer.java @@ -0,0 +1,46 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.multiblock; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.block.entity.BlockEntityRenderDispatcher; +import net.minecraft.client.render.block.entity.BlockEntityRenderer; +import net.minecraft.client.util.math.MatrixStack; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.blockentity.MultiblockWriter; + +public class MultiblockRenderer extends BlockEntityRenderer { + + public MultiblockRenderer(BlockEntityRenderDispatcher blockEntityRenderDispatcher) { + super(blockEntityRenderDispatcher); + } + + @Override + public void render(T blockEntity, float partialTicks, MatrixStack matrixStack, VertexConsumerProvider vertexConsumerProvider, int light, int overlay) { + if (blockEntity.renderMultiblock) { + blockEntity.writeMultiblock(new MultiblockWriter.HologramRenderer(blockEntity.getWorld(), matrixStack, vertexConsumerProvider, 0.4F).rotate(blockEntity.getFacing().getOpposite())); + } + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/BuiltScreenHandlerProvider.java b/RebornCore/src/main/java/reborncore/client/screen/BuiltScreenHandlerProvider.java new file mode 100644 index 000000000..bf9aa98aa --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/BuiltScreenHandlerProvider.java @@ -0,0 +1,32 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen; + +import net.minecraft.entity.player.PlayerEntity; +import reborncore.client.screen.builder.BuiltScreenHandler; + +public interface BuiltScreenHandlerProvider { + BuiltScreenHandler createScreenHandler(int syncID, PlayerEntity player); +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/BlockEntityScreenHandlerBuilder.java b/RebornCore/src/main/java/reborncore/client/screen/builder/BlockEntityScreenHandlerBuilder.java new file mode 100644 index 000000000..3979ce88b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/BlockEntityScreenHandlerBuilder.java @@ -0,0 +1,206 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import net.minecraft.block.entity.AbstractFurnaceBlockEntity; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import org.apache.commons.lang3.Range; +import org.apache.commons.lang3.tuple.Pair; +import reborncore.RebornCore; +import reborncore.api.blockentity.IUpgrade; +import reborncore.api.blockentity.IUpgradeable; +import reborncore.api.recipe.IRecipeCrafterProvider; +import reborncore.client.gui.slots.BaseSlot; +import reborncore.client.gui.slots.SlotFake; +import reborncore.client.gui.slots.SlotOutput; +import reborncore.client.screen.builder.slot.FilteredSlot; +import reborncore.client.screen.builder.slot.UpgradeSlot; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.fluid.container.ItemFluidInfo; +import reborncore.common.powerSystem.PowerAcceptorBlockEntity; +import team.reborn.energy.Energy; + +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public class BlockEntityScreenHandlerBuilder { + + private final Inventory inventory; + private final BlockEntity blockEntity; + private final ScreenHandlerBuilder parent; + private final int rangeStart; + + BlockEntityScreenHandlerBuilder(final ScreenHandlerBuilder parent, final BlockEntity blockEntity) { + if (blockEntity instanceof Inventory) { + this.inventory = (Inventory) blockEntity; + } else { + throw new RuntimeException(blockEntity.getClass().getName() + " is not an inventory"); + } + this.blockEntity = blockEntity; + this.parent = parent; + this.rangeStart = parent.slots.size(); + if (inventory instanceof IUpgradeable) { + upgradeSlots((IUpgradeable) inventory); + } + if (blockEntity instanceof MachineBaseBlockEntity) { + sync(((MachineBaseBlockEntity) blockEntity).getRedstoneConfiguration()); + } + } + + public BlockEntityScreenHandlerBuilder slot(final int index, final int x, final int y) { + this.parent.slots.add(new BaseSlot(this.inventory, index, x, y)); + return this; + } + + public BlockEntityScreenHandlerBuilder slot(final int index, final int x, final int y, Predicate filter) { + this.parent.slots.add(new BaseSlot(this.inventory, index, x, y, filter)); + return this; + } + + public BlockEntityScreenHandlerBuilder outputSlot(final int index, final int x, final int y) { + this.parent.slots.add(new SlotOutput(this.inventory, index, x, y)); + return this; + } + + public BlockEntityScreenHandlerBuilder fakeSlot(final int index, final int x, final int y) { + this.parent.slots.add(new SlotFake(this.inventory, index, x, y, false, false, Integer.MAX_VALUE)); + return this; + } + + public BlockEntityScreenHandlerBuilder filterSlot(final int index, final int x, final int y, + final Predicate filter) { + this.parent.slots.add(new FilteredSlot(this.inventory, index, x, y).setFilter(filter)); + return this; + } + + public BlockEntityScreenHandlerBuilder energySlot(final int index, final int x, final int y) { + this.parent.slots.add(new FilteredSlot(this.inventory, index, x, y) + .setFilter(Energy::valid)); + return this; + } + + public BlockEntityScreenHandlerBuilder fluidSlot(final int index, final int x, final int y) { + this.parent.slots.add(new FilteredSlot(this.inventory, index, x, y).setFilter( + stack -> stack.getItem() instanceof ItemFluidInfo)); + return this; + } + + public BlockEntityScreenHandlerBuilder fuelSlot(final int index, final int x, final int y) { + this.parent.slots.add(new FilteredSlot(this.inventory, index, x, y).setFilter(AbstractFurnaceBlockEntity::canUseAsFuel)); + return this; + } + + @Deprecated + public BlockEntityScreenHandlerBuilder upgradeSlot(final int index, final int x, final int y) { + this.parent.slots.add(new FilteredSlot(this.inventory, index, x, y) + .setFilter(stack -> stack.getItem() instanceof IUpgrade)); + return this; + } + + private BlockEntityScreenHandlerBuilder upgradeSlots(IUpgradeable upgradeable) { + if (upgradeable.canBeUpgraded()) { + for (int i = 0; i < upgradeable.getUpgradeSlotCount(); i++) { + this.parent.slots.add(new UpgradeSlot(upgradeable.getUpgradeInvetory(), i, -18, i * 18 + 12)); + } + } + return this; + } + + /** + * @param supplier The supplier it can supply a variable holding in an Object it + * will be synced with a custom packet + * @param setter The setter to call when the variable has been updated. + * @return ContainerTileInventoryBuilder Inventory which will do the sync + */ + public BlockEntityScreenHandlerBuilder sync(final Supplier supplier, final Consumer setter) { + this.parent.objectValues.add(Pair.of(supplier, setter)); + return this; + } + + public BlockEntityScreenHandlerBuilder sync(Syncable syncable) { + syncable.getSyncPair(this.parent.objectValues); + return this; + } + + public BlockEntityScreenHandlerBuilder sync(Codec codec) { + return sync(() -> { + DataResult dataResult = codec.encodeStart(NbtOps.INSTANCE, (T) blockEntity); + if (dataResult.error().isPresent()) { + throw new RuntimeException("Failed to encode: " + dataResult.error().get().message() + " " + blockEntity); + } else { + return (CompoundTag) dataResult.result().get(); + } + }, compoundTag -> { + DataResult dataResult = codec.parse(NbtOps.INSTANCE, compoundTag); + if (dataResult.error().isPresent()) { + throw new RuntimeException("Failed to encode: " + dataResult.error().get().message() + " " + blockEntity); + } + }); + } + + public BlockEntityScreenHandlerBuilder syncEnergyValue() { + if (this.blockEntity instanceof PowerAcceptorBlockEntity) { + PowerAcceptorBlockEntity powerAcceptor = ((PowerAcceptorBlockEntity) this.blockEntity); + + return this.sync(powerAcceptor::getEnergy, powerAcceptor::setEnergy) + .sync(powerAcceptor::getExtraPowerStorage, powerAcceptor::setExtraPowerStorage) + .sync(powerAcceptor::getPowerChange, powerAcceptor::setPowerChange); + } + + RebornCore.LOGGER.error(this.inventory + " is not an instance of TilePowerAcceptor! Energy cannot be synced."); + return this; + } + + public BlockEntityScreenHandlerBuilder syncCrafterValue() { + if (this.blockEntity instanceof IRecipeCrafterProvider) { + IRecipeCrafterProvider recipeCrafter = ((IRecipeCrafterProvider) this.blockEntity); + return this + .sync(() -> recipeCrafter.getRecipeCrafter().currentTickTime, (time) -> recipeCrafter.getRecipeCrafter().currentTickTime = time) + .sync(() -> recipeCrafter.getRecipeCrafter().currentNeededTicks, (ticks) -> recipeCrafter.getRecipeCrafter().currentNeededTicks = ticks); + } + + RebornCore.LOGGER.error(this.inventory + " is not an instance of IRecipeCrafterProvider! Craft progress cannot be synced."); + return this; + } + + public BlockEntityScreenHandlerBuilder onCraft(final Consumer onCraft) { + this.parent.craftEvents.add(onCraft); + return this; + } + + public ScreenHandlerBuilder addInventory() { + this.parent.blockEntityInventoryRanges.add(Range.between(this.rangeStart, this.parent.slots.size() - 1)); + return this.parent; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/BuiltScreenHandler.java b/RebornCore/src/main/java/reborncore/client/screen/builder/BuiltScreenHandler.java new file mode 100644 index 000000000..4c3654d98 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/BuiltScreenHandler.java @@ -0,0 +1,373 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerListener; +import net.minecraft.screen.ScreenHandlerType; +import net.minecraft.screen.slot.Slot; +import net.minecraft.util.math.BlockPos; +import org.apache.commons.lang3.Range; +import org.apache.commons.lang3.tuple.MutableTriple; +import org.apache.commons.lang3.tuple.Pair; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.util.ItemUtils; +import reborncore.mixin.common.AccessorScreenHandler; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.*; + +public class BuiltScreenHandler extends ScreenHandler implements ExtendedScreenHandlerListener { + + private final String name; + + private final Predicate canInteract; + private final List> playerSlotRanges; + private final List> blockEntitySlotRanges; + + private final ArrayList> shortValues; + private final ArrayList> integerValues; + private final ArrayList> objectValues; + private List> craftEvents; + private Integer[] integerParts; + + private final MachineBaseBlockEntity blockEntity; + + public BuiltScreenHandler(int syncID, final String name, final Predicate canInteract, + final List> playerSlotRange, + final List> blockEntitySlotRange, MachineBaseBlockEntity blockEntity) { + super(null, syncID); + this.name = name; + + this.canInteract = canInteract; + + this.playerSlotRanges = playerSlotRange; + this.blockEntitySlotRanges = blockEntitySlotRange; + + this.shortValues = new ArrayList<>(); + this.integerValues = new ArrayList<>(); + this.objectValues = new ArrayList<>(); + + this.blockEntity = blockEntity; + } + + public void addShortSync(final List> syncables) { + + for (final Pair syncable : syncables) { + this.shortValues.add(MutableTriple.of(syncable.getLeft(), syncable.getRight(), (short) 0)); + } + this.shortValues.trimToSize(); + } + + public void addIntegerSync(final List> syncables) { + + for (final Pair syncable : syncables) { + this.integerValues.add(MutableTriple.of(syncable.getLeft(), syncable.getRight(), 0)); + } + this.integerValues.trimToSize(); + this.integerParts = new Integer[this.integerValues.size()]; + } + + public void addObjectSync(final List> syncables) { + + for (final Pair syncable : syncables) { + this.objectValues.add(MutableTriple.of(syncable.getLeft(), syncable.getRight(), null)); + } + this.objectValues.trimToSize(); + } + + public void addCraftEvents(final List> craftEvents) { + this.craftEvents = craftEvents; + } + + @Override + public boolean canUse(final PlayerEntity playerIn) { + return this.canInteract.test(playerIn); + } + + @Override + public final void onContentChanged(final Inventory inv) { + if (!this.craftEvents.isEmpty()) { + this.craftEvents.forEach(consumer -> consumer.accept((CraftingInventory) inv)); + } + } + + @Override + public void sendContentUpdates() { + super.sendContentUpdates(); + + for (final ScreenHandlerListener listener : ((AccessorScreenHandler) (this)).getListeners()) { + + int i = 0; + if (!this.shortValues.isEmpty()) { + for (final MutableTriple value : this.shortValues) { + final short supplied = (short) value.getLeft().getAsInt(); + if (supplied != value.getRight()) { + + listener.onPropertyUpdate(this, i, supplied); + value.setRight(supplied); + } + i++; + } + } + + if (!this.integerValues.isEmpty()) { + for (final MutableTriple value : this.integerValues) { + final int supplied = value.getLeft().getAsInt(); + if (supplied != value.getRight()) { + + listener.onPropertyUpdate(this, i, supplied >> 16); + listener.onPropertyUpdate(this, i + 1, (short) (supplied & 0xFFFF)); + value.setRight(supplied); + } + i += 2; + } + } + + if (!this.objectValues.isEmpty()) { + int objects = 0; + for (final MutableTriple value : this.objectValues) { + final Object supplied = value.getLeft().get(); + if (supplied != value.getRight()) { + sendObject(listener, this, objects, supplied); + value.setRight(supplied); + } + objects++; + } + } + } + } + + @Override + public void addListener(final ScreenHandlerListener listener) { + super.addListener(listener); + + int i = 0; + if (!this.shortValues.isEmpty()) { + for (final MutableTriple value : this.shortValues) { + final short supplied = (short) value.getLeft().getAsInt(); + + listener.onPropertyUpdate(this, i, supplied); + value.setRight(supplied); + i++; + } + } + + if (!this.integerValues.isEmpty()) { + for (final MutableTriple value : this.integerValues) { + final int supplied = value.getLeft().getAsInt(); + + listener.onPropertyUpdate(this, i, supplied >> 16); + listener.onPropertyUpdate(this, i + 1, (short) (supplied & 0xFFFF)); + value.setRight(supplied); + i += 2; + } + } + + if (!this.objectValues.isEmpty()) { + int objects = 0; + for (final MutableTriple value : this.objectValues) { + final Object supplied = value.getLeft(); + sendObject(listener, this, objects, ((Supplier) supplied).get()); + value.setRight(supplied); + objects++; + } + } + } + + @Override + public void handleObject(int var, Object value) { + this.objectValues.get(var).getMiddle().accept(value); + } + + @Override + public void setProperty(int id, int value) { + if (id < this.shortValues.size()) { + this.shortValues.get(id).getMiddle().accept((short) value); + this.shortValues.get(id).setRight((short) value); + } else if (id - this.shortValues.size() < this.integerValues.size() * 2) { + + if ((id - this.shortValues.size()) % 2 == 0) { + this.integerParts[(id - this.shortValues.size()) / 2] = value; + } else { + this.integerValues.get((id - this.shortValues.size()) / 2).getMiddle().accept( + (this.integerParts[(id - this.shortValues.size()) / 2] & 0xFFFF) << 16 | value & 0xFFFF); + } + } + } + + @Override + public ItemStack transferSlot(final PlayerEntity player, final int index) { + + ItemStack originalStack = ItemStack.EMPTY; + + final Slot slot = this.slots.get(index); + + if (slot != null && slot.hasStack()) { + + final ItemStack stackInSlot = slot.getStack(); + originalStack = stackInSlot.copy(); + + boolean shifted = false; + + for (final Range range : this.playerSlotRanges) { + if (range.contains(index)) { + + if (this.shiftToBlockEntity(stackInSlot)) { + shifted = true; + } + break; + } + } + + if (!shifted) { + for (final Range range : this.blockEntitySlotRanges) { + if (range.contains(index)) { + if (this.shiftToPlayer(stackInSlot)) { + shifted = true; + } + break; + } + } + } + + slot.onStackChanged(stackInSlot, originalStack); + if (stackInSlot.getCount() <= 0) { + slot.setStack(ItemStack.EMPTY); + } else { + slot.markDirty(); + } + if (stackInSlot.getCount() == originalStack.getCount()) { + return ItemStack.EMPTY; + } + slot.onTakeItem(player, stackInSlot); + } + return originalStack; + + } + + protected boolean shiftItemStack(final ItemStack stackToShift, final int start, final int end) { + if (stackToShift.isEmpty()) { + return false; + } + int inCount = stackToShift.getCount(); + + // First lets see if we have the same item in a slot to merge with + for (int slotIndex = start; stackToShift.getCount() > 0 && slotIndex < end; slotIndex++) { + final Slot slot = this.slots.get(slotIndex); + final ItemStack stackInSlot = slot.getStack(); + int maxCount = Math.min(stackToShift.getMaxCount(), slot.getMaxItemCount()); + + if (!stackToShift.isEmpty() && slot.canInsert(stackToShift)) { + if (ItemUtils.isItemEqual(stackInSlot, stackToShift, true, false)) { + // Got 2 stacks that need merging + int freeStackSpace = maxCount - stackInSlot.getCount(); + if (freeStackSpace > 0) { + int transferAmount = Math.min(freeStackSpace, stackToShift.getCount()); + stackInSlot.increment(transferAmount); + stackToShift.decrement(transferAmount); + } + } + } + } + + // If not lets go find the next free slot to insert our remaining stack + for (int slotIndex = start; stackToShift.getCount() > 0 && slotIndex < end; slotIndex++) { + final Slot slot = this.slots.get(slotIndex); + final ItemStack stackInSlot = slot.getStack(); + + if (stackInSlot.isEmpty() && slot.canInsert(stackToShift)) { + int maxCount = Math.min(stackToShift.getMaxCount(), slot.getMaxItemCount()); + + int moveCount = Math.min(maxCount, stackToShift.getCount()); + ItemStack moveStack = stackToShift.copy(); + moveStack.setCount(moveCount); + slot.setStack(moveStack); + stackToShift.decrement(moveCount); + } + } + + //If we moved some, but still have more left over lets try again + if (!stackToShift.isEmpty() && stackToShift.getCount() != inCount) { + shiftItemStack(stackToShift, start, end); + } + + return stackToShift.getCount() != inCount; + } + + private boolean shiftToBlockEntity(final ItemStack stackToShift) { + if (!blockEntity.getOptionalInventory().isPresent()) { + return false; + } + for (final Range range : this.blockEntitySlotRanges) { + if (this.shiftItemStack(stackToShift, range.getMinimum(), range.getMaximum() + 1)) { + return true; + } + } + return false; + } + + private boolean shiftToPlayer(final ItemStack stackToShift) { + for (final Range range : this.playerSlotRanges) { + if (this.shiftItemStack(stackToShift, range.getMinimum(), range.getMaximum() + 1)) { + return true; + } + } + return false; + } + + public String getName() { + return this.name; + } + + @Override + public Slot addSlot(Slot slotIn) { + return super.addSlot(slotIn); + } + + public MachineBaseBlockEntity getBlockEntity() { + return blockEntity; + } + + public BlockPos getPos() { + return getBlockEntity().getPos(); + } + + ScreenHandlerType type = null; + + public void setType(ScreenHandlerType type) { + this.type = type; + } + + @Override + public ScreenHandlerType getType() { + return type; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/ExtendedScreenHandlerListener.java b/RebornCore/src/main/java/reborncore/client/screen/builder/ExtendedScreenHandlerListener.java new file mode 100644 index 000000000..8584bca52 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/ExtendedScreenHandlerListener.java @@ -0,0 +1,44 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder; + +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerListener; +import net.minecraft.server.network.ServerPlayerEntity; +import reborncore.common.network.ClientBoundPackets; +import reborncore.common.network.NetworkManager; + +public interface ExtendedScreenHandlerListener { + + default void sendObject(ScreenHandlerListener screenHandlerListener, ScreenHandler screenHandler, int var, Object value) { + if (screenHandlerListener instanceof ServerPlayerEntity) { + NetworkManager.sendToPlayer(ClientBoundPackets.createPacketSendObject(var, value, screenHandler), (ServerPlayerEntity) screenHandlerListener); + } + } + + default void handleObject(int var, Object value) { + + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/PlayerScreenHandlerBuilder.java b/RebornCore/src/main/java/reborncore/client/screen/builder/PlayerScreenHandlerBuilder.java new file mode 100644 index 000000000..0147309cd --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/PlayerScreenHandlerBuilder.java @@ -0,0 +1,142 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder; + +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.item.ArmorItem; +import net.minecraft.util.Identifier; +import org.apache.commons.lang3.Range; +import reborncore.client.IconSupplier; +import reborncore.client.screen.builder.slot.PlayerInventorySlot; +import reborncore.client.screen.builder.slot.SpriteSlot; + +public final class PlayerScreenHandlerBuilder { + + private final PlayerInventory player; + private final ScreenHandlerBuilder parent; + private Range main; + private Range hotbar; + private Range armor; + + PlayerScreenHandlerBuilder(final ScreenHandlerBuilder parent, final PlayerInventory player) { + this.player = player; + this.parent = parent; + } + + public PlayerScreenHandlerBuilder inventory(final int xStart, final int yStart) { + final int startIndex = this.parent.slots.size(); + for (int i = 0; i < 3; ++i) { + for (int j = 0; j < 9; ++j) { + this.parent.slots.add(new PlayerInventorySlot(this.player, j + i * 9 + 9, xStart + j * 18, yStart + i * 18)); + } + } + this.main = Range.between(startIndex, this.parent.slots.size() - 1); + return this; + } + + public PlayerScreenHandlerBuilder hotbar(final int xStart, final int yStart) { + final int startIndex = this.parent.slots.size(); + for (int i = 0; i < 9; ++i) { + this.parent.slots.add(new PlayerInventorySlot(this.player, i, xStart + i * 18, yStart)); + } + this.hotbar = Range.between(startIndex, this.parent.slots.size() - 1); + return this; + } + + public PlayerScreenHandlerBuilder inventory() { + return this.inventory(8, 94); + } + + public PlayerScreenHandlerBuilder hotbar() { + return this.hotbar(8, 152); + } + + public PlayerArmorScreenHandlerBuilder armor() { + return new PlayerArmorScreenHandlerBuilder(this); + } + + public ScreenHandlerBuilder addInventory() { + if (this.hotbar != null) { + this.parent.addPlayerInventoryRange(this.hotbar); + } + if (this.main != null) { + this.parent.addPlayerInventoryRange(this.main); + } + if (this.armor != null) { + this.parent.addBlockEnityInventoryRange(this.armor); + } + + return this.parent; + } + + public static final class PlayerArmorScreenHandlerBuilder { + private final PlayerScreenHandlerBuilder parent; + private final int startIndex; + + public PlayerArmorScreenHandlerBuilder(final PlayerScreenHandlerBuilder parent) { + this.parent = parent; + this.startIndex = parent.parent.slots.size(); + } + + private PlayerArmorScreenHandlerBuilder armor(final int index, final int xStart, final int yStart, + final EquipmentSlot slotType, final Identifier sprite) { + this.parent.parent.slots.add(new SpriteSlot(this.parent.player, index, xStart, yStart, sprite, 1) + .setFilter(stack -> { + if (stack.getItem() instanceof ArmorItem) { + return ((ArmorItem) stack.getItem()).getSlotType() == slotType; + } + return false; + })); + return this; + } + + public PlayerArmorScreenHandlerBuilder helmet(final int xStart, final int yStart) { + return this.armor(this.parent.player.size() - 2, xStart, yStart, EquipmentSlot.HEAD, IconSupplier.armour_head_id); + } + + public PlayerArmorScreenHandlerBuilder chestplate(final int xStart, final int yStart) { + return this.armor(this.parent.player.size() - 3, xStart, yStart, EquipmentSlot.CHEST, IconSupplier.armour_chest_id); + } + + public PlayerArmorScreenHandlerBuilder leggings(final int xStart, final int yStart) { + return this.armor(this.parent.player.size() - 4, xStart, yStart, EquipmentSlot.LEGS, IconSupplier.armour_legs_id); + } + + public PlayerArmorScreenHandlerBuilder boots(final int xStart, final int yStart) { + return this.armor(this.parent.player.size() - 5, xStart, yStart, EquipmentSlot.FEET, IconSupplier.armour_feet_id); + } + + public PlayerArmorScreenHandlerBuilder complete(final int xStart, final int yStart) { + return this.helmet(xStart, yStart).chestplate(xStart, yStart + 18).leggings(xStart, yStart + 18 + 18) + .boots(xStart, yStart + 18 + 18 + 18); + } + + public PlayerScreenHandlerBuilder addArmor() { + this.parent.armor = Range.between(this.startIndex - 1, this.parent.parent.slots.size() - 2); + return this.parent; + } + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/ScreenHandlerBuilder.java b/RebornCore/src/main/java/reborncore/client/screen/builder/ScreenHandlerBuilder.java new file mode 100644 index 000000000..a41928df2 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/ScreenHandlerBuilder.java @@ -0,0 +1,103 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.entity.player.PlayerInventory; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.screen.slot.Slot; +import net.minecraft.util.math.Vec3d; +import org.apache.commons.lang3.Range; +import org.apache.commons.lang3.tuple.Pair; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +import java.util.ArrayList; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; +import java.util.function.Supplier; + +public class ScreenHandlerBuilder { + + private final String name; + + final List slots; + final List> playerInventoryRanges, blockEntityInventoryRanges; + + final List> objectValues; + + final List> craftEvents; + + public ScreenHandlerBuilder(final String name) { + + this.name = name; + + this.slots = new ArrayList<>(); + this.playerInventoryRanges = new ArrayList<>(); + this.blockEntityInventoryRanges = new ArrayList<>(); + + this.objectValues = new ArrayList<>(); + + this.craftEvents = new ArrayList<>(); + } + + public PlayerScreenHandlerBuilder player(final PlayerInventory player) { + return new PlayerScreenHandlerBuilder(this, player); + } + + public BlockEntityScreenHandlerBuilder blockEntity(final BlockEntity blockEntity) { + return new BlockEntityScreenHandlerBuilder(this, blockEntity); + } + + void addPlayerInventoryRange(final Range range) { + this.playerInventoryRanges.add(range); + } + + void addBlockEnityInventoryRange(final Range range) { + this.blockEntityInventoryRanges.add(range); + } + + private Predicate isUsable(MachineBaseBlockEntity blockEntity) { + return playerEntity -> blockEntity.getWorld().getBlockEntity(blockEntity.getPos()) == blockEntity + && playerEntity.getPos().distanceTo(Vec3d.of(blockEntity.getPos())) < 16; + } + + public BuiltScreenHandler create(final MachineBaseBlockEntity blockEntity, int syncID) { + final BuiltScreenHandler built = new BuiltScreenHandler(syncID, this.name, isUsable(blockEntity), + this.playerInventoryRanges, + this.blockEntityInventoryRanges, blockEntity); + if (!this.objectValues.isEmpty()) + built.addObjectSync(objectValues); + if (!this.craftEvents.isEmpty()) { + built.addCraftEvents(this.craftEvents); + } + + this.slots.forEach(built::addSlot); + + this.slots.clear(); + return built; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/Syncable.java b/RebornCore/src/main/java/reborncore/client/screen/builder/Syncable.java new file mode 100644 index 000000000..62e700627 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/Syncable.java @@ -0,0 +1,37 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder; + +import org.apache.commons.lang3.tuple.Pair; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public interface Syncable { + + void getSyncPair(List> pairList); + +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/slot/FilteredSlot.java b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/FilteredSlot.java new file mode 100644 index 000000000..4ed15d5e4 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/FilteredSlot.java @@ -0,0 +1,65 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder.slot; + +import net.minecraft.inventory.Inventory; +import net.minecraft.item.ItemStack; +import reborncore.client.gui.slots.BaseSlot; + +import java.util.function.Predicate; + +public class FilteredSlot extends BaseSlot { + + private Predicate filter; + private int stackLimit = 64; + + public FilteredSlot(final Inventory inventory, final int index, final int xPosition, final int yPosition) { + super(inventory, index, xPosition, yPosition); + } + + public FilteredSlot(final Inventory inventory, final int index, final int xPosition, final int yPosition, int stackLimit) { + super(inventory, index, xPosition, yPosition); + this.stackLimit = stackLimit; + } + + public FilteredSlot setFilter(final Predicate filter) { + this.filter = filter; + return this; + } + + @Override + public boolean canInsert(final ItemStack stack) { + try { + return this.filter.test(stack); + } catch (NullPointerException e) { + return true; + } + } + + @Override + public int getMaxItemCount() { + return stackLimit; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/slot/PlayerInventorySlot.java b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/PlayerInventorySlot.java new file mode 100644 index 000000000..a32e962fe --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/PlayerInventorySlot.java @@ -0,0 +1,46 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder.slot; + +import net.minecraft.inventory.Inventory; +import net.minecraft.screen.slot.Slot; + +/** + * Created by drcrazy on 31-Dec-19 for TechReborn-1.15. + */ +public class PlayerInventorySlot extends Slot { + + public boolean doDraw; + + public PlayerInventorySlot(Inventory inventory, int index, int xPosition, int yPosition) { + super(inventory, index, xPosition, yPosition); + this.doDraw = true; + } + + @Override + public boolean doDrawHoveringEffect() { + return doDraw; + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/slot/SpriteSlot.java b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/SpriteSlot.java new file mode 100644 index 000000000..611db285b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/SpriteSlot.java @@ -0,0 +1,62 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder.slot; + +import com.mojang.datafixers.util.Pair; +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.inventory.Inventory; +import net.minecraft.util.Identifier; + +import org.jetbrains.annotations.Nullable; + +public class SpriteSlot extends FilteredSlot { + + private final Identifier spriteName; + int stacksize; + + public SpriteSlot(final Inventory inventory, final int index, final int xPosition, final int yPosition, final Identifier sprite, final int stacksize) { + super(inventory, index, xPosition, yPosition); + this.spriteName = sprite; + this.stacksize = stacksize; + } + + public SpriteSlot(final Inventory inventory, final int index, final int xPosition, final int yPosition, final Identifier sprite) { + this(inventory, index, xPosition, yPosition, sprite, 64); + } + + @Override + public int getMaxItemCount() { + return this.stacksize; + } + + @Override + @Nullable + @Environment(EnvType.CLIENT) + public Pair getBackgroundSprite() { + return Pair.of(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE, spriteName); + } +} diff --git a/RebornCore/src/main/java/reborncore/client/screen/builder/slot/UpgradeSlot.java b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/UpgradeSlot.java new file mode 100644 index 000000000..1ad9e6575 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/screen/builder/slot/UpgradeSlot.java @@ -0,0 +1,60 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.screen.builder.slot; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.item.ItemStack; +import reborncore.api.blockentity.IUpgrade; +import reborncore.api.blockentity.IUpgradeable; +import reborncore.client.gui.slots.BaseSlot; +import reborncore.common.util.RebornInventory; + +public class UpgradeSlot extends BaseSlot { + + public UpgradeSlot(final net.minecraft.inventory.Inventory inventory, final int index, final int xPosition, final int yPosition) { + super(inventory, index, xPosition, yPosition); + } + + @Override + public boolean canInsert(final ItemStack stack) { + if (!(stack.getItem() instanceof IUpgrade)) { + return false; + } + IUpgrade upgrade = (IUpgrade) stack.getItem(); + IUpgradeable upgradeable = null; + RebornInventory inv = (RebornInventory) inventory; + BlockEntity blockEntity = inv.getBlockEntity(); + if (blockEntity instanceof IUpgradeable) { + upgradeable = (IUpgradeable) blockEntity; + } + return upgrade.isValidForInventory(upgradeable, stack) && (upgradeable == null || upgradeable.isUpgradeValid(upgrade, stack)); + } + + @Override + public int getMaxItemCount() { + return 1; + } + +} diff --git a/RebornCore/src/main/java/reborncore/client/texture/InputStreamTexture.java b/RebornCore/src/main/java/reborncore/client/texture/InputStreamTexture.java new file mode 100644 index 000000000..36652edb6 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/client/texture/InputStreamTexture.java @@ -0,0 +1,96 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.client.texture; + +import net.minecraft.client.texture.AbstractTexture; +import net.minecraft.client.texture.NativeImage; +import net.minecraft.client.texture.TextureUtil; +import net.minecraft.resource.Resource; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.metadata.ResourceMetadataReader; +import net.minecraft.util.Identifier; +import org.apache.commons.io.IOUtils; + +import org.jetbrains.annotations.Nullable; +import java.io.IOException; +import java.io.InputStream; + +/** + * Created by modmuss50 on 23/05/2016. + */ +public class InputStreamTexture extends AbstractTexture { + protected final InputStream textureLocation; + NativeImage image; + String name; + + public InputStreamTexture(InputStream textureResourceLocation, String name) { + this.textureLocation = textureResourceLocation; + this.name = name; + } + + @Override + public void load(ResourceManager resourceManager) throws IOException { + this.clearGlId(); + if (image == null) { + Resource iresource = null; + try { + iresource = new Resource() { + + @Override + public Identifier getId() { + return new Identifier("reborncore:loaded/" + name); + } + + @Override + public InputStream getInputStream() { + return textureLocation; + } + + @Nullable + @Override + public T getMetadata(ResourceMetadataReader iMetadataSectionSerializer) { + return null; + } + + @Override + public String getResourcePackName() { + return "reborncore"; + } + + @Override + public void close() { + + } + }; + image = NativeImage.read(iresource.getInputStream()); + } finally { + IOUtils.closeQuietly(iresource); + } + } + this.bindTexture(); + TextureUtil.allocate(this.getGlId(), 0, image.getWidth(), image.getHeight()); + image.upload(0, 0, 0, true); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/BaseBlock.java b/RebornCore/src/main/java/reborncore/common/BaseBlock.java new file mode 100644 index 000000000..cf0547035 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/BaseBlock.java @@ -0,0 +1,38 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common; + +import net.minecraft.block.Block; + +public abstract class BaseBlock extends Block { + + public BaseBlock(Settings builder) { + super(builder); + } + + public int getRenderType() { + return 3; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/BaseBlockEntityProvider.java b/RebornCore/src/main/java/reborncore/common/BaseBlockEntityProvider.java new file mode 100644 index 000000000..9b436a804 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/BaseBlockEntityProvider.java @@ -0,0 +1,86 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockEntityProvider; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import java.util.Optional; + +public abstract class BaseBlockEntityProvider extends Block implements BlockEntityProvider { + protected BaseBlockEntityProvider(Settings builder) { + super(builder); + } + + public Optional getDropWithContents(World world, BlockPos pos, ItemStack stack) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity == null) { + return Optional.empty(); + } + ItemStack newStack = stack.copy(); + CompoundTag blockEntityData = blockEntity.toTag(new CompoundTag()); + stripLocationData(blockEntityData); + if (!newStack.hasTag()) { + newStack.setTag(new CompoundTag()); + } + newStack.getTag().put("blockEntity_data", blockEntityData); + return Optional.of(newStack); + } + + @Override + public void onPlaced(World worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + if (stack.hasTag() && stack.getTag().contains("blockEntity_data")) { + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + CompoundTag nbt = stack.getTag().getCompound("blockEntity_data"); + injectLocationData(nbt, pos); + blockEntity.fromTag(state, nbt); + blockEntity.markDirty(); + } + } + + private void stripLocationData(CompoundTag compound) { + compound.remove("x"); + compound.remove("y"); + compound.remove("z"); + } + + private void injectLocationData(CompoundTag compound, BlockPos pos) { + compound.putInt("x", pos.getX()); + compound.putInt("y", pos.getY()); + compound.putInt("z", pos.getZ()); + } + + public void getDrops(BlockState state, DefaultedList drops, World world, BlockPos pos, int fortune){ + + } +} diff --git a/RebornCore/src/main/java/reborncore/common/RebornCoreCommands.java b/RebornCore/src/main/java/reborncore/common/RebornCoreCommands.java new file mode 100644 index 000000000..786518129 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/RebornCoreCommands.java @@ -0,0 +1,206 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common; + +import com.google.common.collect.ImmutableList; +import com.mojang.brigadier.Command; +import com.mojang.brigadier.CommandDispatcher; +import com.mojang.brigadier.arguments.StringArgumentType; +import com.mojang.brigadier.context.CommandContext; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import com.mojang.brigadier.suggestion.SuggestionProvider; +import net.fabricmc.api.EnvType; +import net.fabricmc.fabric.api.command.v1.CommandRegistrationCallback; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.command.argument.EntityArgumentType; +import net.minecraft.command.argument.ItemStackArgumentType; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.server.command.CommandManager; +import net.minecraft.command.CommandSource; +import net.minecraft.server.command.ServerCommandSource; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerChunkManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.text.LiteralText; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.chunk.ChunkStatus; +import reborncore.client.ItemStackRenderManager; +import reborncore.common.crafting.RecipeManager; + +import java.util.Collection; +import java.util.Collections; +import java.util.List; +import java.util.concurrent.CompletableFuture; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.atomic.AtomicInteger; +import java.util.stream.Collectors; + +import static com.mojang.brigadier.arguments.IntegerArgumentType.getInteger; +import static com.mojang.brigadier.arguments.IntegerArgumentType.integer; +import static com.mojang.brigadier.arguments.StringArgumentType.word; +import static net.minecraft.server.command.CommandManager.argument; +import static net.minecraft.server.command.CommandManager.literal; + +public class RebornCoreCommands { + + private final static ExecutorService EXECUTOR_SERVICE = Executors.newSingleThreadExecutor(); + private final static SuggestionProvider MOD_SUGGESTIONS = (context, builder) -> + CommandSource.suggestMatching(FabricLoader.getInstance().getAllMods().stream().map(modContainer -> modContainer.getMetadata().getId()), builder); + + public static void setup() { + CommandRegistrationCallback.EVENT.register(((dispatcher, isDedicated) -> RebornCoreCommands.addCommands(dispatcher))); + } + + private static void addCommands(CommandDispatcher dispatcher) { + dispatcher.register( + literal("reborncore") + + .then( + literal("recipes") + .then(literal("validate") + .requires(source -> source.hasPermissionLevel(3)) + .executes(ctx -> { + RecipeManager.validateRecipes(ctx.getSource().getWorld()); + return Command.SINGLE_SUCCESS; + }) + ) + ) + + .then( + literal("generate") + .requires(source -> source.hasPermissionLevel(3)) + .then(argument("size", integer()) + .executes(RebornCoreCommands::generate) + ) + ) + + .then( + literal("flyspeed") + .requires(source -> source.hasPermissionLevel(3)) + .then(argument("speed", integer(1, 10)) + .executes(ctx -> flySpeed(ctx, ImmutableList.of(ctx.getSource().getPlayer()))) + .then(CommandManager.argument("players", EntityArgumentType.players()) + .executes(ctx -> flySpeed(ctx, EntityArgumentType.getPlayers(ctx, "players"))) + ) + ) + ) + + .then( + literal("render") + .then( + literal("mod") + .then( + argument("modid", word()) + .suggests(MOD_SUGGESTIONS) + .executes(RebornCoreCommands::renderMod) + ) + ) + .then( + literal("item") + .then( + argument("item", ItemStackArgumentType.itemStack()) + .executes(RebornCoreCommands::itemRenderer) + ) + ) + .then( + literal("hand") + .executes(RebornCoreCommands::handRenderer) + ) + ) + ); + } + + private static int generate(CommandContext ctx) { + final int size = getInteger(ctx, "size"); + + final ServerWorld world = ctx.getSource().getWorld(); + final ServerChunkManager serverChunkManager = world.getChunkManager(); + final AtomicInteger completed = new AtomicInteger(0); + + for (int x = -(size / 2); x < size / 2; x++) { + for (int z = -(size / 2); z < size / 2; z++) { + final int chunkPosX = x; + final int chunkPosZ = z; + CompletableFuture.supplyAsync(() -> serverChunkManager.getChunk(chunkPosX, chunkPosZ, ChunkStatus.FULL, true), EXECUTOR_SERVICE) + .whenComplete((chunk, throwable) -> { + int max = (int) Math.pow(size, 2); + ctx.getSource().sendFeedback(new LiteralText(String.format("Finished generating %d:%d (%d/%d %d%%)", chunk.getPos().x, chunk.getPos().z, completed.getAndIncrement(), max, completed.get() == 0 ? 0 : (int) ((completed.get() * 100.0f) / max))), true); + } + ); + } + } + return Command.SINGLE_SUCCESS; + } + + private static int flySpeed(CommandContext ctx, Collection players) { + final int speed = getInteger(ctx, "speed"); + players.stream() + .peek(player -> player.abilities.setFlySpeed(speed / 20F)) + .forEach(ServerPlayerEntity::sendAbilitiesUpdate); + + return Command.SINGLE_SUCCESS; + } + + private static int renderMod(CommandContext ctx) { + String modid = StringArgumentType.getString(ctx, "modid"); + + List list = Registry.ITEM.getIds().stream() + .filter(identifier -> identifier.getNamespace().equals(modid)) + .map(Registry.ITEM::get) + .map(ItemStack::new) + .collect(Collectors.toList()); + + queueRender(list); + return Command.SINGLE_SUCCESS; + } + + private static int itemRenderer(CommandContext ctx) { + Item item = ItemStackArgumentType.getItemStackArgument(ctx, "item").getItem(); + queueRender(Collections.singletonList(new ItemStack(item))); + + return Command.SINGLE_SUCCESS; + } + + private static int handRenderer(CommandContext ctx) { + try { + queueRender(Collections.singletonList(ctx.getSource().getPlayer().inventory.getMainHandStack())); + } catch (CommandSyntaxException e) { + e.printStackTrace(); + return 0; + } + + return Command.SINGLE_SUCCESS; + } + + private static void queueRender(List stacks) { + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.SERVER) { + System.out.println("Render item only works on the client!"); + return; + } + ItemStackRenderManager.RENDER_QUEUE.addAll(stacks); + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/common/RebornCoreConfig.java b/RebornCore/src/main/java/reborncore/common/RebornCoreConfig.java new file mode 100644 index 000000000..5695bd542 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/RebornCoreConfig.java @@ -0,0 +1,35 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common; + +import reborncore.common.config.Config; + +public class RebornCoreConfig { + @Config(config = "misc", key = "Enable Seasonal Easter Eggs", comment = "Disable this is you don't want seasonal easter eggs") + public static boolean easterEggs = true; + + @Config(config = "misc", key = "Selected Energy system", comment = "Possible values are: E (was FE, EU)") + public static String selectedSystem = "E"; +} diff --git a/RebornCore/src/main/java/reborncore/common/blockentity/FluidConfiguration.java b/RebornCore/src/main/java/reborncore/common/blockentity/FluidConfiguration.java new file mode 100644 index 000000000..bf39f6a0e --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/blockentity/FluidConfiguration.java @@ -0,0 +1,218 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.blockentity; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import reborncore.common.fluid.FluidUtil; +import reborncore.common.util.NBTSerializable; +import reborncore.common.util.Tank; + +import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; + +public class FluidConfiguration implements NBTSerializable { + + HashMap sideMap; + boolean input, output; + + public FluidConfiguration() { + sideMap = new HashMap<>(); + Arrays.stream(Direction.values()).forEach(facing -> sideMap.put(facing, new FluidConfig(facing))); + } + + public FluidConfiguration(CompoundTag tagCompound) { + sideMap = new HashMap<>(); + read(tagCompound); + } + + public FluidConfig getSideDetail(Direction side) { + if (side == null) { + return sideMap.get(Direction.NORTH); + } + return sideMap.get(side); + } + + public List getAllSides() { + return new ArrayList<>(sideMap.values()); + } + + public void updateFluidConfig(FluidConfig config) { + FluidConfig toEdit = sideMap.get(config.side); + toEdit.ioConfig = config.ioConfig; + } + + public void update(MachineBaseBlockEntity machineBase) { + if (!input && !output) { + return; + } + if (machineBase.getTank() == null || machineBase.getWorld().getTime() % machineBase.slotTransferSpeed() != 0) { + return; + } + for (Direction facing : Direction.values()) { + FluidConfig fluidConfig = getSideDetail(facing); + if (fluidConfig == null || !fluidConfig.getIoConfig().isEnabled()) { + continue; + } + + Tank tank = getTank(machineBase, facing); + if (autoInput() && fluidConfig.getIoConfig().isInsert()) { + FluidUtil.transferFluid(tank, machineBase.getTank(), machineBase.fluidTransferAmount()); + } + if (autoOutput() && fluidConfig.getIoConfig().isExtact()) { + FluidUtil.transferFluid(machineBase.getTank(), tank, machineBase.fluidTransferAmount()); + } + } + } + + private Tank getTank(MachineBaseBlockEntity machine, Direction facing) { + BlockPos pos = machine.getPos().offset(facing); + BlockEntity blockEntity = machine.getWorld().getBlockEntity(pos); + if (blockEntity instanceof MachineBaseBlockEntity) { + return ((MachineBaseBlockEntity) blockEntity).getTank(); + } + return null; + } + + public boolean autoInput() { + return input; + } + + public boolean autoOutput() { + return output; + } + + public void setInput(boolean input) { + this.input = input; + } + + public void setOutput(boolean output) { + this.output = output; + } + + @NotNull + @Override + public CompoundTag write() { + CompoundTag compound = new CompoundTag(); + Arrays.stream(Direction.values()).forEach(facing -> compound.put("side_" + facing.ordinal(), sideMap.get(facing).write())); + compound.putBoolean("input", input); + compound.putBoolean("output", output); + return compound; + } + + @Override + public void read(@NotNull CompoundTag nbt) { + sideMap.clear(); + Arrays.stream(Direction.values()).forEach(facing -> { + CompoundTag compound = nbt.getCompound("side_" + facing.ordinal()); + FluidConfig config = new FluidConfig(compound); + sideMap.put(facing, config); + }); + input = nbt.getBoolean("input"); + output = nbt.getBoolean("output"); + } + + public static class FluidConfig implements NBTSerializable { + Direction side; + FluidConfiguration.ExtractConfig ioConfig; + + public FluidConfig(Direction side) { + this.side = side; + this.ioConfig = ExtractConfig.ALL; + } + + public FluidConfig(Direction side, FluidConfiguration.ExtractConfig ioConfig) { + this.side = side; + this.ioConfig = ioConfig; + } + + public FluidConfig(CompoundTag tagCompound) { + read(tagCompound); + } + + public Direction getSide() { + return side; + } + + public ExtractConfig getIoConfig() { + return ioConfig; + } + + @NotNull + @Override + public CompoundTag write() { + CompoundTag tagCompound = new CompoundTag(); + tagCompound.putInt("side", side.ordinal()); + tagCompound.putInt("config", ioConfig.ordinal()); + return tagCompound; + } + + @Override + public void read(@NotNull CompoundTag nbt) { + side = Direction.values()[nbt.getInt("side")]; + ioConfig = FluidConfiguration.ExtractConfig.values()[nbt.getInt("config")]; + } + } + + public enum ExtractConfig { + NONE(false, false), + INPUT(false, true), + OUTPUT(true, false), + ALL(true, true); + + boolean extact; + boolean insert; + + ExtractConfig(boolean extact, boolean insert) { + this.extact = extact; + this.insert = insert; + } + + public boolean isExtact() { + return extact; + } + + public boolean isInsert() { + return insert; + } + + public boolean isEnabled() { + return extact || insert; + } + + public FluidConfiguration.ExtractConfig getNext() { + int i = this.ordinal() + 1; + if (i >= FluidConfiguration.ExtractConfig.values().length) { + i = 0; + } + return FluidConfiguration.ExtractConfig.values()[i]; + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/blockentity/MachineBaseBlockEntity.java b/RebornCore/src/main/java/reborncore/common/blockentity/MachineBaseBlockEntity.java new file mode 100644 index 000000000..041edace3 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/blockentity/MachineBaseBlockEntity.java @@ -0,0 +1,518 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.blockentity; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.client.MinecraftClient; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket; +import net.minecraft.server.MinecraftServer; +import net.minecraft.text.LiteralText; +import net.minecraft.text.Text; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.Formatting; +import net.minecraft.util.Tickable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import org.apache.commons.lang3.Validate; +import reborncore.api.IListInfoProvider; +import reborncore.api.blockentity.IUpgrade; +import reborncore.api.blockentity.IUpgradeable; +import reborncore.api.blockentity.InventoryProvider; +import reborncore.api.recipe.IRecipeCrafterProvider; +import reborncore.common.blocks.BlockMachineBase; +import reborncore.common.fluid.FluidValue; +import reborncore.common.network.ClientBoundPackets; +import reborncore.common.network.NetworkManager; +import reborncore.common.recipes.IUpgradeHandler; +import reborncore.common.recipes.RecipeCrafter; +import reborncore.common.util.RebornInventory; +import reborncore.common.util.Tank; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.Objects; +import java.util.Optional; + +/** + * Created by modmuss50 on 04/11/2016. + */ +public class MachineBaseBlockEntity extends BlockEntity implements Tickable, IUpgradeable, IUpgradeHandler, IListInfoProvider, Inventory, SidedInventory { + + public RebornInventory upgradeInventory = new RebornInventory<>(getUpgradeSlotCount(), "upgrades", 1, this, (slotID, stack, face, direction, blockEntity) -> true); + private SlotConfiguration slotConfiguration; + public FluidConfiguration fluidConfiguration; + private RedstoneConfiguration redstoneConfiguration; + + public boolean renderMultiblock = false; + + private int ticktime = 0; + + /** + * This is used to change the speed of the crafting operation. + *

+ * 0 = none; 0.2 = 20% speed increase 0.75 = 75% increase + */ + double speedMultiplier = 0; + /** + * This is used to change the power of the crafting operation. + *

+ * 1 = none; 1.2 = 20% speed increase 1.75 = 75% increase 5 = uses 5 times + * more power + */ + double powerMultiplier = 1; + + public MachineBaseBlockEntity(BlockEntityType blockEntityTypeIn) { + super(blockEntityTypeIn); + redstoneConfiguration = new RedstoneConfiguration(this); + } + + public boolean isMultiblockValid() { + MultiblockWriter.MultiblockVerifier verifier = new MultiblockWriter.MultiblockVerifier(getPos(), getWorld()); + writeMultiblock(verifier.rotate(getFacing().getOpposite())); + return verifier.isValid(); + } + + public void writeMultiblock(MultiblockWriter writer) {} + + public void syncWithAll() { + if (world == null || world.isClient) { return; } + NetworkManager.sendToTracking(ClientBoundPackets.createCustomDescriptionPacket(this), this); + } + + public void onLoad() { + if (slotConfiguration == null) { + if (getOptionalInventory().isPresent()) { + slotConfiguration = new SlotConfiguration(getOptionalInventory().get()); + } + } + if (getTank() != null) { + if (fluidConfiguration == null) { + fluidConfiguration = new FluidConfiguration(); + } + } + redstoneConfiguration.refreshCache(); + } + + @Nullable + @Override + public BlockEntityUpdateS2CPacket toUpdatePacket() { + return new BlockEntityUpdateS2CPacket(getPos(), 0, toInitialChunkDataTag()); + } + + @Override + public CompoundTag toInitialChunkDataTag() { + CompoundTag compound = super.toTag(new CompoundTag()); + toTag(compound); + return compound; + } + + @Override + public void tick() { + if (ticktime == 0) { + onLoad(); + } + ticktime++; + @Nullable + RecipeCrafter crafter = null; + if (getOptionalCrafter().isPresent()) { + crafter = getOptionalCrafter().get(); + } + if (canBeUpgraded()) { + resetUpgrades(); + for (int i = 0; i < getUpgradeSlotCount(); i++) { + ItemStack stack = getUpgradeInvetory().getStack(i); + if (!stack.isEmpty() && stack.getItem() instanceof IUpgrade) { + ((IUpgrade) stack.getItem()).process(this, this, stack); + } + } + } + if (world == null || world.isClient) { + return; + } + if (crafter != null && isActive(RedstoneConfiguration.RECIPE_PROCESSING)) { + crafter.updateEntity(); + } + if (slotConfiguration != null && isActive(RedstoneConfiguration.ITEM_IO)) { + slotConfiguration.update(this); + } + if (fluidConfiguration != null && isActive(RedstoneConfiguration.FLUID_IO)) { + fluidConfiguration.update(this); + } + } + + public void resetUpgrades() { + resetPowerMulti(); + resetSpeedMulti(); + } + + public int getFacingInt() { + Block block = world.getBlockState(pos).getBlock(); + if (block instanceof BlockMachineBase) { + return ((BlockMachineBase) block).getFacing(world.getBlockState(pos)).getId(); + } + return 0; + } + + public Direction getFacingEnum() { + Block block = world.getBlockState(pos).getBlock(); + if (block instanceof BlockMachineBase) { + return ((BlockMachineBase) block).getFacing(world.getBlockState(pos)); + } + return Direction.NORTH; + } + + public void setFacing(Direction enumFacing) { + Block block = world.getBlockState(pos).getBlock(); + if (block instanceof BlockMachineBase) { + ((BlockMachineBase) block).setFacing(enumFacing, world, pos); + } + } + + public boolean isActive() { + Block block = world.getBlockState(pos).getBlock(); + if (block instanceof BlockMachineBase) { + return world.getBlockState(pos).get(BlockMachineBase.ACTIVE); + } + return false; + } + + public Optional> getOptionalInventory() { + if (this instanceof InventoryProvider) { + InventoryProvider inventory = (InventoryProvider) this; + if (inventory.getInventory() == null) { + return Optional.empty(); + } + return Optional.of((RebornInventory) inventory.getInventory()); + } + return Optional.empty(); + } + + protected Optional getOptionalCrafter() { + if (this instanceof IRecipeCrafterProvider) { + IRecipeCrafterProvider crafterProvider = (IRecipeCrafterProvider) this; + if (crafterProvider.getRecipeCrafter() == null) { + return Optional.empty(); + } + return Optional.of(crafterProvider.getRecipeCrafter()); + } + return Optional.empty(); + } + + @Override + public void fromTag(BlockState blockState, CompoundTag tagCompound) { + super.fromTag(blockState, tagCompound); + if (getOptionalInventory().isPresent()) { + getOptionalInventory().get().read(tagCompound); + } + if (getOptionalCrafter().isPresent()) { + getOptionalCrafter().get().read(tagCompound); + } + if (tagCompound.contains("slotConfig")) { + slotConfiguration = new SlotConfiguration(tagCompound.getCompound("slotConfig")); + } else { + if (getOptionalInventory().isPresent()) { + slotConfiguration = new SlotConfiguration(getOptionalInventory().get()); + } + } + if (tagCompound.contains("fluidConfig")) { + fluidConfiguration = new FluidConfiguration(tagCompound.getCompound("fluidConfig")); + } + if (tagCompound.contains("redstoneConfig")) { + redstoneConfiguration.refreshCache(); + redstoneConfiguration.read(tagCompound.getCompound("redstoneConfig")); + } + upgradeInventory.read(tagCompound, "Upgrades"); + } + + @Override + public CompoundTag toTag(CompoundTag tagCompound) { + super.toTag(tagCompound); + if (getOptionalInventory().isPresent()) { + getOptionalInventory().get().write(tagCompound); + } + if (getOptionalCrafter().isPresent()) { + getOptionalCrafter().get().write(tagCompound); + } + if (slotConfiguration != null) { + tagCompound.put("slotConfig", slotConfiguration.write()); + } + if (fluidConfiguration != null) { + tagCompound.put("fluidConfig", fluidConfiguration.write()); + } + upgradeInventory.write(tagCompound, "Upgrades"); + tagCompound.put("redstoneConfig", redstoneConfiguration.write()); + return tagCompound; + } + + private boolean isItemValidForSlot(int index, ItemStack stack) { + if (slotConfiguration == null) { + return false; + } + SlotConfiguration.SlotConfigHolder slotConfigHolder = slotConfiguration.getSlotDetails(index); + if (slotConfigHolder.filter() && getOptionalCrafter().isPresent()) { + RecipeCrafter crafter = getOptionalCrafter().get(); + if (!crafter.isStackValidInput(stack)) { + return false; + } + } + return true; + } + //Inventory end + + @Override + public Inventory getUpgradeInvetory() { + return upgradeInventory; + } + + @Override + public int getUpgradeSlotCount() { + return 4; + } + + public Direction getFacing() { + return getFacingEnum(); + } + + @Override + public void applyRotation(BlockRotation rotationIn) { + setFacing(rotationIn.rotate(getFacing())); + } + + @Override + public void resetSpeedMulti() { + speedMultiplier = 0; + } + + @Override + public double getSpeedMultiplier() { + return speedMultiplier; + } + + @Override + public void addPowerMulti(double amount) { + powerMultiplier = powerMultiplier * (1f + amount); + } + + @Override + public void resetPowerMulti() { + powerMultiplier = 1; + } + + @Override + public double getPowerMultiplier() { + return powerMultiplier; + } + + @Override + public double getEuPerTick(double baseEu) { + return baseEu * powerMultiplier; + } + + @Override + public void addSpeedMulti(double amount) { + if (speedMultiplier + amount <= 0.99) { + speedMultiplier += amount; + } else { + speedMultiplier = 0.99; + } + } + + public boolean hasSlotConfig() { + return true; + } + + @Nullable + public Tank getTank() { + return null; + } + + public boolean showTankConfig() { + return getTank() != null; + } + + //The amount of ticks between a slot tranfer atempt, less is faster + public int slotTransferSpeed() { + return 4; + } + + //The amount of fluid transfured each tick buy the fluid config + public FluidValue fluidTransferAmount() { + return FluidValue.BUCKET_QUARTER; + } + + @Override + public void addInfo(List info, boolean isReal, boolean hasData) { + if (hasData) { + if (getOptionalInventory().isPresent()) { + info.add(new LiteralText(Formatting.GOLD + "" + getOptionalInventory().get().getContents() + Formatting.GRAY + " items")); + } + if (!upgradeInventory.isEmpty()) { + info.add(new LiteralText(Formatting .GOLD + "" + upgradeInventory.getContents() + Formatting .GRAY + " upgrades")); + } + } + } + + public Block getBlockType(){ + return world.getBlockState(pos).getBlock(); + } + + @Override + public int size() { + if(getOptionalInventory().isPresent()){ + return getOptionalInventory().get().size(); + } + return 0; + } + + @Override + public boolean isEmpty() { + if(getOptionalInventory().isPresent()){ + return getOptionalInventory().get().isEmpty(); + } + return true; + } + + @Override + public ItemStack getStack(int i) { + if(getOptionalInventory().isPresent()){ + return getOptionalInventory().get().getStack(i); + } + return ItemStack.EMPTY; + } + + @Override + public ItemStack removeStack(int i, int i1) { + if(getOptionalInventory().isPresent()){ + return getOptionalInventory().get().removeStack(i, i1); + } + return ItemStack.EMPTY; + } + + @Override + public ItemStack removeStack(int i) { + if(getOptionalInventory().isPresent()){ + return getOptionalInventory().get().removeStack(i); + } + return ItemStack.EMPTY; + } + + @Override + public void setStack(int i, ItemStack itemStack) { + if(getOptionalInventory().isPresent()){ + getOptionalInventory().get().setStack(i, itemStack); + } + } + + @Override + public boolean canPlayerUse(PlayerEntity playerEntity) { + if(getOptionalInventory().isPresent()){ + return getOptionalInventory().get().canPlayerUse(playerEntity); + } + return false; + } + + @Override + public boolean isValid(int slot, ItemStack stack) { + return isItemValidForSlot(slot, stack); + } + + @Override + public void clear() { + if(getOptionalInventory().isPresent()){ + getOptionalInventory().get().clear(); + } + } + + @NotNull + public SlotConfiguration getSlotConfiguration() { + Validate.notNull(slotConfiguration, "slotConfiguration cannot be null"); + return slotConfiguration; + } + + @Override + public int[] getAvailableSlots(Direction side) { + if(slotConfiguration == null){ + return new int[]{}; //I think should be ok, if needed this can return all the slots + } + return slotConfiguration.getSlotsForSide(side).stream() + .filter(Objects::nonNull) + .filter(slotConfig -> slotConfig.getSlotIO().ioConfig != SlotConfiguration.ExtractConfig.NONE) + .mapToInt(SlotConfiguration.SlotConfig::getSlotID).toArray(); + } + + @Override + public boolean canInsert(int index, ItemStack stack, @Nullable Direction direction) { + if(direction == null || slotConfiguration == null){ + return false; + } + SlotConfiguration.SlotConfigHolder slotConfigHolder = slotConfiguration.getSlotDetails(index); + SlotConfiguration.SlotConfig slotConfig = slotConfigHolder.getSideDetail(direction); + if (slotConfig.getSlotIO().ioConfig.isInsert()) { + if (slotConfigHolder.filter() && getOptionalCrafter().isPresent()) { + RecipeCrafter crafter = getOptionalCrafter().get(); + return crafter.isStackValidInput(stack); + } + return slotConfig.getSlotIO().getIoConfig().isInsert(); + } + return false; + } + + @Override + public boolean canExtract(int index, ItemStack stack, Direction direction) { + if (slotConfiguration == null) { + return false; + } + SlotConfiguration.SlotConfigHolder slotConfigHolder = slotConfiguration.getSlotDetails(index); + SlotConfiguration.SlotConfig slotConfig = slotConfigHolder.getSideDetail(direction); + return slotConfig.getSlotIO().ioConfig.isExtact(); + } + + public void onBreak(World world, PlayerEntity playerEntity, BlockPos blockPos, BlockState blockState){ + + } + + public void onPlace(World worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack){ + + } + + public RedstoneConfiguration getRedstoneConfiguration() { + return redstoneConfiguration; + } + + public boolean isActive(RedstoneConfiguration.Element element) { + return redstoneConfiguration.isActive(element); + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/common/blockentity/MultiblockWriter.java b/RebornCore/src/main/java/reborncore/common/blockentity/MultiblockWriter.java new file mode 100644 index 000000000..11b26b879 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/blockentity/MultiblockWriter.java @@ -0,0 +1,286 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.blockentity; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.fabric.api.blockrenderlayer.v1.BlockRenderLayerMap; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.FluidBlock; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.render.*; +import net.minecraft.client.render.block.BlockRenderManager; +import net.minecraft.client.render.model.json.ModelTransformation; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.fluid.FluidState; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockRenderView; +import net.minecraft.world.BlockView; + +import java.util.Random; +import java.util.function.BiPredicate; + +/** + * Writes a multiblock for either verification or hologram rendering + * + * @see MultiblockVerifier + * @see HologramRenderer + * @author ramidzkh + */ +public interface MultiblockWriter { + + /** + * Adds a block to the multiblock + * + * @param x X + * @param y Y + * @param z Z + * @param predicate Predicate of the position + * @param state The state for the hologram + * @return This. Useful for chaining + */ + MultiblockWriter add(int x, int y, int z, BiPredicate predicate, BlockState state); + + /** + * Fills a section between (ax, ay, az) to (bx, by, bz) + * + * @param ax X of the first point + * @param ay Y of the first point + * @param az Z of the first point + * @param bx X of the second point + * @param by X of the second point + * @param bz Z of the second point + * @param predicate Predicate of the position + * @param state The state for the hologram + * @return This. Useful for chaining + */ + default MultiblockWriter fill(int ax, int ay, int az, int bx, int by, int bz, BiPredicate predicate, BlockState state) { + for (int x = ax; x < bx; x++) { + for (int y = ay; y < by; y++) { + for (int z = az; z < bz; z++) { + add(x, y, z, predicate, state); + } + } + } + + return this; + } + + /** + * Fills the outer ring of (0, 0, 0) to (pX, pY, pZ) through the axis, using the predicate and + * state. The inside of the ring uses holePredicate and holeHologramState + * + * @param through The axis to go through + * @param pX Size on the X axis + * @param pY Size on the Y axis + * @param pZ Size on the Z axis + * @param predicate Predicate for the ring + * @param state The ring state for the hologram + * @param holePredicate Predicate for the hole + * @param holeHologramState The hole state for the hologram + * @return This. Useful for chaining + */ + default MultiblockWriter ring(Direction.Axis through, int pX, int pY, int pZ, BiPredicate predicate, BlockState state, BiPredicate holePredicate, BlockState holeHologramState) { + if (holePredicate == null) { + holePredicate = predicate.negate(); + } + + if (holeHologramState == null) { + holeHologramState = Blocks.AIR.getDefaultState(); + } + + if (through == Direction.Axis.X) { + for (int y = 0; y < pY; y++) { + for (int z = 0; z < pZ; z++) { + if ((y == 0 || y == (pY - 1)) || (z == 0 || z == (pZ - 1))) { + add(pX, y, z, predicate, state); + } else { + add(pX, y, z, holePredicate, holeHologramState); + } + } + } + } else if (through == Direction.Axis.Y) { + for (int x = 0; x < pX; x++) { + for (int z = 0; z < pZ; z++) { + if ((x == 0 || x == (pX - 1)) || (z == 0 || z == (pZ - 1))) { + add(x, pY, z, predicate, state); + } else { + add(x, pY, z, holePredicate, holeHologramState); + } + } + } + } else if (through == Direction.Axis.Z) { + for (int x = 0; x < pX; x++) { + for (int y = 0; y < pY; y++) { + if ((x == 0 || x == (pX - 1)) || (y == 0 || y == (pY - 1))) { + add(x, y, pZ, predicate, state); + } else { + add(x, y, pZ, holePredicate, holeHologramState); + } + } + } + } + + return this; + } + + default MultiblockWriter ringWithAir(Direction.Axis through, int x, int y, int z, BiPredicate predicate, BlockState state) { + return ring(through, x, y, z, predicate, state, (view, pos) -> view.getBlockState(pos).getBlock() == Blocks.AIR, Blocks.AIR.getDefaultState()); + } + + default MultiblockWriter add(int x, int y, int z, BlockState state) { + return this.add(x, y, z, (view, pos) -> view.getBlockState(pos) == state, state); + } + + default MultiblockWriter fill(int ax, int ay, int az, int bx, int by, int bz, BlockState state) { + return fill(ax, ay, az, bx, by, bz, (view, pos) -> view.getBlockState(pos) == state, state); + } + + default MultiblockWriter ring(Direction.Axis through, int x, int y, int z, BlockState state, BlockState holeState) { + return ring(through, x, y, z, (view, pos) -> view.getBlockState(pos) == state, state, (view, pos) -> view.getBlockState(pos) == holeState, holeState); + } + + default MultiblockWriter ringWithAir(Direction.Axis through, int x, int y, int z, BlockState state) { + return ringWithAir(through, x, y, z, (view, pos) -> view.getBlockState(pos) == state, state); + } + + default MultiblockWriter translate(int offsetX, int offsetY, int offsetZ) { + return (x, y, z, predicate, state) -> add(offsetX + x, offsetY + y, offsetZ + z, predicate, state); + } + + default MultiblockWriter rotate() { + return (x, y, z, predicate, state) -> add(-z, y, x, predicate, state); + } + + default MultiblockWriter rotate(Direction direction) { + MultiblockWriter w = this; + + switch (direction) { + case NORTH: + w = w.rotate(); + case WEST: + w = w.rotate(); + case SOUTH: + w = w.rotate(); + } + + return w; + } + + /** + * A writer which prints the hologram to {@link System#out} + */ + class DebugWriter implements MultiblockWriter { + private final MultiblockWriter writer; + + public DebugWriter(MultiblockWriter writer) { + this.writer = writer; + } + + @Override + public MultiblockWriter add(int x, int y, int z, BiPredicate predicate, BlockState state) { + System.out.printf("\t%d\t%d\t%d\t%s\n", x, y, z, state.getBlock()); + + if (writer != null) { + writer.add(x, y, z, predicate, state); + } + + return this; + } + } + + /** + * A writer which verifies the positions of each block + */ + class MultiblockVerifier implements MultiblockWriter { + private final BlockPos relative; + private final BlockView view; + + private boolean valid = true; + + public MultiblockVerifier(BlockPos relative, BlockView view) { + this.relative = relative; + this.view = view; + } + + public boolean isValid() { + return valid; + } + + @Override + public MultiblockWriter add(int x, int y, int z, BiPredicate predicate, BlockState state) { + if (valid) { + valid = predicate.test(view, relative.add(x, y, z)); + } + + return this; + } + } + + /** + * Renders a hologram + */ + @Environment(EnvType.CLIENT) + class HologramRenderer implements MultiblockWriter { + private static final BlockPos OUT_OF_WORLD_POS = new BlockPos(0, 260, 0); // Bad hack; disables lighting + + private final BlockRenderView view; + private final MatrixStack matrix; + private final VertexConsumerProvider vertexConsumerProvider; + private final float scale; + + public HologramRenderer(BlockRenderView view, MatrixStack matrix, VertexConsumerProvider vertexConsumerProvider, float scale) { + this.view = view; + this.matrix = matrix; + this.vertexConsumerProvider = vertexConsumerProvider; + this.scale = scale; + } + + @Override + public MultiblockWriter add(int x, int y, int z, BiPredicate predicate, BlockState state) { + final BlockRenderManager blockRenderManager = MinecraftClient.getInstance().getBlockRenderManager(); + matrix.push(); + matrix.translate(x, y, z); + matrix.translate(0.5, 0.5, 0.5); + matrix.scale(scale, scale, scale); + + + if (state.getBlock() instanceof FluidBlock) { + FluidState fluidState = ((FluidBlock) state.getBlock()).getFluidState(state); + MinecraftClient.getInstance().getItemRenderer().renderItem(new ItemStack(fluidState.getFluid().getBucketItem()), ModelTransformation.Mode.FIXED, 15728880, OverlayTexture.DEFAULT_UV, matrix, vertexConsumerProvider); + } else { + matrix.translate(-0.5, -0.5, -0.5); + VertexConsumer consumer = vertexConsumerProvider.getBuffer(RenderLayers.getBlockLayer(state)); + blockRenderManager.renderBlock(state, OUT_OF_WORLD_POS, view, matrix, consumer, false, new Random()); + } + + matrix.pop(); + return this; + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/blockentity/RedstoneConfiguration.java b/RebornCore/src/main/java/reborncore/common/blockentity/RedstoneConfiguration.java new file mode 100644 index 000000000..1ba56a158 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/blockentity/RedstoneConfiguration.java @@ -0,0 +1,252 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.blockentity; + +import net.minecraft.block.Blocks; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.tuple.Pair; +import reborncore.api.recipe.IRecipeCrafterProvider; +import reborncore.client.screen.builder.Syncable; +import reborncore.common.util.BooleanFunction; +import reborncore.common.util.NBTSerializable; + +import org.jetbrains.annotations.NotNull; +import java.util.ArrayList; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.Consumer; +import java.util.function.Supplier; +import java.util.stream.Collectors; + +public class RedstoneConfiguration implements NBTSerializable, Syncable { + + //Set in TR to be a better item such as a battery or a cell + public static ItemStack powerStack = new ItemStack(Items.CARROT_ON_A_STICK); + public static ItemStack fluidStack = new ItemStack(Items.BUCKET); + + private static List ELEMENTS = new ArrayList<>(); + private static Map ELEMENT_MAP = new HashMap<>(); + + public static Element ITEM_IO = newBuilder() + .name("item_io") + .icon(() -> new ItemStack(Blocks.HOPPER)) + .build(); + + public static Element POWER_IO = newBuilder() + .name("power_io") + .icon(() -> powerStack) + .build(); + + public static Element FLUID_IO = newBuilder() + .name("fluid_io") + .canApply(type -> type.getTank() != null) + .icon(() -> fluidStack) + .build(); + + public static Element RECIPE_PROCESSING = newBuilder() + .name("recipe_processing") + .canApply(type -> type instanceof IRecipeCrafterProvider) + .icon(() -> new ItemStack(Blocks.CRAFTING_TABLE)) + .build(); + + + private static Element.Builder newBuilder() { + return Element.Builder.getInstance(); + } + + private final MachineBaseBlockEntity blockEntity; + private List activeElements; + private Map stateMap; + + public RedstoneConfiguration(MachineBaseBlockEntity blockEntity) { + this.blockEntity = blockEntity; + } + + public List getElements() { + if (activeElements != null) { + return activeElements; + } + return activeElements = ELEMENTS.stream() + .filter(element -> element.isApplicable(blockEntity)) + .collect(Collectors.toList()); + } + + public void refreshCache() { + activeElements = null; + + if (stateMap != null) { + for (Element element : getElements()) { + if (!stateMap.containsKey(element)) { + stateMap.put(element, State.IGNORED); + } + } + } + } + + public State getState(Element element) { + if (stateMap == null) { + populateStateMap(); + } + State state = stateMap.get(element); + Validate.notNull(state, "Unsupported element " + element.getName() + " for machine: " + blockEntity.getClass().getName()); + return state; + } + + public void setState(Element element, State state) { + if (stateMap == null) { + populateStateMap(); + } + Validate.isTrue(stateMap.containsKey(element)); + stateMap.replace(element, state); + } + + public boolean isActive(Element element) { + State state = getState(element); + if (state == State.IGNORED) { + return true; + } + boolean hasRedstonePower = blockEntity.getWorld().isReceivingRedstonePower(blockEntity.getPos()); + boolean enabledState = state == State.ENABLED_ON; + return enabledState == hasRedstonePower; + } + + private void populateStateMap() { + Validate.isTrue(stateMap == null); + stateMap = new HashMap<>(); + for (Element element : getElements()) { + stateMap.put(element, State.IGNORED); + } + } + + @NotNull + @Override + public CompoundTag write() { + CompoundTag tag = new CompoundTag(); + for (Element element : getElements()) { + tag.putInt(element.getName(), getState(element).ordinal()); + } + return tag; + } + + @Override + public void read(@NotNull CompoundTag tag) { + stateMap = new HashMap<>(); + for (String key : tag.getKeys()) { + Element element = ELEMENT_MAP.get(key); + if (element == null) { + System.out.println("Unknown element type: " + key); + continue; + } + State state = State.values()[tag.getInt(key)]; + stateMap.put(element, state); + } + + //Ensure all active states are in the map, will happen if a new state is added when the world is upgraded + for (Element element : getElements()) { + if (!stateMap.containsKey(element)) { + stateMap.put(element, State.IGNORED); + } + } + } + + @Override + public void getSyncPair(List> pairList) { + pairList.add(Pair.of(this::write, (Consumer) this::read)); + } + + public static Element getElementByName(String name) { + return ELEMENT_MAP.get(name); + } + + //Could be power input/output, item/fluid io, machine processing + public static class Element { + private final String name; + private final BooleanFunction isApplicable; + private final Supplier icon; + + public Element(String name, BooleanFunction isApplicable, Supplier icon) { + this.name = name; + this.isApplicable = isApplicable; + this.icon = icon; + } + + public boolean isApplicable(MachineBaseBlockEntity blockEntity) { + return isApplicable.get(blockEntity); + } + + public String getName() { + return name; + } + + public ItemStack getIcon() { + return icon.get(); + } + + public static class Builder { + + private String name; + private BooleanFunction isApplicable = (be) -> true; + private Supplier icon = () -> ItemStack.EMPTY; + + public Builder name(String name) { + this.name = name; + return this; + } + + public Builder canApply(BooleanFunction isApplicable) { + this.isApplicable = isApplicable; + return this; + } + + public Builder icon(Supplier stack) { + this.icon = stack; + return this; + } + + public Element build() { + Validate.isTrue(!StringUtils.isEmpty(name)); + Element element = new Element(name, isApplicable, icon); + ELEMENTS.add(element); + ELEMENT_MAP.put(element.getName(), element); + return element; + } + + public static Builder getInstance() { + return new Builder(); + } + } + } + + public enum State { + IGNORED, + ENABLED_ON, + ENABLED_OFF + } +} diff --git a/RebornCore/src/main/java/reborncore/common/blockentity/SlotConfiguration.java b/RebornCore/src/main/java/reborncore/common/blockentity/SlotConfiguration.java new file mode 100644 index 000000000..8e8930794 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/blockentity/SlotConfiguration.java @@ -0,0 +1,490 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.blockentity; + +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import it.unimi.dsi.fastutil.ints.IntArrayList; +import it.unimi.dsi.fastutil.ints.IntList; +import it.unimi.dsi.fastutil.ints.IntLists; +import net.minecraft.inventory.Inventory; +import net.minecraft.inventory.SidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.StringNbtReader; +import net.minecraft.util.math.Direction; +import org.apache.commons.lang3.Validate; +import reborncore.RebornCore; +import reborncore.api.items.InventoryUtils; +import reborncore.common.util.ItemUtils; +import reborncore.common.util.NBTSerializable; +import reborncore.common.util.RebornInventory; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.*; +import java.util.stream.Collectors; + +public class SlotConfiguration implements NBTSerializable { + + List slotDetails = new ArrayList<>(); + + @Nullable + Inventory inventory; + + public SlotConfiguration(RebornInventory inventory) { + this.inventory = inventory; + + for (int i = 0; i < inventory.size(); i++) { + updateSlotDetails(new SlotConfigHolder(i)); + } + } + + public void update(MachineBaseBlockEntity machineBase) { + if (inventory == null && machineBase.getOptionalInventory().isPresent()) { + inventory = machineBase.getOptionalInventory().get(); + } + if (inventory != null && slotDetails.size() != inventory.size()) { + for (int i = 0; i < inventory.size(); i++) { + SlotConfigHolder holder = getSlotDetails(i); + if (holder == null) { + RebornCore.LOGGER.debug("Fixed slot " + i + " in " + machineBase); + //humm somthing has gone wrong + updateSlotDetails(new SlotConfigHolder(i)); + } + } + } + if (!machineBase.getWorld().isClient && machineBase.getWorld().getTime() % machineBase.slotTransferSpeed() == 0) { + getSlotDetails().forEach(slotConfigHolder -> slotConfigHolder.handleItemIO(machineBase)); + } + } + + public SlotConfiguration(CompoundTag tagCompound) { + read(tagCompound); + } + + public List getSlotDetails() { + return slotDetails; + } + + /** + * Replaces or adds a slot detail for the slot id + * + * @param slotConfigHolder + * @return SlotConfigHolder + */ + public SlotConfigHolder updateSlotDetails(SlotConfigHolder slotConfigHolder) { + SlotConfigHolder lookup = getSlotDetails(slotConfigHolder.slotID); + if (lookup != null) { + slotDetails.remove(lookup); + } + slotDetails.add(slotConfigHolder); + return slotConfigHolder; + } + + @Nullable + public SlotConfigHolder getSlotDetails(int id) { + for (SlotConfigHolder detail : slotDetails) { + if (detail.slotID == id) { + return detail; + } + } + return null; + } + + public List getSlotsForSide(Direction facing) { + return slotDetails.stream().map(slotConfigHolder -> slotConfigHolder.getSideDetail(facing)).collect(Collectors.toList()); + } + + @NotNull + @Override + public CompoundTag write() { + CompoundTag tagCompound = new CompoundTag(); + tagCompound.putInt("size", slotDetails.size()); + for (int i = 0; i < slotDetails.size(); i++) { + tagCompound.put("slot_" + i, slotDetails.get(i).write()); + } + return tagCompound; + } + + @Override + public void read(@NotNull CompoundTag nbt) { + int size = nbt.getInt("size"); + for (int i = 0; i < size; i++) { + CompoundTag tagCompound = nbt.getCompound("slot_" + i); + SlotConfigHolder slotConfigHolder = new SlotConfigHolder(tagCompound); + updateSlotDetails(slotConfigHolder); + } + } + + public static class SlotConfigHolder implements NBTSerializable { + + int slotID; + HashMap sideMap; + boolean input, output, filter; + + public SlotConfigHolder(int slotID) { + this.slotID = slotID; + sideMap = new HashMap<>(); + Arrays.stream(Direction.values()).forEach(facing -> sideMap.put(facing, new SlotConfig(facing, slotID))); + } + + public SlotConfigHolder(CompoundTag tagCompound) { + sideMap = new HashMap<>(); + read(tagCompound); + Validate.isTrue(Arrays.stream(Direction.values()) + .map(enumFacing -> sideMap.get(enumFacing)) + .noneMatch(Objects::isNull), + "sideMap failed to load from nbt" + ); + } + + public SlotConfig getSideDetail(Direction side) { + Validate.notNull(side, "A none null side must be used"); + SlotConfig slotConfig = sideMap.get(side); + Validate.notNull(slotConfig, "slotConfig was null for side " + side); + return slotConfig; + } + + public List getAllSides() { + return new ArrayList<>(sideMap.values()); + } + + public void updateSlotConfig(SlotConfig config) { + SlotConfig toEdit = sideMap.get(config.side); + toEdit.slotIO = config.slotIO; + } + + private void handleItemIO(MachineBaseBlockEntity machineBase) { + if (!input && !output) { + return; + } + getAllSides().stream() + .filter(config -> config.getSlotIO().getIoConfig() != ExtractConfig.NONE) + .forEach(config -> { + if (input && config.getSlotIO().getIoConfig() == ExtractConfig.INPUT) { + config.handleItemInput(machineBase); + } + if (output && config.getSlotIO().getIoConfig() == ExtractConfig.OUTPUT) { + config.handleItemOutput(machineBase); + } + }); + } + + public boolean autoInput() { + return input; + } + + public boolean autoOutput() { + return output; + } + + public boolean filter() { + return filter; + } + + public void setInput(boolean input) { + this.input = input; + } + + public void setOutput(boolean output) { + this.output = output; + } + + public void setfilter(boolean filter) { + this.filter = filter; + } + + @NotNull + @Override + public CompoundTag write() { + CompoundTag compound = new CompoundTag(); + compound.putInt("slotID", slotID); + Arrays.stream(Direction.values()).forEach(facing -> compound.put("side_" + facing.ordinal(), sideMap.get(facing).write())); + compound.putBoolean("input", input); + compound.putBoolean("output", output); + compound.putBoolean("filter", filter); + return compound; + } + + @Override + public void read(@NotNull CompoundTag nbt) { + sideMap.clear(); + slotID = nbt.getInt("slotID"); + Arrays.stream(Direction.values()).forEach(facing -> { + CompoundTag compound = nbt.getCompound("side_" + facing.ordinal()); + SlotConfig config = new SlotConfig(compound); + sideMap.put(facing, config); + }); + input = nbt.getBoolean("input"); + output = nbt.getBoolean("output"); + if (nbt.contains("filter")) { //Was added later, this allows old saves to be upgraded + filter = nbt.getBoolean("filter"); + } + } + } + + public static class SlotConfig implements NBTSerializable { + @NotNull + private Direction side; + @NotNull + private SlotIO slotIO; + private int slotID; + + public SlotConfig(@NotNull Direction side, int slotID) { + this.side = side; + this.slotID = slotID; + this.slotIO = new SlotIO(ExtractConfig.NONE); + } + + public SlotConfig(@NotNull Direction side, @NotNull SlotIO slotIO, int slotID) { + this.side = side; + this.slotIO = slotIO; + this.slotID = slotID; + } + + public SlotConfig(CompoundTag tagCompound) { + read(tagCompound); + Validate.notNull(side, "error when loading slot config"); + Validate.notNull(slotIO, "error when loading slot config"); + } + + @NotNull + public Direction getSide() { + Validate.notNull(side); + return side; + } + + @NotNull + public SlotIO getSlotIO() { + Validate.notNull(slotIO); + return slotIO; + } + + public int getSlotID() { + return slotID; + } + + private void handleItemInput(MachineBaseBlockEntity machineBase) { + RebornInventory inventory = machineBase.getOptionalInventory().get(); + ItemStack targetStack = inventory.getStack(slotID); + if (targetStack.getMaxCount() == targetStack.getCount()) { + return; + } + Inventory sourceInv = InventoryUtils.getInventoryAt(machineBase.getWorld(), machineBase.getPos().offset(side)); + if (sourceInv == null) { + return; + } + + IntList availableSlots = null; + + if (sourceInv instanceof SidedInventory) { + availableSlots = IntArrayList.wrap(((SidedInventory) sourceInv).getAvailableSlots(side.getOpposite())); + } + + for (int i = 0; i < sourceInv.size(); i++) { + if (availableSlots != null && !availableSlots.contains(i)) { + continue; + } + + ItemStack sourceStack = sourceInv.getStack(i); + if (sourceStack.isEmpty()) { + continue; + } + if(!canInsertItem(slotID, sourceStack, side, machineBase)){ + continue; + } + + if (sourceInv instanceof SidedInventory && !((SidedInventory) sourceInv).canExtract(i, sourceStack, side.getOpposite())) { + continue; + } + + //Checks if we are going to merge stacks that the items are the same + if (!targetStack.isEmpty()) { + if (!ItemUtils.isItemEqual(sourceStack, targetStack, true, false)) { + continue; + } + } + int extract = 4; + if (!targetStack.isEmpty()) { + extract = Math.min(targetStack.getMaxCount() - targetStack.getCount(), extract); + } + ItemStack extractedStack = sourceInv.removeStack(i, extract); + if (targetStack.isEmpty()) { + inventory.setStack(slotID, extractedStack); + } else { + inventory.getStack(slotID).increment(extractedStack.getCount()); + } + inventory.setChanged(); + break; + } + } + + private void handleItemOutput(MachineBaseBlockEntity machineBase) { + RebornInventory inventory = machineBase.getOptionalInventory().get(); + ItemStack sourceStack = inventory.getStack(slotID); + if (sourceStack.isEmpty()) { + return; + } + Inventory destInventory = InventoryUtils.getInventoryAt(machineBase.getWorld(), machineBase.getPos().offset(side)); + if (destInventory == null) { + return; + } + + ItemStack stack = InventoryUtils.insertItem(sourceStack, destInventory, side.getOpposite()); + inventory.setStack(slotID, stack); + } + + @NotNull + @Override + public CompoundTag write() { + CompoundTag tagCompound = new CompoundTag(); + tagCompound.putInt("side", side.ordinal()); + tagCompound.put("config", slotIO.write()); + tagCompound.putInt("slot", slotID); + return tagCompound; + } + + @Override + public void read(@NotNull CompoundTag nbt) { + side = Direction.values()[nbt.getInt("side")]; + slotIO = new SlotIO(nbt.getCompound("config")); + slotID = nbt.getInt("slot"); + } + } + + public static class SlotIO implements NBTSerializable { + ExtractConfig ioConfig; + + public SlotIO(CompoundTag tagCompound) { + read(tagCompound); + } + + public SlotIO(ExtractConfig ioConfig) { + this.ioConfig = ioConfig; + } + + public ExtractConfig getIoConfig() { + return ioConfig; + } + + @NotNull + @Override + public CompoundTag write() { + CompoundTag compound = new CompoundTag(); + compound.putInt("config", ioConfig.ordinal()); + return compound; + } + + @Override + public void read(@NotNull CompoundTag nbt) { + ioConfig = ExtractConfig.values()[nbt.getInt("config")]; + } + } + + public enum ExtractConfig { + NONE(false, false), + INPUT(false, true), + OUTPUT(true, false); + + boolean extact; + boolean insert; + + ExtractConfig(boolean extact, boolean insert) { + this.extact = extact; + this.insert = insert; + } + + public boolean isExtact() { + return extact; + } + + public boolean isInsert() { + return insert; + } + + public ExtractConfig getNext() { + int i = this.ordinal() + 1; + if (i >= ExtractConfig.values().length) { + i = 0; + } + return ExtractConfig.values()[i]; + } + } + + public String toJson(String machineIdent) { + CompoundTag tagCompound = new CompoundTag(); + tagCompound.put("data", write()); + tagCompound.putString("machine", machineIdent); + return tagCompound.toString(); + } + + public void readJson(String json, String machineIdent) throws UnsupportedOperationException { + CompoundTag compound; + try { + compound = StringNbtReader.parse(json); + } catch (CommandSyntaxException e) { + throw new UnsupportedOperationException("Clipboard conetents isnt a valid slot configuation"); + } + if (!compound.contains("machine") || !compound.getString("machine").equals(machineIdent)) { + throw new UnsupportedOperationException("Machine config is not for this machine."); + } + read(compound.getCompound("data")); + } + + //DO NOT CALL THIS, use the inventory access on the inventory + public static boolean canInsertItem(int index, ItemStack itemStackIn, Direction direction, MachineBaseBlockEntity blockEntity) { + if(itemStackIn.isEmpty()){ + return false; + } + SlotConfiguration.SlotConfigHolder slotConfigHolder = blockEntity.getSlotConfiguration().getSlotDetails(index); + SlotConfiguration.SlotConfig slotConfig = slotConfigHolder.getSideDetail(direction); + if (slotConfig.getSlotIO().getIoConfig().isInsert()) { + if (slotConfigHolder.filter()) { + if(blockEntity instanceof SlotFilter){ + return ((SlotFilter) blockEntity).isStackValid(index, itemStackIn); + } + } + return blockEntity.isValid(index, itemStackIn); + } + return false; + } + + //DO NOT CALL THIS, use the inventory access on the inventory + public static boolean canExtractItem(int index, ItemStack stack, Direction direction, MachineBaseBlockEntity blockEntity) { + SlotConfiguration.SlotConfigHolder slotConfigHolder = blockEntity.getSlotConfiguration().getSlotDetails(index); + SlotConfiguration.SlotConfig slotConfig = slotConfigHolder.getSideDetail(direction); + if (slotConfig.getSlotIO().getIoConfig().isExtact()) { + return true; + } + return false; + } + + public interface SlotFilter { + boolean isStackValid(int slotID, ItemStack stack); + + int[] getInputSlots(); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/blocks/BlockMachineBase.java b/RebornCore/src/main/java/reborncore/common/blocks/BlockMachineBase.java new file mode 100644 index 000000000..df21b4566 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/blocks/BlockMachineBase.java @@ -0,0 +1,234 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.blocks; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.InventoryProvider; +import net.minecraft.block.Material; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.SidedInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.state.StateManager; +import net.minecraft.state.property.BooleanProperty; +import net.minecraft.state.property.DirectionProperty; +import net.minecraft.state.property.Properties; +import net.minecraft.util.ActionResult; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockView; +import net.minecraft.world.World; +import net.minecraft.world.WorldAccess; +import reborncore.api.ToolManager; +import reborncore.api.blockentity.IMachineGuiHandler; +import reborncore.api.blockentity.IUpgrade; +import reborncore.api.blockentity.IUpgradeable; +import reborncore.api.items.InventoryUtils; +import reborncore.common.BaseBlockEntityProvider; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.fluid.FluidUtil; +import reborncore.common.util.ItemHandlerUtils; +import reborncore.common.util.Tank; +import reborncore.common.util.WrenchUtils; + +public abstract class BlockMachineBase extends BaseBlockEntityProvider implements InventoryProvider { + + public static final DirectionProperty FACING = Properties.HORIZONTAL_FACING; + public static final BooleanProperty ACTIVE = BooleanProperty.of("active"); + + boolean hasCustomStates; + + public BlockMachineBase() { + this(Block.Settings.of(Material.METAL).strength(2F, 2F)); + } + + public BlockMachineBase(Block.Settings builder) { + this(builder, false); + } + + public BlockMachineBase(Block.Settings builder, boolean hasCustomStates) { + super(builder); + this.hasCustomStates = hasCustomStates; + if (!hasCustomStates) { + this.setDefaultState( + this.getStateManager().getDefaultState().with(FACING, Direction.NORTH).with(ACTIVE, false)); + } + BlockWrenchEventHandler.wrenableBlocks.add(this); + } + + public void setFacing(Direction facing, World world, BlockPos pos) { + if (hasCustomStates) { + return; + } + world.setBlockState(pos, world.getBlockState(pos).with(FACING, facing)); + } + + public Direction getFacing(BlockState state) { + return state.get(FACING); + } + + public void setActive(Boolean active, World world, BlockPos pos) { + if (hasCustomStates) { + return; + } + Direction facing = world.getBlockState(pos).get(FACING); + BlockState state = world.getBlockState(pos).with(ACTIVE, active).with(FACING, facing); + world.setBlockState(pos, state, 3); + } + + public boolean isActive(BlockState state) { + return state.get(ACTIVE); + } + + public boolean isAdvanced() { + return false; + } + + public abstract IMachineGuiHandler getGui(); + + // BaseBlockEntityProvider + @Override + public void onPlaced(World worldIn, BlockPos pos, BlockState state, LivingEntity placer, ItemStack stack) { + super.onPlaced(worldIn, pos, state, placer, stack); + setFacing(placer.getHorizontalFacing().getOpposite(), worldIn, pos); + + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + if (blockEntity instanceof MachineBaseBlockEntity) { + ((MachineBaseBlockEntity) blockEntity).onPlace(worldIn, pos, state, placer, stack); + } + } + + @Override + public BlockEntity createBlockEntity(BlockView worldIn) { + return null; + } + + // Block + @Override + protected void appendProperties(StateManager.Builder builder) { + builder.add(FACING, ACTIVE); + } + + @SuppressWarnings("deprecation") + @Override + public void onStateReplaced(BlockState state, World worldIn, BlockPos pos, BlockState newState, boolean isMoving) { + if (state.getBlock() != newState.getBlock()) { + ItemHandlerUtils.dropContainedItems(worldIn, pos); + super.onStateReplaced(state, worldIn, pos, newState, isMoving); + } + } + + @Override + public void onBreak(World world, BlockPos blockPos, BlockState blockState, PlayerEntity playerEntity) { + BlockEntity blockEntity = world.getBlockEntity(blockPos); + if (blockEntity instanceof MachineBaseBlockEntity) { + ((MachineBaseBlockEntity) blockEntity).onBreak(world, playerEntity, blockPos, blockState); + } + super.onBreak(world, blockPos, blockState, playerEntity); + } + + @SuppressWarnings("deprecation") + @Override + public boolean hasComparatorOutput(BlockState state) { + return true; + } + + @SuppressWarnings("deprecation") + @Override + public int getComparatorOutput(BlockState state, World world, BlockPos pos) { + return ScreenHandler.calculateComparatorOutput(getInventory(state, world, pos)); + } + + /* + * Right-click should open GUI for all non-wrench items + * Shift-Right-click should apply special action, like fill\drain bucket, install behavior, etc. + */ + @SuppressWarnings("deprecation") + @Override + public ActionResult onUse(BlockState state, World worldIn, BlockPos pos, PlayerEntity playerIn, Hand hand, BlockHitResult hitResult) { + + ItemStack stack = playerIn.getStackInHand(hand); + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + + // We extended BlockTileBase. Thus we should always have blockEntity entity. I hope. + if (blockEntity == null) { + return ActionResult.PASS; + } + + if (blockEntity instanceof MachineBaseBlockEntity) { + Tank tank = ((MachineBaseBlockEntity) blockEntity).getTank(); + if (tank != null && FluidUtil.interactWithFluidHandler(playerIn, hand, tank)) { + return ActionResult.SUCCESS; + } + } + + if (!stack.isEmpty()) { + if (ToolManager.INSTANCE.canHandleTool(stack)) { + if (WrenchUtils.handleWrench(stack, worldIn, pos, playerIn, hitResult.getSide())) { + return ActionResult.SUCCESS; + } + } else if (stack.getItem() instanceof IUpgrade && blockEntity instanceof IUpgradeable) { + IUpgradeable upgradeableEntity = (IUpgradeable) blockEntity; + if (upgradeableEntity.canBeUpgraded()) { + if (InventoryUtils.insertItemStacked(upgradeableEntity.getUpgradeInvetory(), stack, + true).getCount() > 0) { + stack = InventoryUtils.insertItemStacked(upgradeableEntity.getUpgradeInvetory(), stack, false); + playerIn.setStackInHand(Hand.MAIN_HAND, stack); + return ActionResult.SUCCESS; + } + } + } + } + + if (getGui() != null && !playerIn.isSneaking()) { + getGui().open(playerIn, pos, worldIn); + return ActionResult.SUCCESS; + } + + return super.onUse(state, worldIn, pos, playerIn, hand, hitResult); + } + + @SuppressWarnings("deprecation") + @Override + public BlockState rotate(BlockState state, BlockRotation rotation) { + return state.with(FACING, rotation.rotate(state.get(FACING))); + } + + // InventoryProvider + @Override + public SidedInventory getInventory(BlockState blockState, WorldAccess world, BlockPos blockPos) { + BlockEntity blockEntity = world.getBlockEntity(blockPos); + if (blockEntity instanceof MachineBaseBlockEntity) { + return (MachineBaseBlockEntity) blockEntity; + } + return null; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/blocks/BlockWrenchEventHandler.java b/RebornCore/src/main/java/reborncore/common/blocks/BlockWrenchEventHandler.java new file mode 100644 index 000000000..36b3200b1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/blocks/BlockWrenchEventHandler.java @@ -0,0 +1,61 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.blocks; + +import net.fabricmc.fabric.api.event.player.UseBlockCallback; +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Hand; +import reborncore.api.ToolManager; + +import java.util.ArrayList; +import java.util.List; + +public class BlockWrenchEventHandler { + + public static List wrenableBlocks = new ArrayList<>(); + + + public static void setup() { + UseBlockCallback.EVENT.register((playerEntity, world, hand, blockHitResult) -> { + if (hand == Hand.OFF_HAND) { + // Wrench should be in main hand + return ActionResult.PASS; + } + if (ToolManager.INSTANCE.canHandleTool(playerEntity.getStackInHand(Hand.MAIN_HAND))) { + BlockState state = world.getBlockState(blockHitResult.getBlockPos()); + if (wrenableBlocks.contains(state.getBlock())) { + Block block = state.getBlock(); + block.onUse(state, world, blockHitResult.getBlockPos(), playerEntity, hand, blockHitResult); + return ActionResult.SUCCESS; + } + } + return ActionResult.PASS; + }); + } + + +} diff --git a/RebornCore/src/main/java/reborncore/common/chunkloading/ChunkLoaderManager.java b/RebornCore/src/main/java/reborncore/common/chunkloading/ChunkLoaderManager.java new file mode 100644 index 000000000..9c27af33e --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/chunkloading/ChunkLoaderManager.java @@ -0,0 +1,221 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.chunkloading; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.codecs.RecordCodecBuilder; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ChunkTicketType; +import net.minecraft.server.world.ServerChunkManager; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.RegistryKey; +import net.minecraft.world.PersistentState; +import net.minecraft.world.World; +import net.minecraft.world.dimension.DimensionType; +import org.apache.commons.lang3.StringUtils; +import org.apache.commons.lang3.Validate; +import reborncore.common.network.ClientBoundPackets; +import reborncore.common.network.NetworkManager; + +import java.util.*; +import java.util.stream.Collectors; + +//This does not do the actual chunk loading, just keeps track of what chunks the chunk loader has loaded +public class ChunkLoaderManager extends PersistentState { + + public static Codec> CODEC = Codec.list(LoadedChunk.CODEC); + + private static final ChunkTicketType CHUNK_LOADER = ChunkTicketType.create("reborncore:chunk_loader", Comparator.comparingLong(ChunkPos::toLong)); + private static final String KEY = "reborncore_chunk_loader"; + + public ChunkLoaderManager() { + super(KEY); + } + + public static ChunkLoaderManager get(World world){ + ServerWorld serverWorld = (ServerWorld) world; + return serverWorld.getPersistentStateManager().getOrCreate(ChunkLoaderManager::new, KEY); + } + + private final List loadedChunks = new ArrayList<>(); + + @Override + public void fromTag(CompoundTag tag) { + loadedChunks.clear(); + + List chunks = CODEC.parse(NbtOps.INSTANCE, tag.getCompound("loadedchunks")) + .result() + .orElse(Collections.emptyList()); + + loadedChunks.addAll(chunks); + } + + @Override + public CompoundTag toTag(CompoundTag compoundTag) { + CODEC.encodeStart(NbtOps.INSTANCE, loadedChunks) + .result() + .ifPresent(tag -> compoundTag.put("loadedchunks", tag)); + return compoundTag; + } + + public Optional getLoadedChunk(World world, ChunkPos chunkPos, BlockPos chunkLoader){ + return loadedChunks.stream() + .filter(loadedChunk -> loadedChunk.getWorld().equals(getWorldName(world))) + .filter(loadedChunk -> loadedChunk.getChunk().equals(chunkPos)) + .filter(loadedChunk -> loadedChunk.getChunkLoader().equals(chunkLoader)) + .findFirst(); + } + + public Optional getLoadedChunk(World world, ChunkPos chunkPos){ + return loadedChunks.stream() + .filter(loadedChunk -> loadedChunk.getWorld().equals(getWorldName(world))) + .filter(loadedChunk -> loadedChunk.getChunk().equals(chunkPos)) + .findFirst(); + } + + public List getLoadedChunks(World world, BlockPos chunkloader){ + return loadedChunks.stream() + .filter(loadedChunk -> loadedChunk.getWorld().equals(getWorldName(world))) + .filter(loadedChunk -> loadedChunk.getChunkLoader().equals(chunkloader)) + .collect(Collectors.toList()); + } + + public boolean isChunkLoaded(World world, ChunkPos chunkPos, BlockPos chunkLoader){ + return getLoadedChunk(world, chunkPos, chunkLoader).isPresent(); + } + + public boolean isChunkLoaded(World world, ChunkPos chunkPos){ + return getLoadedChunk(world, chunkPos).isPresent(); + } + + + public void loadChunk(World world, ChunkPos chunkPos, BlockPos chunkLoader, String player){ + Validate.isTrue(!isChunkLoaded(world, chunkPos, chunkLoader), "chunk is already loaded"); + LoadedChunk loadedChunk = new LoadedChunk(chunkPos, getWorldName(world), player, chunkLoader); + loadedChunks.add(loadedChunk); + + final ServerChunkManager serverChunkManager = ((ServerWorld) world).getChunkManager(); + serverChunkManager.addTicket(ChunkLoaderManager.CHUNK_LOADER, loadedChunk.getChunk(), 31, loadedChunk.getChunk()); + + markDirty(); + } + + public void unloadChunkLoader(World world, BlockPos chunkLoader){ + getLoadedChunks(world, chunkLoader).forEach(loadedChunk -> unloadChunk(world, loadedChunk.getChunk(), chunkLoader)); + } + + public void unloadChunk(World world, ChunkPos chunkPos, BlockPos chunkLoader){ + Optional optionalLoadedChunk = getLoadedChunk(world, chunkPos, chunkLoader); + Validate.isTrue(optionalLoadedChunk.isPresent(), "chunk is not loaded"); + + LoadedChunk loadedChunk = optionalLoadedChunk.get(); + + loadedChunks.remove(loadedChunk); + + if(!isChunkLoaded(world, loadedChunk.getChunk())){ + final ServerChunkManager serverChunkManager = ((ServerWorld) world).getChunkManager(); + serverChunkManager.removeTicket(ChunkLoaderManager.CHUNK_LOADER, loadedChunk.getChunk(), 31, loadedChunk.getChunk()); + } + markDirty(); + } + + public static Identifier getWorldName(World world){ + return world.getRegistryKey().getValue(); + } + + public static RegistryKey getDimensionRegistryKey(World world){ + return world.getRegistryKey(); + } + + public void syncChunkLoaderToClient(ServerPlayerEntity serverPlayerEntity, BlockPos chunkLoader){ + syncToClient(serverPlayerEntity, loadedChunks.stream().filter(loadedChunk -> loadedChunk.getChunkLoader().equals(chunkLoader)).collect(Collectors.toList())); + } + + public void syncAllToClient(ServerPlayerEntity serverPlayerEntity) { + syncToClient(serverPlayerEntity, loadedChunks); + } + + public void clearClient(ServerPlayerEntity serverPlayerEntity) { + syncToClient(serverPlayerEntity, Collections.emptyList()); + } + + public void syncToClient(ServerPlayerEntity serverPlayerEntity, List chunks) { + NetworkManager.sendToPlayer(ClientBoundPackets.createPacketSyncLoadedChunks(chunks), serverPlayerEntity); + } + + public static class LoadedChunk { + + public static Codec CHUNK_POS_CODEC = RecordCodecBuilder.create(instance -> + instance.group( + Codec.INT.fieldOf("x").forGetter(p -> p.x), + Codec.INT.fieldOf("z").forGetter(p -> p.z) + ) + .apply(instance, ChunkPos::new)); + + public static Codec CODEC = RecordCodecBuilder.create(instance -> + instance.group( + CHUNK_POS_CODEC.fieldOf("chunk").forGetter(LoadedChunk::getChunk), + Identifier.CODEC.fieldOf("world").forGetter(LoadedChunk::getWorld), + Codec.STRING.fieldOf("player").forGetter(LoadedChunk::getPlayer), + BlockPos.CODEC.fieldOf("chunkLoader").forGetter(LoadedChunk::getChunkLoader) + ) + .apply(instance, LoadedChunk::new)); + + private ChunkPos chunk; + private Identifier world; + private String player; + private BlockPos chunkLoader; + + public LoadedChunk(ChunkPos chunk, Identifier world, String player, BlockPos chunkLoader) { + this.chunk = chunk; + this.world = world; + this.player = player; + this.chunkLoader = chunkLoader; + Validate.isTrue(!StringUtils.isBlank(player), "Player cannot be blank"); + } + + public ChunkPos getChunk() { + return chunk; + } + + public Identifier getWorld() { + return world; + } + + public String getPlayer() { + return player; + } + + public BlockPos getChunkLoader() { + return chunkLoader; + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/config/Config.java b/RebornCore/src/main/java/reborncore/common/config/Config.java new file mode 100644 index 000000000..7fb549afc --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/config/Config.java @@ -0,0 +1,64 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.config; + +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Retention(RetentionPolicy.RUNTIME) +@Target(ElementType.FIELD) +public @interface Config { + + /** + * This the category of the config + * + * @return + */ + String category() default "config"; + + /** + * This is the key for the config, the default is the field name. + * + * @return + */ + String key() default ""; + + /** + * This is a comment that will be supplied along with the config, use this to explain what the config does + * + * @return + */ + String comment() default ""; + + /** + * this is the config file name, the default is just config.cgf, use this is you whish to split the config into more than one file. + * + * @return + */ + String config() default "config"; + +} diff --git a/RebornCore/src/main/java/reborncore/common/config/Configuration.java b/RebornCore/src/main/java/reborncore/common/config/Configuration.java new file mode 100644 index 000000000..80fb6aa8c --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/config/Configuration.java @@ -0,0 +1,188 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.config; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.fabricmc.loader.api.FabricLoader; +import org.apache.commons.io.FileUtils; + +import java.io.File; +import java.io.IOException; +import java.lang.reflect.Field; +import java.lang.reflect.Modifier; +import java.nio.charset.StandardCharsets; +import java.util.HashMap; +import java.util.Map; + +public class Configuration { + + private static final Gson GSON = new GsonBuilder().setPrettyPrinting().create(); + + private final Class clazz; + private final String modId; + + public Configuration(Class clazz, String modId) { + this.clazz = clazz; + this.modId = modId; + setup(); + } + + private void setup() { + final File configDir = new File(FabricLoader.getInstance().getConfigDir().toFile(), modId); + + if (!configDir.exists()) { + configDir.mkdirs(); + } + + final File[] configFiles = configDir.listFiles(); + if (configFiles != null) { + final HashMap configs = new HashMap<>(); + for (File file : configFiles) { + final String name = file.getName().substring(0, file.getName().length() - (".json".length())); + try { + final String fileContents = FileUtils.readFileToString(file, StandardCharsets.UTF_8); + final JsonObject jsonObject = GSON.fromJson(fileContents, JsonObject.class); + configs.put(name, jsonObject); + } catch (IOException e) { + System.err.println("Failed to read config file: " + file.getAbsolutePath()); + e.printStackTrace(); + } + } + readFromJson(configs); + } + + //Save the configs + for (Map.Entry entry : toJson().entrySet()) { + final File configFile = new File(configDir, entry.getKey() + ".json"); + final String jsonStr = GSON.toJson(entry.getValue()); + try { + FileUtils.writeStringToFile(configFile, jsonStr, StandardCharsets.UTF_8); + } catch (IOException e) { + throw new RuntimeException("Failed to write config file: " + configFile.getAbsolutePath(), e); + } + } + } + + private HashMap getConfigFields() { + final HashMap fieldMap = new HashMap<>(); + for (Field field : clazz.getDeclaredFields()) { + if (!field.isAnnotationPresent(Config.class)) { + continue; + } + if (!Modifier.isStatic(field.getModifiers())) { + throw new UnsupportedOperationException("Config field must be static"); + } + Config annotation = field.getAnnotation(Config.class); + fieldMap.put(field, annotation); + } + return fieldMap; + } + + public HashMap toJson() { + final HashMap fieldMap = getConfigFields(); + final HashMap configs = new HashMap<>(); + + for (Map.Entry entry : fieldMap.entrySet()) { + Field field = entry.getKey(); + Config annotation = entry.getValue(); + + final JsonObject config = configs.computeIfAbsent(annotation.config(), s -> new JsonObject()); + + JsonObject categoryObject; + if (config.has(annotation.category())) { + categoryObject = config.getAsJsonObject(annotation.category()); + } else { + categoryObject = new JsonObject(); + config.add(annotation.category(), categoryObject); + } + + String key = annotation.key().isEmpty() ? field.getName() : annotation.key(); + if (categoryObject.has(key)) { + throw new UnsupportedOperationException("Some bad happened, duplicate key found: " + key); + } + + JsonObject fieldObject = new JsonObject(); + fieldObject.addProperty("comment", annotation.comment()); + + Object value; + try { + value = field.get(null); + } catch (IllegalAccessException e) { + throw new RuntimeException(e); + } + + JsonElement jsonElement = GSON.toJsonTree(value); + fieldObject.add("value", jsonElement); + + categoryObject.add(key, fieldObject); + } + + return configs; + } + + public void readFromJson(HashMap configs) { + final HashMap fieldMap = getConfigFields(); + + for (Map.Entry entry : fieldMap.entrySet()) { + Field field = entry.getKey(); + Config annotation = entry.getValue(); + + final JsonObject config = configs.get(annotation.config()); + + if (config == null) { + continue; //Could be possible if a new config is added + } + + JsonObject categoryObject = config.getAsJsonObject(annotation.category()); + if (categoryObject == null) { + continue; + } + + String key = annotation.key().isEmpty() ? field.getName() : annotation.key(); + if (!categoryObject.has(key)) { + continue; + } + + JsonObject fieldObject = categoryObject.get(key).getAsJsonObject(); + if (!fieldObject.has("value")) { + continue; + } + JsonElement jsonValue = fieldObject.get("value"); + Class fieldType = field.getType(); + + Object fieldValue = GSON.fromJson(jsonValue, fieldType); + + try { + field.set(null, fieldValue); + } catch (IllegalAccessException e) { + throw new RuntimeException("Failed to set field value", e); + } + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ConditionManager.java b/RebornCore/src/main/java/reborncore/common/crafting/ConditionManager.java new file mode 100644 index 000000000..0f4f3b206 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ConditionManager.java @@ -0,0 +1,141 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting; + +import java.util.HashMap; +import java.util.function.Function; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import net.minecraft.tag.ItemTags; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.util.registry.SimpleRegistry; +import org.apache.commons.lang3.Validate; + +import net.fabricmc.loader.api.FabricLoader; + +public final class ConditionManager { + + private static final HashMap> RECIPE_CONDITIONS = new HashMap<>(); + private static final HashMap> RECIPE_CONDITION_TYPES = new HashMap<>(); + + static { + //Only loads the recipe in a development env + register("development", Boolean.class, (bool) -> bool == FabricLoader.getInstance().isDevelopmentEnvironment()); + + //Only loads the recipe when the item is registered + register("item", Identifier.class, (id) -> registryContains(Registry.ITEM, id)); + + //Only loads the recipe when the fluid is registered + register("fluid", Identifier.class, (id) -> registryContains(Registry.FLUID, id)); + + //Only loads the recipe when the tag is loaded + register("tag", Identifier.class, s -> ItemTags.getTagGroup().getTags().containsKey(s)); + + //Only load the recipe if the provided mod is loaded + register("mod", String.class, s -> FabricLoader.getInstance().isModLoaded(s)); + + //Never load, just pass whatever in as the string + register("never", String.class, s -> false); + } + + private static boolean registryContains(SimpleRegistry registry, Identifier ident) { + return registry.containsId(ident); + } + + public static void register(String name, Class type, RecipeCondition recipeCondition){ + register(new Identifier("reborncore", name), type, recipeCondition); + } + + public static void register(Identifier identifier, Class type, RecipeCondition recipeCondition){ + Validate.isTrue(!RECIPE_CONDITIONS.containsKey(identifier), "Recipe condition already registered"); + RECIPE_CONDITIONS.put(identifier, recipeCondition); + RECIPE_CONDITION_TYPES.put(identifier, type); + } + + public static RecipeCondition getRecipeCondition(Identifier identifier){ + RecipeCondition condition = RECIPE_CONDITIONS.get(identifier); + if(condition == null){ + throw new UnsupportedOperationException("Could not find recipe condition for " + identifier.toString()); + } + return condition; + } + + public static boolean shouldLoadRecipe(JsonObject jsonObject){ + if(!jsonObject.has("conditions")) return true; + return jsonObject.get("conditions").getAsJsonObject().entrySet().stream() + .allMatch(entry -> shouldLoad(entry.getKey(), entry.getValue())); + } + + public static boolean shouldLoad(String ident, JsonElement jsonElement){ + Identifier identifier = parseIdent(ident); + RecipeCondition recipeCondition = getRecipeCondition(identifier); + Class type = RECIPE_CONDITION_TYPES.get(identifier); + return shouldLoad(type, jsonElement, recipeCondition); + } + + @SuppressWarnings("unchecked") + private static boolean shouldLoad(Class type, JsonElement jsonElement, RecipeCondition recipeCondition){ + Object val = TypeHelper.getValue(type, jsonElement); + return recipeCondition.shouldLoad(val); + } + + private static Identifier parseIdent(String string) { + if(string.contains(":")){ + return new Identifier(string); + } + return new Identifier("reborncore", string); + } + + @FunctionalInterface + public interface RecipeCondition { + boolean shouldLoad(T t); + } + + private static class TypeHelper { + + private static final HashMap, Function> FUNCTIONS = new HashMap<>(); + + static { + register(String.class, JsonElement::getAsString); + register(Boolean.class, JsonElement::getAsBoolean); + + register(Identifier.class, element -> new Identifier(element.getAsString())); + } + + private static void register(Class type, Function function){ + Validate.isTrue(!FUNCTIONS.containsKey(type), "Function for this class is already registered"); + FUNCTIONS.put(type, function); + } + + public static T getValue(Class type, JsonElement jsonElement){ + Validate.isTrue(FUNCTIONS.containsKey(type), "Function for this class could not be found"); + //noinspection unchecked + return (T) FUNCTIONS.get(type).apply(jsonElement); + } + + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RebornFluidRecipe.java b/RebornCore/src/main/java/reborncore/common/crafting/RebornFluidRecipe.java new file mode 100644 index 000000000..3e68aab90 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/RebornFluidRecipe.java @@ -0,0 +1,132 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting; + +import com.google.gson.JsonObject; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.registry.Registry; +import reborncore.common.crafting.ingredient.RebornIngredient; +import reborncore.common.fluid.FluidValue; +import reborncore.common.fluid.container.FluidInstance; +import net.minecraft.util.collection.DefaultedList; +import reborncore.common.util.Tank; + +import org.jetbrains.annotations.NotNull; + +public abstract class RebornFluidRecipe extends RebornRecipe { + + @NotNull + private FluidInstance fluidInstance = FluidInstance.EMPTY; + + public RebornFluidRecipe(RebornRecipeType type, Identifier name) { + super(type, name); + } + + public RebornFluidRecipe(RebornRecipeType type, Identifier name, DefaultedList ingredients, DefaultedList outputs, int power, int time) { + super(type, name, ingredients, outputs, power, time); + } + + public RebornFluidRecipe(RebornRecipeType type, Identifier name, DefaultedList ingredients, DefaultedList outputs, int power, int time, FluidInstance fluidInstance) { + this(type, name, ingredients, outputs, power, time); + this.fluidInstance = fluidInstance; + } + + @Override + public void deserialize(JsonObject jsonObject) { + super.deserialize(jsonObject); + if(jsonObject.has("tank")){ + JsonObject tank = jsonObject.get("tank").getAsJsonObject(); + + Identifier identifier = new Identifier(JsonHelper.getString(tank, "fluid")); + Fluid fluid = Registry.FLUID.get(identifier); + + FluidValue value = FluidValue.BUCKET; + if(tank.has("amount")){ + value = FluidValue.parseFluidValue(tank.get("amount")); + } + + fluidInstance = new FluidInstance(fluid, value); + } + } + + @Override + public void serialize(JsonObject jsonObject) { + super.serialize(jsonObject); + + JsonObject tankObject = new JsonObject(); + tankObject.addProperty("fluid", Registry.FLUID.getId(fluidInstance.getFluid()).toString()); + tankObject.addProperty("value", fluidInstance.getAmount().getRawValue()); + + jsonObject.add("tank", tankObject); + } + + public abstract Tank getTank(BlockEntity be); + + @Override + public boolean canCraft(BlockEntity be) { + final FluidInstance recipeFluid = fluidInstance; + final FluidInstance tankFluid = getTank(be).getFluidInstance(); + if (fluidInstance.isEmpty()) { + return true; + } + if (tankFluid.isEmpty()) { + return false; + } + if (tankFluid.getFluid().equals(recipeFluid.getFluid())) { + if (tankFluid.getAmount().equalOrMoreThan(recipeFluid.getAmount())) { + return true; + } + } + return false; + } + + @Override + public boolean onCraft(BlockEntity be) { + final FluidInstance recipeFluid = fluidInstance; + final FluidInstance tankFluid = getTank(be).getFluidInstance(); + if (fluidInstance.isEmpty()) { + return true; + } + if (tankFluid.isEmpty()) { + return false; + } + if (tankFluid.getFluid().equals(recipeFluid.getFluid())) { + if (tankFluid.getAmount().equalOrMoreThan(recipeFluid.getAmount())) { + tankFluid.subtractAmount(recipeFluid.getAmount()); + return true; + } + } + return false; + } + + @NotNull + public FluidInstance getFluidInstance() { + return fluidInstance; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipe.java b/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipe.java new file mode 100644 index 000000000..e3f0c99ca --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipe.java @@ -0,0 +1,261 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; +import io.github.cottonmc.libcd.api.CustomOutputRecipe; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.NbtOps; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.recipe.Ingredient; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import org.apache.commons.lang3.Validate; +import reborncore.api.recipe.IRecipeCrafterProvider; +import reborncore.common.crafting.ingredient.DummyIngredient; +import reborncore.common.crafting.ingredient.IngredientManager; +import reborncore.common.crafting.ingredient.RebornIngredient; +import reborncore.common.util.DefaultedListCollector; +import reborncore.common.util.serialization.SerializationUtil; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.Collections; +import java.util.List; + +public class RebornRecipe implements Recipe, CustomOutputRecipe { + + private final RebornRecipeType type; + private final Identifier name; + + private DefaultedList ingredients = DefaultedList.of(); + private DefaultedList outputs = DefaultedList.of(); + protected int power; + protected int time; + + protected boolean dummy = false; + + public RebornRecipe(RebornRecipeType type, Identifier name) { + this.type = type; + this.name = name; + } + + public RebornRecipe(RebornRecipeType type, Identifier name, DefaultedList ingredients, DefaultedList outputs, int power, int time) { + this(type, name); + this.ingredients = ingredients; + this.outputs = outputs; + this.power = power; + this.time = time; + } + + public void deserialize(JsonObject jsonObject) { + if (jsonObject.has("dummy")) { + makeDummy(); + return; + } + + //Crash if the recipe has all ready been deserialized + Validate.isTrue(ingredients.isEmpty()); + + power = JsonHelper.getInt(jsonObject, "power"); + time = JsonHelper.getInt(jsonObject, "time"); + + ingredients = SerializationUtil.stream(JsonHelper.getArray(jsonObject, "ingredients")) + .map(IngredientManager::deserialize) + .collect(DefaultedListCollector.toList()); + + JsonArray resultsJson = JsonHelper.getArray(jsonObject, "results"); + outputs = RecipeUtils.deserializeItems(resultsJson); + } + + public void serialize(JsonObject jsonObject) { + if (isDummy()) { + jsonObject.addProperty("dummy", true); + return; + } + jsonObject.addProperty("power", power); + jsonObject.addProperty("time", time); + + JsonArray ingredientsArray = new JsonArray(); + getRebornIngredients().stream().map(RebornIngredient::witeToJson).forEach(ingredientsArray::add); + jsonObject.add("ingredients", ingredientsArray); + + JsonArray resultsArray = new JsonArray(); + for (ItemStack stack : outputs) { + JsonObject stackObject = new JsonObject(); + stackObject.addProperty("item", Registry.ITEM.getId(stack.getItem()).toString()); + if (stack.getCount() > 1) { + stackObject.addProperty("count", stack.getCount()); + } + if (stack.hasTag()) { + stackObject.add("nbt", Dynamic.convert(NbtOps.INSTANCE, JsonOps.INSTANCE, stack.getTag())); + } + resultsArray.add(stackObject); + } + jsonObject.add("results", resultsArray); + } + + public void serialize(PacketByteBuf byteBuf) { + + } + + public void deserialize(PacketByteBuf byteBuf) { + + } + + @Override + public Identifier getId() { + return name; + } + + @Override + public RecipeSerializer getSerializer() { + return type; + } + + @Override + public net.minecraft.recipe.RecipeType getType() { + return type; + } + + public RebornRecipeType getRebornRecipeType() { + return type; + } + + // use the RebornIngredient version to ensure stack sizes are checked + @Deprecated + @Override + public DefaultedList getPreviewInputs() { + return ingredients.stream().map(RebornIngredient::getPreview).collect(DefaultedListCollector.toList()); + } + + public DefaultedList getRebornIngredients() { + return ingredients; + } + + public List getOutputs() { + return Collections.unmodifiableList(outputs); + } + + public int getPower() { + return power; + } + + public int getTime() { + return time; + } + + /** + * @param blockEntity the blockEntity that is doing the crafting + * @return if true the recipe will craft, if false it will not + */ + public boolean canCraft(BlockEntity blockEntity) { + if (isDummy()) { + return false; + } + if (blockEntity instanceof IRecipeCrafterProvider) { + return ((IRecipeCrafterProvider) blockEntity).canCraft(this); + } + return true; + } + + /** + * @param blockEntity the blockEntity that is doing the crafting + * @return return true if fluid was taken and should craft + */ + public boolean onCraft(BlockEntity blockEntity) { + return true; + } + + //Done as our recipes do not support these functions, hopefully nothing blidly calls them + + @Deprecated + @Override + public boolean matches(Inventory inv, World worldIn) { + throw new UnsupportedOperationException(); + } + + @Deprecated + @Override + public ItemStack craft(Inventory inv) { + throw new UnsupportedOperationException(); + } + + @Deprecated + @Override + public boolean fits(int width, int height) { + throw new UnsupportedOperationException(); + } + + // Do not call directly, this is implemented only as a fallback. getOutputs() will return all of the outputs + @Deprecated + @Override + public ItemStack getOutput() { + if (isDummy() || outputs.isEmpty()) { + return ItemStack.EMPTY; + } + return outputs.get(0); + } + + @Override + public DefaultedList getRemainingStacks(Inventory p_179532_1_) { + throw new UnsupportedOperationException(); + } + + //Done to try and stop the table from loading it + @Override + public boolean isIgnoredInRecipeBook() { + return true; + } + + private boolean isDummy() { + return dummy; + } + + void makeDummy() { + this.ingredients.add(new DummyIngredient()); + this.dummy = true; + } + + @Override + public Collection getOutputItems() { + List items = new ArrayList<>(); + for (ItemStack stack : outputs) { + items.add(stack.getItem()); + } + return items; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipeType.java b/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipeType.java new file mode 100644 index 000000000..fc221869a --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/RebornRecipeType.java @@ -0,0 +1,118 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting; + +import com.google.gson.JsonObject; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.recipe.RecipeType; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.world.World; +import reborncore.RebornCore; +import reborncore.common.util.serialization.SerializationUtil; + +import java.util.List; +import java.util.function.BiFunction; + +public class RebornRecipeType implements RecipeType, RecipeSerializer { + + private final BiFunction, Identifier, R> recipeFunction; + + private final Identifier typeId; + + public RebornRecipeType(BiFunction, Identifier, R> recipeFunction, Identifier typeId) { + this.recipeFunction = recipeFunction; + this.typeId = typeId; + } + + @Override + public R read(Identifier recipeId, JsonObject json) { + Identifier type = new Identifier(JsonHelper.getString(json, "type")); + if (!type.equals(typeId)) { + throw new RuntimeException("RebornRecipe type not supported!"); + } + + R recipe = newRecipe(recipeId); + + try{ + if(!ConditionManager.shouldLoadRecipe(json)) { + recipe.makeDummy(); + return recipe; + } + + recipe.deserialize(json); + } catch (Throwable t){ + t.printStackTrace(); + RebornCore.LOGGER.error("Failed to read recipe: " + recipeId); + } + return recipe; + + } + + public JsonObject toJson(R recipe) { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("type", typeId.toString()); + + recipe.serialize(jsonObject); + + return jsonObject; + } + + public R fromJson(Identifier recipeType, JsonObject json) { + return read(recipeType, json); + } + + R newRecipe(Identifier recipeId) { + return recipeFunction.apply(this, recipeId); + } + + @Override + public R read(Identifier recipeId, PacketByteBuf buffer) { + String input = buffer.readString(buffer.readInt()); + R r = read(recipeId, SerializationUtil.GSON_FLAT.fromJson(input, JsonObject.class)); + r.deserialize(buffer); + return r; + } + + @Override + public void write(PacketByteBuf buffer, Recipe recipe) { + JsonObject jsonObject = toJson((R) recipe); + String output = SerializationUtil.GSON_FLAT.toJson(jsonObject); + buffer.writeInt(output.length()); + buffer.writeString(output); + ((R) recipe).serialize(buffer); + } + + public Identifier getName() { + return typeId; + } + + public List getRecipes(World world) { + return RecipeUtils.getRecipes(world, this); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RecipeManager.java b/RebornCore/src/main/java/reborncore/common/crafting/RecipeManager.java new file mode 100644 index 000000000..6b2f66349 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/RecipeManager.java @@ -0,0 +1,130 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting; + +import io.netty.buffer.Unpooled; +import net.minecraft.item.ItemStack; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeSerializer; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import org.apache.commons.lang3.Validate; +import reborncore.common.crafting.ingredient.RebornIngredient; + +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.function.BiFunction; +import java.util.stream.Collectors; + +public class RecipeManager { + + private static final Map> recipeTypes = new HashMap<>(); + + public static RebornRecipeType newRecipeType(BiFunction, Identifier, R> recipeFunction, Identifier name) { + if (recipeTypes.containsKey(name)) { + throw new RuntimeException("RebornRecipe type with this name already registered"); + } + RebornRecipeType type = new RebornRecipeType<>(recipeFunction, name); + recipeTypes.put(name, type); + + Registry.register(Registry.RECIPE_SERIALIZER, name, (RecipeSerializer) type); + + return type; + } + + public static RebornRecipeType getRecipeType(Identifier name) { + if (!recipeTypes.containsKey(name)) { + throw new RuntimeException("RebornRecipe type " + name + " not found"); + } + return recipeTypes.get(name); + } + + public static List getRecipeTypes(String namespace) { + return recipeTypes.values().stream().filter(rebornRecipeType -> rebornRecipeType.getName().getNamespace().equals(namespace)).collect(Collectors.toList()); + } + + public static void validateRecipes(World world) { + //recipeTypes.forEach((key, value) -> validate(value, world)); + + System.out.println("Validating recipes"); + world.getRecipeManager().keys().forEach(identifier -> { + try { + Recipe recipe = world.getRecipeManager().get(identifier).get(); + RecipeSerializer recipeSerializer = recipe.getSerializer(); + PacketByteBuf buf = new PacketByteBuf(Unpooled.buffer()); + recipeSerializer.write(buf, recipe); + + Recipe readback = recipeSerializer.read(identifier, buf); + } catch (Exception e) { + throw new RuntimeException("Failed to read " + identifier, e); + } + }); + System.out.println("Done"); + } + + private static void validate(RebornRecipeType rebornRecipeType, World world) { + List recipes = rebornRecipeType.getRecipes(world); + + for (RebornRecipe recipe1 : recipes) { + for (RebornRecipe recipe2 : recipes) { + if (recipe1 == recipe2) { + continue; + } + + Validate.isTrue(recipe1.getRebornIngredients().size() > 0, recipe1.getId() + " has no inputs"); + Validate.isTrue(recipe2.getRebornIngredients().size() > 0, recipe2.getId() + " has no inputs"); + Validate.isTrue(recipe1.getOutputs().size() > 0, recipe1.getId() + " has no outputs"); + Validate.isTrue(recipe2.getOutputs().size() > 0, recipe2.getId() + " has no outputs"); + + boolean hasAll = true; + + for (RebornIngredient recipe1Input : recipe1.getRebornIngredients()) { + boolean matches = false; + for (ItemStack testStack : recipe1Input.getPreviewStacks()) { + for (RebornIngredient recipe2Input : recipe2.getRebornIngredients()) { + if (recipe2Input.test(testStack)) { + matches = true; + } + } + } + + if (!matches) { + hasAll = false; + } + } + + if (hasAll) { + System.out.println(recipe1.getId() + " conflicts with " + recipe2.getId()); + } + + } + } + } + + +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/RecipeUtils.java b/RebornCore/src/main/java/reborncore/common/crafting/RecipeUtils.java new file mode 100644 index 000000000..a1e4d5faf --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/RecipeUtils.java @@ -0,0 +1,82 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import reborncore.common.util.DefaultedListCollector; +import reborncore.common.util.serialization.SerializationUtil; +import reborncore.mixin.common.AccessorRecipeManager; + +import java.util.ArrayList; +import java.util.List; + +public class RecipeUtils { + @SuppressWarnings("unchecked") + public static List getRecipes(World world, RebornRecipeType type) { + AccessorRecipeManager accessorRecipeManager = (AccessorRecipeManager) world.getRecipeManager(); + //noinspection unchecked + return new ArrayList<>(accessorRecipeManager.getAll(type).values()); + } + + public static DefaultedList deserializeItems(JsonElement jsonObject) { + if (jsonObject.isJsonArray()) { + return SerializationUtil.stream(jsonObject.getAsJsonArray()).map(entry -> deserializeItem(entry.getAsJsonObject())).collect(DefaultedListCollector.toList()); + } else { + return DefaultedList.copyOf(deserializeItem(jsonObject.getAsJsonObject())); + } + } + + private static ItemStack deserializeItem(JsonObject jsonObject) { + Identifier resourceLocation = new Identifier(JsonHelper.getString(jsonObject, "item")); + Item item = Registry.ITEM.get(resourceLocation); + if (item == Items.AIR) { + throw new IllegalStateException(resourceLocation + " did not exist"); + } + int count = 1; + if (jsonObject.has("count")) { + count = JsonHelper.getInt(jsonObject, "count"); + } + ItemStack stack = new ItemStack(item, count); + if (jsonObject.has("nbt")) { + CompoundTag tag = (CompoundTag) Dynamic.convert(JsonOps.INSTANCE, NbtOps.INSTANCE, jsonObject.get("nbt")); + stack.setTag(tag); + } + return stack; + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/DummyIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/DummyIngredient.java new file mode 100644 index 000000000..c52a28cbd --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/DummyIngredient.java @@ -0,0 +1,65 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import com.google.gson.JsonObject; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.Ingredient; +import net.minecraft.util.Identifier; + +import java.util.Collections; +import java.util.List; + +public class DummyIngredient extends RebornIngredient { + + public DummyIngredient() { + super(new Identifier("reborncore", "dummy")); + } + + @Override + public boolean test(ItemStack itemStack) { + return false; + } + + @Override + public Ingredient getPreview() { + return Ingredient.EMPTY; + } + + @Override + public List getPreviewStacks() { + return Collections.emptyList(); + } + + @Override + protected JsonObject toJson() { + return new JsonObject(); + } + + @Override + public int getCount() { + return 0; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/FluidIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/FluidIngredient.java new file mode 100644 index 000000000..4708c74e3 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/FluidIngredient.java @@ -0,0 +1,161 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import com.google.gson.JsonPrimitive; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.recipe.Ingredient; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.Lazy; +import net.minecraft.util.registry.Registry; +import reborncore.common.fluid.container.ItemFluidInfo; + +import java.util.ArrayList; +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class FluidIngredient extends RebornIngredient { + + private final Fluid fluid; + private final Optional> holders; + private final Optional count; + + private final Lazy> previewStacks; + private final Lazy previewIngredient; + + public FluidIngredient(Fluid fluid, Optional> holders, Optional count) { + super(IngredientManager.FLUID_RECIPE_TYPE); + this.fluid = fluid; + this.holders = holders; + this.count = count; + + previewStacks = new Lazy<>(() -> Registry.ITEM.stream() + .filter(item -> item instanceof ItemFluidInfo) + .filter(item -> !holders.isPresent() || holders.get().stream().anyMatch(i -> i == item)) + .map(item -> ((ItemFluidInfo) item).getFull(fluid)) + .peek(stack -> stack.setCount(count.orElse(1))) + .collect(Collectors.toList())); + + previewIngredient = new Lazy<>(() -> Ingredient.ofStacks(previewStacks.get().stream())); + } + + public static RebornIngredient deserialize(JsonObject json) { + Identifier identifier = new Identifier(JsonHelper.getString(json, "fluid")); + Fluid fluid = Registry.FLUID.get(identifier); + if (fluid == Fluids.EMPTY) { + throw new JsonParseException("Fluid could not be found: " + JsonHelper.getString(json, "fluid")); + } + + Optional> holders = Optional.empty(); + + if (json.has("holder")) { + if (json.get("holder").isJsonPrimitive()) { + String ident = JsonHelper.getString(json, "holder"); + Item item = Registry.ITEM.get(new Identifier(ident)); + if (item == Items.AIR) { + throw new JsonParseException("could not find item:" + ident); + } + holders = Optional.of(Collections.singletonList(item)); + } else { + JsonArray jsonArray = json.getAsJsonArray("holder"); + List itemList = new ArrayList<>(); + for (int i = 0; i < jsonArray.size(); i++) { + String ident = jsonArray.get(i).getAsString(); + Item item = Registry.ITEM.get(new Identifier(ident)); + if (item == Items.AIR) { + throw new JsonParseException("could not find item:" + ident); + } + itemList.add(item); + } + holders = Optional.of(itemList); + } + } + + Optional count = Optional.empty(); + + if (json.has("count")) { + count = Optional.of(json.get("count").getAsInt()); + } + + return new FluidIngredient(fluid, holders, count); + } + + @Override + public boolean test(ItemStack itemStack) { + if (holders.isPresent() && holders.get().stream().noneMatch(item -> itemStack.getItem() == item)) { + return false; + } + if (count.isPresent() && itemStack.getCount() < count.get()) { + return false; + } + if (itemStack.getItem() instanceof ItemFluidInfo) { + return ((ItemFluidInfo) itemStack.getItem()).getFluid(itemStack) == fluid; + } + return false; + } + + @Override + public Ingredient getPreview() { + return previewIngredient.get(); + } + + @Override + public List getPreviewStacks() { + return previewStacks.get(); + } + + @Override + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("fluid", Registry.FLUID.getId(fluid).toString()); + if (holders.isPresent()) { + List holderList = holders.get(); + if (holderList.size() == 1) { + jsonObject.addProperty("holder", Registry.ITEM.getId(holderList.get(0)).toString()); + } else { + JsonArray holderArray = new JsonArray(); + holderList.forEach(item -> holderArray.add(new JsonPrimitive(Registry.ITEM.getId(item).toString()))); + jsonObject.add("holder", holderArray); + } + } + count.ifPresent(integer -> jsonObject.addProperty("count", integer)); + return jsonObject; + } + + @Override + public int getCount() { + return count.orElse(1); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/IngredientManager.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/IngredientManager.java new file mode 100644 index 000000000..160967f43 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/IngredientManager.java @@ -0,0 +1,81 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonParseException; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; + +import org.jetbrains.annotations.Nullable; +import java.util.HashMap; +import java.util.function.Function; + +public class IngredientManager { + + public static final Identifier STACK_RECIPE_TYPE = new Identifier("reborncore", "stack"); + public static final Identifier FLUID_RECIPE_TYPE = new Identifier("reborncore", "fluid"); + public static final Identifier TAG_RECIPE_TYPE = new Identifier("reborncore", "tag"); + public static final Identifier WRAPPED_RECIPE_TYPE = new Identifier("reborncore", "wrapped"); + + private static final HashMap> recipeTypes = new HashMap<>(); + + public static void setup() { + recipeTypes.put(STACK_RECIPE_TYPE, StackIngredient::deserialize); + recipeTypes.put(FLUID_RECIPE_TYPE, FluidIngredient::deserialize); + recipeTypes.put(TAG_RECIPE_TYPE, TagIngredient::deserialize); + recipeTypes.put(WRAPPED_RECIPE_TYPE, WrappedIngredient::deserialize); + } + + public static RebornIngredient deserialize(@Nullable JsonElement jsonElement) { + if (jsonElement == null || !jsonElement.isJsonObject()) { + throw new JsonParseException("ingredient must be a json object"); + } + + JsonObject json = jsonElement.getAsJsonObject(); + + Identifier recipeTypeIdent = STACK_RECIPE_TYPE; + //TODO find a better way to do this. + if (json.has("fluid")) { + recipeTypeIdent = FLUID_RECIPE_TYPE; + } else if (json.has("tag")) { + recipeTypeIdent = TAG_RECIPE_TYPE; + } else if (json.has("wrapped")) { + recipeTypeIdent = WRAPPED_RECIPE_TYPE; + } + + if (json.has("type")) { + recipeTypeIdent = new Identifier(JsonHelper.getString(json, "type")); + } + + Function recipeTypeFunction = recipeTypes.get(recipeTypeIdent); + if (recipeTypeFunction == null) { + throw new JsonParseException("No recipe type found for " + recipeTypeIdent.toString()); + } + return recipeTypeFunction.apply(json); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/RebornIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/RebornIngredient.java new file mode 100644 index 000000000..98c3788b0 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/RebornIngredient.java @@ -0,0 +1,69 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import com.google.gson.JsonObject; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.Ingredient; +import net.minecraft.util.Identifier; + +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Predicate; + +public abstract class RebornIngredient implements Predicate { + + private final Identifier ingredientType; + + public RebornIngredient(Identifier ingredientType) { + this.ingredientType = ingredientType; + } + + @Override + public abstract boolean test(ItemStack itemStack); + + public abstract Ingredient getPreview(); + + public abstract List getPreviewStacks(); + + protected abstract JsonObject toJson(); + + public abstract int getCount(); + + //Same as above but adds the type + public final JsonObject witeToJson() { + JsonObject jsonObject = toJson(); + jsonObject.addProperty("type", ingredientType.toString()); + return jsonObject; + } + + public void ifType(Class clazz, Consumer consumer) { + if (this.getClass().isAssignableFrom(clazz)) { + //noinspection unchecked + consumer.accept((T) this); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/SimpleTag.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/SimpleTag.java new file mode 100644 index 000000000..92a7dfe98 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/SimpleTag.java @@ -0,0 +1,49 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import net.minecraft.tag.Tag; + +import java.util.Collections; +import java.util.List; + +public class SimpleTag implements Tag { + + private final List entries; + + public SimpleTag(List entries) { + this.entries = entries; + } + + @Override + public boolean contains(T entry) { + return entries.contains(entry); + } + + @Override + public List values() { + return Collections.unmodifiableList(entries); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/StackIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/StackIngredient.java new file mode 100644 index 000000000..f13a08fd1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/StackIngredient.java @@ -0,0 +1,158 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import com.mojang.serialization.Dynamic; +import com.mojang.serialization.JsonOps; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.recipe.Ingredient; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.registry.Registry; +import org.apache.commons.lang3.Validate; + +import java.util.Collections; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class StackIngredient extends RebornIngredient { + + private final List stacks; + + private final Optional count; + private final Optional tag; + private final boolean requireEmptyTag; + + public StackIngredient(List stacks, Optional count, Optional tag, boolean requireEmptyTag) { + super(IngredientManager.STACK_RECIPE_TYPE); + this.stacks = stacks; + this.count = count; + this.tag = tag; + this.requireEmptyTag = requireEmptyTag; + Validate.isTrue(stacks.size() == 1, "stack size must 1"); + } + + public static RebornIngredient deserialize(JsonObject json) { + if (!json.has("item")) { + System.out.println("nope"); + } + Identifier identifier = new Identifier(JsonHelper.getString(json, "item")); + Item item = Registry.ITEM.getOrEmpty(identifier).orElseThrow(() -> new JsonSyntaxException("Unknown item '" + identifier + "'")); + + Optional stackSize = Optional.empty(); + if (json.has("count")) { + stackSize = Optional.of(JsonHelper.getInt(json, "count")); + } + + Optional tag = Optional.empty(); + boolean requireEmptyTag = false; + + if (json.has("nbt")) { + if (!json.get("nbt").isJsonObject()) { + if (json.get("nbt").getAsString().equals("empty")) { + requireEmptyTag = true; + } + } else { + tag = Optional.of((CompoundTag) Dynamic.convert(JsonOps.INSTANCE, NbtOps.INSTANCE, json.get("nbt"))); + } + } + + return new StackIngredient(Collections.singletonList(new ItemStack(item)), stackSize, tag, requireEmptyTag); + } + + + @Override + public boolean test(ItemStack itemStack) { + if (itemStack.isEmpty()) { + return false; + } + if (stacks.stream().noneMatch(recipeStack -> recipeStack.getItem() == itemStack.getItem())) { + return false; + } + if (count.isPresent() && count.get() > itemStack.getCount()) { + return false; + } + if (tag.isPresent()) { + if (!itemStack.hasTag()) { + return false; + } + + //Bit of a meme here, as DataFixer likes to use the most basic primative type over using an int. + //So we have to go to json and back on the incoming stack to be sure its using types that match our input. + + CompoundTag compoundTag = itemStack.getTag(); + JsonElement jsonElement = Dynamic.convert(NbtOps.INSTANCE, JsonOps.INSTANCE, compoundTag); + compoundTag = (CompoundTag) Dynamic.convert(JsonOps.INSTANCE, NbtOps.INSTANCE, jsonElement); + + if (!tag.get().equals(compoundTag)) { + return false; + } + } + return !requireEmptyTag || !itemStack.hasTag(); + } + + @Override + public Ingredient getPreview() { + return Ingredient.ofStacks(getPreviewStacks().stream()); + } + + @Override + public List getPreviewStacks() { + return Collections.unmodifiableList( + stacks.stream() + .map(ItemStack::copy) + .peek(itemStack -> itemStack.setCount(count.orElse(1))) + .peek(itemStack -> itemStack.setTag(tag.orElse(null))) + .collect(Collectors.toList())); + } + + @Override + public JsonObject toJson() { + JsonObject jsonObject = new JsonObject(); + + jsonObject.addProperty("item", Registry.ITEM.getId(stacks.get(0).getItem()).toString()); + count.ifPresent(integer -> jsonObject.addProperty("count", integer)); + + if (requireEmptyTag) { + jsonObject.addProperty("nbt", "empty"); + } else { + tag.ifPresent(compoundTag -> jsonObject.add("nbt", Dynamic.convert(NbtOps.INSTANCE, JsonOps.INSTANCE, compoundTag))); + } + + return jsonObject; + } + + @Override + public int getCount() { + return count.orElse(1); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/TagIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/TagIngredient.java new file mode 100644 index 000000000..7a8992fc4 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/TagIngredient.java @@ -0,0 +1,123 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.recipe.Ingredient; +import net.minecraft.tag.ServerTagManagerHolder; +import net.minecraft.tag.Tag; +import net.minecraft.util.Identifier; +import net.minecraft.util.JsonHelper; +import net.minecraft.util.registry.Registry; +import org.apache.commons.lang3.Validate; + +import java.util.ArrayList; +import java.util.List; +import java.util.Optional; +import java.util.stream.Collectors; + +public class TagIngredient extends RebornIngredient { + + private final Identifier tagIdentifier; + private final Tag tag; + private final Optional count; + + public TagIngredient(Identifier tagIdentifier, Tag tag, Optional count) { + super(IngredientManager.TAG_RECIPE_TYPE); + this.tagIdentifier = tagIdentifier; + this.tag = tag; + this.count = count; + } + + @Override + public boolean test(ItemStack itemStack) { + if (count.isPresent() && count.get() > itemStack.getCount()) { + return false; + } + return itemStack.getItem().isIn(tag); + } + + @Override + public Ingredient getPreview() { + return Ingredient.ofStacks(getPreviewStacks().stream()); + } + + @Override + public List getPreviewStacks() { + return tag.values().stream().map(ItemStack::new).peek(itemStack -> itemStack.setCount(count.orElse(1))).collect(Collectors.toList()); + } + + public static RebornIngredient deserialize(JsonObject json) { + Optional count = Optional.empty(); + if (json.has("count")) { + count = Optional.of(JsonHelper.getInt(json, "count")); + } + + if (json.has("server_sync")) { + Identifier tagIdent = new Identifier(JsonHelper.getString(json, "tag_identifier")); + List items = new ArrayList<>(); + for (int i = 0; i < JsonHelper.getInt(json, "items"); i++) { + Identifier identifier = new Identifier(JsonHelper.getString(json, "item_" + i)); + Item item = Registry.ITEM.get(identifier); + Validate.isTrue(item != Items.AIR, "item cannot be air"); + items.add(item); + } + return new TagIngredient(tagIdent, new SimpleTag<>(items), count); + } + + Identifier identifier = new Identifier(JsonHelper.getString(json, "tag")); + Tag tag = ServerTagManagerHolder.getTagManager().getItems().getTag(identifier); + if (tag == null) { + throw new JsonSyntaxException("Unknown item tag '" + identifier + "'"); + } + return new TagIngredient(identifier, tag, count); + } + + @Override + public JsonObject toJson() { + //Tags are not synced across the server so we sync all the items + JsonObject jsonObject = new JsonObject(); + jsonObject.addProperty("server_sync", true); + + Item[] items = tag.values().toArray(new Item[0]); + jsonObject.addProperty("items", items.length); + for (int i = 0; i < items.length; i++) { + jsonObject.addProperty("item_" + i, Registry.ITEM.getId(items[i]).toString()); + } + + count.ifPresent(integer -> jsonObject.addProperty("count", integer)); + jsonObject.addProperty("tag_identifier", tagIdentifier.toString()); + return jsonObject; + } + + @Override + public int getCount() { + return count.orElse(1); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/crafting/ingredient/WrappedIngredient.java b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/WrappedIngredient.java new file mode 100644 index 000000000..359604134 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/crafting/ingredient/WrappedIngredient.java @@ -0,0 +1,87 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.crafting.ingredient; + +import com.google.gson.JsonArray; +import com.google.gson.JsonObject; +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.Ingredient; +import reborncore.mixin.common.AccessorIngredient; + +import java.util.Arrays; +import java.util.List; + +public class WrappedIngredient extends RebornIngredient { + private Ingredient wrapped; + + public WrappedIngredient() { + super(IngredientManager.WRAPPED_RECIPE_TYPE); + } + + public WrappedIngredient(Ingredient wrapped) { + this(); + this.wrapped = wrapped; + } + + @Override + public boolean test(ItemStack itemStack) { + return wrapped.test(itemStack); + } + + @Override + public Ingredient getPreview() { + return wrapped; + } + + @Override + public List getPreviewStacks() { + return Arrays.asList(((AccessorIngredient) (Object) wrapped).getMatchingStacks()); + } + + @Override + protected JsonObject toJson() { + if (wrapped.toJson() instanceof JsonObject) { + return (JsonObject) wrapped.toJson(); + } + JsonObject jsonObject = new JsonObject(); + jsonObject.add("options", wrapped.toJson()); + return jsonObject; + } + + @Override + public int getCount() { + return ((AccessorIngredient) (Object) wrapped).getMatchingStacks().length; + } + + public static RebornIngredient deserialize(JsonObject jsonObject) { + Ingredient underlying; + if (jsonObject.has("options") && jsonObject.get("options") instanceof JsonArray) { + underlying = Ingredient.fromJson(jsonObject.get("options")); + } else { + underlying = Ingredient.fromJson(jsonObject); + } + return new WrappedIngredient(underlying); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/explosion/NuclearDamageSource.java b/RebornCore/src/main/java/reborncore/common/explosion/NuclearDamageSource.java new file mode 100644 index 000000000..4c1800335 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/explosion/NuclearDamageSource.java @@ -0,0 +1,37 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.explosion; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.damage.EntityDamageSource; + +/** + * Created by modmuss50 on 16/03/2016. + */ +public class NuclearDamageSource extends EntityDamageSource { + public NuclearDamageSource(Entity entity) { + super("nuke", entity); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/explosion/RebornExplosion.java b/RebornCore/src/main/java/reborncore/common/explosion/RebornExplosion.java new file mode 100644 index 000000000..d37516d4e --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/explosion/RebornExplosion.java @@ -0,0 +1,141 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.explosion; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.entity.LivingEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.explosion.Explosion; +import org.apache.commons.lang3.time.StopWatch; +import reborncore.RebornCore; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.List; + +/** + * Created by modmuss50 on 12/03/2016. + */ +public class RebornExplosion extends Explosion { + + @NotNull + BlockPos center; + + @NotNull + World world; + + @NotNull + int radius; + + @Nullable + LivingEntity livingBase; + + public RebornExplosion( + @NotNull + BlockPos center, + @NotNull + World world, + @NotNull + int radius) { + super(world, null, null, null, center.getX(), center.getY(), center.getZ(), radius, false, DestructionType.DESTROY); + this.center = center; + this.world = world; + this.radius = radius; + } + + public void setLivingBase( + @Nullable + LivingEntity livingBase) { + this.livingBase = livingBase; + } + + public + @Nullable + LivingEntity getLivingBase() { + return livingBase; + } + + public void explode() { + StopWatch watch = new StopWatch(); + watch.start(); + for (int tx = -radius; tx < radius + 1; tx++) { + for (int ty = -radius; ty < radius + 1; ty++) { + for (int tz = -radius; tz < radius + 1; tz++) { + if (Math.sqrt(Math.pow(tx, 2) + Math.pow(ty, 2) + Math.pow(tz, 2)) <= radius - 2) { + BlockPos pos = center.add(tx, ty, tz); + BlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + if (block != Blocks.BEDROCK && !state.isAir()) { + block.onDestroyedByExplosion(world, pos, this); + world.setBlockState(pos, Blocks.AIR.getDefaultState(), 3); + } + } + } + } + } + RebornCore.LOGGER.info("The explosion took" + watch + " to explode"); + } + + @Override + public void collectBlocksAndDamageEntities() { + explode(); + } + + @Override + public void affectWorld(boolean spawnParticles) { + explode(); + } + + @Override + public + @Nullable + LivingEntity getCausingEntity() { + return livingBase; + } + + @Override + public List getAffectedBlocks() { + List poses = new ArrayList<>(); + for (int tx = -radius; tx < radius + 1; tx++) { + for (int ty = -radius; ty < radius + 1; ty++) { + for (int tz = -radius; tz < radius + 1; tz++) { + if (Math.sqrt(Math.pow(tx, 2) + Math.pow(ty, 2) + Math.pow(tz, 2)) <= radius - 2) { + BlockPos pos = center.add(tx, ty, tz); + BlockState state = world.getBlockState(pos); + Block block = state.getBlock(); + if (block != Blocks.BEDROCK && !state.isAir()) { + poses.add(pos); + } + } + } + } + } + return poses; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/FluidSettings.java b/RebornCore/src/main/java/reborncore/common/fluid/FluidSettings.java new file mode 100644 index 000000000..f9c9318b9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/FluidSettings.java @@ -0,0 +1,59 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import net.minecraft.util.Identifier; + +public class FluidSettings { + + private Identifier flowingTexture = new Identifier("reborncore:nope"); + private Identifier stillTexture = new Identifier("reborncore:nope"); + + public FluidSettings setFlowingTexture(Identifier flowingTexture) { + this.flowingTexture = flowingTexture; + return this; + } + + public FluidSettings setStillTexture(Identifier stillTexture) { + this.stillTexture = stillTexture; + return this; + } + + public Identifier getFlowingTexture() { + return flowingTexture; + } + + public Identifier getStillTexture() { + return stillTexture; + } + + private FluidSettings() { + } + + public static FluidSettings create() { + return new FluidSettings(); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/FluidUtil.java b/RebornCore/src/main/java/reborncore/common/fluid/FluidUtil.java new file mode 100644 index 000000000..5fbb53cf3 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/FluidUtil.java @@ -0,0 +1,91 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Hand; +import net.minecraft.util.registry.Registry; +import org.apache.commons.lang3.StringUtils; +import reborncore.common.fluid.container.FluidInstance; +import reborncore.common.util.Tank; + +import org.jetbrains.annotations.NotNull; + + +public class FluidUtil { + + @Deprecated + public static FluidInstance getFluidHandler(ItemStack stack) { + return null; + } + + @Deprecated + public static boolean interactWithFluidHandler(PlayerEntity playerIn, Hand hand, Tank tank) { + return false; + } + + @Deprecated + public static ItemStack getFilledBucket(FluidInstance stack) { + return null; + } + + public static String getFluidName(@NotNull FluidInstance fluidInstance) { + return getFluidName(fluidInstance.getFluid()); + } + + public static String getFluidName(@NotNull Fluid fluid) { + return StringUtils.capitalize(Registry.FLUID.getId(fluid).getPath()); + } + + public static void transferFluid(Tank source, Tank destination, FluidValue amount) { + if (source == null || destination == null) { + return; + } + if (source.getFluid() == Fluids.EMPTY || source.getFluidAmount().isEmpty()) { + return; + } + if (destination.getFluid() != Fluids.EMPTY && source.getFluid() != destination.getFluid()) { + return; + } + FluidValue transferAmount = source.getFluidAmount().min(amount); + if (destination.getFreeSpace().equalOrMoreThan(transferAmount)) { + FluidInstance fluidInstance = destination.getFluidInstance(); + if (fluidInstance.isEmpty()) { + fluidInstance = new FluidInstance(source.getFluid(), transferAmount); + } else { + fluidInstance.addAmount(transferAmount); + } + source.setFluidAmount(source.getFluidAmount().subtract(transferAmount)); + destination.setFluidInstance(fluidInstance); + + if (source.getFluidAmount().equals(FluidValue.EMPTY)) { + source.setFluid(Fluids.EMPTY); + } + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/FluidValue.java b/RebornCore/src/main/java/reborncore/common/fluid/FluidValue.java new file mode 100644 index 000000000..8badbea10 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/FluidValue.java @@ -0,0 +1,130 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import com.google.common.base.Objects; +import com.google.gson.JsonElement; +import com.google.gson.JsonObject; +import com.google.gson.JsonSyntaxException; +import net.minecraft.util.JsonHelper; + +public final class FluidValue { + + public static final FluidValue EMPTY = new FluidValue(0); + public static final FluidValue BUCKET_QUARTER = new FluidValue(250); + public static final FluidValue BUCKET = new FluidValue(1000); + public static final FluidValue INFINITE = new FluidValue(Integer.MAX_VALUE); + + private final int rawValue; + + private FluidValue(final int rawValue) { + this.rawValue = rawValue; + } + + public FluidValue multiply(int value) { + return fromRaw(rawValue * value); + } + + public FluidValue fraction(int divider) {return fromRaw(rawValue / divider);} + + public FluidValue add(FluidValue fluidValue) { + return fromRaw(rawValue + fluidValue.rawValue); + } + + public FluidValue subtract(FluidValue fluidValue) { + return fromRaw(rawValue - fluidValue.rawValue); + } + + public FluidValue min(FluidValue fluidValue) { + return fromRaw(Math.min(rawValue, fluidValue.rawValue)); + } + + public boolean isEmpty() { + return rawValue == 0; + } + + public boolean moreThan(FluidValue value) { + return rawValue > value.rawValue; + } + + public boolean equalOrMoreThan(FluidValue value) { + return rawValue >= value.rawValue; + } + + public boolean lessThan(FluidValue value) { + return rawValue < value.rawValue; + } + + public boolean lessThanOrEqual(FluidValue value) { + return rawValue <= value.rawValue; + } + + @Override + public String toString() { + return rawValue + " Mb"; + } + + //TODO move away from using this + @Deprecated + public int getRawValue() { + return rawValue; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + FluidValue that = (FluidValue) o; + return rawValue == that.rawValue; + } + + @Override + public int hashCode() { + return Objects.hashCode(rawValue); + } + + @Deprecated + public static FluidValue fromRaw(int rawValue) { + if (rawValue < 0) { + rawValue = 0; + } + return new FluidValue(rawValue); + } + + public static FluidValue parseFluidValue(JsonElement jsonElement) { + if (jsonElement.isJsonObject()) { + final JsonObject jsonObject = jsonElement.getAsJsonObject(); + if (jsonObject.has("buckets")) { + int buckets = JsonHelper.getInt(jsonObject, "buckets"); + return BUCKET.multiply(buckets); + } + } else if (jsonElement.isJsonPrimitive() && jsonElement.getAsJsonPrimitive().isNumber()) { + //TODO add a warning here + return fromRaw(jsonElement.getAsJsonPrimitive().getAsInt()); + } + throw new JsonSyntaxException("Could not parse fluid value"); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/RebornBucketItem.java b/RebornCore/src/main/java/reborncore/common/fluid/RebornBucketItem.java new file mode 100644 index 000000000..eb765dc9b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/RebornBucketItem.java @@ -0,0 +1,34 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import net.minecraft.item.BucketItem; + +public class RebornBucketItem extends BucketItem { + + public RebornBucketItem(RebornFluid fluid, Settings settings) { + super(fluid, settings); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/RebornFluid.java b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluid.java new file mode 100644 index 000000000..3c8ea6153 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluid.java @@ -0,0 +1,143 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import net.minecraft.block.BlockState; +import net.minecraft.block.FluidBlock; +import net.minecraft.fluid.FlowableFluid; +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.FluidState; +import net.minecraft.item.Item; +import net.minecraft.state.StateManager; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.BlockView; +import net.minecraft.world.WorldAccess; +import net.minecraft.world.WorldView; + +import java.util.function.Supplier; + +public abstract class RebornFluid extends FlowableFluid { + + private final boolean still; + + private final FluidSettings fluidSettings; + private final Supplier fluidBlockSupplier; + private final Supplier bucketItemSuppler; + private final Supplier flowingSuppler; + private final Supplier stillSuppler; + + public RebornFluid(boolean still, FluidSettings fluidSettings, Supplier fluidBlockSupplier, Supplier bucketItemSuppler, Supplier flowingSuppler, Supplier stillSuppler) { + this.still = still; + this.fluidSettings = fluidSettings; + this.fluidBlockSupplier = fluidBlockSupplier; + this.bucketItemSuppler = bucketItemSuppler; + this.flowingSuppler = flowingSuppler; + this.stillSuppler = stillSuppler; + } + + public FluidSettings getFluidSettings() { + return fluidSettings; + } + + @Override + public RebornFluid getFlowing() { + return flowingSuppler.get(); + } + + @Override + public RebornFluid getStill() { + return stillSuppler.get(); + } + + @Override + protected boolean isInfinite() { + return false; + } + + @Override + public boolean isStill(FluidState fluidState) { + return still; + } + + @Override + protected void beforeBreakingBlock(WorldAccess world, BlockPos pos, BlockState state) { + + } + + @Override + protected int getFlowSpeed(WorldView world) { + return 4; + } + + @Override + protected int getLevelDecreasePerBlock(WorldView world) { + return 1; + } + + @Override + public Item getBucketItem() { + return bucketItemSuppler.get(); + } + + @Override + protected boolean canBeReplacedWith(FluidState fluidState, BlockView blockView, BlockPos blockPos, Fluid fluid, Direction direction) { + return false; + } + + @Override + public boolean matchesType(Fluid fluid) { + return getFlowing() == fluid || getStill() == fluid; + } + + @Override + public int getTickRate(WorldView world) { + return 10; + } + + @Override + protected float getBlastResistance() { + return 100F; + } + + @Override + protected BlockState toBlockState(FluidState fluidState) { + return fluidBlockSupplier.get().getDefaultState().with(FluidBlock.LEVEL, method_15741(fluidState)); + } + + @Override + public int getLevel(FluidState fluidState) { + return still ? 8 : fluidState.get(LEVEL); + } + + @Override + protected void appendProperties(StateManager.Builder stateBuilder) { + super.appendProperties(stateBuilder); + if (!still) { + stateBuilder.add(LEVEL); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidBlock.java b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidBlock.java new file mode 100644 index 000000000..e47c5c9e7 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidBlock.java @@ -0,0 +1,42 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import net.minecraft.block.Block; +import net.minecraft.block.FluidBlock; + +public class RebornFluidBlock extends FluidBlock { + + private final RebornFluid fluid; + + public RebornFluidBlock(RebornFluid fluid, Block.Settings properties) { + super(fluid, properties); + this.fluid = fluid; + } + + public RebornFluid getFluid() { + return fluid; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidManager.java b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidManager.java new file mode 100644 index 000000000..ce044c0c7 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidManager.java @@ -0,0 +1,77 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import net.minecraft.fluid.Fluid; +import net.minecraft.item.BucketItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.Identifier; +import net.minecraft.util.Lazy; +import net.minecraft.util.registry.Registry; +import reborncore.common.fluid.container.ItemFluidInfo; + +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +public class RebornFluidManager { + + private static final HashMap fluids = new HashMap<>(); + + private static Lazy> bucketMap; + + public static void register(RebornFluid rebornFluid, Identifier identifier) { + fluids.put(identifier, rebornFluid); + Registry.register(Registry.FLUID, identifier, rebornFluid); + } + + public static void setupBucketMap() { + bucketMap = new Lazy<>(() -> { + Map map = new HashMap<>(); + Registry.ITEM.stream().filter(item -> item instanceof BucketItem).forEach(item -> { + BucketItem bucketItem = (BucketItem) item; + //We can be sure of this as we add this via a mixin + ItemFluidInfo fluidInfo = (ItemFluidInfo) bucketItem; + Fluid fluid = fluidInfo.getFluid(new ItemStack(item)); + if (!map.containsKey(fluid)) { + map.put(fluid, bucketItem); + } + }); + return map; + }); + } + + public static Map getBucketMap() { + return bucketMap.get(); + } + + public static HashMap getFluids() { + return fluids; + } + + public static Stream getFluidStream() { + return fluids.values().stream(); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidRenderManager.java b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidRenderManager.java new file mode 100644 index 000000000..8cdaecc56 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/RebornFluidRenderManager.java @@ -0,0 +1,92 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid; + +import net.fabricmc.fabric.api.client.render.fluid.v1.FluidRenderHandlerRegistry; +import net.fabricmc.fabric.api.event.client.ClientSpriteRegistryCallback; +import net.fabricmc.fabric.api.resource.ResourceManagerHelper; +import net.fabricmc.fabric.api.resource.ResourceReloadListenerKeys; +import net.fabricmc.fabric.api.resource.SimpleSynchronousResourceReloadListener; +import net.minecraft.client.texture.Sprite; +import net.minecraft.client.texture.SpriteAtlasTexture; +import net.minecraft.fluid.Fluid; +import net.minecraft.resource.ResourceManager; +import net.minecraft.resource.ResourceType; +import net.minecraft.util.Identifier; +import reborncore.client.RenderUtil; +import reborncore.common.util.TemporaryLazy; + +import java.util.Collection; +import java.util.Collections; +import java.util.HashMap; +import java.util.Map; +import java.util.stream.Stream; + +public class RebornFluidRenderManager implements ClientSpriteRegistryCallback, SimpleSynchronousResourceReloadListener { + + private static final Map> spriteMap = new HashMap<>(); + + public static void setupClient() { + RebornFluidRenderManager rebornFluidRenderManager = new RebornFluidRenderManager(); + ClientSpriteRegistryCallback.event(SpriteAtlasTexture.BLOCK_ATLAS_TEXTURE).register(rebornFluidRenderManager); + ResourceManagerHelper.get(ResourceType.CLIENT_RESOURCES).registerReloadListener(rebornFluidRenderManager); + RebornFluidManager.getFluidStream().forEach(RebornFluidRenderManager::setupFluidRenderer); + } + + private static void setupFluidRenderer(RebornFluid fluid) { + //Done lazy as we want to ensure we get the sprite at the correct time, but also dont want to be making these calls every time its required. + TemporaryLazy sprites = new TemporaryLazy<>(() -> { + FluidSettings fluidSettings = fluid.getFluidSettings(); + return new Sprite[]{RenderUtil.getSprite(fluidSettings.getStillTexture()), RenderUtil.getSprite(fluidSettings.getFlowingTexture())}; + }); + + spriteMap.put(fluid, sprites); + FluidRenderHandlerRegistry.INSTANCE.register(fluid, (extendedBlockView, blockPos, fluidState) -> sprites.get()); + } + + @Override + public void registerSprites(SpriteAtlasTexture spriteAtlasTexture, Registry registry) { + Stream.concat( + RebornFluidManager.getFluidStream().map(rebornFluid -> rebornFluid.getFluidSettings().getFlowingTexture()), + RebornFluidManager.getFluidStream().map(rebornFluid -> rebornFluid.getFluidSettings().getStillTexture()) + ).forEach(registry::register); + } + + @Override + public Identifier getFabricId() { + return new Identifier("reborncore", "fluid_render_manager"); + } + + @Override + public void apply(ResourceManager manager) { + //Reset the cached fluid sprites + spriteMap.forEach((key, value) -> value.reset()); + } + + @Override + public Collection getFabricDependencies() { + return Collections.singletonList(ResourceReloadListenerKeys.TEXTURES); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/container/FluidInstance.java b/RebornCore/src/main/java/reborncore/common/fluid/container/FluidInstance.java new file mode 100644 index 000000000..dc222effb --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/container/FluidInstance.java @@ -0,0 +1,140 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid.container; + +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; +import reborncore.common.fluid.FluidValue; +import reborncore.common.util.NBTSerializable; + +public class FluidInstance implements NBTSerializable { + public static final String FLUID_KEY = "Fluid"; + public static final String AMOUNT_KEY = "Amount"; + public static final String TAG_KEY = "Tag"; + + public static final FluidInstance EMPTY = new FluidInstance(Fluids.EMPTY, FluidValue.EMPTY); + + protected Fluid fluid; + protected FluidValue amount; + protected CompoundTag tag; + + public FluidInstance(Fluid fluid, FluidValue amount) { + this.fluid = fluid; + this.amount = amount; + } + + public FluidInstance(Fluid fluid) { + this(fluid, FluidValue.EMPTY); + } + + public FluidInstance() { + this(Fluids.EMPTY); + } + + public FluidInstance(CompoundTag tag) { + this(); + read(tag); + } + + public Fluid getFluid() { + return fluid; + } + + public FluidValue getAmount() { + return amount; + } + + public CompoundTag getTag() { + return tag; + } + + public FluidInstance setFluid(Fluid fluid) { + this.fluid = fluid; + return this; + } + + public FluidInstance setAmount(FluidValue value) { + this.amount = value; + return this; + } + + public FluidInstance subtractAmount(FluidValue amount) { + this.amount = this.amount.subtract(amount); + return this; + } + + public FluidInstance addAmount(FluidValue amount) { + this.amount = this.amount.add(amount); + return this; + } + + public void setTag(CompoundTag tag) { + this.tag = tag; + } + + public boolean isEmpty() { + return isEmptyFluid() || this.getAmount().isEmpty(); + } + + public boolean isEmptyFluid() { + return this.getFluid() == Fluids.EMPTY; + } + + public FluidInstance copy() { + return new FluidInstance().setFluid(fluid).setAmount(amount); + } + + @Override + public CompoundTag write() { + CompoundTag tag = new CompoundTag(); + tag.putString(FLUID_KEY, Registry.FLUID.getId(fluid).toString()); + tag.putInt(AMOUNT_KEY, amount.getRawValue()); + if (this.tag != null && !this.tag.isEmpty()) { + tag.put(TAG_KEY, this.tag); + } + return tag; + } + + @Override + public void read(CompoundTag tag) { + fluid = Registry.FLUID.get(new Identifier(tag.getString(FLUID_KEY))); + amount = FluidValue.fromRaw(tag.getInt(AMOUNT_KEY)); + if (tag.contains(TAG_KEY)) { + this.tag = tag.getCompound(TAG_KEY); + } + } + + @Override + public boolean equals(Object obj) { + return obj instanceof FluidInstance && fluid == ((FluidInstance) obj).getFluid() && amount.equals(((FluidInstance) obj).getAmount()); + } + + public boolean isFluidEqual(FluidInstance instance) { + return (isEmpty() && instance.isEmpty()) || fluid.equals(instance.getFluid()); + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/common/fluid/container/GenericFluidContainer.java b/RebornCore/src/main/java/reborncore/common/fluid/container/GenericFluidContainer.java new file mode 100644 index 000000000..fd9b4be09 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/container/GenericFluidContainer.java @@ -0,0 +1,96 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid.container; + +import net.minecraft.fluid.Fluid; +import net.minecraft.item.ItemStack; +import reborncore.common.fluid.FluidValue; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +/* + + * Based of Slilk's API but with some breaking changes + + * Direction has been replaced with a generic type, this allows for things like ItemStack to be easily passed along + * Some methods such as getCapacity have been tweaked to also provide the type + * Some methods have got default implementations making it a lot easier to implement without the worry for bugs + * The multiple fluids thing has gone, it is still possible to one fluid per side if wanted as the type is passed around everywhere + * A lot of the "helper" methods have been removed, these should really go in boilerplate classes and not the in raw api + * removed the docs as cba to write them + + */ +public interface GenericFluidContainer { + + @Nullable + static GenericFluidContainer fromStack(@NotNull ItemStack itemStack) { + if (itemStack.getItem() instanceof GenericFluidContainer) { + //noinspection unchecked + return (GenericFluidContainer) itemStack.getItem(); + } + return null; + } + + void setFluid(T type, @NotNull FluidInstance instance); + + @NotNull + FluidInstance getFluidInstance(T type); + + FluidValue getCapacity(T type); + + default boolean canHold(T type, Fluid fluid) { + return true; + } + + default FluidValue getCurrentFluidAmount(T type) { + return getFluidInstance(type).getAmount(); + } + + default boolean canInsertFluid(T type, @NotNull Fluid fluid, FluidValue amount) { + if (!canHold(type, fluid)) { + return false; + } + FluidInstance currentFluid = getFluidInstance(type); + return currentFluid.isEmpty() || currentFluid.getFluid() == fluid && currentFluid.getAmount().add(amount).lessThan(getCapacity(type)); + } + + default boolean canExtractFluid(T type, @NotNull Fluid fluid, FluidValue amount) { + return getFluidInstance(type).getFluid() == fluid && amount.lessThanOrEqual(getFluidInstance(type).getAmount()); + } + + default void insertFluid(T type, @NotNull Fluid fluid, FluidValue amount) { + if (canInsertFluid(type, fluid, amount)) { + setFluid(type, getFluidInstance(type).addAmount(amount)); + } + } + + default void extractFluid(T type, @NotNull Fluid fluid, FluidValue amount) { + if (canExtractFluid(type, fluid, amount)) { + setFluid(type, getFluidInstance(type).subtractAmount(amount)); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/fluid/container/ItemFluidInfo.java b/RebornCore/src/main/java/reborncore/common/fluid/container/ItemFluidInfo.java new file mode 100644 index 000000000..292d26256 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/fluid/container/ItemFluidInfo.java @@ -0,0 +1,38 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.fluid.container; + +import net.minecraft.fluid.Fluid; +import net.minecraft.item.ItemStack; + +public interface ItemFluidInfo { + + ItemStack getEmpty(); + + ItemStack getFull(Fluid fluid); + + Fluid getFluid(ItemStack itemStack); + +} diff --git a/RebornCore/src/main/java/reborncore/common/misc/Functions.java b/RebornCore/src/main/java/reborncore/common/misc/Functions.java new file mode 100644 index 000000000..27fe51b40 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/misc/Functions.java @@ -0,0 +1,67 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.misc; + +import net.minecraft.util.math.Direction; + +public class Functions { + public static int getIntDirFromDirection(Direction dir) { + switch (dir) { + case DOWN: + return 0; + case EAST: + return 5; + case NORTH: + return 2; + case SOUTH: + return 3; + case UP: + return 1; + case WEST: + return 4; + default: + return 0; + } + } + + public static Direction getDirectionFromInt(int dir) { + int metaDataToSet = 0; + switch (dir) { + case 0: + metaDataToSet = 2; + break; + case 1: + metaDataToSet = 4; + break; + case 2: + metaDataToSet = 3; + break; + case 3: + metaDataToSet = 5; + break; + } + return Direction.byId(metaDataToSet); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/misc/ModSounds.java b/RebornCore/src/main/java/reborncore/common/misc/ModSounds.java new file mode 100644 index 000000000..99c4226b2 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/misc/ModSounds.java @@ -0,0 +1,47 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.misc; + +import net.minecraft.sound.SoundEvent; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +/** + * @author drcrazy + */ + +public class ModSounds { + + public static SoundEvent BLOCK_DISMANTLE; + + public static void setup() { + BLOCK_DISMANTLE = createSoundEvent(new Identifier("reborncore", "block_dismantle")); + + } + + private static SoundEvent createSoundEvent(Identifier identifier) { + return Registry.register(Registry.SOUND_EVENT, identifier, new SoundEvent(identifier)); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/misc/MultiBlockBreakingTool.java b/RebornCore/src/main/java/reborncore/common/misc/MultiBlockBreakingTool.java new file mode 100644 index 000000000..3dc4ae53b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/misc/MultiBlockBreakingTool.java @@ -0,0 +1,38 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.misc; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +import org.jetbrains.annotations.Nullable; +import java.util.Set; + +public interface MultiBlockBreakingTool { + + Set getBlocksToBreak(ItemStack stack, World worldIn, BlockPos pos, @Nullable LivingEntity entityLiving); +} diff --git a/RebornCore/src/main/java/reborncore/common/misc/RebornCoreTags.java b/RebornCore/src/main/java/reborncore/common/misc/RebornCoreTags.java new file mode 100644 index 000000000..727ff10eb --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/misc/RebornCoreTags.java @@ -0,0 +1,34 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.misc; + +import net.fabricmc.fabric.api.tag.TagRegistry; +import net.minecraft.item.Item; +import net.minecraft.tag.Tag; +import net.minecraft.util.Identifier; + +public class RebornCoreTags { + public static final Tag WATER_EXPLOSION_ITEM = TagRegistry.item(new Identifier("reborncore", "water_explosion")); +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/BlockMultiblockBase.java b/RebornCore/src/main/java/reborncore/common/multiblock/BlockMultiblockBase.java new file mode 100644 index 000000000..53b3298cf --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/BlockMultiblockBase.java @@ -0,0 +1,39 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +import net.minecraft.block.Block; +import reborncore.common.BaseBlockEntityProvider; + +/* + * Base class for multiblock-capable blocks. This is only a reference implementation + * and can be safely ignored. + */ +public abstract class BlockMultiblockBase extends BaseBlockEntityProvider { + + protected BlockMultiblockBase(Block.Settings builder) { + super(builder); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/IMultiblockPart.java b/RebornCore/src/main/java/reborncore/common/multiblock/IMultiblockPart.java new file mode 100644 index 000000000..e68c06f24 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/IMultiblockPart.java @@ -0,0 +1,264 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.BlockPos; + +import java.util.Set; + +/** + * Basic interface for a multiblock machine part. This is defined as an abstract + * class as we need the basic functionality of a BlockEntity as well. Preferably, + * you should derive from MultiblockBlockEntityBase, which does all the hard work + * for you. + *

+ * {@link MultiblockBlockEntityBase} + */ +public abstract class IMultiblockPart extends BlockEntity { + public static final int INVALID_DISTANCE = Integer.MAX_VALUE; + + public IMultiblockPart(BlockEntityType blockEntityTypeIn) { + super(blockEntityTypeIn); + } + + /** + * @return True if this block is connected to a multiblock controller. False + * otherwise. + */ + public abstract boolean isConnected(); + + /** + * @return The attached multiblock controller for this blockEntity entity. + */ + public abstract MultiblockControllerBase getMultiblockController(); + + /** + * Returns the location of this blockEntity entity in the world, in BlockPos + * form. + * + * @return A BlockPos with its x,y,z members set to the location of this + * blockEntity entity in the world. + */ + public abstract BlockPos getWorldLocation(); + + // Multiblock connection-logic callbacks + + /** + * Called after this block has been attached to a new multiblock controller. + * + * @param newController The new multiblock controller to which this blockEntity entity is + * attached. + */ + public abstract void onAttached(MultiblockControllerBase newController); + + /** + * Called after this block has been detached from a multiblock controller. + * + * @param multiblockController The multiblock controller that no longer controls this blockEntity + * entity. + */ + public abstract void onDetached(MultiblockControllerBase multiblockController); + + /** + * Called when this block is being orphaned. Use this to copy game-data + * values that should persist despite a machine being broken. This should + * NOT mark the part as disconnected. onDetached will be called immediately + * afterwards. + * + * @param oldController The controller which is orphaning this block. + * @param oldControllerSize The number of connected blocks in the controller prior to + * shedding orphans. + * @param newControllerSize The number of connected blocks in the controller after + * shedding orphans. + * @see #onDetached(MultiblockControllerBase) + */ + public abstract void onOrphaned(MultiblockControllerBase oldController, int oldControllerSize, + int newControllerSize); + + // Multiblock fuse/split helper methods. Here there be dragons. + + /** + * Factory method. Creates a new multiblock controller and returns it. Does + * not attach this blockEntity entity to it. Override this in your game code! + * + * @return A new Multiblock Controller, derived from + * MultiblockControllerBase. + */ + public abstract MultiblockControllerBase createNewMultiblock(); + + /** + * Retrieve the type of multiblock controller which governs this part. Used + * to ensure that incompatible multiblocks are not merged. + * + * @return The class/type of the multiblock controller which governs this + * type of part. + */ + public abstract Class getMultiblockControllerType(); + + /** + * Called when this block is moved from its current controller into a new + * controller. A special case of attach/detach, done here for efficiency to + * avoid triggering lots of recalculation logic. + * + * @param newController The new controller into which this blockEntity entity is being + * merged. + */ + public abstract void onAssimilated(MultiblockControllerBase newController); + + // Multiblock connection data access. + // You generally shouldn't toy with these! + // They're for use by Multiblock Controllers. + + /** + * Set that this block has been visited by your validation algorithms. + */ + public abstract void setVisited(); + + /** + * Set that this block has not been visited by your validation algorithms; + */ + public abstract void setUnvisited(); + + /** + * @return True if this block has been visited by your validation algorithms + * since the last reset. + */ + public abstract boolean isVisited(); + + /** + * Called when this block becomes the designated block for saving data and + * transmitting data across the wire. + */ + public abstract void becomeMultiblockSaveDelegate(); + + /** + * Called when this block is no longer the designated block for saving data + * and transmitting data across the wire. + */ + public abstract void forfeitMultiblockSaveDelegate(); + + /** + * Is this block the designated save/load & network delegate? + * + * @return Boolean + */ + public abstract boolean isMultiblockSaveDelegate(); + + /** + * Returns an array containing references to neighboring IMultiblockPart + * blockEntity entities. Primarily a utility method. Only works after blockentity + * construction, so it cannot be used in + * MultiblockControllerBase::attachBlock. + *

+ * This method is chunk-safe on the server; it will not query for parts in + * chunks that are unloaded. Note that no method is chunk-safe on the + * client, because ChunkProviderClient is stupid. + * + * @return An array of references to neighboring IMultiblockPart blockEntity + * entities. + */ + public abstract IMultiblockPart[] getNeighboringParts(); + + // Multiblock business-logic callbacks - implement these! + + /** + * Called when a machine is fully assembled from the disassembled state, + * meaning it was broken by a player/entity action, not by chunk unloads. + * Note that, for non-square machines, the min/max coordinates may not + * actually be part of the machine! They form an outer bounding box for the + * whole machine itself. + * + * @param multiblockControllerBase The controller to which this part is being assembled. + */ + public abstract void onMachineAssembled(MultiblockControllerBase multiblockControllerBase); + + /** + * Called when the machine is broken for game reasons, e.g. a player removed + * a block or an explosion occurred. + */ + public abstract void onMachineBroken(); + + /** + * Called when the user activates the machine. This is not called by + * default, but is included as most machines have this game-logical concept. + */ + public abstract void onMachineActivated(); + + /** + * Called when the user deactivates the machine. This is not called by + * default, but is included as most machines have this game-logical concept. + */ + public abstract void onMachineDeactivated(); + + // Block events + + /** + * Called when this part should check its neighbors. This method MUST NOT + * cause additional chunks to load. ALWAYS check to see if a chunk is loaded + * before querying for its blockEntity entity This part should inform the + * controller that it is attaching at this time. + * + * @return A Set of multiblock controllers to which this object would like + * to attach. It should have attached to one of the controllers in + * this list. Return null if there are no compatible controllers + * nearby. + */ + public abstract Set attachToNeighbors(); + + /** + * Assert that this part is detached. If not, log a warning and set the + * part's controller to null. Do NOT fire the full disconnection logic. + */ + public abstract void assertDetached(); + + /** + * @return True if a part has multiblock game-data saved inside it. + */ + public abstract boolean hasMultiblockSaveData(); + + /** + * @return The part's saved multiblock game-data in NBT format, or null if + * there isn't any. + */ + public abstract CompoundTag getMultiblockSaveData(); + + /** + * Called after a block is added and the controller has incorporated the + * part's saved multiblock game-data into itself. Generally, you should + * clear the saved data here. + */ + public abstract void onMultiblockDataAssimilated(); + + public abstract BlockState getCachedState(); + + public boolean isInvalid() { + return false; + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockBlockEntityBase.java b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockBlockEntityBase.java new file mode 100644 index 000000000..93d8710e5 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockBlockEntityBase.java @@ -0,0 +1,369 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.network.packet.s2c.play.BlockEntityUpdateS2CPacket; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Tickable; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import reborncore.RebornCore; +import reborncore.api.blockentity.UnloadHandler; + +import java.util.ArrayList; +import java.util.HashSet; +import java.util.List; +import java.util.Set; + +/** + * Base logic class for Multiblock-connected blockEntity entities. Most multiblock + * machines should derive from this and implement their game logic in certain + * abstract methods. + */ +public abstract class MultiblockBlockEntityBase extends IMultiblockPart implements Tickable, UnloadHandler { + private MultiblockControllerBase controller; + private boolean visited; + + private boolean saveMultiblockData; + private CompoundTag cachedMultiblockData; + //private boolean paused; + + public MultiblockBlockEntityBase(BlockEntityType tBlockEntityType) { + super(tBlockEntityType); + controller = null; + visited = false; + saveMultiblockData = false; + //paused = false; + cachedMultiblockData = null; + } + + // /// Multiblock Connection Base Logic + @Override + public Set attachToNeighbors() { + Set controllers = null; + MultiblockControllerBase bestController = null; + + // Look for a compatible controller in our neighboring parts. + IMultiblockPart[] partsToCheck = getNeighboringParts(); + for (IMultiblockPart neighborPart : partsToCheck) { + if (neighborPart.isConnected()) { + MultiblockControllerBase candidate = neighborPart.getMultiblockController(); + if (!candidate.getClass().equals(this.getMultiblockControllerType())) { + // Skip multiblocks with incompatible types + continue; + } + + if (controllers == null) { + controllers = new HashSet(); + bestController = candidate; + } else if (!controllers.contains(candidate) && candidate.shouldConsume(bestController)) { + bestController = candidate; + } + + controllers.add(candidate); + } + } + + // If we've located a valid neighboring controller, attach to it. + if (bestController != null) { + // attachBlock will call onAttached, which will set the controller. + this.controller = bestController; + bestController.attachBlock(this); + } + + return controllers; + } + + @Override + public void assertDetached() { + if (this.controller != null) { + RebornCore.LOGGER.info( + String.format("[assert] Part @ (%d, %d, %d) should be detached already, but detected that it was not. This is not a fatal error, and will be repaired, but is unusual.", + getPos().getX(), getPos().getY(), getPos().getZ())); + this.controller = null; + } + } + + // /// Overrides from base BlockEntity methods + + @Override + public void fromTag(BlockState blockState, CompoundTag data) { + super.fromTag(blockState, data); + + // We can't directly initialize a multiblock controller yet, so we cache + // the data here until + // we receive a validate() call, which creates the controller and hands + // off the cached data. + if (data.contains("multiblockData")) { + this.cachedMultiblockData = data.getCompound("multiblockData"); + } + } + + @Override + public CompoundTag toTag(CompoundTag data) { + super.toTag(data); + + if (isMultiblockSaveDelegate() && isConnected()) { + CompoundTag multiblockData = new CompoundTag(); + this.controller.write(multiblockData); + data.put("multiblockData", multiblockData); + } + return data; + } + + @Override + public void markRemoved() { + detachSelf(false); + super.markRemoved(); + } + + /** + * Called from Minecraft's blockEntity entity loop, after all blockEntity entities have + * been ticked, as the chunk in which this blockEntity entity is contained is + * unloading. + * + */ + @Override + public void onUnload() { + detachSelf(true); + } + + /** + * This is called when a block is being marked as valid by the chunk, but + * has not yet fully been placed into the world's BlockEntity cache. + * this.worldObj, xCoord, yCoord and zCoord have been initialized, but any + * attempts to read data about the world can cause infinite loops - if you + * call getBlockEntity on this BlockEntity's coordinate from within + * validate(), you will blow your call stack. + *

+ * TL;DR: Here there be dragons. + * + */ + @Override + public void cancelRemoval() { + super.cancelRemoval(); + MultiblockRegistry.onPartAdded(this.getWorld(), this); + } + + // Network Communication + @Override + public BlockEntityUpdateS2CPacket toUpdatePacket() { + CompoundTag packetData = new CompoundTag(); + encodeDescriptionPacket(packetData); + return new BlockEntityUpdateS2CPacket(getPos(), 0, packetData); + } + + // /// Things to override in most implementations (IMultiblockPart) + + /** + * Override this to easily modify the description packet's data without + * having to worry about sending the packet itself. Decode this data in + * decodeDescriptionPacket. + * + * @param packetData An NBT compound tag into which you should write your custom + * description data. + */ + protected void encodeDescriptionPacket(CompoundTag packetData) { + if (this.isMultiblockSaveDelegate() && isConnected()) { + CompoundTag tag = new CompoundTag(); + getMultiblockController().formatDescriptionPacket(tag); + packetData.put("multiblockData", tag); + } + } + + /** + * Override this to easily read in data from a BlockEntity's description + * packet. Encoded in encodeDescriptionPacket. + * + * @param packetData The NBT data from the blockEntity entity's description packet. + */ + protected void decodeDescriptionPacket(CompoundTag packetData) { + if (packetData.contains("multiblockData")) { + CompoundTag tag = packetData.getCompound("multiblockData"); + if (isConnected()) { + getMultiblockController().decodeDescriptionPacket(tag); + } else { + // This part hasn't been added to a machine yet, so cache the data. + this.cachedMultiblockData = tag; + } + } + } + + @Override + public boolean hasMultiblockSaveData() { + return this.cachedMultiblockData != null; + } + + @Override + public CompoundTag getMultiblockSaveData() { + return this.cachedMultiblockData; + } + + @Override + public void onMultiblockDataAssimilated() { + this.cachedMultiblockData = null; + } + + // /// Game logic callbacks (IMultiblockPart) + + @Override + public abstract void onMachineAssembled(MultiblockControllerBase multiblockControllerBase); + + @Override + public abstract void onMachineBroken(); + + @Override + public abstract void onMachineActivated(); + + @Override + public abstract void onMachineDeactivated(); + + // /// Miscellaneous multiblock-assembly callbacks and support methods + // (IMultiblockPart) + + @Override + public boolean isConnected() { + return (controller != null); + } + + @Override + public MultiblockControllerBase getMultiblockController() { + return controller; + } + + @Override + public BlockPos getWorldLocation() { + return this.getPos(); + } + + @Override + public void becomeMultiblockSaveDelegate() { + this.saveMultiblockData = true; + } + + @Override + public void forfeitMultiblockSaveDelegate() { + this.saveMultiblockData = false; + } + + @Override + public boolean isMultiblockSaveDelegate() { + return this.saveMultiblockData; + } + + @Override + public void setUnvisited() { + this.visited = false; + } + + @Override + public void setVisited() { + this.visited = true; + } + + @Override + public boolean isVisited() { + return this.visited; + } + + @Override + public void onAssimilated(MultiblockControllerBase newController) { + assert (this.controller != newController); + this.controller = newController; + } + + @Override + public void onAttached(MultiblockControllerBase newController) { + this.controller = newController; + } + + @Override + public void onDetached(MultiblockControllerBase oldController) { + this.controller = null; + } + + @Override + public abstract MultiblockControllerBase createNewMultiblock(); + + @Override + public IMultiblockPart[] getNeighboringParts() { + BlockEntity te; + List neighborParts = new ArrayList(); + BlockPos neighborPosition, partPosition = this.getWorldLocation(); + + for (Direction facing : Direction.values()) { + + neighborPosition = partPosition.offset(facing); + te = this.world.getBlockEntity(neighborPosition); + + if (te instanceof IMultiblockPart) { + neighborParts.add((IMultiblockPart) te); + } + } + + return neighborParts.toArray(new IMultiblockPart[neighborParts.size()]); + } + + @Override + public void onOrphaned(MultiblockControllerBase controller, int oldSize, int newSize) { + this.markDirty(); + getWorld().markDirty(getPos(), this); + } + + // // Helper functions for notifying neighboring blocks + protected void notifyNeighborsOfBlockChange() { + world.updateNeighborsAlways(getPos(), getCachedState().getBlock()); + } + + protected void notifyNeighborsOfBlockEntityChange() { + world.updateNeighborsAlways(getPos(), getCachedState().getBlock()); + } + + // /// Private/Protected Logic Helpers + /* + * Detaches this block from its controller. Calls detachBlock() and clears + * the controller member. + */ + protected void detachSelf(boolean chunkUnloading) { + if (this.controller != null) { + // Clean part out of controller + this.controller.detachBlock(this, chunkUnloading); + + // The above should call onDetached, but, just in case... + this.controller = null; + } + + // Clean part out of lists in the registry + MultiblockRegistry.onPartRemovedFromWorld(getWorld(), this); + } + + @Override + public BlockState getCachedState() { + return world.getBlockState(pos); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockControllerBase.java b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockControllerBase.java new file mode 100644 index 000000000..3b60a459e --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockControllerBase.java @@ -0,0 +1,1079 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.WorldChunk; +import reborncore.RebornCore; +import reborncore.common.util.WorldUtils; + +import java.util.HashSet; +import java.util.LinkedList; +import java.util.Set; + +/** + * This class contains the base logic for "multiblock controllers". + * Conceptually, they are meta-TileEntities. They govern the logic for an + * associated group of TileEntities. + *

+ * Subordinate TileEntities implement the IMultiblockPart class and, generally, + * should not have an update() loop. + */ +public abstract class MultiblockControllerBase { + public static final short DIMENSION_UNBOUNDED = -1; + + // Multiblock stuff - do not mess with + protected World worldObj; + + // Disassembled -> Assembled; Assembled -> Disassembled OR Paused; Paused -> + // Assembled + protected enum AssemblyState { + Disassembled, Assembled, Paused + } + + ; + protected AssemblyState assemblyState; + + public HashSet connectedParts; + + /** + * This is a deterministically-picked coordinate that identifies this + * multiblock uniquely in its dimension. Currently, this is the coord with + * the lowest X, Y and Z coordinates, in that order of evaluation. i.e. If + * something has a lower X but higher Y/Z coordinates, it will still be the + * reference. If something has the same X but a lower Y coordinate, it will + * be the reference. Etc. + */ + private BlockPos referenceCoord; + + /** + * Minimum bounding box coordinate. Blocks do not necessarily exist at this + * coord if your machine is not a cube/rectangular prism. + */ + private BlockPos minimumCoord; + + /** + * Maximum bounding box coordinate. Blocks do not necessarily exist at this + * coord if your machine is not a cube/rectangular prism. + */ + private BlockPos maximumCoord; + + /** + * Set to true whenever a part is removed from this controller. + */ + private boolean shouldCheckForDisconnections; + + /** + * Set whenever we validate the multiblock + */ + private MultiblockValidationException lastValidationException; + + protected boolean debugMode; + + protected MultiblockControllerBase(World world) { + // Multiblock stuff + worldObj = world; + connectedParts = new HashSet(); + + referenceCoord = null; + assemblyState = AssemblyState.Disassembled; + + minimumCoord = null; + maximumCoord = null; + + shouldCheckForDisconnections = true; + lastValidationException = null; + + debugMode = false; + } + + public void setDebugMode(boolean active) { + debugMode = active; + } + + public boolean isDebugMode() { + return debugMode; + } + + /** + * Call when a block with cached save-delegate data is added to the + * multiblock. The part will be notified that the data has been used after + * this call completes. + * + * @param part Attached part + * @param data The NBT tag containing this controller's data. + */ + public abstract void onAttachedPartWithMultiblockData(IMultiblockPart part, CompoundTag data); + + /** + * Check if a block is being tracked by this machine. + * + * @param blockCoord Coordinate to check. + * @return True if the blockEntity entity at blockCoord is being tracked by this + * machine, false otherwise. + */ + public boolean hasBlock(BlockPos blockCoord) { + return connectedParts.contains(blockCoord); + } + + /** + * Attach a new part to this machine. + * + * @param part The part to add. + */ + public void attachBlock(IMultiblockPart part) { + //IMultiblockPart candidate; + BlockPos coord = part.getWorldLocation(); + + if (!connectedParts.add(part)) { + RebornCore.LOGGER.warn( + String.format("[%s] Controller %s is double-adding part %d @ %s. This is unusual. If you encounter odd behavior, please tear down the machine and rebuild it.", + (worldObj.isClient ? "CLIENT" : "SERVER"), hashCode(), part.hashCode(), coord)); + } + + part.onAttached(this); + this.onBlockAdded(part); + + if (part.hasMultiblockSaveData()) { + CompoundTag savedData = part.getMultiblockSaveData(); + onAttachedPartWithMultiblockData(part, savedData); + part.onMultiblockDataAssimilated(); + } + + if (this.referenceCoord == null) { + referenceCoord = coord; + part.becomeMultiblockSaveDelegate(); + } else if (coord.compareTo(referenceCoord) < 0) { + BlockEntity te = this.worldObj.getBlockEntity(referenceCoord); + ((IMultiblockPart) te).forfeitMultiblockSaveDelegate(); + + referenceCoord = coord; + part.becomeMultiblockSaveDelegate(); + } else { + part.forfeitMultiblockSaveDelegate(); + } + + Boolean updateRequired = false; + BlockPos partPos = part.getPos(); + + if (minimumCoord != null) { + + if (partPos.getX() < minimumCoord.getX()) { + updateRequired = true; + } + if (partPos.getY() < minimumCoord.getY()) { + updateRequired = true; + } + if (partPos.getZ() < minimumCoord.getZ()) { + updateRequired = true; + } + if (updateRequired) { + this.minimumCoord = new BlockPos(partPos.getX(), partPos.getY(), partPos.getZ()); + } + } + + if (maximumCoord != null) { + if (partPos.getX() > maximumCoord.getX()) { + updateRequired = true; + } + if (partPos.getY() > maximumCoord.getY()) { + updateRequired = true; + } + if (partPos.getZ() > maximumCoord.getZ()) { + updateRequired = true; + } + if (updateRequired) { + this.maximumCoord = new BlockPos(partPos.getX(), partPos.getY(), partPos.getZ()); + } + } + + MultiblockRegistry.addDirtyController(worldObj, this); + } + + /** + * Called when a new part is added to the machine. Good time to register + * things into lists. + * + * @param newPart The part being added. + */ + protected abstract void onBlockAdded(IMultiblockPart newPart); + + /** + * Called when a part is removed from the machine. Good time to clean up + * lists. + * + * @param oldPart The part being removed. + */ + protected abstract void onBlockRemoved(IMultiblockPart oldPart); + + /** + * Called when a machine is assembled from a disassembled state. + */ + protected abstract void onMachineAssembled(); + + /** + * Called when a machine is restored to the assembled state from a paused + * state. + */ + protected abstract void onMachineRestored(); + + /** + * Called when a machine is paused from an assembled state This generally + * only happens due to chunk-loads and other "system" events. + */ + protected abstract void onMachinePaused(); + + /** + * Called when a machine is disassembled from an assembled state. This + * happens due to user or in-game actions (e.g. explosions) + */ + protected abstract void onMachineDisassembled(); + + /** + * Callback whenever a part is removed (or will very shortly be removed) + * from a controller. Do housekeeping/callbacks, also nulls min/max coords. + * + * @param part The part being removed. + */ + private void onDetachBlock(IMultiblockPart part) { + // Strip out this part + part.onDetached(this); + this.onBlockRemoved(part); + part.forfeitMultiblockSaveDelegate(); + + minimumCoord = maximumCoord = null; + + if (referenceCoord != null && referenceCoord.equals(part.getPos())) { + referenceCoord = null; + } + + shouldCheckForDisconnections = true; + } + + /** + * Call to detach a block from this machine. Generally, this should be + * called when the blockEntity entity is being released, e.g. on block destruction. + * + * @param part The part to detach from this machine. + * @param chunkUnloading Is this entity detaching due to the chunk unloading? If true, + * the multiblock will be paused instead of broken. + */ + public void detachBlock(IMultiblockPart part, boolean chunkUnloading) { + if (chunkUnloading && this.assemblyState == AssemblyState.Assembled) { + this.assemblyState = AssemblyState.Paused; + this.onMachinePaused(); + } + + // Strip out this part + onDetachBlock(part); + if (!connectedParts.remove(part)) { + RebornCore.LOGGER.warn( + String.format("[%s] Double-removing part (%d) @ %d, %d, %d, this is unexpected and may cause problems. If you encounter anomalies, please tear down the reactor and rebuild it.", + worldObj.isClient ? "CLIENT" : "SERVER", part.hashCode(), part.getPos().getX(), + part.getPos().getY(), part.getPos().getZ())); + } + + if (connectedParts.isEmpty()) { + // Destroy/unregister + MultiblockRegistry.addDeadController(this.worldObj, this); + return; + } + + MultiblockRegistry.addDirtyController(this.worldObj, this); + + // Find new save delegate if we need to. + if (referenceCoord == null) { + selectNewReferenceCoord(); + } + } + + /** + * Helper method so we don't check for a whole machine until we have enough + * blocks to actually assemble it. This isn't as simple as xmax*ymax*zmax + * for non-cubic machines or for machines with hollow/complex interiors. + * + * @return The minimum number of blocks connected to the machine for it to + * be assembled. + */ + protected abstract int getMinimumNumberOfBlocksForAssembledMachine(); + + /** + * Returns the maximum X dimension size of the machine, or -1 + * (DIMENSION_UNBOUNDED) to disable dimension checking in X. (This is not + * recommended.) + * + * @return The maximum X dimension size of the machine, or -1 + */ + protected abstract int getMaximumXSize(); + + /** + * Returns the maximum Z dimension size of the machine, or -1 + * (DIMENSION_UNBOUNDED) to disable dimension checking in X. (This is not + * recommended.) + * + * @return The maximum Z dimension size of the machine, or -1 + */ + protected abstract int getMaximumZSize(); + + /** + * Returns the maximum Y dimension size of the machine, or -1 + * (DIMENSION_UNBOUNDED) to disable dimension checking in X. (This is not + * recommended.) + * + * @return The maximum Y dimension size of the machine, or -1 + */ + protected abstract int getMaximumYSize(); + + /** + * Returns the minimum X dimension size of the machine. Must be at least 1, + * because nothing else makes sense. + * + * @return The minimum X dimension size of the machine + */ + protected int getMinimumXSize() { + return 1; + } + + /** + * Returns the minimum Y dimension size of the machine. Must be at least 1, + * because nothing else makes sense. + * + * @return The minimum Y dimension size of the machine + */ + protected int getMinimumYSize() { + return 1; + } + + /** + * Returns the minimum Z dimension size of the machine. Must be at least 1, + * because nothing else makes sense. + * + * @return The minimum Z dimension size of the machine + */ + protected int getMinimumZSize() { + return 1; + } + + /** + * @return An exception representing the last error encountered when trying + * to assemble this multiblock, or null if there is no error. + */ + public MultiblockValidationException getLastValidationException() { + return lastValidationException; + } + + /** + * Checks if a machine is whole. If not, throws an exception with the reason + * why. + */ + protected abstract void isMachineWhole() throws MultiblockValidationException; + + /** + * Check if the machine is whole or not. If the machine was not whole, but + * now is, assemble the machine. If the machine was whole, but no longer is, + * disassemble the machine. + * + * @return + */ + public void checkIfMachineIsWhole() { + AssemblyState oldState = this.assemblyState; + boolean isWhole; + this.lastValidationException = null; + try { + isMachineWhole(); + isWhole = true; + } catch (MultiblockValidationException e) { + lastValidationException = e; + isWhole = false; + } + + if (isWhole) { + // This will alter assembly state + assembleMachine(oldState); + } else if (oldState == AssemblyState.Assembled) { + // This will alter assembly state + disassembleMachine(); + } + // Else Paused, do nothing + } + + /** + * Called when a machine becomes "whole" and should begin functioning as a + * game-logically finished machine. Calls onMachineAssembled on all attached + * parts. + */ + private void assembleMachine(AssemblyState oldState) { + for (IMultiblockPart part : connectedParts) { + part.onMachineAssembled(this); + } + + this.assemblyState = AssemblyState.Assembled; + if (oldState == AssemblyState.Paused) { + onMachineRestored(); + } else { + onMachineAssembled(); + } + } + + /** + * Called when the machine needs to be disassembled. It is not longer + * "whole" and should not be functional, usually as a result of a block + * being removed. Calls onMachineBroken on all attached parts. + */ + private void disassembleMachine() { + for (IMultiblockPart part : connectedParts) { + part.onMachineBroken(); + } + + this.assemblyState = AssemblyState.Disassembled; + onMachineDisassembled(); + } + + /** + * Assimilate another controller into this controller. Acquire all of the + * other controller's blocks and attach them to this one. + * + * @param other The controller to merge into this one. + */ + public void assimilate(MultiblockControllerBase other) { + BlockPos otherReferenceCoord = other.getReferenceCoord(); + if (otherReferenceCoord != null && getReferenceCoord().compareTo(otherReferenceCoord) >= 0) { + throw new IllegalArgumentException( + "The controller with the lowest minimum-coord value must consume the one with the higher coords"); + } + + Set partsToAcquire = new HashSet(other.connectedParts); + + // releases all blocks and references gently so they can be incorporated into another multiblock + other._onAssimilated(this); + + for (IMultiblockPart acquiredPart : partsToAcquire) { + // By definition, none of these can be the minimum block. + if (acquiredPart.isInvalid()) { + continue; + } + + connectedParts.add(acquiredPart); + acquiredPart.onAssimilated(this); + this.onBlockAdded(acquiredPart); + } + + this.onAssimilate(other); + other.onAssimilated(this); + } + + /** + * Called when this machine is consumed by another controller. Essentially, + * forcibly tear down this object. + * + * @param otherController The controller consuming this controller. + */ + private void _onAssimilated(MultiblockControllerBase otherController) { + if (referenceCoord != null) { + if (this.worldObj.isChunkLoaded(this.referenceCoord)) { + BlockEntity te = this.worldObj.getBlockEntity(referenceCoord); + if (te instanceof IMultiblockPart) { + ((IMultiblockPart) te).forfeitMultiblockSaveDelegate(); + } + } + this.referenceCoord = null; + } + connectedParts.clear(); + } + + /** + * Callback. Called after this controller assimilates all the blocks from + * another controller. Use this to absorb that controller's game data. + * + * @param assimilated The controller whose uniqueness was added to our own. + */ + protected abstract void onAssimilate(MultiblockControllerBase assimilated); + + /** + * Callback. Called after this controller is assimilated into another + * controller. All blocks have been stripped out of this object and handed + * over to the other controller. This is intended primarily for cleanup. + * + * @param assimilator The controller which has assimilated this controller. + */ + protected abstract void onAssimilated(MultiblockControllerBase assimilator); + + /** + * Driver for the update loop. If the machine is assembled, runs the game + * logic update method. + */ + public final void updateMultiblockEntity() { + if (connectedParts.isEmpty()) { + // This shouldn't happen, but just in case... + MultiblockRegistry.addDeadController(this.worldObj, this); + return; + } + + if (this.assemblyState != AssemblyState.Assembled) { + // Not assembled - don't run game logic + return; + } + + if (worldObj.isClient) { + updateClient(); + } else if (updateServer()) { + // If this returns true, the server has changed its internal data. + // If our chunks are loaded (they should be), we must mark our + // chunks as dirty. + if (minimumCoord != null && maximumCoord != null + && this.worldObj.isRegionLoaded(this.minimumCoord, this.maximumCoord)) { + int minChunkX = minimumCoord.getX() >> 4; + int minChunkZ = minimumCoord.getZ() >> 4; + int maxChunkX = maximumCoord.getX() >> 4; + int maxChunkZ = maximumCoord.getZ() >> 4; + + for (int x = minChunkX; x <= maxChunkX; x++) { + for (int z = minChunkZ; z <= maxChunkZ; z++) { + // Ensure that we save our data, even if the our save + // delegate is in has no TEs. + WorldChunk chunkToSave = this.worldObj.getChunk(x, z); + chunkToSave.markDirty(); + } + } + } + } + // Else: Server, but no need to save data. + } + + /** + * The server-side update loop! Use this similarly to a BlockEntity's update + * loop. You do not need to call your superclass' update() if you're + * directly derived from MultiblockControllerBase. This is a callback. Note + * that this will only be called when the machine is assembled. + * + * @return True if the multiblock should save data, i.e. its internal game + * state has changed. False otherwise. + */ + protected abstract boolean updateServer(); + + /** + * Client-side update loop. Generally, this shouldn't do anything, but if + * you want to do some interpolation or something, do it here. + */ + protected abstract void updateClient(); + + // Validation helpers + + /** + * The "frame" consists of the outer edges of the machine, plus the corners. + * + * @param world World object for the world in which this controller is + * located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's frame + */ + protected void isBlockGoodForFrame(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The top consists of the top face, minus the edges. + * + * @param world World object for the world in which this controller is + * located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's top face + */ + protected void isBlockGoodForTop(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The bottom consists of the bottom face, minus the edges. + * + * @param world World object for the world in which this controller is + * located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's bottom + * face + */ + protected void isBlockGoodForBottom(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The sides consists of the N/E/S/W-facing faces, minus the edges. + * + * @param world World object for the world in which this controller is + * located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed on the machine's side + * faces + */ + protected void isBlockGoodForSides(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * The interior is any block that does not touch blocks outside the machine. + * + * @param world World object for the world in which this controller is + * located. + * @param x X coordinate of the block being tested + * @param y Y coordinate of the block being tested + * @param z Z coordinate of the block being tested + * @throws MultiblockValidationException if the tested block is not allowed in the machine's interior + */ + protected void isBlockGoodForInterior(World world, int x, int y, int z) throws MultiblockValidationException { + throw new MultiblockValidationException( + String.format("%d, %d, %d - Block is not valid for use in the machine's interior", x, y, z)); + } + + /** + * @return The reference coordinate, the block with the lowest x, y, z + * coordinates, evaluated in that order. + */ + public BlockPos getReferenceCoord() { + if (referenceCoord == null) { + selectNewReferenceCoord(); + } + return referenceCoord; + } + + /** + * @return The number of blocks connected to this controller. + */ + public int getNumConnectedBlocks() { + return connectedParts.size(); + } + + public abstract void write(CompoundTag data); + + public abstract void read(CompoundTag data); + + /** + * Force this multiblock to recalculate its minimum and maximum coordinates + * from the list of connected parts. + */ + public void recalculateMinMaxCoords() { + Integer minX, minY, minZ; + Integer maxX, maxY, maxZ; + minX = minY = minZ = Integer.MAX_VALUE; + maxX = maxY = maxZ = Integer.MIN_VALUE; + + for (IMultiblockPart part : connectedParts) { + BlockPos pos = part.getPos(); + if (pos.getX() < minX) { + minX = pos.getX(); + } + if (pos.getX() > maxX) { + maxX = pos.getX(); + } + if (pos.getY() < minY) { + minY = pos.getY(); + } + if (pos.getY() > maxY) { + maxY = pos.getY(); + } + if (pos.getZ() < minZ) { + minZ = pos.getZ(); + } + if (pos.getZ() > maxZ) { + maxZ = pos.getZ(); + } + } + this.minimumCoord = new BlockPos(minX, minY, minZ); + this.maximumCoord = new BlockPos(maxX, maxY, maxZ); + } + + /** + * @return The minimum bounding-box coordinate containing this machine's + * blocks. + */ + public BlockPos getMinimumCoord() { + if (minimumCoord == null) { + recalculateMinMaxCoords(); + } + return minimumCoord; + } + + /** + * @return The maximum bounding-box coordinate containing this machine's + * blocks. + */ + public BlockPos getMaximumCoord() { + if (maximumCoord == null) { + recalculateMinMaxCoords(); + } + return maximumCoord; + } + + /** + * Called when the save delegate's blockEntity entity is being asked for its + * description packet + * + * @param data A fresh compound tag to write your multiblock data into + */ + public abstract void formatDescriptionPacket(CompoundTag data); + + /** + * Called when the save delegate's blockEntity entity receiving a description + * packet + * + * @param data A compound tag containing multiblock data to import + */ + public abstract void decodeDescriptionPacket(CompoundTag data); + + /** + * @return True if this controller has no associated blocks, false otherwise + */ + public boolean isEmpty() { + return connectedParts.isEmpty(); + } + + /** + * Tests whether this multiblock should consume the other multiblock and + * become the new multiblock master when the two multiblocks are adjacent. + * Assumes both multiblocks are the same type. + * + * @param otherController The other multiblock controller. + * @return True if this multiblock should consume the other, false + * otherwise. + */ + public boolean shouldConsume(MultiblockControllerBase otherController) { + if (!otherController.getClass().equals(getClass())) { + throw new IllegalArgumentException( + "Attempting to merge two multiblocks with different master classes - this should never happen!"); + } + + if (otherController == this) { + return false; + } // Don't be silly, don't eat yourself. + + int res = _shouldConsume(otherController); + if (res < 0) { + return true; + } else if (res > 0) { + return false; + } else { + // Strip dead parts from both and retry + RebornCore.LOGGER.warn( + String.format("[%s] Encountered two controllers with the same reference coordinate. Auditing connected parts and retrying.", + worldObj.isClient ? "CLIENT" : "SERVER")); + auditParts(); + otherController.auditParts(); + + res = _shouldConsume(otherController); + if (res < 0) { + return true; + } else if (res > 0) { + return false; + } else { + RebornCore.LOGGER.error(String.format("My Controller (%d): size (%d), parts: %s", hashCode(), connectedParts.size(), + getPartsListString())); + RebornCore.LOGGER.error(String.format("Other Controller (%d): size (%d), coords: %s", otherController.hashCode(), + otherController.connectedParts.size(), otherController.getPartsListString())); + throw new IllegalArgumentException("[" + (worldObj.isClient ? "CLIENT" : "SERVER") + + "] Two controllers with the same reference coord that somehow both have valid parts - this should never happen!"); + } + + } + } + + private int _shouldConsume(MultiblockControllerBase otherController) { + BlockPos myCoord = getReferenceCoord(); + BlockPos theirCoord = otherController.getReferenceCoord(); + + // Always consume other controllers if their reference coordinate is + // null - this means they're empty and can be assimilated on the cheap + if (theirCoord == null) { + return -1; + } else { + return myCoord.compareTo(theirCoord); + } + } + + private String getPartsListString() { + StringBuilder sb = new StringBuilder(); + boolean first = true; + for (IMultiblockPart part : connectedParts) { + if (!first) { + sb.append(", "); + } + sb.append(String.format("(%d: %d, %d, %d)", part.hashCode(), part.getPos().getX(), part.getPos().getY(), + part.getPos().getZ())); + first = false; + } + + return sb.toString(); + } + + /** + * Checks all of the parts in the controller. If any are dead or do not + * exist in the world, they are removed. + */ + private void auditParts() { + HashSet deadParts = new HashSet(); + for (IMultiblockPart part : connectedParts) { + if (part.isInvalid() || worldObj.getBlockEntity(part.getPos()) != part) { + onDetachBlock(part); + deadParts.add(part); + } + } + + connectedParts.removeAll(deadParts); + RebornCore.LOGGER.warn(String.format("[%s] Controller found %d dead parts during an audit, %d parts remain attached", + worldObj.isClient ? "CLIENT" : "SERVER", deadParts.size(), connectedParts.size())); + } + + /** + * Called when this machine may need to check for blocks that are no longer + * physically connected to the reference coordinate. + * + * @return + */ + public Set checkForDisconnections() { + if (!this.shouldCheckForDisconnections) { + return null; + } + + if (this.isEmpty()) { + MultiblockRegistry.addDeadController(worldObj, this); + return null; + } + + // Invalidate our reference coord, we'll recalculate it shortly + referenceCoord = null; + + // Reset visitations and find the minimum coordinate + Set deadParts = new HashSet(); + BlockPos pos; + IMultiblockPart referencePart = null; + + int originalSize = connectedParts.size(); + + for (IMultiblockPart part : connectedParts) { + pos = part.getWorldLocation(); + if (!this.worldObj.isChunkLoaded(pos) || part.isInvalid()) { + deadParts.add(part); + onDetachBlock(part); + continue; + } + + if (worldObj.getBlockEntity(pos) != part) { + deadParts.add(part); + onDetachBlock(part); + continue; + } + + part.setUnvisited(); + part.forfeitMultiblockSaveDelegate(); + + if (referenceCoord == null) { + referenceCoord = pos; + referencePart = part; + } else if (pos.compareTo(referenceCoord) < 0) { + referenceCoord = pos; + referencePart = part; + } + } + + connectedParts.removeAll(deadParts); + deadParts.clear(); + + if (referencePart == null || isEmpty()) { + // There are no valid parts remaining. The entire multiblock was + // unloaded during a chunk unload. Halt. + shouldCheckForDisconnections = false; + MultiblockRegistry.addDeadController(worldObj, this); + return null; + } else { + referencePart.becomeMultiblockSaveDelegate(); + } + + // Now visit all connected parts, breadth-first, starting from reference + // coord's part + IMultiblockPart part; + LinkedList partsToCheck = new LinkedList(); + IMultiblockPart[] nearbyParts = null; + int visitedParts = 0; + + partsToCheck.add(referencePart); + + while (!partsToCheck.isEmpty()) { + part = partsToCheck.removeFirst(); + part.setVisited(); + visitedParts++; + + // Chunk-safe on server, but not on client + nearbyParts = part.getNeighboringParts(); + for (IMultiblockPart nearbyPart : nearbyParts) { + // Ignore different machines + if (nearbyPart.getMultiblockController() != this) { + continue; + } + + if (!nearbyPart.isVisited()) { + nearbyPart.setVisited(); + partsToCheck.add(nearbyPart); + } + } + } + + // Finally, remove all parts that remain disconnected. + Set removedParts = new HashSet(); + for (IMultiblockPart orphanCandidate : connectedParts) { + if (!orphanCandidate.isVisited()) { + deadParts.add(orphanCandidate); + orphanCandidate.onOrphaned(this, originalSize, visitedParts); + onDetachBlock(orphanCandidate); + removedParts.add(orphanCandidate); + } + } + + // Trim any blocks that were invalid, or were removed. + connectedParts.removeAll(deadParts); + + // Cleanup. Not necessary, really. + deadParts.clear(); + + // Juuuust in case. + if (referenceCoord == null) { + selectNewReferenceCoord(); + } + + // We've run the checks from here on out. + shouldCheckForDisconnections = false; + + return removedParts; + } + + /** + * Detach all parts. Return a set of all parts which still have a valid blockEntity + * entity. Chunk-safe. + * + * @return A set of all parts which still have a valid blockEntity entity. + */ + public Set detachAllBlocks() { + if (worldObj == null) { + return new HashSet(); + } + + for (IMultiblockPart part : connectedParts) { + if (this.worldObj.isChunkLoaded(part.getWorldLocation())) { + onDetachBlock(part); + } + } + + Set detachedParts = connectedParts; + connectedParts = new HashSet(); + return detachedParts; + } + + /** + * @return True if this multiblock machine is considered assembled and ready + * to go. + */ + public boolean isAssembled() { + return this.assemblyState == AssemblyState.Assembled; + } + + private void selectNewReferenceCoord() { + IMultiblockPart theChosenOne = null; + BlockPos pos; + referenceCoord = null; + + for (IMultiblockPart part : connectedParts) { + pos = part.getWorldLocation(); + if (part.isInvalid() || !this.worldObj.isChunkLoaded(pos)) { + // Chunk is unloading, skip this coord to prevent chunk thrashing + continue; + } + + if (referenceCoord == null || referenceCoord.compareTo(pos) > 0) { + referenceCoord = pos; + theChosenOne = part; + } + } + + if (theChosenOne != null) { + theChosenOne.becomeMultiblockSaveDelegate(); + } + } + + /** + * Marks the reference coord dirty & updateable. + *

+ * On the server, this will mark the for a data-update, so that nearby + * clients will receive an updated description packet from the server after + * a short time. The block's chunk will also be marked dirty and the block's + * chunk will be saved to disk the next time chunks are saved. + *

+ * On the client, this will mark the block for a rendering update. + */ + protected void markReferenceCoordForUpdate() { + BlockPos rc = getReferenceCoord(); + if (worldObj != null && rc != null) { + //TO-DO Change to notifyBlockUpdate, probably + WorldUtils.updateBlock(worldObj, rc); + } + } + + /** + * Marks the reference coord dirty. + *

+ * On the server, this marks the reference coord's chunk as dirty; the block + * (and chunk) will be saved to disk the next time chunks are saved. This + * does NOT mark it dirty for a description-packet update. + *

+ * On the client, does nothing. + * + * @see MultiblockControllerBase#markReferenceCoordForUpdate() + */ + protected void markReferenceCoordDirty() { + if (worldObj == null || worldObj.isClient) { + return; + } + + BlockPos referenceCoord = getReferenceCoord(); + if (referenceCoord == null) { + return; + } + + BlockEntity saveTe = worldObj.getBlockEntity(referenceCoord); + worldObj.markDirty(referenceCoord, saveTe); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockEventHandler.java b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockEventHandler.java new file mode 100644 index 000000000..87f3093f9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockEventHandler.java @@ -0,0 +1,46 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +/** + * In your mod, subscribe this on both the client and server sides side to + * handle chunk load events for your multiblock machines. Chunks can load + * asynchronously in environments like MCPC+, so we cannot behavior any blocks + * that are in chunks which are still loading. + */ +public class MultiblockEventHandler { + + //TODO mixins needed for this +// public void onChunkLoad(ChunkEvent.Load loadEvent) { +// Chunk chunk = loadEvent.getChunk(); +// IWorld world = loadEvent.getWorld(); +// MultiblockRegistry.onChunkLoaded(world, chunk); +// } +// +// +// public void onWorldUnload(WorldEvent.Unload unloadWorldEvent) { +// MultiblockRegistry.onWorldUnloaded(unloadWorldEvent.getWorld()); +// } +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockRegistry.java b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockRegistry.java new file mode 100644 index 000000000..da9e2afda --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockRegistry.java @@ -0,0 +1,163 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import reborncore.RebornCore; + +import java.util.HashMap; +import java.util.Set; + +/** + * This is a very static singleton registry class which directs incoming events + * to sub-objects, which actually manage each individual world's multiblocks. + * + * @author Erogenous Beef + */ +public class MultiblockRegistry { + // World > WorldRegistry map + private static HashMap registries = new HashMap<>(); + + /** + * Called before Tile Entities are ticked in the world. Do bookkeeping here. + * + * @param world The world being ticked + */ + public static void tickStart(World world) { + if (registries.containsKey(world)) { + MultiblockWorldRegistry registry = registries.get(world); + registry.processMultiblockChanges(); + registry.tickStart(); + } + } + + /** + * Called when the world has finished loading a chunk. + * + * @param world The world which has finished loading a chunk + * @param chunk Loaded chunk + */ + public static void onChunkLoaded(World world, Chunk chunk) { + if (registries.containsKey(world)) { + registries.get(world).onChunkLoaded(chunk); + } + } + + /** + * Register a new part in the system. The part has been created either + * through user action or via a chunk loading. + * + * @param world The world into which this part is loading. + * @param part The part being loaded. + */ + public static void onPartAdded(World world, IMultiblockPart part) { + MultiblockWorldRegistry registry = getOrCreateRegistry(world); + registry.onPartAdded(part); + } + + /** + * Call to remove a part from world lists. + * + * @param world The world from which a multiblock part is being removed. + * @param part The part being removed. + */ + public static void onPartRemovedFromWorld(World world, IMultiblockPart part) { + if (registries.containsKey(world)) { + registries.get(world).onPartRemovedFromWorld(part); + } + + } + + /** + * Called whenever a world is unloaded. Unload the relevant registry, if we + * have one. + * + * @param world The world being unloaded. + */ + public static void onWorldUnloaded(World world) { + if (registries.containsKey(world)) { + registries.get(world).onWorldUnloaded(); + registries.remove(world); + } + } + + /** + * Call to mark a controller as dirty. Dirty means that parts have been + * added or removed this tick. + * + * @param world The world containing the multiblock + * @param controller The dirty controller + */ + public static void addDirtyController(World world, MultiblockControllerBase controller) { + if (registries.containsKey(world)) { + registries.get(world).addDirtyController(controller); + } else { + RebornCore.LOGGER.error("Adding a dirty controller to a world that has no registered controllers! This is most likey not an issue with reborn core, please check the full log file for more infomation!"); + } + } + + /** + * Call to mark a controller as dead. It should only be marked as dead when + * it has no connected parts. It will be removed after the next world tick. + * + * @param world The world formerly containing the multiblock + * @param controller The dead controller + */ + public static void addDeadController(World world, MultiblockControllerBase controller) { + if (registries.containsKey(world)) { + registries.get(world).addDeadController(controller); + } else { + RebornCore.LOGGER.warn(String.format( + "Controller %d in world %s marked as dead, but that world is not tracked! Controller is being ignored.", + controller.hashCode(), world)); + } + } + + /** + * @param world The world whose controllers you wish to retrieve. + * @return An unmodifiable set of controllers active in the given world, or + * null if there are none. + */ + public static Set getControllersFromWorld(World world) { + if (registries.containsKey(world)) { + return registries.get(world).getControllers(); + } + return null; + } + + // / *** PRIVATE HELPERS *** /// + + private static MultiblockWorldRegistry getOrCreateRegistry(World world) { + if (registries.containsKey(world)) { + return registries.get(world); + } else { + MultiblockWorldRegistry newRegistry = new MultiblockWorldRegistry(world); + registries.put(world, newRegistry); + return newRegistry; + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockValidationException.java b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockValidationException.java new file mode 100644 index 000000000..e40e55a0f --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockValidationException.java @@ -0,0 +1,43 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +/** + * An exception thrown when trying to validate a multiblock. Requires a string + * describing why the multiblock could not assemble. + * + * @author Erogenous Beef + */ +public class MultiblockValidationException extends Exception { + + /** + * + */ + private static final long serialVersionUID = -4038176177468678877L; + + public MultiblockValidationException(String reason) { + super(reason); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockWorldRegistry.java b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockWorldRegistry.java new file mode 100644 index 000000000..6cd1d9430 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/MultiblockWorldRegistry.java @@ -0,0 +1,464 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock; + +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.ChunkPos; +import net.minecraft.world.World; +import net.minecraft.world.chunk.Chunk; +import reborncore.RebornCore; + +import java.util.*; + +/** + * This class manages all the multiblock controllers that exist in a given + * world, either client- or server-side. You must create different registries + * for server and client worlds. + * + * @author Erogenous Beef + */ +public class MultiblockWorldRegistry { + + private World worldObj; + + // Active controllers + private Set controllers; + // Controllers whose parts lists have changed + private Set dirtyControllers; + // Controllers which are empty + private Set deadControllers; + + // A list of orphan parts - parts which currently have no master, but should + // seek one this tick + // Indexed by the hashed chunk coordinate + // This can be added-to asynchronously via chunk loads! + private Set orphanedParts; + + // A list of parts which have been detached during internal operations + private Set detachedParts; + + // A list of parts whose chunks have not yet finished loading + // They will be added to the orphan list when they are finished loading. + // Indexed by the hashed chunk coordinate + // This can be added-to asynchronously via chunk loads! + private HashMap> partsAwaitingChunkLoad; + + // Mutexes to protect lists which may be changed due to asynchronous events, + // such as chunk loads + private Object partsAwaitingChunkLoadMutex; + private Object orphanedPartsMutex; + + public MultiblockWorldRegistry(final World world) { + worldObj = world; + + controllers = new HashSet(); + deadControllers = new HashSet(); + dirtyControllers = new HashSet(); + + detachedParts = new HashSet(); + orphanedParts = new HashSet(); + + partsAwaitingChunkLoad = new HashMap>(); + partsAwaitingChunkLoadMutex = new Object(); + orphanedPartsMutex = new Object(); + } + + /** + * Called before Tile Entities are ticked in the world. Run game logic. + */ + public void tickStart() { + if (controllers.size() > 0) { + for (MultiblockControllerBase controller : controllers) { + if (controller.worldObj == worldObj && controller.worldObj.isClient == worldObj.isClient) { + if (controller.isEmpty()) { + // This happens on the server when the user breaks the + // last block. It's fine. + // Mark 'er dead and move on. + deadControllers.add(controller); + } else { + // Run the game logic for this world + controller.updateMultiblockEntity(); + } + } + } + } + } + + /** + * Called prior to processing multiblock controllers. Do bookkeeping. + */ + public void processMultiblockChanges() { + BlockPos coord; + + // Merge pools - sets of adjacent machines which should be merged later + // on in processing + List> mergePools = null; + if (orphanedParts.size() > 0) { + Set orphansToProcess = null; + + // Keep the synchronized block small. We can't iterate over + // orphanedParts directly + // because the client does not know which chunks are actually + // loaded, so attachToNeighbors() + // is not chunk-safe on the client, because Minecraft is stupid. + // It's possible to polyfill this, but the polyfill is too slow for + // comfort. + synchronized (orphanedPartsMutex) { + if (orphanedParts.size() > 0) { + orphansToProcess = orphanedParts; + orphanedParts = new HashSet(); + } + } + + if (orphansToProcess != null && orphansToProcess.size() > 0) { + Set compatibleControllers; + + // Process orphaned blocks + // These are blocks that exist in a valid chunk and require a + // controller + for (IMultiblockPart orphan : orphansToProcess) { + coord = orphan.getWorldLocation(); + if (!this.worldObj.isChunkLoaded(coord)) { + continue; + } + + // This can occur on slow machines. + if (orphan.isInvalid()) { + continue; + } + + // This block has been replaced by another. + if (worldObj.getBlockEntity(coord) != orphan) { + continue; + } + + // THIS IS THE ONLY PLACE WHERE PARTS ATTACH TO MACHINES + // Try to attach to a neighbor's master controller + compatibleControllers = orphan.attachToNeighbors(); + if (compatibleControllers == null) { + // FOREVER ALONE! Create and register a new controller. + // THIS IS THE ONLY PLACE WHERE NEW CONTROLLERS ARE + // CREATED. + MultiblockControllerBase newController = orphan.createNewMultiblock(); + newController.attachBlock(orphan); + this.controllers.add(newController); + } else if (compatibleControllers.size() > 1) { + if (mergePools == null) { + mergePools = new ArrayList>(); + } + + // THIS IS THE ONLY PLACE WHERE MERGES ARE DETECTED + // Multiple compatible controllers indicates an + // impending merge. + // Locate the appropriate merge pool(s) + //boolean hasAddedToPool = false; + List> candidatePools = new ArrayList>(); + for (Set candidatePool : mergePools) { + if (!Collections.disjoint(candidatePool, compatibleControllers)) { + // They share at least one element, so that + // means they will all touch after the merge + candidatePools.add(candidatePool); + } + } + + if (candidatePools.size() <= 0) { + // No pools nearby, create a new merge pool + mergePools.add(compatibleControllers); + } else if (candidatePools.size() == 1) { + // Only one pool nearby, simply add to that one + candidatePools.get(0).addAll(compatibleControllers); + } else { + // Multiple pools- merge into one, then add the + // compatible controllers + Set masterPool = candidatePools.get(0); + Set consumedPool; + for (int i = 1; i < candidatePools.size(); i++) { + consumedPool = candidatePools.get(i); + masterPool.addAll(consumedPool); + mergePools.remove(consumedPool); + } + masterPool.addAll(compatibleControllers); + } + } + } + } + } + + if (mergePools != null && mergePools.size() > 0) { + // Process merges - any machines that have been marked for merge + // should be merged + // into the "master" machine. + // To do this, we combine lists of machines that are touching one + // another and therefore + // should voltron the fuck up. + for (Set mergePool : mergePools) { + // Search for the new master machine, which will take over all + // the blocks contained in the other machines + MultiblockControllerBase newMaster = null; + for (MultiblockControllerBase controller : mergePool) { + if (newMaster == null || controller.shouldConsume(newMaster)) { + newMaster = controller; + } + } + + if (newMaster == null) { + RebornCore.LOGGER.fatal( + String.format("Multiblock system checked a merge pool of size %d, found no master candidates. This should never happen.", + mergePool.size())); + } else { + // Merge all the other machines into the master machine, + // then unregister them + addDirtyController(newMaster); + for (MultiblockControllerBase controller : mergePool) { + if (controller != newMaster) { + newMaster.assimilate(controller); + addDeadController(controller); + addDirtyController(newMaster); + } + } + } + } + } + + // Process splits and assembly + // Any controllers which have had parts removed must be checked to see + // if some parts are no longer + // physically connected to their master. + if (dirtyControllers.size() > 0) { + Set newlyDetachedParts = null; + for (MultiblockControllerBase controller : dirtyControllers) { + // Tell the machine to check if any parts are disconnected. + // It should return a set of parts which are no longer + // connected. + // POSTCONDITION: The controller must have informed those parts + // that + // they are no longer connected to this machine. + newlyDetachedParts = controller.checkForDisconnections(); + + if (!controller.isEmpty()) { + controller.recalculateMinMaxCoords(); + controller.checkIfMachineIsWhole(); + } else { + addDeadController(controller); + } + + if (newlyDetachedParts != null && newlyDetachedParts.size() > 0) { + // Controller has shed some parts - add them to the detached + // list for delayed processing + detachedParts.addAll(newlyDetachedParts); + } + } + + dirtyControllers.clear(); + } + + // Unregister dead controllers + if (deadControllers.size() > 0) { + for (MultiblockControllerBase controller : deadControllers) { + // Go through any controllers which have marked themselves as + // potentially dead. + // Validate that they are empty/dead, then unregister them. + if (!controller.isEmpty()) { + RebornCore.LOGGER.fatal( + "Found a non-empty controller. Forcing it to shed its blocks and die. This should never happen!"); + detachedParts.addAll(controller.detachAllBlocks()); + } + + // THIS IS THE ONLY PLACE WHERE CONTROLLERS ARE UNREGISTERED. + this.controllers.remove(controller); + } + + deadControllers.clear(); + } + + // Process detached blocks + // Any blocks which have been detached this tick should be moved to the + // orphaned + // list, and will be checked next tick to see if their chunk is still + // loaded. + for (IMultiblockPart part : detachedParts) { + // Ensure parts know they're detached + part.assertDetached(); + } + + addAllOrphanedPartsThreadsafe(detachedParts); + detachedParts.clear(); + } + + /** + * Called when a multiblock part is added to the world, either via + * chunk-load or user action. If its chunk is loaded, it will be processed + * during the next tick. If the chunk is not loaded, it will be added to a + * list of objects waiting for a chunkload. + * + * @param part The part which is being added to this world. + */ + public void onPartAdded(IMultiblockPart part) { + BlockPos pos = part.getWorldLocation(); + + if (!this.worldObj.isChunkLoaded(pos)) { + // Part goes into the waiting-for-chunk-load list + Set partSet; + int chunkHash = new ChunkPos(pos).hashCode(); + + synchronized (partsAwaitingChunkLoadMutex) { + if (!partsAwaitingChunkLoad.containsKey(chunkHash)) { + partSet = new HashSet(); + partsAwaitingChunkLoad.put(chunkHash, partSet); + } else { + partSet = partsAwaitingChunkLoad.get(chunkHash); + } + + partSet.add(part); + } + } else { + // Part goes into the orphan queue, to be checked this tick + addOrphanedPartThreadsafe(part); + } + } + + /** + * Called when a part is removed from the world, via user action or via + * chunk unloads. This part is removed from any lists in which it may be, + * and its machine is marked for recalculation. + * + * @param part The part which is being removed. + */ + public void onPartRemovedFromWorld(IMultiblockPart part) { + BlockPos pos = part.getWorldLocation(); + if (pos != null) { + int chunkHash = new ChunkPos(pos).hashCode(); + + if (partsAwaitingChunkLoad.containsKey(chunkHash)) { + synchronized (partsAwaitingChunkLoadMutex) { + if (partsAwaitingChunkLoad.containsKey(chunkHash)) { + partsAwaitingChunkLoad.get(chunkHash).remove(part); + if (partsAwaitingChunkLoad.get(chunkHash).size() <= 0) { + partsAwaitingChunkLoad.remove(chunkHash); + } + } + } + } + } + + detachedParts.remove(part); + if (orphanedParts.contains(part)) { + synchronized (orphanedPartsMutex) { + orphanedParts.remove(part); + } + } + + part.assertDetached(); + } + + /** + * Called when the world which this World Registry represents is fully + * unloaded from the system. Does some housekeeping just to be nice. + */ + public void onWorldUnloaded() { + controllers.clear(); + deadControllers.clear(); + dirtyControllers.clear(); + + detachedParts.clear(); + + synchronized (partsAwaitingChunkLoadMutex) { + partsAwaitingChunkLoad.clear(); + } + + synchronized (orphanedPartsMutex) { + orphanedParts.clear(); + } + + worldObj = null; + } + + /** + * Called when a chunk has finished loading. Adds all of the parts which are + * awaiting load to the list of parts which are orphans and therefore will + * be added to machines after the next world tick. + * + * @param chunk Chunk that was + * loaded + */ + public void onChunkLoaded(Chunk chunk) { + int chunkHash = chunk.getPos().hashCode(); + if (partsAwaitingChunkLoad.containsKey(chunkHash)) { + synchronized (partsAwaitingChunkLoadMutex) { + if (partsAwaitingChunkLoad.containsKey(chunkHash)) { + addAllOrphanedPartsThreadsafe(partsAwaitingChunkLoad.get(chunkHash)); + partsAwaitingChunkLoad.remove(chunkHash); + } + } + } + } + + /** + * Registers a controller as dead. It will be cleaned up at the end of the + * next world tick. Note that a controller must shed all of its blocks + * before being marked as dead, or the system will complain at you. + * + * @param deadController The controller which is dead. + */ + public void addDeadController(MultiblockControllerBase deadController) { + this.deadControllers.add(deadController); + } + + /** + * Registers a controller as dirty - its list of attached blocks has + * changed, and it must be re-checked for assembly and, possibly, for + * orphans. + * + * @param dirtyController The dirty controller. + */ + public void addDirtyController(MultiblockControllerBase dirtyController) { + this.dirtyControllers.add(dirtyController); + } + + /** + * Use this only if you know what you're doing. You should rarely need to + * iterate over all controllers in a world! + * + * @return An (unmodifiable) set of controllers which are active in this + * world. + */ + public Set getControllers() { + return Collections.unmodifiableSet(controllers); + } + + /* *** PRIVATE HELPERS *** */ + + private void addOrphanedPartThreadsafe(IMultiblockPart part) { + synchronized (orphanedPartsMutex) { + orphanedParts.add(part); + } + } + + private void addAllOrphanedPartsThreadsafe(Collection parts) { + synchronized (orphanedPartsMutex) { + orphanedParts.addAll(parts); + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/PartPosition.java b/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/PartPosition.java new file mode 100644 index 000000000..9a9468b76 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/PartPosition.java @@ -0,0 +1,43 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock.rectangular; + +public enum PartPosition { + Unknown, Interior, FrameCorner, Frame, TopFace, BottomFace, NorthFace, SouthFace, EastFace, WestFace; + + public boolean isFace(PartPosition position) { + switch (position) { + case TopFace: + case BottomFace: + case NorthFace: + case SouthFace: + case EastFace: + case WestFace: + return true; + default: + return false; + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/RectangularMultiblockBlockEntityBase.java b/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/RectangularMultiblockBlockEntityBase.java new file mode 100644 index 000000000..05b46693a --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/RectangularMultiblockBlockEntityBase.java @@ -0,0 +1,133 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock.rectangular; + +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import reborncore.common.multiblock.MultiblockControllerBase; +import reborncore.common.multiblock.MultiblockBlockEntityBase; +import reborncore.common.multiblock.MultiblockValidationException; + +public abstract class RectangularMultiblockBlockEntityBase extends MultiblockBlockEntityBase { + + PartPosition position; + Direction outwards; + + public RectangularMultiblockBlockEntityBase(BlockEntityType blockEntityType) { + super(blockEntityType); + + position = PartPosition.Unknown; + outwards = null; + } + + // Positional Data + public Direction getOutwardsDir() { + return outwards; + } + + public PartPosition getPartPosition() { + return position; + } + + // Handlers from MultiblockBlockEntityBase + @Override + public void onAttached(MultiblockControllerBase newController) { + super.onAttached(newController); + recalculateOutwardsDirection(newController.getMinimumCoord(), newController.getMaximumCoord()); + } + + @Override + public void onMachineAssembled(MultiblockControllerBase controller) { + BlockPos maxCoord = controller.getMaximumCoord(); + BlockPos minCoord = controller.getMinimumCoord(); + + // Discover where I am on the reactor + recalculateOutwardsDirection(minCoord, maxCoord); + } + + @Override + public void onMachineBroken() { + position = PartPosition.Unknown; + outwards = null; + } + + // Positional helpers + public void recalculateOutwardsDirection(BlockPos minCoord, BlockPos maxCoord) { + outwards = null; + position = PartPosition.Unknown; + + int facesMatching = 0; + if (maxCoord.getX() == this.getPos().getX() || minCoord.getX() == this.getPos().getX()) { + facesMatching++; + } + if (maxCoord.getY() == this.getPos().getY() || minCoord.getY() == this.getPos().getY()) { + facesMatching++; + } + if (maxCoord.getZ() == this.getPos().getZ() || minCoord.getZ() == this.getPos().getZ()) { + facesMatching++; + } + + if (facesMatching <= 0) { + position = PartPosition.Interior; + } else if (facesMatching >= 3) { + position = PartPosition.FrameCorner; + } else if (facesMatching == 2) { + position = PartPosition.Frame; + } else { + // 1 face matches + if (maxCoord.getX() == this.getPos().getX()) { + position = PartPosition.EastFace; + outwards = Direction.EAST; + } else if (minCoord.getX() == this.getPos().getX()) { + position = PartPosition.WestFace; + outwards = Direction.WEST; + } else if (maxCoord.getZ() == this.getPos().getZ()) { + position = PartPosition.SouthFace; + outwards = Direction.SOUTH; + } else if (minCoord.getZ() == this.getPos().getZ()) { + position = PartPosition.NorthFace; + outwards = Direction.NORTH; + } else if (maxCoord.getY() == this.getPos().getY()) { + position = PartPosition.TopFace; + outwards = Direction.UP; + } else { + position = PartPosition.BottomFace; + outwards = Direction.DOWN; + } + } + } + + // /// Validation Helpers (IMultiblockPart) + public abstract void isGoodForFrame() throws MultiblockValidationException; + + public abstract void isGoodForSides() throws MultiblockValidationException; + + public abstract void isGoodForTop() throws MultiblockValidationException; + + public abstract void isGoodForBottom() throws MultiblockValidationException; + + public abstract void isGoodForInterior() throws MultiblockValidationException; +} diff --git a/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/RectangularMultiblockControllerBase.java b/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/RectangularMultiblockControllerBase.java new file mode 100644 index 000000000..ed4c092fa --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/multiblock/rectangular/RectangularMultiblockControllerBase.java @@ -0,0 +1,179 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.multiblock.rectangular; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import reborncore.common.multiblock.MultiblockControllerBase; +import reborncore.common.multiblock.MultiblockValidationException; + +public abstract class RectangularMultiblockControllerBase extends MultiblockControllerBase { + + protected RectangularMultiblockControllerBase(World world) { + super(world); + } + + /** + * @return True if the machine is "whole" and should be assembled. False + * otherwise. + */ + @Override + protected void isMachineWhole() throws MultiblockValidationException { + if (connectedParts.size() < getMinimumNumberOfBlocksForAssembledMachine()) { + throw new MultiblockValidationException("Machine is too small."); + } + + BlockPos maximumCoord = getMaximumCoord(); + BlockPos minimumCoord = getMinimumCoord(); + + // Quickly check for exceeded dimensions + int deltaX = maximumCoord.getX() - minimumCoord.getX() + 1; + int deltaY = maximumCoord.getY() - minimumCoord.getY() + 1; + int deltaZ = maximumCoord.getZ() - minimumCoord.getZ() + 1; + + int maxX = getMaximumXSize(); + int maxY = getMaximumYSize(); + int maxZ = getMaximumZSize(); + int minX = getMinimumXSize(); + int minY = getMinimumYSize(); + int minZ = getMinimumZSize(); + + if (maxX > 0 && deltaX > maxX) { + throw new MultiblockValidationException( + String.format("Machine is too large, it may be at most %d blocks in the X dimension", maxX)); + } + if (maxY > 0 && deltaY > maxY) { + throw new MultiblockValidationException( + String.format("Machine is too large, it may be at most %d blocks in the Y dimension", maxY)); + } + if (maxZ > 0 && deltaZ > maxZ) { + throw new MultiblockValidationException( + String.format("Machine is too large, it may be at most %d blocks in the Z dimension", maxZ)); + } + if (deltaX < minX) { + throw new MultiblockValidationException( + String.format("Machine is too small, it must be at least %d blocks in the X dimension", minX)); + } + if (deltaY < minY) { + throw new MultiblockValidationException( + String.format("Machine is too small, it must be at least %d blocks in the Y dimension", minY)); + } + if (deltaZ < minZ) { + throw new MultiblockValidationException( + String.format("Machine is too small, it must be at least %d blocks in the Z dimension", minZ)); + } + + // Now we run a simple check on each block within that volume. + // Any block deviating = NO DEAL SIR + BlockEntity te; + RectangularMultiblockBlockEntityBase part; + Class myClass = this.getClass(); + + for (int x = minimumCoord.getX(); x <= maximumCoord.getX(); x++) { + for (int y = minimumCoord.getY(); y <= maximumCoord.getY(); y++) { + for (int z = minimumCoord.getZ(); z <= maximumCoord.getZ(); z++) { + // Okay, figure out what sort of block this should be. + + te = this.worldObj.getBlockEntity(new BlockPos(x, y, z)); + if (te instanceof RectangularMultiblockBlockEntityBase) { + part = (RectangularMultiblockBlockEntityBase) te; + + // Ensure this part should actually be allowed within a + // cube of this controller's type + if (!myClass.equals(part.getMultiblockControllerType())) { + throw new MultiblockValidationException( + String.format("Part @ %d, %d, %d is incompatible with machines of type %s", x, y, z, + myClass.getSimpleName())); + } + } else { + // This is permitted so that we can incorporate certain + // non-multiblock parts inside interiors + part = null; + } + + // Validate block type against both part-level and + // material-level validators. + int extremes = 0; + if (x == minimumCoord.getX()) { + extremes++; + } + if (y == minimumCoord.getY()) { + extremes++; + } + if (z == minimumCoord.getZ()) { + extremes++; + } + + if (x == maximumCoord.getX()) { + extremes++; + } + if (y == maximumCoord.getY()) { + extremes++; + } + if (z == maximumCoord.getZ()) { + extremes++; + } + + if (extremes >= 2) { + if (part != null) { + part.isGoodForFrame(); + } else { + isBlockGoodForFrame(this.worldObj, x, y, z); + } + } else if (extremes == 1) { + if (y == maximumCoord.getY()) { + if (part != null) { + part.isGoodForTop(); + } else { + isBlockGoodForTop(this.worldObj, x, y, z); + } + } else if (y == minimumCoord.getY()) { + if (part != null) { + part.isGoodForBottom(); + } else { + isBlockGoodForBottom(this.worldObj, x, y, z); + } + } else { + // Side + if (part != null) { + part.isGoodForSides(); + } else { + isBlockGoodForSides(this.worldObj, x, y, z); + } + } + } else { + if (part != null) { + part.isGoodForInterior(); + } else { + isBlockGoodForInterior(this.worldObj, x, y, z); + } + } + } + } + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/network/ClientBoundPacketHandlers.java b/RebornCore/src/main/java/reborncore/common/network/ClientBoundPacketHandlers.java new file mode 100644 index 000000000..0992b9ad3 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/network/ClientBoundPacketHandlers.java @@ -0,0 +1,127 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.network; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.screen.Screen; +import net.minecraft.client.gui.screen.ingame.HandledScreen; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import reborncore.RebornCore; +import reborncore.client.ClientChunkManager; +import reborncore.client.screen.builder.ExtendedScreenHandlerListener; +import reborncore.common.blockentity.FluidConfiguration; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.blockentity.SlotConfiguration; +import reborncore.common.chunkloading.ChunkLoaderManager; + +import java.util.List; + +@Environment(EnvType.CLIENT) +public class ClientBoundPacketHandlers { + + public static void init() { + NetworkManager.registerClientBoundHandler(new Identifier("reborncore", "custom_description"), (client, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + CompoundTag tagCompound = packetBuffer.readCompoundTag(); + client.execute(() -> { + World world = MinecraftClient.getInstance().world; + if (world.isChunkLoaded(pos)) { + BlockEntity blockentity = world.getBlockEntity(pos); + if (blockentity != null && tagCompound != null) { + blockentity.fromTag(blockentity.getCachedState(), tagCompound); + } + } + }); + }); + + NetworkManager.registerClientBoundHandler(new Identifier("reborncore", "fluid_config_sync"), (client, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + CompoundTag compoundTag = packetBuffer.readCompoundTag(); + + client.execute(() -> { + FluidConfiguration fluidConfiguration = new FluidConfiguration(compoundTag); + if (!MinecraftClient.getInstance().world.isChunkLoaded(pos)) { + return; + } + MachineBaseBlockEntity machineBase = (MachineBaseBlockEntity) MinecraftClient.getInstance().world.getBlockEntity(pos); + if (machineBase == null || machineBase.fluidConfiguration == null || fluidConfiguration == null) { + RebornCore.LOGGER.error("Failed to sync fluid config data to " + pos); + return; + } + fluidConfiguration.getAllSides().forEach(fluidConfig -> machineBase.fluidConfiguration.updateFluidConfig(fluidConfig)); + machineBase.fluidConfiguration.setInput(fluidConfiguration.autoInput()); + machineBase.fluidConfiguration.setOutput(fluidConfiguration.autoOutput()); + + }); + }); + + NetworkManager.registerClientBoundHandler(new Identifier("reborncore", "slot_sync"), (client, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + CompoundTag compoundTag = packetBuffer.readCompoundTag(); + + client.execute(() -> { + SlotConfiguration slotConfig = new SlotConfiguration(compoundTag); + if (!MinecraftClient.getInstance().world.isChunkLoaded(pos)) { + return; + } + MachineBaseBlockEntity machineBase = (MachineBaseBlockEntity) MinecraftClient.getInstance().world.getBlockEntity(pos); + if (machineBase == null || machineBase.getSlotConfiguration() == null || slotConfig == null || slotConfig.getSlotDetails() == null) { + RebornCore.LOGGER.error("Failed to sync slot data to " + pos); + return; + } + MinecraftClient.getInstance().execute(() -> slotConfig.getSlotDetails().forEach(slotConfigHolder -> machineBase.getSlotConfiguration().updateSlotDetails(slotConfigHolder))); + }); + }); + + NetworkManager.registerClientBoundHandler(new Identifier("reborncore", "send_object"), (client, handler, packetBuffer, responseSender) -> { + int id = packetBuffer.readInt(); + Object value = new ExtendedPacketBuffer(packetBuffer).readObject(); + String container = packetBuffer.readString(packetBuffer.readInt()); + client.execute(() -> { + Screen gui = MinecraftClient.getInstance().currentScreen; + if (gui instanceof HandledScreen) { + ScreenHandler screenHandler = ((HandledScreen) gui).getScreenHandler(); + if (screenHandler instanceof ExtendedScreenHandlerListener) { + ((ExtendedScreenHandlerListener) screenHandler).handleObject(id, value); + } + } + }); + }); + + NetworkManager.registerClientBoundHandler(new Identifier("reborncore", "sync_chunks"), (client, handler, packetBuffer, responseSender) -> { + List chunks = new ExtendedPacketBuffer(packetBuffer).readCodec(ChunkLoaderManager.CODEC); + + client.execute(() -> ClientChunkManager.setLoadedChunks(chunks)); + }); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/network/ClientBoundPackets.java b/RebornCore/src/main/java/reborncore/common/network/ClientBoundPackets.java new file mode 100644 index 000000000..adcba6b7b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/network/ClientBoundPackets.java @@ -0,0 +1,80 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.network; + +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.screen.ScreenHandler; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import reborncore.common.blockentity.FluidConfiguration; +import reborncore.common.blockentity.SlotConfiguration; +import reborncore.common.chunkloading.ChunkLoaderManager; + +import java.util.List; + +public class ClientBoundPackets { + + public static IdentifiedPacket createCustomDescriptionPacket(BlockEntity blockEntity) { + return createCustomDescriptionPacket(blockEntity.getPos(), blockEntity.toTag(new CompoundTag())); + } + + public static IdentifiedPacket createCustomDescriptionPacket(BlockPos blockPos, CompoundTag nbt) { + return NetworkManager.createClientBoundPacket(new Identifier("reborncore", "custom_description"), packetBuffer -> { + packetBuffer.writeBlockPos(blockPos); + packetBuffer.writeCompoundTag(nbt); + }); + } + + public static IdentifiedPacket createPacketFluidConfigSync(BlockPos pos, FluidConfiguration fluidConfiguration) { + return NetworkManager.createClientBoundPacket(new Identifier("reborncore", "fluid_config_sync"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeCompoundTag(fluidConfiguration.write()); + }); + } + + public static IdentifiedPacket createPacketSlotSync(BlockPos pos, SlotConfiguration slotConfig) { + return NetworkManager.createClientBoundPacket(new Identifier("reborncore", "slot_sync"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeCompoundTag(slotConfig.write()); + }); + } + + public static IdentifiedPacket createPacketSendObject(int id, Object value, ScreenHandler screenHandler) { + return NetworkManager.createClientBoundPacket(new Identifier("reborncore", "send_object"), packetBuffer -> { + packetBuffer.writeInt(id); + packetBuffer.writeObject(value); + packetBuffer.writeInt(screenHandler.getClass().getName().length()); + packetBuffer.writeString(screenHandler.getClass().getName()); + }); + } + + public static IdentifiedPacket createPacketSyncLoadedChunks(List chunks) { + return NetworkManager.createClientBoundPacket(new Identifier("reborncore", "sync_chunks"), extendedPacketBuffer -> { + extendedPacketBuffer.writeCodec(ChunkLoaderManager.CODEC, chunks); + }); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/network/ExtendedPacketBuffer.java b/RebornCore/src/main/java/reborncore/common/network/ExtendedPacketBuffer.java new file mode 100644 index 000000000..b1ca68fbc --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/network/ExtendedPacketBuffer.java @@ -0,0 +1,116 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.network; + +import com.mojang.serialization.Codec; +import com.mojang.serialization.DataResult; +import io.netty.buffer.ByteBuf; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; +import net.minecraft.nbt.NbtOps; +import net.minecraft.nbt.Tag; +import net.minecraft.network.PacketByteBuf; + +import java.io.ByteArrayInputStream; +import java.io.ByteArrayOutputStream; +import java.io.ObjectInputStream; +import java.io.ObjectOutputStream; +import java.math.BigInteger; + +public class ExtendedPacketBuffer extends PacketByteBuf { + public ExtendedPacketBuffer(ByteBuf wrapped) { + super(wrapped); + } + + protected void writeObject(Object object) { + ObjectBufferUtils.writeObject(object, this); + } + + protected Object readObject() { + return ObjectBufferUtils.readObject(this); + } + + public void writeBigInt(BigInteger bigInteger) { + try { + ByteArrayOutputStream baos = new ByteArrayOutputStream(); + ObjectOutputStream outputStream = new ObjectOutputStream(baos); + outputStream.writeObject(bigInteger); + writeByteArray(baos.toByteArray()); + } catch (Exception e) { + throw new RuntimeException("Failed to write big int"); + } + } + + public BigInteger readBigInt() { + try { + ObjectInputStream inputStream = new ObjectInputStream(new ByteArrayInputStream(readByteArray())); + return (BigInteger) inputStream.readObject(); + } catch (Exception e) { + throw new RuntimeException("Failed to read big int"); + } + } + + // Supports reading and writing list codec's + public void writeCodec(Codec codec, T object) { + DataResult dataResult = codec.encodeStart(NbtOps.INSTANCE, object); + if (dataResult.error().isPresent()) { + throw new RuntimeException("Failed to encode: " + dataResult.error().get().message() + " " + object); + } else { + Tag tag = dataResult.result().get(); + if (tag instanceof CompoundTag) { + writeByte(0); + writeCompoundTag((CompoundTag) tag); + } else if (tag instanceof ListTag) { + writeByte(1); + CompoundTag compoundTag = new CompoundTag(); + compoundTag.put("tag", tag); + writeCompoundTag(compoundTag); + } else { + throw new RuntimeException("Failed to write: " + tag); + } + } + } + + public T readCodec(Codec codec) { + byte type = readByte(); + Tag tag = null; + + if (type == 0) { + tag = readCompoundTag(); + } else if (type == 1) { + tag = readCompoundTag().get("tag"); + } else { + throw new RuntimeException("Failed to read codec"); + } + + DataResult dataResult = codec.parse(NbtOps.INSTANCE, tag); + + if (dataResult.error().isPresent()) { + throw new RuntimeException("Failed to decode: " + dataResult.error().get().message() + " " + tag); + } else { + return dataResult.result().get(); + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/network/IdentifiedPacket.java b/RebornCore/src/main/java/reborncore/common/network/IdentifiedPacket.java new file mode 100644 index 000000000..f25714fbb --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/network/IdentifiedPacket.java @@ -0,0 +1,47 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.network; + +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; + +public final class IdentifiedPacket { + + private final Identifier channel; + private final PacketByteBuf packetByteBuf; + + public IdentifiedPacket(Identifier channel, PacketByteBuf packetByteBuf) { + this.channel = channel; + this.packetByteBuf = packetByteBuf; + } + + public Identifier getChannel() { + return channel; + } + + public PacketByteBuf getPacketByteBuf() { + return packetByteBuf; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/network/NetworkManager.java b/RebornCore/src/main/java/reborncore/common/network/NetworkManager.java new file mode 100644 index 000000000..938fe0577 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/network/NetworkManager.java @@ -0,0 +1,94 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.network; + +import net.fabricmc.fabric.api.client.networking.v1.ClientPlayNetworking; +import net.fabricmc.fabric.api.networking.v1.PacketByteBufs; +import net.fabricmc.fabric.api.networking.v1.PlayerLookup; +import net.fabricmc.fabric.api.networking.v1.ServerPlayNetworking; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.server.MinecraftServer; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; + +import java.util.Collection; +import java.util.Collections; +import java.util.function.Consumer; + +public class NetworkManager { + + + public static IdentifiedPacket createServerBoundPacket(Identifier identifier, Consumer packetBufferConsumer) { + PacketByteBuf buf = PacketByteBufs.create(); + packetBufferConsumer.accept(new ExtendedPacketBuffer(buf)); + return new IdentifiedPacket(identifier, buf); + } + + public static void registerServerBoundHandler(Identifier identifier, ServerPlayNetworking.PlayChannelHandler handler) { + ServerPlayNetworking.registerGlobalReceiver(identifier, handler); + } + + public static IdentifiedPacket createClientBoundPacket(Identifier identifier, Consumer packetBufferConsumer) { + PacketByteBuf buf = PacketByteBufs.create(); + packetBufferConsumer.accept(new ExtendedPacketBuffer(buf)); + return new IdentifiedPacket(identifier, buf); + } + + public static void registerClientBoundHandler(Identifier identifier, ClientPlayNetworking.PlayChannelHandler handler) { + ClientPlayNetworking.registerGlobalReceiver(identifier, handler); + } + + + public static void sendToServer(IdentifiedPacket packet) { + ClientPlayNetworking.send(packet.getChannel(), packet.getPacketByteBuf()); + } + + public static void sendToAll(IdentifiedPacket packet, MinecraftServer server) { + send(packet, PlayerLookup.all(server)); + } + + public static void sendToPlayer(IdentifiedPacket packet, ServerPlayerEntity serverPlayerEntity) { + send(packet, Collections.singletonList(serverPlayerEntity)); + } + + public static void sendToWorld(IdentifiedPacket packet, ServerWorld world) { + send(packet, PlayerLookup.world(world)); + } + + + public static void sendToTracking(IdentifiedPacket packet, BlockEntity blockEntity) { + send(packet, PlayerLookup.tracking(blockEntity)); + } + + public static void send(IdentifiedPacket packet, Collection players) { + for (ServerPlayerEntity player : players) { + ServerPlayNetworking.send(player, packet.getChannel(), packet.getPacketByteBuf()); + } + } + + +} diff --git a/RebornCore/src/main/java/reborncore/common/network/ObjectBufferUtils.java b/RebornCore/src/main/java/reborncore/common/network/ObjectBufferUtils.java new file mode 100644 index 000000000..4b5dbe90a --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/network/ObjectBufferUtils.java @@ -0,0 +1,119 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.network; + +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.PacketByteBuf; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import reborncore.common.fluid.FluidValue; + +import java.math.BigInteger; +import java.util.Arrays; +import java.util.Objects; + +public enum ObjectBufferUtils { + + STRING(String.class, (string, buffer) -> { + buffer.writeInt(string.length()); + buffer.writeString(string); + }, buffer -> { + return buffer.readString(buffer.readInt()); + }), + + INT(Integer.class, (value, buffer) -> { + buffer.writeInt(value); + }, PacketByteBuf::readInt), + + LONG(Long.class, (pos, buffer) -> { + buffer.writeLong(pos); + }, ExtendedPacketBuffer::readLong), + + DOUBLE(Double.class, (pos, buffer) -> { + buffer.writeDouble(pos); + }, ExtendedPacketBuffer::readDouble), + + FLOAT(Float.class, (pos, buffer) -> { + buffer.writeFloat(pos); + }, ExtendedPacketBuffer::readFloat), + + BLOCK_POS(BlockPos.class, (pos, buffer) -> { + buffer.writeBlockPos(pos); + }, PacketByteBuf::readBlockPos), + + ID(Identifier.class, (id, buffer) -> { + String string = id.toString(); + buffer.writeInt(string.length()); + buffer.writeString(string); + }, buffer -> { + return new Identifier(buffer.readString(buffer.readInt())); + }), + + FLUID_VALUE(FluidValue.class, (value, buffer) -> { + buffer.writeInt(value.getRawValue()); + }, buffer -> { + return FluidValue.fromRaw(buffer.readInt()); + }), + + COMPOUND_TAG(CompoundTag.class, (value, buffer) -> { + buffer.writeCompoundTag(value); + }, PacketByteBuf::readCompoundTag), + + BIG_INT(BigInteger.class, (pos, buffer) -> { + buffer.writeBigInt(pos); + }, ExtendedPacketBuffer::readBigInt); + + Class clazz; + ObjectWriter writer; + ObjectReader reader; + + ObjectBufferUtils(Class clazz, ObjectWriter writer, ObjectReader reader) { + this.clazz = clazz; + this.writer = writer; + this.reader = reader; + } + + public static void writeObject(Object object, ExtendedPacketBuffer buffer) { + ObjectBufferUtils utils = Arrays.stream(values()).filter(objectBufferUtils -> objectBufferUtils.clazz == object.getClass()).findFirst().orElse(null); + Objects.requireNonNull(utils, "No support found for " + object.getClass()); + buffer.writeInt(utils.ordinal()); + utils.writer.write(object, buffer); + } + + public static Object readObject(ExtendedPacketBuffer buffer) { + ObjectBufferUtils utils = values()[buffer.readInt()]; + Objects.requireNonNull(utils, "Could not find reader"); + return utils.reader.read(buffer); + } + + private interface ObjectWriter { + void write(T object, ExtendedPacketBuffer buffer); + } + + private interface ObjectReader { + T read(ExtendedPacketBuffer buffer); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/network/ServerBoundPackets.java b/RebornCore/src/main/java/reborncore/common/network/ServerBoundPackets.java new file mode 100644 index 000000000..fb7127b37 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/network/ServerBoundPackets.java @@ -0,0 +1,221 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.network; + +import net.minecraft.block.BlockState; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.server.world.ServerWorld; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import org.apache.commons.lang3.Validate; +import reborncore.common.blockentity.FluidConfiguration; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.blockentity.RedstoneConfiguration; +import reborncore.common.blockentity.SlotConfiguration; +import reborncore.common.chunkloading.ChunkLoaderManager; + +public class ServerBoundPackets { + + public static void init() { + NetworkManager.registerServerBoundHandler(new Identifier("reborncore", "fluid_config_save"), (server, player, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + CompoundTag compoundTag = packetBuffer.readCompoundTag(); + + server.execute(() -> { + FluidConfiguration.FluidConfig fluidConfiguration = new FluidConfiguration.FluidConfig(compoundTag); + MachineBaseBlockEntity legacyMachineBase = (MachineBaseBlockEntity) player.world.getBlockEntity(pos); + legacyMachineBase.fluidConfiguration.updateFluidConfig(fluidConfiguration); + legacyMachineBase.markDirty(); + + IdentifiedPacket packetFluidConfigSync = ClientBoundPackets.createPacketFluidConfigSync(pos, legacyMachineBase.fluidConfiguration); + NetworkManager.sendToTracking(packetFluidConfigSync, legacyMachineBase); + + //We update the block to allow pipes that are connecting to detctect the update and change their connection status if needed + World world = legacyMachineBase.getWorld(); + BlockState blockState = world.getBlockState(legacyMachineBase.getPos()); + world.updateNeighborsAlways(legacyMachineBase.getPos(), blockState.getBlock()); + }); + }); + + NetworkManager.registerServerBoundHandler(new Identifier("reborncore", "config_save"), (server, player, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + CompoundTag tagCompound = packetBuffer.readCompoundTag(); + + server.execute(() -> { + MachineBaseBlockEntity legacyMachineBase = (MachineBaseBlockEntity) player.world.getBlockEntity(pos); + legacyMachineBase.getSlotConfiguration().read(tagCompound); + legacyMachineBase.markDirty(); + + IdentifiedPacket packetSlotSync = ClientBoundPackets.createPacketSlotSync(pos, legacyMachineBase.getSlotConfiguration()); + NetworkManager.sendToWorld(packetSlotSync, (ServerWorld) legacyMachineBase.getWorld()); + }); + }); + + NetworkManager.registerServerBoundHandler(new Identifier("reborncore", "fluid_io_save"), (server, player, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + boolean input = packetBuffer.readBoolean(); + boolean output = packetBuffer.readBoolean(); + + server.execute(() -> { + MachineBaseBlockEntity legacyMachineBase = (MachineBaseBlockEntity) player.world.getBlockEntity(pos); + FluidConfiguration config = legacyMachineBase.fluidConfiguration; + if (config == null) { + return; + } + config.setInput(input); + config.setOutput(output); + + //Syncs back to the client + IdentifiedPacket packetFluidConfigSync = ClientBoundPackets.createPacketFluidConfigSync(pos, legacyMachineBase.fluidConfiguration); + NetworkManager.sendToTracking(packetFluidConfigSync, legacyMachineBase); + }); + }); + + NetworkManager.registerServerBoundHandler(new Identifier("reborncore", "io_save"), (server, player, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + int slotID = packetBuffer.readInt(); + boolean input = packetBuffer.readBoolean(); + boolean output = packetBuffer.readBoolean(); + boolean filter = packetBuffer.readBoolean(); + + server.execute(() -> { + MachineBaseBlockEntity machineBase = (MachineBaseBlockEntity) player.world.getBlockEntity(pos); + Validate.notNull(machineBase, "machine cannot be null"); + SlotConfiguration.SlotConfigHolder holder = machineBase.getSlotConfiguration().getSlotDetails(slotID); + if (holder == null) { + return; + } + + holder.setInput(input); + holder.setOutput(output); + holder.setfilter(filter); + + //Syncs back to the client + IdentifiedPacket packetSlotSync = ClientBoundPackets.createPacketSlotSync(pos, machineBase.getSlotConfiguration()); + NetworkManager.sendToAll(packetSlotSync, player.getServer()); + }); + }); + + NetworkManager.registerServerBoundHandler(new Identifier("reborncore", "slot_save"), (server, player, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + CompoundTag compoundTag = packetBuffer.readCompoundTag(); + + server.execute(() -> { + SlotConfiguration.SlotConfig slotConfig = new SlotConfiguration.SlotConfig(compoundTag); + MachineBaseBlockEntity legacyMachineBase = (MachineBaseBlockEntity) player.world.getBlockEntity(pos); + legacyMachineBase.getSlotConfiguration().getSlotDetails(slotConfig.getSlotID()).updateSlotConfig(slotConfig); + legacyMachineBase.markDirty(); + + IdentifiedPacket packetSlotSync = ClientBoundPackets.createPacketSlotSync(pos, legacyMachineBase.getSlotConfiguration()); + NetworkManager.sendToWorld(packetSlotSync, (ServerWorld) legacyMachineBase.getWorld()); + }); + }); + + NetworkManager.registerServerBoundHandler(new Identifier("reborncore", "chunk_loader_request"), (server, player, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + server.execute(() -> { + Validate.isInstanceOf(ServerPlayerEntity.class, player, "something very very bad has happened"); + ChunkLoaderManager chunkLoaderManager = ChunkLoaderManager.get(player.world); + chunkLoaderManager.syncChunkLoaderToClient((ServerPlayerEntity) player, pos); + }); + }); + + NetworkManager.registerServerBoundHandler(new Identifier("reborncore", "set_redstone_state"), (server, player, handler, packetBuffer, responseSender) -> { + BlockPos pos = packetBuffer.readBlockPos(); + String elementName = packetBuffer.readString(packetBuffer.readInt()); + int stateId = packetBuffer.readInt(); + + RedstoneConfiguration.Element element = RedstoneConfiguration.getElementByName(elementName); + if (element == null) return; + + if (stateId < 0 || stateId >= RedstoneConfiguration.State.values().length) return; + RedstoneConfiguration.State state = RedstoneConfiguration.State.values()[stateId]; + + server.execute(() -> { + MachineBaseBlockEntity blockEntity = (MachineBaseBlockEntity) player.world.getBlockEntity(pos); + if (blockEntity == null) return; + + blockEntity.getRedstoneConfiguration().setState(element, state); + }); + }); + } + + + public static IdentifiedPacket createPacketFluidConfigSave(BlockPos pos, FluidConfiguration.FluidConfig fluidConfiguration) { + return NetworkManager.createServerBoundPacket(new Identifier("reborncore", "fluid_config_save"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeCompoundTag(fluidConfiguration.write()); + }); + } + + public static IdentifiedPacket createPacketConfigSave(BlockPos pos, SlotConfiguration slotConfig) { + return NetworkManager.createServerBoundPacket(new Identifier("reborncore", "config_save"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeCompoundTag(slotConfig.write()); + }); + } + + public static IdentifiedPacket createPacketFluidIOSave(BlockPos pos, boolean input, boolean output) { + return NetworkManager.createServerBoundPacket(new Identifier("reborncore", "fluid_io_save"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeBoolean(input); + packetBuffer.writeBoolean(output); + }); + } + + public static IdentifiedPacket createPacketIOSave(BlockPos pos, int slotID, boolean input, boolean output, boolean filter) { + return NetworkManager.createServerBoundPacket(new Identifier("reborncore", "io_save"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeInt(slotID); + packetBuffer.writeBoolean(input); + packetBuffer.writeBoolean(output); + packetBuffer.writeBoolean(filter); + }); + } + + public static IdentifiedPacket createPacketSlotSave(BlockPos pos, SlotConfiguration.SlotConfig slotConfig) { + return NetworkManager.createServerBoundPacket(new Identifier("reborncore", "slot_save"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeCompoundTag(slotConfig.write()); + }); + } + + public static IdentifiedPacket requestChunkloaderChunks(BlockPos pos) { + return NetworkManager.createServerBoundPacket(new Identifier("reborncore", "chunk_loader_request"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + }); + } + + public static IdentifiedPacket createPacketSetRedstoneSate(BlockPos pos, RedstoneConfiguration.Element element, RedstoneConfiguration.State state) { + return NetworkManager.createServerBoundPacket(new Identifier("reborncore", "set_redstone_state"), packetBuffer -> { + packetBuffer.writeBlockPos(pos); + packetBuffer.writeInt(element.getName().length()); + packetBuffer.writeString(element.getName()); + packetBuffer.writeInt(state.ordinal()); + }); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/powerSystem/PowerAcceptorBlockEntity.java b/RebornCore/src/main/java/reborncore/common/powerSystem/PowerAcceptorBlockEntity.java new file mode 100644 index 000000000..2a64fd3cc --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/powerSystem/PowerAcceptorBlockEntity.java @@ -0,0 +1,486 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.powerSystem; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.block.entity.BlockEntityType; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.Direction; +import net.minecraft.util.math.MathHelper; +import org.jetbrains.annotations.Nullable; +import reborncore.api.IListInfoProvider; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.blockentity.RedstoneConfiguration; +import reborncore.common.util.StringUtils; +import team.reborn.energy.Energy; +import team.reborn.energy.EnergySide; +import team.reborn.energy.EnergyStorage; +import team.reborn.energy.EnergyTier; + +import java.util.List; + +public abstract class PowerAcceptorBlockEntity extends MachineBaseBlockEntity implements EnergyStorage, IListInfoProvider // TechReborn +{ + private EnergyTier blockEntityPowerTier; + private double energy; + + public double extraPowerStorage; + public double extraPowerInput; + public int extraTier; + public double powerChange; + public double powerLastTick; + public boolean checkOverfill = true; // Set to false to disable the overfill check. + + public PowerAcceptorBlockEntity(BlockEntityType blockEntityType) { + super(blockEntityType); + checkTier(); + } + + public void checkTier() { + if (this.getMaxInput(EnergySide.UNKNOWN) == 0) { + blockEntityPowerTier = getTier((int) this.getBaseMaxOutput()); + } else { + blockEntityPowerTier = getTier((int) this.getBaseMaxInput()); + } + } + + // TO-DO: Move to Energy API probably. Cables use this method. + public static EnergyTier getTier(int power) { + for (EnergyTier tier : EnergyTier.values()) { + if (tier.getMaxInput() >= power) { + return tier; + } + } + return EnergyTier.INFINITE; + } + + /** + * Get amount of missing energy + * + * @return double Free space for energy in internal buffer + */ + public double getFreeSpace() { + return getMaxStoredPower() - getStored(EnergySide.UNKNOWN); + } + + /** + * Adds energy to block entity + * + * @param amount double Amount to add + */ + public void addEnergy(double amount){ + setStored(energy + amount); + } + + /** + * Use energy from block entity + * + * @param amount double Amount of energy to use + */ + public void useEnergy(double amount){ + if (energy > amount) { + setStored(energy - amount); + } else { + setStored(0); + } + } + + /** + * Charge machine from battery placed inside inventory slot + * + * @param slot int Slot ID for battery slot + */ + public void charge(int slot) { + if (world == null) { + return; + } + if (world.isClient) { + return; + } + + double chargeEnergy = Math.min(getFreeSpace(), getMaxInput(EnergySide.UNKNOWN)); + if (chargeEnergy <= 0.0) { + return; + } + if (!getOptionalInventory().isPresent()) { + return; + } + ItemStack batteryStack = getOptionalInventory().get().getStack(slot); + if (batteryStack.isEmpty()) { + return; + } + + if (Energy.valid(batteryStack)) { + Energy.of(batteryStack).into(Energy.of(this)).move(); + } + } + + /** + * Charge battery placed inside inventory slot from machine + * + * @param slot int Slot ID for battery slot + */ + public void discharge(int slot) { + if (world == null) { + return; + } + + if (world.isClient) { + return; + } + + if (!getOptionalInventory().isPresent()){ + return; + } + + ItemStack batteryStack = getOptionalInventory().get().getStack(slot); + if (batteryStack.isEmpty()) { + return; + } + + if (Energy.valid(batteryStack)) { + Energy.of(this).into(Energy.of(batteryStack)).move(getTier().getMaxOutput()); + } + } + + /** + * Calculates the comparator output of a powered BE with the formula + * {@code ceil(blockEntity.getStored(EnergySide.UNKNOWN) * 15.0 / storage.getMaxPower())}. + * + * @param blockEntity the powered BE + * @return the calculated comparator output or 0 if {@code blockEntity} is not a {@code PowerAcceptorBlockEntity} + */ + public static int calculateComparatorOutputFromEnergy(@Nullable BlockEntity blockEntity) { + if (blockEntity instanceof PowerAcceptorBlockEntity) { + PowerAcceptorBlockEntity storage = (PowerAcceptorBlockEntity) blockEntity; + return MathHelper.ceil(storage.getStored(EnergySide.UNKNOWN) * 15.0 / storage.getMaxStoredPower()); + } else { + return 0; + } + } + + /** + * Check if machine should load energy data from NBT + * + * @return boolean Returns true if machine should load energy data from NBT + */ + protected boolean shouldHandleEnergyNBT() { + return true; + } + + /** + * Check if block entity can accept energy from a particular side + * + * @param side EnergySide Machine side + * @return boolean Returns true if machine can accept energy from side provided + */ + protected boolean canAcceptEnergy(EnergySide side){ + return true; + } + + /** + * Check if block entity can provide energy via a particular side + * + * @param side EnergySide Machine side + * @return boolean Returns true if machine can provide energy via particular side + */ + protected boolean canProvideEnergy(EnergySide side){ + return true; + } + + @Deprecated + public boolean canAcceptEnergy(Direction direction) { + return true; + } + + @Deprecated + public boolean canProvideEnergy(Direction direction) { + return true; + } + + /** + * Wrapper method used to sync additional energy storage values with client via BlockEntityScreenHandlerBuilder + * + * @return double Size of additional energy buffer + */ + public double getExtraPowerStorage(){ + return extraPowerStorage; + } + + /** + * Wrapper method used to sync additional energy storage values with client via BlockEntityScreenHandlerBuilder + * + * @param extraPowerStorage double Size of additional energy buffer + */ + public void setExtraPowerStorage(double extraPowerStorage) { + this.extraPowerStorage = extraPowerStorage; + } + + /** + * Wrapper method used to sync energy change values with client via BlockEntityScreenHandlerBuilder + * + * @return double Energy change per tick + */ + public double getPowerChange() { + return powerChange; + } + + /** + * Wrapper method used to sync energy change values with client via BlockEntityScreenHandlerBuilder + * + * @param powerChange double Energy change per tick + */ + public void setPowerChange(double powerChange) { + this.powerChange = powerChange; + } + + /** + * Wrapper method used to sync energy values with client via BlockEntityScreenHandlerBuilder + * + * @return double Energy stored in block entity + */ + + public double getEnergy() { + return getStored(EnergySide.UNKNOWN); + } + + /** + * Wrapper method used to sync energy values with client via BlockEntityScreenHandlerBuilder + * @param energy double Energy stored in block entity + */ + public void setEnergy(double energy) { + setStored(energy); + } + + /** + * Returns base size of internal Energy buffer of a particular machine before any upgrades applied + * + * @return double Size of internal Energy buffer + */ + public abstract double getBaseMaxPower(); + + /** + * Returns base output rate or zero if machine doesn't output energy + * + * @return double Output rate, E\t + */ + public abstract double getBaseMaxOutput(); + + /** + * Returns base input rate or zero if machine doesn't accept energy + * + * @return double Input rate, E\t + */ + public abstract double getBaseMaxInput(); + + // MachineBaseBlockEntity + @Override + public void tick() { + super.tick(); + if (world == null || world.isClient) { + return; + } + if (getStored(EnergySide.UNKNOWN) <= 0) { + return; + } + if (!isActive(RedstoneConfiguration.POWER_IO)) { + return; + } + + for (Direction side : Direction.values()) { + BlockEntity blockEntity = world.getBlockEntity(getPos().offset(side)); + if (blockEntity == null || !Energy.valid(blockEntity)) { + continue; + } + Energy.of(this) + .side(side) + .into(Energy.of(blockEntity).side(side.getOpposite())) + .move(); + } + + powerChange = getStored(EnergySide.UNKNOWN) - powerLastTick; + powerLastTick = getStored(EnergySide.UNKNOWN); + } + + @Override + public void fromTag(BlockState blockState, CompoundTag tag) { + super.fromTag(blockState, tag); + CompoundTag data = tag.getCompound("PowerAcceptor"); + if (shouldHandleEnergyNBT()) { + this.setStored(data.getDouble("energy")); + } + } + + @Override + public CompoundTag toTag(CompoundTag tag) { + super.toTag(tag); + CompoundTag data = new CompoundTag(); + data.putDouble("energy", getStored(EnergySide.UNKNOWN)); + tag.put("PowerAcceptor", data); + return tag; + } + + @Override + public void resetUpgrades() { + super.resetUpgrades(); + extraPowerStorage = 0; + extraTier = 0; + extraPowerInput = 0; + } + + // EnergyStorage + @Override + public double getStored(EnergySide face) { + return energy; + } + + @Override + public void setStored(double amount) { + this.energy = amount; + if(checkOverfill){ + this.energy = Math.max(Math.min(energy, getMaxStoredPower()), 0); + } + markDirty(); + } + + @Override + public double getMaxStoredPower() { + return getBaseMaxPower() + extraPowerStorage; + } + + @Override + public double getMaxOutput(EnergySide face) { + if (!isActive(RedstoneConfiguration.POWER_IO)) { + return 0; + } + if(!canProvideEnergy(face)) { + return 0; + } + if (this.extraTier > 0) { + return this.getTier().getMaxOutput(); + } + return getBaseMaxOutput(); + } + + @Override + public double getMaxInput(EnergySide face) { + if (!isActive(RedstoneConfiguration.POWER_IO)) { + return 0; + } + if (!canAcceptEnergy(face)) { + return 0; + } + if (this.extraTier > 0) { + return this.getTier().getMaxInput(); + } + return getBaseMaxInput() + extraPowerInput; + } + + @Override + public EnergyTier getTier() { + if (blockEntityPowerTier == null) { + checkTier(); + } + + if (extraTier > 0) { + for (EnergyTier enumTier : EnergyTier.values()) { + if (enumTier.ordinal() == blockEntityPowerTier.ordinal() + extraTier) { + return enumTier; + } + } + return EnergyTier.INFINITE; + } + return blockEntityPowerTier; + } + + // IListInfoProvider + @Override + public void addInfo(List info, boolean isReal, boolean hasData) { + if (!isReal && hasData) { + info.add( + new TranslatableText("reborncore.tooltip.energy") + .formatted(Formatting.GRAY) + .append(": ") + .append(PowerSystem.getLocalizedPower(energy)) + .formatted(Formatting.GOLD) + ); + } + + info.add( + new TranslatableText("reborncore.tooltip.energy.maxEnergy") + .formatted(Formatting.GRAY) + .append(": ") + .append(PowerSystem.getLocalizedPower(getMaxStoredPower())) + .formatted(Formatting.GOLD) + ); + + if (getMaxInput(EnergySide.UNKNOWN) != 0) { + info.add( + new TranslatableText("reborncore.tooltip.energy.inputRate") + .formatted(Formatting.GRAY) + .append(": ") + .append(PowerSystem.getLocalizedPower(getMaxInput(EnergySide.UNKNOWN))) + .formatted(Formatting.GOLD) + ); + } + if (getMaxOutput(EnergySide.UNKNOWN) > 0) { + info.add( + new TranslatableText("reborncore.tooltip.energy.outputRate") + .formatted(Formatting.GRAY) + .append(": ") + .append(PowerSystem.getLocalizedPower(getMaxOutput(EnergySide.UNKNOWN))) + .formatted(Formatting.GOLD) + ); + } + + info.add( + new TranslatableText("reborncore.tooltip.energy.tier") + .formatted(Formatting.GRAY) + .append(": ") + .append(StringUtils.toFirstCapitalAllLowercase(getTier().toString())) + .formatted(Formatting.GOLD) + ); + + if (isReal) { + info.add( + new TranslatableText("reborncore.tooltip.energy.change") + .formatted(Formatting.GRAY) + .append(": ") + .append(PowerSystem.getLocalizedPower(powerChange)) + .append("/t") + .formatted(Formatting.GOLD) + ); + } + + + + super.addInfo(info, isReal, hasData); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/powerSystem/PowerSystem.java b/RebornCore/src/main/java/reborncore/common/powerSystem/PowerSystem.java new file mode 100644 index 000000000..246f92384 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/powerSystem/PowerSystem.java @@ -0,0 +1,190 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.powerSystem; + +import net.fabricmc.api.EnvType; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import reborncore.common.RebornCoreConfig; + +import java.text.DecimalFormat; +import java.util.Arrays; +import java.util.Locale; +import java.util.function.Supplier; + +public class PowerSystem { + private static EnergySystem selectedSystem = EnergySystem.values()[0]; + + private static final char[] magnitude = new char[] { 'k', 'M', 'G', 'T' }; + + private static Locale locale = Locale.ROOT; + + public static String getLocalizedPower(double power) { + + return getRoundedString(power, selectedSystem.abbreviation, true); + } + + public static String getLocalizedPowerNoSuffix(double power) { + return getRoundedString(power, "", true); + } + + public static String getLocalizedPowerNoFormat(double power){ + return getRoundedString(power, selectedSystem.abbreviation, false); + } + + public static String getLocalizedPowerNoSuffixNoFormat(double power){ + return getRoundedString(power, "", false); + } + + public static String getLocalizedPowerFull(double power){ + return getFullPower(power, selectedSystem.abbreviation); + } + + public static String getLocalizedPowerFullNoSuffix(double power){ + return getFullPower(power, ""); + } + + private static String getFullPower(double power, String units){ + checkLocale(); + DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance(locale); + return formatter.format(power) + " " + units; + } + + private static String getRoundedString(double originalValue, String units, boolean doFormat) { + String ret = ""; + double value = 0f; + int i = 0; + boolean showMagnitude = true; + double euValue = originalValue; + if (euValue < 0) { + ret = "-"; + euValue = -euValue; + } + + if (euValue < 1000) { + doFormat = false; + showMagnitude = false; + value = euValue; + } else if (euValue >= 1000) { + for (i = 0; ; i++) { + if (euValue < 10000 && euValue % 1000 >= 100) { + value = Math.floor(euValue / 1000); + value += ((float) euValue % 1000) / 1000; + break; + } + euValue /= 1000; + if (euValue < 1000) { + value = euValue; + break; + } + } + } + + if (i > 10) { + doFormat = false; + showMagnitude = false; + } else if (i > 3) { + value = originalValue; + showMagnitude = false; + } + + if (doFormat){ + checkLocale(); + DecimalFormat formatter = (DecimalFormat) DecimalFormat.getInstance(locale); + ret += formatter.format(value); + int idx = ret.lastIndexOf(formatter.getDecimalFormatSymbols().getDecimalSeparator()); + if (idx > 0){ + ret = ret.substring(0, idx + 2); + } + } + else { + if (i>10){ + ret += "∞"; + } + else { + ret += value; + } + } + + if (showMagnitude) { + ret += magnitude[i]; + } + + if (!units.equals("")) { + ret += " " + units; + } + + return ret; + } + + public static EnergySystem getDisplayPower() { + if(!selectedSystem.enabled.get()){ + bumpPowerConfig(); + } + return selectedSystem; + } + + public static void bumpPowerConfig() { + int value = selectedSystem.ordinal() + 1; + if (value == EnergySystem.values().length) { + value = 0; + } + selectedSystem = EnergySystem.values()[value]; + } + + public static void init(){ + selectedSystem = Arrays.stream(EnergySystem.values()).filter(energySystem -> energySystem.abbreviation.equalsIgnoreCase(RebornCoreConfig.selectedSystem)).findFirst().orElse(EnergySystem.values()[0]); + if(!selectedSystem.enabled.get()){ + bumpPowerConfig(); + } + } + + private static void checkLocale() { + if (FabricLoader.getInstance().getEnvironmentType() != EnvType.CLIENT) { return; } + MinecraftClient instance = MinecraftClient.getInstance(); + if (instance == null) { return; } + String strangeMcLang = instance.getLanguageManager().getLanguage().getCode(); + locale = Locale.forLanguageTag(strangeMcLang.substring(0, 2)); + } + + public enum EnergySystem { + EU(0xFF800600, "E", 141, 151, 0xFF670000); + + public int colour; + public int altColour; + public String abbreviation; + public int xBar; + public int yBar; + public Supplier enabled = () -> true; + + EnergySystem(int colour, String abbreviation, int xBar, int yBar, int altColour) { + this.colour = colour; + this.abbreviation = abbreviation; + this.xBar = xBar; + this.yBar = yBar; + this.altColour = altColour; + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/recipes/ExtendedRecipeRemainder.java b/RebornCore/src/main/java/reborncore/common/recipes/ExtendedRecipeRemainder.java new file mode 100644 index 000000000..f876357a1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/recipes/ExtendedRecipeRemainder.java @@ -0,0 +1,35 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.recipes; + +import net.minecraft.item.ItemStack; + +public interface ExtendedRecipeRemainder { + + default ItemStack getRemainderStack(ItemStack stack) { + return stack.getItem().hasRecipeRemainder() ? new ItemStack(stack.getItem().getRecipeRemainder()) : ItemStack.EMPTY; + } + +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/common/recipes/ICrafterSoundHanlder.java b/RebornCore/src/main/java/reborncore/common/recipes/ICrafterSoundHanlder.java new file mode 100644 index 000000000..d61768e71 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/recipes/ICrafterSoundHanlder.java @@ -0,0 +1,36 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.recipes; + +import net.minecraft.block.entity.BlockEntity; + +/** + * Created by Mark on 01/07/2017. + */ +public interface ICrafterSoundHanlder { + + void playSound(boolean firstRun, BlockEntity blockEntity); + +} diff --git a/RebornCore/src/main/java/reborncore/common/recipes/IRecipeInput.java b/RebornCore/src/main/java/reborncore/common/recipes/IRecipeInput.java new file mode 100644 index 000000000..deec907ff --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/recipes/IRecipeInput.java @@ -0,0 +1,36 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.recipes; + +import net.minecraft.item.ItemStack; + +import java.util.List; + +public interface IRecipeInput { + + ItemStack getItemStack(); + + List getAllStacks(); +} diff --git a/RebornCore/src/main/java/reborncore/common/recipes/IUpgradeHandler.java b/RebornCore/src/main/java/reborncore/common/recipes/IUpgradeHandler.java new file mode 100644 index 000000000..fc7297e78 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/recipes/IUpgradeHandler.java @@ -0,0 +1,46 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.recipes; + +/** + * This class isnt designed to be used by other mods, if you want to have upgrades have your + */ +public interface IUpgradeHandler { + + void resetSpeedMulti(); + + double getSpeedMultiplier(); + + void addPowerMulti(double amount); + + void resetPowerMulti(); + + double getPowerMultiplier(); + + double getEuPerTick(double baseEu); + + void addSpeedMulti(double amount); + +} diff --git a/RebornCore/src/main/java/reborncore/common/recipes/RCRecipeMethods.java b/RebornCore/src/main/java/reborncore/common/recipes/RCRecipeMethods.java new file mode 100644 index 000000000..1b32c545c --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/recipes/RCRecipeMethods.java @@ -0,0 +1,51 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.recipes; + +import net.minecraft.block.Block; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; + +/** + * Created by Prospector + */ +public abstract class RCRecipeMethods { + + static ItemStack getStack(Item item) { + return getStack(item, 1); + } + + static ItemStack getStack(Item item, int count) { + return getStack(item, count); + } + + static ItemStack getStack(Block block) { + return getStack(block, 1); + } + + static ItemStack getStack(Block block, int count) { + return getStack(block, count); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/recipes/RecipeCrafter.java b/RebornCore/src/main/java/reborncore/common/recipes/RecipeCrafter.java new file mode 100644 index 000000000..64f8db377 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/recipes/RecipeCrafter.java @@ -0,0 +1,417 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.recipes; + +import net.minecraft.block.BlockState; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.BlockPos; +import reborncore.RebornCore; +import reborncore.api.recipe.IRecipeCrafterProvider; +import reborncore.common.blocks.BlockMachineBase; +import reborncore.common.crafting.RebornRecipe; +import reborncore.common.crafting.RebornRecipeType; +import reborncore.common.crafting.ingredient.RebornIngredient; +import reborncore.common.util.ItemUtils; +import reborncore.common.util.RebornInventory; +import team.reborn.energy.Energy; +import team.reborn.energy.EnergySide; +import team.reborn.energy.EnergyStorage; + +import org.jetbrains.annotations.Nullable; +import java.util.ArrayList; +import java.util.Optional; + +/** + * Use this in your blockEntity entity to craft things + */ +public class RecipeCrafter implements IUpgradeHandler { + + /** + * This is the recipe type to use + */ + public RebornRecipeType recipeType; + + /** + * This is the parent blockEntity + */ + public BlockEntity blockEntity; + + /** + * This is the place to use the power from + */ + public EnergyStorage energy; + + public Optional parentUpgradeHandler = Optional.empty(); + + /** + * This is the amount of inputs that the setRecipe has + */ + public int inputs; + + /** + * This is the amount of outputs that the recipe has + */ + public int outputs; + + /** + * This is the inventory to use for the crafting + */ + public RebornInventory inventory; + + /** + * This is the list of the slots that the crafting logic should look for the + * input item stacks. + */ + public int[] inputSlots; + + /** + * This is the list for the slots that the crafting logic should look fot + * the output item stacks. + */ + public int[] outputSlots; + public RebornRecipe currentRecipe; + public int currentTickTime = 0; + public int currentNeededTicks = 1;// Set to 1 to stop rare crashes + + int ticksSinceLastChange; + + @Nullable + public static ICrafterSoundHanlder soundHanlder = (firstRun, blockEntity) -> { + }; + + public RecipeCrafter(RebornRecipeType recipeType, BlockEntity blockEntity, int inputs, int outputs, RebornInventory inventory, + int[] inputSlots, int[] outputSlots) { + this.recipeType = recipeType; + this.blockEntity = blockEntity; + if (blockEntity instanceof EnergyStorage) { + energy = (EnergyStorage) blockEntity; + } + if (blockEntity instanceof IUpgradeHandler) { + parentUpgradeHandler = Optional.of((IUpgradeHandler) blockEntity); + } + this.inputs = inputs; + this.outputs = outputs; + this.inventory = inventory; + this.inputSlots = inputSlots; + this.outputSlots = outputSlots; + if (!(blockEntity instanceof IRecipeCrafterProvider)) { + RebornCore.LOGGER.error(blockEntity.getClass().getName() + " does not use IRecipeCrafterProvider report this to the issue tracker!"); + } + } + + /** + * Call this on the blockEntity tick + */ + public void updateEntity() { + if (blockEntity.getWorld() == null || blockEntity.getWorld().isClient) { + return; + } + ticksSinceLastChange++; + // Force a has chanced every second + if (ticksSinceLastChange == 20) { + setInvDirty(true); + ticksSinceLastChange = 0; + setIsActive(); + } + // It will now look for new recipes. + if (currentRecipe == null && isInvDirty()) { + updateCurrentRecipe(); + } + if (currentRecipe != null) { + // If it doesn't have all the inputs reset + if (isInvDirty() && !hasAllInputs()) { + currentRecipe = null; + currentTickTime = 0; + setIsActive(); + } + // If it has reached the recipe tick time + if (currentRecipe != null && currentTickTime >= currentNeededTicks && hasAllInputs()) { + boolean canGiveInvAll = true; + // Checks to see if it can fit the output + for (int i = 0; i < currentRecipe.getOutputs().size(); i++) { + if (!canFitOutput(currentRecipe.getOutputs().get(i), outputSlots[i])) { + canGiveInvAll = false; + } + } + // The slots that have been filled + ArrayList filledSlots = new ArrayList<>(); + if (canGiveInvAll && currentRecipe.onCraft(blockEntity)) { + for (int i = 0; i < currentRecipe.getOutputs().size(); i++) { + // Checks it has not been filled + if (!filledSlots.contains(outputSlots[i])) { + // Fills the slot with the output stack + fitStack(currentRecipe.getOutputs().get(i).copy(), outputSlots[i]); + filledSlots.add(outputSlots[i]); + } + } + // This uses all the inputs + useAllInputs(); + // Reset + currentRecipe = null; + currentTickTime = 0; + updateCurrentRecipe(); + //Update active sate if the blockEntity isnt going to start crafting again + if (currentRecipe == null) { + setIsActive(); + } + } + } else if (currentRecipe != null && currentTickTime < currentNeededTicks) { + double useRequirement = getEuPerTick(currentRecipe.getPower()); + if (Energy.of(energy).use(useRequirement)) { + currentTickTime++; + if ((currentTickTime == 1 || currentTickTime % 20 == 0) && soundHanlder != null) { + soundHanlder.playSound(false, blockEntity); + } + } + } + } + setInvDirty(false); + } + + /** + * Checks that we have all inputs, can fit output and update max tick time and current tick time + */ + public void updateCurrentRecipe() { + currentTickTime = 0; + for (RebornRecipe recipe : recipeType.getRecipes(blockEntity.getWorld())) { + // This checks to see if it has all of the inputs + if (!hasAllInputs(recipe)) continue; + if (!recipe.canCraft(blockEntity)) continue; + + // This checks to see if it can fit all of the outputs + boolean hasOutputSpace = true; + for (int i = 0; i < recipe.getOutputs().size(); i++) { + if (!canFitOutput(recipe.getOutputs().get(i), outputSlots[i])) { + hasOutputSpace = false; + } + } + if (!hasOutputSpace) continue; + // Sets the current recipe then syncs + setCurrentRecipe(recipe); + this.currentNeededTicks = Math.max((int) (currentRecipe.getTime() * (1.0 - getSpeedMultiplier())), 1); + setIsActive(); + return; + } + setCurrentRecipe(null); + currentNeededTicks = 0; + setIsActive(); + } + + public boolean hasAllInputs() { + return hasAllInputs(currentRecipe); + } + + public boolean hasAllInputs(RebornRecipe recipeType) { + if (recipeType == null) { + return false; + } + for (RebornIngredient ingredient : recipeType.getRebornIngredients()) { + boolean hasItem = false; + for (int slot : inputSlots) { + if (ingredient.test(inventory.getStack(slot))) { + hasItem = true; + } + } + if (!hasItem) { + return false; + } + } + return true; + } + + public void useAllInputs() { + if (currentRecipe == null) { + return; + } + for (RebornIngredient ingredient : currentRecipe.getRebornIngredients()) { + for (int inputSlot : inputSlots) {// Uses all of the inputs + if (ingredient.test(inventory.getStack(inputSlot))) { + inventory.shrinkSlot(inputSlot, ingredient.getCount()); + break; + } + } + } + } + + public boolean canFitOutput(ItemStack stack, int slot) {// Checks to see if it can fit the stack + if (stack.isEmpty()) { + return true; + } + if (inventory.getStack(slot).isEmpty()) { + return true; + } + if (ItemUtils.isItemEqual(inventory.getStack(slot), stack, true, true)) { + return stack.getCount() + inventory.getStack(slot).getCount() <= stack.getMaxCount(); + } + return false; + } + + public void fitStack(ItemStack stack, int slot) {// This fits a stack into a slot + if (stack.isEmpty()) { + return; + } + if (inventory.getStack(slot).isEmpty()) {// If the slot is empty set the contents + inventory.setStack(slot, stack); + return; + } + if (ItemUtils.isItemEqual(inventory.getStack(slot), stack, true)) {// If the slot has stuff in + if (stack.getCount() + inventory.getStack(slot).getCount() <= stack.getMaxCount()) {// Check to see if it fits + ItemStack newStack = stack.copy(); + newStack.setCount(inventory.getStack(slot).getCount() + stack.getCount());// Sets + // the + // new + // stack + // size + inventory.setStack(slot, newStack); + } + } + } + + public void read(CompoundTag tag) { + CompoundTag data = tag.getCompound("Crater"); + + if (data.contains("currentTickTime")) { + currentTickTime = data.getInt("currentTickTime"); + } + + if (blockEntity != null && blockEntity.getWorld() != null && blockEntity.getWorld().isClient) { + blockEntity.getWorld().updateListeners(blockEntity.getPos(), + blockEntity.getWorld().getBlockState(blockEntity.getPos()), + blockEntity.getWorld().getBlockState(blockEntity.getPos()), 3); + } + } + + public void write(CompoundTag tag) { + + CompoundTag data = new CompoundTag(); + + data.putDouble("currentTickTime", currentTickTime); + + tag.put("Crater", data); + } + + private boolean isActive() { + return currentRecipe != null && energy.getStored(EnergySide.UNKNOWN) >= currentRecipe.getPower(); + } + + public boolean canCraftAgain() { + for (RebornRecipe recipe : recipeType.getRecipes(blockEntity.getWorld())) { + if (recipe.canCraft(blockEntity) && hasAllInputs(recipe)) { + for (int i = 0; i < recipe.getOutputs().size(); i++) { + if (!canFitOutput(recipe.getOutputs().get(i), outputSlots[i])) { + return false; + } + } + return !(energy.getStored(EnergySide.UNKNOWN) < recipe.getPower()); + } + } + return false; + } + + public void setIsActive() { + BlockPos pos = blockEntity.getPos(); + if (blockEntity.getWorld() == null) return; + BlockState oldState = blockEntity.getWorld().getBlockState(pos); + if (oldState.getBlock() instanceof BlockMachineBase) { + BlockMachineBase blockMachineBase = (BlockMachineBase) oldState.getBlock(); + boolean isActive = isActive() || canCraftAgain(); + + if (isActive == oldState.get(BlockMachineBase.ACTIVE)) { + return; + } + + blockMachineBase.setActive(isActive, blockEntity.getWorld(), pos); + blockEntity.getWorld().updateListeners(pos, oldState, blockEntity.getWorld().getBlockState(pos), 3); + } + } + + public void setCurrentRecipe(RebornRecipe recipe) { + this.currentRecipe = recipe; + } + + public boolean isInvDirty() { + return inventory.hasChanged(); + } + + public void setInvDirty(boolean isDiry) { + inventory.setChanged(isDiry); + } + + public boolean isStackValidInput(ItemStack stack) { + if (stack.isEmpty()) { + return false; + } + + //Test with a stack with the max stack size as some independents will check the stacksize. Bit of a hack but should work. + ItemStack largeStack = stack.copy(); + largeStack.setCount(largeStack.getMaxCount()); + for (RebornRecipe recipe : recipeType.getRecipes(blockEntity.getWorld())) { + for (RebornIngredient ingredient : recipe.getRebornIngredients()) { + if (ingredient.test(largeStack)) { + return true; + } + } + } + return false; + } + + @Override + public void resetSpeedMulti() { + parentUpgradeHandler.ifPresent(IUpgradeHandler::resetSpeedMulti); + } + + @Override + public double getSpeedMultiplier() { + return Math.min(parentUpgradeHandler.map(IUpgradeHandler::getSpeedMultiplier).orElse(0D), 0.975); + } + + @Override + public void addPowerMulti(double amount) { + parentUpgradeHandler.ifPresent(iUpgradeHandler -> iUpgradeHandler.addPowerMulti(amount)); + } + + @Override + public void resetPowerMulti() { + parentUpgradeHandler.ifPresent(IUpgradeHandler::resetPowerMulti); + } + + @Override + public double getPowerMultiplier() { + return parentUpgradeHandler.map(IUpgradeHandler::getPowerMultiplier).orElse(1D); + } + + @Override + public double getEuPerTick(double baseEu) { + double power = parentUpgradeHandler.map(iUpgradeHandler -> iUpgradeHandler.getEuPerTick(baseEu)).orElse(1D); + return Math.min(power, energy.getMaxStoredPower()); + } + + @Override + public void addSpeedMulti(double amount) { + parentUpgradeHandler.ifPresent(iUpgradeHandler -> iUpgradeHandler.addSpeedMulti(amount)); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ArrayUtils.java b/RebornCore/src/main/java/reborncore/common/util/ArrayUtils.java new file mode 100644 index 000000000..18b608589 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ArrayUtils.java @@ -0,0 +1,49 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import java.util.Collection; +import java.util.Locale; + +/** + * Created by covers1624 on 3/27/2016. + */ +public class ArrayUtils { + + public static String[] arrayToLowercase(String[] array) { + String[] copy = new String[array.length]; + for (int i = 0; i < array.length; i++) { + copy[i] = array[i].toLowerCase(Locale.ROOT).intern(); + } + return copy; + } + + public static Collection addAll(Collection dest, Collection... src) { + for (Collection c : src) { + dest.addAll(c); + } + return dest; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/BiObseravable.java b/RebornCore/src/main/java/reborncore/common/util/BiObseravable.java new file mode 100644 index 000000000..4672ee41b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/BiObseravable.java @@ -0,0 +1,77 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; + +import java.util.LinkedList; +import java.util.List; +import java.util.Objects; +import java.util.function.BiConsumer; + +public class BiObseravable { + @Nullable + private A a; + @Nullable + private B b; + + private final List> listeners = new LinkedList<>(); + + public void pushA(A a) { + this.a = a; + fireListeners(); + } + + public void pushB(B b) { + this.b = b; + fireListeners(); + } + + @NotNull + public A getA() { + Objects.requireNonNull(a); + return a; + } + + @NotNull + public B getB() { + Objects.requireNonNull(b); + return b; + } + + private void fireListeners() { + if (a == null || b == null) { + return; + } + for (BiConsumer listener : listeners) { + listener.accept(a, b); + } + } + + public void listen(@NotNull BiConsumer<@NotNull A, @NotNull B> consumer) { + listeners.add(consumer); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/BooleanFunction.java b/RebornCore/src/main/java/reborncore/common/util/BooleanFunction.java new file mode 100644 index 000000000..087349046 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/BooleanFunction.java @@ -0,0 +1,31 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +@FunctionalInterface +public interface BooleanFunction { + + boolean get(T type); +} diff --git a/RebornCore/src/main/java/reborncore/common/util/CalenderUtils.java b/RebornCore/src/main/java/reborncore/common/util/CalenderUtils.java new file mode 100644 index 000000000..be84df257 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/CalenderUtils.java @@ -0,0 +1,52 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import reborncore.RebornCore; + +import java.util.Calendar; + +/** + * Created by Mark on 27/11/2016. + */ +public class CalenderUtils { + + public static boolean christmas; + + public static void loadCalender() { + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(System.currentTimeMillis()); + + int day = calendar.get(Calendar.DAY_OF_MONTH); + int month = calendar.get(Calendar.MONTH) + 1; //Java months start at 0 + if (month == 12) { + if (day >= 24 && day <= 26) { + christmas = true; + RebornCore.LOGGER.info("Merry christmas from reborn core! :)"); + } + } + + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ChatUtils.java b/RebornCore/src/main/java/reborncore/common/util/ChatUtils.java new file mode 100644 index 000000000..d10daaaef --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ChatUtils.java @@ -0,0 +1,59 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.fabricmc.api.EnvType; +import net.fabricmc.api.Environment; +import net.fabricmc.loader.api.FabricLoader; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.gui.hud.ChatHud; +import net.minecraft.text.Text; +import reborncore.mixin.client.AccessorChatHud; + +/** + * Class stolen from SteamAgeRevolution, which I stole from BloodMagic, which was stolen from EnderCore, which stole the + * idea from ExtraUtilities, who stole it from vanilla. + *

+ * Original class link: + * https://github.com/SleepyTrousers/EnderCore/blob/master/src/main/java/com/enderio/core/common/util/ChatUtil.java + */ + +public class ChatUtils { + private static final int DELETION_ID = 1337; //MAKE THIS UNIQUE PER MOD THAT USES THIS + + public static void sendNoSpamMessages(int messageID, Text message) { + if (FabricLoader.getInstance().getEnvironmentType() == EnvType.CLIENT) { + sendNoSpamMessage(messageID, message); + } + } + + @Environment(EnvType.CLIENT) + private static void sendNoSpamMessage(int messageID, Text message) { + int deleteID = DELETION_ID + messageID; + ChatHud chat = MinecraftClient.getInstance().inGameHud.getChatHud(); + AccessorChatHud accessorChatHud = (AccessorChatHud) chat; + accessorChatHud.invokeAddMessage(message, deleteID); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/Color.java b/RebornCore/src/main/java/reborncore/common/util/Color.java new file mode 100644 index 000000000..f4aeddcce --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/Color.java @@ -0,0 +1,73 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +//A basic color class that is used in place of the AWT color class as it cannot be used with lwjgl 3 +public class Color { + + public final static Color WHITE = new Color(255, 255, 255); + public final static Color RED = new Color(255, 0, 0); + public final static Color GREEN = new Color(0, 255, 0); + public final static Color BLUE = new Color(0, 0, 255); + + private final int color; + + public Color(int r, int g, int b, int a) { + color = ((a & 0xFF) << 24) | ((r & 0xFF) << 16) | ((g & 0xFF) << 8) | ((b & 0xFF)); + } + + public Color(int r, int g, int b) { + this(r, g, b, 255); + } + + public Color(float r, float g, float b) { + this((int) (r * 255 + 0.5), (int) (g * 255 + 0.5), (int) (b * 255 + 0.5)); + } + + public int getColor() { + return color; + } + + public int getRed() { + return (getColor() >> 16) & 0xFF; + } + + public int getGreen() { + return (getColor() >> 8) & 0xFF; + } + + public int getBlue() { + return getColor() & 0xFF; + } + + public int getAlpha() { + return (getColor() >> 24) & 0xff; + } + + public Color darker() { + double amount = 0.7; + return new Color((int) (getRed() * amount), (int) (getGreen() * amount), (int) (getBlue() * amount), getAlpha()); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/DefaultedListCollector.java b/RebornCore/src/main/java/reborncore/common/util/DefaultedListCollector.java new file mode 100644 index 000000000..a20666ee9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/DefaultedListCollector.java @@ -0,0 +1,74 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.util.collection.DefaultedList; + +import java.util.Collections; +import java.util.EnumSet; +import java.util.Set; +import java.util.function.BiConsumer; +import java.util.function.BinaryOperator; +import java.util.function.Function; +import java.util.function.Supplier; +import java.util.stream.Collector; + +//Taken from https://github.com/The-Acronym-Coders/BASE/blob/develop/1.12.0/src/main/java/com/teamacronymcoders/base/util/collections/NonnullListCollector.java, thanks for this ;) +public class DefaultedListCollector implements Collector, DefaultedList> { + + private final Set CH_ID = Collections.unmodifiableSet(EnumSet.of(Characteristics.IDENTITY_FINISH)); + + public static DefaultedListCollector toList() { + return new DefaultedListCollector<>(); + } + + @Override + public Supplier> supplier() { + return DefaultedList::of; + } + + @Override + public BiConsumer, T> accumulator() { + return DefaultedList::add; + } + + @Override + public BinaryOperator> combiner() { + return (left, right) -> { + left.addAll(right); + return left; + }; + } + + @Override + public Function, DefaultedList> finisher() { + return i -> (DefaultedList) i; + } + + @Override + public Set characteristics() { + return CH_ID; + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/common/util/EasingFunctions.java b/RebornCore/src/main/java/reborncore/common/util/EasingFunctions.java new file mode 100644 index 000000000..e222a9ed9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/EasingFunctions.java @@ -0,0 +1,98 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +/* + * Easing Functions - taken from https://gist.github.com/gre/1650294 + * only considering the t value for the range [0, 1] => [0, 1] + */ +public class EasingFunctions { + + // no easing, no acceleration + public double linear(double t) { + return t; + } + + // accelerating from zero velocity + public double easeInQuad(double t) { + return t * t; + } + + // decelerating to zero velocity + public double easeOutQuad(double t) { + return t * (2 - t); + } + + // acceleration until halfway, then deceleration + public double easeInOutQuad(double t) { + return t < .5 ? 2 * t * t : -1 + (4 - 2 * t) * t; + } + + // accelerating from zero velocity + public double easeInCubic(double t) { + return t * t * t; + } + + // decelerating to zero velocity + public double easeOutCubic(double t) { + return (--t) * t * t + 1; + } + + // acceleration until halfway, then deceleration + public double easeInOutCubic(double t) { + return t < .5 ? 4 * t * t * t : (t - 1) * (2 * t - 2) * (2 * t - 2) + 1; + } + + // accelerating from zero velocity + public double easeInQuart(double t) { + return t * t * t * t; + } + + // decelerating to zero velocity + public double easeOutQuart(double t) { + return 1 - (--t) * t * t * t; + } + + // acceleration until halfway, then deceleration + public double easeInOutQuart(double t) { + return t < .5 ? 8 * t * t * t * t : 1 - 8 * (--t) * t * t * t; + } + + // accelerating from zero velocity + public double easeInQuint(double t) { + return t * t * t * t * t; + } + + // decelerating to zero velocity + public double easeOutQuint(double t) { + return 1 + (--t) * t * t * t * t; + } + + // acceleration until halfway, then deceleration + public double easeInOutQuint(double t) { + return t < .5 ? 16 * t * t * t * t * t : 1 + 16 * (--t) * t * t * t * t; + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ExceptionUtils.java b/RebornCore/src/main/java/reborncore/common/util/ExceptionUtils.java new file mode 100644 index 000000000..f5fdd6d32 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ExceptionUtils.java @@ -0,0 +1,38 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +public class ExceptionUtils { + + public static void tryAndThrow(Runnable runnable, String message) throws RuntimeException { + try { + runnable.run(); + } catch (Throwable t) { + t.printStackTrace(); + throw new RuntimeException(message, t); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/GenericWrenchHelper.java b/RebornCore/src/main/java/reborncore/common/util/GenericWrenchHelper.java new file mode 100644 index 000000000..fafaafa3c --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/GenericWrenchHelper.java @@ -0,0 +1,59 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.util.registry.Registry; +import net.minecraft.world.World; +import reborncore.api.ICustomToolHandler; + +public class GenericWrenchHelper implements ICustomToolHandler { + + Identifier itemLocation; + boolean damage; + + public GenericWrenchHelper(Identifier itemLocation, boolean damage) { + this.itemLocation = itemLocation; + this.damage = damage; + } + + @Override + public boolean canHandleTool(ItemStack stack) { + return Registry.ITEM.getId(stack.getItem()).equals(itemLocation); + } + + @Override + public boolean handleTool(ItemStack stack, BlockPos pos, World world, PlayerEntity player, Direction side, boolean damage) { + if (this.damage && damage && !world.isClient) { + stack.damage(1, world.random, (ServerPlayerEntity) player); + } + return true; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/IDebuggable.java b/RebornCore/src/main/java/reborncore/common/util/IDebuggable.java new file mode 100644 index 000000000..fcc261064 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/IDebuggable.java @@ -0,0 +1,43 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.util.Formatting; + +public interface IDebuggable { + + String getDebugText(); + + + // Formatting helpers + static String propertyFormat(String property, String info){ + String s = "" + Formatting.GREEN; + s += property + ": "; + s += Formatting.RED; + s += info; + + return s; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/IInventoryAccess.java b/RebornCore/src/main/java/reborncore/common/util/IInventoryAccess.java new file mode 100644 index 000000000..30730117b --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/IInventoryAccess.java @@ -0,0 +1,40 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.Direction; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +public interface IInventoryAccess { + + boolean canHandleIO(int slotID, ItemStack stack, Direction face, AccessDirection direction, T blockEntity); + + enum AccessDirection { + INSERT, + EXTRACT + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/IdentifiableObject.java b/RebornCore/src/main/java/reborncore/common/util/IdentifiableObject.java new file mode 100644 index 000000000..6a2890186 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/IdentifiableObject.java @@ -0,0 +1,68 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.util.Identifier; +import org.jetbrains.annotations.NotNull; + +import java.util.Objects; + +public class IdentifiableObject { + @NotNull + private final T object; + @NotNull + private final Identifier identifier; + + public IdentifiableObject(@NotNull T object, @NotNull Identifier identifier) { + Objects.requireNonNull(object); + Objects.requireNonNull(identifier); + this.object = object; + this.identifier = identifier; + } + + @NotNull + public T getObject() { + return object; + } + + @NotNull + public Identifier getIdentifier() { + return identifier; + } + + @Override + public boolean equals(Object o) { + if (this == o) return true; + if (o == null || getClass() != o.getClass()) return false; + IdentifiableObject that = (IdentifiableObject) o; + return object.equals(that.object) && + identifier.equals(that.identifier); + } + + @Override + public int hashCode() { + return Objects.hash(object, identifier); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/InventoryItem.java b/RebornCore/src/main/java/reborncore/common/util/InventoryItem.java new file mode 100644 index 000000000..812886781 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/InventoryItem.java @@ -0,0 +1,133 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import org.apache.commons.lang3.Validate; +import reborncore.api.items.InventoryBase; + +import org.jetbrains.annotations.NotNull; +import java.util.List; +import java.util.stream.Collectors; +import java.util.stream.IntStream; + +public class InventoryItem extends InventoryBase { + + @NotNull + ItemStack stack; + int size; + + private InventoryItem( + @NotNull + ItemStack stack, int size) { + super(size); + Validate.notNull(stack); + Validate.isTrue(!stack.isEmpty()); + this.size = size; + this.stack = stack; + } + + public static InventoryItem getItemInvetory(ItemStack stack, int size) { + return new InventoryItem(stack, size); + } + + public ItemStack getStack() { + return stack; + } + + public CompoundTag getInvData() { + Validate.isTrue(!stack.isEmpty()); + if (!stack.hasTag()) { + stack.setTag(new CompoundTag()); + } + if (!stack.getTag().contains("inventory")) { + stack.getTag().put("inventory", new CompoundTag()); + } + return stack.getTag().getCompound("inventory"); + } + + public CompoundTag getSlotData(int slot) { + validateSlotIndex(slot); + CompoundTag invData = getInvData(); + if (!invData.contains("slot_" + slot)) { + invData.put("slot_" + slot, new CompoundTag()); + } + return invData.getCompound("slot_" + slot); + } + + public void setSlotData(int slot, CompoundTag tagCompound) { + validateSlotIndex(slot); + Validate.notNull(tagCompound); + CompoundTag invData = getInvData(); + invData.put("slot_" + slot, tagCompound); + } + + public List getAllStacks() { + return IntStream.range(0, size) + .mapToObj(this::getStack) + .collect(Collectors.toList()); + } + + public int getSlots() { + return size; + } + + @NotNull + @Override + public ItemStack getStack(int slot) { + return ItemStack.fromTag(getSlotData(slot)); + } + + @Override + public void setStack(int slot, + @NotNull + ItemStack stack) { + setSlotData(slot, stack.toTag(new CompoundTag())); + } + + public int getSlotLimit(int slot) { + return 64; + } + + public void validateSlotIndex(int slot) { + if (slot < 0 || slot >= size) { + throw new RuntimeException("Slot " + slot + " not in valid range - [0," + size + ")"); + } + + } + + public int getStackLimit(int slot, + @NotNull + ItemStack stack) { + return Math.min(getSlotLimit(slot), stack.getMaxCount()); + } + + @Override + public boolean isValid(int slot, ItemStack stack) { + return true; + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ItemDurabilityExtensions.java b/RebornCore/src/main/java/reborncore/common/util/ItemDurabilityExtensions.java new file mode 100644 index 000000000..c38ebc9ee --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ItemDurabilityExtensions.java @@ -0,0 +1,43 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.item.ItemStack; + +public interface ItemDurabilityExtensions { + + default double getDurability(ItemStack stack) { + return 0; + } + + default boolean showDurability(ItemStack stack) { + return false; + } + + default int getDurabilityColor(ItemStack stack) { + return 0; + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ItemHandlerUtils.java b/RebornCore/src/main/java/reborncore/common/util/ItemHandlerUtils.java new file mode 100644 index 000000000..c474f2ff0 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ItemHandlerUtils.java @@ -0,0 +1,70 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.block.FluidBlock; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.inventory.Inventory; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.util.ItemScatterer; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; +import reborncore.api.blockentity.IUpgradeable; + +public class ItemHandlerUtils { + + public static void dropContainedItems(World world, BlockPos pos) { + BlockEntity blockEntity = world.getBlockEntity(pos); + if (blockEntity == null) { + return; + } + if (blockEntity instanceof Inventory) { + Inventory inventory = (Inventory) blockEntity; + dropItemHandler(world, pos, inventory); + } + if (blockEntity instanceof IUpgradeable) { + dropItemHandler(world, pos, ((IUpgradeable) blockEntity).getUpgradeInvetory()); + } + } + + public static void dropItemHandler(World world, BlockPos pos, Inventory inventory) { + for (int i = 0; i < inventory.size(); i++) { + ItemStack itemStack = inventory.getStack(i); + if (itemStack.isEmpty()) { + continue; + } + if (itemStack.getCount() > 0) { + if (itemStack.getItem() instanceof BlockItem) { + if (((BlockItem) itemStack.getItem()).getBlock() instanceof FluidBlock) { + continue; + } + } + } + ItemScatterer.spawn(world, pos.getX(), pos.getY(), + pos.getZ(), itemStack); + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ItemNBTHelper.java b/RebornCore/src/main/java/reborncore/common/util/ItemNBTHelper.java new file mode 100644 index 000000000..4d116706e --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ItemNBTHelper.java @@ -0,0 +1,165 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.ListTag; + +public class ItemNBTHelper { + + /** + * Checks if an ItemStack has a Tag Compound + **/ + public static boolean detectNBT(ItemStack stack) { + return stack.hasTag(); + } + + /** + * Tries to initialize an NBT Tag Compound in an ItemStack, this will not do + * anything if the stack already has a tag compound + **/ + public static void initNBT(ItemStack stack) { + if (!detectNBT(stack)) { + injectNBT(stack, new CompoundTag()); + } + } + + /** + * Injects an NBT Tag Compound to an ItemStack, no checks are made + * previously + **/ + public static void injectNBT(ItemStack stack, CompoundTag nbt) { + stack.setTag(nbt); + } + + /** + * Gets the NBTTagCompound in an ItemStack. Tries to init it previously in + * case there isn't one present + **/ + public static CompoundTag getNBT(ItemStack stack) { + initNBT(stack); + return stack.getTag(); + } + + // SETTERS + // /////////////////////////////////////////////////////////////////// + + public static void setBoolean(ItemStack stack, String tag, boolean b) { + getNBT(stack).putBoolean(tag, b); + } + + public static void setByte(ItemStack stack, String tag, byte b) { + getNBT(stack).putByte(tag, b); + } + + public static void setShort(ItemStack stack, String tag, short s) { + getNBT(stack).putShort(tag, s); + } + + public static void setInt(ItemStack stack, String tag, int i) { + getNBT(stack).putInt(tag, i); + } + + public static void setLong(ItemStack stack, String tag, long l) { + getNBT(stack).putLong(tag, l); + } + + public static void setFloat(ItemStack stack, String tag, float f) { + getNBT(stack).putFloat(tag, f); + } + + public static void setDouble(ItemStack stack, String tag, double d) { + getNBT(stack).putDouble(tag, d); + } + + public static void setCompound(ItemStack stack, String tag, CompoundTag cmp) { + if (!tag.equalsIgnoreCase("ench")) // not override the enchantments + { + getNBT(stack).put(tag, cmp); + } + } + + public static void setString(ItemStack stack, String tag, String s) { + getNBT(stack).putString(tag, s); + } + + public static void setList(ItemStack stack, String tag, ListTag list) { + getNBT(stack).put(tag, list); + } + + // GETTERS + // /////////////////////////////////////////////////////////////////// + + public static boolean verifyExistance(ItemStack stack, String tag) { + return !stack.isEmpty() && getNBT(stack).contains(tag); + } + + public static boolean getBoolean(ItemStack stack, String tag, boolean defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getBoolean(tag) : defaultExpected; + } + + public static byte getByte(ItemStack stack, String tag, byte defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getByte(tag) : defaultExpected; + } + + public static short getShort(ItemStack stack, String tag, short defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getShort(tag) : defaultExpected; + } + + public static int getInt(ItemStack stack, String tag, int defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getInt(tag) : defaultExpected; + } + + public static long getLong(ItemStack stack, String tag, long defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getLong(tag) : defaultExpected; + } + + public static float getFloat(ItemStack stack, String tag, float defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getFloat(tag) : defaultExpected; + } + + public static double getDouble(ItemStack stack, String tag, double defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getDouble(tag) : defaultExpected; + } + + /** + * If nullifyOnFail is true it'll return null if it doesn't find any + * compounds, otherwise it'll return a new one. + **/ + public static CompoundTag getCompound(ItemStack stack, String tag, boolean nullifyOnFail) { + return verifyExistance(stack, tag) ? getNBT(stack).getCompound(tag) + : nullifyOnFail ? null : new CompoundTag(); + } + + public static String getString(ItemStack stack, String tag, String defaultExpected) { + return verifyExistance(stack, tag) ? getNBT(stack).getString(tag) : defaultExpected; + } + + public static ListTag getList(ItemStack stack, String tag, int objtype, boolean nullifyOnFail) { + return verifyExistance(stack, tag) ? getNBT(stack).getList(tag, objtype) + : nullifyOnFail ? null : new ListTag(); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ItemUsageContextCustomStack.java b/RebornCore/src/main/java/reborncore/common/util/ItemUsageContextCustomStack.java new file mode 100644 index 000000000..5a9347704 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ItemUsageContextCustomStack.java @@ -0,0 +1,41 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.util.Hand; +import net.minecraft.util.hit.BlockHitResult; +import net.minecraft.world.World; + +import org.jetbrains.annotations.Nullable; + +public class ItemUsageContextCustomStack extends ItemUsageContext { + + public ItemUsageContextCustomStack(World world, @Nullable PlayerEntity player, Hand hand, ItemStack stack, BlockHitResult hit) { + super(world, player, hand, stack, hit); + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/ItemUtils.java b/RebornCore/src/main/java/reborncore/common/util/ItemUtils.java new file mode 100644 index 000000000..f7942ed48 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/ItemUtils.java @@ -0,0 +1,239 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.text.Text; +import net.minecraft.text.TranslatableText; +import net.minecraft.util.Formatting; +import reborncore.common.recipes.IRecipeInput; +import team.reborn.energy.Energy; + +import java.util.List; +import java.util.function.Predicate; + +/** + * Created by mark on 12/04/15. + */ +public class ItemUtils { + + public static boolean isItemEqual(final ItemStack a, final ItemStack b, + final boolean matchNBT) { + if (a.isEmpty() || b.isEmpty()) { + return false; + } + if (a.getItem() != b.getItem()) { + return false; + } + return !matchNBT || ItemStack.areTagsEqual(a, b); + } + + public static boolean isItemEqual(ItemStack a, ItemStack b, boolean matchNBT, + boolean useTags) { + if (a.isEmpty() && b.isEmpty()) { + return true; + } + if (isItemEqual(a, b, matchNBT)) { + return true; + } + if (a.isEmpty() || b.isEmpty()) { + return false; + } + if (useTags) { + + //TODO tags + } + return false; + } + + //TODO tags + public static boolean isInputEqual(Object input, ItemStack other, boolean matchNBT, + boolean useTags) { + if (input instanceof ItemStack) { + return isItemEqual((ItemStack) input, other, matchNBT, useTags); + } else if (input instanceof String) { + //TODO tags + } else if (input instanceof IRecipeInput) { + List inputs = ((IRecipeInput) input).getAllStacks(); + for (ItemStack stack : inputs) { + if (isItemEqual(stack, other, matchNBT, false)) { + return true; + } + } + } + return false; + } + + public static void writeItemToNBT(ItemStack stack, CompoundTag data) { + if (stack.isEmpty() || stack.getCount() <= 0) { + return; + } + if (stack.getCount() > 127) { + stack.setCount(127); + } + stack.toTag(data); + } + + public static ItemStack readItemFromNBT(CompoundTag data) { + return ItemStack.fromTag(data); + } + + public static double getPowerForDurabilityBar(ItemStack stack) { + if (stack.isEmpty()) { + return 0.0; + } + + if (!Energy.valid(stack)) { + return 0.0; + } + + return Energy.of(stack).getEnergy() / Energy.of(stack).getMaxStored(); + } + + /** + * Checks if powered item is active + * + * @param stack ItemStack ItemStack to check + * @return True if powered item is active + */ + public static boolean isActive(ItemStack stack) { + return !stack.isEmpty() && stack.getTag() != null && stack.getTag().getBoolean("isActive"); + } + + /** + * Check if powered item has enough energy to continue being in active state + * + * @param stack ItemStack ItemStack to check + * @param cost int Cost of operation performed by tool + * @param isClient boolean Client side + * @param messageId int MessageID for sending no spam message + */ + public static void checkActive(ItemStack stack, int cost, boolean isClient, int messageId) { + if (!ItemUtils.isActive(stack)) { + return; + } + if (Energy.of(stack).getEnergy() >= cost) { + return; + } + if (isClient) { + ChatUtils.sendNoSpamMessages(messageId, new TranslatableText("reborncore.message.energyError") + .formatted(Formatting.GRAY) + .append(" ") + .append( + new TranslatableText("reborncore.message.deactivating") + .formatted(Formatting.GOLD) + ) + ); + } + stack.getOrCreateTag().putBoolean("isActive", false); + } + + /** + * Switch active\inactive state for powered item + * + * @param stack ItemStack ItemStack to work on + * @param cost int Cost of operation performed by tool + * @param isClient boolean Are we on client side + * @param messageId MessageID for sending no spam message + */ + public static void switchActive(ItemStack stack, int cost, boolean isClient, int messageId) { + ItemUtils.checkActive(stack, cost, isClient, messageId); + + if (!ItemUtils.isActive(stack)) { + stack.getOrCreateTag().putBoolean("isActive", true); + if (isClient) { + + + ChatUtils.sendNoSpamMessages(messageId, new TranslatableText("reborncore.message.setTo") + .formatted(Formatting.GRAY) + .append(" ") + .append( + new TranslatableText("reborncore.message.active") + .formatted(Formatting.GOLD) + ) + ); + } + } else { + stack.getOrCreateTag().putBoolean("isActive", false); + if (isClient) { + ChatUtils.sendNoSpamMessages(messageId, new TranslatableText("reborncore.message.setTo") + .formatted(Formatting.GRAY) + .append(" ") + .append( + new TranslatableText("reborncore.message.inactive") + .formatted(Formatting.GOLD) + ) + ); + } + } + } + + /** + * Adds active\inactive state to powered item tooltip + * + * @param stack ItemStack ItemStack to check + * @param tooltip List Tooltip strings + */ + public static void buildActiveTooltip(ItemStack stack, List tooltip) { + if (!ItemUtils.isActive(stack)) { + tooltip.add(new TranslatableText("reborncore.message.inactive").formatted(Formatting.RED)); + } else { + tooltip.add(new TranslatableText("reborncore.message.active").formatted(Formatting.GREEN)); + } + } + + /** + * Output energy from item to other items in inventory + * + * @param player PlayerEntity having powered item + * @param itemStack ItemStack Powered item + * @param maxOutput int Maximum output rate of powered item + */ + public static void distributePowerToInventory(PlayerEntity player, ItemStack itemStack, int maxOutput) { + distributePowerToInventory(player, itemStack, maxOutput, (stack) -> true); + } + + public static void distributePowerToInventory(PlayerEntity player, ItemStack itemStack, int maxOutput, Predicate filter) { + if (!Energy.valid(itemStack)) { + return; + } + + for (int i = 0; i < player.inventory.size(); i++) { + ItemStack invStack = player.inventory.getStack(i); + + if (invStack.isEmpty() || !filter.test(invStack)) { + continue; + } + + if (Energy.valid(invStack)) { + Energy.of(itemStack) + .into(Energy.of(invStack)) + .move(maxOutput); + } + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/MachineFacing.java b/RebornCore/src/main/java/reborncore/common/util/MachineFacing.java new file mode 100644 index 000000000..69633cefd --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/MachineFacing.java @@ -0,0 +1,77 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.util.math.Direction; +import reborncore.common.blockentity.MachineBaseBlockEntity; + +public enum MachineFacing { + FRONT, + BACK, + UP, + DOWN, + LEFT, + RIGHT; + + public Direction getFacing(MachineBaseBlockEntity machineBase) { + if (this == FRONT) { + return machineBase.getFacing(); + } + if (this == BACK) { + return machineBase.getFacing().getOpposite(); + } + if (this == RIGHT) { + //North -> West + int i = machineBase.getFacing().getOpposite().getHorizontal() + 1; + if (i > 3) { + i = 0; + } + if (i < 0) { + i = 3; + } + return Direction.fromHorizontal(i); + } + if (this == LEFT) { + //North -> East + int i = machineBase.getFacing().getOpposite().getHorizontal() - 1; + if (i > 3) { + i = 0; + } + if (i < 0) { + i = 3; + } + return Direction.fromHorizontal(i); + } + if (this == UP) { + return Direction.UP; + } + if (this == DOWN) { + return Direction.DOWN; + } + + return Direction.NORTH; + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/NBTSerializable.java b/RebornCore/src/main/java/reborncore/common/util/NBTSerializable.java new file mode 100644 index 000000000..fe0976ab1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/NBTSerializable.java @@ -0,0 +1,38 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.nbt.CompoundTag; + +import org.jetbrains.annotations.NotNull; + +public interface NBTSerializable { + + @NotNull + CompoundTag write(); + + void read(@NotNull CompoundTag tag); + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/RebornInventory.java b/RebornCore/src/main/java/reborncore/common/util/RebornInventory.java new file mode 100644 index 000000000..3f6e57919 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/RebornInventory.java @@ -0,0 +1,168 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.math.Direction; +import reborncore.api.items.InventoryBase; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.blockentity.SlotConfiguration; + +import org.jetbrains.annotations.NotNull; + +public class RebornInventory extends InventoryBase { + + private final String name; + private final int stackLimit; + private final T blockEntity; + private boolean hasChanged = false; + private final IInventoryAccess inventoryAccess; + + public RebornInventory(int size, String invName, int invStackLimit, T blockEntity, IInventoryAccess access) { + super(size); + name = invName; + stackLimit = (invStackLimit == 64 ? Items.AIR.getMaxCount() : invStackLimit); //Blame asie for this + this.blockEntity = blockEntity; + this.inventoryAccess = access; + } + + //If you are using this with a machine, dont forget to set .withConfiguredAccess() + public RebornInventory(int size, String invName, int invStackLimit, T blockEntity) { + this(size, invName, invStackLimit, blockEntity, (slotID, stack, facing, direction, be) -> { + if (facing == null) { + return true; + } + switch (direction) { + case INSERT: + return SlotConfiguration.canInsertItem(slotID, stack, facing, be); + case EXTRACT: + return SlotConfiguration.canExtractItem(slotID, stack, facing, be); + } + return false; + }); + } + + public String getName() { + return name; + } + + @Override + public void setStack(int slot, @NotNull ItemStack stack) { + super.setStack(slot, stack); + setChanged(); + } + + @Override + public ItemStack removeStack(int i, int i1) { + ItemStack stack = super.removeStack(i, i1); + + if (!stack.isEmpty()) { + setChanged(); + } + + return stack; + } + + @Override + public int getMaxCountPerStack() { + return stackLimit; + } + + public ItemStack shrinkSlot(int slot, int count) { + ItemStack stack = getStack(slot); + stack.decrement(count); + setChanged(); + return stack; + } + + + public RebornInventory getExternal(Direction facing) { + throw new UnsupportedOperationException("needs fixing"); + //return externalInventory.withFacing(facing); + } + + public void read(CompoundTag data) { + read(data, "Items"); + } + + public void read(CompoundTag data, String tag) { + CompoundTag nbttaglist = data.getCompound(tag); + deserializeNBT(nbttaglist); + hasChanged = true; + } + + public void write(CompoundTag data) { + write(data, "Items"); + } + + public void write(CompoundTag data, String tag) { + data.put(tag, serializeNBT()); + } + + + public int getContents() { + int count = 0; + for (ItemStack stack : getStacks()) { + if (stack.isEmpty()) { + continue; + } + count += stack.getCount(); + } + return count; + } + + public T getBlockEntity() { + return blockEntity; + } + + public boolean hasChanged() { + return hasChanged; + } + + public void setChanged() { + this.hasChanged = true; + } + + public void setChanged(boolean changed) { + this.hasChanged = changed; + } + + public void resetChanged() { + this.hasChanged = false; + } + + public int getStackLimit() { + return stackLimit; + } + + @Override + public void markDirty() { + super.markDirty(); + blockEntity.markDirty(); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/StringUtils.java b/RebornCore/src/main/java/reborncore/common/util/StringUtils.java new file mode 100644 index 000000000..63ac4f178 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/StringUtils.java @@ -0,0 +1,76 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.text.LiteralText; +import net.minecraft.text.MutableText; +import net.minecraft.util.Formatting; + +import java.util.Locale; + +/** + * @author Prospector on 11/05/16 + */ +public class StringUtils { + + public static String toFirstCapital(String input) { + if (input == null || input.length() == 0) { + return input; + } + + return input.substring(0, 1).toUpperCase() + input.substring(1); + } + + public static String toFirstCapitalAllLowercase(String input) { + if (input == null || input.length() == 0) { + return input; + } + String output = input.toLowerCase(Locale.ROOT); + return output.substring(0, 1).toUpperCase() + output.substring(1); + } + + /** + * Returns red-yellow-green text formatting depending on percentage + * + * @param percentage int percentage amount + * @return TextFormatting Red or Yellow or Green + */ + public static Formatting getPercentageColour(int percentage) { + if (percentage <= 10) { + return Formatting.RED; + } else if (percentage >= 75) { + return Formatting.GREEN; + } else { + return Formatting.YELLOW; + } + } + + public static MutableText getPercentageText(int percentage) { + return new LiteralText(String.valueOf(percentage)) + .formatted(getPercentageColour(percentage)) + .append("%"); + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/Tank.java b/RebornCore/src/main/java/reborncore/common/util/Tank.java new file mode 100644 index 000000000..d03cab0d5 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/Tank.java @@ -0,0 +1,166 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.fluid.Fluid; +import net.minecraft.fluid.Fluids; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.util.Identifier; +import net.minecraft.util.math.Direction; +import net.minecraft.util.registry.Registry; +import org.apache.commons.lang3.Validate; +import org.apache.commons.lang3.tuple.Pair; +import reborncore.client.screen.builder.Syncable; +import reborncore.common.blockentity.MachineBaseBlockEntity; +import reborncore.common.fluid.FluidValue; +import reborncore.common.fluid.container.FluidInstance; +import reborncore.common.fluid.container.GenericFluidContainer; + +import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; +import java.util.List; +import java.util.function.Consumer; +import java.util.function.Supplier; + +public class Tank implements GenericFluidContainer, Syncable { + + private final String name; + @NotNull + private FluidInstance fluidInstance = new FluidInstance(); + private final FluidValue capacity; + + @Nullable + private Direction side = null; + + private final MachineBaseBlockEntity blockEntity; + + public Tank(String name, FluidValue capacity, MachineBaseBlockEntity blockEntity) { + super(); + this.name = name; + this.capacity = capacity; + this.blockEntity = blockEntity; + } + + @NotNull + public FluidInstance getFluidInstance() { + return getFluidInstance(side); + } + + @NotNull + public Fluid getFluid() { + return getFluidInstance().getFluid(); + } + + public FluidValue getCapacity() { + return capacity; + } + + public FluidValue getFreeSpace() { + return getCapacity().subtract(getFluidAmount()); + } + + public boolean canFit(Fluid fluid, FluidValue amount) { + return (isEmpty() || getFluid() == fluid) && getFreeSpace().equalOrMoreThan(amount); + } + + public boolean isEmpty() { + return getFluidInstance().isEmpty(); + } + + public boolean isFull() { + return !getFluidInstance().isEmpty() && getFluidInstance().getAmount().equalOrMoreThan(getCapacity()); + } + + public final CompoundTag write(CompoundTag nbt) { + CompoundTag tankData = fluidInstance.write(); + nbt.put(name, tankData); + return nbt; + } + + public void setFluidAmount(FluidValue amount) { + if (!fluidInstance.isEmptyFluid()) { + fluidInstance.setAmount(amount); + } + } + + public final Tank read(CompoundTag nbt) { + if (nbt.contains(name)) { + // allow to read empty tanks + setFluid(Fluids.EMPTY); + + CompoundTag tankData = nbt.getCompound(name); + fluidInstance = new FluidInstance(tankData); + } + return this; + } + + public void setFluid(@NotNull Fluid f) { + Validate.notNull(f); + fluidInstance.setFluid(f); + } + + @Nullable + public Direction getSide() { + return side; + } + + public void setSide( + @Nullable + Direction side) { + this.side = side; + } + + @Override + public void getSyncPair(List> pairList) { + pairList.add(Pair.of(() -> Registry.FLUID.getId(fluidInstance.getFluid()).toString(), (Consumer) o -> fluidInstance.setFluid(Registry.FLUID.get(new Identifier(o))))); + pairList.add(Pair.of(() -> fluidInstance.getAmount(), o -> fluidInstance.setAmount((FluidValue) o))); + } + + public FluidValue getFluidAmount() { + return getFluidInstance().getAmount(); + } + + @Override + public void setFluid(@Nullable Direction type, @NotNull FluidInstance instance) { + fluidInstance = instance; + } + + @NotNull + @Override + public FluidInstance getFluidInstance(@Nullable Direction type) { + return fluidInstance; + } + + public void setFluidInstance(@NotNull FluidInstance fluidInstance) { + this.fluidInstance = fluidInstance; + } + + @Override + public FluidValue getCapacity(@Nullable Direction type) { + return capacity; + } + + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/TemporaryLazy.java b/RebornCore/src/main/java/reborncore/common/util/TemporaryLazy.java new file mode 100644 index 000000000..6ef31c343 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/TemporaryLazy.java @@ -0,0 +1,47 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import java.util.function.Supplier; + +public class TemporaryLazy { + private T value; + private final Supplier valueSupplier; + + public TemporaryLazy(Supplier valueSupplier) { + this.valueSupplier = valueSupplier; + } + + public T get() { + if (value == null) { + value = valueSupplier.get(); + } + return value; + } + + public void reset() { + value = null; + } +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/common/util/TorchHelper.java b/RebornCore/src/main/java/reborncore/common/util/TorchHelper.java new file mode 100644 index 000000000..83d6653f4 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/TorchHelper.java @@ -0,0 +1,67 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.BlockItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.util.ActionResult; +import net.minecraft.util.hit.BlockHitResult; + +import java.util.Locale; + +public class TorchHelper { + + public static ActionResult placeTorch(ItemUsageContext itemUsageContext) { + PlayerEntity player = itemUsageContext.getPlayer(); + if (player == null) { + return ActionResult.FAIL; + } + + for (int i = 0; i < player.inventory.main.size(); i++) { + ItemStack torchStack = player.inventory.getStack(i); + if (torchStack.isEmpty() || !torchStack.getTranslationKey().toLowerCase(Locale.ROOT).contains("torch")) { + continue; + } + if (!(torchStack.getItem() instanceof BlockItem)) { + continue; + } + + int oldSize = torchStack.getCount(); + ItemUsageContext context = new ItemUsageContextCustomStack(itemUsageContext.getWorld(), player, itemUsageContext.getHand(), torchStack, new BlockHitResult(itemUsageContext.getHitPos(), itemUsageContext.getSide(), itemUsageContext.getBlockPos(), true)); + ActionResult result = torchStack.useOnBlock(context); + if (player.isCreative()) { + torchStack.setCount(oldSize); + } else if (torchStack.getCount() <= 0) { + player.inventory.setStack(i, ItemStack.EMPTY); + } + if (result == ActionResult.SUCCESS) { + return ActionResult.SUCCESS; + } + } + return ActionResult.FAIL; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/Torus.java b/RebornCore/src/main/java/reborncore/common/util/Torus.java new file mode 100644 index 000000000..7b1bc2e50 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/Torus.java @@ -0,0 +1,97 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import net.minecraft.util.math.BlockPos; + +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ExecutorService; +import java.util.concurrent.Executors; +import java.util.concurrent.TimeUnit; + +public class Torus { + private static final ExecutorService GEN_EXECUTOR = Executors.newSingleThreadExecutor(); + private static Int2IntMap torusSizeCache; + + public static List generate(BlockPos orgin, int radius) { + List posLists = new ArrayList<>(); + for (int x = -radius; x < radius; x++) { + for (int y = -radius; y < radius; y++) { + for (int z = -radius; z < radius; z++) { + if (Math.pow(radius / 2 - Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), 2) + Math.pow(z, 2) < Math.pow(radius * 0.05, 2)) { + posLists.add(orgin.add(x, z, y)); + } + } + } + } + return posLists; + } + + public static void genSizeMap(int maxRadius) { + if (torusSizeCache != null) { + //Lets not do this again + return; + } + //10 is added as the control computer has a base of around 6 less + final int sizeToCompute = maxRadius + 10; + + torusSizeCache = new Int2IntOpenHashMap(sizeToCompute); + + for (int i = 0; i < sizeToCompute; i++) { + final int radius = i; + GEN_EXECUTOR.submit(() -> { + int size = 0; + for (int x = -radius; x < radius; x++) { + for (int y = -radius; y < radius; y++) { + for (int z = -radius; z < radius; z++) { + if (Math.pow(radius / 2 - Math.sqrt(Math.pow(x, 2) + Math.pow(y, 2)), 2) + Math.pow(z, 2) < Math.pow(radius * 0.05, 2)) { + size++; + } + } + } + } + torusSizeCache.put(radius, size); + }); + } + + // Finish running the tasks, and then shutdown the ExecutorService. This call does not stall the main thread + GEN_EXECUTOR.shutdown(); + } + + public static Int2IntMap getTorusSizeCache() { + if (!GEN_EXECUTOR.isShutdown()) { + try { + GEN_EXECUTOR.awaitTermination(1, TimeUnit.SECONDS); + } catch (InterruptedException e) { + throw new RuntimeException("Reborn core failed to initialize the torus cache", e); + } + } + + return torusSizeCache; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/TranslationTools.java b/RebornCore/src/main/java/reborncore/common/util/TranslationTools.java new file mode 100644 index 000000000..b29d4af56 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/TranslationTools.java @@ -0,0 +1,168 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import com.google.gson.Gson; +import com.google.gson.reflect.TypeToken; + +import java.io.IOException; +import java.lang.reflect.Type; +import java.nio.charset.StandardCharsets; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.util.*; +import java.util.stream.Collectors; + +//Quick too to migrate to the new lang format, and to try and keep as many lang entrys as possible +public class TranslationTools { + + //Scanner used for manual matching + private static final Scanner SCANNER = new Scanner(System.in); + + public static void main(String[] args) throws IOException { + Path dir = Paths.get("C:\\Users\\mark\\Desktop\\translations"); + //generateMigrationMap(dir); + migrateMappings(dir); + } + + private static void migrateMappings(Path dir) throws IOException { + final Map keyMap = readJsonFile(dir.resolve("map.json")); + final Map newLang = readJsonFile(dir.resolve("en_us.json")); + + Path outputDir = dir.resolve("out"); + Files.createDirectories(outputDir); + + for (Path path : Files.walk(dir.resolve("old")).collect(Collectors.toList())) { + if (Files.isDirectory(path)) { + continue; + } + Map oldLang = readLangFile(path); + Map output = new HashMap<>(); + + for (Map.Entry entry : oldLang.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + if (keyMap.containsKey(key)) { + key = keyMap.get(key); + } + if (!newLang.containsKey(key)) { + //Lost key, no point copying them over + continue; + } + output.put(key, value); + } + + + Path outputPath = outputDir.resolve(path.getFileName().toString().toLowerCase().replace(".lang", ".json")); + writeJsonMap(outputPath, output); + } + } + + @SuppressWarnings("unused") + private static void generateMigrationMap(Path dir) throws IOException { + Map oldLang = readLangFile(dir.resolve("en_us.lang")); + Map newLang = readJsonFile(dir.resolve("en_us.json")); + + Map conversion = new HashMap<>(); + + for (Map.Entry entry : oldLang.entrySet()) { + String key = entry.getKey(); + String value = entry.getValue(); + + List newKeys = getKeysByValue(newLang, value); + if (newKeys.size() == 1) { + conversion.put(key, newKeys.get(0)); + } else if (newKeys.size() > 0) { + boolean autoMatched = false; + String[][] autoMatches = new String[][]{{"tile.", "block."}, {"fluid.", "fluid."}}; + for (String[] arr : autoMatches) { + if (key.startsWith(arr[0])) { + for (String newKey : newKeys) { + if (newKey.startsWith(arr[1])) { + autoMatched = true; + conversion.put(key, newKey); + } + } + } + } + if (!autoMatched) { + System.out.println(); + System.out.println(key); + System.out.println(); + for (int i = 0; i < newKeys.size(); i++) { + System.out.println(String.format("%d) %s", i, newKeys.get(i))); + } + System.out.print("Input selection:"); + int input = SCANNER.nextInt(); + conversion.put(key, newKeys.get(input)); + System.out.println(); + } + } + } + + writeJsonMap(dir.resolve("map.json"), conversion); + } + + private static Map readJsonFile(Path path) throws IOException { + Type mapType = new TypeToken>() { + }.getType(); + return new Gson().fromJson(new String(Files.readAllBytes(path), StandardCharsets.UTF_8), mapType); + } + + private static Map readLangFile(Path path) throws IOException { + List lines = Files.lines(path).collect(Collectors.toList()); + Map map = new HashMap<>(); + for (String line : lines) { + line = line.trim(); + if (line.isEmpty() || line.startsWith("#")) { + continue; + } + String[] split = line.split("="); + if (split.length != 2) { + throw new UnsupportedOperationException(); + } + map.put(split[0], split[1]); + } + return map; + } + + private static void writeJsonMap(Path path, Map map) throws IOException { + Files.deleteIfExists(path); + String json = new Gson().toJson(map); + Files.write(path, json.getBytes()); + } + + private static List getKeysByValue(Map map, E value) { + List keys = new ArrayList<>(); + for (Map.Entry entry : map.entrySet()) { + if (Objects.equals(value, entry.getValue())) { + keys.add(entry.getKey()); + } + } + return keys; + } + +} diff --git a/RebornCore/src/main/java/reborncore/common/util/WorldUtils.java b/RebornCore/src/main/java/reborncore/common/util/WorldUtils.java new file mode 100644 index 000000000..d09052dbf --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/WorldUtils.java @@ -0,0 +1,83 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.block.BlockState; +import net.minecraft.entity.ItemEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Vec3d; +import net.minecraft.world.World; + +import java.util.List; +import java.util.Random; + +/** + * Created by Mark on 13/03/2016. + */ +public class WorldUtils { + + public static void updateBlock(World world, BlockPos pos) { + BlockState state = world.getBlockState(pos); + world.updateListeners(pos, state, state, 3); + } + + public static boolean chunkExists(World world, int x, int z) { + return world.isChunkLoaded(new BlockPos(x << 4, 64, z << 4)); + } + + public static void dropItem(ItemStack itemStack, World world, BlockPos pos) { + Random rand = new Random(); + + float dX = rand.nextFloat() * 0.8F + 0.1F; + float dY = rand.nextFloat() * 0.8F + 0.1F; + float dZ = rand.nextFloat() * 0.8F + 0.1F; + + ItemEntity entityItem = new ItemEntity(world, pos.getX() + dX, pos.getY() + dY, pos.getZ() + dZ, + itemStack.copy()); + + if (itemStack.hasTag()) { + entityItem.getStack().setTag(itemStack.getTag().copy()); + } + + float factor = 0.05F; + entityItem.setVelocity(new Vec3d(rand.nextGaussian() * factor, rand.nextGaussian() * factor + 0.2F, rand.nextGaussian() * factor)); + if (!world.isClient) { + world.spawnEntity(entityItem); + } + } + + public static void dropItem(Item item, World world, BlockPos pos) { + dropItem(new ItemStack(item), world, pos); + } + + public static void dropItems(List itemStackList, World world, BlockPos pos) { + for (final ItemStack itemStack : itemStackList) { + WorldUtils.dropItem(itemStack, world, pos); + itemStack.setCount(0); + } + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/WrenchUtils.java b/RebornCore/src/main/java/reborncore/common/util/WrenchUtils.java new file mode 100644 index 000000000..55574ad73 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/WrenchUtils.java @@ -0,0 +1,106 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util; + +import net.minecraft.block.Block; +import net.minecraft.block.BlockState; +import net.minecraft.block.Blocks; +import net.minecraft.block.entity.BlockEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.sound.SoundCategory; +import net.minecraft.state.property.Properties; +import net.minecraft.util.BlockRotation; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.math.Direction; +import net.minecraft.world.World; +import reborncore.api.IToolDrop; +import reborncore.api.ToolManager; +import reborncore.common.BaseBlockEntityProvider; +import reborncore.common.misc.ModSounds; + +/** + * @author drcrazy + */ +public class WrenchUtils { + + public static boolean handleWrench(ItemStack stack, World worldIn, BlockPos pos, PlayerEntity playerIn, Direction side) { + BlockEntity blockEntity = worldIn.getBlockEntity(pos); + if (blockEntity == null) { + return false; + } + + if (ToolManager.INSTANCE.handleTool(stack, pos, worldIn, playerIn, side, true)) { + if (playerIn.isSneaking()) { + if (blockEntity instanceof IToolDrop) { + ItemStack drop = ((IToolDrop) blockEntity).getToolDrop(playerIn); + if (drop == null) { + return false; + } + + boolean dropContents = true; + Block block = blockEntity.getCachedState().getBlock(); + if (block instanceof BaseBlockEntityProvider) { + ItemStack blockEntityDrop = ((BaseBlockEntityProvider) block).getDropWithContents(worldIn, pos, drop).orElse(ItemStack.EMPTY); + if (!blockEntityDrop.isEmpty()) { + dropContents = false; + drop = blockEntityDrop; + } + } + + if (!worldIn.isClient) { + if (dropContents) { + ItemHandlerUtils.dropContainedItems(worldIn, pos); + } + if (!drop.isEmpty()) { + net.minecraft.util.ItemScatterer.spawn(worldIn, pos.getX(), pos.getY(), pos.getZ(), drop); + } + worldIn.removeBlockEntity(pos); + worldIn.setBlockState(pos, Blocks.AIR.getDefaultState(), 2); + } + worldIn.playSound(null, playerIn.getX(), playerIn.getY(), playerIn.getZ(), ModSounds.BLOCK_DISMANTLE, + SoundCategory.BLOCKS, 0.6F, 1F); + } + } else { + BlockState oldState = worldIn.getBlockState(pos); + BlockState newState; + if (oldState.contains(Properties.FACING)) { + // Machine can face all 6 directions. Let's move face to hit side. + newState = oldState.with(Properties.FACING, side); + } else { + newState = oldState.rotate(BlockRotation.CLOCKWISE_90); + } + + if (!newState.canPlaceAt(worldIn, pos)) { + return false; + } + worldIn.setBlockState(pos, newState); + worldIn.updateNeighbor(pos, newState.getBlock(), pos); + } + return true; + } + return false; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/serialization/ItemStackSerializer.java b/RebornCore/src/main/java/reborncore/common/util/serialization/ItemStackSerializer.java new file mode 100644 index 000000000..a937490ce --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/serialization/ItemStackSerializer.java @@ -0,0 +1,104 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util.serialization; + +import com.google.gson.*; +import com.mojang.brigadier.exceptions.CommandSyntaxException; +import net.minecraft.item.ItemStack; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.StringNbtReader; +import net.minecraft.util.Identifier; +import net.minecraft.util.registry.Registry; + +import java.lang.reflect.Type; + +//Based from ee3's code +public class ItemStackSerializer implements JsonSerializer, JsonDeserializer { + + private static final String NAME = "name"; + private static final String STACK_SIZE = "stackSize"; + private static final String TAG_COMPOUND = "tagCompound"; + + @Override + public ItemStack deserialize(JsonElement json, Type typeOfT, JsonDeserializationContext context) throws JsonParseException { + + if (json.isJsonObject()) { + + JsonObject jsonObject = json.getAsJsonObject(); + + String name = null; + int stackSize = 1; + CompoundTag tagCompound = null; + + if (jsonObject.has(NAME) && jsonObject.get(NAME).isJsonPrimitive()) { + name = jsonObject.getAsJsonPrimitive(NAME).getAsString(); + } + + if (jsonObject.has(STACK_SIZE) && jsonObject.get(STACK_SIZE).isJsonPrimitive()) { + stackSize = jsonObject.getAsJsonPrimitive(STACK_SIZE).getAsInt(); + } + + if (jsonObject.has(TAG_COMPOUND) && jsonObject.get(TAG_COMPOUND).isJsonPrimitive()) { + try { + tagCompound = StringNbtReader.parse(jsonObject.getAsJsonPrimitive(TAG_COMPOUND).getAsString()); + } catch (CommandSyntaxException e) { + + } + } + + if (name != null && Registry.ITEM.get(new Identifier(name)) != null) { + ItemStack itemStack = new ItemStack(Registry.ITEM.get(new Identifier(name)), stackSize); + itemStack.setTag(tagCompound); + return itemStack; + } + } + + return ItemStack.EMPTY; + } + + @Override + public JsonElement serialize(ItemStack src, Type typeOfSrc, JsonSerializationContext context) { + + if (src != null && src.getItem() != null) { + JsonObject jsonObject = new JsonObject(); + + if (Registry.ITEM.getId(src.getItem()) != null) { + jsonObject.addProperty(NAME, Registry.ITEM.getId(src.getItem()).toString()); + } else { + return JsonNull.INSTANCE; + } + + jsonObject.addProperty(STACK_SIZE, src.getCount()); + + if (src.getTag() != null) { + jsonObject.addProperty(TAG_COMPOUND, src.getTag().toString()); + } + + return jsonObject; + } + + return JsonNull.INSTANCE; + } +} diff --git a/RebornCore/src/main/java/reborncore/common/util/serialization/SerializationUtil.java b/RebornCore/src/main/java/reborncore/common/util/serialization/SerializationUtil.java new file mode 100644 index 000000000..15de9e0f4 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/common/util/serialization/SerializationUtil.java @@ -0,0 +1,62 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.common.util.serialization; + +import com.google.gson.Gson; +import com.google.gson.GsonBuilder; +import com.google.gson.JsonArray; +import com.google.gson.JsonElement; +import net.minecraft.item.ItemStack; + +import java.util.List; +import java.util.stream.IntStream; +import java.util.stream.Stream; + +public class SerializationUtil { + + public static final Gson GSON = new GsonBuilder() + .setPrettyPrinting() + .enableComplexMapKeySerialization() + .registerTypeAdapter(ItemStack.class, new ItemStackSerializer()) + .create(); + + //Same as above, just without pretty printing + public static final Gson GSON_FLAT = new GsonBuilder() + .enableComplexMapKeySerialization() + .registerTypeAdapter(ItemStack.class, new ItemStackSerializer()) + .create(); + + + public static Stream stream(JsonArray array) { + return IntStream.range(0, array.size()) + .mapToObj(array::get); + } + + public static JsonArray asArray(List elements) { + JsonArray array = new JsonArray(); + elements.forEach(array::add); + return array; + } +} diff --git a/RebornCore/src/main/java/reborncore/mixin/client/AccessorChatHud.java b/RebornCore/src/main/java/reborncore/mixin/client/AccessorChatHud.java new file mode 100644 index 000000000..2cd4e06bc --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/client/AccessorChatHud.java @@ -0,0 +1,36 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.client; + +import net.minecraft.client.gui.hud.ChatHud; +import net.minecraft.text.Text; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ChatHud.class) +public interface AccessorChatHud { + @Invoker("addMessage") + void invokeAddMessage(Text message, int messageId); +} diff --git a/RebornCore/src/main/java/reborncore/mixin/client/AccessorModelPredicateProviderRegistry.java b/RebornCore/src/main/java/reborncore/mixin/client/AccessorModelPredicateProviderRegistry.java new file mode 100644 index 000000000..aed127c3f --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/client/AccessorModelPredicateProviderRegistry.java @@ -0,0 +1,40 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.client; + +import net.minecraft.client.item.ModelPredicateProvider; +import net.minecraft.client.item.ModelPredicateProviderRegistry; +import net.minecraft.item.Item; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(ModelPredicateProviderRegistry.class) +public interface AccessorModelPredicateProviderRegistry { + @Invoker + static void callRegister(Item item, Identifier id, ModelPredicateProvider provider) { + throw new RuntimeException("nope"); + } +} diff --git a/RebornCore/src/main/java/reborncore/mixin/client/MixinDebugRenderer.java b/RebornCore/src/main/java/reborncore/mixin/client/MixinDebugRenderer.java new file mode 100644 index 000000000..fd9d85e18 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/client/MixinDebugRenderer.java @@ -0,0 +1,43 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.client; + +import net.minecraft.client.render.VertexConsumerProvider; +import net.minecraft.client.render.debug.DebugRenderer; +import net.minecraft.client.util.math.MatrixStack; +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 reborncore.client.ClientChunkManager; + +@Mixin(DebugRenderer.class) +public class MixinDebugRenderer { + + @Inject(method = "render", at = @At("RETURN")) + public void render(MatrixStack matrices, VertexConsumerProvider.Immediate vertexConsumers, double cameraX, double cameraY, double cameraZ, CallbackInfo info) { + ClientChunkManager.render(matrices, vertexConsumers, cameraX, cameraY, cameraZ); + } +} diff --git a/RebornCore/src/main/java/reborncore/mixin/client/MixinGameRenderer.java b/RebornCore/src/main/java/reborncore/mixin/client/MixinGameRenderer.java new file mode 100644 index 000000000..a2d52166f --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/client/MixinGameRenderer.java @@ -0,0 +1,56 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.client; + +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.AbstractClientPlayerEntity; +import net.minecraft.client.render.GameRenderer; +import net.minecraft.item.ItemStack; +import org.spongepowered.asm.mixin.Final; +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.Redirect; +import reborncore.api.items.ArmorFovHandler; + +@Mixin(GameRenderer.class) +public class MixinGameRenderer { + + @Shadow + @Final + private MinecraftClient client; + + @Redirect(method = "updateMovementFovMultiplier", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;getSpeed()F")) + private float updateMovementFovMultiplier(AbstractClientPlayerEntity playerEntity) { + float playerSpeed = playerEntity.getSpeed(); + for (ItemStack stack : playerEntity.getArmorItems()) { + if (stack.getItem() instanceof ArmorFovHandler) { + playerSpeed = ((ArmorFovHandler) stack.getItem()).changeFov(playerSpeed, stack, client.player); + } + } + return playerSpeed; + } + +} diff --git a/RebornCore/src/main/java/reborncore/mixin/client/MixinItemRenderer.java b/RebornCore/src/main/java/reborncore/mixin/client/MixinItemRenderer.java new file mode 100644 index 000000000..ba25ec0a9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/client/MixinItemRenderer.java @@ -0,0 +1,77 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.client; + +import com.mojang.blaze3d.systems.RenderSystem; +import net.minecraft.client.font.TextRenderer; +import net.minecraft.client.render.BufferBuilder; +import net.minecraft.client.render.Tessellator; +import net.minecraft.client.render.item.ItemRenderer; +import net.minecraft.item.ItemStack; +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.callback.CallbackInfo; +import reborncore.common.util.ItemDurabilityExtensions; + +import org.jetbrains.annotations.Nullable; + +//Not too happy with this, need to find and get a better solution into fabric soon +@Mixin(ItemRenderer.class) +public abstract class MixinItemRenderer { + + @Shadow + protected abstract void renderGuiQuad(BufferBuilder bufferBuilder_1, int int_1, int int_2, int int_3, int int_4, int int_5, int int_6, int int_7, int int_8); + + @Inject(method = "renderGuiItemOverlay(Lnet/minecraft/client/font/TextRenderer;Lnet/minecraft/item/ItemStack;IILjava/lang/String;)V", at = @At("HEAD")) + private void renderGuiItemOverlay(TextRenderer textRenderer, ItemStack stack, int x, int y, @Nullable String string, CallbackInfo info) { + if (stack.getItem() instanceof ItemDurabilityExtensions) { + ItemDurabilityExtensions durabilityExtensions = (ItemDurabilityExtensions) stack.getItem(); + if (!durabilityExtensions.showDurability(stack)) { + return; + } + RenderSystem.disableDepthTest(); + RenderSystem.disableTexture(); + RenderSystem.disableAlphaTest(); + RenderSystem.disableBlend(); + + Tessellator tessellator = Tessellator.getInstance(); + BufferBuilder bufferBuilder = tessellator.getBuffer(); + + int durability = (int) (13 * (1 - Math.max(0.0F, durabilityExtensions.getDurability(stack)))); + int color = durabilityExtensions.getDurabilityColor(stack); + + this.renderGuiQuad(bufferBuilder, x + 2, y + 13, 13, 2, 0, 0, 0, 255); + this.renderGuiQuad(bufferBuilder, x + 2, y + 13, durability, 1, color >> 16 & 255, color >> 8 & 255, color & 255, 255); + + RenderSystem.enableBlend(); + RenderSystem.enableAlphaTest(); + RenderSystem.enableTexture(); + RenderSystem.enableDepthTest(); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/mixin/client/MixinWorldRenderer.java b/RebornCore/src/main/java/reborncore/mixin/client/MixinWorldRenderer.java new file mode 100644 index 000000000..6669fb757 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/client/MixinWorldRenderer.java @@ -0,0 +1,103 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.client; + +import net.minecraft.block.BlockState; +import net.minecraft.block.ShapeContext; +import net.minecraft.client.MinecraftClient; +import net.minecraft.client.network.ClientPlayerEntity; +import net.minecraft.client.render.VertexConsumer; +import net.minecraft.client.render.WorldRenderer; +import net.minecraft.client.util.math.MatrixStack; +import net.minecraft.client.world.ClientWorld; +import net.minecraft.entity.Entity; +import net.minecraft.item.ItemStack;; +import net.minecraft.util.math.BlockPos; +import net.minecraft.util.shape.VoxelShape; +import net.minecraft.util.shape.VoxelShapes; +import org.spongepowered.asm.mixin.Final; +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.callback.CallbackInfo; +import reborncore.common.misc.MultiBlockBreakingTool; + +import java.util.ArrayList; +import java.util.List; +import java.util.Set; + +@Mixin(WorldRenderer.class) +public abstract class MixinWorldRenderer { + + @Shadow + @Final + private MinecraftClient client; + @Shadow + private ClientWorld world; + + @Shadow + private static void drawShapeOutline(MatrixStack matrixStack, VertexConsumer vertexConsumer, VoxelShape voxelShape, double d, double e, double f, float g, float h, float i, float j) { + throw new AssertionError(); + } + + @Inject(method = "drawBlockOutline", at = @At("HEAD"), cancellable = true) + private void drawBlockOutline(MatrixStack matrixStack, VertexConsumer vertexConsumer, Entity entity, double d, double e, double f, BlockPos targetPos, BlockState targetBlockState, CallbackInfo info) { + List shapes = new ArrayList<>(); + + if (entity == client.player) { + ClientPlayerEntity clientPlayerEntity = client.player; + ItemStack stack = clientPlayerEntity.getMainHandStack(); + if (stack.isEmpty()) { + return; + } + if (stack.getItem() instanceof MultiBlockBreakingTool) { + Set blockPosList = ((MultiBlockBreakingTool) stack.getItem()).getBlocksToBreak(stack, clientPlayerEntity.world, targetPos, clientPlayerEntity); + + for (BlockPos pos : blockPosList) { + if (pos.equals(targetPos)) { + continue; + } + + BlockState blockState = world.getBlockState(pos); + shapes.add(blockState.getOutlineShape(world, pos, ShapeContext.of(entity)).offset(pos.getX() - targetPos.getX(), pos.getY() - targetPos.getY(), pos.getZ() - targetPos.getZ())); + + } + } + } + + if (!shapes.isEmpty()) { + VoxelShape shape = targetBlockState.getOutlineShape(world, targetPos, ShapeContext.of(entity)); + + for (VoxelShape voxelShape : shapes) { + shape = VoxelShapes.union(shape, voxelShape); + } + + drawShapeOutline(matrixStack, vertexConsumer, shape, (double)targetPos.getX() - d, (double)targetPos.getY() - e, (double)targetPos.getZ() - f, 0.0F, 0.0F, 0.0F, 0.4F); + //info.cancel(); // Enable to render a single bounding box around the whole thing + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/AccessorFluidBlock.java b/RebornCore/src/main/java/reborncore/mixin/common/AccessorFluidBlock.java new file mode 100644 index 000000000..2bef416cd --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/AccessorFluidBlock.java @@ -0,0 +1,37 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.block.FluidBlock; +import net.minecraft.fluid.FlowableFluid; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(FluidBlock.class) +public interface AccessorFluidBlock { + + @Accessor + FlowableFluid getFluid(); +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/AccessorFoliagePlacerType.java b/RebornCore/src/main/java/reborncore/mixin/common/AccessorFoliagePlacerType.java new file mode 100644 index 000000000..d4befb6cc --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/AccessorFoliagePlacerType.java @@ -0,0 +1,40 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import com.mojang.serialization.Codec; +import net.minecraft.world.gen.foliage.FoliagePlacer; +import net.minecraft.world.gen.foliage.FoliagePlacerType; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(FoliagePlacerType.class) +public interface AccessorFoliagePlacerType { + + @Invoker("register") + static

FoliagePlacerType

register(String id, Codec

codec) { + throw new UnsupportedOperationException(); + } +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/AccessorIngredient.java b/RebornCore/src/main/java/reborncore/mixin/common/AccessorIngredient.java new file mode 100644 index 000000000..068dd6ca2 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/AccessorIngredient.java @@ -0,0 +1,37 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.item.ItemStack; +import net.minecraft.recipe.Ingredient; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Ingredient.class) +public interface AccessorIngredient { + + @Accessor + ItemStack[] getMatchingStacks(); +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/AccessorRecipeManager.java b/RebornCore/src/main/java/reborncore/mixin/common/AccessorRecipeManager.java new file mode 100644 index 000000000..06586fc14 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/AccessorRecipeManager.java @@ -0,0 +1,42 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.inventory.Inventory; +import net.minecraft.recipe.Recipe; +import net.minecraft.recipe.RecipeManager; +import net.minecraft.recipe.RecipeType; +import net.minecraft.util.Identifier; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +import java.util.Map; + +@Mixin(RecipeManager.class) +public interface AccessorRecipeManager { + + @Invoker(value = "getAllOfType") + > Map> getAll(RecipeType type); +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/AccessorScreenHandler.java b/RebornCore/src/main/java/reborncore/mixin/common/AccessorScreenHandler.java new file mode 100644 index 000000000..36738a8af --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/AccessorScreenHandler.java @@ -0,0 +1,40 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.screen.ScreenHandler; +import net.minecraft.screen.ScreenHandlerListener; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +import java.util.List; + +@Mixin(ScreenHandler.class) +public interface AccessorScreenHandler { + + @Accessor + List getListeners(); + +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/AccessorSlot.java b/RebornCore/src/main/java/reborncore/mixin/common/AccessorSlot.java new file mode 100644 index 000000000..c51937a54 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/AccessorSlot.java @@ -0,0 +1,36 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.screen.slot.Slot; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Slot.class) +public interface AccessorSlot { + + @Accessor + int getIndex(); +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/MixinBucketItem.java b/RebornCore/src/main/java/reborncore/mixin/common/MixinBucketItem.java new file mode 100644 index 000000000..044d67139 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/MixinBucketItem.java @@ -0,0 +1,59 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.fluid.Fluid; +import net.minecraft.item.BucketItem; +import net.minecraft.item.ItemStack; +import net.minecraft.item.Items; +import org.spongepowered.asm.mixin.Final; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Shadow; +import reborncore.common.fluid.RebornFluidManager; +import reborncore.common.fluid.container.ItemFluidInfo; + +@Mixin(BucketItem.class) +public class MixinBucketItem implements ItemFluidInfo { + + @Shadow + @Final + private Fluid fluid; + + @Override + public ItemStack getEmpty() { + return new ItemStack(Items.BUCKET); + } + + @Override + public ItemStack getFull(Fluid fluid) { + BucketItem item = RebornFluidManager.getBucketMap().get(fluid); + return new ItemStack(item); + } + + @Override + public Fluid getFluid(ItemStack itemStack) { + return fluid; + } +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/MixinCraftingResultSlot.java b/RebornCore/src/main/java/reborncore/mixin/common/MixinCraftingResultSlot.java new file mode 100644 index 000000000..2f2a06af1 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/MixinCraftingResultSlot.java @@ -0,0 +1,72 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.inventory.CraftingInventory; +import net.minecraft.item.ItemStack; +import net.minecraft.screen.slot.CraftingResultSlot; +import net.minecraft.util.collection.DefaultedList; +import org.spongepowered.asm.mixin.Final; +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.ModifyVariable; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfo; +import reborncore.api.events.ItemCraftCallback; +import reborncore.common.recipes.ExtendedRecipeRemainder; + +@Mixin(CraftingResultSlot.class) +public abstract class MixinCraftingResultSlot { + + @Shadow + @Final + private CraftingInventory input; + + @Shadow + @Final + private PlayerEntity player; + + @ModifyVariable(method = "onTakeItem", at = @At(value = "INVOKE"), index = 3) + private DefaultedList defaultedList(DefaultedList list) { + for (int i = 0; i < input.size(); i++) { + ItemStack invStack = input.getStack(i); + if (invStack.getItem() instanceof ExtendedRecipeRemainder) { + ItemStack remainder = ((ExtendedRecipeRemainder) invStack.getItem()).getRemainderStack(invStack.copy()); + if (!remainder.isEmpty()) { + list.set(i, remainder); + } + } + } + return list; + } + + @Inject(method = "onCrafted(Lnet/minecraft/item/ItemStack;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;onCraft(Lnet/minecraft/world/World;Lnet/minecraft/entity/player/PlayerEntity;I)V", shift = At.Shift.AFTER)) + private void onCrafted(ItemStack itemStack, CallbackInfo info) { + ItemCraftCallback.EVENT.invoker().onCraft(itemStack, input, player); + } + +} \ No newline at end of file diff --git a/RebornCore/src/main/java/reborncore/mixin/common/MixinItemEntity.java b/RebornCore/src/main/java/reborncore/mixin/common/MixinItemEntity.java new file mode 100644 index 000000000..0e88a5dde --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/MixinItemEntity.java @@ -0,0 +1,59 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.entity.Entity; +import net.minecraft.entity.EntityType; +import net.minecraft.entity.ItemEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.world.World; +import net.minecraft.world.explosion.Explosion; +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.callback.CallbackInfo; +import reborncore.common.misc.RebornCoreTags; + +@Mixin(ItemEntity.class) +public abstract class MixinItemEntity extends Entity { + @Shadow + public abstract ItemStack getStack(); + + public MixinItemEntity(EntityType type, World world) { + super(type, world); + } + + @Inject(method = "tick", at = @At("RETURN")) + public void tick(CallbackInfo info) { + if (!world.isClient && isTouchingWater() && !getStack().isEmpty()) { + if (getStack().getItem().isIn(RebornCoreTags.WATER_EXPLOSION_ITEM)) { + world.createExplosion(this, getX(), getY(), getZ(), 2F, Explosion.DestructionType.BREAK); + this.remove(); + } + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/MixinItemStack.java b/RebornCore/src/main/java/reborncore/mixin/common/MixinItemStack.java new file mode 100644 index 000000000..6fdce2391 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/MixinItemStack.java @@ -0,0 +1,58 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import com.google.common.collect.ArrayListMultimap; +import com.google.common.collect.ImmutableMultimap; +import com.google.common.collect.Multimap; +import net.minecraft.entity.EquipmentSlot; +import net.minecraft.entity.attribute.EntityAttribute; +import net.minecraft.entity.attribute.EntityAttributeModifier; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +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.callback.CallbackInfoReturnable; +import reborncore.api.items.ItemStackModifiers; + +@Mixin(ItemStack.class) +public abstract class MixinItemStack { + + @Shadow + public abstract Item getItem(); + + @Inject(method = "getAttributeModifiers", at = @At("RETURN"), cancellable = true) + private void getAttributeModifiers(EquipmentSlot equipmentSlot, CallbackInfoReturnable> info) { + if (getItem() instanceof ItemStackModifiers) { + ItemStackModifiers item = (ItemStackModifiers) getItem(); + Multimap modifierHashMap = ArrayListMultimap.create(info.getReturnValue()); + item.getAttributeModifiers(equipmentSlot, (ItemStack) (Object) this, modifierHashMap); + info.setReturnValue(ImmutableMultimap.copyOf(modifierHashMap)); + } + } + +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/MixinLivingEntity.java b/RebornCore/src/main/java/reborncore/mixin/common/MixinLivingEntity.java new file mode 100644 index 000000000..d8d9ef1b2 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/MixinLivingEntity.java @@ -0,0 +1,47 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.damage.DamageSource; +import net.minecraft.entity.player.PlayerEntity; +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.CallbackInfoReturnable; +import reborncore.api.events.ApplyArmorToDamageCallback; + +@Mixin(LivingEntity.class) +abstract class MixinLivingEntity { + + @Inject(method = "applyArmorToDamage", at = @At("RETURN"), cancellable = true) + public void onApplyArmorToDamage(DamageSource source, float amount, CallbackInfoReturnable cir){ + + LivingEntity entity = (LivingEntity) (Object) this; + if (! (entity instanceof PlayerEntity)) { return; } + + cir.setReturnValue(ApplyArmorToDamageCallback.EVENT.invoker().applyArmorToDamage((PlayerEntity) entity, source, amount)); + } +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/MixinPlayerEntity.java b/RebornCore/src/main/java/reborncore/mixin/common/MixinPlayerEntity.java new file mode 100644 index 000000000..27c7669d9 --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/MixinPlayerEntity.java @@ -0,0 +1,72 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import net.minecraft.entity.EntityType; +import net.minecraft.entity.LivingEntity; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.item.ItemStack; +import net.minecraft.util.collection.DefaultedList; +import net.minecraft.world.World; +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.callback.CallbackInfo; +import reborncore.api.items.ArmorRemoveHandler; +import reborncore.api.items.ArmorTickable; +import reborncore.common.util.ItemUtils; + +@Mixin(PlayerEntity.class) +public abstract class MixinPlayerEntity extends LivingEntity { + + @Shadow + public abstract Iterable getArmorItems(); + + protected MixinPlayerEntity(EntityType type, World world) { + super(type, world); + } + + private final DefaultedList reborncore_armorcache = DefaultedList.ofSize(4, ItemStack.EMPTY); + + @Inject(method = "tick", at = @At("HEAD")) + public void tick(CallbackInfo info) { + int i = 0; + for (ItemStack stack : getArmorItems()) { + ItemStack cachedStack = reborncore_armorcache.get(i); + if (!ItemUtils.isItemEqual(cachedStack, stack, false, false)) { + if (cachedStack.getItem() instanceof ArmorRemoveHandler) { + ((ArmorRemoveHandler) cachedStack.getItem()).onRemoved((PlayerEntity) (Object) this); + } + reborncore_armorcache.set(i, stack.copy()); + } + i++; + + if (!stack.isEmpty() && stack.getItem() instanceof ArmorTickable) { + ((ArmorTickable) stack.getItem()).tickArmor(stack, (PlayerEntity) (Object) this); + } + } + } +} diff --git a/RebornCore/src/main/java/reborncore/mixin/common/MixinRecipeManager.java b/RebornCore/src/main/java/reborncore/mixin/common/MixinRecipeManager.java new file mode 100644 index 000000000..463ca0eec --- /dev/null +++ b/RebornCore/src/main/java/reborncore/mixin/common/MixinRecipeManager.java @@ -0,0 +1,60 @@ +/* + * This file is part of RebornCore, licensed under the MIT License (MIT). + * + * Copyright (c) 2021 TeamReborn + * + * Permission is hereby granted, free of charge, to any person obtaining a copy + * of this software and associated documentation files (the "Software"), to deal + * in the Software without restriction, including without limitation the rights + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell + * copies of the Software, and to permit persons to whom the Software is + * furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice shall be included in all + * copies or substantial portions of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE + * SOFTWARE. + */ + +package reborncore.mixin.common; + +import com.google.gson.JsonObject; +import net.minecraft.recipe.RecipeManager; +import net.minecraft.resource.ResourceManager; +import net.minecraft.util.Identifier; +import net.minecraft.util.profiler.Profiler; +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 reborncore.common.crafting.ConditionManager; + +import java.util.Iterator; +import java.util.Map; + +@Mixin(RecipeManager.class) +public class MixinRecipeManager { + + @Inject(method = "apply", at = @At("HEAD")) + private void deserialize(Map map, ResourceManager resourceManager, Profiler profiler, CallbackInfo info) { + Iterator> iterator = map.entrySet().iterator(); + while (iterator.hasNext()) { + Map.Entry entry = iterator.next(); + Identifier id = entry.getKey(); + JsonObject json = entry.getValue(); + + // TODO dont hard code this as its awful + if (id.getNamespace().equals("reborncore") || id.getNamespace().equals("techreborn")) { + if (!ConditionManager.shouldLoadRecipe(json)) { + iterator.remove(); + } + } + } + } +} diff --git a/RebornCore/src/main/resources/assets/reborncore/icon.png b/RebornCore/src/main/resources/assets/reborncore/icon.png new file mode 100644 index 000000000..e18414a0e Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/icon.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/de_de.lang b/RebornCore/src/main/resources/assets/reborncore/lang/de_de.lang new file mode 100644 index 000000000..1af4fc4a8 --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/de_de.lang @@ -0,0 +1,31 @@ +reborncore.message.active=Aktiv +reborncore.message.inactive=Inaktiv + +item.reborncore.manual.name=Team Reborn-Handbuch + +reborncore.tooltip.energy.maxEnergy=Maximale Energie +reborncore.tooltip.energy.inputRate=Eingangs-Rate +reborncore.tooltip.energy.outputRate=Ausgangs-Rate +reborncore.tooltip.energy.tier=Stufe +reborncore.tooltip.energy.change=Energie-Änderung + +reborncore.gui.heat=Wärme +reborncore.gui.missingmultiblock=Unvollständiger Multiblock + +reborncore.gui.tooltip.config_slots=Slots konfigurieren +reborncore.gui.tooltip.config_fluids=Flüssigkeiten konfigurieren +reborncore.gui.tooltip.hologram=Multiblock-Hologramm umschalten +reborncore.gui.tooltip.lock_items=Gegenstände sperren +reborncore.gui.tooltip.power_charged=Aufgeladen +reborncore.gui.tooltip.power_click=Klicken zum Ändern der angezeigten Einheit +reborncore.gui.tooltip.power_moreinfo=für mehr Information +reborncore.gui.tooltip.dsu_fullness=Voll +reborncore.gui.tooltip.tank_amount=%smB/%smB +reborncore.gui.tooltip.tank_empty=Leerer Tank +reborncore.gui.tooltip.tank_fullness=Voll +reborncore.gui.tooltip.unlock_items=Gegenstände entsperren +reborncore.gui.tooltip.upgrades=Maschinenaufrüstung + +reborncore.gui.slotconfigtip.slot=Auf einen Slot klicken zum Konfigurieren. +reborncore.gui.slotconfigtip.side=Orange Seite bedeutet Ausgang, blaue Seite bedeutet Eingang. +reborncore.gui.slotconfigtip.side=Strg+C zum Kopieren der Slotkonfiguration, Strg+V zum Einfügen Slotkonfiguration. diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/en_US.lang b/RebornCore/src/main/resources/assets/reborncore/lang/en_US.lang new file mode 100644 index 000000000..b9e19c0aa --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/en_US.lang @@ -0,0 +1,32 @@ +reborncore.message.active=Active +reborncore.message.inactive=Inactive + +item.reborncore.manual.name=Team Reborn Manual + +reborncore.tooltip.energy.maxEnergy=Max Energy +reborncore.tooltip.energy.inputRate=Input Rate +reborncore.tooltip.energy.outputRate=Output Rate +reborncore.tooltip.energy.tier=Tier +reborncore.tooltip.energy.change=Energy Change + +reborncore.gui.heat=Heat +reborncore.gui.missingmultiblock=Incomplete Multiblock + +reborncore.gui.tooltip.config_slots=Configure slots +reborncore.gui.tooltip.config_fluids=Configure Fluids +reborncore.gui.tooltip.hologram=Toggle Multiblock Hologram +reborncore.gui.tooltip.lock_items=Lock Items +reborncore.gui.tooltip.power_charged=Charged +reborncore.gui.tooltip.power_click=Click to change display unit +reborncore.gui.tooltip.power_moreinfo=for more info +reborncore.gui.tooltip.dsu_fullness=Full +reborncore.gui.tooltip.tank_amount=%smB/%smB +reborncore.gui.tooltip.tank_empty=Empty Tank +reborncore.gui.tooltip.tank_fullness=Full +reborncore.gui.tooltip.unlock_items=Unlock Items +reborncore.gui.tooltip.upgrades=Machine upgrades + +reborncore.gui.slotconfigtip.slot=Click on slot to configure. +reborncore.gui.slotconfigtip.side=Orange side means output, blue side means input. +reborncore.gui.slotconfigtip.side=Ctrl+C to copy slot config, Ctrl+V to paste slot config. + diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/en_us.json b/RebornCore/src/main/resources/assets/reborncore/lang/en_us.json new file mode 100644 index 000000000..6c94e8f5a --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/en_us.json @@ -0,0 +1,53 @@ +{ + "reborncore.message.active": "Active", + "reborncore.message.inactive": "Inactive", + "reborncore.message.energyError": "Not Enough Energy:", + "reborncore.message.deactivating": "Deactivating", + "reborncore.message.setTo": "Set to", + + "reborncore.tooltip.energy.maxEnergy": "Max Energy", + "reborncore.tooltip.energy.inputRate": "Input Rate", + "reborncore.tooltip.energy.outputRate": "Output Rate", + "reborncore.tooltip.energy.tier": "Tier", + "reborncore.tooltip.energy.change": "Energy Change", + "reborncore.tooltip.energy": "Energy Stored", + "reborncore.tooltip.has_data": "Stored data", + + "reborncore.gui.heat": "Heat", + "reborncore.gui.missingmultiblock": "Incomplete Multiblock", + + "reborncore.gui.tooltip.config_slots": "Configure Slots", + "reborncore.gui.tooltip.config_fluids": "Configure Fluids", + "reborncore.gui.tooltip.config_redstone": "Configure Redstone", + "reborncore.gui.tooltip.hologram": "Toggle Multiblock Hologram", + "reborncore.gui.tooltip.lock_items": "Lock Items", + "reborncore.gui.tooltip.power_charged": "Charged", + "reborncore.gui.tooltip.power_moreinfo": "for more info", + "reborncore.gui.tooltip.dsu_fullness": "Full", + "reborncore.gui.tooltip.tank_amount": "%s / %s", + "reborncore.gui.tooltip.tank_empty": "Empty Tank", + "reborncore.gui.tooltip.tank_fullness": "Full", + "reborncore.gui.tooltip.unlock_items": "Unlock Items", + "reborncore.gui.tooltip.upgrades": "Machine upgrades", + + "reborncore.gui.slotconfig.autoinput": "Auto Input", + "reborncore.gui.slotconfig.autooutput": "Auto Output", + "reborncore.gui.slotconfig.filter_input": "Filter Input", + + "reborncore.gui.slotconfigtip.slot": "Click on slot to configure.", + "reborncore.gui.slotconfigtip.side1": "Orange side means output.", + "reborncore.gui.slotconfigtip.side2": "Blue side means input.", + "reborncore.gui.slotconfigtip.side3": "Green side means both.", + "reborncore.gui.slotconfigtip.copy1": "Ctrl+C to copy slot config.", + "reborncore.gui.slotconfigtip.copy2": "Ctrl+V to paste slot config.", + + "reborncore.gui.fluidconfig.pullin": "Pull In", + "reborncore.gui.fluidconfig.pumpout": "Pump Out", + "reborncore.gui.fluidconfig.item_io": "Item I/O", + "reborncore.gui.fluidconfig.power_io": "Power I/O", + "reborncore.gui.fluidconfig.fluid_io": "Fluid I/O", + "reborncore.gui.fluidconfig.recipe_processing": "Crafting", + "reborncore.gui.fluidconfig.ignored": "Ignored", + "reborncore.gui.fluidconfig.enabled_on": "§cRedstone §aOn", + "reborncore.gui.fluidconfig.enabled_off": "§cRedstone §4Off" +} diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/es_AR.lang b/RebornCore/src/main/resources/assets/reborncore/lang/es_AR.lang new file mode 100644 index 000000000..df4a7133f --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/es_AR.lang @@ -0,0 +1,10 @@ +reborncore.message.active=Activo +reborncore.message.inactive=Inactivo + +item.reborncore:manual.name=Manual de Team Reborn + +reborncore.tooltip.energy.maxEnergy=Energía máxima +reborncore.tooltip.energy.inputRate=Tasa de entrada +reborncore.tooltip.energy.outputRate=Tasa de salida +reborncore.tooltip.energy.tier=Tier +reborncore.tooltip.energy.change=Cambio de energía diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/pt_BR.lang b/RebornCore/src/main/resources/assets/reborncore/lang/pt_BR.lang new file mode 100644 index 000000000..5b60ee542 --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/pt_BR.lang @@ -0,0 +1,33 @@ +reborncore.message.active=Ativo +reborncore.message.inactive=Inativo + +item.reborncore:manual.name=Manual do Grupo Reborn + +reborncore.tooltip.energy.maxEnergy=Energia Máx +reborncore.tooltip.energy.inputRate=Taxa de Entrada +reborncore.tooltip.energy.outputRate=Taxa de Saída +reborncore.tooltip.energy.tier=Nível +reborncore.tooltip.energy.change=Troca de Energia + +reborncore.gui.heat=Calor +reborncore.gui.missingmultiblock=Multibloco Incompleto + +reborncore.gui.tooltip.config_slots=Configurar slots +reborncore.gui.tooltip.config_fluids=Configurar Fluídos +reborncore.gui.tooltip.hologram=Alternar Holograma Multibloco +reborncore.gui.tooltip.lock_items=Bloquear Itens +reborncore.gui.tooltip.power_charged=Carregado +reborncore.gui.tooltip.power_click=Clique para mudar unidade de exibição +reborncore.gui.tooltip.power_moreinfo=para mais informações +reborncore.gui.tooltip.dsu_fullness=Cheio +reborncore.gui.tooltip.tank_amount=%smB/%smB +reborncore.gui.tooltip.tank_empty=Tanque Vazio +reborncore.gui.tooltip.tank_fullness=Cheio +reborncore.gui.tooltip.unlock_items=Desbloquear itens +reborncore.gui.tooltip.upgrades=Atualizações de máquinas + +reborncore.gui.slotconfigtip.slot=Clique no slot para configurar. +reborncore.gui.slotconfigtip.side=Lado laranja significa saída, lado azul significa entrada. +reborncore.gui.slotconfigtip.side=Ctrl+C para copiar a configuração de slot, Ctrl+V para colar a configuração de slot. + + diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/pt_br.json b/RebornCore/src/main/resources/assets/reborncore/lang/pt_br.json new file mode 100644 index 000000000..63bcfad8a --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/pt_br.json @@ -0,0 +1,33 @@ +{ + "reborncore.message.active": "Ativo", + "reborncore.message.inactive": "Inativo", + + "item.reborncore:manual.name": "Manual do Grupo Reborn", + + "reborncore.tooltip.energy.maxEnergy": "Energia Máx", + "reborncore.tooltip.energy.inputRate": "Taxa de Entrada", + "reborncore.tooltip.energy.outputRate": "Taxa de Saída", + "reborncore.tooltip.energy.tier": "Nível", + "reborncore.tooltip.energy.change": "Troca de Energia", + + "reborncore.gui.heat": "Calor", + "reborncore.gui.missingmultiblock": "Multibloco Incompleto", + + "reborncore.gui.tooltip.config_slots": "Configurar slots", + "reborncore.gui.tooltip.config_fluids": "Configurar Fluídos", + "reborncore.gui.tooltip.hologram": "Alternar Holograma Multibloco", + "reborncore.gui.tooltip.lock_items": "Bloquear Itens", + "reborncore.gui.tooltip.power_charged": "Carregado", + "reborncore.gui.tooltip.power_click": "Clique para mudar unidade de exibição", + "reborncore.gui.tooltip.power_moreinfo": "para mais informações", + "reborncore.gui.tooltip.dsu_fullness": "Cheio", + "reborncore.gui.tooltip.tank_amount": "%s / %s", + "reborncore.gui.tooltip.tank_empty": "Tanque Vazio", + "reborncore.gui.tooltip.tank_fullness": "Cheio", + "reborncore.gui.tooltip.unlock_items": "Desbloquear itens", + "reborncore.gui.tooltip.upgrades": "Atualizações de máquinas", + + "reborncore.gui.slotconfigtip.slot": "Clique no slot para configurar.", + "reborncore.gui.slotconfigtip.side1": "Lado laranja significa saída, lado azul significa entrada.", + "reborncore.gui.slotconfigtip.side2": "Ctrl+C para copiar a configuração de slot, Ctrl+V para colar a configuração de slot." +} \ No newline at end of file diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/ru_ru.json b/RebornCore/src/main/resources/assets/reborncore/lang/ru_ru.json new file mode 100644 index 000000000..089d6fad2 --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/ru_ru.json @@ -0,0 +1,52 @@ +{ + "reborncore.message.active": "Активно", + "reborncore.message.inactive": "Неактивно", + "reborncore.message.energyError": "Недостаточно энергии:", + "reborncore.message.deactivating": "Деактивировано", + "reborncore.message.setTo": "Изменено на", + + "reborncore.tooltip.energy.maxEnergy": "Макс. энергия", + "reborncore.tooltip.energy.inputRate": "Скорость ввода", + "reborncore.tooltip.energy.outputRate": "Скорость вывода", + "reborncore.tooltip.energy.tier": "Уровень", + "reborncore.tooltip.energy.change": "Изменение энергии", + "reborncore.tooltip.energy": "Накопленная энергия", + + "reborncore.gui.heat": "Нагрев", + "reborncore.gui.missingmultiblock": "Неполный мультиблок", + + "reborncore.gui.tooltip.config_slots": "Настроить слоты", + "reborncore.gui.tooltip.config_fluids": "Настроить жидкости", + "reborncore.gui.tooltip.config_redstone": "Настроить сигнал красного камня", + "reborncore.gui.tooltip.hologram": "Переключить многоблочную голограмму", + "reborncore.gui.tooltip.lock_items": "Заблокировать предметы", + "reborncore.gui.tooltip.power_charged": "Заряженный", + "reborncore.gui.tooltip.power_moreinfo": "для большей информации", + "reborncore.gui.tooltip.dsu_fullness": "Полный", + "reborncore.gui.tooltip.tank_amount": "%s / %s", + "reborncore.gui.tooltip.tank_empty": "Пустой резервуар", + "reborncore.gui.tooltip.tank_fullness": "заполнено", + "reborncore.gui.tooltip.unlock_items": "Разблокировать предметы", + "reborncore.gui.tooltip.upgrades": "Улучшение", + + "reborncore.gui.slotconfig.autoinput": "Авто ввод", + "reborncore.gui.slotconfig.autooutput": "Авто вывод", + "reborncore.gui.slotconfig.filter_input": "Фильтр ввода", + + "reborncore.gui.slotconfigtip.slot": "Выберите слот для настройки.", + "reborncore.gui.slotconfigtip.side1": "Оранжевый - вход.", + "reborncore.gui.slotconfigtip.side2": "Синий - выход.", + "reborncore.gui.slotconfigtip.side3": "Зеленый - вход и выход.", + "reborncore.gui.slotconfigtip.copy1": "Ctrl+C скопировать настройки.", + "reborncore.gui.slotconfigtip.copy2": "Ctrl+V вставить настройки.", + + "reborncore.gui.fluidconfig.pullin": "Закачивать", + "reborncore.gui.fluidconfig.pumpout": "Откачивать", + "reborncore.gui.fluidconfig.item_io": "Предметы", + "reborncore.gui.fluidconfig.power_io": "Энергия", + "reborncore.gui.fluidconfig.fluid_io": "Жидкости", + "reborncore.gui.fluidconfig.recipe_processing": "Создание", + "reborncore.gui.fluidconfig.ignored": "Игнорировать", + "reborncore.gui.fluidconfig.enabled_on": "§cСигнал §aВкл", + "reborncore.gui.fluidconfig.enabled_off": "§cСигнал §4Выкл" +} diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/tr_TR.lang b/RebornCore/src/main/resources/assets/reborncore/lang/tr_TR.lang new file mode 100644 index 000000000..c1a11c6d7 --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/tr_TR.lang @@ -0,0 +1,9 @@ +reborncore.message.active=Aktif +reborncore.message.inactive=İnaktif + +item.reborncore:manual.name=Team Reborn Kullanım Kılavuzu + +reborncore.tooltip.energy.maxEnergy=Maksimum Enerji +reborncore.tooltip.energy.inputRate=Giriş Oranı +reborncore.tooltip.energy.outputRate=Çıkış Oranı +reborncore.tooltip.energy.tier=Aşama \ No newline at end of file diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/zh_CN.lang b/RebornCore/src/main/resources/assets/reborncore/lang/zh_CN.lang new file mode 100644 index 000000000..eb4fd0486 --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/zh_CN.lang @@ -0,0 +1,4 @@ +reborncore.message.active=激活 +reborncore.message.inactive=未激活 + +item.reborncore:manual.name=Reborn 团队手册 diff --git a/RebornCore/src/main/resources/assets/reborncore/lang/zh_cn.json b/RebornCore/src/main/resources/assets/reborncore/lang/zh_cn.json new file mode 100644 index 000000000..2ede0ed14 --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/lang/zh_cn.json @@ -0,0 +1,31 @@ +{ + "reborncore.message.active": "激活", + "reborncore.message.inactive": "未激活", + + "reborncore.tooltip.energy.maxEnergy": "最大能量", + "reborncore.tooltip.energy.inputRate": "输入速率", + "reborncore.tooltip.energy.outputRate": "输出速率", + "reborncore.tooltip.energy.tier": "层", + "reborncore.tooltip.energy.change": "能量变化", + + "reborncore.gui.heat": "热", + "reborncore.gui.missingmultiblock": "多个方块不完整", + + "reborncore.gui.tooltip.config_slots": "配置插槽", + "reborncore.gui.tooltip.config_fluids": "配置流体", + "reborncore.gui.tooltip.hologram": "切换多个方块全息图", + "reborncore.gui.tooltip.lock_items": "锁定物品", + "reborncore.gui.tooltip.power_charged": "充电", + "reborncore.gui.tooltip.power_click": "单击以更改显示单位", + "reborncore.gui.tooltip.power_moreinfo": "了解更多信息", + "reborncore.gui.tooltip.dsu_fullness": "满", + "reborncore.gui.tooltip.tank_amount": "%smB/%smB", + "reborncore.gui.tooltip.tank_empty": "空罐", + "reborncore.gui.tooltip.tank_fullness": "满", + "reborncore.gui.tooltip.unlock_items": "解锁物品", + "reborncore.gui.tooltip.upgrades": "机器升级", + + "reborncore.gui.slotconfigtip.slot": "单击插槽进行配置.", + "reborncore.gui.slotconfigtip.side1": "橙色面表示输出,蓝色面表示输入.", + "reborncore.gui.slotconfigtip.side2": "ctrl+c复制插槽配置,ctrl+v粘贴插槽配置." +} diff --git a/RebornCore/src/main/resources/assets/reborncore/sounds.json b/RebornCore/src/main/resources/assets/reborncore/sounds.json new file mode 100644 index 000000000..d12dea821 --- /dev/null +++ b/RebornCore/src/main/resources/assets/reborncore/sounds.json @@ -0,0 +1,8 @@ +{ + "block_dismantle": { + "category": "block", + "sounds": [ + "reborncore:block_dismantle" + ] + } +} \ No newline at end of file diff --git a/RebornCore/src/main/resources/assets/reborncore/sounds/block_dismantle.ogg b/RebornCore/src/main/resources/assets/reborncore/sounds/block_dismantle.ogg new file mode 100644 index 000000000..af4b63f87 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/sounds/block_dismantle.ogg differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/base.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/base.png new file mode 100644 index 000000000..b0bdb7d6e Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/base.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/elements.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/elements.png new file mode 100644 index 000000000..658a48dd7 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/elements.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/gui_sheet.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/gui_sheet.png new file mode 100644 index 000000000..e38a415b3 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/gui_sheet.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/guielements.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/guielements.png new file mode 100644 index 000000000..877a06ca1 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/guielements.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/guielementsTR.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/guielementsTR.png new file mode 100644 index 000000000..825567214 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/guielementsTR.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/manual.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/manual.png new file mode 100644 index 000000000..aa1227899 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/manual.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/manual_elements.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/manual_elements.png new file mode 100644 index 000000000..3db8ddca2 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/manual_elements.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_chest.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_chest.png new file mode 100644 index 000000000..ae52fd808 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_chest.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_feet.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_feet.png new file mode 100644 index 000000000..774a41471 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_feet.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_head.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_head.png new file mode 100644 index 000000000..d2d2f4df1 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_head.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_legs.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_legs.png new file mode 100644 index 000000000..6ebae576a Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_legs.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_offhand.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_offhand.png new file mode 100644 index 000000000..fb4f1b387 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/armour_offhand.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/cells.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/cells.png new file mode 100644 index 000000000..c68c624d8 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/cells.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/upgrade.png b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/upgrade.png new file mode 100644 index 000000000..0f69c497b Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/gui/slot_sprites/upgrade.png differ diff --git a/RebornCore/src/main/resources/assets/reborncore/textures/models/santa_hat.png b/RebornCore/src/main/resources/assets/reborncore/textures/models/santa_hat.png new file mode 100644 index 000000000..65a76fd96 Binary files /dev/null and b/RebornCore/src/main/resources/assets/reborncore/textures/models/santa_hat.png differ diff --git a/RebornCore/src/main/resources/fabric.mod.json b/RebornCore/src/main/resources/fabric.mod.json new file mode 100644 index 000000000..b54fdf1f2 --- /dev/null +++ b/RebornCore/src/main/resources/fabric.mod.json @@ -0,0 +1,50 @@ +{ + "schemaVersion": 1, + "id": "reborncore", + "version": "${version}", + "name": "Reborn Core", + "icon": "assets/reborncore/icon.png", + "description": "Reborn Core is a library used for many of the Tech Reborn team's mods, including Tech Reborn, Quantum Storage, Fluxed Redstone, Hardcore Map Reset, and many more.", + "license": "MIT", + "contact": { + "homepage": "https://www.curseforge.com/minecraft/mc-mods/reborncore", + "sources": "https://github.com/TechReborn/RebornCore", + "issues": "https://github.com/TechReborn/RebornCore/issues" + }, + "environment": "*", + "entrypoints": { + "main": [ + "reborncore.RebornCore" + ], + "client": [ + "reborncore.RebornCoreClient" + ] + }, + "mixins": [ + "reborncore.client.mixins.json", + "reborncore.common.mixins.json" + ], + "depends": { + "fabricloader": ">=0.6.3", + "fabric": ">=0.28.3", + "team_reborn_energy": ">=0.1.1", + "fabric-biome-api-v1": ">=3.0.0" + }, + "authors": [ + "Team Reborn", + "modmuss50", + "drcrazy" + ], + "contributors": [ + "Gigabit101", + "Prospector", + "Rushmead", + "Dragon2488", + "Ourten", + "coderbot", + "estebes" + ], + "custom": { + "modmenu:api": true + } +} \ No newline at end of file diff --git a/RebornCore/src/main/resources/reborncore.client.mixins.json b/RebornCore/src/main/resources/reborncore.client.mixins.json new file mode 100644 index 000000000..61521d393 --- /dev/null +++ b/RebornCore/src/main/resources/reborncore.client.mixins.json @@ -0,0 +1,16 @@ +{ + "required": true, + "package": "reborncore.mixin.client", + "compatibilityLevel": "JAVA_16", + "client": [ + "MixinGameRenderer", + "MixinItemRenderer", + "MixinDebugRenderer", + "MixinWorldRenderer", + "AccessorModelPredicateProviderRegistry", + "AccessorChatHud" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/RebornCore/src/main/resources/reborncore.common.mixins.json b/RebornCore/src/main/resources/reborncore.common.mixins.json new file mode 100644 index 000000000..3af154233 --- /dev/null +++ b/RebornCore/src/main/resources/reborncore.common.mixins.json @@ -0,0 +1,23 @@ +{ + "required": true, + "package": "reborncore.mixin.common", + "compatibilityLevel": "JAVA_16", + "mixins": [ + "AccessorFluidBlock", + "AccessorFoliagePlacerType", + "AccessorIngredient", + "AccessorRecipeManager", + "AccessorScreenHandler", + "AccessorSlot", + "MixinBucketItem", + "MixinCraftingResultSlot", + "MixinItemEntity", + "MixinItemStack", + "MixinLivingEntity", + "MixinPlayerEntity", + "MixinRecipeManager" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/build.gradle b/build.gradle index fda2444d6..a68707d21 100644 --- a/build.gradle +++ b/build.gradle @@ -6,19 +6,17 @@ buildscript { plugins { id 'java' + id 'java-library' id 'idea' id 'eclipse' id 'maven-publish' id 'signing' id "org.cadixdev.licenser" version "0.5.0" - id "fabric-loom" version "0.6-SNAPSHOT" + id "fabric-loom" version "0.8-SNAPSHOT" id "com.matthewprenger.cursegradle" version "1.4.0" id "de.undercouch.download" version "4.1.1" } -sourceCompatibility = 1.8 -targetCompatibility = 1.8 - repositories { maven { name = "Modmuss50" @@ -50,7 +48,7 @@ repositories { } } -version = "3.8.3" + configurations { shade @@ -69,29 +67,94 @@ license { group = 'TechReborn' -configurations.all { - resolutionStrategy.cacheDynamicVersionsFor 2, 'minutes' +allprojects { + version = "5.0.0-alpha+1.16" + + apply plugin: "fabric-loom" + + sourceCompatibility = JavaVersion.VERSION_16 + targetCompatibility = JavaVersion.VERSION_16 + + configurations { + dev + } + + // Shared deps between TR and RC + dependencies { + minecraft "com.mojang:minecraft:1.16.5" + mappings "net.fabricmc:yarn:1.16.5+build.4:v2" + modImplementation "net.fabricmc:fabric-loader:0.11.3" + + //Fabric api + modImplementation "net.fabricmc.fabric-api:fabric-api:0.30.0+1.16" + + modApi 'teamreborn:energy:0.1.1' + } + + processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } + } + + tasks.withType(JavaCompile).configureEach { + it.options.encoding = "UTF-8" + it.options.release = 16 + } + + java { + withSourcesJar() + } + + publishing { + publications { + maven(MavenPublication) { + groupId project.name + artifactId project.archivesBaseName + version project.version + + artifact(remapJar) { + builtBy remapJar + } + artifact(sourcesJar) { + builtBy remapSourcesJar + } + } + } + repositories { + if (ENV.MAVEN_URL) { + maven { + url ENV.MAVEN_URL + credentials { + username ENV.MAVEN_USERNAME + password ENV.MAVEN_PASSWORD + } + } + } + } + } + + if (ENV.SIGNING_KEY) { + signing { + useInMemoryPgpKeys(ENV.SIGNING_KEY, ENV.SIGNING_PASSWORD) + + sign publishing.publications.maven + sign remapJar + } + + task signAll(dependsOn: [signMavenPublication, signRemapJar, remapJar]) + } } +// TechReborn sepecific deps dependencies { - minecraft "com.mojang:minecraft:1.16.5" - mappings "net.fabricmc:yarn:1.16.5+build.4:v2" - modImplementation "net.fabricmc:fabric-loader:0.11.1" - - //Fabric api - modImplementation "net.fabricmc.fabric-api:fabric-api:0.30.0+1.16" - - optionalDependency "me.shedaniel:RoughlyEnoughItems:5.8.9" - disabledOptionalDependency ('com.github.emilyploszaj:trinkets:2.6.7') - - def rcVersion = 'RebornCore:RebornCore-1.16:+' - modApi (rcVersion) { - exclude group: "net.fabricmc.fabric-api" - } - include rcVersion - - modApi 'teamreborn:energy:0.1.1' + api project(":RebornCore") + include project(":RebornCore") + optionalDependency "me.shedaniel:RoughlyEnoughItems:5.8.9" + disabledOptionalDependency ('com.github.emilyploszaj:trinkets:2.6.7') optionalDependency "com.github.dexman545:autoswitch-api:-SNAPSHOT" } @@ -113,21 +176,6 @@ def disabledOptionalDependency(String dep) { } } -processResources { - inputs.property "version", project.version - - filesMatching("fabric.mod.json") { - expand "version": project.version - } -} - -tasks.withType(JavaCompile).configureEach { - it.options.encoding = "UTF-8" - - if (JavaVersion.current().isJava9Compatible()) { - it.options.release = 8 - } -} jar { exclude "**/*.psd" @@ -194,50 +242,6 @@ task fixTranslations(dependsOn: ['renameCrowdin']) { } } -task sourcesJar(type: Jar, dependsOn: classes) { - classifier = "sources" - from sourceSets.main.allSource -} - -publishing { - publications { - maven(MavenPublication) { - groupId 'TechReborn' - artifactId project.archivesBaseName - version project.version - - artifact(remapJar) { - builtBy remapJar - } - artifact(sourcesJar) { - builtBy remapSourcesJar - } - } - } - repositories { - if (ENV.MAVEN_URL) { - maven { - url ENV.MAVEN_URL - credentials { - username ENV.MAVEN_USERNAME - password ENV.MAVEN_PASSWORD - } - } - } - } -} - -if (ENV.SIGNING_KEY) { - signing { - useInMemoryPgpKeys(ENV.SIGNING_KEY, ENV.SIGNING_PASSWORD) - - sign publishing.publications.maven - sign remapJar - } - - task signAll(dependsOn: [signMavenPublication, signRemapJar, remapJar]) -} - import com.google.gson.JsonArray import groovy.util.XmlSlurper import org.apache.commons.io.FileUtils diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 2a563242c..0f80bbf51 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,5 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-6.8.2-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-7.0.2-bin.zip zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/settings.gradle b/settings.gradle index ade6bbada..61a473e8d 100644 --- a/settings.gradle +++ b/settings.gradle @@ -8,4 +8,6 @@ pluginManagement { } } -rootProject.name = "TechReborn-1.16" \ No newline at end of file +rootProject.name = "TechReborn" + +include("RebornCore") \ No newline at end of file