From 3b2013be9e34305ba98e0dd5624ab0d049dbdb99 Mon Sep 17 00:00:00 2001 From: FITFC <101124415+FITFC@users.noreply.github.com> Date: Sat, 29 Oct 2022 18:25:57 -0500 Subject: [PATCH 01/24] added pt_br.json --- .../src/main/resources/assets/tradingpost/lang/pt_br.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Common/src/main/resources/assets/tradingpost/lang/pt_br.json diff --git a/Common/src/main/resources/assets/tradingpost/lang/pt_br.json b/Common/src/main/resources/assets/tradingpost/lang/pt_br.json new file mode 100644 index 0000000..b611839 --- /dev/null +++ b/Common/src/main/resources/assets/tradingpost/lang/pt_br.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Posto de Comércio", + "container.trading_post": "Posto de Comércio", + "trading_post.no_trader_found": "Não foi possível encontrar nenhum comerciante disponível nas proximidades", + "trading_post.trader_gone": "O comerciante não está mais disponível.", + "trading_post.search": "Procurar..." + } \ No newline at end of file From e36e0b7d2bfaa6083f537788a2b02d7154733f6f Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Fri, 24 Mar 2023 15:29:30 +0100 Subject: [PATCH 02/24] 1.19.3 port --- .github/ISSUE_TEMPLATE/config.yml | 4 +- .gitignore | 7 +- CHANGELOG.md | 17 +-- Common/build.gradle | 65 ++++----- .../java/fuzs/tradingpost/TradingPost.java | 25 ++-- .../tradingpost/client/TradingPostClient.java | 38 ++--- .../screens/inventory/TradingPostScreen.java | 18 +-- .../blockentity/TradingPostRenderer.java | 11 +- .../fuzs/tradingpost/config/ServerConfig.java | 15 +- .../fuzs/tradingpost/init/ModRegistry.java | 22 ++- .../accessor/TradeOfferButtonAccessor.java | 9 +- .../network/S2CBuildOffersMessage.java | 7 +- .../network/S2CMerchantDataMessage.java | 4 +- .../network/S2CRemoveMerchantsMessage.java | 4 +- .../network/client/C2SClearSlotsMessage.java | 4 +- .../world/entity/npc/MerchantCollection.java | 2 +- .../world/item/trading/TradingPostOffers.java | 2 +- .../world/level/block/TradingPostBlock.java | 2 +- .../block/entity/TradingPostBlockEntity.java | 3 +- Common/src/main/resources/pack.mcmeta | 4 +- Common/src/main/resources/quilt.mod.json | 8 -- .../resources/tradingpost.common.mixins.json | 1 + Fabric/build.gradle | 69 +++++----- .../fuzs/tradingpost/TradingPostFabric.java | 4 +- .../client/TradingPostFabricClient.java | 4 +- .../main/java/mixin/ModMixinConfigPlugin.java | 47 +++++++ Fabric/src/main/resources/fabric.mod.json | 8 +- Forge/build.gradle | 76 +++++----- .../bd6432cce18694f9890e2363106a178883f44a06 | 2 + .../assets/minecraft/atlases/blocks.json | 8 ++ .../fuzs/tradingpost/TradingPostForge.java | 21 ++- .../client/TradingPostForgeClient.java | 4 +- .../data/ModSpriteSourceProvider.java | 22 +++ .../mixin/ModMixinConfigPlugin.java | 47 +++++++ Forge/src/main/resources/META-INF/mods.toml | 5 +- LICENSE-ASSETS.md | 1 + LICENSE => LICENSE.md | 0 README.md | 4 +- build.gradle | 19 +-- gradle.properties | 29 ++-- gradle/tasks.gradle | 18 ++- run/config/modmenu.json | 19 --- run/options.txt | 130 ------------------ 43 files changed, 395 insertions(+), 414 deletions(-) delete mode 100644 Common/src/main/resources/quilt.mod.json create mode 100644 Fabric/src/main/java/mixin/ModMixinConfigPlugin.java create mode 100644 Forge/src/generated/resources/.cache/bd6432cce18694f9890e2363106a178883f44a06 create mode 100644 Forge/src/generated/resources/assets/minecraft/atlases/blocks.json create mode 100644 Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java create mode 100644 Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java create mode 100644 LICENSE-ASSETS.md rename LICENSE => LICENSE.md (100%) delete mode 100644 run/config/modmenu.json delete mode 100644 run/options.txt diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index 7f79bf6..e0133b0 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - name: Questions - url: https://discord.gg/8ZmhaPPbjE - about: "Please ask questions on the Luna Pixel Studios Discord (in #fuzs-projects) or contact me directly on Discord at Fuzs#0212." \ No newline at end of file + url: https://lunapixel.studio/discord + about: "Please ask questions on the Luna Pixel Studios Discord in #fuzs-projects." \ No newline at end of file diff --git a/.gitignore b/.gitignore index 29fed19..0c5a409 100644 --- a/.gitignore +++ b/.gitignore @@ -59,14 +59,9 @@ gradle-app.setting .gradletasknamecache ### Other ### +run .DS_Store *.txt -!run -run/* -!run/options.txt -!run/config -run/config/* -!run/config/modmenu.json # Log file *.log diff --git a/CHANGELOG.md b/CHANGELOG.md index eea0371..70f97b8 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,20 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. -## [v4.2.0-1.19.2] - 2022-08-21 -- Compiled for Minecraft 1.19.2 -- Updated to Puzzles Lib v4.2.0 - -## [v4.0.1-1.19] - 2022-08-01 -### Fixed -- Fixed crash on opening trading post menu due to the mod using an outdated version of Puzzles Lib - -## [v4.1.0-1.19.1] - 2022-07-30 -- Compiled for Minecraft 1.19.1 -- Updated to Puzzles Lib v4.1.0 - -## [v4.0.0-1.19] - 2022-07-19 -- Ported to Minecraft 1.19 -- Split into multi-loader project +## [v5.0.0-1.19.3] - 2023-03-24 +- Ported to Minecraft 1.19.3 [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/Common/build.gradle b/Common/build.gradle index 1ea86ea..2b33892 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -1,5 +1,6 @@ plugins { - id 'org.quiltmc.loom' version '0.12.+' + id 'fabric-loom' version '1.0.+' + id 'io.github.juuxel.loom-quiltflower' version '1.7.1' } archivesBaseName = rootProject.name @@ -14,18 +15,8 @@ dependencies { parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") } - // Mixin Dependencies - implementation 'org.ow2.asm:asm-tree:9.2' - implementation 'org.ow2.asm:asm-commons:9.2' - implementation 'org.ow2.asm:asm-util:9.2' - implementation 'org.spongepowered:mixin:0.8.5' - - // Config Dependencies - implementation 'com.electronwill.night-config:core:3.6.5' - implementation 'com.electronwill.night-config:toml:3.6.5' - // Puzzles Lib - modImplementation "fuzs.puzzleslib:puzzleslib-common:${puzzlesVersion}" + modApi "fuzs.puzzleslib:puzzleslib-common:${puzzlesVersion}" } loom { @@ -57,26 +48,16 @@ processResources { duplicatesStrategy DuplicatesStrategy.INCLUDE // this will ensure that this task is redone when a value changes - inputs.property "modId", "${modId}" - inputs.property "modVersion", "${modVersion}" - inputs.property "modGroup", project.group inputs.property "modDescription", "${modDescription}" - inputs.property "packFormat", "${packFormat}" - - // replace stuff in fabric.mod.json and pack.mcmeta - filesMatching ('quilt.mod.json') { - expand ( - 'modId': "${modId}", - 'modVersion': "${modVersion}", - 'modGroup': project.group - ) - } + inputs.property "resourcePackFormat", "${resourcePackFormat}" + inputs.property "dataPackFormat", "${dataPackFormat}" // replace stuff in pack.mcmeta filesMatching ('pack.mcmeta') { expand ( 'modDescription': "${modDescription}", - "packFormat": "${packFormat}" + "resourcePackFormat": "${resourcePackFormat}", + "dataPackFormat": "${dataPackFormat}" ) } } @@ -113,18 +94,6 @@ publishing { } } } - afterEvaluate { - // exclude certain dependencies when publishing to maven - // from https://stackoverflow.com/a/50121790 - pom.withXml { - asNode().dependencies.dependency.each { dep -> - // use this approach to make excluding dependencies from Curse Maven more convenient - if ([].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { - assert dep.parent().remove(dep) - } - } - } - } } } repositories { @@ -138,3 +107,23 @@ publishing { signing { sign publishing.publications.mavenJava } + +import net.fabricmc.loom.task.AbstractRemapJarTask + +// thanks to lukebemish for this comment: https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 +tasks.withType(AbstractRemapJarTask).each { + it.targetNamespace = "named" +} + +task copyJarToDir(type: Copy) { + onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } + if (project.findProperty('copyBuildJar').toBoolean()) { + from remapJar + into project.findProperty('buildJarOutputDir') + // add build number to be able to distinguish jars when testing thorough official launcher + // build number is stored in global gradle.properties + rename { fileName -> fileName.replace("v${modVersion}", "v${modVersion}.${uniqueBuildNumber}") } + } +} + +build.finalizedBy project.tasks.copyJarToDir, rootProject.tasks.incrementBuildNumber diff --git a/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/Common/src/main/java/fuzs/tradingpost/TradingPost.java index 15db11d..19139c2 100644 --- a/Common/src/main/java/fuzs/tradingpost/TradingPost.java +++ b/Common/src/main/java/fuzs/tradingpost/TradingPost.java @@ -1,16 +1,17 @@ package fuzs.tradingpost; -import fuzs.puzzleslib.config.ConfigHolder; -import fuzs.puzzleslib.core.CoreServices; -import fuzs.puzzleslib.core.ModConstructor; -import fuzs.puzzleslib.network.MessageDirection; -import fuzs.puzzleslib.network.NetworkHandler; +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.core.v1.context.FuelBurnTimesContext; +import fuzs.puzzleslib.api.network.v2.MessageDirection; +import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; import fuzs.tradingpost.config.ServerConfig; import fuzs.tradingpost.init.ModRegistry; -import fuzs.tradingpost.network.client.C2SClearSlotsMessage; import fuzs.tradingpost.network.S2CBuildOffersMessage; import fuzs.tradingpost.network.S2CMerchantDataMessage; import fuzs.tradingpost.network.S2CRemoveMerchantsMessage; +import fuzs.tradingpost.network.client.C2SClearSlotsMessage; +import net.minecraft.resources.ResourceLocation; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -19,13 +20,11 @@ public class TradingPost implements ModConstructor { public static final String MOD_NAME = "Trading Post"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - public static final NetworkHandler NETWORK = CoreServices.FACTORIES.network(MOD_ID); - @SuppressWarnings("Convert2MethodRef") - public static final ConfigHolder CONFIG = CoreServices.FACTORIES.serverConfig(ServerConfig.class, () -> new ServerConfig()); + public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID); + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).server(ServerConfig.class); @Override public void onConstructMod() { - CONFIG.bakeConfigs(MOD_ID); ModRegistry.touch(); registerMessages(); } @@ -39,6 +38,10 @@ private static void registerMessages() { @Override public void onRegisterFuelBurnTimes(FuelBurnTimesContext context) { - context.registerWoodenBlock(ModRegistry.TRADING_POST_BLOCK.get()); + context.registerFuel(300, ModRegistry.TRADING_POST_BLOCK.get()); + } + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); } } diff --git a/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java index 62d9af3..2fd34d2 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java +++ b/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -1,41 +1,38 @@ package fuzs.tradingpost.client; -import fuzs.puzzleslib.client.core.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; +import fuzs.puzzleslib.api.client.core.v1.context.BuildCreativeModeTabContentsContext; +import fuzs.puzzleslib.api.client.core.v1.context.SearchRegistryContext; +import fuzs.puzzleslib.api.core.v1.context.ModLifecycleContext; import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; import fuzs.tradingpost.client.renderer.blockentity.TradingPostRenderer; import fuzs.tradingpost.init.ModRegistry; import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.searchtree.FullTextSearchTree; -import net.minecraft.client.searchtree.SearchRegistry; -import net.minecraft.core.Registry; -import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; -import net.minecraft.world.item.trading.MerchantOffer; import java.util.stream.Stream; public class TradingPostClient implements ClientModConstructor { - public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); @Override - public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { - context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), TradingPostRenderer::new); - } - - @Override - public void onRegisterMenuScreens(MenuScreensContext context) { - context.registerMenuScreen(ModRegistry.TRADING_POST_MENU_TYPE.get(), TradingPostScreen::new); + public void onClientSetup(ModLifecycleContext context) { + MenuScreens.register(ModRegistry.TRADING_POST_MENU_TYPE.get(), TradingPostScreen::new); } @Override - public void onRegisterAtlasSprites(AtlasSpritesContext context) { - context.registerAtlasSprite(InventoryMenu.BLOCK_ATLAS, TradingPostScreen.MAGNIFYING_GLASS_LOCATION); + public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { + context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), TradingPostRenderer::new); } @Override public void onRegisterSearchTrees(SearchRegistryContext context) { - context.registerSearchTree(OFFER_SEARCH_TREE, base -> new FullTextSearchTree<>(offer -> + context.registerSearchTree(TradingPostScreen.OFFER_SEARCH_TREE, base -> new FullTextSearchTree<>(offer -> Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) .filter(itemStack -> !itemStack.isEmpty()) .flatMap(itemStack -> itemStack.getTooltipLines(null, TooltipFlag.Default.NORMAL).stream()) @@ -44,8 +41,15 @@ public void onRegisterSearchTrees(SearchRegistryContext context) { offer -> Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) .filter(itemStack -> !itemStack.isEmpty()) .map(ItemStack::getItem) - .map(Registry.ITEM::getKey), + .map(BuiltInRegistries.ITEM::getKey), base )); } + + @Override + public void onBuildCreativeModeTabContents(BuildCreativeModeTabContentsContext context) { + context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (featureFlagSet, output, bl) -> { + output.accept(ModRegistry.TRADING_POST_ITEM.get()); + }); + } } diff --git a/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java index d876ad6..3bafe21 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java +++ b/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -2,9 +2,7 @@ import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; -import fuzs.puzzleslib.client.core.ClientCoreServices; import fuzs.tradingpost.TradingPost; -import fuzs.tradingpost.client.TradingPostClient; import fuzs.tradingpost.mixin.client.accessor.ButtonAccessor; import fuzs.tradingpost.mixin.client.accessor.MerchantScreenAccessor; import fuzs.tradingpost.mixin.client.accessor.TradeOfferButtonAccessor; @@ -15,10 +13,11 @@ import net.minecraft.client.gui.GuiComponent; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.components.Widget; +import net.minecraft.client.gui.components.Renderable; import net.minecraft.client.gui.screens.inventory.MerchantScreen; import net.minecraft.client.renderer.GameRenderer; import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.client.searchtree.SearchTree; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ServerboundSelectTradePacket; @@ -37,6 +36,7 @@ public class TradingPostScreen extends MerchantScreen { public static final ResourceLocation MAGNIFYING_GLASS_LOCATION = new ResourceLocation(TradingPost.MOD_ID, "item/magnifying_glass"); + public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); private static final ResourceLocation VILLAGER_LOCATION = new ResourceLocation("textures/gui/container/villager2.png"); private static final ResourceLocation CREATIVE_INVENTORY_LOCATION = new ResourceLocation("textures/gui/container/creative_inventory/tab_item_search.png"); private static final Component DEPRECATED_TOOLTIP = Component.translatable("merchant.deprecated"); @@ -54,13 +54,13 @@ public TradingPostScreen(MerchantMenu container, Inventory playerInventory, Comp @Override protected void init() { super.init(); - this.tradeOfferButtons = this.getTradeOfferButtons(ClientCoreServices.SCREENS.getRenderableButtons(this)); + this.tradeOfferButtons = this.getTradeOfferButtons(this.renderables); for (Button tradeOfferButton : this.tradeOfferButtons) { ((ButtonAccessor) tradeOfferButton).setOnPress(button -> { MerchantScreenAccessor accessor = (MerchantScreenAccessor) this; - final int shopItem = ((TradeOfferButtonAccessor) button).getIndex() + accessor.getScrollOff(); + final int shopItem = ((TradeOfferButtonAccessor) button).tradingpost$getIndex() + accessor.getScrollOff(); MerchantOffers offers = this.getMenu().getOffers(); accessor.setShopItem(shopItem); this.getMenu().setSelectionHint(shopItem); @@ -88,7 +88,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { this.addWidget(this.searchBox); } - private Button[] getTradeOfferButtons(List buttons) { + private Button[] getTradeOfferButtons(List buttons) { Button[] tradeOfferButtons = buttons.stream() .filter(button -> button instanceof TradeOfferButtonAccessor) .map(button -> (Button) button) @@ -259,7 +259,7 @@ public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialT Button button = offerButtons[i]; if (button.active && button.isHoveredOrFocused()) { - button.renderToolTip(matrixStack, mouseX, mouseY); + ((TradeOfferButtonAccessor) button).tradingpost$callRenderToolTip(matrixStack, mouseX, mouseY); } button.visible = i < this.getMenu().getOffers().size(); @@ -297,7 +297,7 @@ protected void renderBg(PoseStack matrixStack, float partialTicks, int mouseX, i this.renderSearchBox(matrixStack, partialTicks, mouseX, mouseY); TextureAtlasSprite textureatlassprite = this.minecraft.getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(MAGNIFYING_GLASS_LOCATION); RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, textureatlassprite.atlas().location()); + RenderSystem.setShaderTexture(0, textureatlassprite.atlasLocation()); blit(matrixStack, this.leftPos, this.topPos + 4, this.getBlitOffset(), 16, 16, textureatlassprite); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); @@ -373,7 +373,7 @@ public void refreshSearchResults() { if (query.isEmpty()) { offers.clearFilter(); } else { - SearchTree isearchtree = this.minecraft.getSearchTree(TradingPostClient.OFFER_SEARCH_TREE); + SearchTree isearchtree = this.minecraft.getSearchTree(OFFER_SEARCH_TREE); offers.setFilter(isearchtree.search(query.toLowerCase(Locale.ROOT))); } ((MerchantScreenAccessor) this).setScrollOff(0); diff --git a/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java index b1faf5a..2c9af19 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java +++ b/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java @@ -1,7 +1,7 @@ package fuzs.tradingpost.client.renderer.blockentity; import com.mojang.blaze3d.vertex.PoseStack; -import com.mojang.math.Vector3f; +import com.mojang.math.Axis; import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; @@ -14,12 +14,11 @@ import net.minecraft.world.item.Items; /** - * mostly copied from Quark's matrix enchanting table by Vazkii - * https://github.com/Vazkii/Quark/blob/master/src/main/java/vazkii/quark/addons/oddities/client/render/MatrixEnchantingTableTileEntityRenderer.java + * Mostly copied from Quark's MatrixEnchantingTableRenderer.java by Vazkii, thanks! */ public class TradingPostRenderer implements BlockEntityRenderer { - public TradingPostRenderer(BlockEntityRendererProvider.Context pContext) { + public TradingPostRenderer(BlockEntityRendererProvider.Context context) { } @@ -45,9 +44,9 @@ private void renderItem(ItemStack stack, float ageInTicks, float bookOpen, float bookRotation *= -180.0F / (float) Math.PI; bookRotation -= 90.0F; bookRotation *= bookOpen; - matrixStackIn.mulPose(Vector3f.YP.rotationDegrees(bookRotation)); + matrixStackIn.mulPose(Axis.YP.rotationDegrees(bookRotation)); matrixStackIn.translate(0.0F, bookOpen, Math.sin(bookOpen * Math.PI)); - matrixStackIn.mulPose(Vector3f.XP.rotationDegrees(-90.0F * (bookOpen - 1.0F))); + matrixStackIn.mulPose(Axis.XP.rotationDegrees(-90.0F * (bookOpen - 1.0F))); float hoveringHeight = (float) Math.sin(ageInTicks * 0.06F) * bookOpen * 0.2F; matrixStackIn.translate(0.0F, hoveringHeight, 0.0F); ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); diff --git a/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java b/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java index 7c75a98..936d6a4 100644 --- a/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java +++ b/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java @@ -1,15 +1,14 @@ package fuzs.tradingpost.config; import com.google.common.collect.Lists; -import fuzs.puzzleslib.config.ConfigCore; -import fuzs.puzzleslib.config.annotation.Config; -import fuzs.puzzleslib.config.serialization.EntryCollectionBuilder; +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; +import fuzs.puzzleslib.api.config.v3.serialization.ConfigDataSet; import fuzs.tradingpost.TradingPost; -import net.minecraft.core.Registry; +import net.minecraft.core.registries.Registries; import net.minecraft.world.entity.EntityType; import java.util.List; -import java.util.Set; public class ServerConfig implements ConfigCore { @Config(description = "Range on xz plane trading post should search for merchants.") @@ -24,13 +23,13 @@ public class ServerConfig implements ConfigCore { public boolean teleportXp = true; @Config(name = "close_empty_screen", description = "Close trading post interface when all traders have become unavailable.") public boolean closeScreen = true; - @Config(name = "trader_blacklist", description = {"Trader entities disabled from being found by the trading post.", "Modders may add their own incompatible trader entities via the \"" + TradingPost.MOD_ID + ":blacklisted_traders\" entity tag.", EntryCollectionBuilder.CONFIG_DESCRIPTION}) + @Config(name = "trader_blacklist", description = {"Trader entities disabled from being found by the trading post.", "Modders may add their own incompatible trader entities via the \"" + TradingPost.MOD_ID + ":blacklisted_traders\" entity tag.", ConfigDataSet.CONFIG_DESCRIPTION}) List traderBlacklistRaw = Lists.newArrayList(); - public Set> traderBlacklist; + public ConfigDataSet> traderBlacklist; @Override public void afterConfigReload() { - this.traderBlacklist = EntryCollectionBuilder.of(Registry.ENTITY_TYPE_REGISTRY).buildSet(this.traderBlacklistRaw); + this.traderBlacklist = ConfigDataSet.from(Registries.ENTITY_TYPE, this.traderBlacklistRaw); } } diff --git a/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java index 83aec75..c9bf687 100644 --- a/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java +++ b/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java @@ -1,19 +1,15 @@ package fuzs.tradingpost.init; -import fuzs.puzzleslib.core.CoreServices; -import fuzs.puzzleslib.init.RegistryManager; -import fuzs.puzzleslib.init.RegistryReference; -import fuzs.puzzleslib.init.builder.ModBlockEntityTypeBuilder; +import fuzs.puzzleslib.api.init.v2.RegistryManager; +import fuzs.puzzleslib.api.init.v2.RegistryReference; import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.world.inventory.TradingPostMenu; import fuzs.tradingpost.world.level.block.TradingPostBlock; import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; -import net.minecraft.core.Registry; -import net.minecraft.resources.ResourceLocation; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.EntityType; import net.minecraft.world.inventory.MenuType; -import net.minecraft.world.item.CreativeModeTab; +import net.minecraft.world.item.Item; import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntityType; @@ -21,12 +17,12 @@ import net.minecraft.world.level.material.Material; public class ModRegistry { - private static final RegistryManager REGISTRY = CoreServices.FACTORIES.registration(TradingPost.MOD_ID); - public static final RegistryReference TRADING_POST_BLOCK = REGISTRY.registerBlockWithItem("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of(Material.WOOD).strength(2.5F).sound(SoundType.WOOD)), CreativeModeTab.TAB_DECORATIONS); - public static final RegistryReference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityTypeBuilder("trading_post", () -> ModBlockEntityTypeBuilder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.get())); - public static final RegistryReference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuTypeSupplier("trading_post", () -> TradingPostMenu::new); - - public static final TagKey> BLACKLISTED_TRADERS_TAG = TagKey.create(Registry.ENTITY_TYPE_REGISTRY, new ResourceLocation(TradingPost.MOD_ID, "blacklisted_traders")); + static final RegistryManager REGISTRY = RegistryManager.instant(TradingPost.MOD_ID); + public static final RegistryReference TRADING_POST_BLOCK = REGISTRY.registerBlock("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of(Material.WOOD).strength(2.5F).sound(SoundType.WOOD))); + public static final RegistryReference TRADING_POST_ITEM = REGISTRY.registerBlockItem(TRADING_POST_BLOCK); + public static final RegistryReference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType("trading_post", () -> BlockEntityType.Builder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.get())); + public static final RegistryReference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); + public static final TagKey> BLACKLISTED_TRADERS_TAG = REGISTRY.createEntityTypeTag("blacklisted_traders"); public static void touch() { diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java index d481a31..402bf79 100644 --- a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java +++ b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java @@ -1,11 +1,16 @@ package fuzs.tradingpost.mixin.client.accessor; +import com.mojang.blaze3d.vertex.PoseStack; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; @Mixin(targets = "net.minecraft.client.gui.screens.inventory.MerchantScreen$TradeOfferButton") public interface TradeOfferButtonAccessor { - @Accessor - int getIndex(); + @Accessor("index") + int tradingpost$getIndex(); + + @Invoker("renderToolTip") + void tradingpost$callRenderToolTip(PoseStack poseStack, int mouseX, int mouseY); } diff --git a/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java b/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java index 65533bc..a892cec 100644 --- a/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java +++ b/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java @@ -1,7 +1,6 @@ package fuzs.tradingpost.network; -import fuzs.puzzleslib.network.Message; -import fuzs.tradingpost.client.TradingPostClient; +import fuzs.puzzleslib.api.network.v2.MessageV2; import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; import fuzs.tradingpost.world.inventory.TradingPostMenu; import it.unimi.dsi.fastutil.ints.Int2IntMap; @@ -10,7 +9,7 @@ import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.player.Player; -public class S2CBuildOffersMessage implements Message { +public class S2CBuildOffersMessage implements MessageV2 { private int containerId; private Int2IntOpenHashMap idToOfferCount; @@ -53,7 +52,7 @@ public void handle(S2CBuildOffersMessage message, Player player, Object gameInst Minecraft minecraft = (Minecraft) gameInstance; if (message.containerId == player.containerMenu.containerId && player.containerMenu instanceof TradingPostMenu playerMenu && minecraft.screen instanceof TradingPostScreen screen) { playerMenu.getTraders().buildOffers(message.idToOfferCount); - minecraft.populateSearchTree(TradingPostClient.OFFER_SEARCH_TREE, playerMenu.getOffers()); + minecraft.populateSearchTree(TradingPostScreen.OFFER_SEARCH_TREE, playerMenu.getOffers()); screen.refreshSearchResults(); } } diff --git a/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java b/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java index 9ef20ad..91c9727 100644 --- a/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java +++ b/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java @@ -1,6 +1,6 @@ package fuzs.tradingpost.network; -import fuzs.puzzleslib.network.Message; +import fuzs.puzzleslib.api.network.v2.MessageV2; import fuzs.tradingpost.world.inventory.TradingPostMenu; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.chat.Component; @@ -8,7 +8,7 @@ import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.trading.MerchantOffers; -public class S2CMerchantDataMessage implements Message { +public class S2CMerchantDataMessage implements MessageV2 { private int containerId; private int merchantId; private Component merchantTitle; diff --git a/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java b/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java index 84e4f8c..8aa0653 100644 --- a/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java +++ b/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java @@ -1,6 +1,6 @@ package fuzs.tradingpost.network; -import fuzs.puzzleslib.network.Message; +import fuzs.puzzleslib.api.network.v2.MessageV2; import fuzs.tradingpost.world.inventory.TradingPostMenu; import it.unimi.dsi.fastutil.ints.IntOpenHashSet; import it.unimi.dsi.fastutil.ints.IntSet; @@ -8,7 +8,7 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -public class S2CRemoveMerchantsMessage implements Message { +public class S2CRemoveMerchantsMessage implements MessageV2 { private int containerId; private IntSet merchantIds; diff --git a/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java b/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java index 0b895e2..ba5d25a 100644 --- a/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java +++ b/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java @@ -1,12 +1,12 @@ package fuzs.tradingpost.network.client; -import fuzs.puzzleslib.network.Message; +import fuzs.puzzleslib.api.network.v2.MessageV2; import fuzs.tradingpost.world.inventory.TradingPostMenu; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; -public class C2SClearSlotsMessage implements Message { +public class C2SClearSlotsMessage implements MessageV2 { @Override public void write(FriendlyByteBuf buf) { diff --git a/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java b/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java index 19ba577..b0488aa 100644 --- a/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java +++ b/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java @@ -27,8 +27,8 @@ import net.minecraft.world.item.trading.MerchantOffers; import net.minecraft.world.phys.AABB; import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Comparator; import java.util.List; import java.util.Map; diff --git a/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java b/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java index c46e9b5..8bde01b 100644 --- a/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java +++ b/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java @@ -3,8 +3,8 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.world.item.trading.MerchantOffers; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.Collection; import java.util.Set; diff --git a/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java b/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java index 2407e92..9fd17c4 100644 --- a/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java +++ b/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java @@ -45,8 +45,8 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; -import javax.annotation.Nullable; import java.util.List; @SuppressWarnings("deprecation") diff --git a/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java index 039690b..33bd5d4 100644 --- a/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java +++ b/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java @@ -11,8 +11,7 @@ import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; - -import javax.annotation.Nullable; +import org.jetbrains.annotations.Nullable; public class TradingPostBlockEntity extends BlockEntity implements Nameable { private Component name; diff --git a/Common/src/main/resources/pack.mcmeta b/Common/src/main/resources/pack.mcmeta index 6221806..19bfab2 100755 --- a/Common/src/main/resources/pack.mcmeta +++ b/Common/src/main/resources/pack.mcmeta @@ -1,6 +1,8 @@ { "pack": { "description": "${modDescription}", - "pack_format": ${packFormat} + "pack_format": ${resourcePackFormat}, + "forge:resource_pack_format": ${resourcePackFormat}, + "forge:data_pack_format": ${dataPackFormat} } } diff --git a/Common/src/main/resources/quilt.mod.json b/Common/src/main/resources/quilt.mod.json deleted file mode 100644 index 878577d..0000000 --- a/Common/src/main/resources/quilt.mod.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "schema_version": 1, - "quilt_loader": { - "group": "${modGroup}", - "id": "${modId}", - "version": "${modVersion}" - } -} diff --git a/Common/src/main/resources/tradingpost.common.mixins.json b/Common/src/main/resources/tradingpost.common.mixins.json index 097e18e..7833fd6 100644 --- a/Common/src/main/resources/tradingpost.common.mixins.json +++ b/Common/src/main/resources/tradingpost.common.mixins.json @@ -4,6 +4,7 @@ "compatibilityLevel": "JAVA_17", "package": "fuzs.tradingpost.mixin", "refmap": "tradingpost.refmap.json", + "plugin": "fuzs.tradingpost.mixin.ModMixinConfigPlugin", "mixins": [ "accessor.MerchantMenuAccessor", "accessor.VillagerAccessor" diff --git a/Fabric/build.gradle b/Fabric/build.gradle index 74674f2..57cbe18 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -1,5 +1,5 @@ plugins { - id 'fabric-loom' version '0.12-SNAPSHOT' + id 'fabric-loom' version '1.0.+' id 'io.github.juuxel.loom-quiltflower' version '1.7.1' // this depends on an older version of guava, which loom is incompatible with, so make sure to apply this plugin after loom // haven't found a proper way to manage plugin dependencies otherwise @@ -32,28 +32,28 @@ repositories { } dependencies { - // Include Common Project - compileOnly project(":Common") + // Common Project + compileOnly(project(path: ":Common", configuration: "namedElements")) { + transitive = false + } // Minecraft minecraft "com.mojang:minecraft:${minecraftVersion}" mappings loom.layered() { officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") + parchment("org.parchmentmc.data:parchment-${parchmentMinecraftVersion}:${parchmentMappingsVersion}@zip") } // Fabric - modImplementation "net.fabricmc:fabric-loader:${fabricVersion}" - modImplementation "net.fabricmc.fabric-api:fabric-api:${fabricApiVersion}" - - // Forge Configs - modImplementation "net.minecraftforge:forgeconfigapiport-fabric:4.2.0" + modApi "net.fabricmc:fabric-loader:${fabricVersion}" + modApi "net.fabricmc.fabric-api:fabric-api:${fabricApiVersion}" - // Mod Menu - modRuntimeOnly "com.terraformersmc:modmenu:4.0.6" + // Quality of Life Mods + modLocalRuntime "com.terraformersmc:modmenu:5.0.2" + modLocalRuntime "curse.maven:configured-fabric-667378:4441611" // Puzzles Lib - modImplementation "fuzs.puzzleslib:puzzleslib-fabric:${puzzlesVersion}" + modApi "fuzs.puzzleslib:puzzleslib-fabric:${puzzlesVersion}" } loom { @@ -78,9 +78,15 @@ loom { } processResources { - from project(":Common").sourceSets.main.resources - // we need to have this in common so that in a non-production environment the common jar is correctly deobfuscated - exclude("**/quilt.mod.json") + from(project(":Common").sourceSets.main.resources) + from(project(":Forge").file('src/generated/resources')) { + exclude('.cache/') + } + // Forge's data gen doesn't work with assets placed in the common project, so we place them in Forge and include them here + from(project(":Forge").sourceSets.main.resources) { + include("assets/") + include("data/") + } duplicatesStrategy DuplicatesStrategy.INCLUDE @@ -95,15 +101,15 @@ processResources { inputs.property "modAuthor", "${modAuthor}" inputs.property "minFabricVersion", "${minFabricVersion}" inputs.property "minFabricApiVersion", "${minFabricApiVersion}" - inputs.property "minMinecraftVersion", "${minMinecraftVersion}" - inputs.property "nextMinecraftVersion", rootProject.getNextVersion("${minMinecraftVersion}") + inputs.property "minecraftVersion", "${minecraftVersion}" inputs.property "minPuzzlesVersion", "${minPuzzlesVersion}" - inputs.property "packFormat", "${packFormat}" + inputs.property "resourcePackFormat", "${resourcePackFormat}" + inputs.property "dataPackFormat", "${dataPackFormat}" inputs.property "mainEntryPoint", "${project.group}.${rootProject.name}Fabric" inputs.property "clientEntryPoint", "${project.group}.client.${rootProject.name}FabricClient" inputs.property "modFabricEnvironment", "${modFabricEnvironment}" - // replace stuff in fabric.mod.json and pack.mcmeta + // replace stuff in fabric.mod.json filesMatching ('fabric.mod.json') { expand ( 'modId': "${modId}", @@ -116,8 +122,7 @@ processResources { 'modAuthor': "${modAuthor}", 'minFabricVersion': "${minFabricVersion}", 'minFabricApiVersion': "${minFabricApiVersion}", - 'minMinecraftVersion': "${minMinecraftVersion}", - "nextMinecraftVersion": rootProject.getNextVersion("${minMinecraftVersion}"), + 'minecraftVersion': "${minecraftVersion}", "minPuzzlesVersion": "${minPuzzlesVersion}", "mainEntryPoint": "${project.group}.${rootProject.name}Fabric", "clientEntryPoint": "${project.group}.client.${rootProject.name}FabricClient", @@ -125,10 +130,12 @@ processResources { ) } + // replace stuff in pack.mcmeta filesMatching ('pack.mcmeta') { expand ( 'modDescription': "${modDescription}", - "packFormat": "${packFormat}" + "resourcePackFormat": "${resourcePackFormat}", + "dataPackFormat": "${dataPackFormat}" ) } } @@ -177,18 +184,6 @@ publishing { } } } - afterEvaluate { - // exclude certain dependencies when publishing to maven - // from https://stackoverflow.com/a/50121790 - pom.withXml { - asNode().dependencies.dependency.each { dep -> - // use this approach to make excluding dependencies from Curse Maven more convenient - if (["com.terraformersmc:modmenu"].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { - assert dep.parent().remove(dep) - } - } - } - } } } repositories { @@ -223,7 +218,7 @@ curseforge { requiredDependency 'puzzles-lib' } } - addArtifact sourcesJar +// addArtifact sourcesJar } options { // debug = true @@ -245,7 +240,7 @@ modrinth { gameVersions.add it.trim() } loaders.add 'fabric' - additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") +// additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") dependencies { required.project 'fabric-api' required.project 'forge-config-api-port' @@ -254,8 +249,6 @@ modrinth { // debugMode = true } -import groovy.json.* - task copyJarToDir(type: Copy) { onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } if (project.findProperty('copyBuildJar').toBoolean()) { diff --git a/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java b/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java index 720fea7..5fc6ff1 100644 --- a/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java +++ b/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java @@ -1,12 +1,12 @@ package fuzs.tradingpost; -import fuzs.puzzleslib.core.CoreServices; +import fuzs.puzzleslib.api.core.v1.ModConstructor; import net.fabricmc.api.ModInitializer; public class TradingPostFabric implements ModInitializer { @Override public void onInitialize() { - CoreServices.FACTORIES.modConstructor(TradingPost.MOD_ID).accept(new TradingPost()); + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); } } diff --git a/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java b/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java index ce8cb77..c5198a1 100644 --- a/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java +++ b/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java @@ -1,6 +1,6 @@ package fuzs.tradingpost.client; -import fuzs.puzzleslib.client.core.ClientCoreServices; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.tradingpost.TradingPost; import net.fabricmc.api.ClientModInitializer; @@ -8,6 +8,6 @@ public class TradingPostFabricClient implements ClientModInitializer { @Override public void onInitializeClient() { - ClientCoreServices.FACTORIES.clientModConstructor(TradingPost.MOD_ID).accept(new TradingPostClient()); + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); } } diff --git a/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java b/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..c394fbe --- /dev/null +++ b/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package mixin; + +import net.fabricmc.loader.api.FabricLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FabricLoader.getInstance().isModLoaded("puzzleslib"); + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index e370de7..86f93d9 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -5,19 +5,22 @@ "name": "${modName}", "description": "${modDescription}", + "authors": [ "${modAuthor}" ], + "contact": { "homepage": "${modPageUrl}", "issues": "${modIssueUrl}", "sources": "${modPageUrl}" }, - "license": "MPL-2", + "license": "MPL-2.0", "icon": "mod_logo.png", "environment": "${modFabricEnvironment}", + "entrypoints": { "main": [ "${mainEntryPoint}" @@ -26,6 +29,7 @@ "${clientEntryPoint}" ] }, + "mixins": [ "${modId}.common.mixins.json" ], @@ -34,7 +38,7 @@ "fabricloader": ">=${minFabricVersion}", "fabric-api": ">=${minFabricApiVersion}", "puzzleslib": ">=${minPuzzlesVersion}", - "minecraft": ">=${minMinecraftVersion} <${nextMinecraftVersion}", + "minecraft": "${minecraftVersion}", "java": ">=17" } } diff --git a/Forge/build.gradle b/Forge/build.gradle index d34bd7c..bc302cb 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -18,16 +18,16 @@ plugins { } apply plugin: 'net.minecraftforge.gradle' +apply plugin: 'org.parchmentmc.librarian.forgegradle' apply plugin: 'eclipse' apply plugin: 'org.spongepowered.mixin' -apply plugin: 'org.parchmentmc.librarian.forgegradle' archivesBaseName = rootProject.name version = "v${modVersion}-${minecraftVersion}-Forge" group = modMavenGroup minecraft { - mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${minecraftVersion}" + mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${parchmentMinecraftVersion}" // mappings channel: 'official', version: "${minecraftVersion}" runs { @@ -106,21 +106,22 @@ minecraft { } dependencies { - // Include Common Project - compileOnly project(":Common") + // Common Project + compileOnly(project(":Common")) { + transitive = false + } // Minecraft minecraft "net.minecraftforge:forge:${forgeVersion}" annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' // Quality of Life Mods - runtimeOnly fg.deobf("curse.maven:catalogue-459701:3873264") - runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:4.2.0") -// runtimeOnly fg.deobf("curse.maven:configmenusforge-544048:3822820") -// runtimeOnly fg.deobf("curse.maven:configured-457570:3903908") + runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:5.0.0") + runtimeOnly fg.deobf("curse.maven:catalogue-459701:4171025") + runtimeOnly fg.deobf("curse.maven:configured-457570:4441589") // Puzzles Lib - implementation fg.deobf("fuzs.puzzleslib:puzzleslib-forge:${puzzlesVersion}") + api fg.deobf("fuzs.puzzleslib:puzzleslib-forge:${puzzlesVersion}") } mixin { @@ -136,31 +137,32 @@ mixin { } processResources { - from project(":Common").sourceSets.main.resources - // we need to have this in common so that in a non-production environment the common jar is correctly deobfuscated - exclude("**/quilt.mod.json") + from(project(":Common").sourceSets.main.resources) + from(file('src/generated/resources')) { + exclude('.cache/') + } duplicatesStrategy DuplicatesStrategy.INCLUDE // this will ensure that this task is redone when a value changes - inputs.property "modId", "${modId}" - inputs.property "modName", "${modName}" - inputs.property "modVersion", "${modVersion}" - inputs.property "modDescription", "${modDescription}" - inputs.property "modGroup", project.group - inputs.property "modPageUrl", "${modSourceUrl}" - inputs.property "modUpdateUrl", "${modUpdateUrl}" - inputs.property "modIssueUrl", "${modIssueUrl}" - inputs.property "modAuthor", "${modAuthor}" - inputs.property "minFMLVersion", "${minForgeVersion}".replaceAll("\\..*", "") - inputs.property "minForgeVersion", "${minForgeVersion}" - inputs.property "minMinecraftVersion", "${minMinecraftVersion}" - inputs.property "nextMinecraftVersion", rootProject.getNextVersion("${minMinecraftVersion}") - inputs.property "minPuzzlesVersion", "${minPuzzlesVersion}" - inputs.property "packFormat", "${packFormat}" - inputs.property "modForgeDisplayTest", "${modForgeDisplayTest}" + inputs.property "modId", "${modId}" + inputs.property "modName", "${modName}" + inputs.property "modVersion", "${modVersion}" + inputs.property "modDescription", "${modDescription}" + inputs.property "modGroup", project.group + inputs.property "modPageUrl", "${modSourceUrl}" + inputs.property "modUpdateUrl", "${modUpdateUrl}" + inputs.property "modIssueUrl", "${modIssueUrl}" + inputs.property "modAuthor", "${modAuthor}" + inputs.property "minFMLVersion", "${minForgeVersion}".replaceAll("\\..*", "") + inputs.property "minForgeVersion", "${minForgeVersion}" + inputs.property "minecraftVersion", "${minecraftVersion}" + inputs.property "minPuzzlesVersion", "${minPuzzlesVersion}" + inputs.property "resourcePackFormat", "${resourcePackFormat}" + inputs.property "dataPackFormat", "${dataPackFormat}" + inputs.property "modForgeDisplayTest", "${modForgeDisplayTest}" - // replace stuff in mods.toml and pack.mcmeta + // replace stuff in mods.toml filesMatching ('META-INF/mods.toml') { expand ( 'modId': "${modId}", @@ -174,17 +176,18 @@ processResources { 'modAuthor': "${modAuthor}", 'minFMLVersion': "${minForgeVersion}".replaceAll("\\..*", ""), 'minForgeVersion': "${minForgeVersion}", - 'minMinecraftVersion': "${minMinecraftVersion}", - 'nextMinecraftVersion': rootProject.getNextVersion("${minMinecraftVersion}"), + 'minecraftVersion': "${minecraftVersion}", 'minPuzzlesVersion': "${minPuzzlesVersion}", 'modForgeDisplayTest': "${modForgeDisplayTest}" ) } + // replace stuff in pack.mcmeta filesMatching ('pack.mcmeta') { expand ( 'modDescription': "${modDescription}", - "packFormat": "${packFormat}" + "resourcePackFormat": "${resourcePackFormat}", + "dataPackFormat": "${dataPackFormat}" ) } } @@ -201,6 +204,8 @@ javadoc { source project(":Common").sourceSets.main.allJava } +// important: the task may not run before 'compileJava', otherwise overridden/shadowed fields and methods in mixin classes will not be reobfuscated +jar.finalizedBy("configureReobfTaskForReobfJar") jar.finalizedBy('reobfJar') publishing { @@ -242,9 +247,8 @@ publishing { // from https://stackoverflow.com/a/50121790 pom.withXml { asNode().dependencies.dependency.each { dep -> - // Forge is weird as a dependency, so skip it along with quality of life mods // use this approach to make excluding dependencies from Curse Maven more convenient - if (["curse.maven:catalogue", "curse.maven:configured", "curse.maven:configmenusforge", "fuzs.bettermodsbutton:bettermodsbutton-forge"].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { + if (["curse.maven:", "fuzs.bettermodsbutton:bettermodsbutton-forge"].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { assert dep.parent().remove(dep) } } @@ -294,7 +298,7 @@ curseforge { requiredDependency 'puzzles-lib' } } - addArtifact sourcesJar +// addArtifact sourcesJar } options { // debug = true @@ -316,7 +320,7 @@ modrinth { gameVersions.add it.trim() } loaders.add 'forge' - additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") +// additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") dependencies { required.project 'puzzles-lib' } diff --git a/Forge/src/generated/resources/.cache/bd6432cce18694f9890e2363106a178883f44a06 b/Forge/src/generated/resources/.cache/bd6432cce18694f9890e2363106a178883f44a06 new file mode 100644 index 0000000..fb5b310 --- /dev/null +++ b/Forge/src/generated/resources/.cache/bd6432cce18694f9890e2363106a178883f44a06 @@ -0,0 +1,2 @@ +// 1.19.3 2023-03-24T15:14:38.508122 atlases generator for tradingpost +84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json b/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json new file mode 100644 index 0000000..0cfb27c --- /dev/null +++ b/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json @@ -0,0 +1,8 @@ +{ + "sources": [ + { + "type": "minecraft:single", + "resource": "tradingpost:item/magnifying_glass" + } + ] +} \ No newline at end of file diff --git a/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java index 482d035..3092c8c 100644 --- a/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java +++ b/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java @@ -1,16 +1,33 @@ package fuzs.tradingpost; -import fuzs.puzzleslib.core.CoreServices; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.tradingpost.data.ModSpriteSourceProvider; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.data.event.GatherDataEvent; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; +import java.util.concurrent.CompletableFuture; + @Mod(TradingPost.MOD_ID) @Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public class TradingPostForge { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { - CoreServices.FACTORIES.modConstructor(TradingPost.MOD_ID).accept(new TradingPost()); + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + final DataGenerator dataGenerator = evt.getGenerator(); + final PackOutput packOutput = dataGenerator.getPackOutput(); + final CompletableFuture lookupProvider = evt.getLookupProvider(); + final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); + dataGenerator.addProvider(true, new ModSpriteSourceProvider(packOutput, TradingPost.MOD_ID, fileHelper)); } } diff --git a/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java b/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java index 2d64f5d..41d3cbf 100644 --- a/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java +++ b/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java @@ -1,6 +1,6 @@ package fuzs.tradingpost.client; -import fuzs.puzzleslib.client.core.ClientCoreServices; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.tradingpost.TradingPost; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.eventbus.api.SubscribeEvent; @@ -12,6 +12,6 @@ public class TradingPostForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { - ClientCoreServices.FACTORIES.clientModConstructor(TradingPost.MOD_ID).accept(new TradingPostClient()); + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); } } diff --git a/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java new file mode 100644 index 0000000..1c37134 --- /dev/null +++ b/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java @@ -0,0 +1,22 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v1.AbstractSpriteSourceProvider; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import net.minecraft.client.renderer.texture.atlas.sources.SingleFile; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.common.data.SpriteSourceProvider; + +import java.util.Optional; + +public class ModSpriteSourceProvider extends AbstractSpriteSourceProvider { + + public ModSpriteSourceProvider(PackOutput packOutput, String modId, ExistingFileHelper fileHelper) { + super(packOutput, modId, fileHelper); + } + + @Override + protected void addSources() { + this.atlas(SpriteSourceProvider.BLOCKS_ATLAS).addSource(new SingleFile(TradingPostScreen.MAGNIFYING_GLASS_LOCATION, Optional.empty())); + } +} diff --git a/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..7528a9e --- /dev/null +++ b/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.tradingpost.mixin; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml index 5e945cb..925e0f6 100644 --- a/Forge/src/main/resources/META-INF/mods.toml +++ b/Forge/src/main/resources/META-INF/mods.toml @@ -1,6 +1,6 @@ modLoader="javafml" loaderVersion="[${minFMLVersion},)" -license="MPL-2" +license="MPL-2.0" issueTrackerURL="${modIssueUrl}" [[mods]] @@ -25,7 +25,7 @@ issueTrackerURL="${modIssueUrl}" [[dependencies.${modId}]] modId="minecraft" mandatory=true - versionRange="[${minMinecraftVersion},${nextMinecraftVersion})" + versionRange="[${minecraftVersion}]" ordering="NONE" side="BOTH" @@ -38,4 +38,3 @@ issueTrackerURL="${modIssueUrl}" [modproperties.${modId}] catalogueImageIcon="mod_logo.png" - configuredBackground="minecraft:textures/block/coarse_dirt.png" diff --git a/LICENSE-ASSETS.md b/LICENSE-ASSETS.md new file mode 100644 index 0000000..79fd8f1 --- /dev/null +++ b/LICENSE-ASSETS.md @@ -0,0 +1 @@ +Copyright (c) 2023 @heyitsfuzs. All Rights Reserved. \ No newline at end of file diff --git a/LICENSE b/LICENSE.md similarity index 100% rename from LICENSE rename to LICENSE.md diff --git a/README.md b/README.md index 8b83cd2..8310988 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Trading Post +# Example Mod A Minecraft mod. Downloads can be found on [CurseForge](https://www.curseforge.com/members/fuzs_/projects) and [Modrinth](https://modrinth.com/user/Fuzs). -![](https://i.imgur.com/UzgNFIB.png) +![](https://raw.githubusercontent.com/Fuzss/modresources/main/pages/data/examplemod/banner.png) diff --git a/build.gradle b/build.gradle index f8ef596..83a423b 100644 --- a/build.gradle +++ b/build.gradle @@ -43,6 +43,14 @@ subprojects { name = "Fuzs Mod Resources" url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" } + maven { + name = "Progwml6 maven" + url = "https://dvs1.progwml6.com/files/maven/" + } + maven { + name = "ModMaven" + url = "https://modmaven.dev" + } flatDir { dirs 'libs' } @@ -58,7 +66,8 @@ subprojects { } tasks.withType(Jar).configureEach { - from rootProject.file("LICENSE") + from rootProject.file("LICENSE.md") + from rootProject.file("LICENSE-ASSETS.md") from rootProject.file("CHANGELOG.md") manifest { attributes([ @@ -86,7 +95,6 @@ subprojects { } } -import groovy.json.* import java.util.regex.Pattern println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) @@ -105,10 +113,3 @@ task incrementBuildNumber { propertiesFile.write(propertiesContent) } } - -def static getNextVersion(String puzzlesVersion) { - def puzzlesVersionMatcher = Pattern.compile("(\\d+\\.\\d+)").matcher(puzzlesVersion) - puzzlesVersionMatcher.find() - def currentVersion = puzzlesVersionMatcher.group(1) - return currentVersion.substring(0, currentVersion.indexOf(".") + 1).concat(String.valueOf(Integer.parseInt(currentVersion.substring(currentVersion.indexOf(".") + 1, currentVersion.size())) + 1)) -} diff --git a/gradle.properties b/gradle.properties index 37db4d1..d4fa42a 100755 --- a/gradle.properties +++ b/gradle.properties @@ -5,28 +5,29 @@ org.gradle.daemon=false org.gradle.parallel=true # Common Project -minecraftVersion=1.19.2 -minMinecraftVersion=1.19.1 -parchmentMappingsVersion=2022.08.14 -puzzlesVersion=4.2.1 -minPuzzlesVersion=4.2.1 -packFormat=9 +minecraftVersion=1.19.3 +parchmentMinecraftVersion=1.19.3 +parchmentMappingsVersion=2023.03.12 +puzzlesVersion=5.0.10 +minPuzzlesVersion=5.0.10 +resourcePackFormat=12 +dataPackFormat=10 copyBuildJar=true # Forge Project -forgeVersion=1.19.2-43.1.1 -minForgeVersion=42.0.0 +forgeVersion=1.19.3-44.1.23 +minForgeVersion=44.1.0 # Fabric Project -fabricVersion=0.14.9 -minFabricVersion=0.14 -fabricApiVersion=0.60.0+1.19.2 -minFabricApiVersion=0.60.0 +fabricVersion=0.14.17 +minFabricVersion=0.14.0 +fabricApiVersion=0.76.0+1.19.3 +minFabricApiVersion=0.72.0 # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=4.2.0 +modVersion=5.0.0 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modSourceUrl=https://github.com/Fuzss/tradingpost @@ -40,6 +41,6 @@ modFabricEnvironment=* # Mod Publishing projectReleaseType=release -projectGameVersions=1.19.1, 1.19.2 +projectGameVersions=1.19.3 projectCurseId=539057 projectModrinthId=8pcjMDgj diff --git a/gradle/tasks.gradle b/gradle/tasks.gradle index dbd3dc0..766f674 100644 --- a/gradle/tasks.gradle +++ b/gradle/tasks.gradle @@ -1,3 +1,10 @@ +task commonClean(type: GradleBuild) { + group = '_main' + tasks = [ + ':Common:clean' + ] +} + task forgeClean(type: GradleBuild) { group = '_main' tasks = [ @@ -206,7 +213,7 @@ task fabricGenSources(type: GradleBuild) { task forgeClient(type: GradleBuild) { group = '_main' tasks = [ - ':Forge:runClient' + ':Forge:Client' ] } @@ -220,7 +227,7 @@ task fabricClient(type: GradleBuild) { task forgeServer(type: GradleBuild) { group = '_main' tasks = [ - ':Forge:runServer' + ':Forge:Server' ] } @@ -230,3 +237,10 @@ task fabricServer(type: GradleBuild) { ':Fabric:runServer' ] } + +task forgeData(type: GradleBuild) { + group = '_main' + tasks = [ + ':Forge:Data' + ] +} diff --git a/run/config/modmenu.json b/run/config/modmenu.json deleted file mode 100644 index c9e0984..0000000 --- a/run/config/modmenu.json +++ /dev/null @@ -1,19 +0,0 @@ -{ - "sorting": "ascending", - "count_libraries": true, - "compact_list": false, - "count_children": true, - "mods_button_style": "classic", - "count_hidden_mods": true, - "mod_count_location": "title_screen_and_mods_button", - "hide_mod_links": false, - "show_libraries": false, - "hide_mod_license": false, - "hide_badges": false, - "hide_mod_credits": false, - "easter_eggs": true, - "modify_title_screen": true, - "modify_game_menu": true, - "hide_config_buttons": false, - "hidden_mods": [] -} \ No newline at end of file diff --git a/run/options.txt b/run/options.txt deleted file mode 100644 index b9cbf63..0000000 --- a/run/options.txt +++ /dev/null @@ -1,130 +0,0 @@ -version:3105 -autoJump:false -autoSuggestions:true -chatColors:true -chatLinks:true -chatLinksPrompt:true -enableVsync:true -entityShadows:true -forceUnicodeFont:false -discrete_mouse_scroll:false -invertYMouse:false -realmsNotifications:true -reducedDebugInfo:false -showSubtitles:false -directionalAudio:false -touchscreen:false -fullscreen:false -bobView:true -toggleCrouch:false -toggleSprint:false -darkMojangStudiosBackground:false -hideLightningFlashes:false -mouseSensitivity:0.5 -fov:0.0 -screenEffectScale:1.0 -fovEffectScale:1.0 -darknessEffectScale:1.0 -gamma:0.5 -renderDistance:12 -simulationDistance:12 -entityDistanceScaling:1.0 -guiScale:0 -particles:0 -maxFps:120 -graphicsMode:1 -ao:2 -prioritizeChunkUpdates:0 -biomeBlendRadius:2 -renderClouds:"true" -resourcePacks:["Fabric Mods"] -incompatibleResourcePacks:[] -lastServer: -lang:en_us -soundDevice:"" -chatVisibility:0 -chatOpacity:1.0 -chatLineSpacing:0.0 -textBackgroundOpacity:0.5 -backgroundForChatOnly:true -hideServerAddress:false -advancedItemTooltips:false -pauseOnLostFocus:true -overrideWidth:0 -overrideHeight:0 -heldItemTooltips:true -chatHeightFocused:1.0 -chatDelay:0.0 -chatHeightUnfocused:0.4375 -chatScale:1.0 -chatWidth:1.0 -mipmapLevels:4 -useNativeTransport:true -mainHand:"right" -attackIndicator:1 -narrator:0 -tutorialStep:none -mouseWheelSensitivity:1.0 -rawMouseInput:true -glDebugVerbosity:1 -skipMultiplayerWarning:false -skipRealms32bitWarning:false -hideMatchedNames:true -joinedFirstServer:false -hideBundleTutorial:false -syncChunkWrites:false -showAutosaveIndicator:true -allowServerListing:true -chatPreview:true -onlyShowSecureChat:false -key_key.attack:key.mouse.left -key_key.use:key.mouse.right -key_key.forward:key.keyboard.w -key_key.left:key.keyboard.a -key_key.back:key.keyboard.s -key_key.right:key.keyboard.d -key_key.jump:key.keyboard.space -key_key.sneak:key.keyboard.left.shift -key_key.sprint:key.keyboard.left.control -key_key.drop:key.keyboard.q -key_key.inventory:key.keyboard.e -key_key.chat:key.keyboard.t -key_key.playerlist:key.keyboard.tab -key_key.pickItem:key.mouse.middle -key_key.command:key.keyboard.slash -key_key.socialInteractions:key.keyboard.p -key_key.screenshot:key.keyboard.f2 -key_key.togglePerspective:key.keyboard.f5 -key_key.smoothCamera:key.keyboard.unknown -key_key.fullscreen:key.keyboard.f11 -key_key.spectatorOutlines:key.keyboard.unknown -key_key.swapOffhand:key.keyboard.f -key_key.saveToolbarActivator:key.keyboard.c -key_key.loadToolbarActivator:key.keyboard.x -key_key.advancements:key.keyboard.l -key_key.hotbar.1:key.keyboard.1 -key_key.hotbar.2:key.keyboard.2 -key_key.hotbar.3:key.keyboard.3 -key_key.hotbar.4:key.keyboard.4 -key_key.hotbar.5:key.keyboard.5 -key_key.hotbar.6:key.keyboard.6 -key_key.hotbar.7:key.keyboard.7 -key_key.hotbar.8:key.keyboard.8 -key_key.hotbar.9:key.keyboard.9 -soundCategory_master:0.102649 -soundCategory_music:0.0 -soundCategory_record:1.0 -soundCategory_weather:0.056338027 -soundCategory_block:1.0 -soundCategory_hostile:1.0 -soundCategory_neutral:1.0 -soundCategory_player:1.0 -soundCategory_ambient:1.0 -soundCategory_voice:1.0 -modelPart_cape:true -modelPart_jacket:true -modelPart_left_sleeve:true -modelPart_right_sleeve:true -modelPart_left_pants_leg:true -modelPart_right_pants_leg:true -modelPart_hat:true From e3f0757260e357cfdbc9f8030ab0638fb39e8a4c Mon Sep 17 00:00:00 2001 From: Zano1999 <42555362+Zano1999@users.noreply.github.com> Date: Mon, 10 Apr 2023 21:02:23 +0200 Subject: [PATCH 03/24] Create it_it.json --- .../src/main/resources/assets/tradingpost/lang/it_it.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 Common/src/main/resources/assets/tradingpost/lang/it_it.json diff --git a/Common/src/main/resources/assets/tradingpost/lang/it_it.json b/Common/src/main/resources/assets/tradingpost/lang/it_it.json new file mode 100644 index 0000000..84afc50 --- /dev/null +++ b/Common/src/main/resources/assets/tradingpost/lang/it_it.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Postazione commerciale", + "container.trading_post": "Postazione commerciale", + "trading_post.no_trader_found": "Nessun commerciante disponibile trovato nelle vicinanze", + "trading_post.trader_gone": "Il commerciante non è più disponibile.", + "trading_post.search": "Ricerca..." +} From d4709251fe7a89c525267e9310d8e799c7cca100 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Mon, 29 May 2023 09:12:42 +0200 Subject: [PATCH 04/24] 1.19.4 port --- CHANGELOG.md | 4 +- Common/build.gradle | 4 +- .../tradingpost/client/TradingPostClient.java | 2 +- .../screens/inventory/TradingPostScreen.java | 71 ++++++++++--------- .../blockentity/TradingPostRenderer.java | 19 ++--- .../fuzs/tradingpost/init/ModRegistry.java | 3 +- Fabric/build.gradle | 8 +-- Forge/build.gradle | 10 +-- ... 178bb4356f8bea3c4b8966704e26df58ba8fa865} | 2 +- .../fuzs/tradingpost/TradingPostForge.java | 2 +- .../data/ModSpriteSourceProvider.java | 4 +- README.md | 4 +- gradle.properties | 25 ++++--- 13 files changed, 81 insertions(+), 77 deletions(-) rename Forge/src/generated/resources/.cache/{bd6432cce18694f9890e2363106a178883f44a06 => 178bb4356f8bea3c4b8966704e26df58ba8fa865} (52%) diff --git a/CHANGELOG.md b/CHANGELOG.md index 70f97b8..5d4d0e2 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. -## [v5.0.0-1.19.3] - 2023-03-24 -- Ported to Minecraft 1.19.3 +## [v6.0.0-1.19.4] - 2023-05-28 +- Ported to Minecraft 1.19.4 [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/Common/build.gradle b/Common/build.gradle index 2b33892..6dabd07 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -1,6 +1,6 @@ plugins { id 'fabric-loom' version '1.0.+' - id 'io.github.juuxel.loom-quiltflower' version '1.7.1' + id 'io.github.juuxel.loom-quiltflower' version '1.+' } archivesBaseName = rootProject.name @@ -12,7 +12,7 @@ dependencies { minecraft "com.mojang:minecraft:${minecraftVersion}" mappings loom.layered() { officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") +// parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") } // Puzzles Lib diff --git a/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java index 2fd34d2..29883e8 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java +++ b/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -48,7 +48,7 @@ public void onRegisterSearchTrees(SearchRegistryContext context) { @Override public void onBuildCreativeModeTabContents(BuildCreativeModeTabContentsContext context) { - context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (featureFlagSet, output, bl) -> { + context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (itemDisplayParameters, output) -> { output.accept(ModRegistry.TRADING_POST_ITEM.get()); }); } diff --git a/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java index 3bafe21..77f1ac5 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java +++ b/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -1,5 +1,6 @@ package fuzs.tradingpost.client.gui.screens.inventory; +import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; import com.mojang.blaze3d.vertex.PoseStack; import fuzs.tradingpost.TradingPost; @@ -75,7 +76,7 @@ protected void init() { @Override public boolean mouseClicked(double mouseX, double mouseY, int button) { // left click clears text - if (this.isVisible() && button == 1) { + if (this.isVisible() && button == InputConstants.MOUSE_BUTTON_RIGHT) { this.setValue(""); TradingPostScreen.this.refreshSearchResults(); } @@ -128,7 +129,7 @@ protected void renderLabels(PoseStack matrixStack, int mouseX, int mouseY) { } @Override - public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialTime) { + public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTime) { MerchantOffers merchantoffers = this.getMenu().getOffers(); this.setButtonsActive(merchantoffers); @@ -137,7 +138,7 @@ public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialT final Slot hoveredSlot = this.hoveredSlot; // set offers to empty to prevent MerchantScreen::render code from running, also disabled buttons drawing tooltips by changing scrollOff, as well as tooltip for hovered slot by removing hovered slot this.lock(true, merchantoffers.size(), null); - super.render(matrixStack, mouseX, mouseY, partialTime); + super.render(poseStack, mouseX, mouseY, partialTime); // reset everything so we can do this ourselves this.lock(false, scrollOff, hoveredSlot); @@ -152,7 +153,7 @@ public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialT RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - blit(matrixStack, this.leftPos + 83 + 99, this.topPos + 35, this.getBlitOffset(), 311.0F, 0.0F, 28, 21, 512, 256); + blit(poseStack, this.leftPos + 83 + 99, this.topPos + 35, 0, 311.0F, 0.0F, 28, 21, 512, 256); } } @@ -162,61 +163,63 @@ public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialT int posY = height + 16 + 2; RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); - ((MerchantScreenAccessor) this).callRenderScroller(matrixStack, width, height, merchantoffers); + ((MerchantScreenAccessor) this).callRenderScroller(poseStack, width, height, merchantoffers); for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { MerchantOffer merchantoffer = merchantoffers.get(i); - ((MerchantScreenAccessor) this).callRenderButtonArrows(matrixStack, merchantoffer, width, posY + 1); + ((MerchantScreenAccessor) this).callRenderButtonArrows(poseStack, merchantoffer, width, posY + 1); if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { - GuiComponent.fill(matrixStack, posX, posY, posX + 88, posY + 20, 822018048); + GuiComponent.fill(poseStack, posX, posY, posX + 88, posY + 20, 822018048); } ItemStack itemstack = merchantoffer.getBaseCostA(); ItemStack itemstack1 = merchantoffer.getCostA(); ItemStack itemstack2 = merchantoffer.getCostB(); ItemStack itemstack3 = merchantoffer.getResult(); - this.itemRenderer.blitOffset = 100.0F; - this.itemRenderer.renderAndDecorateFakeItem(itemstack1, posX + 5, posY + 1); + poseStack.pushPose(); + poseStack.translate(0.0F, 0.0F, 100.0F); + this.itemRenderer.renderAndDecorateFakeItem(poseStack, itemstack1, posX + 5, posY + 1); if (!itemstack2.isEmpty()) { - this.itemRenderer.renderAndDecorateFakeItem(itemstack2, posX + 35, posY + 1); + this.itemRenderer.renderAndDecorateFakeItem(poseStack, itemstack2, posX + 35, posY + 1); } - this.itemRenderer.renderAndDecorateFakeItem(itemstack3, posX + 68, posY + 1); + this.itemRenderer.renderAndDecorateFakeItem(poseStack, itemstack3, posX + 68, posY + 1); if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { RenderSystem.depthFunc(516); - GuiComponent.fill(matrixStack, posX, posY, posX + 88, posY + 20, 822083583); + GuiComponent.fill(poseStack, posX, posY, posX + 88, posY + 20, 822083583); RenderSystem.depthFunc(515); } if (itemstack.getCount() == itemstack1.getCount()) { - this.itemRenderer.renderGuiItemDecorations(this.font, itemstack1, posX + 5, posY + 1); + this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack1, posX + 5, posY + 1); } else { - this.itemRenderer.renderGuiItemDecorations(this.font, itemstack, posX + 5, posY + 1, itemstack.getCount() == 1 ? "1" : null); - this.itemRenderer.renderGuiItemDecorations(this.font, itemstack1, posX + 5 + 14, posY + 1, itemstack1.getCount() == 1 ? "1" : null); + this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack, posX + 5, posY + 1, itemstack.getCount() == 1 ? "1" : null); + this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack1, posX + 5 + 14, posY + 1, itemstack1.getCount() == 1 ? "1" : null); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); - this.setBlitOffset(this.getBlitOffset() + 300); - blit(matrixStack, posX + 5 + 7, posY + 1 + 12, this.getBlitOffset(), 0.0F, 176.0F, 9, 2, 512, 256); - this.setBlitOffset(this.getBlitOffset() - 300); + poseStack.pushPose(); + poseStack.translate(0.0F, 0.0F, 300.0F); + blit(poseStack, posX + 5 + 7, posY + 1 + 12, 0, 0.0F, 176.0F, 9, 2, 512, 256); + poseStack.popPose(); } if (!itemstack2.isEmpty()) { - this.itemRenderer.renderGuiItemDecorations(this.font, itemstack2, posX + 35, posY + 1); + this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack2, posX + 35, posY + 1); } - this.itemRenderer.renderGuiItemDecorations(this.font, itemstack3, posX + 68, posY + 1); - this.itemRenderer.blitOffset = 0.0F; + this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack3, posX + 68, posY + 1); + poseStack.popPose(); posY += 20; } } @@ -224,12 +227,12 @@ public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialT final MerchantOffer activeOffer = merchantoffers.get(shopItem); if (this.getMenu().showProgressBar()) { - ((MerchantScreenAccessor) this).callRenderProgressBar(matrixStack, width, height, activeOffer); + ((MerchantScreenAccessor) this).callRenderProgressBar(poseStack, width, height, activeOffer); } if (activeOffer.isOutOfStock() && this.isHovering(186, 35, 22, 21, mouseX, mouseY) && this.getMenu().canRestock()) { - this.renderTooltip(matrixStack, DEPRECATED_TOOLTIP, mouseX, mouseY); + this.renderTooltip(poseStack, DEPRECATED_TOOLTIP, mouseX, mouseY); } posY = height + 16 + 2; @@ -242,7 +245,7 @@ public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialT if (this.isHovering(posX, posY, 88, 19, mouseX + this.leftPos, mouseY + this.topPos)) { - this.renderTooltip(matrixStack, MERCHANT_GONE, mouseX, mouseY); + this.renderTooltip(poseStack, MERCHANT_GONE, mouseX, mouseY); } } @@ -259,13 +262,13 @@ public void render(PoseStack matrixStack, int mouseX, int mouseY, float partialT Button button = offerButtons[i]; if (button.active && button.isHoveredOrFocused()) { - ((TradeOfferButtonAccessor) button).tradingpost$callRenderToolTip(matrixStack, mouseX, mouseY); + ((TradeOfferButtonAccessor) button).tradingpost$callRenderToolTip(poseStack, mouseX, mouseY); } button.visible = i < this.getMenu().getOffers().size(); } - this.renderTooltip(matrixStack, mouseX, mouseY); + this.renderTooltip(poseStack, mouseX, mouseY); } private void setButtonsActive(MerchantOffers merchantoffers) { @@ -298,7 +301,7 @@ protected void renderBg(PoseStack matrixStack, float partialTicks, int mouseX, i TextureAtlasSprite textureatlassprite = this.minecraft.getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(MAGNIFYING_GLASS_LOCATION); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, textureatlassprite.atlasLocation()); - blit(matrixStack, this.leftPos, this.topPos + 4, this.getBlitOffset(), 16, 16, textureatlassprite); + blit(matrixStack, this.leftPos, this.topPos + 4, 0, 16, 16, textureatlassprite); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); } @@ -308,7 +311,7 @@ private void renderSearchBox(PoseStack matrixStack, float partialTicks, int mous RenderSystem.setShaderTexture(0, CREATIVE_INVENTORY_LOCATION); int i = (this.width - this.imageWidth) / 2; int j = (this.height - this.imageHeight) / 2; - blit(matrixStack, i + 11, j + 4, this.getBlitOffset(), 80.0F, 4.0F, 90, 12, 256, 256); + blit(matrixStack, i + 11, j + 4, 0, 80.0F, 4.0F, 90, 12, 256, 256); this.searchBox.render(matrixStack, mouseX, mouseY, partialTicks); } @@ -328,10 +331,10 @@ protected void containerTick() { @Override public boolean keyPressed(int keyCode, int scanCode, int modifierKeys) { this.ignoreTextInput = false; - final String lastSearch = this.searchBox.getValue(); + final String lastSearch = this.searchBox.getValue().trim(); if (this.searchBox.keyPressed(keyCode, scanCode, modifierKeys)) { - if (!Objects.equals(this.searchBox.getValue(), lastSearch)) { + if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { this.refreshSearchResults(); } @@ -341,7 +344,7 @@ public boolean keyPressed(int keyCode, int scanCode, int modifierKeys) { return true; } else if (this.minecraft.options.keyChat.matches(keyCode, scanCode) && !this.searchBox.isFocused()) { this.ignoreTextInput = true; - this.searchBox.setFocus(true); + this.searchBox.setFocused(true); return true; } return super.keyPressed(keyCode, scanCode, modifierKeys); @@ -350,10 +353,10 @@ public boolean keyPressed(int keyCode, int scanCode, int modifierKeys) { @Override public boolean charTyped(char typedChar, int modifierKeys) { - final String lastSearch = this.searchBox.getValue(); + final String lastSearch = this.searchBox.getValue().trim(); if (!this.ignoreTextInput && this.searchBox.charTyped(typedChar, modifierKeys)) { - if (!Objects.equals(this.searchBox.getValue(), lastSearch)) { + if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { this.refreshSearchResults(); } @@ -369,7 +372,7 @@ public void refreshSearchResults() { if (!(this.getMenu().getOffers() instanceof TradingPostOffers offers)) { return; } - String query = this.searchBox.getValue(); + String query = this.searchBox.getValue().trim(); if (query.isEmpty()) { offers.clearFilter(); } else { diff --git a/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java index 2c9af19..5aa684e 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java +++ b/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java @@ -5,13 +5,14 @@ import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; -import net.minecraft.client.renderer.block.model.ItemTransforms; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; import net.minecraft.client.renderer.entity.ItemRenderer; import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemDisplayContext; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; /** * Mostly copied from Quark's MatrixEnchantingTableRenderer.java by Vazkii, thanks! @@ -23,21 +24,21 @@ public TradingPostRenderer(BlockEntityRendererProvider.Context context) { } @Override - public void render(TradingPostBlockEntity tileEntityIn, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { - float ageInTicks = tileEntityIn.time + partialTicks; - float nextRotation = tileEntityIn.rot - tileEntityIn.oRot; + public void render(TradingPostBlockEntity blockEntity, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { + float ageInTicks = blockEntity.time + partialTicks; + float nextRotation = blockEntity.rot - blockEntity.oRot; while (nextRotation >= Math.PI) { nextRotation -= (Math.PI * 2F); } while (nextRotation < -Math.PI) { nextRotation += (Math.PI * 2F); } - float bookRotation = tileEntityIn.oRot + nextRotation * partialTicks; - float bookOpen = Mth.lerp(partialTicks, tileEntityIn.oOpen, tileEntityIn.open); - this.renderItem(new ItemStack(Items.EMERALD), ageInTicks, bookOpen, bookRotation, matrixStackIn, bufferIn, combinedLightIn, combinedOverlayIn); + float bookRotation = blockEntity.oRot + nextRotation * partialTicks; + float bookOpen = Mth.lerp(partialTicks, blockEntity.oOpen, blockEntity.open); + this.renderItem(new ItemStack(Items.EMERALD), ageInTicks, bookOpen, bookRotation, matrixStackIn, bufferIn, combinedLightIn, combinedOverlayIn, blockEntity.getLevel()); } - private void renderItem(ItemStack stack, float ageInTicks, float bookOpen, float bookRotation, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { + private void renderItem(ItemStack stack, float ageInTicks, float bookOpen, float bookRotation, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, Level level) { matrixStackIn.pushPose(); matrixStackIn.translate(0.5F, 1.03125F, 0.5F); matrixStackIn.scale(0.8F, 0.8F, 0.8F); @@ -50,7 +51,7 @@ private void renderItem(ItemStack stack, float ageInTicks, float bookOpen, float float hoveringHeight = (float) Math.sin(ageInTicks * 0.06F) * bookOpen * 0.2F; matrixStackIn.translate(0.0F, hoveringHeight, 0.0F); ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); - itemRenderer.renderStatic(stack, ItemTransforms.TransformType.FIXED, combinedLightIn, combinedOverlayIn, matrixStackIn, bufferIn, 0); + itemRenderer.renderStatic(stack, ItemDisplayContext.FIXED, combinedLightIn, combinedOverlayIn, matrixStackIn, bufferIn, level, 0); matrixStackIn.popPose(); } diff --git a/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java index c9bf687..d58a0e0 100644 --- a/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java +++ b/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java @@ -22,7 +22,8 @@ public class ModRegistry { public static final RegistryReference TRADING_POST_ITEM = REGISTRY.registerBlockItem(TRADING_POST_BLOCK); public static final RegistryReference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType("trading_post", () -> BlockEntityType.Builder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.get())); public static final RegistryReference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); - public static final TagKey> BLACKLISTED_TRADERS_TAG = REGISTRY.createEntityTypeTag("blacklisted_traders"); + + public static final TagKey> BLACKLISTED_TRADERS_TAG = REGISTRY.registerEntityTypeTag("blacklisted_traders"); public static void touch() { diff --git a/Fabric/build.gradle b/Fabric/build.gradle index 57cbe18..87e6c61 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -1,6 +1,6 @@ plugins { id 'fabric-loom' version '1.0.+' - id 'io.github.juuxel.loom-quiltflower' version '1.7.1' + id 'io.github.juuxel.loom-quiltflower' version '1.+' // this depends on an older version of guava, which loom is incompatible with, so make sure to apply this plugin after loom // haven't found a proper way to manage plugin dependencies otherwise id 'me.hypherionmc.cursegradle' version '2.+' @@ -41,7 +41,7 @@ dependencies { minecraft "com.mojang:minecraft:${minecraftVersion}" mappings loom.layered() { officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${parchmentMinecraftVersion}:${parchmentMappingsVersion}@zip") +// parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") } // Fabric @@ -49,8 +49,8 @@ dependencies { modApi "net.fabricmc.fabric-api:fabric-api:${fabricApiVersion}" // Quality of Life Mods - modLocalRuntime "com.terraformersmc:modmenu:5.0.2" - modLocalRuntime "curse.maven:configured-fabric-667378:4441611" + modLocalRuntime "com.terraformersmc:modmenu:6.2.2" +// modLocalRuntime "curse.maven:configured-fabric-667378:4441611" // Puzzles Lib modApi "fuzs.puzzleslib:puzzleslib-fabric:${puzzlesVersion}" diff --git a/Forge/build.gradle b/Forge/build.gradle index bc302cb..6781901 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -27,8 +27,8 @@ version = "v${modVersion}-${minecraftVersion}-Forge" group = modMavenGroup minecraft { - mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${parchmentMinecraftVersion}" -// mappings channel: 'official', version: "${minecraftVersion}" +// mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${minecraftVersion}" + mappings channel: 'official', version: "${minecraftVersion}" runs { client { @@ -116,9 +116,9 @@ dependencies { annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' // Quality of Life Mods - runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:5.0.0") - runtimeOnly fg.deobf("curse.maven:catalogue-459701:4171025") - runtimeOnly fg.deobf("curse.maven:configured-457570:4441589") + runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:6.0.0") + runtimeOnly fg.deobf("curse.maven:catalogue-459701:4496718") + runtimeOnly fg.deobf("curse.maven:configured-457570:4462894") // Puzzles Lib api fg.deobf("fuzs.puzzleslib:puzzleslib-forge:${puzzlesVersion}") diff --git a/Forge/src/generated/resources/.cache/bd6432cce18694f9890e2363106a178883f44a06 b/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 similarity index 52% rename from Forge/src/generated/resources/.cache/bd6432cce18694f9890e2363106a178883f44a06 rename to Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 index fb5b310..b4c5001 100644 --- a/Forge/src/generated/resources/.cache/bd6432cce18694f9890e2363106a178883f44a06 +++ b/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 @@ -1,2 +1,2 @@ -// 1.19.3 2023-03-24T15:14:38.508122 atlases generator for tradingpost +// 1.19.4 2023-05-29T09:07:32.722967 Sprite Sources 84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java index 3092c8c..46a80b4 100644 --- a/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java +++ b/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java @@ -28,6 +28,6 @@ public static void onGatherData(final GatherDataEvent evt) { final PackOutput packOutput = dataGenerator.getPackOutput(); final CompletableFuture lookupProvider = evt.getLookupProvider(); final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); - dataGenerator.addProvider(true, new ModSpriteSourceProvider(packOutput, TradingPost.MOD_ID, fileHelper)); + dataGenerator.addProvider(true, new ModSpriteSourceProvider(packOutput, fileHelper)); } } diff --git a/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java index 1c37134..7ddde99 100644 --- a/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java +++ b/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java @@ -11,8 +11,8 @@ public class ModSpriteSourceProvider extends AbstractSpriteSourceProvider { - public ModSpriteSourceProvider(PackOutput packOutput, String modId, ExistingFileHelper fileHelper) { - super(packOutput, modId, fileHelper); + public ModSpriteSourceProvider(PackOutput packOutput, ExistingFileHelper fileHelper) { + super(packOutput, fileHelper); } @Override diff --git a/README.md b/README.md index 8310988..0998b84 100644 --- a/README.md +++ b/README.md @@ -1,5 +1,5 @@ -# Example Mod +# Trading Post A Minecraft mod. Downloads can be found on [CurseForge](https://www.curseforge.com/members/fuzs_/projects) and [Modrinth](https://modrinth.com/user/Fuzs). -![](https://raw.githubusercontent.com/Fuzss/modresources/main/pages/data/examplemod/banner.png) +![](https://raw.githubusercontent.com/Fuzss/modresources/main/pages/data/tradingpost/banner.png) diff --git a/gradle.properties b/gradle.properties index d4fa42a..6dcd6e1 100755 --- a/gradle.properties +++ b/gradle.properties @@ -5,29 +5,28 @@ org.gradle.daemon=false org.gradle.parallel=true # Common Project -minecraftVersion=1.19.3 -parchmentMinecraftVersion=1.19.3 +minecraftVersion=1.19.4 parchmentMappingsVersion=2023.03.12 -puzzlesVersion=5.0.10 -minPuzzlesVersion=5.0.10 -resourcePackFormat=12 -dataPackFormat=10 +puzzlesVersion=6.0.8 +minPuzzlesVersion=6.0.8 +resourcePackFormat=13 +dataPackFormat=12 copyBuildJar=true # Forge Project -forgeVersion=1.19.3-44.1.23 -minForgeVersion=44.1.0 +forgeVersion=1.19.4-45.0.64 +minForgeVersion=45.0 # Fabric Project -fabricVersion=0.14.17 +fabricVersion=0.14.19 minFabricVersion=0.14.0 -fabricApiVersion=0.76.0+1.19.3 -minFabricApiVersion=0.72.0 +fabricApiVersion=0.81.1+1.19.4 +minFabricApiVersion=0.76.0 # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=5.0.0 +modVersion=6.0.0 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modSourceUrl=https://github.com/Fuzss/tradingpost @@ -41,6 +40,6 @@ modFabricEnvironment=* # Mod Publishing projectReleaseType=release -projectGameVersions=1.19.3 +projectGameVersions=1.19.4 projectCurseId=539057 projectModrinthId=8pcjMDgj From 2e02a2c017aeb6ec0c64c8efadaf78e762758ee9 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sun, 11 Jun 2023 16:08:18 +0200 Subject: [PATCH 05/24] 1.20 port --- .github/ISSUE_TEMPLATE/bug.yml | 2 +- .github/ISSUE_TEMPLATE/crash.yml | 2 +- .github/ISSUE_TEMPLATE/suggestion.yml | 2 +- CHANGELOG.md | 4 +- Common/build.gradle | 37 ++--- .../screens/inventory/TradingPostScreen.java | 147 ++++++++--------- .../fuzs/tradingpost/init/ModRegistry.java | 5 +- .../mixin/client/accessor/ButtonAccessor.java | 4 +- .../accessor/MerchantScreenAccessor.java | 30 ++-- .../accessor/TradeOfferButtonAccessor.java | 4 +- .../world/inventory/TradingPostMenu.java | 2 +- Fabric/build.gradle | 137 ++++++++-------- Fabric/src/main/resources/fabric.mod.json | 2 +- Forge/build.gradle | 155 +++++++++--------- .../178bb4356f8bea3c4b8966704e26df58ba8fa865 | 2 +- Forge/src/main/resources/META-INF/mods.toml | 2 +- build.gradle | 68 ++++++-- gradle.properties | 23 +-- gradle/libs.versions.toml | 25 +++ gradle/wrapper/gradle-wrapper.jar | Bin 59821 -> 61574 bytes gradle/wrapper/gradle-wrapper.properties | 3 +- gradlew | 18 +- gradlew.bat | 15 +- settings.gradle | 12 +- 24 files changed, 365 insertions(+), 336 deletions(-) create mode 100644 gradle/libs.versions.toml diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 629f0ed..1b22d43 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -1,6 +1,6 @@ name: Bug Report description: >- - Please use this template when you have encountered a bug in this mod. + Please use this template when you have encountered a bug in this mod. Supported versions are for Minecraft 1.18+. title: '[Bug]: ' labels: ["bug"] assignees: diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 690bc86..3df638c 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -1,6 +1,6 @@ name: Crash Report description: >- - Please use this template when this mod has caused your game to crash. + Please use this template when this mod has caused your game to crash. Supported versions are for Minecraft 1.18+. title: '[Crash]: ' labels: ["bug"] assignees: diff --git a/.github/ISSUE_TEMPLATE/suggestion.yml b/.github/ISSUE_TEMPLATE/suggestion.yml index b4d3720..aca1ce4 100644 --- a/.github/ISSUE_TEMPLATE/suggestion.yml +++ b/.github/ISSUE_TEMPLATE/suggestion.yml @@ -1,6 +1,6 @@ name: Suggestion description: >- - Please use this template when you want to suggest a feature. + Please use this template when you want to suggest a feature. Do not ask for mod updates or ports, they will come when they are ready. title: '[Suggestion]: ' labels: ["enhancement"] assignees: diff --git a/CHANGELOG.md b/CHANGELOG.md index 5d4d0e2..34d883b 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. -## [v6.0.0-1.19.4] - 2023-05-28 -- Ported to Minecraft 1.19.4 +## [v7.0.0-1.20] - 2023-06-11 +- Ported to Minecraft 1.20 [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/Common/build.gradle b/Common/build.gradle index 6dabd07..1b574a0 100644 --- a/Common/build.gradle +++ b/Common/build.gradle @@ -1,22 +1,19 @@ -plugins { - id 'fabric-loom' version '1.0.+' - id 'io.github.juuxel.loom-quiltflower' version '1.+' -} +apply plugin: 'fabric-loom' +apply plugin: 'io.github.juuxel.loom-quiltflower' archivesBaseName = rootProject.name -version = "v${modVersion}-${minecraftVersion}-Common" +version = "v${modVersion}-${libs.versions.minecraft.get()}-Common" group = modMavenGroup dependencies { - // Minecraft - minecraft "com.mojang:minecraft:${minecraftVersion}" + minecraft "com.mojang:minecraft:${libs.versions.minecraft.get()}" mappings loom.layered() { officialMojangMappings() -// parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") + parchment("org.parchmentmc.data:parchment-${libs.versions.parchmentMinecraft.get()}:${libs.versions.parchment.get()}@zip") } // Puzzles Lib - modApi "fuzs.puzzleslib:puzzleslib-common:${puzzlesVersion}" + modApi ("fuzs.puzzleslib:puzzleslib-common:${libs.versions.puzzles.get()}") } loom { @@ -48,23 +45,23 @@ processResources { duplicatesStrategy DuplicatesStrategy.INCLUDE // this will ensure that this task is redone when a value changes - inputs.property "modDescription", "${modDescription}" - inputs.property "resourcePackFormat", "${resourcePackFormat}" - inputs.property "dataPackFormat", "${dataPackFormat}" + inputs.property "modDescription", modDescription + inputs.property "resourcePackFormat", libs.versions.resources.get() + inputs.property "dataPackFormat", libs.versions.data.get() // replace stuff in pack.mcmeta - filesMatching ('pack.mcmeta') { - expand ( - 'modDescription': "${modDescription}", - "resourcePackFormat": "${resourcePackFormat}", - "dataPackFormat": "${dataPackFormat}" + filesMatching('pack.mcmeta') { + expand( + 'modDescription': modDescription, + "resourcePackFormat": libs.versions.resources.get(), + "dataPackFormat": libs.versions.data.get() ) } } publishing { publications { - mavenJava (MavenPublication) { + mavenJava(MavenPublication) { artifactId = "${modId}-common" version = modVersion from components.java @@ -83,8 +80,8 @@ publishing { } licenses { license { - name = 'MPL-2' - url = 'https://www.mozilla.org/en-US/MPL/2.0/' + name = "${modLicense}" + url = "https://spdx.org/licenses/${modLicense}.html" } } developers { diff --git a/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java index 77f1ac5..58d8d8a 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java +++ b/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -2,7 +2,6 @@ import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; -import com.mojang.blaze3d.vertex.PoseStack; import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.mixin.client.accessor.ButtonAccessor; import fuzs.tradingpost.mixin.client.accessor.MerchantScreenAccessor; @@ -11,7 +10,7 @@ import fuzs.tradingpost.world.inventory.TradingPostMenu; import fuzs.tradingpost.world.item.trading.TradingPostOffers; import net.minecraft.client.Minecraft; -import net.minecraft.client.gui.GuiComponent; +import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; import net.minecraft.client.gui.components.Renderable; @@ -58,12 +57,12 @@ protected void init() { this.tradeOfferButtons = this.getTradeOfferButtons(this.renderables); for (Button tradeOfferButton : this.tradeOfferButtons) { - ((ButtonAccessor) tradeOfferButton).setOnPress(button -> { + ((ButtonAccessor) tradeOfferButton).tradingpost$setOnPress(button -> { MerchantScreenAccessor accessor = (MerchantScreenAccessor) this; - final int shopItem = ((TradeOfferButtonAccessor) button).tradingpost$getIndex() + accessor.getScrollOff(); + final int shopItem = ((TradeOfferButtonAccessor) button).tradingpost$getIndex() + accessor.tradingpost$getScrollOff(); MerchantOffers offers = this.getMenu().getOffers(); - accessor.setShopItem(shopItem); + accessor.tradingpost$setShopItem(shopItem); this.getMenu().setSelectionHint(shopItem); this.getMenu().getTraders().setActiveOffer(offers.get(shopItem)); this.getMenu().tryMoveItems(shopItem); @@ -90,10 +89,7 @@ public boolean mouseClicked(double mouseX, double mouseY, int button) { } private Button[] getTradeOfferButtons(List buttons) { - Button[] tradeOfferButtons = buttons.stream() - .filter(button -> button instanceof TradeOfferButtonAccessor) - .map(button -> (Button) button) - .toArray(Button[]::new); + Button[] tradeOfferButtons = buttons.stream().filter(button -> button instanceof TradeOfferButtonAccessor).map(button -> (Button) button).toArray(Button[]::new); if (tradeOfferButtons.length != 7) { TradingPost.LOGGER.warn("Unable to find enough tradeOfferButtons"); } @@ -102,7 +98,6 @@ private Button[] getTradeOfferButtons(List buttons) { @Override public void resize(Minecraft mc, int newWidth, int newHeight) { - final String lastSearch = this.searchBox.getValue(); super.resize(mc, newWidth, newHeight); this.searchBox.setValue(lastSearch); @@ -113,8 +108,7 @@ public void resize(Minecraft mc, int newWidth, int newHeight) { } @Override - protected void renderLabels(PoseStack matrixStack, int mouseX, int mouseY) { - + protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) { Component title = this.getMenu().getTraders().getDisplayName(); if (title != null) { int traderLevel = this.menu.getTraderLevel(); @@ -124,36 +118,34 @@ protected void renderLabels(PoseStack matrixStack, int mouseX, int mouseY) { } else { title = this.title; } - this.font.draw(matrixStack, title, (float)(49 + this.imageWidth / 2 - this.font.width(title) / 2), 6.0F, 4210752); - this.font.draw(matrixStack, this.playerInventoryTitle, (float)this.inventoryLabelX, (float)this.inventoryLabelY, 4210752); + guiGraphics.drawString(this.font, title, (49 + this.imageWidth / 2 - this.font.width(title) / 2), 6, 0x404040, false); + guiGraphics.drawString(this.font, this.playerInventoryTitle, this.inventoryLabelX, this.inventoryLabelY, 0x404040, false); } @Override - public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTime) { + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTime) { MerchantOffers merchantoffers = this.getMenu().getOffers(); this.setButtonsActive(merchantoffers); - final int scrollOff = ((MerchantScreenAccessor) this).getScrollOff(); + final int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); final Slot hoveredSlot = this.hoveredSlot; // set offers to empty to prevent MerchantScreen::render code from running, also disabled buttons drawing tooltips by changing scrollOff, as well as tooltip for hovered slot by removing hovered slot this.lock(true, merchantoffers.size(), null); - super.render(poseStack, mouseX, mouseY, partialTime); + super.render(guiGraphics, mouseX, mouseY, partialTime); // reset everything so we can do this ourselves this.lock(false, scrollOff, hoveredSlot); if (!merchantoffers.isEmpty()) { // normally rendered as part of background, but skipped as offers are empty when it's called - final int shopItem = ((MerchantScreenAccessor) this).getShopItem(); + final int shopItem = ((MerchantScreenAccessor) this).tradingpost$getShopItem(); if (shopItem >= 0 && shopItem < merchantoffers.size()) { MerchantOffer merchantoffer = merchantoffers.get(shopItem); if (merchantoffer.isOutOfStock()) { - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - blit(poseStack, this.leftPos + 83 + 99, this.topPos + 35, 0, 311.0F, 0.0F, 28, 21, 512, 256); + guiGraphics.blit(VILLAGER_LOCATION, this.leftPos + 83 + 99, this.topPos + 35, 0, 311.0F, 0.0F, 28, 21, 512, 256); } } @@ -163,63 +155,44 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTim int posY = height + 16 + 2; RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); - ((MerchantScreenAccessor) this).callRenderScroller(poseStack, width, height, merchantoffers); + ((MerchantScreenAccessor) this).tradingpost$callRenderScroller(guiGraphics, width, height, merchantoffers); for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { MerchantOffer merchantoffer = merchantoffers.get(i); - ((MerchantScreenAccessor) this).callRenderButtonArrows(poseStack, merchantoffer, width, posY + 1); + // move this call here to render below red overlay + ((MerchantScreenAccessor) this).tradingpost$callRenderButtonArrows(guiGraphics, merchantoffer, width, posY + 1); if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { - GuiComponent.fill(poseStack, posX, posY, posX + 88, posY + 20, 822018048); - } - - ItemStack itemstack = merchantoffer.getBaseCostA(); - ItemStack itemstack1 = merchantoffer.getCostA(); - ItemStack itemstack2 = merchantoffer.getCostB(); - ItemStack itemstack3 = merchantoffer.getResult(); - poseStack.pushPose(); - poseStack.translate(0.0F, 0.0F, 100.0F); - this.itemRenderer.renderAndDecorateFakeItem(poseStack, itemstack1, posX + 5, posY + 1); - - if (!itemstack2.isEmpty()) { - - this.itemRenderer.renderAndDecorateFakeItem(poseStack, itemstack2, posX + 35, posY + 1); + guiGraphics.fill(posX, posY, posX + 88, posY + 20, 822018048); } - this.itemRenderer.renderAndDecorateFakeItem(poseStack, itemstack3, posX + 68, posY + 1); + ItemStack baseCostA = merchantoffer.getBaseCostA(); + ItemStack costA = merchantoffer.getCostA(); + ItemStack costB = merchantoffer.getCostB(); + ItemStack result = merchantoffer.getResult(); + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(0.0F, 0.0F, 100.0F); if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { RenderSystem.depthFunc(516); - GuiComponent.fill(poseStack, posX, posY, posX + 88, posY + 20, 822083583); + guiGraphics.fill(posX, posY, posX + 88, posY + 20, 822083583); RenderSystem.depthFunc(515); } - if (itemstack.getCount() == itemstack1.getCount()) { - - this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack1, posX + 5, posY + 1); - } else { - - this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack, posX + 5, posY + 1, itemstack.getCount() == 1 ? "1" : null); - this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack1, posX + 5 + 14, posY + 1, itemstack1.getCount() == 1 ? "1" : null); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); - poseStack.pushPose(); - poseStack.translate(0.0F, 0.0F, 300.0F); - blit(poseStack, posX + 5 + 7, posY + 1 + 12, 0, 0.0F, 176.0F, 9, 2, 512, 256); - poseStack.popPose(); - } - - if (!itemstack2.isEmpty()) { + this.renderAndDecorateCostA(guiGraphics, posX, posY, baseCostA, costA); - this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack2, posX + 35, posY + 1); + if (!costB.isEmpty()) { + guiGraphics.renderFakeItem(costB, posX + 35, posY + 1); + guiGraphics.renderItemDecorations(this.font, costB, posX + 35, posY + 1); } - this.itemRenderer.renderGuiItemDecorations(poseStack, this.font, itemstack3, posX + 68, posY + 1); - poseStack.popPose(); + guiGraphics.renderFakeItem(result, posX + 68, posY + 1); + guiGraphics.renderItemDecorations(this.font, result, posX + 68, posY + 1); + guiGraphics.pose().popPose(); posY += 20; } } @@ -227,12 +200,12 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTim final MerchantOffer activeOffer = merchantoffers.get(shopItem); if (this.getMenu().showProgressBar()) { - ((MerchantScreenAccessor) this).callRenderProgressBar(poseStack, width, height, activeOffer); + ((MerchantScreenAccessor) this).tradingpost$callRenderProgressBar(guiGraphics, width, height, activeOffer); } if (activeOffer.isOutOfStock() && this.isHovering(186, 35, 22, 21, mouseX, mouseY) && this.getMenu().canRestock()) { - - this.renderTooltip(poseStack, DEPRECATED_TOOLTIP, mouseX, mouseY); + + guiGraphics.renderTooltip(this.font, DEPRECATED_TOOLTIP, mouseX, mouseY); } posY = height + 16 + 2; @@ -245,7 +218,7 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTim if (this.isHovering(posX, posY, 88, 19, mouseX + this.leftPos, mouseY + this.topPos)) { - this.renderTooltip(poseStack, MERCHANT_GONE, mouseX, mouseY); + guiGraphics.renderTooltip(this.font, MERCHANT_GONE, mouseX, mouseY); } } @@ -262,13 +235,27 @@ public void render(PoseStack poseStack, int mouseX, int mouseY, float partialTim Button button = offerButtons[i]; if (button.active && button.isHoveredOrFocused()) { - ((TradeOfferButtonAccessor) button).tradingpost$callRenderToolTip(poseStack, mouseX, mouseY); + ((TradeOfferButtonAccessor) button).tradingpost$callRenderToolTip(guiGraphics, mouseX, mouseY); } button.visible = i < this.getMenu().getOffers().size(); } - this.renderTooltip(poseStack, mouseX, mouseY); + this.renderTooltip(guiGraphics, mouseX, mouseY); + } + + private void renderAndDecorateCostA(GuiGraphics guiGraphics, int posX, int posY, ItemStack baseCostA, ItemStack costA) { + guiGraphics.renderFakeItem(costA, posX + 5, posY + 1); + if (baseCostA.getCount() == costA.getCount()) { + guiGraphics.renderItemDecorations(this.font, costA, posX + 5, posY + 1); + } else { + guiGraphics.renderItemDecorations(this.font, baseCostA, posX + 5, posY + 1, baseCostA.getCount() == 1 ? "1" : null); + guiGraphics.renderItemDecorations(this.font, costA, posX + 5 + 14, posY + 1, costA.getCount() == 1 ? "1" : null); + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(0.0F, 0.0F, 300.0F); + guiGraphics.blit(VILLAGER_LOCATION, posX + 5 + 7, posY + 1 + 12, 0, 0.0F, 176.0F, 9, 2, 512, 256); + guiGraphics.pose().popPose(); + } } private void setButtonsActive(MerchantOffers merchantoffers) { @@ -277,7 +264,7 @@ private void setButtonsActive(MerchantOffers merchantoffers) { for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { - int scrollOff = ((MerchantScreenAccessor) this).getScrollOff(); + int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { MerchantOffer offer = merchantoffers.get(i); @@ -288,31 +275,27 @@ private void setButtonsActive(MerchantOffers merchantoffers) { } private void lock(boolean lockOffers, int newScrollOff, Slot newHoveredSlot) { - + this.getMenu().lockOffers(lockOffers); - ((MerchantScreenAccessor) this).setScrollOff(newScrollOff); + ((MerchantScreenAccessor) this).tradingpost$setScrollOff(newScrollOff); this.hoveredSlot = newHoveredSlot; } @Override - protected void renderBg(PoseStack matrixStack, float partialTicks, int mouseX, int mouseY) { - super.renderBg(matrixStack, partialTicks, mouseX, mouseY); - this.renderSearchBox(matrixStack, partialTicks, mouseX, mouseY); - TextureAtlasSprite textureatlassprite = this.minecraft.getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(MAGNIFYING_GLASS_LOCATION); - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, textureatlassprite.atlasLocation()); - blit(matrixStack, this.leftPos, this.topPos + 4, 0, 16, 16, textureatlassprite); + protected void renderBg(GuiGraphics guiGraphics, float partialTicks, int mouseX, int mouseY) { + super.renderBg(guiGraphics, partialTicks, mouseX, mouseY); + this.renderSearchBox(guiGraphics, partialTicks, mouseX, mouseY); + TextureAtlasSprite atlasSprite = this.minecraft.getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(MAGNIFYING_GLASS_LOCATION); + guiGraphics.blit(this.leftPos, this.topPos + 4, 0, 16, 16, atlasSprite); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); } - private void renderSearchBox(PoseStack matrixStack, float partialTicks, int mouseX, int mouseY) { - RenderSystem.setShader(GameRenderer::getPositionTexShader); - RenderSystem.setShaderTexture(0, CREATIVE_INVENTORY_LOCATION); + private void renderSearchBox(GuiGraphics guiGraphics, float partialTicks, int mouseX, int mouseY) { int i = (this.width - this.imageWidth) / 2; int j = (this.height - this.imageHeight) / 2; - blit(matrixStack, i + 11, j + 4, 0, 80.0F, 4.0F, 90, 12, 256, 256); - this.searchBox.render(matrixStack, mouseX, mouseY, partialTicks); + guiGraphics.blit(CREATIVE_INVENTORY_LOCATION, i + 11, j + 4, 0, 80.0F, 4.0F, 90, 12, 256, 256); + this.searchBox.render(guiGraphics, mouseX, mouseY, partialTicks); } @Override @@ -379,8 +362,8 @@ public void refreshSearchResults() { SearchTree isearchtree = this.minecraft.getSearchTree(OFFER_SEARCH_TREE); offers.setFilter(isearchtree.search(query.toLowerCase(Locale.ROOT))); } - ((MerchantScreenAccessor) this).setScrollOff(0); - ((MerchantScreenAccessor) this).setShopItem(0); + ((MerchantScreenAccessor) this).tradingpost$setScrollOff(0); + ((MerchantScreenAccessor) this).tradingpost$setShopItem(0); this.getMenu().setSelectionHint(-1); this.getMenu().getTraders().setActiveOffer(null); this.getMenu().clearPaymentSlots(); @@ -389,7 +372,7 @@ public void refreshSearchResults() { @Override public TradingPostMenu getMenu() { - + return (TradingPostMenu) super.getMenu(); } diff --git a/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java index d58a0e0..b01649b 100644 --- a/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java +++ b/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java @@ -14,11 +14,12 @@ import net.minecraft.world.level.block.SoundType; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockBehaviour; -import net.minecraft.world.level.material.Material; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraft.world.level.material.MapColor; public class ModRegistry { static final RegistryManager REGISTRY = RegistryManager.instant(TradingPost.MOD_ID); - public static final RegistryReference TRADING_POST_BLOCK = REGISTRY.registerBlock("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of(Material.WOOD).strength(2.5F).sound(SoundType.WOOD))); + public static final RegistryReference TRADING_POST_BLOCK = REGISTRY.registerBlock("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.5F).sound(SoundType.WOOD).ignitedByLava())); public static final RegistryReference TRADING_POST_ITEM = REGISTRY.registerBlockItem(TRADING_POST_BLOCK); public static final RegistryReference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType("trading_post", () -> BlockEntityType.Builder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.get())); public static final RegistryReference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java index 4c6911b..5f844e7 100644 --- a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java +++ b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java @@ -9,6 +9,6 @@ public interface ButtonAccessor { @Mutable - @Accessor - void setOnPress(Button.OnPress onPress); + @Accessor("onPress") + void tradingpost$setOnPress(Button.OnPress onPress); } diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java index fc13489..a67dadd 100644 --- a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java +++ b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java @@ -1,6 +1,6 @@ package fuzs.tradingpost.mixin.client.accessor; -import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.screens.inventory.MerchantScreen; import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.world.item.trading.MerchantOffers; @@ -11,24 +11,24 @@ @Mixin(MerchantScreen.class) public interface MerchantScreenAccessor { - @Accessor - int getShopItem(); + @Accessor("shopItem") + int tradingpost$getShopItem(); - @Accessor - void setShopItem(int shopItem); + @Accessor("shopItem") + void tradingpost$setShopItem(int shopItem); - @Accessor - int getScrollOff(); + @Accessor("scrollOff") + int tradingpost$getScrollOff(); - @Accessor - void setScrollOff(int scrollOff); + @Accessor("scrollOff") + void tradingpost$setScrollOff(int scrollOff); - @Invoker - void callRenderScroller(PoseStack matrixStack, int width, int height, MerchantOffers offers); + @Invoker("renderScroller") + void tradingpost$callRenderScroller(GuiGraphics guiGraphics, int width, int height, MerchantOffers offers); - @Invoker - void callRenderButtonArrows(PoseStack matrixStack, MerchantOffer offer, int width, int height); + @Invoker("renderButtonArrows") + void tradingpost$callRenderButtonArrows(GuiGraphics guiGraphics, MerchantOffer offer, int width, int height); - @Invoker - void callRenderProgressBar(PoseStack matrixStack, int width, int height, MerchantOffer activeOffer); + @Invoker("renderProgressBar") + void tradingpost$callRenderProgressBar(GuiGraphics guiGraphics, int width, int height, MerchantOffer activeOffer); } diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java index 402bf79..99e17d4 100644 --- a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java +++ b/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java @@ -1,6 +1,6 @@ package fuzs.tradingpost.mixin.client.accessor; -import com.mojang.blaze3d.vertex.PoseStack; +import net.minecraft.client.gui.GuiGraphics; import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.gen.Accessor; import org.spongepowered.asm.mixin.gen.Invoker; @@ -12,5 +12,5 @@ public interface TradeOfferButtonAccessor { int tradingpost$getIndex(); @Invoker("renderToolTip") - void tradingpost$callRenderToolTip(PoseStack poseStack, int mouseX, int mouseY); + void tradingpost$callRenderToolTip(GuiGraphics guiGraphics, int mouseX, int mouseY); } diff --git a/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java index 1d5c0b5..bb7a64b 100644 --- a/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java +++ b/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java @@ -112,7 +112,7 @@ private void playTradeSound() { if (!this.traders.isClientSide()) { Merchant merchant = this.traders.getCurrentMerchant(); if (merchant instanceof Entity entity) { - entity.getLevel().playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.traders.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false); + entity.level().playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.traders.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false); } } } diff --git a/Fabric/build.gradle b/Fabric/build.gradle index 87e6c61..356bbf5 100644 --- a/Fabric/build.gradle +++ b/Fabric/build.gradle @@ -1,15 +1,10 @@ -plugins { - id 'fabric-loom' version '1.0.+' - id 'io.github.juuxel.loom-quiltflower' version '1.+' - // this depends on an older version of guava, which loom is incompatible with, so make sure to apply this plugin after loom - // haven't found a proper way to manage plugin dependencies otherwise - id 'me.hypherionmc.cursegradle' version '2.+' - // cannot apply this in the base build.gradle as it'll be the same for all subprojects, only one configuration will work - id 'com.modrinth.minotaur' version '2.+' -} +apply plugin: 'fabric-loom' +apply plugin: 'io.github.juuxel.loom-quiltflower' +apply plugin: 'me.hypherionmc.cursegradle' +apply plugin: 'com.modrinth.minotaur' archivesBaseName = rootProject.name -version = "v${modVersion}-${minecraftVersion}-Fabric" +version = "v${modVersion}-${libs.versions.minecraft.get()}-Fabric" group = modMavenGroup repositories { @@ -17,10 +12,6 @@ repositories { name = "Modmuss" url = "https://maven.modmuss50.me/" } - maven { - name = 'Terraformers' - url = "https://maven.terraformersmc.com/" - } maven { name = "ladysnake" url = 'https://ladysnake.jfrog.io/artifactory/mods' @@ -38,22 +29,26 @@ dependencies { } // Minecraft - minecraft "com.mojang:minecraft:${minecraftVersion}" + minecraft "com.mojang:minecraft:${libs.versions.minecraft.get()}" mappings loom.layered() { officialMojangMappings() -// parchment("org.parchmentmc.data:parchment-${minecraftVersion}:${parchmentMappingsVersion}@zip") + parchment("org.parchmentmc.data:parchment-${libs.versions.parchmentMinecraft.get()}:${libs.versions.parchment.get()}@zip") } // Fabric - modApi "net.fabricmc:fabric-loader:${fabricVersion}" - modApi "net.fabricmc.fabric-api:fabric-api:${fabricApiVersion}" + modApi "net.fabricmc:fabric-loader:${libs.versions.fabric.get()}" + modApi "net.fabricmc.fabric-api:fabric-api:${libs.versions.fabricApi.get()}" + + // Cardinal Components +// modApi(include("dev.onyxstudios.cardinal-components-api:cardinal-components-base:${libs.versions.cardinalcomponents.get()}")) +// modApi(include("dev.onyxstudios.cardinal-components-api:cardinal-components-entity:${libs.versions.cardinalcomponents.get()}")) // Quality of Life Mods - modLocalRuntime "com.terraformersmc:modmenu:6.2.2" -// modLocalRuntime "curse.maven:configured-fabric-667378:4441611" + modLocalRuntime "com.terraformersmc:modmenu:${libs.versions.modmenu.get()}" + modLocalRuntime "fuzs.forgeconfigscreens:forgeconfigscreens-fabric:${libs.versions.forgeconfigscreens.get()}" // Puzzles Lib - modApi "fuzs.puzzleslib:puzzleslib-fabric:${puzzlesVersion}" + modApi "fuzs.puzzleslib:puzzleslib-fabric:${libs.versions.puzzles.get()}" } loom { @@ -91,51 +86,53 @@ processResources { duplicatesStrategy DuplicatesStrategy.INCLUDE // this will ensure that this task is redone when a value changes - inputs.property "modId", "${modId}" - inputs.property "modName", "${modName}" - inputs.property "modVersion", "${modVersion}" - inputs.property "modDescription", "${modDescription}" - inputs.property "modGroup", project.group - inputs.property "modPageUrl", "${modSourceUrl}" - inputs.property "modIssueUrl", "${modIssueUrl}" - inputs.property "modAuthor", "${modAuthor}" - inputs.property "minFabricVersion", "${minFabricVersion}" - inputs.property "minFabricApiVersion", "${minFabricApiVersion}" - inputs.property "minecraftVersion", "${minecraftVersion}" - inputs.property "minPuzzlesVersion", "${minPuzzlesVersion}" - inputs.property "resourcePackFormat", "${resourcePackFormat}" - inputs.property "dataPackFormat", "${dataPackFormat}" - inputs.property "mainEntryPoint", "${project.group}.${rootProject.name}Fabric" - inputs.property "clientEntryPoint", "${project.group}.client.${rootProject.name}FabricClient" - inputs.property "modFabricEnvironment", "${modFabricEnvironment}" + inputs.property "modId", modId + inputs.property "modName", modName + inputs.property "modVersion", modVersion + inputs.property "modDescription", modDescription + inputs.property "modGroup", project.group + inputs.property "modPageUrl", modSourceUrl + inputs.property "modIssueUrl", modIssueUrl + inputs.property "modAuthor", modAuthor + inputs.property "modLicense", modLicense + inputs.property "minFabricVersion", libs.versions.minFabric.get() + inputs.property "minFabricApiVersion", libs.versions.minFabricApi.get() + inputs.property "minecraftVersion", libs.versions.minecraft.get() + inputs.property "minPuzzlesVersion", libs.versions.minPuzzles.get() + inputs.property "resourcePackFormat", libs.versions.resources.get() + inputs.property "dataPackFormat", libs.versions.data.get() + inputs.property "mainEntryPoint", "${project.group}.${rootProject.name}Fabric" + inputs.property "clientEntryPoint", "${project.group}.client.${rootProject.name}FabricClient" + inputs.property "modFabricEnvironment", modFabricEnvironment // replace stuff in fabric.mod.json - filesMatching ('fabric.mod.json') { - expand ( - 'modId': "${modId}", - 'modName': "${modName}", - 'modVersion': "${modVersion}", - 'modDescription': "${modDescription}", - 'modGroup': project.group, - 'modPageUrl': "${modSourceUrl}", - 'modIssueUrl': "${modIssueUrl}", - 'modAuthor': "${modAuthor}", - 'minFabricVersion': "${minFabricVersion}", - 'minFabricApiVersion': "${minFabricApiVersion}", - 'minecraftVersion': "${minecraftVersion}", - "minPuzzlesVersion": "${minPuzzlesVersion}", - "mainEntryPoint": "${project.group}.${rootProject.name}Fabric", - "clientEntryPoint": "${project.group}.client.${rootProject.name}FabricClient", - "modFabricEnvironment": "${modFabricEnvironment}" + filesMatching('fabric.mod.json') { + expand( + 'modId': modId, + 'modName': modName, + 'modVersion': modVersion, + 'modDescription': modDescription, + 'modGroup': project.group, + 'modPageUrl': modSourceUrl, + 'modIssueUrl': modIssueUrl, + 'modAuthor': modAuthor, + 'modLicense': modLicense, + 'minFabricVersion': libs.versions.minFabric.get(), + 'minFabricApiVersion': libs.versions.minFabricApi.get(), + 'minecraftVersion': libs.versions.minecraft.get(), + "minPuzzlesVersion": libs.versions.minPuzzles.get(), + "mainEntryPoint": "${project.group}.${rootProject.name}Fabric", + "clientEntryPoint": "${project.group}.client.${rootProject.name}FabricClient", + "modFabricEnvironment": modFabricEnvironment ) } // replace stuff in pack.mcmeta - filesMatching ('pack.mcmeta') { - expand ( - 'modDescription': "${modDescription}", - "resourcePackFormat": "${resourcePackFormat}", - "dataPackFormat": "${dataPackFormat}" + filesMatching('pack.mcmeta') { + expand( + 'modDescription': modDescription, + "resourcePackFormat": libs.versions.resources.get(), + "dataPackFormat": libs.versions.data.get() ) } } @@ -154,7 +151,7 @@ javadoc { publishing { publications { - mavenJava (MavenPublication) { + mavenJava(MavenPublication) { artifactId = "${modId}-fabric" version = modVersion from components.java @@ -173,8 +170,8 @@ publishing { } licenses { license { - name = 'MPL-2' - url = 'https://www.mozilla.org/en-US/MPL/2.0/' + name = "${modLicense}" + url = "https://spdx.org/licenses/${modLicense}.html" } } developers { @@ -199,7 +196,9 @@ signing { } curseforge { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } + if (!file('../CHANGELOG.md').canRead()) { + throw new FileNotFoundException("Could not read changelog file") + } apiKey = project.hasProperty('curseApiToken') ? project.findProperty('curseApiToken') : '' project { id = projectCurseId @@ -211,11 +210,12 @@ curseforge { addGameVersion it.trim() } mainArtifact(remapJar) { - displayName = "[FABRIC] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" + displayName = "[FABRIC] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" relations { requiredDependency 'fabric-api' requiredDependency 'forge-config-api-port-fabric' requiredDependency 'puzzles-lib' +// embeddedLibrary 'cardinal-components' } } // addArtifact sourcesJar @@ -228,11 +228,13 @@ curseforge { } modrinth { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } + if (!file('../CHANGELOG.md').canRead()) { + throw new FileNotFoundException("Could not read changelog file") + } token = project.hasProperty('modrinthApiToken') ? project.findProperty('modrinthApiToken') : '' projectId = projectModrinthId versionNumber = project.version - versionName = "[FABRIC] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" + versionName = "[FABRIC] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" changelog = file('../CHANGELOG.md').text versionType = projectReleaseType uploadFile = remapJar // This is the java jar task @@ -245,6 +247,7 @@ modrinth { required.project 'fabric-api' required.project 'forge-config-api-port' required.project 'puzzles-lib' +// embedded.project 'cardinal-components-api' } // debugMode = true } diff --git a/Fabric/src/main/resources/fabric.mod.json b/Fabric/src/main/resources/fabric.mod.json index 86f93d9..c0c6cfa 100644 --- a/Fabric/src/main/resources/fabric.mod.json +++ b/Fabric/src/main/resources/fabric.mod.json @@ -16,7 +16,7 @@ "sources": "${modPageUrl}" }, - "license": "MPL-2.0", + "license": "${modLicense}", "icon": "mod_logo.png", "environment": "${modFabricEnvironment}", diff --git a/Forge/build.gradle b/Forge/build.gradle index 6781901..fb60176 100644 --- a/Forge/build.gradle +++ b/Forge/build.gradle @@ -1,34 +1,19 @@ -buildscript { - repositories { - mavenCentral() - maven { url = 'https://maven.minecraftforge.net' } - maven { url = 'https://repo.spongepowered.org/repository/maven-public/' } - } - dependencies { - classpath group: 'net.minecraftforge.gradle', name: 'ForgeGradle', version: '5.1.+', changing: true - classpath 'org.spongepowered:mixingradle:0.7-SNAPSHOT' - classpath group: 'org.parchmentmc', name: 'librarian', version: '1.+' - } -} - plugins { - id 'me.hypherionmc.cursegradle' version '2.+' - // cannot apply this in the base build.gradle as it'll be the same for all subprojects, only one configuration will work - id 'com.modrinth.minotaur' version '2.+' + id 'net.minecraftforge.gradle' version '6.0.+' + id 'org.spongepowered.mixin' version '0.7.+' + id 'org.parchmentmc.librarian.forgegradle' version '1.+' } -apply plugin: 'net.minecraftforge.gradle' -apply plugin: 'org.parchmentmc.librarian.forgegradle' -apply plugin: 'eclipse' -apply plugin: 'org.spongepowered.mixin' +apply plugin: 'me.hypherionmc.cursegradle' +apply plugin: 'com.modrinth.minotaur' archivesBaseName = rootProject.name -version = "v${modVersion}-${minecraftVersion}-Forge" +version = "v${modVersion}-${libs.versions.minecraft.get()}-Forge" group = modMavenGroup minecraft { -// mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${minecraftVersion}" - mappings channel: 'official', version: "${minecraftVersion}" +// mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${parchmentMinecraftVersion}" + mappings channel: 'official', version: "${libs.versions.minecraft.get()}" runs { client { @@ -112,16 +97,15 @@ dependencies { } // Minecraft - minecraft "net.minecraftforge:forge:${forgeVersion}" + minecraft "net.minecraftforge:forge:${libs.versions.forge.get()}" annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' // Quality of Life Mods - runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:6.0.0") - runtimeOnly fg.deobf("curse.maven:catalogue-459701:4496718") - runtimeOnly fg.deobf("curse.maven:configured-457570:4462894") + runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.get()}") + runtimeOnly fg.deobf("fuzs.forgeconfigscreens:forgeconfigscreens-forge:${libs.versions.forgeconfigscreens.get()}") // Puzzles Lib - api fg.deobf("fuzs.puzzleslib:puzzleslib-forge:${puzzlesVersion}") + api fg.deobf("fuzs.puzzleslib:puzzleslib-forge:${libs.versions.puzzles.get()}") } mixin { @@ -145,49 +129,51 @@ processResources { duplicatesStrategy DuplicatesStrategy.INCLUDE // this will ensure that this task is redone when a value changes - inputs.property "modId", "${modId}" - inputs.property "modName", "${modName}" - inputs.property "modVersion", "${modVersion}" - inputs.property "modDescription", "${modDescription}" - inputs.property "modGroup", project.group - inputs.property "modPageUrl", "${modSourceUrl}" - inputs.property "modUpdateUrl", "${modUpdateUrl}" - inputs.property "modIssueUrl", "${modIssueUrl}" - inputs.property "modAuthor", "${modAuthor}" - inputs.property "minFMLVersion", "${minForgeVersion}".replaceAll("\\..*", "") - inputs.property "minForgeVersion", "${minForgeVersion}" - inputs.property "minecraftVersion", "${minecraftVersion}" - inputs.property "minPuzzlesVersion", "${minPuzzlesVersion}" - inputs.property "resourcePackFormat", "${resourcePackFormat}" - inputs.property "dataPackFormat", "${dataPackFormat}" - inputs.property "modForgeDisplayTest", "${modForgeDisplayTest}" + inputs.property "modId", modId + inputs.property "modName", modName + inputs.property "modVersion", modVersion + inputs.property "modDescription", modDescription + inputs.property "modGroup", project.group + inputs.property "modPageUrl", modSourceUrl + inputs.property "modUpdateUrl", modUpdateUrl + inputs.property "modIssueUrl", modIssueUrl + inputs.property "modAuthor", modAuthor + inputs.property "modLicense", modLicense + inputs.property "minFMLVersion", libs.versions.minForge.get().replaceAll("\\..*", "") + inputs.property "minForgeVersion", libs.versions.minForge.get() + inputs.property "minecraftVersion", libs.versions.minecraft.get() + inputs.property "minPuzzlesVersion", libs.versions.minPuzzles.get() + inputs.property "resourcePackFormat", libs.versions.resources.get() + inputs.property "dataPackFormat", libs.versions.data.get() + inputs.property "modForgeDisplayTest", modForgeDisplayTest // replace stuff in mods.toml - filesMatching ('META-INF/mods.toml') { - expand ( - 'modId': "${modId}", - 'modName': "${modName}", - 'modVersion': "${modVersion}", - 'modDescription': "${modDescription}", - 'modGroup': project.group, - 'modPageUrl': "${modSourceUrl}", - 'modUpdateUrl': "${modUpdateUrl}", - 'modIssueUrl': "${modIssueUrl}", - 'modAuthor': "${modAuthor}", - 'minFMLVersion': "${minForgeVersion}".replaceAll("\\..*", ""), - 'minForgeVersion': "${minForgeVersion}", - 'minecraftVersion': "${minecraftVersion}", - 'minPuzzlesVersion': "${minPuzzlesVersion}", - 'modForgeDisplayTest': "${modForgeDisplayTest}" + filesMatching('META-INF/mods.toml') { + expand( + 'modId': modId, + 'modName': modName, + 'modVersion': modVersion, + 'modDescription': modDescription, + 'modGroup': project.group, + 'modPageUrl': modSourceUrl, + 'modUpdateUrl': modUpdateUrl, + 'modIssueUrl': modIssueUrl, + 'modAuthor': modAuthor, + 'modLicense': modLicense, + 'minFMLVersion': libs.versions.minForge.get().replaceAll("\\..*", ""), + 'minForgeVersion': libs.versions.minForge.get(), + 'minecraftVersion': libs.versions.minecraft.get(), + 'minPuzzlesVersion': libs.versions.minPuzzles.get(), + 'modForgeDisplayTest': modForgeDisplayTest ) } // replace stuff in pack.mcmeta - filesMatching ('pack.mcmeta') { - expand ( - 'modDescription': "${modDescription}", - "resourcePackFormat": "${resourcePackFormat}", - "dataPackFormat": "${dataPackFormat}" + filesMatching('pack.mcmeta') { + expand( + 'modDescription': modDescription, + "resourcePackFormat": libs.versions.resources.get(), + "dataPackFormat": libs.versions.data.get() ) } } @@ -210,7 +196,7 @@ jar.finalizedBy('reobfJar') publishing { publications { - mavenJava (MavenPublication) { + mavenJava(MavenPublication) { artifactId = "${modId}-forge" version = modVersion from components.java @@ -231,8 +217,8 @@ publishing { } licenses { license { - name = 'MPL-2' - url = 'https://www.mozilla.org/en-US/MPL/2.0/' + name = "${modLicense}" + url = "https://spdx.org/licenses/${modLicense}.html" } } developers { @@ -281,7 +267,9 @@ jar.finalizedBy 'signJar' signJar.mustRunAfter 'reobfJar' curseforge { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } + if (!file('../CHANGELOG.md').canRead()) { + throw new FileNotFoundException("Could not read changelog file") + } apiKey = project.hasProperty('curseApiToken') ? project.findProperty('curseApiToken') : '' project { id = projectCurseId @@ -293,7 +281,7 @@ curseforge { addGameVersion it.trim() } mainArtifact(jar) { - displayName = "[FORGE] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" + displayName = "[FORGE] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" relations { requiredDependency 'puzzles-lib' } @@ -308,11 +296,13 @@ curseforge { } modrinth { - if (!file('../CHANGELOG.md').canRead()) { throw new FileNotFoundException("Could not read changelog file") } + if (!file('../CHANGELOG.md').canRead()) { + throw new FileNotFoundException("Could not read changelog file") + } token = project.hasProperty('modrinthApiToken') ? project.findProperty('modrinthApiToken') : '' projectId = projectModrinthId versionNumber = project.version - versionName = "[FORGE] [${minecraftVersion}] ${rootProject.name}-v${modVersion}" + versionName = "[FORGE] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" changelog = file('../CHANGELOG.md').text versionType = projectReleaseType uploadFile = jar // This is the java jar task @@ -327,7 +317,10 @@ modrinth { // debugMode = true } -import groovy.json.* + +import groovy.json.JsonBuilder +import groovy.json.JsonOutput +import groovy.json.JsonSlurper task copyJarToDir(type: Copy) { onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } @@ -359,13 +352,15 @@ task refreshUpdateJson { def builder = new JsonBuilder() updateJson = builder { homepage "${modSourceUrl}" - promos { "${projectGameVersions}".replaceAll(" ", "").split(",").each { version -> - "${version}-latest" "${modVersion}" - // alpha and beta releases will contain 'a' or 'b' char respectively, don't update recommended for those - if ("${modVersion}".matches("[^a-zA-Z]+")) { - "${version}-recommended" "${modVersion}" + promos { + "${projectGameVersions}".replaceAll(" ", "").split(",").each { version -> + "${version}-latest" "${modVersion}" + // alpha and beta releases will contain 'a' or 'b' char respectively, don't update recommended for those + if ("${modVersion}".matches("[^a-zA-Z]+")) { + "${version}-recommended" "${modVersion}" + } } - } } + } } } def output = new JsonOutput() @@ -374,4 +369,4 @@ task refreshUpdateJson { } build.finalizedBy project.tasks.copyJarToDir, rootProject.tasks.incrementBuildNumber -[tasks.modrinth, tasks.curseforge].each {it.finalizedBy project.tasks.refreshUpdateJson} +[tasks.modrinth, tasks.curseforge].each { it.finalizedBy project.tasks.refreshUpdateJson } diff --git a/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 b/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 index b4c5001..f6123e9 100644 --- a/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 +++ b/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 @@ -1,2 +1,2 @@ -// 1.19.4 2023-05-29T09:07:32.722967 Sprite Sources +// 1.20 2023-06-11T15:28:40.244103 Sprite Sources 84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/Forge/src/main/resources/META-INF/mods.toml b/Forge/src/main/resources/META-INF/mods.toml index 925e0f6..6f39b5f 100644 --- a/Forge/src/main/resources/META-INF/mods.toml +++ b/Forge/src/main/resources/META-INF/mods.toml @@ -1,6 +1,6 @@ modLoader="javafml" loaderVersion="[${minFMLVersion},)" -license="MPL-2.0" +license = "${modLicense}" issueTrackerURL="${modIssueUrl}" [[mods]] diff --git a/build.gradle b/build.gradle index 83a423b..bffa446 100644 --- a/build.gradle +++ b/build.gradle @@ -1,3 +1,10 @@ +plugins { + id 'fabric-loom' version '1.2.+' apply false + id 'io.github.juuxel.loom-quiltflower' version '1.+' apply false + id 'me.hypherionmc.cursegradle' version '2.+' apply false + id 'com.modrinth.minotaur' version '2.+' apply false +} + apply from: './gradle/tasks.gradle' subprojects { @@ -5,6 +12,7 @@ subprojects { apply plugin: 'java-library' apply plugin: 'maven-publish' apply plugin: 'signing' + apply plugin: 'idea' java.toolchain.languageVersion = JavaLanguageVersion.of(17) java.withSourcesJar() @@ -16,7 +24,7 @@ subprojects { mavenCentral() mavenLocal() maven { - name = 'Sponge / Mixin' + name = 'Sponge' url = 'https://repo.spongepowered.org/repository/maven-public/' } maven { @@ -35,22 +43,44 @@ subprojects { name = 'Parchment' url = 'https://maven.parchmentmc.org' } - maven { - name = 'Curse Maven' - url = 'https://cursemaven.com' + exclusiveContent { + forRepository { + maven { + name = "CurseForge" + url = "https://cursemaven.com" + } + } + filter { + includeGroup "curse.maven" + } + } + exclusiveContent { + forRepository { + maven { + name = "Modrinth" + url = "https://api.modrinth.com/maven" + } + } + filter { + includeGroup "maven.modrinth" + } } maven { name = "Fuzs Mod Resources" url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" } maven { - name = "Progwml6 maven" - url = "https://dvs1.progwml6.com/files/maven/" + name = 'Terraformers' + url = "https://maven.terraformersmc.com/" } maven { name = "ModMaven" url = "https://modmaven.dev" } + maven { + name = "AppleSkin" + url "https://maven.ryanliptak.com/" + } flatDir { dirs 'libs' } @@ -71,17 +101,17 @@ subprojects { from rootProject.file("CHANGELOG.md") manifest { attributes([ - "Specification-Title" : modName, - 'Specification-Version' : modVersion, - "Specification-Vendor" : modAuthor, - 'Implementation-Title' : modName, - 'Implementation-Version' : modVersion, - 'Implementation-Vendor' : modAuthor, - 'Implementation-Timestamp' : new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - 'Implementation-Timestamp-Milli' : System.currentTimeMillis(), - 'Implementation-URL' : modSourceUrl, - 'Built-On-Java' : "${System.getProperty('java.vm.version')} (${System.getProperty('java.vm.vendor')})", - 'Built-On-Minecraft' : minecraftVersion + "Specification-Title" : modName, + 'Specification-Version' : modVersion, + "Specification-Vendor" : modAuthor, + 'Implementation-Title' : modName, + 'Implementation-Version' : modVersion, + 'Implementation-Vendor' : modAuthor, + 'Implementation-Timestamp' : new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), + 'Implementation-Timestamp-Milli': System.currentTimeMillis(), + 'Implementation-URL' : modSourceUrl, + 'Built-On-Java' : "${System.getProperty('java.vm.version')} (${System.getProperty('java.vm.vendor')})", + 'Built-On-Minecraft' : libs.versions.minecraft.get() ]) } group 'jar' @@ -105,7 +135,9 @@ task incrementBuildNumber { def propertiesName = 'gradle.properties' // build number is stored in global gradle.properties def propertiesFile = new File(project.gradle.gradleUserHomeDir, propertiesName) - if (!propertiesFile.canRead()) { throw new FileNotFoundException("Could not read file ".concat(propertiesName)) } + if (!propertiesFile.canRead()) { + throw new FileNotFoundException("Could not read file ".concat(propertiesName)) + } def buildNumberMatcher = Pattern.compile("uniqueBuildNumber=(\\d+)").matcher(propertiesFile.getText()) buildNumberMatcher.find() def versionCode = Integer.parseInt(buildNumberMatcher.group(1)) diff --git a/gradle.properties b/gradle.properties index 6dcd6e1..5ce5c46 100755 --- a/gradle.properties +++ b/gradle.properties @@ -3,32 +3,15 @@ org.gradle.jvmargs=-Xmx3G org.gradle.daemon=false org.gradle.parallel=true - -# Common Project -minecraftVersion=1.19.4 -parchmentMappingsVersion=2023.03.12 -puzzlesVersion=6.0.8 -minPuzzlesVersion=6.0.8 -resourcePackFormat=13 -dataPackFormat=12 copyBuildJar=true -# Forge Project -forgeVersion=1.19.4-45.0.64 -minForgeVersion=45.0 - -# Fabric Project -fabricVersion=0.14.19 -minFabricVersion=0.14.0 -fabricApiVersion=0.81.1+1.19.4 -minFabricApiVersion=0.76.0 - # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=6.0.0 +modVersion=7.0.0 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! +modLicense=MPL-2.0 modSourceUrl=https://github.com/Fuzss/tradingpost modIssueUrl=https://github.com/Fuzss/tradingpost/issues modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/tradingpost.json @@ -40,6 +23,6 @@ modFabricEnvironment=* # Mod Publishing projectReleaseType=release -projectGameVersions=1.19.4 +projectGameVersions=1.20 projectCurseId=539057 projectModrinthId=8pcjMDgj diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml new file mode 100644 index 0000000..7b68bce --- /dev/null +++ b/gradle/libs.versions.toml @@ -0,0 +1,25 @@ +[versions] +minecraft = "1.20" +parchment = "2023.03.12" +parchmentMinecraft = "1.19.3" +puzzles = "7.0.2" +minPuzzles = "7.0.2" +resources = "15" +data = "15" + +# Forge +forge = "1.20-46.0.10" +minForge = "46.0.0" + +# Fabric +fabric = "0.14.21" +minFabric = "0.14.21" +fabricApi = "0.83.0+1.20" +minFabricApi = "0.83.0" + +# Mods +modmenu = "7.0.1" +bettermodsbutton = "7.0.0" +forgeconfigscreens = "7.0.0" +cardinalcomponents = "5.2.0" +forgeconfigapiport = "7.0.0" diff --git a/gradle/wrapper/gradle-wrapper.jar b/gradle/wrapper/gradle-wrapper.jar index 41d9927a4d4fb3f96a785543079b8df6723c946b..943f0cbfa754578e88a3dae77fce6e3dea56edbf 100644 GIT binary patch delta 36987 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 z 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 VBfu2+*qg&~f-ihLS3eum{s(|${^$Sz diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 41dfb87..37aef8d 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,5 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-7.4-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/gradlew b/gradlew index 1b6c787..65dcd68 100755 --- a/gradlew +++ b/gradlew @@ -55,7 +55,7 @@ # Darwin, MinGW, and NonStop. # # (3) This script is generated from the Groovy template -# https://github.com/gradle/gradle/blob/master/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt # within the Gradle project. # # You can find Gradle at https://github.com/gradle/gradle/. @@ -80,10 +80,10 @@ do esac done -APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit - -APP_NAME="Gradle" +# This is normally unused +# shellcheck disable=SC2034 APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit # Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' @@ -143,12 +143,16 @@ fi if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then case $MAX_FD in #( max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 MAX_FD=$( ulimit -H -n ) || warn "Could not query maximum file descriptor limit" esac case $MAX_FD in #( '' | soft) :;; #( *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 ulimit -n "$MAX_FD" || warn "Could not set maximum file descriptor limit to $MAX_FD" esac @@ -205,6 +209,12 @@ set -- \ org.gradle.wrapper.GradleWrapperMain \ "$@" +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + # Use "xargs" to parse quoted args. # # With -n1 it outputs one arg per line, with the quotes and backslashes removed. diff --git a/gradlew.bat b/gradlew.bat index 107acd3..93e3f59 100644 --- a/gradlew.bat +++ b/gradlew.bat @@ -14,7 +14,7 @@ @rem limitations under the License. @rem -@if "%DEBUG%" == "" @echo off +@if "%DEBUG%"=="" @echo off @rem ########################################################################## @rem @rem Gradle startup script for Windows @@ -25,7 +25,8 @@ if "%OS%"=="Windows_NT" setlocal set DIRNAME=%~dp0 -if "%DIRNAME%" == "" set DIRNAME=. +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused set APP_BASE_NAME=%~n0 set APP_HOME=%DIRNAME% @@ -40,7 +41,7 @@ if defined JAVA_HOME goto findJavaFromJavaHome set JAVA_EXE=java.exe %JAVA_EXE% -version >NUL 2>&1 -if "%ERRORLEVEL%" == "0" goto execute +if %ERRORLEVEL% equ 0 goto execute echo. echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. @@ -75,13 +76,15 @@ set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar :end @rem End local scope for the variables with windows NT shell -if "%ERRORLEVEL%"=="0" goto mainEnd +if %ERRORLEVEL% equ 0 goto mainEnd :fail rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of rem the _cmd.exe /c_ return code! -if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1 -exit /b 1 +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% :mainEnd if "%OS%"=="Windows_NT" endlocal diff --git a/settings.gradle b/settings.gradle index 429f534..18da063 100644 --- a/settings.gradle +++ b/settings.gradle @@ -6,20 +6,16 @@ pluginManagement { url = 'https://maven.fabricmc.net/' } maven { - name = 'Sponge Snapshots' + name = 'Sponge' url = 'https://repo.spongepowered.org/repository/maven-public/' } maven { - name = 'Quilt (Release)' + name = 'Quilt' url = 'https://maven.quiltmc.org/repository/release' } maven { - name = 'Quilt (Snapshot)' - url = 'https://maven.quiltmc.org/repository/snapshot' - } - maven { - name = 'QuiltFlower' - url = 'https://server.bbkr.space/artifactory/libs-release/' + name = 'Minecraft Forge' + url = 'https://maven.minecraftforge.net/' } } } From 7169563816d78fb2c4272f1ef7c97f1da326522c Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 28 Jun 2023 11:13:29 +0200 Subject: [PATCH 06/24] new 1.20.1 setup --- .gitattributes | 2 - .github/ISSUE_TEMPLATE/bug.yml | 6 +- .github/ISSUE_TEMPLATE/crash.yml | 6 +- .github/ISSUE_TEMPLATE/suggestion.yml | 2 +- .gitignore | 5 +- .idea/gradle.xml | 44 +++ 1.18/.idea/scopes/Fabric_sources.xml | 3 + 1.18/.idea/scopes/Forge_sources.xml | 3 + CHANGELOG.md => 1.18/CHANGELOG.md | 4 +- 1.18/Common/build.gradle | 11 + .../main/java/fuzs/examplemod/ExampleMod.java | 16 + .../examplemod/client/ExampleModClient.java | 7 + .../resources/examplemod.common.mixins.json | 15 + 1.18/Common/src/main/resources/mod_banner.png | Bin 0 -> 17858 bytes 1.18/Common/src/main/resources/mod_logo.png | Bin 0 -> 6537 bytes .../Common}/src/main/resources/pack.mcmeta | 0 1.18/Fabric/build.gradle | 29 ++ .../fuzs/examplemod/ExampleModFabric.java | 12 + .../client/ExampleModFabricClient.java | 13 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../resources/examplemod.fabric.mixins.json | 15 + .../Fabric/src/main/resources/fabric.mod.json | 45 +++ 1.18/Forge/build.gradle | 28 ++ .../java/fuzs/examplemod/ExampleModForge.java | 25 ++ .../client/ExampleModForgeClient.java | 17 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../src/main/resources/META-INF/mods.toml | 40 ++ .../resources/examplemod.forge.mixins.json | 15 + 1.18/build.gradle | 12 + 1.18/gradle.properties | 35 ++ .../gradle}/wrapper/gradle-wrapper.jar | Bin 1.18/gradle/wrapper/gradle-wrapper.properties | 6 + gradlew => 1.18/gradlew | 0 gradlew.bat => 1.18/gradlew.bat | 0 settings.gradle => 1.18/settings.gradle | 16 +- 1.19/.idea/scopes/Fabric_sources.xml | 3 + 1.19/.idea/scopes/Forge_sources.xml | 3 + 1.19/CHANGELOG.md | 9 + 1.19/Common/build.gradle | 11 + .../main/java/fuzs/examplemod/ExampleMod.java | 16 + .../examplemod/client/ExampleModClient.java | 7 + .../resources/examplemod.common.mixins.json | 15 + 1.19/Common/src/main/resources/mod_banner.png | Bin 0 -> 17858 bytes 1.19/Common/src/main/resources/mod_logo.png | Bin 0 -> 6537 bytes 1.19/Common/src/main/resources/pack.mcmeta | 8 + 1.19/Fabric/build.gradle | 29 ++ .../fuzs/examplemod/ExampleModFabric.java | 12 + .../client/ExampleModFabricClient.java | 13 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../resources/examplemod.fabric.mixins.json | 15 + .../Fabric/src/main/resources/fabric.mod.json | 45 +++ 1.19/Forge/build.gradle | 29 ++ .../java/fuzs/examplemod/ExampleModForge.java | 25 ++ .../client/ExampleModForgeClient.java | 17 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../src/main/resources/META-INF/mods.toml | 40 ++ .../resources/examplemod.forge.mixins.json | 15 + 1.19/build.gradle | 12 + 1.19/gradle.properties | 35 ++ 1.19/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes 1.19/gradle/wrapper/gradle-wrapper.properties | 6 + 1.19/gradlew | 244 ++++++++++++ 1.19/gradlew.bat | 92 +++++ 1.19/settings.gradle | 38 ++ 1.20/.idea/scopes/Fabric_sources.xml | 3 + 1.20/.idea/scopes/Forge_sources.xml | 3 + 1.20/CHANGELOG.md | 9 + 1.20/Common/build.gradle | 11 + .../java/fuzs/tradingpost/TradingPost.java | 9 + .../tradingpost/client/TradingPostClient.java | 9 - .../screens/inventory/TradingPostScreen.java | 0 .../blockentity/TradingPostRenderer.java | 0 .../fuzs/tradingpost/config/ServerConfig.java | 0 .../fuzs/tradingpost/init/ModRegistry.java | 0 .../mixin/accessor/MerchantMenuAccessor.java | 0 .../mixin/accessor/VillagerAccessor.java | 0 .../mixin/client/accessor/ButtonAccessor.java | 0 .../accessor/MerchantScreenAccessor.java | 0 .../accessor/TradeOfferButtonAccessor.java | 0 .../network/S2CBuildOffersMessage.java | 0 .../network/S2CMerchantDataMessage.java | 0 .../network/S2CRemoveMerchantsMessage.java | 0 .../network/client/C2SClearSlotsMessage.java | 0 .../world/entity/npc/LocalMerchant.java | 0 .../world/entity/npc/MerchantCollection.java | 0 .../world/inventory/TradingPostContainer.java | 0 .../world/inventory/TradingPostMenu.java | 0 .../world/item/trading/TradingPostOffers.java | 0 .../world/level/block/TradingPostBlock.java | 0 .../block/entity/TradingPostBlockEntity.java | 0 .../tradingpost/blockstates/trading_post.json | 0 .../assets/tradingpost/lang/en_us.json | 0 .../assets/tradingpost/lang/it_it.json | 0 .../assets/tradingpost/lang/pt_br.json | 12 +- .../assets/tradingpost/lang/ru_ru.json | 0 .../assets/tradingpost/lang/zh_tw.json | 0 .../models/block/trading_post.json | 0 .../tradingpost/models/item/trading_post.json | 0 .../textures/block/trading_post_bottom.png | Bin .../textures/block/trading_post_front.png | Bin .../textures/block/trading_post_side.png | Bin .../textures/block/trading_post_top.png | Bin .../textures/item/magnifying_glass.png | Bin .../minecraft/tags/blocks/mineable/axe.json | 0 .../loot_tables/blocks/trading_post.json | 0 .../tradingpost/recipes/trading_post.json | 0 .../entity_types/blacklisted_traders.json | 0 .../Common}/src/main/resources/mod_banner.png | Bin .../Common}/src/main/resources/mod_logo.png | Bin 1.20/Common/src/main/resources/pack.mcmeta | 8 + .../resources/tradingpost.common.mixins.json | 0 1.20/Fabric/build.gradle | 29 ++ .../fuzs/tradingpost/TradingPostFabric.java | 0 .../client/TradingPostFabricClient.java | 0 .../main/java/mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/fabric.mod.json | 0 1.20/Forge/build.gradle | 28 ++ .../178bb4356f8bea3c4b8966704e26df58ba8fa865 | 2 +- .../assets/minecraft/atlases/blocks.json | 0 .../fuzs/tradingpost/TradingPostForge.java | 0 .../client/TradingPostForgeClient.java | 0 .../data/ModSpriteSourceProvider.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 1.20/build.gradle | 12 + gradle.properties => 1.20/gradle.properties | 13 +- 1.20/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle}/wrapper/gradle-wrapper.properties | 0 1.20/gradlew | 244 ++++++++++++ 1.20/gradlew.bat | 92 +++++ 1.20/settings.gradle | 38 ++ Common/build.gradle | 126 ------ Fabric/build.gradle | 266 ------------- Forge/build.gradle | 372 ------------------ build.gradle | 147 ------- gradle/libs.versions.toml | 25 -- gradle/tasks.gradle | 246 ------------ 137 files changed, 1848 insertions(+), 1215 deletions(-) delete mode 100644 .gitattributes create mode 100644 .idea/gradle.xml create mode 100644 1.18/.idea/scopes/Fabric_sources.xml create mode 100644 1.18/.idea/scopes/Forge_sources.xml rename CHANGELOG.md => 1.18/CHANGELOG.md (75%) create mode 100644 1.18/Common/build.gradle create mode 100644 1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java create mode 100644 1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java create mode 100644 1.18/Common/src/main/resources/examplemod.common.mixins.json create mode 100644 1.18/Common/src/main/resources/mod_banner.png create mode 100644 1.18/Common/src/main/resources/mod_logo.png rename {Common => 1.18/Common}/src/main/resources/pack.mcmeta (100%) create mode 100644 1.18/Fabric/build.gradle create mode 100644 1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java create mode 100644 1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java create mode 100644 1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json create mode 100644 1.18/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.18/Forge/build.gradle create mode 100644 1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java create mode 100644 1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java create mode 100644 1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.18/Forge/src/main/resources/META-INF/mods.toml create mode 100644 1.18/Forge/src/main/resources/examplemod.forge.mixins.json create mode 100644 1.18/build.gradle create mode 100755 1.18/gradle.properties rename {gradle => 1.18/gradle}/wrapper/gradle-wrapper.jar (100%) create mode 100644 1.18/gradle/wrapper/gradle-wrapper.properties rename gradlew => 1.18/gradlew (100%) rename gradlew.bat => 1.18/gradlew.bat (100%) rename settings.gradle => 1.18/settings.gradle (55%) create mode 100644 1.19/.idea/scopes/Fabric_sources.xml create mode 100644 1.19/.idea/scopes/Forge_sources.xml create mode 100644 1.19/CHANGELOG.md create mode 100644 1.19/Common/build.gradle create mode 100644 1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java create mode 100644 1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java create mode 100644 1.19/Common/src/main/resources/examplemod.common.mixins.json create mode 100644 1.19/Common/src/main/resources/mod_banner.png create mode 100644 1.19/Common/src/main/resources/mod_logo.png create mode 100755 1.19/Common/src/main/resources/pack.mcmeta create mode 100644 1.19/Fabric/build.gradle create mode 100644 1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java create mode 100644 1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java create mode 100644 1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json create mode 100644 1.19/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.19/Forge/build.gradle create mode 100644 1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java create mode 100644 1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java create mode 100644 1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java create mode 100644 1.19/Forge/src/main/resources/META-INF/mods.toml create mode 100644 1.19/Forge/src/main/resources/examplemod.forge.mixins.json create mode 100644 1.19/build.gradle create mode 100755 1.19/gradle.properties create mode 100644 1.19/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.19/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.19/gradlew create mode 100644 1.19/gradlew.bat create mode 100644 1.19/settings.gradle create mode 100644 1.20/.idea/scopes/Fabric_sources.xml create mode 100644 1.20/.idea/scopes/Forge_sources.xml create mode 100644 1.20/CHANGELOG.md create mode 100644 1.20/Common/build.gradle rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/TradingPost.java (82%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/client/TradingPostClient.java (83%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/config/ServerConfig.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/init/ModRegistry.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java (100%) rename {Common => 1.20/Common}/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/blockstates/trading_post.json (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/lang/en_us.json (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/lang/it_it.json (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/lang/pt_br.json (98%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/lang/ru_ru.json (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/lang/zh_tw.json (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/models/block/trading_post.json (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/models/item/trading_post.json (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png (100%) rename {Common => 1.20/Common}/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png (100%) rename {Common => 1.20/Common}/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json (100%) rename {Common => 1.20/Common}/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json (100%) rename {Common => 1.20/Common}/src/main/resources/data/tradingpost/recipes/trading_post.json (100%) rename {Common => 1.20/Common}/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json (100%) rename {Common => 1.20/Common}/src/main/resources/mod_banner.png (100%) rename {Common => 1.20/Common}/src/main/resources/mod_logo.png (100%) create mode 100755 1.20/Common/src/main/resources/pack.mcmeta rename {Common => 1.20/Common}/src/main/resources/tradingpost.common.mixins.json (100%) create mode 100644 1.20/Fabric/build.gradle rename {Fabric => 1.20/Fabric}/src/main/java/fuzs/tradingpost/TradingPostFabric.java (100%) rename {Fabric => 1.20/Fabric}/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java (100%) rename {Fabric => 1.20/Fabric}/src/main/java/mixin/ModMixinConfigPlugin.java (100%) rename {Fabric => 1.20/Fabric}/src/main/resources/fabric.mod.json (100%) create mode 100644 1.20/Forge/build.gradle rename {Forge => 1.20/Forge}/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 (60%) rename {Forge => 1.20/Forge}/src/generated/resources/assets/minecraft/atlases/blocks.json (100%) rename {Forge => 1.20/Forge}/src/main/java/fuzs/tradingpost/TradingPostForge.java (100%) rename {Forge => 1.20/Forge}/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java (100%) rename {Forge => 1.20/Forge}/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java (100%) rename {Forge => 1.20/Forge}/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java (100%) rename {Forge => 1.20/Forge}/src/main/resources/META-INF/mods.toml (100%) create mode 100644 1.20/build.gradle rename gradle.properties => 1.20/gradle.properties (69%) create mode 100644 1.20/gradle/wrapper/gradle-wrapper.jar rename {gradle => 1.20/gradle}/wrapper/gradle-wrapper.properties (100%) create mode 100755 1.20/gradlew create mode 100644 1.20/gradlew.bat create mode 100644 1.20/settings.gradle delete mode 100644 Common/build.gradle delete mode 100644 Fabric/build.gradle delete mode 100644 Forge/build.gradle delete mode 100644 build.gradle delete mode 100644 gradle/libs.versions.toml delete mode 100644 gradle/tasks.gradle diff --git a/.gitattributes b/.gitattributes deleted file mode 100644 index dfe0770..0000000 --- a/.gitattributes +++ /dev/null @@ -1,2 +0,0 @@ -# Auto detect text files and perform LF normalization -* text=auto diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 1b22d43..7726363 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -1,6 +1,6 @@ name: Bug Report description: >- - Please use this template when you have encountered a bug in this mod. Supported versions are for Minecraft 1.18+. + Please use this template when you have encountered a bug in this mod. Please note that only the latest mod version for Minecraft 1.18.2, 1.19.2 and 1.20.1 is supported. title: '[Bug]: ' labels: ["bug"] assignees: @@ -27,7 +27,7 @@ body: attributes: label: Minecraft Version (Required) description: What is the Minecraft version you are playing with? - placeholder: ex. 1.19 + placeholder: ex. 1.20.1 validations: required: true - type: input @@ -35,7 +35,7 @@ body: attributes: label: Mod Version (Required) description: What version of the mod are you playing with? - placeholder: ex. v4.0.0 + placeholder: ex. v8.0.0 validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 3df638c..5ca6180 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -1,6 +1,6 @@ name: Crash Report description: >- - Please use this template when this mod has caused your game to crash. Supported versions are for Minecraft 1.18+. + Please use this template when this mod has caused your game to crash. Please note that only the latest mod version for Minecraft 1.18.2, 1.19.2 and 1.20.1 is supported. title: '[Crash]: ' labels: ["bug"] assignees: @@ -27,7 +27,7 @@ body: attributes: label: Minecraft Version (Required) description: What is the Minecraft version you are playing with? - placeholder: ex. 1.19 + placeholder: ex. 1.20.1 validations: required: true - type: input @@ -35,7 +35,7 @@ body: attributes: label: Mod Version (Required) description: What version of the mod are you playing with? - placeholder: ex. v4.0.0 + placeholder: ex. v8.0.0 validations: required: true - type: textarea diff --git a/.github/ISSUE_TEMPLATE/suggestion.yml b/.github/ISSUE_TEMPLATE/suggestion.yml index aca1ce4..0eb9a33 100644 --- a/.github/ISSUE_TEMPLATE/suggestion.yml +++ b/.github/ISSUE_TEMPLATE/suggestion.yml @@ -1,6 +1,6 @@ name: Suggestion description: >- - Please use this template when you want to suggest a feature. Do not ask for mod updates or ports, they will come when they are ready. + Please use this template when you want to suggest a feature. Please do not ask for mod updates or ports, they will come when they are ready. title: '[Suggestion]: ' labels: ["enhancement"] assignees: diff --git a/.gitignore b/.gitignore index 0c5a409..223cbb5 100644 --- a/.gitignore +++ b/.gitignore @@ -32,8 +32,9 @@ classes *.ipr *.iws *.iml -.idea/* -!.idea/scopes +**/.idea/* +!**/.idea/scopes +!.idea/gradle.xml ### NetBeans ### nbproject/private/ diff --git a/.idea/gradle.xml b/.idea/gradle.xml new file mode 100644 index 0000000..311bce0 --- /dev/null +++ b/.idea/gradle.xml @@ -0,0 +1,44 @@ + + + + + + + \ No newline at end of file diff --git a/1.18/.idea/scopes/Fabric_sources.xml b/1.18/.idea/scopes/Fabric_sources.xml new file mode 100644 index 0000000..0448412 --- /dev/null +++ b/1.18/.idea/scopes/Fabric_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.18/.idea/scopes/Forge_sources.xml b/1.18/.idea/scopes/Forge_sources.xml new file mode 100644 index 0000000..7b5f24d --- /dev/null +++ b/1.18/.idea/scopes/Forge_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/CHANGELOG.md b/1.18/CHANGELOG.md similarity index 75% rename from CHANGELOG.md rename to 1.18/CHANGELOG.md index 34d883b..916e567 100644 --- a/CHANGELOG.md +++ b/1.18/CHANGELOG.md @@ -3,7 +3,7 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. -## [v7.0.0-1.20] - 2023-06-11 -- Ported to Minecraft 1.20 +## [v3.0.0-1.18.2] - 2023-06-25 +- Ported to Minecraft 1.18.2 [Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/1.18/Common/build.gradle b/1.18/Common/build.gradle new file mode 100644 index 0000000..949b426 --- /dev/null +++ b/1.18/Common/build.gradle @@ -0,0 +1,11 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common +} + +// @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).each { + it.targetNamespace = "named" +} diff --git a/1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java new file mode 100644 index 0000000..45113b2 --- /dev/null +++ b/1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java @@ -0,0 +1,16 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExampleMod implements ModConstructor { + public static final String MOD_ID = "examplemod"; + public static final String MOD_NAME = "Example Mod"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } +} diff --git a/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java new file mode 100644 index 0000000..e1afacc --- /dev/null +++ b/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java @@ -0,0 +1,7 @@ +package fuzs.examplemod.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; + +public class ExampleModClient implements ClientModConstructor { + +} diff --git a/1.18/Common/src/main/resources/examplemod.common.mixins.json b/1.18/Common/src/main/resources/examplemod.common.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.18/Common/src/main/resources/examplemod.common.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.18/Common/src/main/resources/mod_banner.png b/1.18/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..bda5a0f63968a9c20cc144359547c6d8bb1e893b GIT binary patch literal 17858 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 literal 0 HcmV?d00001 diff --git a/1.18/Common/src/main/resources/mod_logo.png b/1.18/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..98c247e46e4c250202abe7f66209dd16464ade34 GIT binary patch literal 6537 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 literal 0 HcmV?d00001 diff --git a/Common/src/main/resources/pack.mcmeta b/1.18/Common/src/main/resources/pack.mcmeta similarity index 100% rename from Common/src/main/resources/pack.mcmeta rename to 1.18/Common/src/main/resources/pack.mcmeta diff --git a/1.18/Fabric/build.gradle b/1.18/Fabric/build.gradle new file mode 100644 index 0000000..cd8b641 --- /dev/null +++ b/1.18/Fabric/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // Puzzles Lib + modApi libs.puzzleslib.fabric + + // Cardinal Components +// modApi(include(libs.cardinalcomponentsbase.fabric.get())) +// modApi(include(libs.cardinalcomponentsentity.fabric.get())) +// modApi(include(libs.cardinalcomponentsblock.fabric.get())) +// modApi(include(libs.cardinalcomponentschunk.fabric.get())) +// modApi(include(libs.cardinalcomponentsworld.fabric.get())) + + // Extensible Enums +// modApi(include(libs.extensibleenums.fabric.get())) + + // Quality of Life Mods + versionCatalog.findLibrary("modmenu.fabric").ifPresent { + modLocalRuntime(it) + } + versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { + modLocalRuntime(it) + } +} diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java new file mode 100644 index 0000000..124b062 --- /dev/null +++ b/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java @@ -0,0 +1,12 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.fabricmc.api.ModInitializer; + +public class ExampleModFabric implements ModInitializer { + + @Override + public void onInitialize() { + ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); + } +} diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java new file mode 100644 index 0000000..7b55517 --- /dev/null +++ b/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java @@ -0,0 +1,13 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import net.fabricmc.api.ClientModInitializer; + +public class ExampleModFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); + } +} diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..6d413e8 --- /dev/null +++ b/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.mixin; + +import net.fabricmc.loader.api.FabricLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FabricLoader.getInstance().isModLoaded("puzzleslib"); + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.18/Fabric/src/main/resources/fabric.mod.json b/1.18/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..07fc00c --- /dev/null +++ b/1.18/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,45 @@ +{ + "schemaVersion": 1, + "id": "${modId}", + "version": "${modVersion}", + + "name": "${modName}", + "description": "${modDescription}", + + "authors": [ + "${modAuthor}" + ], + + "contact": { + "homepage": "${modPageUrl}", + "issues": "${modIssueUrl}", + "sources": "${modPageUrl}" + }, + + "license": "${modLicense}", + "icon": "mod_logo.png", + + "environment": "${modFabricEnvironment}", + + "entrypoints": { + "main": [ + "${mainEntryPoint}" + ], + "client": [ + "${clientEntryPoint}" + ] + }, + + "mixins": [ + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" + ], + + "depends": { + "fabricloader": ">=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.18/Forge/build.gradle b/1.18/Forge/build.gradle new file mode 100644 index 0000000..dec494a --- /dev/null +++ b/1.18/Forge/build.gradle @@ -0,0 +1,28 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Puzzles Lib + api fg.deobf(libs.puzzleslib.forge.get()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } + versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +} + +task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { + onlyIf { project.hasProperty('keyStore') } + keyStore = project.findProperty('keyStore') + alias = project.findProperty('keyStoreAlias') + storePass = project.findProperty('keyStorePass') + keyPass = project.findProperty('keyStoreKeyPass') + inputFile = outputFile = tasks.jarJar.archivePath +} + +jar.finalizedBy 'signJar' +signJar.mustRunAfter 'reobfJar' diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java new file mode 100644 index 0000000..18d3c6f --- /dev/null +++ b/1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java @@ -0,0 +1,25 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.minecraft.data.DataGenerator; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; +import net.minecraftforge.forge.event.lifecycle.GatherDataEvent; + +@Mod(ExampleMod.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ExampleModForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(ExampleMod.MOD_ID, ExampleMod::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + final DataGenerator dataGenerator = evt.getGenerator(); + final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); + } +} diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java new file mode 100644 index 0000000..d6502ba --- /dev/null +++ b/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = ExampleMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ExampleModForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(ExampleMod.MOD_ID, ExampleModClient::new); + } +} diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..af281eb --- /dev/null +++ b/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.mixin; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.18/Forge/src/main/resources/META-INF/mods.toml b/1.18/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..e15b638 --- /dev/null +++ b/1.18/Forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,40 @@ +modLoader = "javafml" +loaderVersion = "[${minFMLVersion},)" +license = "${modLicense}" +issueTrackerURL = "${modIssueUrl}" + +[[mods]] +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" + +[[dependencies.${ modId }]] +modId = "forge" +mandatory = true +versionRange = "[${minForgeVersion},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.18/Forge/src/main/resources/examplemod.forge.mixins.json b/1.18/Forge/src/main/resources/examplemod.forge.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.18/Forge/src/main/resources/examplemod.forge.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.18/build.gradle b/1.18/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.18/build.gradle @@ -0,0 +1,12 @@ +plugins { + alias libs.plugins.loom apply false + alias libs.plugins.quiltflower apply false + alias libs.plugins.forgegradle apply false + alias libs.plugins.mixin apply false + alias libs.plugins.librarian apply false + alias libs.plugins.cursegradle apply false + alias libs.plugins.minotaur apply false +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/main.gradle' +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/tasks.gradle' diff --git a/1.18/gradle.properties b/1.18/gradle.properties new file mode 100755 index 0000000..ff013f2 --- /dev/null +++ b/1.18/gradle.properties @@ -0,0 +1,35 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +# This is required to provide enough memory for the Minecraft decompilation process. +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false +org.gradle.parallel=true +copyBuildJar=true + +# Mod Attributes +modId=examplemod +modName=Example Mod +modVersion=3.0.0 +modAuthor=Fuzs +modDescription=Example description. +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/examplemod +modIssueUrl=https://github.com/Fuzss/examplemod/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/examplemod.json +modMavenGroup=fuzs.examplemod +# "MATCH_VERSION" for a mod required on both sides, "IGNORE_SERVER_VERSION" for a server only mod, "IGNORE_ALL_VERSION" for a client only mod +modForgeDisplayTest=MATCH_VERSION +# "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod +modFabricEnvironment=* + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=0 +projectModrinthId=0 + +dependenciesVersionCatalog=1.18.2-v6 +dependenciesRequiredForgeCurseForge=puzzles-lib +dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredForgeModrinth=puzzles-lib +dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib +#dependenciesEmbeddedFabricCurseForge=cardinal-components +#dependenciesEmbeddedFabricModrinth=cardinal-components-api diff --git a/gradle/wrapper/gradle-wrapper.jar b/1.18/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from gradle/wrapper/gradle-wrapper.jar rename to 1.18/gradle/wrapper/gradle-wrapper.jar diff --git a/1.18/gradle/wrapper/gradle-wrapper.properties b/1.18/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..f398c33 --- /dev/null +++ b/1.18/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/gradlew b/1.18/gradlew similarity index 100% rename from gradlew rename to 1.18/gradlew diff --git a/gradlew.bat b/1.18/gradlew.bat similarity index 100% rename from gradlew.bat rename to 1.18/gradlew.bat diff --git a/settings.gradle b/1.18/settings.gradle similarity index 55% rename from settings.gradle rename to 1.18/settings.gradle index 18da063..697dd5f 100644 --- a/settings.gradle +++ b/1.18/settings.gradle @@ -20,5 +20,19 @@ pluginManagement { } } -rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}" +dependencyResolutionManagement { + repositories { + maven { + name = "Fuzs Mod Resources" + url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" + } + } + versionCatalogs { + libs { + from("fuzs.sharedcatalogs:sharedcatalogs:${dependenciesVersionCatalog}") + } + } +} + +rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}-${dependenciesVersionCatalog.replaceAll("-v\\d+", "")}" include("Common", "Fabric", "Forge") diff --git a/1.19/.idea/scopes/Fabric_sources.xml b/1.19/.idea/scopes/Fabric_sources.xml new file mode 100644 index 0000000..0448412 --- /dev/null +++ b/1.19/.idea/scopes/Fabric_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.19/.idea/scopes/Forge_sources.xml b/1.19/.idea/scopes/Forge_sources.xml new file mode 100644 index 0000000..7b5f24d --- /dev/null +++ b/1.19/.idea/scopes/Forge_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.19/CHANGELOG.md b/1.19/CHANGELOG.md new file mode 100644 index 0000000..61ac69e --- /dev/null +++ b/1.19/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog]. + +## [v4.0.0-1.19.2] - 2023-06-25 +- Ported to Minecraft 1.19.2 + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/1.19/Common/build.gradle b/1.19/Common/build.gradle new file mode 100644 index 0000000..949b426 --- /dev/null +++ b/1.19/Common/build.gradle @@ -0,0 +1,11 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common +} + +// @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).each { + it.targetNamespace = "named" +} diff --git a/1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java new file mode 100644 index 0000000..ea9aa8b --- /dev/null +++ b/1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java @@ -0,0 +1,16 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.core.ModConstructor; +import net.minecraft.resources.ResourceLocation; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class ExampleMod implements ModConstructor { + public static final String MOD_ID = "examplemod"; + public static final String MOD_NAME = "Example Mod"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } +} diff --git a/1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java new file mode 100644 index 0000000..d36b967 --- /dev/null +++ b/1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java @@ -0,0 +1,7 @@ +package fuzs.examplemod.client; + +import fuzs.puzzleslib.client.core.ClientModConstructor; + +public class ExampleModClient implements ClientModConstructor { + +} diff --git a/1.19/Common/src/main/resources/examplemod.common.mixins.json b/1.19/Common/src/main/resources/examplemod.common.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.19/Common/src/main/resources/examplemod.common.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.19/Common/src/main/resources/mod_banner.png b/1.19/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..bda5a0f63968a9c20cc144359547c6d8bb1e893b GIT binary patch literal 17858 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 literal 0 HcmV?d00001 diff --git a/1.19/Common/src/main/resources/mod_logo.png b/1.19/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..98c247e46e4c250202abe7f66209dd16464ade34 GIT binary patch literal 6537 zcmV;48FuE0P)pOk{gJ(ID36A2T30nlM=2{R95XH@ zkcd!;aY}b)I%ZimPCP6(G#ff(GBR5&wUkGQXE}FRH$hTtI%6(KbT?8@Ey0~buZcX9 zZ#F+rYe!i%Z%i#MRwg1m9i?wLhFLf@DjQ-%9!oVFDkd8n926BA4Qf9vB_kOj9Th7p zByyBakXk~IQ#CkPD_3YZOKB}+ol0$_RbP}yZgDnbi9}3%I&-2|ScybgcRE~?Lsg1C zW|&BBs!dXaJ!qv!YottdvQv4tR(`=*jKpknu2FojW^k-dcCu5|mM`uT=$>S9(5*#!e)5fT0hIkYt5(pOsJ5@*X^z)*|?WwJ+@$To9 zw9Tc-?XS=9M^{-lMpjN*YI~EY?eUTa{8J)xJd7_nnqN10Kb5?j(MQJw6=>IrQQ`pV59V{#9@$=c`>?A`Y zxvGlg=jOM@%q%!WRA*?$;rK36FqOUPZH#X%Ml`s(xJFJJG9jdFj9)z{aPm6K0zON4u8&%mC^=KmQR8WSWBEmJBcL>>JoQ%cg5Y^x4XOBarawwd(DJEQDnom^Xa^mP%s5Nc{{5orqkrV$Vc)onI_lZ zk+@7>R_~goWOBKAD9g#DsjGh()&$jn9B&PwBN=Lq0}q2R$zMQ)rp=;muCA_G2mA!# z$4}C_ySl3D#U?a|-k+6)uFV#hxwQczKYiwCrip>I9N?`c^!{wL>>8Api=f^uXeB`M zWugLQ%lYYEx;SoLT$X|UJZ+QBQH1`ySFP0>r99!MXqq0NX{tvb=w)n=HXj20>FmSi zWrVhN+8ri1*(jA+dY~JidvXt-_OBsyx%sKBVQRQ-q1x%R%}c>a?F<3#ek@e^sGJA8 zyoOs34$7ZW7r(dXFLYKIhT*=d+ZrVd(=mge%7zU zWg~~>UrL@=In+wNmOo<5t|m;G@wS<5GgqtCmV$OgbNXP=ESAexx9q}Wz7y!cl(|~9Ua#-iM-)v2cz^~P+g+Zbc%G(t3g*5a46C7a4?-_DK5X3b zV6uodFL)U<$8pfr;jr25Acx%%eVZ_3xD|@FTJa?-O;w1V42?qx7YQ<#nSZt7UNJnX1g-6FULfWu(!S*AKpT_>#uK|-d!F-g|8p$ zyBmb6KiHr!1Yp9?vOK0ORKbE5Q13Se~a?A~q(9VaSXc8cs~51A)Nzp3}+TCWoMJ8wYRjk{u3~ zO;HqZ8znbkM3*Z#-NG#X=wM@FSewB~30JOS*BeM@JZSXV$+GN%bM zbHI=lhs~jAr5I6R!375gyWQaT+QPcSv!1hO&w4yJg>zS@9tRBhHu~<`hJ2#jLWTB) z>Qb#6xI<4m91eIwVP_1BN5k{HvCIH_Qa5pg?77aAE~nE{rhs0~JwHKqjiVQBE?5u3 z8UUF!)fI&AJ4NY{${8XQ?K$AXkHg$7;UJ#-oD2!b%hNYi=Mla@E?_Z=Q+N?1g zR(I?WsH$jiSVYn3bo+cHjm!1LW8zF|{(f{K6xv%)Oih6cumo^o6BXv<6Beo7=D4aL z2s;kwscGSo)9nT`5{ZxlR;$JG9vU}Rg^AGK(>KEj>_XB~T#9G12+jTaKDmXI4s#_d zKt^W6B@s|xgoIf1SarE?0QRVAG_-dS;B*g;OYbrxX#By3+_&&J+FD_lE58f#g6avo zV?Njuk~UBp0Bl>1qxBbMiHyBUsj86Od$SIAkAN|1faB?O<~%AqaP=Q_uF5dyLecy4 z^XiP~BY6Wmpp4Sp=wR=%4$lItX7|>gCEleWaH#dhl9c%)haU7Db`f3Lu5nx_8jaq^ zjU(jYKzSUD;KxCDvKyZ`qc?`ai8zqhmLzyc|C3s=0DKBcP)Rh%C#1Z=evMtfDt2Nd%2!BolaJxDc!;7fWc*p)W;cfD#TQS- zN7koa6wJd8(&{V-a#3Unpzqy3+#-AYmMifOWis+>`y?s&`6YxD8-t;5_~<8+XD=;y z3!7_vJTOC1uFY>ZQ}gYfRnMX;dx_XL{`}qD-~REVEGm0X{I{EnGHTrk7cejL{2*A+ zEY9o&$s>`>ukaRLN{lsQd@n;~eMY}DS3P$~M=T$GclUP`b)OcJP08#$97Urr(H_<3!^ zL%WnIt9;>4^v$iv!1Od;|2}I5Dt7NuF%5#=RAHZebe_PY@xP|`#bJ2h;68uOvim@7#@=;Q!7r)qwh~e~w3NnGjFp>N1 zCBATYpIWUZuER%K-A{VGkas(2PhYz+y%oyOkHJ=dGVI!yo2$;fbH_FB85Lwe9&yEf zKWLV9TGcK->fCTRPpc_ovB(=?dR2>FCyq<{3AQt7Hd$he&u6tK!%I{mQo%t!yCH%( z4%>^>=oE$f9~3^=U#OHQ%FFfIiZYbEZJ+Yyy?C_a^!RdmBtlw^N4bv?!U2UfNKdudl%_zS;QU-eoY$pNIkzM)84u}0v_^t|@jj#=wwabrHe!sI!g zsXdqmKA3SR=iWbla8U9oT7VaERwu)LC(aA0_HfmKy1F;sXgX3Kg-a_mYb=YmvZr!? zVv#@dp3QG;Zf+*@gazYi?V1>_JyY9!o zLE4SgfLRO#gPUHJYRVPvj#1r_fKJ0~AQ))|yl4fRcRbxm;V8vq}3 z4=!T@`jS@U-A-)k^Tlx&Fg^t4`cvU6t+Dh|vhR0Yaz^K?zZa}vI*Bgz;tKaPC z?CRpW7p?xO2A&Sv!z;GulGjr+SxfPPO<&<4L{}Q<5u)$D7;G^~J#^Z1PwECE- zi@?-8?W)8P5`UT^jrq;Q#dymE=R~cpq-02RsLD!yjzw_WN*kilmm7+V^+%5$0ZVeM zn}^q3^g_q}1pF>wvcBXo<^Z>{FFm=kr;<)3I>YpkXh zOb?#M;hPcC=g`OiCJ=5?3@^^dGPFsjoYgYG$rDH$XuyY!$B!F%wxg`9Y-FgH>&JLBp8hLg5lku`A#`wZ zaxMiP^~N$Pejlg87&`2LHJTEQ2Bosw2#*dTVmP{`$>_r{fcsx*0vVO2f$e_O47jb$ zjx&<&C)tj>tOzE1D>nMPBJ8EXQ0t;r`?*-0ZFb^Dza*f-jl!J*d=rCDGz50O0z3*g z8!juVm{a*IK0eGOhD*5Y8cOG7!0IIUo9ThANT?t`20Meh!caloN1tVFb`jiXnVp@r zIKp9Dm|XrK_BJQE=j(**2E4P?^SC{n9w|V(Bm5c%2LUHb(IocQo?Hs`uFTm*&#`KD z7DJX}Sd9xH2PZ8n({MqC;iT?P#C^q;1iyd1?|O9fu}m|;pa7@M)jbO;3i&YT^Kl~B zg5eHuSUonT4y&YQvy@|Ie2mmYVADE|Oj8{G7wwrIm>!4#9vSGvkr_;d?=KETv$!yS z2Oo;A_`rv#QL1Z(tTOcbKA?@~SZV2%}E{KL>!u zSS^OhoNm`(qTv|pnfF|-%kS+|RT9`GhQk3|u>qdJclkm}Y4kg2l@ZaSb zHm3--jRg>;^1y)yg=1qem}3NZmt>PqIlf>8y=u~8Q}4VGfQu1?T%vydxs4OUfq+7x zkSI@_IH6Q311*5ffc?9|!noipsVFm%C0^*{_m(hO7x3;hZjBwEJI;t+$nEf8#JV5?0bfl1QSV=PidVdhog zAmEP9Y>U7n{1}t~IfxthOY)U>(U|cD7R-@CYm#D?$Ngh5kmXniX zr6|{vc&-k~DLKRVii}1B@7A2u>57c)^+=T*-xg1H4f*d^4xQAo+4NMUS#eu*ZS2_s z9GWbNxbdPxkqw64w+{6hj7EK_{;=Wn>380F z`!|q(G%NqF)?8xRIJ+=hdxz{`Br90dE>1EOjH6T@q=@1aVN_$(F;jaczKkzG9CHbj z%r2@_sjC)sQzWEzgVIG>{r{p(5Ie^^o32tyqCh1pgpCVrsH(`4WqE;>Mc*@?*q}g4 z2wC)zYy(Dq=3Hjxo8t+KEcaMmXmXj#2TjVKVI6Q|{?s72ETvnk?6f?5hysHyR5&Pl z{n(K|wBc&d9}I^>d?d>4rDt_NxOQA+L*a0MEm6Q~YwfQx*7aE3&g%@#ZEaA0T!lXs z(9MIi7qD#5+pZizx;onZLdX}3M}|j6M~KlYS4Kxi5;2L7#pCgaLY#*)1bpGEa>3#< zmS3huZ561_eoqClkXEClMGvIst}9#*&dpGMP}pTMCKTg#5_kc`;!1RI%{G zX^3%L=;%1pJvWyYRj(-ObnTZe!QB24I(uk{6{7*TA`n9q;Sm;oqhBfPeUN`Fd36CR z01KUo4=`{24@Z$(`VLsTy1O}Ujzy|{J|)?R_@WZ=d+&F2cRSLo7!JV<8HoGBQM4J= zdn}o(DTfI~J`!n=Zw@dxS{_XC|MKTIAok)g0YnOl>cyjO(xCr>KR7gWrmKtNFl(cj zLnH%ySQHgAl8mrx=DK%6USeEkYw^%KA}}E~p@#@vfI_OmLoEb@LurQtnK(~VJ}oPX zljs|skMW^NmL+qwos(p)Dpl{bDVY*&KxZ9de)3da*7(uT!XV%QQtb;N(@{}O+t1g5 z8M4VRq7DV3tTwHfu^p7~x>>Pb8(GHMk};vP4mbZHHwe?y(}Qho)6;PtPEn+Tq*iN( zHeW?GLk3$kI*I>qC<%y?Taw6J2W20ZSKJ=66`gfB*=4yTK}<-Yz$9yj4uh|~)T1Vy z$g-@~VMqL=CNoOCr_Ljhrx={NYP;}ZWnNz(^PnUN0`kk+S2MSrP7Ei&elM9R-GD_> z$g6147&S3=q~SY&eX3D|xPV zV=_TJ7spES13mU66!_)*_GJAhd18{n}`xnSKX?-?xn^$ig{5kX&q=}M}C!3U9B-S*?u#< z*zM?edU80@O6FBNNW>}67AIK&<_x_Sv-zwUkF(cXQw#D^W536uDHkDlHFdceL2rLLlTpgJLrz>QSuCV( zsR8df@`7Ho&1SOMY<-;u6zV23z?du9*<;*poZZ}fggQN5MSpYoogL(`8z7ghH7~<3 zG-FV_5SvUUTc2iyMven6i^-Zj=H2rtLv9({ezynee4b0QL7grb^bSGKwE~MmXRnHx z0Y4K#$jeTN}!1zCQ5w#o)$Ge`Oc;{VeXT8EUA8uBFynH$2S7i~+;KdHQ`2lMXKU6sB+r&p vxYMG>rZrVwd$ZEIeYUt&qc{uae};bm+U`)~9h?8j00000NkvXXu0mjfr5A3W literal 0 HcmV?d00001 diff --git a/1.19/Common/src/main/resources/pack.mcmeta b/1.19/Common/src/main/resources/pack.mcmeta new file mode 100755 index 0000000..19bfab2 --- /dev/null +++ b/1.19/Common/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "${modDescription}", + "pack_format": ${resourcePackFormat}, + "forge:resource_pack_format": ${resourcePackFormat}, + "forge:data_pack_format": ${dataPackFormat} + } +} diff --git a/1.19/Fabric/build.gradle b/1.19/Fabric/build.gradle new file mode 100644 index 0000000..cd8b641 --- /dev/null +++ b/1.19/Fabric/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // Puzzles Lib + modApi libs.puzzleslib.fabric + + // Cardinal Components +// modApi(include(libs.cardinalcomponentsbase.fabric.get())) +// modApi(include(libs.cardinalcomponentsentity.fabric.get())) +// modApi(include(libs.cardinalcomponentsblock.fabric.get())) +// modApi(include(libs.cardinalcomponentschunk.fabric.get())) +// modApi(include(libs.cardinalcomponentsworld.fabric.get())) + + // Extensible Enums +// modApi(include(libs.extensibleenums.fabric.get())) + + // Quality of Life Mods + versionCatalog.findLibrary("modmenu.fabric").ifPresent { + modLocalRuntime(it) + } + versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { + modLocalRuntime(it) + } +} diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java new file mode 100644 index 0000000..9c64526 --- /dev/null +++ b/1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java @@ -0,0 +1,12 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.core.CommonFactories; +import net.fabricmc.api.ModInitializer; + +public class ExampleModFabric implements ModInitializer { + + @Override + public void onInitialize() { + CommonFactories.INSTANCE.modConstructor(ExampleMod.MOD_ID).accept(new ExampleMod()); + } +} diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java new file mode 100644 index 0000000..a9677a6 --- /dev/null +++ b/1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java @@ -0,0 +1,13 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.client.core.ClientFactories; +import net.fabricmc.api.ClientModInitializer; + +public class ExampleModFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ClientFactories.INSTANCE.clientModConstructor(ExampleMod.MOD_ID).accept(new ExampleModClient()); + } +} diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..6d413e8 --- /dev/null +++ b/1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.mixin; + +import net.fabricmc.loader.api.FabricLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FabricLoader.getInstance().isModLoaded("puzzleslib"); + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.19/Fabric/src/main/resources/fabric.mod.json b/1.19/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..07fc00c --- /dev/null +++ b/1.19/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,45 @@ +{ + "schemaVersion": 1, + "id": "${modId}", + "version": "${modVersion}", + + "name": "${modName}", + "description": "${modDescription}", + + "authors": [ + "${modAuthor}" + ], + + "contact": { + "homepage": "${modPageUrl}", + "issues": "${modIssueUrl}", + "sources": "${modPageUrl}" + }, + + "license": "${modLicense}", + "icon": "mod_logo.png", + + "environment": "${modFabricEnvironment}", + + "entrypoints": { + "main": [ + "${mainEntryPoint}" + ], + "client": [ + "${clientEntryPoint}" + ] + }, + + "mixins": [ + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" + ], + + "depends": { + "fabricloader": ">=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.19/Forge/build.gradle b/1.19/Forge/build.gradle new file mode 100644 index 0000000..fc4b4de --- /dev/null +++ b/1.19/Forge/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Puzzles Lib + api fg.deobf(libs.puzzleslib.forge.get()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +// runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.get()}") + versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +} + +task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { + onlyIf { project.hasProperty('keyStore') } + keyStore = project.findProperty('keyStore') + alias = project.findProperty('keyStoreAlias') + storePass = project.findProperty('keyStorePass') + keyPass = project.findProperty('keyStoreKeyPass') + inputFile = outputFile = tasks.jarJar.archivePath +} + +jar.finalizedBy 'signJar' +signJar.mustRunAfter 'reobfJar' diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java new file mode 100644 index 0000000..ab8de0a --- /dev/null +++ b/1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java @@ -0,0 +1,25 @@ +package fuzs.examplemod; + +import fuzs.puzzleslib.core.CommonFactories; +import net.minecraft.data.DataGenerator; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(ExampleMod.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class ExampleModForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + CommonFactories.INSTANCE.modConstructor(ExampleMod.MOD_ID).accept(new ExampleMod()); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + final DataGenerator dataGenerator = evt.getGenerator(); + final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); + } +} diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java new file mode 100644 index 0000000..1abfe32 --- /dev/null +++ b/1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.examplemod.client; + +import fuzs.examplemod.ExampleMod; +import fuzs.puzzleslib.client.core.ClientFactories; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = ExampleMod.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class ExampleModForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientFactories.INSTANCE.clientModConstructor(ExampleMod.MOD_ID).accept(new ExampleModClient()); + } +} diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..af281eb --- /dev/null +++ b/1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.examplemod.mixin; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.19/Forge/src/main/resources/META-INF/mods.toml b/1.19/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..e15b638 --- /dev/null +++ b/1.19/Forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,40 @@ +modLoader = "javafml" +loaderVersion = "[${minFMLVersion},)" +license = "${modLicense}" +issueTrackerURL = "${modIssueUrl}" + +[[mods]] +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" + +[[dependencies.${ modId }]] +modId = "forge" +mandatory = true +versionRange = "[${minForgeVersion},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.19/Forge/src/main/resources/examplemod.forge.mixins.json b/1.19/Forge/src/main/resources/examplemod.forge.mixins.json new file mode 100644 index 0000000..ec8895e --- /dev/null +++ b/1.19/Forge/src/main/resources/examplemod.forge.mixins.json @@ -0,0 +1,15 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.examplemod.mixin", + "refmap": "examplemod.refmap.json", + "plugin": "fuzs.examplemod.mixin.ModMixinConfigPlugin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.19/build.gradle b/1.19/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.19/build.gradle @@ -0,0 +1,12 @@ +plugins { + alias libs.plugins.loom apply false + alias libs.plugins.quiltflower apply false + alias libs.plugins.forgegradle apply false + alias libs.plugins.mixin apply false + alias libs.plugins.librarian apply false + alias libs.plugins.cursegradle apply false + alias libs.plugins.minotaur apply false +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/main.gradle' +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/tasks.gradle' diff --git a/1.19/gradle.properties b/1.19/gradle.properties new file mode 100755 index 0000000..b41f3a6 --- /dev/null +++ b/1.19/gradle.properties @@ -0,0 +1,35 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +# This is required to provide enough memory for the Minecraft decompilation process. +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false +org.gradle.parallel=true +copyBuildJar=true + +# Mod Attributes +modId=examplemod +modName=Example Mod +modVersion=4.0.0 +modAuthor=Fuzs +modDescription=Example description. +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/examplemod +modIssueUrl=https://github.com/Fuzss/examplemod/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/examplemod.json +modMavenGroup=fuzs.examplemod +# "MATCH_VERSION" for a mod required on both sides, "IGNORE_SERVER_VERSION" for a server only mod, "IGNORE_ALL_VERSION" for a client only mod +modForgeDisplayTest=MATCH_VERSION +# "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod +modFabricEnvironment=* + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=0 +projectModrinthId=0 + +dependenciesVersionCatalog=1.19.2-v6 +dependenciesRequiredForgeCurseForge=puzzles-lib +dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredForgeModrinth=puzzles-lib +dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib +#dependenciesEmbeddedFabricCurseForge=cardinal-components +#dependenciesEmbeddedFabricModrinth=cardinal-components-api diff --git a/1.19/gradle/wrapper/gradle-wrapper.jar b/1.19/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/1.19/gradle/wrapper/gradle-wrapper.properties b/1.19/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..f398c33 --- /dev/null +++ b/1.19/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-7.6-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/1.19/gradlew b/1.19/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.19/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/1.19/gradlew.bat b/1.19/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.19/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/1.19/settings.gradle b/1.19/settings.gradle new file mode 100644 index 0000000..697dd5f --- /dev/null +++ b/1.19/settings.gradle @@ -0,0 +1,38 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + name = 'Sponge' + url = 'https://repo.spongepowered.org/repository/maven-public/' + } + maven { + name = 'Quilt' + url = 'https://maven.quiltmc.org/repository/release' + } + maven { + name = 'Minecraft Forge' + url = 'https://maven.minecraftforge.net/' + } + } +} + +dependencyResolutionManagement { + repositories { + maven { + name = "Fuzs Mod Resources" + url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" + } + } + versionCatalogs { + libs { + from("fuzs.sharedcatalogs:sharedcatalogs:${dependenciesVersionCatalog}") + } + } +} + +rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}-${dependenciesVersionCatalog.replaceAll("-v\\d+", "")}" +include("Common", "Fabric", "Forge") diff --git a/1.20/.idea/scopes/Fabric_sources.xml b/1.20/.idea/scopes/Fabric_sources.xml new file mode 100644 index 0000000..0448412 --- /dev/null +++ b/1.20/.idea/scopes/Fabric_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.20/.idea/scopes/Forge_sources.xml b/1.20/.idea/scopes/Forge_sources.xml new file mode 100644 index 0000000..7b5f24d --- /dev/null +++ b/1.20/.idea/scopes/Forge_sources.xml @@ -0,0 +1,3 @@ + + + \ No newline at end of file diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md new file mode 100644 index 0000000..c7f9a93 --- /dev/null +++ b/1.20/CHANGELOG.md @@ -0,0 +1,9 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog]. + +## [v8.0.0-1.20.1] - 2023-06-27 +- Ported to Minecraft 1.20.1 + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/1.20/Common/build.gradle b/1.20/Common/build.gradle new file mode 100644 index 0000000..949b426 --- /dev/null +++ b/1.20/Common/build.gradle @@ -0,0 +1,11 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common +} + +// @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).each { + it.targetNamespace = "named" +} diff --git a/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/1.20/Common/src/main/java/fuzs/tradingpost/TradingPost.java similarity index 82% rename from Common/src/main/java/fuzs/tradingpost/TradingPost.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/TradingPost.java index 19139c2..333c896 100644 --- a/Common/src/main/java/fuzs/tradingpost/TradingPost.java +++ b/1.20/Common/src/main/java/fuzs/tradingpost/TradingPost.java @@ -2,6 +2,7 @@ import fuzs.puzzleslib.api.config.v3.ConfigHolder; import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.core.v1.context.BuildCreativeModeTabContentsContext; import fuzs.puzzleslib.api.core.v1.context.FuelBurnTimesContext; import fuzs.puzzleslib.api.network.v2.MessageDirection; import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; @@ -12,6 +13,7 @@ import fuzs.tradingpost.network.S2CRemoveMerchantsMessage; import fuzs.tradingpost.network.client.C2SClearSlotsMessage; import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTabs; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -36,6 +38,13 @@ private static void registerMessages() { NETWORK.register(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new, MessageDirection.TO_SERVER); } + @Override + public void onBuildCreativeModeTabContents(BuildCreativeModeTabContentsContext context) { + context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (itemDisplayParameters, output) -> { + output.accept(ModRegistry.TRADING_POST_ITEM.get()); + }); + } + @Override public void onRegisterFuelBurnTimes(FuelBurnTimesContext context) { context.registerFuel(300, ModRegistry.TRADING_POST_BLOCK.get()); diff --git a/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/1.20/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java similarity index 83% rename from Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java index 29883e8..5c4c211 100644 --- a/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java +++ b/1.20/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -2,7 +2,6 @@ import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; -import fuzs.puzzleslib.api.client.core.v1.context.BuildCreativeModeTabContentsContext; import fuzs.puzzleslib.api.client.core.v1.context.SearchRegistryContext; import fuzs.puzzleslib.api.core.v1.context.ModLifecycleContext; import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; @@ -12,7 +11,6 @@ import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.searchtree.FullTextSearchTree; import net.minecraft.core.registries.BuiltInRegistries; -import net.minecraft.world.item.CreativeModeTabs; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; @@ -45,11 +43,4 @@ public void onRegisterSearchTrees(SearchRegistryContext context) { base )); } - - @Override - public void onBuildCreativeModeTabContents(BuildCreativeModeTabContentsContext context) { - context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (itemDisplayParameters, output) -> { - output.accept(ModRegistry.TRADING_POST_ITEM.get()); - }); - } } diff --git a/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.20/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java diff --git a/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/1.20/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java diff --git a/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java b/1.20/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java diff --git a/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/1.20/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java b/1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java b/1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java b/1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java b/1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java diff --git a/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java b/1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java diff --git a/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java b/1.20/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java diff --git a/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java b/1.20/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java diff --git a/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java b/1.20/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java diff --git a/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java b/1.20/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java diff --git a/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java b/1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java diff --git a/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java b/1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java diff --git a/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java b/1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java diff --git a/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java diff --git a/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java b/1.20/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java diff --git a/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java b/1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java diff --git a/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java similarity index 100% rename from Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java rename to 1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java diff --git a/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json b/1.20/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json similarity index 100% rename from Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json rename to 1.20/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json diff --git a/Common/src/main/resources/assets/tradingpost/lang/en_us.json b/1.20/Common/src/main/resources/assets/tradingpost/lang/en_us.json similarity index 100% rename from Common/src/main/resources/assets/tradingpost/lang/en_us.json rename to 1.20/Common/src/main/resources/assets/tradingpost/lang/en_us.json diff --git a/Common/src/main/resources/assets/tradingpost/lang/it_it.json b/1.20/Common/src/main/resources/assets/tradingpost/lang/it_it.json similarity index 100% rename from Common/src/main/resources/assets/tradingpost/lang/it_it.json rename to 1.20/Common/src/main/resources/assets/tradingpost/lang/it_it.json diff --git a/Common/src/main/resources/assets/tradingpost/lang/pt_br.json b/1.20/Common/src/main/resources/assets/tradingpost/lang/pt_br.json similarity index 98% rename from Common/src/main/resources/assets/tradingpost/lang/pt_br.json rename to 1.20/Common/src/main/resources/assets/tradingpost/lang/pt_br.json index b611839..e84791f 100644 --- a/Common/src/main/resources/assets/tradingpost/lang/pt_br.json +++ b/1.20/Common/src/main/resources/assets/tradingpost/lang/pt_br.json @@ -1,7 +1,7 @@ -{ - "block.tradingpost.trading_post": "Posto de Comércio", - "container.trading_post": "Posto de Comércio", - "trading_post.no_trader_found": "Não foi possível encontrar nenhum comerciante disponível nas proximidades", - "trading_post.trader_gone": "O comerciante não está mais disponível.", - "trading_post.search": "Procurar..." +{ + "block.tradingpost.trading_post": "Posto de Comércio", + "container.trading_post": "Posto de Comércio", + "trading_post.no_trader_found": "Não foi possível encontrar nenhum comerciante disponível nas proximidades", + "trading_post.trader_gone": "O comerciante não está mais disponível.", + "trading_post.search": "Procurar..." } \ No newline at end of file diff --git a/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json b/1.20/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json similarity index 100% rename from Common/src/main/resources/assets/tradingpost/lang/ru_ru.json rename to 1.20/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json diff --git a/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json b/1.20/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json similarity index 100% rename from Common/src/main/resources/assets/tradingpost/lang/zh_tw.json rename to 1.20/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json diff --git a/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json b/1.20/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json similarity index 100% rename from Common/src/main/resources/assets/tradingpost/models/block/trading_post.json rename to 1.20/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json diff --git a/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json b/1.20/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json similarity index 100% rename from Common/src/main/resources/assets/tradingpost/models/item/trading_post.json rename to 1.20/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json diff --git a/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png b/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png similarity index 100% rename from Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png rename to 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png diff --git a/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png b/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png similarity index 100% rename from Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png rename to 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png diff --git a/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png b/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png similarity index 100% rename from Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png rename to 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png diff --git a/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png b/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png similarity index 100% rename from Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png rename to 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png diff --git a/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png b/1.20/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png similarity index 100% rename from Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png rename to 1.20/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png diff --git a/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json b/1.20/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json similarity index 100% rename from Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json rename to 1.20/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json diff --git a/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json b/1.20/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json similarity index 100% rename from Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json rename to 1.20/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json diff --git a/Common/src/main/resources/data/tradingpost/recipes/trading_post.json b/1.20/Common/src/main/resources/data/tradingpost/recipes/trading_post.json similarity index 100% rename from Common/src/main/resources/data/tradingpost/recipes/trading_post.json rename to 1.20/Common/src/main/resources/data/tradingpost/recipes/trading_post.json diff --git a/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json b/1.20/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json similarity index 100% rename from Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json rename to 1.20/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json diff --git a/Common/src/main/resources/mod_banner.png b/1.20/Common/src/main/resources/mod_banner.png similarity index 100% rename from Common/src/main/resources/mod_banner.png rename to 1.20/Common/src/main/resources/mod_banner.png diff --git a/Common/src/main/resources/mod_logo.png b/1.20/Common/src/main/resources/mod_logo.png similarity index 100% rename from Common/src/main/resources/mod_logo.png rename to 1.20/Common/src/main/resources/mod_logo.png diff --git a/1.20/Common/src/main/resources/pack.mcmeta b/1.20/Common/src/main/resources/pack.mcmeta new file mode 100755 index 0000000..19bfab2 --- /dev/null +++ b/1.20/Common/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "${modDescription}", + "pack_format": ${resourcePackFormat}, + "forge:resource_pack_format": ${resourcePackFormat}, + "forge:data_pack_format": ${dataPackFormat} + } +} diff --git a/Common/src/main/resources/tradingpost.common.mixins.json b/1.20/Common/src/main/resources/tradingpost.common.mixins.json similarity index 100% rename from Common/src/main/resources/tradingpost.common.mixins.json rename to 1.20/Common/src/main/resources/tradingpost.common.mixins.json diff --git a/1.20/Fabric/build.gradle b/1.20/Fabric/build.gradle new file mode 100644 index 0000000..cd8b641 --- /dev/null +++ b/1.20/Fabric/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // Puzzles Lib + modApi libs.puzzleslib.fabric + + // Cardinal Components +// modApi(include(libs.cardinalcomponentsbase.fabric.get())) +// modApi(include(libs.cardinalcomponentsentity.fabric.get())) +// modApi(include(libs.cardinalcomponentsblock.fabric.get())) +// modApi(include(libs.cardinalcomponentschunk.fabric.get())) +// modApi(include(libs.cardinalcomponentsworld.fabric.get())) + + // Extensible Enums +// modApi(include(libs.extensibleenums.fabric.get())) + + // Quality of Life Mods + versionCatalog.findLibrary("modmenu.fabric").ifPresent { + modLocalRuntime(it) + } + versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { + modLocalRuntime(it) + } +} diff --git a/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java b/1.20/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java similarity index 100% rename from Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java rename to 1.20/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java diff --git a/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java b/1.20/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java similarity index 100% rename from Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java rename to 1.20/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java diff --git a/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java b/1.20/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java similarity index 100% rename from Fabric/src/main/java/mixin/ModMixinConfigPlugin.java rename to 1.20/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java diff --git a/Fabric/src/main/resources/fabric.mod.json b/1.20/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from Fabric/src/main/resources/fabric.mod.json rename to 1.20/Fabric/src/main/resources/fabric.mod.json diff --git a/1.20/Forge/build.gradle b/1.20/Forge/build.gradle new file mode 100644 index 0000000..dec494a --- /dev/null +++ b/1.20/Forge/build.gradle @@ -0,0 +1,28 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Puzzles Lib + api fg.deobf(libs.puzzleslib.forge.get()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } + versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +} + +task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { + onlyIf { project.hasProperty('keyStore') } + keyStore = project.findProperty('keyStore') + alias = project.findProperty('keyStoreAlias') + storePass = project.findProperty('keyStorePass') + keyPass = project.findProperty('keyStoreKeyPass') + inputFile = outputFile = tasks.jarJar.archivePath +} + +jar.finalizedBy 'signJar' +signJar.mustRunAfter 'reobfJar' diff --git a/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 b/1.20/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 similarity index 60% rename from Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 rename to 1.20/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 index f6123e9..26e7e09 100644 --- a/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 +++ b/1.20/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 @@ -1,2 +1,2 @@ -// 1.20 2023-06-11T15:28:40.244103 Sprite Sources +// 1.20.1 2023-06-28T11:09:24.480978 Sprite Sources 84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json b/1.20/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json similarity index 100% rename from Forge/src/generated/resources/assets/minecraft/atlases/blocks.json rename to 1.20/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json diff --git a/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/1.20/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java similarity index 100% rename from Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java rename to 1.20/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java diff --git a/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java b/1.20/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java similarity index 100% rename from Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java rename to 1.20/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java diff --git a/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/1.20/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java similarity index 100% rename from Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java rename to 1.20/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java diff --git a/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java similarity index 100% rename from Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java rename to 1.20/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java diff --git a/Forge/src/main/resources/META-INF/mods.toml b/1.20/Forge/src/main/resources/META-INF/mods.toml similarity index 100% rename from Forge/src/main/resources/META-INF/mods.toml rename to 1.20/Forge/src/main/resources/META-INF/mods.toml diff --git a/1.20/build.gradle b/1.20/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.20/build.gradle @@ -0,0 +1,12 @@ +plugins { + alias libs.plugins.loom apply false + alias libs.plugins.quiltflower apply false + alias libs.plugins.forgegradle apply false + alias libs.plugins.mixin apply false + alias libs.plugins.librarian apply false + alias libs.plugins.cursegradle apply false + alias libs.plugins.minotaur apply false +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/main.gradle' +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/tasks.gradle' diff --git a/gradle.properties b/1.20/gradle.properties similarity index 69% rename from gradle.properties rename to 1.20/gradle.properties index 5ce5c46..1828641 100755 --- a/gradle.properties +++ b/1.20/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=7.0.0 +modVersion=8.0.0 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modLicense=MPL-2.0 @@ -23,6 +23,13 @@ modFabricEnvironment=* # Mod Publishing projectReleaseType=release -projectGameVersions=1.20 -projectCurseId=539057 +projectCurseForgeId=539057 projectModrinthId=8pcjMDgj + +dependenciesVersionCatalog=1.20.1-v5 +dependenciesRequiredForgeCurseForge=puzzles-lib +dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredForgeModrinth=puzzles-lib +dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib +#dependenciesEmbeddedFabricCurseForge=cardinal-components +#dependenciesEmbeddedFabricModrinth=cardinal-components-api diff --git a/1.20/gradle/wrapper/gradle-wrapper.jar b/1.20/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 zcmb6AV{~QRwml9f72CFLyJFk6ZKq;e729@pY}>YNR8p1vbMJH7ubt# zZR`2@zJD1Ad^Oa6Hk1{VlN1wGR-u;_dyt)+kddaNpM#U8qn@6eX;fldWZ6BspQIa= zoRXcQk)#ENJ`XiXJuK3q0$`Ap92QXrW00Yv7NOrc-8ljOOOIcj{J&cR{W`aIGXJ-` z`ez%Mf7qBi8JgIb{-35Oe>Zh^GIVe-b^5nULQhxRDZa)^4+98@`hUJe{J%R>|LYHA z4K3~Hjcp8_owGF{d~lZVKJ;kc48^OQ+`_2migWY?JqgW&))70RgSB6KY9+&wm<*8 z_{<;(c;5H|u}3{Y>y_<0Z59a)MIGK7wRMX0Nvo>feeJs+U?bt-++E8bu7 zh#_cwz0(4#RaT@xy14c7d<92q-Dd}Dt<*RS+$r0a^=LGCM{ny?rMFjhgxIG4>Hc~r zC$L?-FW0FZ((8@dsowXlQq}ja%DM{z&0kia*w7B*PQ`gLvPGS7M}$T&EPl8mew3In z0U$u}+bk?Vei{E$6dAYI8Tsze6A5wah?d(+fyP_5t4ytRXNktK&*JB!hRl07G62m_ zAt1nj(37{1p~L|m(Bsz3vE*usD`78QTgYIk zQ6BF14KLzsJTCqx&E!h>XP4)bya|{*G7&T$^hR0(bOWjUs2p0uw7xEjbz1FNSBCDb@^NIA z$qaq^0it^(#pFEmuGVS4&-r4(7HLmtT%_~Xhr-k8yp0`$N|y>#$Ao#zibzGi*UKzi zhaV#@e1{2@1Vn2iq}4J{1-ox;7K(-;Sk{3G2_EtV-D<)^Pk-G<6-vP{W}Yd>GLL zuOVrmN@KlD4f5sVMTs7c{ATcIGrv4@2umVI$r!xI8a?GN(R;?32n0NS(g@B8S00-=zzLn z%^Agl9eV(q&8UrK^~&$}{S(6-nEXnI8%|hoQ47P?I0Kd=woZ-pH==;jEg+QOfMSq~ zOu>&DkHsc{?o&M5`jyJBWbfoPBv9Y#70qvoHbZXOj*qRM(CQV=uX5KN+b>SQf-~a8 ziZg}@&XHHXkAUqr)Q{y`jNd7`1F8nm6}n}+_She>KO`VNlnu(&??!(i#$mKOpWpi1 z#WfWxi3L)bNRodhPM~~?!5{TrrBY_+nD?CIUupkwAPGz-P;QYc-DcUoCe`w(7)}|S zRvN)9ru8b)MoullmASwsgKQo1U6nsVAvo8iKnbaWydto4y?#-|kP^%e6m@L`88KyDrLH`=EDx*6>?r5~7Iv~I zr__%SximG(izLKSnbTlXa-ksH@R6rvBrBavt4)>o3$dgztLt4W=!3=O(*w7I+pHY2(P0QbTma+g#dXoD7N#?FaXNQ^I0*;jzvjM}%=+km`YtC%O#Alm| zqgORKSqk!#^~6whtLQASqiJ7*nq?38OJ3$u=Tp%Y`x^eYJtOqTzVkJ60b2t>TzdQ{I}!lEBxm}JSy7sy8DpDb zIqdT%PKf&Zy--T^c-;%mbDCxLrMWTVLW}c=DP2>Td74)-mLl|70)8hU??(2)I@Zyo z2i`q5oyA!!(2xV~gahuKl&L(@_3SP012#x(7P!1}6vNFFK5f*A1xF({JwxSFwA|TM z&1z}!*mZKcUA-v4QzLz&5wS$7=5{M@RAlx@RkJaA4nWVqsuuaW(eDh^LNPPkmM~Al zwxCe@*-^4!ky#iNv2NIIU$CS+UW%ziW0q@6HN3{eCYOUe;2P)C*M`Bt{~-mC%T3%# zEaf)lATO1;uF33x>Hr~YD0Ju*Syi!Jz+x3myVvU^-O>C*lFCKS&=Tuz@>&o?68aF& zBv<^ziPywPu#;WSlTkzdZ9`GWe7D8h<1-v0M*R@oYgS5jlPbgHcx)n2*+!+VcGlYh?;9Ngkg% z=MPD+`pXryN1T|%I7c?ZPLb3bqWr7 zU4bfG1y+?!bw)5Iq#8IqWN@G=Ru%Thxf)#=yL>^wZXSCC8we@>$hu=yrU;2=7>h;5 zvj_pYgKg2lKvNggl1ALnsz2IlcvL;q79buN5T3IhXuJvy@^crqWpB-5NOm{7UVfxmPJ>`?;Tn@qHzF+W!5W{8Z&ZAnDOquw6r4$bv*jM#5lc%3v|c~^ zdqo4LuxzkKhK4Q+JTK8tR_|i6O(x#N2N0Fy5)!_trK&cn9odQu#Vlh1K~7q|rE z61#!ZPZ+G&Y7hqmY;`{XeDbQexC2@oFWY)Nzg@lL3GeEVRxWQlx@0?Zt`PcP0iq@6 zLgc)p&s$;*K_;q0L(mQ8mKqOJSrq$aQYO-Hbssf3P=wC6CvTVHudzJH-Jgm&foBSy zx0=qu$w477lIHk);XhaUR!R-tQOZ;tjLXFH6;%0)8^IAc*MO>Q;J={We(0OHaogG0 zE_C@bXic&m?F7slFAB~x|n#>a^@u8lu;=!sqE*?vq zu4`(x!Jb4F#&3+jQ|ygldPjyYn#uCjNWR)%M3(L!?3C`miKT;~iv_)dll>Q6b+I&c zrlB04k&>mSYLR7-k{Od+lARt~3}Bv!LWY4>igJl!L5@;V21H6dNHIGr+qV551e@yL z`*SdKGPE^yF?FJ|`#L)RQ?LJ;8+={+|Cl<$*ZF@j^?$H%V;jqVqt#2B0yVr}Nry5R z5D?S9n+qB_yEqvdy9nFc+8WxK$XME$3ftSceLb+L(_id5MMc*hSrC;E1SaZYow%jh zPgo#1PKjE+1QB`Of|aNmX?}3TP;y6~0iN}TKi3b+yvGk;)X&i3mTnf9M zuv3qvhErosfZ%Pb-Q>|BEm5(j-RV6Zf^$icM=sC-5^6MnAvcE9xzH@FwnDeG0YU{J zi~Fq?=bi0;Ir=hfOJu8PxC)qjYW~cv^+74Hs#GmU%Cw6?3LUUHh|Yab`spoqh8F@_ zm4bCyiXPx-Cp4!JpI~w!ShPfJOXsy>f*|$@P8L8(oeh#~w z-2a4IOeckn6}_TQ+rgl_gLArS3|Ml(i<`*Lqv6rWh$(Z5ycTYD#Z*&-5mpa}a_zHt z6E`Ty-^L9RK-M*mN5AasoBhc|XWZ7=YRQSvG)3$v zgr&U_X`Ny0)IOZtX}e$wNUzTpD%iF7Rgf?nWoG2J@PsS-qK4OD!kJ?UfO+1|F*|Bo z1KU`qDA^;$0*4mUJ#{EPOm7)t#EdX=Yx1R2T&xlzzThfRC7eq@pX&%MO&2AZVO%zw zS;A{HtJiL=rfXDigS=NcWL-s>Rbv|=)7eDoOVnVI>DI_8x>{E>msC$kXsS}z?R6*x zi(yO`$WN)_F1$=18cbA^5|f`pZA+9DG_Zu8uW?rA9IxUXx^QCAp3Gk1MSdq zBZv;_$W>*-zLL)F>Vn`}ti1k!%6{Q=g!g1J*`KONL#)M{ZC*%QzsNRaL|uJcGB7jD zTbUe%T(_x`UtlM!Ntp&-qu!v|mPZGcJw$mdnanY3Uo>5{oiFOjDr!ZznKz}iWT#x& z?*#;H$`M0VC|a~1u_<(}WD>ogx(EvF6A6S8l0%9U<( zH||OBbh8Tnzz*#bV8&$d#AZNF$xF9F2{_B`^(zWNC}af(V~J+EZAbeC2%hjKz3V1C zj#%d%Gf(uyQ@0Y6CcP^CWkq`n+YR^W0`_qkDw333O<0FoO9()vP^!tZ{`0zsNQx~E zb&BcBU>GTP2svE2Tmd;~73mj!_*V8uL?ZLbx}{^l9+yvR5fas+w&0EpA?_g?i9@A$j*?LnmctPDQG|zJ`=EF}Vx8aMD^LrtMvpNIR*|RHA`ctK*sbG= zjN7Q)(|dGpC}$+nt~bupuKSyaiU}Ws{?Tha@$q}cJ;tvH>+MuPih+B4d$Zbq9$Y*U z)iA(-dK?Ov@uCDq48Zm%%t5uw1GrnxDm7*ITGCEF!2UjA`BqPRiUR`yNq^zz|A3wU zG(8DAnY-GW+PR2&7@In{Sla(XnMz5Rk^*5u4UvCiDQs@hvZXoiziv{6*i?fihVI|( zPrY8SOcOIh9-AzyJ*wF4hq%ojB&Abrf;4kX@^-p$mmhr}xxn#fVU?ydmD=21&S)s*v*^3E96(K1}J$6bi8pyUr-IU)p zcwa$&EAF$0Aj?4OYPcOwb-#qB=kCEDIV8%^0oa567_u6`9+XRhKaBup z2gwj*m#(}=5m24fBB#9cC?A$4CCBj7kanaYM&v754(b%Vl!gg&N)ZN_gO0mv(jM0# z>FC|FHi=FGlEt6Hk6H3!Yc|7+q{&t%(>3n#>#yx@*aS+bw)(2!WK#M0AUD~wID>yG z?&{p66jLvP1;!T7^^*_9F322wJB*O%TY2oek=sA%AUQT75VQ_iY9`H;ZNKFQELpZd z$~M`wm^Y>lZ8+F0_WCJ0T2td`bM+b`)h3YOV%&@o{C#|t&7haQfq#uJJP;81|2e+$ z|K#e~YTE87s+e0zCE2X$df`o$`8tQhmO?nqO?lOuTJ%GDv&-m_kP9X<5GCo1=?+LY z?!O^AUrRb~3F!k=H7Aae5W0V1{KlgH379eAPTwq=2+MlNcJ6NM+4ztXFTwI)g+)&Q7G4H%KH_(}1rq%+eIJ*3$?WwnZxPZ;EC=@`QS@|-I zyl+NYh&G>k%}GL}1;ap8buvF>x^yfR*d+4Vkg7S!aQ++_oNx6hLz6kKWi>pjWGO5k zlUZ45MbA=v(xf>Oeqhg8ctl56y{;uDG?A9Ga5aEzZB80BW6vo2Bz&O-}WAq>(PaV;*SX0=xXgI_SJ< zYR&5HyeY%IW}I>yKu^?W2$~S!pw?)wd4(#6;V|dVoa}13Oiz5Hs6zA zgICc;aoUt$>AjDmr0nCzeCReTuvdD1{NzD1wr*q@QqVW*Wi1zn;Yw1dSwLvTUwg#7 zpp~Czra7U~nSZZTjieZxiu~=}!xgV68(!UmQz@#w9#$0Vf@y%!{uN~w^~U_d_Aa&r zt2l>)H8-+gA;3xBk?ZV2Cq!L71;-tb%7A0FWziYwMT|#s_Ze_B>orZQWqDOZuT{|@ zX04D%y&8u@>bur&*<2??1KnaA7M%%gXV@C3YjipS4|cQH68OSYxC`P#ncvtB%gnEI z%fxRuH=d{L70?vHMi>~_lhJ@MC^u#H66=tx?8{HG;G2j$9@}ZDYUuTetwpvuqy}vW)kDmj^a|A%z(xs7yY2mU0#X2$un&MCirr|7 z%m?8+9aekm0x5hvBQ2J+>XeAdel$cy>J<6R3}*O^j{ObSk_Ucv$8a3_WPTd5I4HRT z(PKP5!{l*{lk_19@&{5C>TRV8_D~v*StN~Pm*(qRP+`1N12y{#w_fsXrtSt={0hJw zQ(PyWgA;;tBBDql#^2J(pnuv;fPn(H>^d<6BlI%00ylJZ?Evkh%=j2n+|VqTM~EUh zTx|IY)W;3{%x(O{X|$PS&x0?z#S2q-kW&G}7#D?p7!Q4V&NtA_DbF~v?cz6_l+t8e zoh1`dk;P-%$m(Ud?wnoZn0R=Ka$`tnZ|yQ-FN!?!9Wmb^b(R!s#b)oj9hs3$p%XX9DgQcZJE7B_dz0OEF6C zx|%jlqj0WG5K4`cVw!19doNY+(;SrR_txAlXxf#C`uz5H6#0D>SzG*t9!Fn|^8Z8; z1w$uiQzufUzvPCHXhGma>+O327SitsB1?Rn6|^F198AOx}! zfXg22Lm0x%=gRvXXx%WU2&R!p_{_1H^R`+fRO2LT%;He@yiekCz3%coJ=8+Xbc$mN zJ;J7*ED|yKWDK3CrD?v#VFj|l-cTgtn&lL`@;sMYaM1;d)VUHa1KSB5(I54sBErYp z>~4Jz41?Vt{`o7T`j=Se{-kgJBJG^MTJ}hT00H%U)pY-dy!M|6$v+-d(CkZH5wmo1 zc2RaU`p3_IJ^hf{g&c|^;)k3zXC0kF1>rUljSxd}Af$!@@R1fJWa4g5vF?S?8rg=Z z4_I!$dap>3l+o|fyYy(sX}f@Br4~%&&#Z~bEca!nMKV zgQSCVC!zw^j<61!7#T!RxC6KdoMNONcM5^Q;<#~K!Q?-#6SE16F*dZ;qv=`5 z(kF|n!QIVd*6BqRR8b8H>d~N@ab+1+{3dDVPVAo>{mAB#m&jX{usKkCg^a9Fef`tR z?M79j7hH*;iC$XM)#IVm&tUoDv!(#f=XsTA$)(ZE37!iu3Gkih5~^Vlx#<(M25gr@ zOkSw4{l}6xI(b0Gy#ywglot$GnF)P<FQt~9ge1>qp8Q^k;_Dm1X@Tc^{CwYb4v_ld}k5I$&u}avIDQ-D(_EP zhgdc{)5r_iTFiZ;Q)5Uq=U73lW%uYN=JLo#OS;B0B=;j>APk?|!t{f3grv0nv}Z%` zM%XJk^#R69iNm&*^0SV0s9&>cl1BroIw*t3R0()^ldAsq)kWcI=>~4!6fM#0!K%TS ziZH=H%7-f=#-2G_XmF$~Wl~Um%^9%AeNSk)*`RDl##y+s)$V`oDlnK@{y+#LNUJp1^(e89sed@BB z^W)sHm;A^9*RgQ;f(~MHK~bJRvzezWGr#@jYAlXIrCk_iiUfC_FBWyvKj2mBF=FI;9|?0_~=E<)qnjLg9k*Qd!_ zl}VuSJB%#M>`iZm*1U^SP1}rkkI};91IRpZw%Hb$tKmr6&H5~m?A7?+uFOSnf)j14 zJCYLOYdaRu>zO%5d+VeXa-Ai7{7Z}iTn%yyz7hsmo7E|{ z@+g9cBcI-MT~2f@WrY0dpaC=v{*lDPBDX}OXtJ|niu$xyit;tyX5N&3pgmCxq>7TP zcOb9%(TyvOSxtw%Y2+O&jg39&YuOtgzn`uk{INC}^Na_-V;63b#+*@NOBnU{lG5TS zbC+N-qt)u26lggGPcdrTn@m+m>bcrh?sG4b(BrtdIKq3W<%?WuQtEW0Z)#?c_Lzqj*DlZ zVUpEV3~mG#DN$I#JJp3xc8`9ex)1%Il7xKwrpJt)qtpq}DXqI=5~~N}N?0g*YwETZ z(NKJO5kzh?Os`BQ7HYaTl>sXVr!b8>(Wd&PU*3ivSn{;q`|@n*J~-3tbm;4WK>j3&}AEZ*`_!gJ3F4w~4{{PyLZklDqWo|X}D zbZU_{2E6^VTCg#+6yJt{QUhu}uMITs@sRwH0z5OqM>taO^(_+w1c ztQ?gvVPj<_F_=(ISaB~qML59HT;#c9x(;0vkCi2#Zp`;_r@+8QOV1Ey2RWm6{*J&9 zG(Dt$zF^7qYpo9Ne}ce5re^j|rvDo*DQ&1Be#Fvo#?m4mfFrNZb1#D4f`Lf(t_Fib zwxL3lx(Zp(XVRjo_ocElY#yS$LHb6yl;9;Ycm1|5y_praEcGUZxLhS%7?b&es2skI z9l!O)b%D=cXBa@v9;64f^Q9IV$xOkl;%cG6WLQ`_a7I`woHbEX&?6NJ9Yn&z+#^#! zc8;5=jt~Unn7!cQa$=a7xSp}zuz#Lc#Q3-e7*i`Xk5tx_+^M~!DlyBOwVEq3c(?`@ zZ_3qlTN{eHOwvNTCLOHjwg0%niFYm({LEfAieI+k;U2&uTD4J;Zg#s`k?lxyJN<$mK6>j?J4eOM@T*o?&l@LFG$Gs5f4R*p*V1RkTdCfv9KUfa< z{k;#JfA3XA5NQJziGd%DchDR*Dkld&t;6i9e2t7{hQPIG_uDXN1q0T;IFCmCcua-e z`o#=uS2_en206(TuB4g-!#=rziBTs%(-b1N%(Bl}ea#xKK9zzZGCo@<*i1ZoETjeC zJ)ll{$mpX7Eldxnjb1&cB6S=7v@EDCsmIOBWc$p^W*;C0i^Hc{q(_iaWtE{0qbLjxWlqBe%Y|A z>I|4)(5mx3VtwRBrano|P))JWybOHUyOY67zRst259tx;l(hbY@%Z`v8Pz^0Sw$?= zwSd^HLyL+$l&R+TDnbV_u+h{Z>n$)PMf*YGQ}1Df@Nr{#Gr+@|gKlnv?`s1rm^$1+ zic`WeKSH?{+E}0^#T<&@P;dFf;P5zCbuCOijADb}n^{k=>mBehDD6PtCrn5ZBhh2L zjF$TbzvnwT#AzGEG_Rg>W1NS{PxmL9Mf69*?YDeB*pK!&2PQ7!u6eJEHk5e(H~cnG zZQ?X_rtws!;Tod88j=aMaylLNJbgDoyzlBv0g{2VYRXObL=pn!n8+s1s2uTwtZc

YH!Z*ZaR%>WTVy8-(^h5J^1%NZ$@&_ZQ)3AeHlhL~=X9=fKPzFbZ;~cS**=W-LF1 z5F82SZ zG8QZAet|10U*jK*GVOA(iULStsUDMjhT$g5MRIc4b8)5q_a?ma-G+@xyNDk{pR*YH zjCXynm-fV`*;}%3=+zMj**wlCo6a{}*?;`*j%fU`t+3Korws%dsCXAANKkmVby*eJ z6`2%GB{+&`g2;snG`LM9S~>#^G|nZ|JMnWLgSmJ4!kB->uAEF0sVn6km@s=#_=d)y zzld%;gJY>ypQuE z!wgqqTSPxaUPoG%FQ()1hz(VHN@5sfnE68of>9BgGsQP|9$7j zGqN{nxZx4CD6ICwmXSv6&RD<-etQmbyTHIXn!Q+0{18=!p))>To8df$nCjycnW07Q zsma_}$tY#Xc&?#OK}-N`wPm)+2|&)9=9>YOXQYfaCI*cV1=TUl5({a@1wn#V?y0Yn z(3;3-@(QF|0PA}|w4hBWQbTItc$(^snj$36kz{pOx*f`l7V8`rZK}82pPRuy zxwE=~MlCwOLRC`y%q8SMh>3BUCjxLa;v{pFSdAc7m*7!}dtH`MuMLB)QC4B^Uh2_? zApl6z_VHU}=MAA9*g4v-P=7~3?Lu#ig)cRe90>@B?>})@X*+v&yT6FvUsO=p#n8p{ zFA6xNarPy0qJDO1BPBYk4~~LP0ykPV ztoz$i+QC%Ch%t}|i^(Rb9?$(@ijUc@w=3F1AM}OgFo1b89KzF6qJO~W52U_;R_MsB zfAC29BNUXpl!w&!dT^Zq<__Hr#w6q%qS1CJ#5Wrb*)2P1%h*DmZ?br)*)~$^TExX1 zL&{>xnM*sh=@IY)i?u5@;;k6+MLjx%m(qwDF3?K3p>-4c2fe(cIpKq#Lc~;#I#Wwz zywZ!^&|9#G7PM6tpgwA@3ev@Ev_w`ZZRs#VS4}<^>tfP*(uqLL65uSi9H!Gqd59C&=LSDo{;#@Isg3caF1X+4T}sL2B+Q zK*kO0?4F7%8mx3di$B~b&*t7y|{x%2BUg4kLFXt`FK;Vi(FIJ+!H zW;mjBrfZdNT>&dDfc4m$^f@k)mum{DioeYYJ|XKQynXl-IDs~1c(`w{*ih0-y_=t$ zaMDwAz>^CC;p*Iw+Hm}%6$GN49<(rembdFvb!ZyayLoqR*KBLc^OIA*t8CXur+_e0 z3`|y|!T>7+jdny7x@JHtV0CP1jI^)9){!s#{C>BcNc5#*hioZ>OfDv)&PAM!PTjS+ zy1gRZirf>YoGpgprd?M1k<;=SShCMn406J>>iRVnw9QxsR|_j5U{Ixr;X5n$ih+-=X0fo(Oga zB=uer9jc=mYY=tV-tAe@_d-{aj`oYS%CP@V3m6Y{)mZ5}b1wV<9{~$`qR9 zEzXo|ok?1fS?zneLA@_C(BAjE_Bv7Dl2s?=_?E9zO5R^TBg8Be~fpG?$9I; zDWLH9R9##?>ISN8s2^wj3B?qJxrSSlC6YB}Yee{D3Ex8@QFLZ&zPx-?0>;Cafcb-! zlGLr)wisd=C(F#4-0@~P-C&s%C}GvBhb^tTiL4Y_dsv@O;S56@?@t<)AXpqHx9V;3 zgB!NXwp`=%h9!L9dBn6R0M<~;(g*nvI`A@&K!B`CU3^FpRWvRi@Iom>LK!hEh8VjX z_dSw5nh-f#zIUDkKMq|BL+IO}HYJjMo=#_srx8cRAbu9bvr&WxggWvxbS_Ix|B}DE zk!*;&k#1BcinaD-w#E+PR_k8I_YOYNkoxw5!g&3WKx4{_Y6T&EV>NrnN9W*@OH+niSC0nd z#x*dm=f2Zm?6qhY3}Kurxl@}d(~ z<}?Mw+>%y3T{!i3d1%ig*`oIYK|Vi@8Z~*vxY%Od-N0+xqtJ*KGrqo*9GQ14WluUn z+%c+og=f0s6Mcf%r1Be#e}&>1n!!ZxnWZ`7@F9ymfVkuFL;m6M5t%6OrnK#*lofS{ z=2;WPobvGCu{(gy8|Mn(9}NV99Feps6r*6s&bg(5aNw$eE ztbYsrm0yS`UIJ?Kv-EpZT#76g76*hVNg)L#Hr7Q@L4sqHI;+q5P&H{GBo1$PYkr@z zFeVdcS?N1klRoBt4>fMnygNrDL!3e)k3`TXoa3#F#0SFP(Xx^cc)#e2+&z9F=6{qk z%33-*f6=+W@baq){!d_;ouVthV1PREX^ykCjD|%WUMnNA2GbA#329aEihLk~0!!}k z)SIEXz(;0lemIO{|JdO{6d|-9LePs~$}6vZ>`xYCD(ODG;OuwOe3jeN;|G$~ml%r* z%{@<9qDf8Vsw581v9y+)I4&te!6ZDJMYrQ*g4_xj!~pUu#er`@_bJ34Ioez)^055M$)LfC|i*2*3E zLB<`5*H#&~R*VLYlNMCXl~=9%o0IYJ$bY+|m-0OJ-}6c@3m<~C;;S~#@j-p?DBdr<><3Y92rW-kc2C$zhqwyq09;dc5;BAR#PPpZxqo-@e_s9*O`?w5 zMnLUs(2c-zw9Pl!2c#+9lFpmTR>P;SA#Id;+fo|g{*n&gLi}7`K)(=tcK|?qR4qNT z%aEsSCL0j9DN$j8g(a+{Z-qPMG&O)H0Y9!c*d?aN0tC&GqC+`%(IFY$ll~!_%<2pX zuD`w_l)*LTG%Qq3ZSDE)#dt-xp<+n=3&lPPzo}r2u~>f8)mbcdN6*r)_AaTYq%Scv zEdwzZw&6Ls8S~RTvMEfX{t@L4PtDi{o;|LyG>rc~Um3;x)rOOGL^Bmp0$TbvPgnwE zJEmZ>ktIfiJzdW5i{OSWZuQWd13tz#czek~&*?iZkVlLkgxyiy^M~|JH(?IB-*o6% zZT8+svJzcVjcE0UEkL_5$kNmdrkOl3-`eO#TwpTnj?xB}AlV2`ks_Ua9(sJ+ok|%b z=2n2rgF}hvVRHJLA@9TK4h#pLzw?A8u31&qbr~KA9;CS7aRf$^f1BZ5fsH2W8z}FU zC}Yq76IR%%g|4aNF9BLx6!^RMhv|JYtoZW&!7uOskGSGL+}_>L$@Jg2Vzugq-NJW7 zzD$7QK7cftU1z*Fxd@}wcK$n6mje}=C|W)tm?*V<<{;?8V9hdoi2NRm#~v^#bhwlc z5J5{cSRAUztxc6NH>Nwm4yR{(T>0x9%%VeU&<&n6^vFvZ{>V3RYJ_kC9zN(M(` zp?1PHN>f!-aLgvsbIp*oTZv4yWsXM2Q=C}>t7V(iX*N8{aoWphUJ^(n3k`pncUt&` ze+sYjo)>>=I?>X}1B*ZrxYu`|WD0J&RIb~ zPA_~u)?&`}JPwc1tu=OlKlJ3f!9HXa)KMb|2%^~;)fL>ZtycHQg`j1Vd^nu^XexYkcae@su zOhxk8ws&Eid_KAm_<}65zbgGNzwshR#yv&rQ8Ae<9;S^S}Dsk zubzo?l{0koX8~q*{uA%)wqy*Vqh4>_Os7PPh-maB1|eT-4 zK>*v3q}TBk1QlOF!113XOn(Kzzb5o4Dz@?q3aEb9%X5m{xV6yT{;*rnLCoI~BO&SM zXf=CHLI>kaSsRP2B{z_MgbD;R_yLnd>^1g`l;uXBw7|)+Q_<_rO!!VaU-O+j`u%zO z1>-N8OlHDJlAqi2#z@2yM|Dsc$(nc>%ZpuR&>}r(i^+qO+sKfg(Ggj9vL%hB6 zJ$8an-DbmKBK6u6oG7&-c0&QD#?JuDYKvL5pWXG{ztpq3BWF)e|7aF-(91xvKt047 zvR{G@KVKz$0qPNXK*gt*%qL-boz-*E;7LJXSyj3f$7;%5wj)2p8gvX}9o_u}A*Q|7 z)hjs?k`8EOxv1zahjg2PQDz5pYF3*Cr{%iUW3J+JU3P+l?n%CwV;`noa#3l@vd#6N zc#KD2J;5(Wd1BP)`!IM;L|(d9m*L8QP|M7W#S7SUF3O$GFnWvSZOwC_Aq~5!=1X+s z6;_M++j0F|x;HU6kufX-Ciy|du;T%2@hASD9(Z)OSVMsJg+=7SNTAjV<8MYN-zX5U zVp~|N&{|#Z)c6p?BEBBexg4Q((kcFwE`_U>ZQotiVrS-BAHKQLr87lpmwMCF_Co1M z`tQI{{7xotiN%Q~q{=Mj5*$!{aE4vi6aE$cyHJC@VvmemE4l_v1`b{)H4v7=l5+lm^ ztGs>1gnN(Vl+%VuwB+|4{bvdhCBRxGj3ady^ zLxL@AIA>h@eP|H41@b}u4R`s4yf9a2K!wGcGkzUe?!21Dk)%N6l+#MP&}B0%1Ar*~ zE^88}(mff~iKMPaF+UEp5xn(gavK(^9pvsUQT8V;v!iJt|7@&w+_va`(s_57#t?i6 zh$p!4?BzS9fZm+ui`276|I307lA-rKW$-y^lK#=>N|<-#?WPPNs86Iugsa&n{x%*2 zzL_%$#TmshCw&Yo$Ol?^|hy{=LYEUb|bMMY`n@#(~oegs-nF){0ppwee|b{ca)OXzS~01a%cg&^ zp;}mI0ir3zapNB)5%nF>Sd~gR1dBI!tDL z&m24z9sE%CEv*SZh1PT6+O`%|SG>x74(!d!2xNOt#C5@I6MnY%ij6rK3Y+%d7tr3&<^4XU-Npx{^`_e z9$-|@$t`}A`UqS&T?cd@-+-#V7n7tiZU!)tD8cFo4Sz=u65?f#7Yj}MDFu#RH_GUQ z{_-pKVEMAQ7ljrJ5Wxg4*0;h~vPUI+Ce(?={CTI&(RyX&GVY4XHs>Asxcp%B+Y9rK z5L$q94t+r3=M*~seA3BO$<0%^iaEb2K=c7((dIW$ggxdvnC$_gq~UWy?wljgA0Dwd`ZsyqOC>)UCn-qU5@~!f znAWKSZeKRaq#L$3W21fDCMXS;$X(C*YgL7zi8E|grQg%Jq8>YTqC#2~ys%Wnxu&;ZG<`uZ1L<53jf2yxYR3f0>a;%=$SYI@zUE*g7f)a{QH^<3F?%({Gg)yx^zsdJ3^J2 z#(!C3qmwx77*3#3asBA(jsL`86|OLB)j?`0hQIh>v;c2A@|$Yg>*f+iMatg8w#SmM z<;Y?!$L--h9vH+DL|Wr3lnfggMk*kyGH^8P48or4m%K^H-v~`cBteWvnN9port02u zF;120HE2WUDi@8?&Oha6$sB20(XPd3LhaT~dRR2_+)INDTPUQ9(-370t6a!rLKHkIA`#d-#WUcqK%pMcTs6iS2nD?hln+F-cQPUtTz2bZ zq+K`wtc1;ex_iz9?S4)>Fkb~bj0^VV?|`qe7W02H)BiibE9=_N8=(5hQK7;(`v7E5Mi3o? z>J_)L`z(m(27_&+89P?DU|6f9J*~Ih#6FWawk`HU1bPWfdF?02aY!YSo_!v$`&W znzH~kY)ll^F07=UNo|h;ZG2aJ<5W~o7?*${(XZ9zP0tTCg5h-dNPIM=*x@KO>a|Bk zO13Cbnbn7+_Kj=EEMJh4{DW<))H!3)vcn?_%WgRy=FpIkVW>NuV`knP`VjT78dqzT z>~ay~f!F?`key$EWbp$+w$8gR1RHR}>wA8|l9rl7jsT+>sQLqs{aITUW{US&p{Y)O zRojdm|7yoA_U+`FkQkS?$4$uf&S52kOuUaJT9lP@LEqjKDM)iqp9aKNlkpMyJ76eb zAa%9G{YUTXa4c|UE>?CCv(x1X3ebjXuL&9Dun1WTlw@Wltn3zTareM)uOKs$5>0tR zDA~&tM~J~-YXA<)&H(ud)JyFm+d<97d8WBr+H?6Jn&^Ib0<{6ov- ze@q`#Y%KpD?(k{if5-M(fO3PpK{Wjqh)7h+ojH ztb=h&vmy0tn$eA8_368TlF^DKg>BeFtU%3|k~3lZAp(C$&Qjo9lR<#rK{nVn$)r*y z#58_+t=UJm7tp|@#7}6M*o;vn7wM?8Srtc z3ZFlKRDYc^HqI!O9Z*OZZ8yo-3ie9i8C%KDYCfE?`rjrf(b&xBXub!54yaZY2hFi2w2asEOiO8;Hru4~KsqQZMrs+OhO8WMX zFN0=EvME`WfQ85bmsnPFp|RU;GP^&Ik#HV(iR1B}8apb9W9)Nv#LwpED~%w67o;r! zVzm@zGjsl)loBy6p>F(G+#*b|7BzZbV#E0Pi`02uAC}D%6d12TzOD19-9bhZZT*GS zqY|zxCTWn+8*JlL3QH&eLZ}incJzgX>>i1dhff}DJ=qL{d?yv@k33UhC!}#hC#31H zOTNv5e*ozksj`4q5H+75O70w4PoA3B5Ea*iGSqA=v)}LifPOuD$ss*^W}=9kq4qqd z6dqHmy_IGzq?j;UzFJ*gI5)6qLqdUL;G&E*;lnAS+ZV1nO%OdoXqw(I+*2-nuWjwM-<|XD541^5&!u2 z1XflFJp(`^D|ZUECbaoqT5$#MJ=c23KYpBjGknPZ7boYRxpuaO`!D6C_Al?T$<47T zFd@QT%860pwLnUwer$BspTO9l1H`fknMR|GC?@1Wn`HscOe4mf{KbVio zahne0&hJd0UL#{Xyz=&h@oc>E4r*T|PHuNtK6D279q!2amh%r#@HjaN_LT4j>{&2I z?07K#*aaZ?lNT6<8o85cjZoT~?=J&Xd35I%JJom{P=jj?HQ5yfvIR8bd~#7P^m%B-szS{v<)7i?#at=WA+}?r zwMlc-iZv$GT};AP4k2nL70=Q-(+L_CYUN{V?dnvG-Av+%)JxfwF4-r^Z$BTwbT!Jh zG0YXK4e8t`3~){5Qf6U(Ha0WKCKl^zlqhqHj~F}DoPV#yHqLu+ZWlv2zH29J6}4amZ3+-WZkR7(m{qEG%%57G!Yf&!Gu~FDeSYmNEkhi5nw@#6=Bt& zOKT!UWVY-FFyq1u2c~BJ4F`39K7Vw!1U;aKZw)2U8hAb&7ho|FyEyP~D<31{_L>RrCU>eEk-0)TBt5sS5?;NwAdRzRj5qRSD?J6 ze9ueq%TA*pgwYflmo`=FnGj2r_u2!HkhE5ZbR_Xf=F2QW@QTLD5n4h(?xrbOwNp5` zXMEtm`m52{0^27@=9VLt&GI;nR9S)p(4e+bAO=e4E;qprIhhclMO&7^ThphY9HEko z#WfDFKKCcf%Bi^umN({q(avHrnTyPH{o=sXBOIltHE?Q65y_At<9DsN*xWP|Q=<|R z{JfV?B5dM9gsXTN%%j;xCp{UuHuYF;5=k|>Q=;q zU<3AEYawUG;=%!Igjp!FIAtJvoo!*J^+!oT%VI4{P=XlbYZl;Dc467Nr*3j zJtyn|g{onj!_vl)yv)Xv#}(r)@25OHW#|eN&q7_S4i2xPA<*uY9vU_R7f};uqRgVb zM%<_N3ys%M;#TU_tQa#6I1<+7Bc+f%mqHQ}A@(y^+Up5Q*W~bvS9(21FGQRCosvIX zhmsjD^OyOpae*TKs=O?(_YFjSkO`=CJIb*yJ)Pts1egl@dX6-YI1qb?AqGtIOir&u zyn>qxbJhhJi9SjK+$knTBy-A)$@EfzOj~@>s$M$|cT5V!#+|X`aLR_gGYmNuLMVH4 z(K_Tn;i+fR28M~qv4XWqRg~+18Xb?!sQ=Dy)oRa)Jkl{?pa?66h$YxD)C{F%EfZt| z^qWFB2S_M=Ryrj$a?D<|>-Qa5Y6RzJ$6Yp`FOy6p2lZSjk%$9guVsv$OOT*6V$%TH zMO}a=JR(1*u`MN8jTn|OD!84_h${A)_eFRoH7WTCCue9X73nbD282V`VzTH$ckVaC zalu%ek#pHxAx=0migDNXwcfbK3TwB7@T7wx2 zGV7rS+2g9eIT9>uWfao+lW2Qi9L^EBu#IZSYl0Q~A^KYbQKwNU(YO4Xa1XH_>ml1v z#qS;P!3Lt%2|U^=++T`A!;V-!I%upi?<#h~h!X`p7eP!{+2{7DM0$yxi9gBfm^W?M zD1c)%I7N>CG6250NW54T%HoCo^ud#`;flZg_4ciWuj4a884oWUYV(#VW`zO1T~m(_ zkayymAJI)NU9_0b6tX)GU+pQ3K9x=pZ-&{?07oeb1R7T4RjYYbfG^>3Y>=?dryJq& zw9VpqkvgVB?&aK}4@m78NQhTqZeF=zUtBkJoz8;6LO<4>wP7{UPEs1tP69;v919I5 zzCqXUhfi~FoK5niVU~hQqAksPsD@_|nwH4avOw67#fb@Z5_OS=$eP%*TrPU%HG<-A z`9)Y3*SAdfiqNTJ2eKj8B;ntdqa@U46)B+odlH)jW;U{A*0sg@z>-?;nN}I=z3nEE@Bf3kh1B zdqT{TWJvb#AT&01hNsBz8v(OwBJSu#9}A6Y!lv|`J#Z3uVK1G`0$J&OH{R?3YVfk% z9P3HGpo<1uy~VRCAe&|c4L!SR{~^0*TbVtqej3ARx(Okl5c>m~|H9ZwKVHc_tCe$hsqA`l&h7qPP5xBgtwu!; zzQyUD<6J!M5fsV-9P?C9P49qnXR+iXt#G_AS2N<6!HZ(eS`|-ndb|y!(0Y({2 z4aF~GO8bHM7s+wnhPz>sa!Z%|!qWk*DGr)azB}j6bLe#FQXV4aO>Eo7{v`0x=%5SY zy&{kY+VLXni6pPJYG_Sa*9hLy-s$79$zAhkF)r?9&?UaNGmY9F$uf>iJ~u@Q;sydU zQaN7B>4B*V;rtl^^pa3nFh$q*c&sx^Um}I)Z)R&oLEoWi3;Yv6za?;7m?fZe>#_mS z-EGInS^#UHdOzCaMRSLh7Mr0}&)WCuw$4&K^lx{;O+?Q1p5PD8znQ~srGrygJ?b~Q5hIPt?Wf2)N?&Dae4%GRcRKL(a-2koctrcvxSslXn-k9cYS|<-KJ#+$Wo>}yKKh*3Q zHsK(4-Jv!9R3*FKmN$Z#^aZcACGrlGjOe^#Z&DfPyS-1bT9OIX~-I-5lN6Y>M}dvivbs2BcbPcaNH%25-xMkT$>*soDJ) z27;};8oCYHSLF0VawZFn8^H;hIN=J457@eoI6s2P87QN6O`q8coa;PN$mRZ>2Vv+! zQj1}Tvp8?>yyd_U>dnhx%q~k*JR`HO=43mB?~xKAW9Z}Vh2b0<(T89%eZ z57kGs@{NUHM>|!+QtqI@vE8hp`IIGc`A9Y{p?c;@a!zJFmdaCJ;JmzOJ8)B1x{yZp zi!U{Wh-h+u6vj`2F+(F6gTv*cRX7MR z9@?>is`MSS1L#?PaW6BWEd#EX4+O1x6WdU~LZaQ^Quow~ybz*aAu{ZMrQ;yQ8g)-qh>x z^}@eFu1u7+3C0|hRMD1{MEn(JOmJ|wYHqGyn*xt-Y~J3j@nY56i)sgNjS4n@Q&p@@^>HQjzNaw#C9=TbwzDtiMr2a^}bX< zZE%HU^|CnS`WYVcs}D)+fP#bW0+Q#l#JC+!`OlhffKUCN8M-*CqS;VQX`If78$as0 z=$@^NFcDpTh~45heE63=x5nmP@4hBaFn(rmTY2Yj{S&k;{4W!0Nu9O5pK30}oxM7{ z>l4cKb~9D?N#u_AleD<~8XD@23sY^rt&fN%Q0L=Ti2bV#px`RhM$}h*Yg-iC4A+rI zV~@yY7!1}-@onsZ)@0tUM23cN-rXrZYWF#!V-&>vds8rP+w0t{?~Q zT^LN*lW==+_ifPb+-yMh9JhfcYiXo_zWa`ObRP9_En3P))Qyu0qPJ3*hiFSu>Vt-j z<*HWbiP2#BK@nt<g|pe3 zfBKS@i;ISkorx@cOIx9}p^d8Gis%$)))%ByVYU^KG#eE+j1p;^(Y1ndHnV&YuQZm~ zj;f+mf>0ru!N`)_p@Ls<& z`t+JDx7}R568Q|8`4A}G@t8Wc?SOXunyW5C-AWoB@P>r}uwFY*=?=!K@J(!t@#xOuPXhFS@FTf6-7|%k;nw2%Z+iHl219Ho1!bv(Ee0|ao!Rs%Jl0@3suGrOsb_@VM;(xzrf^Cbd;CK3b%a|ih-fG)`Rd00O74=sQYW~Ve z#fl!*(fo~SIQ5-Sl?1@o7-E*|SK|hoVEKzxeg!$KmQLSTN=5N`rYeh$AH&x}JMR+5dq|~FUy&Oj%QIy;HNr;V*7cQC+ka>LAwdU)?ubI@W z={eg%A&7D**SIj$cu=CN%vN^(_JeIHMUyejCrO%C3MhOcVL~Niu;8WYoN}YVhb+=- zR}M3p|H0`E2Id99y#03r`8$s0t*iD>`^7EPm1~guC)L~uW#O~>I85Q3Nj8(sG<@T| zL^e~XQt9O0AXQ^zkMdgzk5bdYttP~nf-<831zulL>>ghTFii$lg3^80t8Gb*x1w5| zN{kZuv`^8Fj=t(T*46M=S$6xY@0~AvWaGOYOBTl0?}KTkplmGn-*P(X=o-v^48OY} zi11-+Y}y)fdy_tI;*W(>#qzvgQZ52t!nrGsJEy!c86TKIN(n|!&ucCduG$XaIapI z{(Z9gZANsI={A=5Aorgq2H25Dd}H5@-5=j=s{f`%^>6b5qkm_2|3g>r-^amf=B_xV zXg*>aqxXZ6=VUI4$})ypDMy$IKkgJ;V>077T9o#OhpFhKtHP_4mnjS5QCgGe<;~Xe zt<2ZhL7?JL6Mi|U_w?;?@4OD@=4EB2op_s)N-ehm#7`zSU#7itU$#%^ncqjc`9HCG zfj;O1T+*oTkzRi-6NN`oS3w3$7ZB37L>PcN$C$L^qqHfiYO4_>0_qCw0r@FEMj=>}}%q_`d#pUT;c?=gI zqTGpiY4Z;Q(B~#hXIVBFbi#dO=cOdmOqD0|An?7nMdrm2^C>yw*dQ=#lf8)@DvXK; z$MXp}QZgnE!&L73x0LZX_bCdD4lRY$$^?9dt1RwCng{lIpbb%Ej%yOh{@76yEyb}K zXZy%^656Sk3BLKbalcc>Dt5iDzo^tj2!wnDL(X;urJfpkWrab!frFSC6Q7m zuoqN!(t=L&+Ov&~9mz(yEB`MK%RPXS>26Ww5(F;aZ zR@tPAw~=q2ioOiynxgBqE&3-R-@6yCo0*mE;#I^c!=g~HyyjGA6}|<(0EseKDTM4w z94YnCO^VYIUY@}x8kr;;El-cFHVO<$6;-UdmUB|J8R*Wf$a37gVgYT|w5^KkYe=(i zMkA$%7;^a*$V+}e%S~&*^^O;AX9NLt@cIPc*v!lKZ)(zahAsUj%PJot19ErFU=Uk( z9Hw;Lb`V+BzVpMu;TGB9}y~ff)^mbEmF?g{{7_0SR zPgp*n)l{?>7-Ji;eWG{ln$)Bro+UJAQo6W2-23d@SI=HiFV3hR2OUcAq_9q~ye)o@ zq8WZvhg`H(?1AUZ-NM%_Cuj}eb{4wOCnqs^E1G9U4HKjqaw@4dsXWP#$wx^}XPZ0F zywsJ0aJHA>AHc^q#nhQjD3!KDFT6FaDioJ#HsZU7Wo?8WH19TJ%OMDz$XH5J4Cjdt z@crE;#JNG`&1H8ekB(R4?QiiZ55kztsx}pQti}gG0&8`dP=d(8aCLOExd*Sw^WL`Q zHvZ(u`5A58h?+G&GVsA;pQNNPFI)U@O`#~RjaG(6Y<=gKT2?1 z*pCUGU)f??VlyP64P@uT`qh?L03ZQyLOBn?EKwH+IG{XvTh5|NldaSV_n~DK&F1aa znq~C_lCQHMfW6xib%a2m!h&%J)aXb{%-0!HCcW|kzaoSwPMhJ6$KL|F~Sx(tctbwfkgV;#KZlEmJN5&l5XF9eD;Kqb<| z>os)CqC^qF8$be|v;)LY{Gh@c0?a??k7M7&9CH+-B)t&T$xeSzCs30sf8O-+I#rq} z&kZj5&i>UyK9lDjI<*TLZ3USVwwpiE5x8<|{Db z3`HX3+Tt>1hg?+uY{^wC$|Tb7ud@3*Ub?=2xgztgv6OOz0G z-4VRyIChHfegUak^-)-P;VZY@FT64#xyo=+jG<48n2%wcx`ze6yd51(!NclmN=$*kY=#uu#>=yAU-u4I9Bt0n_6ta?&9jN+tM_5_3RH);I zxTN4n$EhvKH%TmOh5mq|?Cx$m>$Ed?H7hUEiRW^lnW+}ZoN#;}aAuy_n189qe1Juk z6;QeZ!gdMAEx4Na;{O*j$3F3e?FLAYuJ2iuMbWf8Ub6(nDo?zI5VNhN@ib6Yw_4P)GY^0M7TJwat z2S*2AcP}e0tibZ@k&htTD&yxT9QRG0CEq$;obfgV^&6YVX9B9|VJf`1aS_#Xk>DFo zwhk?~)>XlP5(u~UW0hP7dWZuCuN4QM24Td&j^7~)WQ6YeCg)njG*ri}tTcG-NxX}p zNB>kcxd5ipW@tN3=6r@Jgm#rgrK*dXA!gxy6fAvP7$)8)Vc~PPQ|`( zPy|bG1sUz958-!zW^j(8ILV%QC@x`~PDFczboZqWjvSU<9O3!TQ&xYi%?Y0AiVBLV z%R?#1L#G&xw*RZPsrwF?)B5+MSM(b$L;GLnRsSU!_$N;6pD97~H}`c>0F`&E_FCNE z_)Q*EA1%mOp`z>+h&aqlLKUD9*w?D>stDeBRdR*AS9)u;ABm7w1}eE|>YH>YtMyBR z^e%rPeZzBx_hj?zhJVNRM_PX(O9N#^ngmIJ0W@A)PRUV7#2D!#3vyd}ADuLry;jdn zSsTsHfQ@6`lH z^GWQf?ANJS>bBO-_obBL$Apvakhr1e5}l3axEgcNWRN$4S6ByH+viK#CnC1|6Xqj& z*_i7cullAJKy9GBAkIxUIzsmN=M|(4*WfBhePPHp?55xfF}yjeBld7+A7cQPX8PE-|Pe_xqboE;2AJb5ifrEfr86k&F0+y!r`-urW}OXSkfz2;E``UTrGSt^B)7&#RSLTQitk=mmPKUKP`uGQ4)vp_^$^U`2Jjq zeul!ptEpa%aJo0S(504oXPGdWM7dAA9=o9s4-{>z*pP zJ31L#|L?YR;^%+>YRJrLrFC=5vc;0{hcxDKF z!ntmgO>rVDaGmRpMI7-+mv(j~;s_LARvcpkXj|{GHu1c<1 zKI)#7RE~Dizu1lG>p-PcY2jX#)!oJlBA$LHnTUWX=lu``E)vhf9h4tYL-juZ`e|Kb z=F?C;Ou)h^cxB;M-8@$ZSH0jkVD>x-XS$ePV1vlU8&CG))4NgU(=XFH=Jb1IB7dBysS+94}Y>sjS(&YcJwhn zifzA|g$D5rW89vkJSv()I+Th4R&C$g-!CB30xkh%aw4po3$@DK2fW>}enE2YPt&{C~j}`>RYICK{ zYAPfZ&%`R}u6MYo<>d`^O#Q(dM{3>T^%J{Vu;lr#Utg4x9!Z9J%iXs(j+dn&SS1_2 zzxGtMnu^`d%K4Xq4Ms-ErG3_7n?c(3T!?rvyW=G<7_XKDv*ox`zN*^BVwUoqh{D7o zdEiq;Zp6}k_mCIAVTUcMdH|fo%L#qkN19X$%b1#Oko|u4!M*oRqdBa3z98{H#g=d%5X&D#NXhLh`nUjxi8@3oo(AgeItdJ zIrt9ieHI1GiwHiU4Cba-*nK@eHI4uj^LVmVIntU@Gwf^t6i3{;SfLMCs#L;s;P4s5oqd^}8Uil!NssP>?!K z07nAH>819U=^4H6l-Dhy`^Q6DV^}B9^aR0B%4AH=D&+dowt9N}zCK+xHnXb-tsKaV6kjf;Wdp#uIZ_QsI4ralE>MWP@%_5eN=MApv92( z09SSB#%eE|2atm9P~X2W2F-zJD+#{q9@1}L2fF|Lzu@1CAJq*d6gA8*Jjb;<+Asih zctE|7hdr5&b-hRhVe}PN z$0G{~;pz1yhkbwuLkfbvnX=<7?b(1PhxAmefKn$VS6Sv)t-UypwhEs3?*E=(pc%Dlul1V~OdWvdf z{WBX?lhfO_g$$X~hm^Bhl@U0t<|beYgT)2L_C(z@B^-63c9Ak2*Aa)iOMylfl|qyNQdO#yoJ?m2FOkhZ1ou@G%+^m z#!#(gTv8nx^34(HddDp|dcFl@&eh+&FFJc@^FL3fV2?u&9Wt|Yp3&MS)e+ez0g~Ys zY7d0n^)+ z0@K^GJTLN?XAV(0F6e>o>HCGJU5(8WsSFErs0FsO=O1u$=T~xx7HYK{7C>-IGB8U+ z&G^Vy>uY}Bq7HX-X`U^nNh+11GjG-)N1l_tG<^4Tu4+4X9KO9IrdH+eXGk|G6Tc(U zU~g7BoO!{elBk>;uN-`rGQP-7qIf9lQhj-=_~0Qyszu>s$s0FrJatSylv!ol&{29~ z7S4fv&-UBOF&cR@xpuW*{x9$R;c_ALt?{+dI&HoBKG-!EY{yE=>aWhlmNhHlCXc(B zuA-zI*?Z9ohO$i8s*SEIHzVvyEF$65b5m=H*fQ)hi*rX8 zKlPqjD*Ix1tPzfR_Z3bO^n32iQ#vhjWDwj6g@4S?_2GyjiGdZZRs3MLM zTfl0_Dsn=CvL`zRey?yi)&4TpF&skAi|)+`N-wrB_%I_Osi~)9`X+`Z^03whrnP7f z?T`*4Id`J@1x#T~L(h5^5z%Cok~U|&g&GpCF%E4sB#i3xAe>6>24%Kuu=)=HRS;Pu2wghgTFa zHqm#sa{7-~{w_039gH0vrOm&KPMiPmuPRpAQTm5fkPTZVT&9eKuu%Riu%-oMQl2X6 z{Bnx`3ro^Z$}rVzvUZsk9T)pX|4%sY+j0i)If_z-9;a^vr1YN>=D(I7PX){_JTJ&T zPS6~9iDT{TFPn}%H=QS!Tc$I9FPgI<0R7?Mu`{FTP~rRq(0ITmP1yrJdy|m;nWmDelF-V^y7*UEVvbxNv0sHR?Q=PVYRuZinR(;RjVAG zm&qlSYvaiIbVEqBwyDaJ8LVmiCi{6ESF4pO?U&7pk&CASm6vuB;n-RauPFzdr!C%1 z8pjdSUts7EbA4Kg(01zK!ZU<-|d zU&jWswHnSLIg&mTR;!=-=~z(#!UsXt%NJR|^teM8kG@8Qg_0^6Jqfn&(eENtP8D7K zvnll3Y%7yh1Ai~0+l6dAG|lEGe~Oa+3hO>K2}{ulO?Vf*R{o2feaRBolc;SJg)HXHn4qtzomq^EM zb)JygZ=_4@I_T=Xu$_;!Q`pv6l)4E%bV%37)RAba{sa4T*cs%C!zK?T8(cPTqE`bJ zrBWY`04q&+On`qH^KrAQT7SD2j@C>aH7E8=9U*VZPN-(x>2a++w7R$!sHH+wlze2X)<<=zC_JJvTdY7h&Jum?s?VRV)JU`T;vjdi7N-V)_QCBzI zcWqZT{RI4(lYU~W0N}tdOY@dYO8Rx5d7DF1Ba5*U7l$_Er$cO)R4dV zE#ss{Dl`s#!*MdLfGP>?q2@GSNboVP!9ZcHBZhQZ>TJ85(=-_i4jdX5A-|^UT}~W{CO^Lt4r;<1ps@s|K7A z90@6x1583&fobrg9-@p&`Gh+*&61N!$v2He2fi9pk9W2?6|)ng7Y~pJT3=g~DjTcYWjY9gtZ5hk*1Qf!y2$ot@0St$@r8|9^GMWEE>iB~etL zXYxn#Rvc`DV&y93@U$Z91md1qVtGY*M(=uCc}@STDOry@58JNx`bUH}EIb(n6I}i? zSYJOZ2>B6&Payu+@V!gxb;)_zh-{~qtgVwQ-V;vK7e0^Ag_$3+g+{xSVudVOY_p-R z$sXhpFSk7je2lk5)7Y2;Z847E1<;5?;z(I)55YFtgF!J;NT|eVi}q^*2sM}zyM{+s zD0phl+J>k1E7cZEGmP?1-3~RE;R$q(I5}m?MX8xi?6@0f#rD8Cjkpv1GmL5HVbTnM zAQ&4-rbkpdaoLp~?ZoW>^+t0t1t%GO2B;ZD4?{qeP+qsjOm{1%!oy1OfmX?_POQJ4 zGwvChl|uE;{zGoO?9B_m{c8p(-;_yq?b^jA({}iQG35?7H7`1cm`BGyfuq7z1s~T| zm88HpS{z54T{jxC=>kZ=Z#8G@uya3tt0$xST5V$-V<;6MA66VFg}`LLU8L=q3DmkU z)P^X8pg`ndMY*>gr{6~ur^Q@Z8LNQf*6wkP03K<|M*+cDc#XKZ`Z0$1FkI-IDRw#| za52W4MyHlDABs~AQu7Duebjgc}02W;1jgBx&I@TMDXU`LJutQ?@r%1z`W zlB8G-U$q37G1ob>Er8j0$q@OU3IwG#8HsvJM#)j=Y%~#zY`jaG%5;!(kY3*a^t>(qf6>I zpAJpF%;FQ?BhDSsVG27tQEG*CmWhl4)Ngp%}D?U0!nb1=)1M==^B)^$8Li$boCY$S4U;G^A!?24nSYHra{< zSNapX#G+0BTac|xh`w&}K!);$sA3ay%^a2f?+^*9Ev8ONilfwYUaDTMvhqz2Ue2<81uuB71 zAl|VEOy%GQ7zxAJ&;V^h6HOrAzF=q!s4x)Mdlmp{WWI=gZRk(;4)saI0cpWJw$2TJcyc2hWG=|v^1CAkKYp;s_QmU?A;Yj!VQ1m-ugzkaJA(wQ_ zah00eSuJg<5Nd#OWWE?|GrmWr+{-PpE_Dbqs&2`BI=<%ggbwK^8VcGiwC-6x`x|ZY z1&{Vj*XIF2$-2Lx?KC3UNRT z&=j7p1B(akO5G)SjxXOjEzujDS{s?%o*k{Ntu4*X z;2D|UsC@9Wwk5%)wzTrR`qJX!c1zDZXG>-Q<3Z)7@=8Y?HAlj_ZgbvOJ4hPlcH#Iw z!M-f`OSHF~R5U`p(3*JY=kgBZ{Gk;0;bqEu%A;P6uvlZ0;BAry`VUoN(*M9NJ z%CU2_w<0(mSOqG;LS4@`p(3*Z7jC|Khm5-i>FcYr87};_J9)XKlE}(|HSfnA(I3)I zfxNYZhs#E6k5W(z9TI2)qGY&++K@Z?bd;H%B@^!>e2Wi@gLk)wC)T93gTxdRPU7uh z)`$-m(G2I5AuK52aj!fMJR|d^H?0X~+4xSpw zqNRtq5r8hic*{eAwUT<=gI5uXLg)o5mg4XnO^T+Rd+{l)<$Aqp{+RxhNYuX^45W0k z5$t%+7R;dX$`s6CYQYcims>5bNt+k&l_t%C9D-6sYVm%Y8SRC#kgRh*%2kqMg2ewb zp_X*$NFU%#$PuQ@ULP>h9Xw`cJ>J-ma8lU`n*9PcWFpE%x0^}(DvOVe2jz@ z0^2QOi0~t!ov?jI{#bw~`Aj5ymQW@eruRg`ZNJ5IT5_5AHbQ?|C>_7rwREf2e2x&L zlV8xdOkp_*+wdaqE?6bmdrFfaGepcj=0AI<+c=Tg^WB9BhFx?SvwoVdTEm&zPy@Vs zPs2mVPiw1n_h?Xi6!+w)ypsFXXuM>gIY(J+1N6r!sJ{+r1%BzRF20!D;bN>L^?O8n z(5|x2p^Q6X`!pm3!MMFET5`nJXn>tK`fFAj5Eo&t6;F>TU_4G93YGyzvF2_fB& zfE8(dq?R@@&Wh8~%G~rDt1+e)96O5)by_%;G~Zv`TpmZ)vY@BkAan*zEy(s`*{-@U z;$WPjoNx~m?`6Z;^O=K3SBL3LrIxfU{&g)edERkPQZK!mVYU-zHuV0ENDq^e<-?^U zGyRcrPDZZw*wxK(1SPUR$0t0Wc^*u_gb*>qEOP102FX|`^U%n*7z=wM@pOmYa6Z=-)T%!{tAFELY2`dTl3$&w! z7sgKXCTU(h3+8)H#Qov19%85Xo+oQh?C-q0zaM_X2twSCz|j_u!te3J2zLV#Ut_q7 zl+5LGx#{I`(9FzE$0==km|?%m?g~HB#BSz2vHynf1x14mEX^~pej*dhzD|6gMgOJ_ z8F_<>&OIz;`NSqrel?HI-K(|ypxwz}NtX!CF3&T(CkuYOnKS&%lUSU44KsgS`L>!w zl{MoT4`t=+p8>@88)Ea%*hOIkxt#b4RfrwRMr91UF_Ic~kV;|+dRW0a8Vl725+gsvtHr5 z>?3fai&9NmU|3;-nAu8OB|<(-2Kfub4MX&1i}dDd=R~Dk=U-Vr=@&lfEIYU~xtHHO z4TKt=wze`qm=69lD)sOOkZ;$9=0B#*g@X6xPM-%zG*rCXkN%eRDEUp$gAaEd29t&T zRTAg##Sk+TAYaa(LyTD__zL3?Z+45^+1o}(&f<~lQ*-z7`Um^>v@PKqOunTE#OyKFY^q&L^fqZgplhXQ>P3?BMaq6%rO5hfsiln7TppJ z>nG9|2MmL|lShn4-yz0qH>+o;Fe`V!-e*R0M|q~31B=EC$(bQZTW^!PrHCPE4i|>e zyAFK!@P}u>@hqwf%<#uv*jen5xEL|v!VQEK!F`SIz_H8emZfn#Hg}}@SuqPv+gJ@- zf3a`DT_Q#)DnHv+XVXX`H}At zmQwW2K`t@(k%ULJrBe6ln9|W8+3B*pJ#-^9P?21%mOk(W1{t#h?|j0ZrRi_dwGh#*eBd?fy(UBXWqAt5I@L3=@QdaiK`B_NQ$ zLXzm{0#6zh2^M zfu>HFK^d`&v|x&xxa&M|pr))A4)gFw<_X@eN`B1X%C^a{$39fq`(mOG!~22h)DYut z(?MONP1>xp4@dIN^rxtMp&a^yeGc8gmcajyuXhgaB;3}vFCQFa!pTDht9ld9`&ql`2&(dwNl5FZqedD^BP zf5K1`(_&i7x-&rD=^zkFD87idQrk(Y?E;-j^DMCht`A8Qa5J-46@G_*Y3J+&l{$}*QCATEc9zuzaQGHR8B;y*>eWuv)E##?Ba3w= zZ|v(l{EB`XzD#|ncVm#Wy?#Nzm3bS1!FJ70e{DGe$EgNDg7<_ic^mJSh&Xc|aTwCrTv;XkW~UlS&G%KyLklCn}F^i(YP(f z{cqH%5q9ND_S;l$HRP$Q@`D=F*_1$CXIA5X@|V&Vir$NQ$vCx!b&LGCR<-2y)m%HI zxeeyQIjiWcf4uD9+FP+EJ`&$oJ%$R(#w~GjqP|aTQj#d(;l#rq$vcM&Y4ZQ_i{Kpx z?k2BtoKb?+1-EVmG^ne-W%8+y?i#J5N5g8f^qpH5(ZZp7$u+?I9GB+&MREX?TmVV$ zA}Ps=^CkD^sD9N;tNtN!a>@D^&940cTETu*DUZlJO*z7BBy`Rl;$-D@8$6PFq@tz0 z=_2JMmq-JRSvx`;!XM|kO!|DENI-5ke8WR*Zj#vy#Nf1;mW-{6>_sCO8?sVWOKDM| zR(iaZrBrzlRatUzp_Y|2nOXnY2G%WLGXCo9*)th_RnXvXV=q;WNAimI98!A54|$&OCCG%$4m{%E&o?S|Qx<4K~YGmM1CS!vZAzLN%d znbZsw6ql=XkiwSbNofNeA42q8#LH6Rk(u@z172O#6K>Sb{#`t#GUgpd{2;D(9@I_9 zwsY(6Go7RmOThs2rM3|Z#Vbs}CHPLgBK6gE8;XkJQDx~p5wJ?XkE(0<^hwnt6;$~R zXCAzMfK@`myzdkkpv*ZbarVwCi&{-O#rswrb-#x4zRkxfVCq;mJLic|*C92T?0CYv z)FCqY$xA(QZmggPocZqQj0Rc?=Afna`@fpSn)&nSqtI}?;cLphqEF3F9^OZfW9@HDunc^2{_H)1D9(O}4e zJMi_4(&$CD{Jf5&u|7#Iq*F~)l!8pAzNrX^<&wfEu~}Ipslzx=g^ff2?B9SnV=!$ zv&K0`hMN6BVIusHNX-lr`#K?OG1S*S4rCQaI3ea(!gCl7YjxJ3YQ)7-b&N*D8k><*x|47s3; z4f~WTWuk|Qd*d*DICV}Vb0YSzFZp5|%s4}@jvtTfm&`|(jNpajge zD}@CMaUBs+b?Yu6&c#18=TxzMCLE76#Dy=DLiq_a_knQX4Uxk$&@3ORoBFK_&a>`QKaWu^)Hzrqz{5)?h3B_`4AOn{fG9k zEwnjQb>8XRq!k?rmCd6E**1cY#b9yczN4mD%GLCeRk}{TmR1*!dTNzY;(f!B0yVuk zSjRyf;9i@2>bdGSZJ=FNrnxOExb075;gB z*7&YR|4ZraFO#45-4h%8z8U}jdt?83AmU3)Ln#m3GT!@hYdzqqDrkeHW zU#R`Z8RHq996HR=mC}SRGtsz07;-C-!n*ALpwwBe~loM)YqMH)Um$sH0RbTTzxFd)h1=-w5Yl3k|3nQ zZG>=_yZ7Lsn=b8_MZI+LSHLGYSSCc?ht~7cv#39>Moz6AS}5 zus?xge0PGdFd2FpXgIscWOyG}oxATgd$yl0Ugf_&J_vwt`)XWx!p*gE_cWU(tUTnz zQS}!bMxJyi3KWh^W9m zxLcy``V@EfJzYjK@$e7Yk=q!kL8cd3E-zpc*wwvGJ62O!V;N zFG7Y?sJ+^a%H1;rdDZRu2JmGn6<&ERKes=Pwx)GG-nt73&M78+>SOy!^#=gvLB)2H zjv!J0O`-zft|0Jv$3k5wScY)XB+9leZgR5%3~HtZA=bCg7=Dn+F}>2lf;!*1+vBtf z9jhmqlH=t5XW{0MC7Y~O7jaju&2`p!ZDLGlgnd~%+EJ%A#pIByi-+EOmoLVoK&ow8 zTDjB%0hxhiRv+O3c2*y00rMA=)s|3-ev7emcbT43#izku7dvaDXy1IMV0ahjB9yzi z9C9fN+I2Mzt1*{`a6B?+PdWHiJ5fH}rb2t>q)~3RfCxmyK^y5jN7Pn(9DFh61GO%p zuBErj=m|bDn_L8SINU)Z&@K*AgGz+SUYO_RUeJt=E0M+eh&kqK;%Y1psBNU<4-s9# ziHFr7QP6Ew=-2CdfA#Bf|EsctH;<&=Hsd>)Ma8NvHB$cpVY@}TV!UN}3?9o@CS5kw zx%nXo%y|r5`YOWoZi#hE(3+rNKLZ2g5^(%Z99nSVt$2TeU2zD%$Q(=$Y;%@QyT5Rq zRI#b><}zztscQaTiFbsu2+%O~sd`L+oKYy5nkF4Co6p88i0pmJN9In`zg*Q;&u#uK zj#>lsuWWH14-2iG z&4w{6QN8h$(MWPNu84w1m{Qg0I31ra?jdyea*I~Xk(+A5bz{x%7+IL}vFDUI-Rf{! zE^&Dau9QxA2~)M98b42(D6Q}2PUum0%g>B?JS?o~VrP+Go2&c-7hIf7(@o1*7k$zS zy@o5MEe8DoX$Ie(%SZByyf9Xf9n8xkoX}s6RiO1sg*kAV^6EAAz$>*x^OmIy!*?1k zG+UQ|aIWDEl%)#;k{>-(w9UE7oKM#2AvQud}sby=D7$l6{$}SE8O9WgHM_+ zJ?tHeu@Pi93{AuwVF^)N(B~0?#V*6z;zY)wtgqF7Nx7?YQdD^s+f8T0_;mFV9r<+C z4^NloIJIir%}ptEpDk!z`l+B z5h(k$0bO$VV(i$E@(ngVG^YAjdieHWwMrz6DvNGM*ydHGU#ZG{HG5YGTT&SIqub@) z=U)hR_)Q@#!jck+V`$X5itp9&PGiENo(yT5>4erS<|Rh#mbCA^aO2rw+~zR&2N6XP z5qAf^((HYO2QQQu2j9fSF)#rRAwpbp+o=X>au|J5^|S@(vqun`du;1_h-jxJU-%v| z_#Q!izX;$3%BBE8Exh3ojXC?$Rr6>dqXlxIGF?_uY^Z#INySnWam=5dV`v_un`=G*{f$51(G`PfGDBJNJfg1NRT2&6E^sG%z8wZyv|Yuj z%#)h~7jGEI^U&-1KvyxIbHt2%zb|fa(H0~Qwk7ED&KqA~VpFtQETD^AmmBo54RUhi z=^Xv>^3L^O8~HO`J_!mg4l1g?lLNL$*oc}}QDeh!w@;zex zHglJ-w>6cqx3_lvZ_R#`^19smw-*WwsavG~LZUP@suUGz;~@Cj9E@nbfdH{iqCg>! zD7hy1?>dr^ynOw|2(VHK-*e%fvU0AoKxsmReM7Uy{qqUVvrYc5Z#FK&Z*XwMNJ$TJ zW1T**U1Vfvq1411ol1R?nE)y%NpR?4lVjqZL`J}EWT0m7r>U{2BYRVVzAQamN#wiT zu*A`FGaD=fz|{ahqurK^jCapFS^2e>!6hSQTh87V=OjzVZ}ShM3vHX+5IY{f^_uFp zIpKBGq)ildb_?#fzJWy)MLn#ov|SvVOA&2|y;{s;Ym4#as?M^K}L_g zDkd`3GR+CuH0_$s*Lm6j)6@N;L7Vo@R=W3~a<#VxAmM&W33LiEioyyVpsrtMBbON+ zX^#%iKHM;ueExK@|t3fX`R+vO(C zucU#Xf>OjSH0Kd%521=Sz%5Y!O(ug(?gRH@K>IUayFU~ntx`Wdm27dB-2s@)J=jf_ zjI-o;hKnjQ|Lg~GKX!*OHB69xvuDU zuG-H48~inKa)^r539a{F)OS`*4GShX>%BR)LU~a-|6+sx&FYsrS1}_b)xSNOzH|Kv zq>+1-cSc0`99EsUz(XWcoRO)|shn>TqKoQBHE)w8i8K`*Xy6(ls%WN_#d}YC^)NJ; zzl8!Zduz^Gg8*f0tCWnLEzw6k5Fv!QWC1x4)3r}+x~@#O8_)0>lP-@3(kFwLl%%Mz(TpATVnL5Pl2Gahw45QXI~>Hrw))CcEs@PP?}4^zkM$ z@(?H6^`Jl?A=(&Ue;W0`*a8&fR7vde@^q^AzX^H#gd~96`Ay^_A%?;?@q@t7l7iGn zWms#2J|To4;o1?3g3L!K_chdtmbEg~>U>$5{WO@Ip~YE&H($(^X6y_OBuNHkd0wu= z4rXGy#-@vZ?>M<_gpE8+W-{#ZJeAfgE#yIDSS?M?K(oY@A|FaS3P;OjMNOG% zGWyZWS(}LJCPaGi9=5b%sq$i!6x@o(G}wwfpI5|yJe24d_V}cT1{^(Qe$KEMZ;>I@ zuE6ee%FLgem>CKEN8SeY)fpK#>*lGcH~71)T4p|9jWT;vwM@N!gL}nCW=Oi6+_>K2 zl4sWXeM1U}RETA~hp=o3tCk+?Zwl#*QA>Wwd|FlUF0)U;rEGPD1s0Syluo zfW9L(F>q9li8YKwKXZrp*t)N9E;?&Hdbm-AZp2BcDTHO6q=tzVkZsozEIXjIH`tm} zo2-UleNm*Lj7zgvhBph_|1IggkSuW~S(9ueZEfao8BuzqlF(a+pRivTv(Zb zXFaHwcuovdM#d+!rjV7F<^VW&@}=5|xj!OUF)s0zh|8yzC)7!9CZB+TLnycoGBsDF z$u&j={5c(4A$iik;x6_S96Krw8--+9pGY+*oSVTIuq;$z8*)W8B~rMX_(U6uM}!Gc`T;WfEKwI84%)-e7j}>NA(O_)3Vn9 zjXxY1Fnx3Fx%CFpUHVu0xjvxgZv}F9@!vC!lD|05#ew3eJ}@!V&urwRKH`1f{0e^o zWvM1S@NbI6pHdzm33pza_q;#?s%J*$4>10uYi4l%5qi|j5qh+D=oqSJR=7QwkQh>>c$|uJ#Z@lK6PMHs@ zyvnnoOSkGQkYz#g>||xN&1fV)aJb*y--Y`UQV~lt!u8yTUG59ns1l7u>CX2F>9fl; zB)zH3z^XHmSU{F_jlvESvaNL&nj^;j)29~1LcTYw>(6}>bt0hiRooqm0@qTj%A&P9 zKmexPwyXG@Rs1i+8>AJ;=?&7RHC7Mn%nO>@+l?Qj~+lD376O2rp)>tlVHn8MKq zwop1KRLhUjZ|+6ecGIAftSPT*3i94=QzYCi_ay+5J&O(%^IsqZ!$w-^bmd7ds$^!q z;AkC;5mTAU>l0S$6NSyG30Ej?KPq@#T)^x#x?@U~fl2m$Ffk)s6u|iPr!)-j0BlA7p3E*A|My8S#KH;8i-IQq7Q*F4*ZVPe<{^SWz_ zr?!6cS+@|C#-P~d#=W1n7acn8_pg#W-lcyf+41zwR+BU6`jUkP^`*wgX)FxEaXzoi z8)?FE*97Yqz|b@fR1(r{QD363t260rQ(F||dt9^xABi+{C*_HL9Zt5T;fq|#*b}=K zo5yj_cZB(oydMAL&X(W6yKf>ui?!%(HhiHJ83EA|#k0hQ!gpVd( zVSqRR&ado+v4BP9mzamKtSsV<|0U-Fe2HP5{{x&K>NxWLIT+D^7md{%>D1Z-5lwS~ z6Q<1`Hfc+0G{4-84o-6dr@)>5;oTt|P6jt9%a43^wGCslQtONH)7QXJEYa!c~39 zWJpTL@bMYhtem1de>svLvOUa*DL7+Ah0(_~2|ng`!Z!qiN}6xL;F}<%M8qWv&52-Y zG*1A&ZKlp~{UFV%Hb_*Re({93f7W*jJZMV-Yn|<+l3SPN+%GuPl=+tSZxxr%?6SEc zntb0~hcK691wwxlQz_jSY+V_h+0o`X!Vm{;qYK$n?6ib1G{q>a%UejzOfk6q<=8oM z6Izkn2%JA2E)aRZbel(M#gI45(Fo^O=F=W26RA8Qb0X;m(IPD{^Wd|Q;#jgBg}e( z+zY(c!4nxoIWAE4H*_ReTm|0crMv8#RLSDwAv<+|fsaqT)3}g=|0_CJgxKZo7MhUiYc8Dy7B~kohCQ$O6~l#1*#v4iWZ=7AoNuXkkVVrnARx?ZW^4-%1I8 zEdG1%?@|KmyQ}tploH>5@&8Cp{`)CxVQOss&x|Z7@gGL3=tCVNDG!N9`&;N$gu^MDk|`rRm=lhnXAJ5v1T)WTz)qvz|Dw zR?{}W4VB(O6#9%o9Z^kFZZV*PDTAWqkQ8TH!rti8QIcR&>zcg3qG}&A( zwH^K8=`1C1lRfhrX{IvNn9R9!$UMC%k(;;VH%`S0h_on|Gh6qDSH&#}*m-u{;p~WB zF$_I~xx!RxVrxNQdr@3T>{F#^D{@N9OYC9LsV62F_Z1KYQ5yk*C5WQ4&q}Kz(I{9UWWf?LIcCZicB1EO_FUH*a9QKS(4IR%#D5DTi_@M}Q_-4)J4d zz@!vR0}5MPAOK(#uL+$7XOcP$5SS#*EK9Rt6XN%}HB7@`8S^gNRk!HLv(CvCjX4o= z>9scPwWbE!F8T=@x9^;s-OF2!eO(!gL9$-AmzUiDnu&QS4If5ea2T070n1-IyNhck z9$J8b!he3@q5qB-cQ;5ymVIXXn46kK0sqKZV+3s3^mac=3~BrCW})WNrrRs1KtMmg zLzwXYC?@_H#s3W4D$W0rh%WL|G<1$$uYdptPbxy0ke!c%v#x9I=2?S)YVkg1X$W^cB!i>B{e9wXlm8AcCT8|verIZQngj>{%W%~W0J%N`Q($h z^u3}p|HyHk?(ls7?R`a&&-q@R<94fI30;ImG3jARzFz<(!K|o9@lqB@Va+on`X2G) zegCM8$vvJ$kUwXlM8df|r^GQXr~2q*Zepf&Mc%kgWGTf;=Wx%7e{&KId-{G}r22lI zmq%L6Y-M*T$xf8 z#kWOBg2TF1cwcd{<$B)AZmD%h-a6>j z%I=|#ir#iEkj3t4UhHy)cRB$3-K12y!qH^1Z%g*-t;RK z6%Mjb*?GGROZSHSRVY1Ip=U_V%(GNfjnUkhk>q%&h!xjFvh69W8Mzg)7?UM=8VHS* zx|)6Ew!>6-`!L+uS+f0xLQC^brt2b(8Y9|5j=2pxHHlbdSN*J1pz(#O%z*W-5WSf# z6EW5Nh&r<;$<3o1b013?U$#Y!jXY)*QiGFt|M58sO45TBGPiHl4PKqZhJ|VRX=AOO zsFz-=3$~g#t4Ji9c;GFS9L~}~bzgCqnYuJ-60AMDdN7HZt8_$~Of{oXaD3HVn9zkH z`>#xQNe=YpWTq_LcOoy}R`L<_4il7w4)QH4rl?AUk%?fH##I>`1_mnp&=$-%SutYT zs}sSNMWo;(a&D()U$~PG0MvZ#1lmsF&^P4l_oN#_NORD-GSmR{h_NbJ^ZdY#R9#qW zKAC%V*?y~}V1Zh#d|-z1Z8sy5A+}*cOq$xk@Pn&{QffzG-9ReyPeEhqF%~Z3@|r(s z3(wA&)dV~fELW*&*=!~l9M=7wq8xE(<@)BjjN8bUiS8@N9E{wi+Dd!V1AtT;Nl}9> zTz`2ge2Jn#Dlg1kC%oFlOe<>?jYC`Asr^%i4hH;S`*qZTPRan2a9Kjj=0aq{iVi2Z z87PZt$d(LAm_{92kl+2Z%k3KGV;~gsp;C>k?gMYZrVIzaI|0D+fka9G_4v>N96*8T zI(C8bj?A7l%V&U?H_IpSeCvf7@y1e?b>G7cN382GVO0qAMQ93(T*<*9c_;%P1}x2l zi8S$s<=e_8ww%DaBAf4oIQ7}U7_48$eYpo}Fb+F|K|43IAPR1y9xbqPPg6er{I7xj|=>-c%pGBRLn1~=5KbAb1mJAx=z(loN!w{49VkEthF>*OX z)=gqXyZB5%5lIWYPWh~{!5pSt43-)-@L@x=pmiuKP-3Cwq8qSxGNwaTT4->BWEjxk zUjr)z7WrBZB5u3iV>Y_>*i~*!vRYL)iAh5hMqNzVq1eeq=&d9Ye!26jks{f~6Ru&c zg$D;^4ui#kC`rSxx`fP!zZ^6&qSneQzZRq0F*V4QvKYKB<9FC%t#)Tik%Zq*G*IOW z3*`2!4d)!3oH>GxVcXlorJDt+JnH)p{~olYBPq|>_V@8=l#(f*diW=L+%>rfWCcPQ z#H^ksQt15Z5Uc4ODq8_JwD5^H&OGqyH6E@MabJQO>s`?bqgA6}J_QpytW{2jH#eCN z8k7y*TFZ2lj2B|1CB(@QZedFfPhX|IQbKMI;$YK>9Zla0fsU7}an6(kP;sXpBWLR` zJ#z_kk!`JJC7h(1J!+G)gL2WB2&0*~Q!%s??}GH?=`hU@03xOwU} z6s7?tGySLz!%(MwxQRiF)2(vR2wQX`YB}u&I-S+RR)LQcyH407#-{*pWLJJR?X|5 zsAl2k{&0N-?JArn@)9YTo-5+gl}R~XkbZM*5AOjPrcikpE3P?p0oN^?H+5+n)}Qxe z*RQ!-eu0RxPyF8B=}xnseNpQMXFU$d^=(G%kUd&|!BHSm7bXoGR$WA+%yjuA{|S>u z?9N6JDhS+ui~rd?wY_t7`p)|qKIMM>6jz%$jv4hc_YUDjF6-%5muq|SNuoji2)|qK zNY5+oWMe+5vu{I*grk6xlVk;(J)uuy13G`VDbj(~Vz9lA)_;$aj?=-cmd#h~N0mn{ z9EIS_d4C=L3H;Pl^;vcpb&-B+)8vt%#?gn5z>#;G{1L&8u8cXJYADMUsm9>%*%)&F zsi&I{Y=VUsV82+)hdNgDWh^M7^hMs|TA0M269^|RIGfdX1MetV2z`Ycb&_Mn4iRI! zeI6O}O9mOhN6pzfs5IfMz#Gxl`C{(111okA8M4gijgb~5s7QTyh84zUiZZ^sr1^ps z1GO`$eOS@k@XP^OVH|8)n}Wx)fKHoGwL&5;W?qEf5Jdsd!3hf7L`%QNwN0gGBm^2= z@WI+qJMJG1w2AS9d@Dt$sj_P$+S2kh7+M72^SfcdBjQEtWQ5?PT&a~G9hOo6CtS>h zoghqoR;sk{X)`ZK-M|lu{M}0>Mrs^ZW@ngC?c$26_vYKDBK^n7sFiod_xV#XcPL!^ zRPyqD{w^9u{oA3y73IW0 zH;%xop$r(Q=bq=JaLT%myEKD_2&?L@s6TzsUwE#g^OkiU6{lN)(7I?%a;_%r5_^@d zS-Z)Q-2o|~?F~f`sHlhNhiZk;!CW;3Ma6{xPlBjJx8PXc!Oq{uTo$p*tyH~ka`g<` z;3?wLhLg5pfL)2bYZTd)jP%f+N7|vIi?c491#Kv57sE3fQh(ScM?+ucH2M>9Rqj?H zY^d!KezBk6rQ|p{^RNn2dRt(9)VN_j#O!3TV`AGl-@jbbBAW$!3S$LXS0xNMr}S%f z%K9x%MRp(D2uO90(0||EOzFc6DaLm((mCe9Hy2 z-59y8V)5(K^{B0>YZUyNaQD5$3q41j-eX))x+REv|TIckJ+g#DstadNn_l~%*RBSss_jV3XS&>yNBc8H2jo(lwcLz-PuYp< z7>)~}zl$Ts0+RFxnYj7-UMpmFcw_H zYrsXM>8icD)@Iauiu_(Y#~Iyl)|pj@kHkWvg2N$kGG(W>Y)nfNn%z2xvTLwk1O2GQ zb^5KAW?c%5;VM4RWBy}`JVCBFOGQWoA9|+bgn7^fY3tSk1MSZccs9&Fy6{8F>_K@? zK(z=zgmq1R#jGE^eGV`<`>SP9SEBx!_-Ao|VZq6)-rUpd^<2GgVN&uHiM{0zA9kI( z<1^1%*uE$?4mXV@?W8}fvnBOpfwCo^?(a0E402!pZi&Kd5pp$oV%2Ofx<}YC-1mynB3X|BzWC_ufrmaH1F&VrU&Gs+5>uixj*OJ*f=gs9VR8k^7HRR$Ns|DYBc*Slz>hGK5B1}U+}#j0{ohGC zE80>WClD5FP+nUS?1qa}ENOPb2`P4ccI<9j;k?hqEe|^#jE4gguHYz-$_BCovNqIb zMUrsU;Fq%n$Ku_wB{Ny>%(B&x9$pr=Anti@#U%DgKX|HzC^=21<5Fn6EKc#~g!Mcj zJrI(gW+aK+3BWVFPWEF*ntHX5;aabHqRgU-Nr2t++%JRPP7-6$XS|M8o&YSgf3a9A zLW*tSJxoe1?#T4EocApa*+1kUIgy7oA%Ig9n@)AdY%)p_FWgF-Kxx{6vta)2X1O5y z#+%KQlxETmcIz@64y`mrSk2Z17~}k1n{=>d#$AVMbp>_60Jc&$ILCg-DTN~kM8)#o$M#Fk~<10{bQ>_@gU2uZE z*eN~mqqQC*wh{CI(!xvRQ^{jyUcvE~8N)S0bMA^SK@v;b7|xUOi63X~3Qc>2UNSD1) z7moi9K3QN_iW5KmKH>1ijU41PO>BvA6f1;kL)6io%^r>?YQ#+bB;)Rzad5;{XAJGeAT#FnDV0$w2>v|JeFIB zZ>8vmz?WVs78PuCDiHfb@D0Yi;2#%){*#?bY4dpta6dSjquGLcOw?Z{nxg98mN^4* zj&^!WMUQ_zFp+}B|G0vcNsk8(2u9(LAPk5ogKt%zgQ4^1#UCd;`-W#X8v{YyQ_m9g z8`jydw>>@1J{Q*q#5^cHVA~xR9LR3Hl@^bx)`IBKmj+Gmye36;xwL0>sS|mV+$~%b zC;2wEm&Ht3#6P|2Y0XQ+5t-aI)jn{o%&ZHWvjzEtSojFgXxNKO^e(RmM`gsJ4GrR8 zKhBtBoRjnH`mD$kT;-8ttq|iw?*`7iTF_AX<^Qe3=h8L^tqz$w$#Z@Z$`C579Jeeu ztr0z~HEazU&htfG@`HW!201!N(70hCd{%~@Wv)G*uKnJZ8>hFx`9LnYs;T>8p!`5T zx#aXXU?}B{QTV_Ux(EMzDhl-a^y^f5tRU;xnOQoN)pThr4M>-HU)As8nQ34-0*sab&z<2ye-D_3m&Q`KJJ|ZEZbaDrE%j>yQ(LM#N845j zNYrP)@)md;&r5|;JA?<~l^<=F1VRGFM93c=6@MJ`tDO_7E7Ru zW{ShCijJ?yHl63Go)-YlOW2n3W*x%w||iw(Cy>@dBJHdQl){bBVg{wmRt{#oXb9kaWqe{bJPmGE$$ z_0=cmD9dVzh<8&oyM8rK9F^bufW$Bj2cFhw&f*oKKyu$H{PI=Aqe^NL6B=dkMEAk& zE3y&F=x;e|!7kMn%(UX>G!OE$Y$@UyME#d;#d+WLmm@W@y!sboiIox^DZPB|EN<>7 z57xm5YWlFUGyF|{<*;b&Cqm+|DC8{rB9R@2EFHGL^NX*l#AcDpw6}bCmhY7!(Gv{s zm^eYNvzyJLQA#GhmL*oSt^Uulb5&ZYBuGJTC>Vm9yGaZ=Vd--pMUoDRaV_^3hE9b*Pby#Ubl65U!VBm7sV}coY)m zn1Ag^jPPLT93J{wpK%>8TnkNp;=a@;`sA7{Q}JmmS1bEK5=d@hQEWl;k$9M-PYX~S zayGm;P(Wwk23}JR7XM~kNqba`6!Z+Wt2|5K>g_j3ajhR>+;HF?88GBN!P; zr6sQ8YYpn%r^gbi8yYK7qx6U5^Tf<|VfcR$jCo`$VMVh_&(9w@O?|o3eRHq*e*#P z8-==G)D?vB3Zo~b-dkx8lg0^=gn`9FUy?ZzAfWQd>>@cyqF!sHQ_S&@$r&tTB~Lxq zAjAZTK~?J{A|L3)8K>S{`Qf%131B>?<~t=w!D{;olQ>#31R#{go`a9DOy+H*q5t+; z^*Ka!r@#8tk?~tQbylaG-$n#wP2VzIm3vjrZjcmTL zl`{6mhBhMKbSWoGqi;g3z1@G0q!ib`(Zz_o8HG_*vr8U5G|vhZn26h`f~bO&)RY0; zw(CWk*a_{ji_=O9U}66lI` zCm32)SEcAo5)5k>{<8DLI@Zz)*R29BB!^wF;WZRF9sAi39BGObmZzg?$lUn6w1rYPHSB^L4^AN zLObEaUh7TXpt6)hWck#6AZV(2`lze<`urGFre|>LUF+j5;9z%=K@&BPXCM)P$>;Xc z!tRA4j0grcS%E!urO^lsH-Ey*XY4m&9lK(;gJOyKk*#l!y7$BaBC)xHc|3i~e^bpR zz5E-=BX_5n8|<6hLj(W67{mWk@Bfc){NGAX z5-O3SP^38wjh6dCEDLB#0((3`g4rl}@I(&E8V2yDB=wYhSxlxB4&!sRy>NTh#cVvv z=HyRrf9dVK&3lyXel+#=R6^hf`;lF$COPUYG)Bq4`#>p z@u%=$28dn8+?|u94l6)-ay7Z!8l*6?m}*!>#KuZ1rF??R@Zd zrRXSfn3}tyD+Z0WOeFnKEZi^!az>x zDgDtgv>Hk-xS~pZRq`cTQD(f=kMx3Mfm2AVxtR(u^#Ndd6xli@n1(c6QUgznNTseV z_AV-qpfQ0#ZIFIccG-|a+&{gSAgtYJ{5g!ane(6mLAs5z?>ajC?=-`a5p8%b*r*mOk}?)zMfus$+W~k z{Tmz9p5$wsX1@q`aNMukq-jREu;;A6?LA(kpRut+jX?Tt?}4HGQr}7>+8z4miohO2 zU4fQ?Y8ggl%cj&>+M+)TTjn8(?^%`~!oAt#ri8gIbzIig$y#d7o##077fM9sCu%N9 zOIsq4vyox6`itu*j{eOD<$gTZd-$JuyM^cM>{?v<8# zS1yN%R0zRy&>+D*Gv-&S80?JF+Y|c^^IJWDnfy06MI2{NFO-x4JXsb@3Qp;EnL!a{ zJwKwV@mO zYVGvNmeJ!;+ce+@j@oo-+`DaPJX|h@7@4BD`QEdP?NKkYzdIa3KrZt%VUSsR+{b+| zk?dSd#9NnVl?&Y$A{-OtZ>wk%mWVF5)bf`)AA2{EFapIS4jil69Xan>*J^6Juou&`oJx|7-&|@8z?$ z2V#jm!UHstCE*qM{OGtqYY8q+x%SL6&aGY!a>@d=_G~^0;+7dY9P`oJ*)67*9Kx*O zKitC5V3g5;&L-fa37?eN=;V_c^L-ph_uKv5)Q`&!Z!RPlDWA2{J%a2q@_*?-cn@bH zIt)+mA@HaJj2RV+-MNc#y#Vji*N~m!ZyrYyg-7UK4PYK4F7Y$3Y%@Lk6iPp=I96N> z!;ih(KtZMB23*v{`5cJ}^4D*P!k1&OfU&1%borv_q|7jfaV7fL+wwx8Zp*b}B_O>NRSeJeM zpvw3M`=vSYjFYQ11kx1xqOnJ@degPh&SyXnWz-l719EiW17Yo?c~Bh~;R$MOl+jzV zM1yTq-1**x-=AVR;p0;IPi`#=E!G5qIT>EFE`Bn<7o*8!aVd7?(CZT=U9^Gi3rmWUQG z0|GaP9s$^4t_oLCs!fInyCoB(d?=tZ%%Bb2Y+X&7gvQ6~C4kU%e$W_H;-%XSM;&*HYYnLI z>%{5x_RtSUC~PI4C0H^>O%FixKYVubA>#72wexd}Cgwuw5ZYTvcN2ywVP(dO=5975 zCjo)mOa2Bo&ucEsaq8wi1{h*brT(H=XrTOy*P>?0%VV1QDr09X+Je!T)JT`02?gjX zT@B8}h|;4lH35Guq2gKZT?ags-~Ts~S=poPnQ_T1*?U|{$jaur_PjQ6WmF_(XLFG)d#|iiBC=&B zp}1eOQvQ!3UpL?K`=8hAzMkv#a^COr`J8i}d!BPX&*xp-LL#qse~mOtxI-}{yPRNV zJNTL1{7A55F~K>0e&Os%MwQ~?n1>QV=j!8o_`^-&*E|Q-L9DNr%#6sw8kQVE3E|*}$aAoO$@27ei1w=+zU%?AA!;mf#!%IV*w_D=u516!Kz1F0-WnyVB`I6F1Pc3r1=0iT<_(pCyk>@22z1$w$@M>7AIuk6+ zRG&MFVQ_7>5DLoR5HeOa$?2SA(v2u!#8;5I(ss%=x9U#R zU62n~&)22RTTsp${}6C&$+l&0skFVX%ACgc$(iQ#DVRRz!`Y+b>E?;ib(TH#6Wa=} zs(q_;SA|fhyEo7Ix%rAY9j=Ul^Rzd`3ABf+yO@~h@Rh=wo`?;8PdHE1AUo34r7izy znAr`;VavQueSu7bD5r^nXTERcW(P-{2SOSfF1x0cW1Nczvj0}@!!upORN1%_-b2bh zGt#zokJz&SveJRzlUK4DruxR(YuHEAmB%F}buU`*pAzJ7Mbgs4sg;H@&6x*wxvGm6 z>KH@ilsvvdl@CGfm4T+$agodrB=md8ygG!|O=r@FY>S_zX%*)mqf?XBX*chhQ9uPP z-(T(24)})vWD*{bQM5_hy3CD8C>anuNtCXMkG7T?Yew^>=PK!~Hlr0{-0h0cNAJ8> zRMzLFz7aJv)Yh)_s)^L&L*nDV@qfeg>_<`z1z(?s}}3tE4h|7_taB> zPfmmOCFZ8%>`gyf1@|7t3;e~mwBRCDDw(Rrt>@O}obs#1?!W((+9>d$b7t!{&wR!P ziQbn0@j=&sw={`s##Uc@uS^(tbShjtsk=qrU1LW0lu}BplIfzv{fwxNsSaG~b|ryo zTQ}YXfp6o?^sSHW>s~m;l@h6wFbIPw{Z(IqO1u){{hEZgrTdF0o$n;hYIm`h5ejym zWt^w~#8p1J)FtfY6LvGmNQ~#n>4#mN4B^ zjrQk)Zt%k}GBRD>l`<~og6N_{6HYKDtsAtd%y?KbXCQR(sW8O(v_)kwYMz|(OW zsFz6A1^abSklOl`wLC-KYI8x=oMD^qZBs}}JVW@YY|3&k&IZ_n2Ia@5WiK>buV!E- zOsYcS4dFPE7vzj%_?5i2!XY`TiPd*jy>#C`i^XG8h?f35`=)s`0EhQBN!+YrXbpt( z-bwg_Jen`w<+6&B`hldU%rr&Xdgtze>rKuJ61AI12ja-eDZZX-+u1H>Sa|7pCine9 z&MEhmT7nq`P!pPK>l?I8cjuPpN<7(hqH~beChC*YMR+p;;@6#0j2k$=onUM`IXW3> z`dtX8`|@P|Ep-_0>)@&7@aLeg$jOd4G`eIW=^dQQ*^cgKeWAsSHOY?WEOsrtnG|^yeQ3lSd`pKAR}kzgIiEk@OvQb>DS*pGidh`E=BHYepHXbV)SV6pE2dx6 zkND~nK}2qjDVX3Z`H;2~lUvar>zT7u%x8LZa&rp7YH@n@GqQ65Cv+pkxI1OU6(g`b z?>)NcE7>j@p>V0mFk-5Rpi`W}oQ!tUU&Yn8m0OWYFj|~`?aVFOx;e`M)Q!YSokY)3 zV6l-;hK6?j=mp2#1e5cCn7P6n_7)n^+MdRw@5pvkOA>|&B8`QZ32|ynqaf}Kcdro= zzQchCYM0^)7$;m2iZnMbE$!}hwk&AVvN`iX3A9mB&`*BDmLV-m`OMvd`sJ?;%U`p~ zmwow{y6sPbcZNQPZ#GQS0&mzy?s%>_p>ZM|sCXVAUlST;rQ-3#Iu!-bpFSV4g7?-l zGfX>Z#hR+i;9B};^CO@7<<#MGFeY)SC&;a{!` zf;yaQo%{bjSa8KT~@?O$cK z(DGnm7w>cG1hH#*J%X}%Y%~+nLT*{aP08@l&Nu}>!-j|!8lSqt_xUNF+Y}SQmupyb zPua2PI;@1YaIsRF*knA^rJv84Tc=7?J2}!1kMfHSO$d$+PK*u?OI%=P7;`PHxMB0k zau~T0Wk)rPEGJ$NiXW~kfPA#m%Sr|7=$tHelF9A6rFLa$^g{6)8GSW*6}#~Zb^qk% zg=pLwC!SkY+&Gne((9`TCy`i`a#eCS{A2yMi>J>p*NS*!V~aAgK;wnSOHPULqzyj- z-q4BPXqXn))iRnMF*WZj17wUYjC!h43tI7uScHLf1|WJfA7^5O9`%lH>ga`cmpiz( zs|I8nTUD4?d{CQ-vwD!2uwGU_Ts&{1_mvqY`@A{j^b?n&WbPhb418NY1*Otz19`1w zc9rn?0e_*En&8?OWii89x+jaqRVzlL!QUCg^qU&+WERycV&1+fcsJ%ExEPjiQWRTU zCJpu*1dXyvrJJcH`+OKn7;q`X#@Gmy3U?5ZAV~mXjQhBJOCMw>o@2kznF>*?qOW;D z6!GTcM)P-OY-R`Yd>FeX%UyL%dY%~#^Yl!c42;**WqdGtGwTfB9{2mf2h@#M8YyY+!Q(4}X^+V#r zcZXYE$-hJyYzq%>$)k8vSQU` zIpxU*yy~naYp=IocRp5no^PeFROluibl( zmaKkWgSWZHn(`V_&?hM{%xl3TBWCcr59WlX6Q{j45)`A^-kUv4!qM=OdcwpsGB)l} z&-_U+8S8bQ!RDc&Y3~?w5NwLNstoUYqPYs(y+lj!HFqIZ7FA>WsxAE7vB=20K zn_&y{2)Uaw4b^NCFNhJXd&XrhA4E~zD7Ue7X^f98=&5!wn_r=6qAwDkd>g#2+*ahd zaV|_P_8e%jiHh7W;cl(d=&-r-C}_Ov?bts8s^rKUWQ|XkuW!ToSwe}Z{4|kl+q&&W zn%iW48c5*ft#*m)+xSps+j(B5bPh&u0&m6=@WgwBf_QfJJzg2Qdz89HwcV`5kZ#5z zw;W&H8>5R(>KRwvd0gh30wJHA>|2N(im;~wy1HTv_}Ue%qb)>5qL^$hIyPvoT(nk_<`7F;#nS8;q!cqKspvBc<%xMsQj*h|>`Z)F6LDxue@to))OIbs2X+zY2L9#2UNrR^)?c8&PFc?j*&Q-r|C%7a$)ZRQ->#|?rEj&M4spQfNt;J^ntwf(d+q;tt)C`d{*|t)czD4x-qw{Chm0vuKp8axqy5`Yz z1756|;JX1q(lEieR=uT;%havqflgv+`5i!Z`R}(JNV~&`x}I9Lmm;aB7Bnc^UC?>W zu)(J7@fs}pL=Y-4aLq&Z*lO$e^0(bOW z3gWbcvb^gjEfhV=6Lgu2aX{(zjq|NH*fSgm&kBj?6dFqD2MWk5@eHt@_&^ZTX$b?o}S<9BGaCZIm6Hz)Qkruacn!qv*>La|#%j*XFp(*;&v3h4 zcjPbZWzv|cOypb@XDnd}g%(@f7A>w2Nseo|{KdeVQu)mN=W=Q`N?ID%J_SXUr0Rl# z3X;tO*^?41^%c!H;ia@hX``kWS3TR|CJ4_9j-?l6RjC=n?}r&sr>m%58&~?$JJV6{ zDq5h#m4S_BPiibQQaPGg6LIHVCc`9w3^3ZVWP$n>p7 z5dIEH-W9e;$Id8>9?wh%WnWf>4^1U<%vn=<4oNFhVl9zVk+jn;WtQUQ)ZeEjKYy8C z3g#tIb28thR1nZdKrN}(r zJdy-Y3Rvr5D3D|msZbmE;FLePbiM0ZjwTIQQHk)8G+sB$iwmEa2kQv&9Vs9m#$_8j zNKz}(x$Wc(M)a9H-Pn?5(Lk-CmOS(&+EVLOfsiq>e3ru6P?Lp>FOwPt>0o=j8UyF^ zO{(vf#MGx^y~WaOKnt%I78s}60(O#jFx0^47^Ikh$QTar(Dg$c=0KR|rRD|6s zz?tEX0_=(Hm0jWl;QOu!-k)mV?^i(Etl=Lg-{ z0G}CBprLX60zgAUz-fS^&m#o;erEC5TU+mn_Wj(zL$zqMo!e`D>s7X&;E zFz}}}puI+c%xq0uTpWS3RBlIS2jH0)W(9FU1>6PLcj|6O>=y)l`*%P`6K4}U2p}a0 zvInj%$AmqzkNLy%azH|_f7x$lYxSG=-;7BViUN(&0HPUobDixM1RVBzWhv8LokKI2 zjDwvWu=S~8We)+K{oMd-_cuXNO&+{eUaA8Ope3MxME0?PD+0a)99N>WZ66*;sn(N++hjPyz5z0RC{- z$pcSs{|)~a_h?w)y}42A6fg|nRnYUjMaBqg=68&_K%h3eboQ=%i083nfIVZZ04qOp%d*)*hNJA_foPjiW z$1r8ZZiRSvJT3zhK>iR@8_+TTJ!tlNLdL`e0=yjzv3Ie80h#wSfS3$>DB!!@JHxNd z0Mvd0Vqq!zfDy$?goY+|h!e(n3{J2;Ag=b)eLq{F0W*O?j&@|882U5?hUVIw_v3aV8tMn`8jPa5pSxzaZe{z}z|}$zM$o=3-mQ0Zgd?ZtaI> zQVHP1W3v1lbw>|?z@2MO(Ex!5KybKQ@+JRAg1>nzpP-!@3!th3rV=o?eiZ~fQRWy_ zfA!U9^bUL+z_$VJI=ic;{epla<&J@W-QMPZm^kTQ8a^2TX^TDpza*^tOu!WZ=T!PT z+0lJ*HuRnNGobNk0PbPT?i;^h{&0u+-fejISNv#9&j~Ep2;dYspntgzwR6<$@0dTQ z!qLe3Ztc=Ozy!btCcx!G$U7FlBRe}-L(E|RpH%_gt4m_LJllX3!iRYJEPvxcJ>C76 zfBy0_zKaYn{3yG6@;}S&+BeJk5X}$Kchp<Ea-=>VDg&zi*8xM0-ya!{ zcDN@>%H#vMwugU&1KN9pqA6-?Q8N@Dz?VlJ3IDfz#i#_RxgQS*>K+|Q@bek+s7#Qk z(5NZ-4xs&$j)X=@(1(hLn)vPj&pP>Nyu)emQ1MW6)g0hqXa5oJ_slh@(5MMS4xnG= z{0aK#F@_p=e}FdAa3tEl!|+j?h8h`t0CvCmNU%dOwEq<+jmm-=n|r|G^7QX4N4o(v zPU!%%w(Cet)Zev3QA?;TMm_aEK!5(~Nc6pJlp|sQP@z%JI}f0_`u+rc`1Df^j0G&s ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/1.20.4/gradle/wrapper/gradle-wrapper.properties b/1.20.4/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..37aef8d --- /dev/null +++ b/1.20.4/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/1.20.4/gradlew b/1.20.4/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.20.4/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/1.20.4/gradlew.bat b/1.20.4/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.20.4/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/1.20.4/settings.gradle b/1.20.4/settings.gradle new file mode 100644 index 0000000..697dd5f --- /dev/null +++ b/1.20.4/settings.gradle @@ -0,0 +1,38 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + name = 'Sponge' + url = 'https://repo.spongepowered.org/repository/maven-public/' + } + maven { + name = 'Quilt' + url = 'https://maven.quiltmc.org/repository/release' + } + maven { + name = 'Minecraft Forge' + url = 'https://maven.minecraftforge.net/' + } + } +} + +dependencyResolutionManagement { + repositories { + maven { + name = "Fuzs Mod Resources" + url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" + } + } + versionCatalogs { + libs { + from("fuzs.sharedcatalogs:sharedcatalogs:${dependenciesVersionCatalog}") + } + } +} + +rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}-${dependenciesVersionCatalog.replaceAll("-v\\d+", "")}" +include("Common", "Fabric", "Forge") diff --git a/1.20/.idea/scopes/Fabric_sources.xml b/1.20/.idea/scopes/Fabric_sources.xml deleted file mode 100644 index 0448412..0000000 --- a/1.20/.idea/scopes/Fabric_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file diff --git a/1.20/.idea/scopes/Forge_sources.xml b/1.20/.idea/scopes/Forge_sources.xml deleted file mode 100644 index 7b5f24d..0000000 --- a/1.20/.idea/scopes/Forge_sources.xml +++ /dev/null @@ -1,3 +0,0 @@ - - - \ No newline at end of file From dfbc03b491c1744f7373188b8e2eb2f09ea0c2fd Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 24 Jan 2024 23:16:33 +0100 Subject: [PATCH 09/24] full 1.20.4 port --- 1.20.1/CHANGELOG.md | 4 + .../screens/inventory/TradingPostScreen.java | 1 + 1.20.1/gradle.properties | 2 +- 1.20.4/CHANGELOG.md | 18 ++- 1.20.4/Common/build.gradle | 7 +- .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 + .../50b16d832771f8a8317f4d1b88c5121208c8c4f9 | 2 + .../77038cb024c5999ce280bcb6800e72cf1c655fe7 | 3 + .../9e953cc4ec64c82f6e78f1ad2800a952d804eb06 | 2 + .../9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e | 3 + .../dc1d6e7286e7569a79007c10f809d49635ea1c49 | 2 + .../tradingpost/blockstates/trading_post.json | 2 +- .../assets/tradingpost/lang/en_us.json | 3 +- .../tradingpost/models/item/trading_post.json | 3 + .../minecraft/tags/blocks/mineable/axe.json | 3 +- .../recipes/decorations/trading_post.json | 34 ++++++ .../loot_tables/blocks/trading_post.json | 24 ++-- .../tradingpost/recipes/trading_post.json | 21 ++-- .../tags/entity_types/concealed_traders.json | 3 + .../java/fuzs/tradingpost/TradingPost.java | 15 ++- .../tradingpost/client/TradingPostClient.java | 31 ++--- .../screens/inventory/TradingPostScreen.java | 115 ++++++------------ .../blockentity/TradingPostRenderer.java | 8 +- .../data/ModBlockLootProvider.java | 16 +++ .../tradingpost/data/ModBlockTagProvider.java | 19 +++ .../data/ModEntityTypeTagProvider.java | 18 +++ .../tradingpost/data/ModRecipeProvider.java | 30 +++++ .../data/client/ModLanguageProvider.java | 23 ++++ .../data/client/ModModelProvider.java | 18 +++ .../fuzs/tradingpost/init/ModRegistry.java | 18 +-- .../network/S2CBuildOffersMessage.java | 3 +- .../world/entity/npc/MerchantCollection.java | 4 +- .../world/inventory/TradingPostMenu.java | 21 ++-- .../world/level/block/TradingPostBlock.java | 85 +++++++------ .../block/entity/TradingPostBlockEntity.java | 60 ++++----- .../main/resources/architectury.common.json | 3 + .../tradingpost/models/item/trading_post.json | 3 - .../container/villager}/magnifying_glass.png | Bin ....common.mixins.json => common.mixins.json} | 4 +- .../entity_types/blacklisted_traders.json | 5 - 1.20.4/Common/src/main/resources/pack.mcmeta | 4 +- .../main/resources/tradingpost.accesswidener | 1 + 1.20.4/Fabric/build.gradle | 12 +- .../{ => fabric}/TradingPostFabric.java | 3 +- .../client/TradingPostFabricClient.java | 3 +- .../mixin/ModMixinConfigPlugin.java | 47 ------- .../src/main/resources/fabric.mixins.json | 13 ++ .../Fabric/src/main/resources/fabric.mod.json | 5 +- 1.20.4/Forge/build.gradle | 26 +--- 1.20.4/Forge/gradle.properties | 1 + .../178bb4356f8bea3c4b8966704e26df58ba8fa865 | 2 - .../assets/minecraft/atlases/blocks.json | 8 -- .../fuzs/tradingpost/TradingPostForge.java | 33 ----- .../data/ModSpriteSourceProvider.java | 22 ---- .../tradingpost/forge/TradingPostForge.java | 17 +++ .../forge}/client/TradingPostForgeClient.java | 3 +- .../mixin/ModMixinConfigPlugin.java | 47 ------- .../src/main/resources/META-INF/mods.toml | 77 +++++++----- .../src/main/resources/forge.mixins.json | 13 ++ 1.20.4/NeoForge/build.gradle | 26 +--- 1.20.4/NeoForge/gradle.properties | 1 + .../178bb4356f8bea3c4b8966704e26df58ba8fa865 | 2 - .../assets/minecraft/atlases/blocks.json | 8 -- .../fuzs/tradingpost/TradingPostForge.java | 33 ----- .../data/ModSpriteSourceProvider.java | 22 ---- .../mixin/ModMixinConfigPlugin.java | 47 ------- .../neoforge/TradingPostNeoForge.java | 25 ++++ .../client/TradingPostNeoForgeClient.java} | 13 +- .../src/main/resources/META-INF/mods.toml | 75 +++++++----- .../src/main/resources/neoforge.mixins.json | 13 ++ 1.20.4/build.gradle | 11 +- 1.20.4/gradle.properties | 29 +++-- .../gradle/wrapper/gradle-wrapper.properties | 2 +- 1.20.4/settings.gradle | 37 +----- 74 files changed, 619 insertions(+), 700 deletions(-) create mode 100644 1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 create mode 100644 1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 create mode 100644 1.20.4/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 create mode 100644 1.20.4/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 create mode 100644 1.20.4/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e create mode 100644 1.20.4/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 rename 1.20.4/Common/src/{main => generated}/resources/assets/tradingpost/blockstates/trading_post.json (97%) rename 1.20.4/Common/src/{main => generated}/resources/assets/tradingpost/lang/en_us.json (85%) create mode 100644 1.20.4/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json rename 1.20.4/Common/src/{main => generated}/resources/data/minecraft/tags/blocks/mineable/axe.json (69%) create mode 100644 1.20.4/Common/src/generated/resources/data/tradingpost/advancements/recipes/decorations/trading_post.json rename 1.20.4/Common/src/{main => generated}/resources/data/tradingpost/loot_tables/blocks/trading_post.json (51%) rename 1.20.4/Common/src/{main => generated}/resources/data/tradingpost/recipes/trading_post.json (81%) create mode 100644 1.20.4/Common/src/generated/resources/data/tradingpost/tags/entity_types/concealed_traders.json create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java create mode 100644 1.20.4/Common/src/main/resources/architectury.common.json delete mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json rename 1.20.4/Common/src/main/resources/assets/tradingpost/textures/{item => gui/sprites/container/villager}/magnifying_glass.png (100%) rename 1.20.4/Common/src/main/resources/{tradingpost.common.mixins.json => common.mixins.json} (72%) delete mode 100644 1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json create mode 100644 1.20.4/Common/src/main/resources/tradingpost.accesswidener rename 1.20.4/Fabric/src/main/java/fuzs/tradingpost/{ => fabric}/TradingPostFabric.java (80%) rename 1.20.4/Fabric/src/main/java/fuzs/tradingpost/{ => fabric}/client/TradingPostFabricClient.java (80%) delete mode 100644 1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Fabric/src/main/resources/fabric.mixins.json create mode 100644 1.20.4/Forge/gradle.properties delete mode 100644 1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 delete mode 100644 1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json delete mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java delete mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java rename 1.20.4/{NeoForge/src/main/java/fuzs/tradingpost => Forge/src/main/java/fuzs/tradingpost/forge}/client/TradingPostForgeClient.java (87%) delete mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Forge/src/main/resources/forge.mixins.json create mode 100644 1.20.4/NeoForge/gradle.properties delete mode 100644 1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 delete mode 100644 1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json delete mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java delete mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java delete mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java rename 1.20.4/{Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java => NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java} (55%) create mode 100644 1.20.4/NeoForge/src/main/resources/neoforge.mixins.json diff --git a/1.20.1/CHANGELOG.md b/1.20.1/CHANGELOG.md index d0f42b1..8789b77 100644 --- a/1.20.1/CHANGELOG.md +++ b/1.20.1/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.2-1.20.1] - 2024-01-24 +### Fix +- Fix unable to click on search box to select + ## [v8.0.1-1.20.1] - 2023-07-13 ### Fixed - Fixed Mixin config plugin being configured incorrectly on Fabric diff --git a/1.20.1/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java index 58d8d8a..31f11f5 100644 --- a/1.20.1/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java +++ b/1.20.1/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -301,6 +301,7 @@ private void renderSearchBox(GuiGraphics guiGraphics, float partialTicks, int mo @Override public boolean mouseClicked(double mouseX, double mouseY, int mouseKey) { if (this.searchBox.mouseClicked(mouseX, mouseY, mouseKey)) { + this.searchBox.setFocused(true); return true; } return super.mouseClicked(mouseX, mouseY, mouseKey); diff --git a/1.20.1/gradle.properties b/1.20.1/gradle.properties index 75109d0..105cdc7 100755 --- a/1.20.1/gradle.properties +++ b/1.20.1/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=8.0.1 +modVersion=8.0.2 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modLicense=MPL-2.0 diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index d0f42b1..3cbbf65 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -1,13 +1,11 @@ # Changelog All notable changes to this project will be documented in this file. -The format is based on [Keep a Changelog]. - -## [v8.0.1-1.20.1] - 2023-07-13 -### Fixed -- Fixed Mixin config plugin being configured incorrectly on Fabric - -## [v8.0.0-1.20.1] - 2023-06-27 -- Ported to Minecraft 1.20.1 - -[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v20.4.0-1.20.4] - 2024-01-24 +- Ported to Minecraft 1.20.4 +- Ported to NeoForge +### Fix +- Fix unable to click on search box to select diff --git a/1.20.4/Common/build.gradle b/1.20.4/Common/build.gradle index 949b426..13b80d3 100644 --- a/1.20.4/Common/build.gradle +++ b/1.20.4/Common/build.gradle @@ -1,11 +1,10 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/common.gradle" dependencies { // Puzzles Lib modApi libs.puzzleslib.common } -// @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 -tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).each { - it.targetNamespace = "named" +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).configureEach { + targetNamespace = "named" } diff --git a/1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 new file mode 100644 index 0000000..bacc607 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -0,0 +1,2 @@ +// 1.20.4 2024-01-24T22:24:15.874424 Language (en_us) +147b78684226f399eeac6159d3fa21f598f5ec2b assets/tradingpost/lang/en_us.json diff --git a/1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 b/1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 new file mode 100644 index 0000000..679a1f9 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 @@ -0,0 +1,2 @@ +// 1.20.4 2024-01-24T22:24:15.873951 Tags for minecraft:block mod id vanilla +e37ec5e3a6ed0926dc1d26eb5ad2e1873593f360 data/minecraft/tags/blocks/mineable/axe.json diff --git a/1.20.4/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 b/1.20.4/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 new file mode 100644 index 0000000..eb91da7 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 @@ -0,0 +1,3 @@ +// 1.20.4 2024-01-24T22:24:15.874265 Model Definitions +744a7fd8de66b44ea6012a51eb661120ebc8425e assets/tradingpost/blockstates/trading_post.json +cb2e625aee94c9cf690c12865dbd70b3ca956fb5 assets/tradingpost/models/item/trading_post.json diff --git a/1.20.4/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 b/1.20.4/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 new file mode 100644 index 0000000..9325470 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 @@ -0,0 +1,2 @@ +// 1.20.4 2024-01-24T22:24:15.874126 Tags for minecraft:entity_type mod id vanilla +35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/tradingpost/tags/entity_types/concealed_traders.json diff --git a/1.20.4/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/1.20.4/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e new file mode 100644 index 0000000..6cbed6e --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -0,0 +1,3 @@ +// 1.20.4 2024-01-24T22:24:15.874545 Recipes +18ab7e30d3db73a41a3e52c4dc419c21b7001bc7 data/tradingpost/advancements/recipes/decorations/trading_post.json +9817fabcf446177d2837f82610585da24bb4586a data/tradingpost/recipes/trading_post.json diff --git a/1.20.4/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 b/1.20.4/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 new file mode 100644 index 0000000..3aeba04 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 @@ -0,0 +1,2 @@ +// 1.20.4 2024-01-24T22:24:15.87298 Block Loot Tables +ede38073af8a425c53fa810881defe08a8cd025c data/tradingpost/loot_tables/blocks/trading_post.json diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json b/1.20.4/Common/src/generated/resources/assets/tradingpost/blockstates/trading_post.json similarity index 97% rename from 1.20.4/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json rename to 1.20.4/Common/src/generated/resources/assets/tradingpost/blockstates/trading_post.json index 9ae1fe4..f9d843d 100644 --- a/1.20.4/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json +++ b/1.20.4/Common/src/generated/resources/assets/tradingpost/blockstates/trading_post.json @@ -4,4 +4,4 @@ "model": "tradingpost:block/trading_post" } } -} +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/en_us.json b/1.20.4/Common/src/generated/resources/assets/tradingpost/lang/en_us.json similarity index 85% rename from 1.20.4/Common/src/main/resources/assets/tradingpost/lang/en_us.json rename to 1.20.4/Common/src/generated/resources/assets/tradingpost/lang/en_us.json index 1722313..55eb8e1 100644 --- a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/en_us.json +++ b/1.20.4/Common/src/generated/resources/assets/tradingpost/lang/en_us.json @@ -2,6 +2,5 @@ "block.tradingpost.trading_post": "Trading Post", "container.trading_post": "Trading Post", "trading_post.no_trader_found": "Couldn't find any available trader nearby", - "trading_post.trader_gone": "The trader is no longer available.", - "trading_post.search": "Search..." + "trading_post.trader_gone": "The trader is no longer available." } \ No newline at end of file diff --git a/1.20.4/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json b/1.20.4/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json new file mode 100644 index 0000000..ad10a89 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json @@ -0,0 +1,3 @@ +{ + "parent": "tradingpost:block/trading_post" +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json b/1.20.4/Common/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json similarity index 69% rename from 1.20.4/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json rename to 1.20.4/Common/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json index 1a49ae7..bee9214 100644 --- a/1.20.4/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json +++ b/1.20.4/Common/src/generated/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -1,6 +1,5 @@ { - "replace": false, "values": [ "tradingpost:trading_post" ] -} +} \ No newline at end of file diff --git a/1.20.4/Common/src/generated/resources/data/tradingpost/advancements/recipes/decorations/trading_post.json b/1.20.4/Common/src/generated/resources/data/tradingpost/advancements/recipes/decorations/trading_post.json new file mode 100644 index 0000000..19efbc7 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/data/tradingpost/advancements/recipes/decorations/trading_post.json @@ -0,0 +1,34 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_emerald": { + "conditions": { + "items": [ + { + "items": [ + "minecraft:emerald" + ] + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "tradingpost:trading_post" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_emerald" + ] + ], + "rewards": { + "recipes": [ + "tradingpost:trading_post" + ] + } +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json b/1.20.4/Common/src/generated/resources/data/tradingpost/loot_tables/blocks/trading_post.json similarity index 51% rename from 1.20.4/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json rename to 1.20.4/Common/src/generated/resources/data/tradingpost/loot_tables/blocks/trading_post.json index 3cfa463..c14bf1d 100644 --- a/1.20.4/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json +++ b/1.20.4/Common/src/generated/resources/data/tradingpost/loot_tables/blocks/trading_post.json @@ -2,18 +2,26 @@ "type": "minecraft:block", "pools": [ { - "rolls": 1, + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], "entries": [ { "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_name", + "source": "block_entity" + } + ], "name": "tradingpost:trading_post" } ], - "conditions": [ - { - "condition": "minecraft:survives_explosion" - } - ] + "rolls": 1.0 } - ] -} + ], + "random_sequence": "tradingpost:blocks/trading_post" +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/data/tradingpost/recipes/trading_post.json b/1.20.4/Common/src/generated/resources/data/tradingpost/recipes/trading_post.json similarity index 81% rename from 1.20.4/Common/src/main/resources/data/tradingpost/recipes/trading_post.json rename to 1.20.4/Common/src/generated/resources/data/tradingpost/recipes/trading_post.json index 2d26369..d8b58d9 100644 --- a/1.20.4/Common/src/main/resources/data/tradingpost/recipes/trading_post.json +++ b/1.20.4/Common/src/generated/resources/data/tradingpost/recipes/trading_post.json @@ -1,22 +1,23 @@ { - "type": "crafting_shaped", - "pattern": [ - " X ", - "###", - "S S" - ], + "type": "minecraft:crafting_shaped", + "category": "misc", "key": { "#": { "tag": "minecraft:planks" }, - "X": { - "item": "minecraft:emerald" - }, "S": { "item": "minecraft:stick" + }, + "X": { + "item": "minecraft:emerald" } }, + "pattern": [ + " X ", + "###", + "S S" + ], "result": { "item": "tradingpost:trading_post" } -} +} \ No newline at end of file diff --git a/1.20.4/Common/src/generated/resources/data/tradingpost/tags/entity_types/concealed_traders.json b/1.20.4/Common/src/generated/resources/data/tradingpost/tags/entity_types/concealed_traders.json new file mode 100644 index 0000000..f72d209 --- /dev/null +++ b/1.20.4/Common/src/generated/resources/data/tradingpost/tags/entity_types/concealed_traders.json @@ -0,0 +1,3 @@ +{ + "values": [] +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java index 333c896..8a3e329 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java @@ -4,7 +4,6 @@ import fuzs.puzzleslib.api.core.v1.ModConstructor; import fuzs.puzzleslib.api.core.v1.context.BuildCreativeModeTabContentsContext; import fuzs.puzzleslib.api.core.v1.context.FuelBurnTimesContext; -import fuzs.puzzleslib.api.network.v2.MessageDirection; import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; import fuzs.tradingpost.config.ServerConfig; import fuzs.tradingpost.init.ModRegistry; @@ -22,7 +21,7 @@ public class TradingPost implements ModConstructor { public static final String MOD_NAME = "Trading Post"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID); + public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID, false); public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).server(ServerConfig.class); @Override @@ -32,22 +31,22 @@ public void onConstructMod() { } private static void registerMessages() { - NETWORK.register(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new, MessageDirection.TO_CLIENT); - NETWORK.register(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new, MessageDirection.TO_CLIENT); - NETWORK.register(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new, MessageDirection.TO_CLIENT); - NETWORK.register(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new, MessageDirection.TO_SERVER); + NETWORK.registerClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new); + NETWORK.registerClientbound(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new); + NETWORK.registerClientbound(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new); + NETWORK.registerServerbound(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new); } @Override public void onBuildCreativeModeTabContents(BuildCreativeModeTabContentsContext context) { context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (itemDisplayParameters, output) -> { - output.accept(ModRegistry.TRADING_POST_ITEM.get()); + output.accept(ModRegistry.TRADING_POST_ITEM.value()); }); } @Override public void onRegisterFuelBurnTimes(FuelBurnTimesContext context) { - context.registerFuel(300, ModRegistry.TRADING_POST_BLOCK.get()); + context.registerFuel(300, ModRegistry.TRADING_POST_BLOCK.value()); } public static ResourceLocation id(String path) { diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java index 5c4c211..f459e21 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -1,36 +1,29 @@ package fuzs.tradingpost.client; +import fuzs.puzzleslib.api.client.core.v1.ClientAbstractions; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; -import fuzs.puzzleslib.api.client.core.v1.context.SearchRegistryContext; -import fuzs.puzzleslib.api.core.v1.context.ModLifecycleContext; +import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; import fuzs.tradingpost.client.renderer.blockentity.TradingPostRenderer; import fuzs.tradingpost.init.ModRegistry; import net.minecraft.ChatFormatting; -import net.minecraft.client.gui.screens.MenuScreens; import net.minecraft.client.searchtree.FullTextSearchTree; +import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.trading.MerchantOffer; import java.util.stream.Stream; public class TradingPostClient implements ClientModConstructor { - @Override - public void onClientSetup(ModLifecycleContext context) { - MenuScreens.register(ModRegistry.TRADING_POST_MENU_TYPE.get(), TradingPostScreen::new); - } + public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); @Override - public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { - context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), TradingPostRenderer::new); - } - - @Override - public void onRegisterSearchTrees(SearchRegistryContext context) { - context.registerSearchTree(TradingPostScreen.OFFER_SEARCH_TREE, base -> new FullTextSearchTree<>(offer -> + public void onClientSetup() { + ClientAbstractions.INSTANCE.getSearchRegistry().register(OFFER_SEARCH_TREE, base -> new FullTextSearchTree<>(offer -> Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) .filter(itemStack -> !itemStack.isEmpty()) .flatMap(itemStack -> itemStack.getTooltipLines(null, TooltipFlag.Default.NORMAL).stream()) @@ -43,4 +36,14 @@ public void onRegisterSearchTrees(SearchRegistryContext context) { base )); } + + @Override + public void onRegisterMenuScreens(MenuScreensContext context) { + context.registerMenuScreen(ModRegistry.TRADING_POST_MENU_TYPE.value(), TradingPostScreen::new); + } + + @Override + public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { + context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(), TradingPostRenderer::new); + } } diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java index 58d8d8a..7a9ddf1 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -1,66 +1,63 @@ package fuzs.tradingpost.client.gui.screens.inventory; -import com.mojang.blaze3d.platform.InputConstants; import com.mojang.blaze3d.systems.RenderSystem; import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.client.TradingPostClient; import fuzs.tradingpost.mixin.client.accessor.ButtonAccessor; import fuzs.tradingpost.mixin.client.accessor.MerchantScreenAccessor; import fuzs.tradingpost.mixin.client.accessor.TradeOfferButtonAccessor; import fuzs.tradingpost.network.client.C2SClearSlotsMessage; import fuzs.tradingpost.world.inventory.TradingPostMenu; import fuzs.tradingpost.world.item.trading.TradingPostOffers; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; import net.minecraft.client.Minecraft; import net.minecraft.client.gui.GuiGraphics; import net.minecraft.client.gui.components.Button; import net.minecraft.client.gui.components.EditBox; -import net.minecraft.client.gui.components.Renderable; import net.minecraft.client.gui.screens.inventory.MerchantScreen; import net.minecraft.client.renderer.GameRenderer; -import net.minecraft.client.renderer.texture.TextureAtlasSprite; -import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.client.searchtree.SearchTree; import net.minecraft.network.chat.Component; import net.minecraft.network.protocol.game.ServerboundSelectTradePacket; import net.minecraft.resources.ResourceLocation; import net.minecraft.world.entity.player.Inventory; -import net.minecraft.world.inventory.InventoryMenu; import net.minecraft.world.inventory.MerchantMenu; import net.minecraft.world.inventory.Slot; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.world.item.trading.MerchantOffers; -import java.util.List; import java.util.Locale; import java.util.Objects; public class TradingPostScreen extends MerchantScreen { - public static final ResourceLocation MAGNIFYING_GLASS_LOCATION = new ResourceLocation(TradingPost.MOD_ID, "item/magnifying_glass"); - public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); - private static final ResourceLocation VILLAGER_LOCATION = new ResourceLocation("textures/gui/container/villager2.png"); + public static final ResourceLocation MAGNIFYING_GLASS_LOCATION = TradingPost.id("container/villager/magnifying_glass"); + private static final ResourceLocation VILLAGER_LOCATION = new ResourceLocation("textures/gui/container/villager.png"); + private static final ResourceLocation OUT_OF_STOCK_SPRITE = new ResourceLocation("container/villager/out_of_stock"); + private static final ResourceLocation DISCOUNT_STRIKETHRUOGH_SPRITE = new ResourceLocation("container/villager/discount_strikethrough"); private static final ResourceLocation CREATIVE_INVENTORY_LOCATION = new ResourceLocation("textures/gui/container/creative_inventory/tab_item_search.png"); - private static final Component DEPRECATED_TOOLTIP = Component.translatable("merchant.deprecated"); - private static final Component MERCHANT_GONE = Component.translatable("trading_post.trader_gone"); + public static final Component DEPRECATED_TRADE_COMPONENT = Component.translatable("merchant.deprecated"); + public static final Component MERCHANT_UNAVAILABLE_COMPONENT = Component.translatable("trading_post.trader_gone"); private Button[] tradeOfferButtons = new Button[7]; private EditBox searchBox; private boolean ignoreTextInput; public TradingPostScreen(MerchantMenu container, Inventory playerInventory, Component title) { - super(container, playerInventory, title); } @Override protected void init() { super.init(); - this.tradeOfferButtons = this.getTradeOfferButtons(this.renderables); + this.tradeOfferButtons = this.renderables.stream().filter(Button.class::isInstance).limit(7).map(Button.class::cast).toArray(Button[]::new); + Objects.checkIndex(6, this.tradeOfferButtons.length); for (Button tradeOfferButton : this.tradeOfferButtons) { ((ButtonAccessor) tradeOfferButton).tradingpost$setOnPress(button -> { MerchantScreenAccessor accessor = (MerchantScreenAccessor) this; - final int shopItem = ((TradeOfferButtonAccessor) button).tradingpost$getIndex() + accessor.tradingpost$getScrollOff(); + int shopItem = ((TradeOfferButtonAccessor) button).tradingpost$getIndex() + accessor.tradingpost$getScrollOff(); MerchantOffers offers = this.getMenu().getOffers(); accessor.tradingpost$setShopItem(shopItem); this.getMenu().setSelectionHint(shopItem); @@ -71,38 +68,19 @@ protected void init() { }); } - this.searchBox = new EditBox(this.font, this.leftPos + 13, this.topPos + 6, 80, 9, Component.translatable("itemGroup.search")) { - @Override - public boolean mouseClicked(double mouseX, double mouseY, int button) { - // left click clears text - if (this.isVisible() && button == InputConstants.MOUSE_BUTTON_RIGHT) { - this.setValue(""); - TradingPostScreen.this.refreshSearchResults(); - } - return super.mouseClicked(mouseX, mouseY, button); - } - }; + this.searchBox = new EditBox(this.font, this.leftPos + 13, this.topPos + 6, 80, 9, TradingPostBlockEntity.CONTAINER_COMPONENT); this.searchBox.setMaxLength(50); this.searchBox.setBordered(false); this.searchBox.setTextColor(16777215); this.addWidget(this.searchBox); } - private Button[] getTradeOfferButtons(List buttons) { - Button[] tradeOfferButtons = buttons.stream().filter(button -> button instanceof TradeOfferButtonAccessor).map(button -> (Button) button).toArray(Button[]::new); - if (tradeOfferButtons.length != 7) { - TradingPost.LOGGER.warn("Unable to find enough tradeOfferButtons"); - } - return tradeOfferButtons; - } - @Override - public void resize(Minecraft mc, int newWidth, int newHeight) { - final String lastSearch = this.searchBox.getValue(); - super.resize(mc, newWidth, newHeight); + public void resize(Minecraft minecraft, int width, int height) { + String lastSearch = this.searchBox.getValue(); + super.resize(minecraft, width, height); this.searchBox.setValue(lastSearch); if (!this.searchBox.getValue().isEmpty()) { - this.refreshSearchResults(); } } @@ -128,8 +106,8 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia MerchantOffers merchantoffers = this.getMenu().getOffers(); this.setButtonsActive(merchantoffers); - final int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); - final Slot hoveredSlot = this.hoveredSlot; + int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); + Slot hoveredSlot = this.hoveredSlot; // set offers to empty to prevent MerchantScreen::render code from running, also disabled buttons drawing tooltips by changing scrollOff, as well as tooltip for hovered slot by removing hovered slot this.lock(true, merchantoffers.size(), null); super.render(guiGraphics, mouseX, mouseY, partialTime); @@ -139,23 +117,21 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia if (!merchantoffers.isEmpty()) { // normally rendered as part of background, but skipped as offers are empty when it's called - final int shopItem = ((MerchantScreenAccessor) this).tradingpost$getShopItem(); - if (shopItem >= 0 && shopItem < merchantoffers.size()) { + int shopItemIndex = ((MerchantScreenAccessor) this).tradingpost$getShopItem(); + if (shopItemIndex >= 0 && shopItemIndex < merchantoffers.size()) { - MerchantOffer merchantoffer = merchantoffers.get(shopItem); + MerchantOffer merchantoffer = merchantoffers.get(shopItemIndex); if (merchantoffer.isOutOfStock()) { RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); - guiGraphics.blit(VILLAGER_LOCATION, this.leftPos + 83 + 99, this.topPos + 35, 0, 311.0F, 0.0F, 28, 21, 512, 256); + guiGraphics.blitSprite(OUT_OF_STOCK_SPRITE, this.leftPos + 83 + 99, this.topPos + 35, 0, 28, 21); } } - final int width = (this.width - this.imageWidth) / 2; - final int height = (this.height - this.imageHeight) / 2; - int posX = width + 5; - int posY = height + 16 + 2; + int posX = this.leftPos + 5; + int posY = this.topPos + 16 + 2; RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); - ((MerchantScreenAccessor) this).tradingpost$callRenderScroller(guiGraphics, width, height, merchantoffers); + ((MerchantScreenAccessor) this).tradingpost$callRenderScroller(guiGraphics, this.leftPos, this.topPos, merchantoffers); for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { @@ -163,7 +139,7 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia MerchantOffer merchantoffer = merchantoffers.get(i); // move this call here to render below red overlay - ((MerchantScreenAccessor) this).tradingpost$callRenderButtonArrows(guiGraphics, merchantoffer, width, posY + 1); + ((MerchantScreenAccessor) this).tradingpost$callRenderButtonArrows(guiGraphics, merchantoffer, this.leftPos, posY + 1); if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { guiGraphics.fill(posX, posY, posX + 88, posY + 20, 822018048); @@ -197,18 +173,18 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia } } - final MerchantOffer activeOffer = merchantoffers.get(shopItem); + MerchantOffer activeOffer = merchantoffers.get(shopItemIndex); if (this.getMenu().showProgressBar()) { - ((MerchantScreenAccessor) this).tradingpost$callRenderProgressBar(guiGraphics, width, height, activeOffer); + ((MerchantScreenAccessor) this).tradingpost$callRenderProgressBar(guiGraphics, this.leftPos, this.topPos, activeOffer); } if (activeOffer.isOutOfStock() && this.isHovering(186, 35, 22, 21, mouseX, mouseY) && this.getMenu().canRestock()) { - guiGraphics.renderTooltip(this.font, DEPRECATED_TOOLTIP, mouseX, mouseY); + guiGraphics.renderTooltip(this.font, DEPRECATED_TRADE_COMPONENT, mouseX, mouseY); } - posY = height + 16 + 2; + posY = this.topPos + 16 + 2; for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { @@ -218,7 +194,7 @@ public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partia if (this.isHovering(posX, posY, 88, 19, mouseX + this.leftPos, mouseY + this.topPos)) { - guiGraphics.renderTooltip(this.font, MERCHANT_GONE, mouseX, mouseY); + guiGraphics.renderTooltip(this.font, MERCHANT_UNAVAILABLE_COMPONENT, mouseX, mouseY); } } @@ -253,7 +229,7 @@ private void renderAndDecorateCostA(GuiGraphics guiGraphics, int posX, int posY, guiGraphics.renderItemDecorations(this.font, costA, posX + 5 + 14, posY + 1, costA.getCount() == 1 ? "1" : null); guiGraphics.pose().pushPose(); guiGraphics.pose().translate(0.0F, 0.0F, 300.0F); - guiGraphics.blit(VILLAGER_LOCATION, posX + 5 + 7, posY + 1 + 12, 0, 0.0F, 176.0F, 9, 2, 512, 256); + guiGraphics.blitSprite(DISCOUNT_STRIKETHRUOGH_SPRITE, posX + 5 + 7, posY + 1 + 12, 0, 9, 2); guiGraphics.pose().popPose(); } } @@ -275,7 +251,6 @@ private void setButtonsActive(MerchantOffers merchantoffers) { } private void lock(boolean lockOffers, int newScrollOff, Slot newHoveredSlot) { - this.getMenu().lockOffers(lockOffers); ((MerchantScreenAccessor) this).tradingpost$setScrollOff(newScrollOff); this.hoveredSlot = newHoveredSlot; @@ -284,37 +259,26 @@ private void lock(boolean lockOffers, int newScrollOff, Slot newHoveredSlot) { @Override protected void renderBg(GuiGraphics guiGraphics, float partialTicks, int mouseX, int mouseY) { super.renderBg(guiGraphics, partialTicks, mouseX, mouseY); - this.renderSearchBox(guiGraphics, partialTicks, mouseX, mouseY); - TextureAtlasSprite atlasSprite = this.minecraft.getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(MAGNIFYING_GLASS_LOCATION); - guiGraphics.blit(this.leftPos, this.topPos + 4, 0, 16, 16, atlasSprite); + guiGraphics.blit(CREATIVE_INVENTORY_LOCATION, this.leftPos + 11, this.topPos + 4, 0, 80.0F, 4.0F, 90, 12, 256, 256); + this.searchBox.render(guiGraphics, mouseX, mouseY, partialTicks); + guiGraphics.blitSprite(MAGNIFYING_GLASS_LOCATION, this.leftPos, this.topPos + 4, 0, 16, 16); RenderSystem.setShader(GameRenderer::getPositionTexShader); RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); } - private void renderSearchBox(GuiGraphics guiGraphics, float partialTicks, int mouseX, int mouseY) { - int i = (this.width - this.imageWidth) / 2; - int j = (this.height - this.imageHeight) / 2; - guiGraphics.blit(CREATIVE_INVENTORY_LOCATION, i + 11, j + 4, 0, 80.0F, 4.0F, 90, 12, 256, 256); - this.searchBox.render(guiGraphics, mouseX, mouseY, partialTicks); - } - @Override public boolean mouseClicked(double mouseX, double mouseY, int mouseKey) { if (this.searchBox.mouseClicked(mouseX, mouseY, mouseKey)) { + this.searchBox.setFocused(true); return true; } return super.mouseClicked(mouseX, mouseY, mouseKey); } - @Override - protected void containerTick() { - this.searchBox.tick(); - } - @Override public boolean keyPressed(int keyCode, int scanCode, int modifierKeys) { this.ignoreTextInput = false; - final String lastSearch = this.searchBox.getValue().trim(); + String lastSearch = this.searchBox.getValue().trim(); if (this.searchBox.keyPressed(keyCode, scanCode, modifierKeys)) { if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { @@ -330,13 +294,14 @@ public boolean keyPressed(int keyCode, int scanCode, int modifierKeys) { this.searchBox.setFocused(true); return true; } + return super.keyPressed(keyCode, scanCode, modifierKeys); } @Override public boolean charTyped(char typedChar, int modifierKeys) { - final String lastSearch = this.searchBox.getValue().trim(); + String lastSearch = this.searchBox.getValue().trim(); if (!this.ignoreTextInput && this.searchBox.charTyped(typedChar, modifierKeys)) { if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { @@ -359,7 +324,7 @@ public void refreshSearchResults() { if (query.isEmpty()) { offers.clearFilter(); } else { - SearchTree isearchtree = this.minecraft.getSearchTree(OFFER_SEARCH_TREE); + SearchTree isearchtree = this.minecraft.getSearchTree(TradingPostClient.OFFER_SEARCH_TREE); offers.setFilter(isearchtree.search(query.toLowerCase(Locale.ROOT))); } ((MerchantScreenAccessor) this).tradingpost$setScrollOff(0); @@ -372,8 +337,6 @@ public void refreshSearchResults() { @Override public TradingPostMenu getMenu() { - return (TradingPostMenu) super.getMenu(); } - } diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java index 5aa684e..4ca2973 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java @@ -3,7 +3,6 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; -import net.minecraft.client.Minecraft; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; @@ -18,9 +17,10 @@ * Mostly copied from Quark's MatrixEnchantingTableRenderer.java by Vazkii, thanks! */ public class TradingPostRenderer implements BlockEntityRenderer { + private final ItemRenderer itemRenderer; public TradingPostRenderer(BlockEntityRendererProvider.Context context) { - + this.itemRenderer = context.getItemRenderer(); } @Override @@ -50,9 +50,7 @@ private void renderItem(ItemStack stack, float ageInTicks, float bookOpen, float matrixStackIn.mulPose(Axis.XP.rotationDegrees(-90.0F * (bookOpen - 1.0F))); float hoveringHeight = (float) Math.sin(ageInTicks * 0.06F) * bookOpen * 0.2F; matrixStackIn.translate(0.0F, hoveringHeight, 0.0F); - ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); - itemRenderer.renderStatic(stack, ItemDisplayContext.FIXED, combinedLightIn, combinedOverlayIn, matrixStackIn, bufferIn, level, 0); + this.itemRenderer.renderStatic(stack, ItemDisplayContext.FIXED, combinedLightIn, combinedOverlayIn, matrixStackIn, bufferIn, level, 0); matrixStackIn.popPose(); } - } diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java new file mode 100644 index 0000000..992c48f --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java @@ -0,0 +1,16 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractLootProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; + +public class ModBlockLootProvider extends AbstractLootProvider.Blocks { + public ModBlockLootProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addLootTables() { + this.add(ModRegistry.TRADING_POST_BLOCK.value(), this::createNameableBlockEntityTable); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java new file mode 100644 index 0000000..9eb0a46 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java @@ -0,0 +1,19 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractTagProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.core.HolderLookup; +import net.minecraft.tags.BlockTags; + +public class ModBlockTagProvider extends AbstractTagProvider.Blocks { + + public ModBlockTagProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTags(HolderLookup.Provider provider) { + this.tag(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.TRADING_POST_BLOCK.value()); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java new file mode 100644 index 0000000..e41bf65 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java @@ -0,0 +1,18 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractTagProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.core.HolderLookup; + +public class ModEntityTypeTagProvider extends AbstractTagProvider.EntityTypes { + + public ModEntityTypeTagProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTags(HolderLookup.Provider provider) { + this.tag(ModRegistry.CONCEALED_TRADERS_ENTITY_TYPE_TAG); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java new file mode 100644 index 0000000..9f06de2 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java @@ -0,0 +1,30 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractRecipeProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.data.recipes.RecipeCategory; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.data.recipes.ShapedRecipeBuilder; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.item.Items; + +public class ModRecipeProvider extends AbstractRecipeProvider { + + public ModRecipeProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addRecipes(RecipeOutput recipeOutput) { + ShapedRecipeBuilder.shaped(RecipeCategory.DECORATIONS, ModRegistry.TRADING_POST_BLOCK.value()) + .define('#', ItemTags.PLANKS) + .define('X', Items.EMERALD) + .define('S', Items.STICK) + .pattern(" X ") + .pattern("###") + .pattern("S S") + .unlockedBy(getHasName(Items.EMERALD), has(Items.EMERALD)) + .save(recipeOutput); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java new file mode 100644 index 0000000..a1f0e67 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java @@ -0,0 +1,23 @@ +package fuzs.tradingpost.data.client; + +import fuzs.puzzleslib.api.client.data.v2.AbstractLanguageProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTranslations(TranslationBuilder builder) { + builder.add(ModRegistry.TRADING_POST_BLOCK.value(), "Trading Post"); + builder.add(TradingPostBlockEntity.CONTAINER_COMPONENT, "Trading Post"); + builder.add(TradingPostScreen.MERCHANT_UNAVAILABLE_COMPONENT, "The trader is no longer available."); + builder.add(TradingPostBlock.MISSING_MERCHANT_COMPONENT, "Couldn't find any available trader nearby"); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java new file mode 100644 index 0000000..5bb580a --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java @@ -0,0 +1,18 @@ +package fuzs.tradingpost.data.client; + +import fuzs.puzzleslib.api.client.data.v2.AbstractModelProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.data.models.BlockModelGenerators; + +public class ModModelProvider extends AbstractModelProvider { + + public ModModelProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addBlockModels(BlockModelGenerators builder) { + builder.createNonTemplateModelBlock(ModRegistry.TRADING_POST_BLOCK.value()); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java index b01649b..4994315 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java @@ -1,11 +1,12 @@ package fuzs.tradingpost.init; -import fuzs.puzzleslib.api.init.v2.RegistryManager; -import fuzs.puzzleslib.api.init.v2.RegistryReference; +import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; +import fuzs.puzzleslib.api.init.v3.tags.BoundTagFactory; import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.world.inventory.TradingPostMenu; import fuzs.tradingpost.world.level.block.TradingPostBlock; import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.core.Holder; import net.minecraft.tags.TagKey; import net.minecraft.world.entity.EntityType; import net.minecraft.world.inventory.MenuType; @@ -18,13 +19,14 @@ import net.minecraft.world.level.material.MapColor; public class ModRegistry { - static final RegistryManager REGISTRY = RegistryManager.instant(TradingPost.MOD_ID); - public static final RegistryReference TRADING_POST_BLOCK = REGISTRY.registerBlock("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.5F).sound(SoundType.WOOD).ignitedByLava())); - public static final RegistryReference TRADING_POST_ITEM = REGISTRY.registerBlockItem(TRADING_POST_BLOCK); - public static final RegistryReference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType("trading_post", () -> BlockEntityType.Builder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.get())); - public static final RegistryReference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); + static final RegistryManager REGISTRY = RegistryManager.from(TradingPost.MOD_ID); + public static final Holder.Reference TRADING_POST_BLOCK = REGISTRY.registerBlock("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.5F).sound(SoundType.WOOD).ignitedByLava())); + public static final Holder.Reference TRADING_POST_ITEM = REGISTRY.registerBlockItem(TRADING_POST_BLOCK); + public static final Holder.Reference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType("trading_post", () -> BlockEntityType.Builder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.value())); + public static final Holder.Reference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); - public static final TagKey> BLACKLISTED_TRADERS_TAG = REGISTRY.registerEntityTypeTag("blacklisted_traders"); + static final BoundTagFactory TAGS = BoundTagFactory.make(TradingPost.MOD_ID); + public static final TagKey> CONCEALED_TRADERS_ENTITY_TYPE_TAG = TAGS.registerEntityTypeTag("concealed_traders"); public static void touch() { diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java index a892cec..48d34fb 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java @@ -1,6 +1,7 @@ package fuzs.tradingpost.network; import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.client.TradingPostClient; import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; import fuzs.tradingpost.world.inventory.TradingPostMenu; import it.unimi.dsi.fastutil.ints.Int2IntMap; @@ -52,7 +53,7 @@ public void handle(S2CBuildOffersMessage message, Player player, Object gameInst Minecraft minecraft = (Minecraft) gameInstance; if (message.containerId == player.containerMenu.containerId && player.containerMenu instanceof TradingPostMenu playerMenu && minecraft.screen instanceof TradingPostScreen screen) { playerMenu.getTraders().buildOffers(message.idToOfferCount); - minecraft.populateSearchTree(TradingPostScreen.OFFER_SEARCH_TREE, playerMenu.getOffers()); + minecraft.populateSearchTree(TradingPostClient.OFFER_SEARCH_TREE, playerMenu.getOffers()); screen.refreshSearchResults(); } } diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java index b0488aa..3328c71 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java @@ -8,7 +8,7 @@ import fuzs.tradingpost.network.S2CMerchantDataMessage; import fuzs.tradingpost.network.S2CRemoveMerchantsMessage; import fuzs.tradingpost.world.item.trading.TradingPostOffers; -import fuzs.tradingpost.world.level.block.TradingPostBlock; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; import it.unimi.dsi.fastutil.ints.*; import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; import net.minecraft.core.BlockPos; @@ -237,7 +237,7 @@ public void setActiveOffer(MerchantOffer offer) { public void sendMerchantData(final int containerId, Player player) { for (Map.Entry entry : this.idToMerchant.int2ObjectEntrySet()) { Merchant merchant = entry.getValue(); - final Component merchantTitle = merchant instanceof Entity ? ((Entity) merchant).getDisplayName() : TradingPostBlock.CONTAINER_TITLE; + final Component merchantTitle = merchant instanceof Entity ? ((Entity) merchant).getDisplayName() : TradingPostBlockEntity.CONTAINER_COMPONENT; final int merchantLevel = merchant instanceof VillagerDataHolder ? ((VillagerDataHolder) merchant).getVillagerData().getLevel() : 0; S2CMerchantDataMessage message = new S2CMerchantDataMessage(containerId, entry.getKey(), merchantTitle, merchant.getOffers(), merchantLevel, merchant.getVillagerXp(), merchant.showProgressBar(), merchant.canRestock()); TradingPost.NETWORK.sendTo(message, (ServerPlayer) player); diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java index bb7a64b..c9f9ff3 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java @@ -7,6 +7,7 @@ import fuzs.tradingpost.world.entity.npc.LocalMerchant; import fuzs.tradingpost.world.entity.npc.MerchantCollection; import fuzs.tradingpost.world.level.block.TradingPostBlock; +import net.minecraft.core.BlockPos; import net.minecraft.network.chat.Component; import net.minecraft.sounds.SoundSource; import net.minecraft.world.entity.Entity; @@ -16,6 +17,7 @@ import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.Merchant; import net.minecraft.world.item.trading.MerchantOffers; +import net.minecraft.world.level.Level; import java.util.Optional; @@ -50,20 +52,23 @@ private void replaceSlot(int index, Slot slot) { @Override public MenuType getType() { - return ModRegistry.TRADING_POST_MENU_TYPE.get(); + return ModRegistry.TRADING_POST_MENU_TYPE.value(); } @Override public boolean stillValid(Player player) { // this also updates merchants, so run independent of config option // don't want this to go off on every tick - Optional anyTrader = this.access.evaluate((level, pos) -> this.traders.updateAvailableMerchants(this.containerId, pos, player, TradingPost.CONFIG.get(ServerConfig.class).enforceRange && ++this.ticks >= 20)); + Optional anyTrader = this.access.evaluate((Level level, BlockPos pos) -> { + boolean testRange = TradingPost.CONFIG.get(ServerConfig.class).enforceRange && ++this.ticks >= 20; + return this.traders.updateAvailableMerchants(this.containerId, pos, player, testRange); + }); if (this.ticks >= 20) this.ticks = 0; if (TradingPost.CONFIG.get(ServerConfig.class).closeScreen && anyTrader.isPresent() && !anyTrader.get()) { - player.displayClientMessage(TradingPostBlock.NO_MERCHANT_FOUND, false); + player.displayClientMessage(TradingPostBlock.MISSING_MERCHANT_COMPONENT, false); return false; } - return stillValid(this.access, player, ModRegistry.TRADING_POST_BLOCK.get()); + return stillValid(this.access, player, ModRegistry.TRADING_POST_BLOCK.value()); } @Override @@ -151,14 +156,12 @@ public void lockOffers(boolean lock) { } public void addMerchant(Player playerEntity, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { - LocalMerchant merchant = new LocalMerchant(playerEntity, merchantTitle, offers, villagerLevel, villagerXp, showProgress, canRestock); this.traders.addMerchant(merchantId, merchant); } @Override public int getTraderLevel() { - return this.traders.getTraderLevel(); } @@ -174,27 +177,31 @@ public boolean showProgressBar() { @Override public void setShowProgressBar(boolean showProgressBar) { - // we don't raise an exception anywhere here as you never know what other mods are up to since this extends vanilla's merchant menu + // Don't throw to not break other mods possibly interfering with the merchant menu. TradingPost.LOGGER.error("Operation setShowProgressBar no supported on trading post, set showProgressBar to merchants directly"); } @Override public void setXp(int xpValue) { + // Don't throw to not break other mods possibly interfering with the merchant menu. TradingPost.LOGGER.error("Operation setXp no supported on trading post, set xp to merchants directly"); } @Override public void setMerchantLevel(int merchantLevel) { + // Don't throw to not break other mods possibly interfering with the merchant menu. TradingPost.LOGGER.error("Operation setMerchantLevel no supported on trading post, set level to merchants directly"); } @Override public void setCanRestock(boolean canRestock) { + // Don't throw to not break other mods possibly interfering with the merchant menu. TradingPost.LOGGER.error("Operation setCanRestock no supported on trading post, set canRestock to merchants directly"); } @Override public void setOffers(MerchantOffers offers) { + // Don't throw to not break other mods possibly interfering with the merchant menu. TradingPost.LOGGER.error("Operation setOffers no supported on trading post, set offers to merchants directly"); } } diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java index 9fd17c4..17a2916 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java @@ -1,5 +1,7 @@ package fuzs.tradingpost.world.level.block; +import com.mojang.serialization.MapCodec; +import fuzs.puzzleslib.api.block.v1.entity.TickingEntityBlock; import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.config.ServerConfig; import fuzs.tradingpost.init.ModRegistry; @@ -12,11 +14,11 @@ import net.minecraft.network.chat.Component; import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; -import net.minecraft.world.Nameable; import net.minecraft.world.SimpleMenuProvider; import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.LivingEntity; import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.ContainerLevelAccess; import net.minecraft.world.item.ItemStack; @@ -29,8 +31,6 @@ import net.minecraft.world.level.block.Block; import net.minecraft.world.level.block.RenderShape; import net.minecraft.world.level.block.SimpleWaterloggedBlock; -import net.minecraft.world.level.block.entity.BlockEntity; -import net.minecraft.world.level.block.entity.BlockEntityTicker; import net.minecraft.world.level.block.entity.BlockEntityType; import net.minecraft.world.level.block.state.BlockState; import net.minecraft.world.level.block.state.StateDefinition; @@ -45,15 +45,14 @@ import net.minecraft.world.phys.shapes.CollisionContext; import net.minecraft.world.phys.shapes.Shapes; import net.minecraft.world.phys.shapes.VoxelShape; -import org.jetbrains.annotations.Nullable; import java.util.List; +import java.util.OptionalInt; -@SuppressWarnings("deprecation") -public class TradingPostBlock extends BaseEntityBlock implements SimpleWaterloggedBlock { - public static final Component CONTAINER_TITLE = Component.translatable("container.trading_post"); - public static final Component NO_MERCHANT_FOUND = Component.translatable("trading_post.no_trader_found"); +public class TradingPostBlock extends BaseEntityBlock implements SimpleWaterloggedBlock, TickingEntityBlock { + public static final Component MISSING_MERCHANT_COMPONENT = Component.translatable("trading_post.no_trader_found"); public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; + public static final MapCodec CODEC = simpleCodec(TradingPostBlock::new); private static final VoxelShape LEG1 = Block.box(0.0, 0.0, 0.0, 4.0, 8.0, 4.0); private static final VoxelShape LEG2 = Block.box(12.0, 0.0, 0.0, 16.0, 8.0, 4.0); private static final VoxelShape LEG3 = Block.box(0.0, 0.0, 12.0, 4.0, 8.0, 16.0); @@ -66,6 +65,11 @@ public TradingPostBlock(Properties blockProperties) { this.registerDefaultState(this.stateDefinition.any().setValue(WATERLOGGED, Boolean.FALSE)); } + @Override + protected MapCodec codec() { + return CODEC; + } + @Override public boolean useShapeForLightOcclusion(BlockState state) { return true; @@ -91,24 +95,18 @@ public BlockState updateShape(BlockState state, Direction direction, BlockState @Override public BlockState getStateForPlacement(BlockPlaceContext context) { - FluidState fluidstate = context.getLevel().getFluidState(context.getClickedPos()); - return this.defaultBlockState().setValue(WATERLOGGED, fluidstate.getType() == Fluids.WATER); + FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos()); + return this.defaultBlockState().setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER); } @Override - public FluidState getFluidState(BlockState state) { - return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state); + public FluidState getFluidState(BlockState blockState) { + return blockState.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(blockState); } - @Nullable @Override - public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) { - return new TradingPostBlockEntity(pPos, pState); - } - - @Nullable - public BlockEntityTicker getTicker(Level pLevel, BlockState pState, BlockEntityType pBlockEntityType) { - return pLevel.isClientSide ? createTickerHelper(pBlockEntityType, ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), TradingPostBlockEntity::tickEmeraldAnimation) : null; + public BlockEntityType getBlockEntityType() { + return ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(); } @Override @@ -116,14 +114,14 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player if (level.isClientSide) { return InteractionResult.SUCCESS; } else { - Vec3 blockCenterPos = Vec3.atCenterOf(pos); + Vec3 atCenter = Vec3.atCenterOf(pos); final int horizontalRange = TradingPost.CONFIG.get(ServerConfig.class).horizontalRange; final int verticalRange = TradingPost.CONFIG.get(ServerConfig.class).verticalRange; - List nearbyTraders = level.getEntitiesOfClass(Entity.class, new AABB(blockCenterPos.add(-horizontalRange, -verticalRange, -horizontalRange), blockCenterPos.add(horizontalRange, verticalRange, horizontalRange)), this::canTrade); - if (!nearbyTraders.isEmpty()) { + List traders = level.getEntitiesOfClass(Entity.class, new AABB(atCenter.add(-horizontalRange, -verticalRange, -horizontalRange), atCenter.add(horizontalRange, verticalRange, horizontalRange)), TradingPostBlock::isAllowedToTrade); + if (!traders.isEmpty()) { ContainerLevelAccess access = ContainerLevelAccess.create(level, pos); MerchantCollection merchants = new MerchantCollection(access); - for (Entity merchant : nearbyTraders) { + for (Entity merchant : traders) { if (merchant instanceof Villager) { ((VillagerAccessor) merchant).callUpdateSpecialPrices(player); } @@ -131,41 +129,42 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player } merchants.setTradingPlayer(player); merchants.buildOffers(merchants.getIdToOfferCountMap()); - Component title = this.getContainerTitle(level, pos); - this.openTradingScreen(player, merchants, title, access); + Component title; + if (level.getBlockEntity(pos) instanceof TradingPostBlockEntity blockEntity) + title = blockEntity.getDisplayName(); + else { + title = TradingPostBlockEntity.CONTAINER_COMPONENT; + } + OptionalInt result = player.openMenu(new SimpleMenuProvider((int containerId, Inventory inventory, Player containerPlayer) -> { + return new TradingPostMenu(containerId, inventory, merchants, access); + }, title)); + result.ifPresent((int containerId) -> { + merchants.sendMerchantData(containerId, player); + }); } else { - player.displayClientMessage(NO_MERCHANT_FOUND, false); + player.displayClientMessage(MISSING_MERCHANT_COMPONENT, false); } return InteractionResult.CONSUME; } } - private boolean canTrade(Entity entity) { - if (TradingPost.CONFIG.get(ServerConfig.class).traderBlacklist.contains(entity.getType()) || entity.getType().is(ModRegistry.BLACKLISTED_TRADERS_TAG)) { + public static boolean isAllowedToTrade(Entity entity) { + if (entity.getType().is(ModRegistry.CONCEALED_TRADERS_ENTITY_TYPE_TAG)) { return false; } - if (!entity.isAlive() || !(entity instanceof Merchant) || ((Merchant) entity).getTradingPlayer() != null || ((Merchant) entity).getOffers().isEmpty()) { + + if (!entity.isAlive() || !(entity instanceof Merchant merchant) || merchant.getTradingPlayer() != null || merchant.getOffers().isEmpty()) { return false; } - return !(entity instanceof LivingEntity) || (!((LivingEntity) entity).isSleeping() && !((LivingEntity) entity).isBaby()); - } - - private Component getContainerTitle(Level level, BlockPos pos) { - BlockEntity tileentity = level.getBlockEntity(pos); - return tileentity instanceof TradingPostBlockEntity ? ((Nameable) tileentity).getDisplayName() : TradingPostBlock.CONTAINER_TITLE; - } - private void openTradingScreen(Player player, MerchantCollection merchants, Component title, ContainerLevelAccess worldPosCallable) { - player.openMenu(new SimpleMenuProvider((containerMenuId, playerInventory, playerEntity) -> new TradingPostMenu(containerMenuId, playerInventory, merchants, worldPosCallable), title)) - .ifPresent(containerId -> merchants.sendMerchantData(containerId, player)); + return !(entity instanceof LivingEntity livingEntity) || !livingEntity.isSleeping() && !livingEntity.isBaby(); } @Override public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity entity, ItemStack stack) { if (stack.hasCustomHoverName()) { - BlockEntity tileentity = level.getBlockEntity(pos); - if (tileentity instanceof TradingPostBlockEntity) { - ((TradingPostBlockEntity) tileentity).setCustomName(stack.getHoverName()); + if (level.getBlockEntity(pos) instanceof TradingPostBlockEntity blockEntity) { + blockEntity.setCustomName(stack.getHoverName()); } } } diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java index 33bd5d4..956c2cd 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java @@ -1,19 +1,20 @@ package fuzs.tradingpost.world.level.block.entity; +import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; import fuzs.tradingpost.init.ModRegistry; -import fuzs.tradingpost.world.level.block.TradingPostBlock; import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; import net.minecraft.util.Mth; import net.minecraft.world.Nameable; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.level.Level; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; -public class TradingPostBlockEntity extends BlockEntity implements Nameable { +public class TradingPostBlockEntity extends BlockEntity implements Nameable, TickingBlockEntity { + public static final Component CONTAINER_COMPONENT = Component.translatable("container.trading_post"); + private Component name; public int time; public float open; @@ -22,8 +23,8 @@ public class TradingPostBlockEntity extends BlockEntity implements Nameable { public float oRot; private float tRot; - public TradingPostBlockEntity(BlockPos pWorldPosition, BlockState pBlockState) { - super(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), pWorldPosition, pBlockState); + public TradingPostBlockEntity(BlockPos blockPos, BlockState blockState) { + super(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(), blockPos, blockState); } @Override @@ -42,48 +43,49 @@ public void load(CompoundTag compoundTag) { } } - public static void tickEmeraldAnimation(Level pLevel, BlockPos pPos, BlockState pState, TradingPostBlockEntity pBlockEntity) { - if (pLevel == null || !pLevel.isClientSide) return; - pBlockEntity.oOpen = pBlockEntity.open; - pBlockEntity.oRot = pBlockEntity.rot; - Player playerentity = pLevel.getNearestPlayer((double) pPos.getX() + 0.5, (double) pPos.getY() + 0.5, (double) pPos.getZ() + 0.5, 3.0, false); + @Override + public void clientTick() { + if (this.getLevel() == null || !this.getLevel().isClientSide) return; + this.oOpen = this.open; + this.oRot = this.rot; + Player playerentity = this.getLevel().getNearestPlayer((double) this.getBlockPos().getX() + 0.5, (double) this.getBlockPos().getY() + 0.5, (double) this.getBlockPos().getZ() + 0.5, 3.0, false); if (playerentity != null) { - double d0 = playerentity.getX() - ((double) pPos.getX() + 0.5); - double d1 = playerentity.getZ() - ((double) pPos.getZ() + 0.5); - pBlockEntity.tRot = (float) Mth.atan2(d1, d0); - pBlockEntity.open += 0.1F; + double d0 = playerentity.getX() - ((double) this.getBlockPos().getX() + 0.5); + double d1 = playerentity.getZ() - ((double) this.getBlockPos().getZ() + 0.5); + this.tRot = (float) Mth.atan2(d1, d0); + this.open += 0.1F; } else { - pBlockEntity.tRot += 0.02F; - pBlockEntity.open -= 0.1F; + this.tRot += 0.02F; + this.open -= 0.1F; } - while(pBlockEntity.rot >= (float) Math.PI) { - pBlockEntity.rot -= ((float) Math.PI * 2.0F); + while(this.rot >= (float) Math.PI) { + this.rot -= ((float) Math.PI * 2.0F); } - while(pBlockEntity.rot < -(float) Math.PI) { - pBlockEntity.rot += ((float) Math.PI * 2.0F); + while(this.rot < -(float) Math.PI) { + this.rot += ((float) Math.PI * 2.0F); } - while(pBlockEntity.tRot >= (float) Math.PI) { - pBlockEntity.tRot -= ((float) Math.PI * 2.0F); + while(this.tRot >= (float) Math.PI) { + this.tRot -= ((float) Math.PI * 2.0F); } - while(pBlockEntity.tRot < -(float) Math.PI) { - pBlockEntity.tRot += ((float) Math.PI * 2.0F); + while(this.tRot < -(float) Math.PI) { + this.tRot += ((float) Math.PI * 2.0F); } float f2; - f2 = pBlockEntity.tRot - pBlockEntity.rot; + f2 = this.tRot - this.rot; while (f2 >= (float) Math.PI) { f2 -= ((float) Math.PI * 2.0F); } while(f2 < -(float) Math.PI) { f2 += ((float) Math.PI * 2.0F); } - pBlockEntity.rot += f2 * 0.4F; - pBlockEntity.open = Mth.clamp(pBlockEntity.open, 0.0F, 1.0F); - ++pBlockEntity.time; + this.rot += f2 * 0.4F; + this.open = Mth.clamp(this.open, 0.0F, 1.0F); + ++this.time; } @Override public Component getName() { - return this.name != null ? this.name : TradingPostBlock.CONTAINER_TITLE; + return this.name != null ? this.name : CONTAINER_COMPONENT; } public void setCustomName(@Nullable Component textComponent) { diff --git a/1.20.4/Common/src/main/resources/architectury.common.json b/1.20.4/Common/src/main/resources/architectury.common.json new file mode 100644 index 0000000..e813a5a --- /dev/null +++ b/1.20.4/Common/src/main/resources/architectury.common.json @@ -0,0 +1,3 @@ +{ + "accessWidener": "tradingpost.accesswidener" +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json b/1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json deleted file mode 100644 index 9c7f8ce..0000000 --- a/1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "parent": "tradingpost:block/trading_post" -} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png b/1.20.4/Common/src/main/resources/assets/tradingpost/textures/gui/sprites/container/villager/magnifying_glass.png similarity index 100% rename from 1.20.4/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png rename to 1.20.4/Common/src/main/resources/assets/tradingpost/textures/gui/sprites/container/villager/magnifying_glass.png diff --git a/1.20.4/Common/src/main/resources/tradingpost.common.mixins.json b/1.20.4/Common/src/main/resources/common.mixins.json similarity index 72% rename from 1.20.4/Common/src/main/resources/tradingpost.common.mixins.json rename to 1.20.4/Common/src/main/resources/common.mixins.json index 7833fd6..b0cdaf5 100644 --- a/1.20.4/Common/src/main/resources/tradingpost.common.mixins.json +++ b/1.20.4/Common/src/main/resources/common.mixins.json @@ -2,9 +2,7 @@ "required": true, "minVersion": "0.8", "compatibilityLevel": "JAVA_17", - "package": "fuzs.tradingpost.mixin", - "refmap": "tradingpost.refmap.json", - "plugin": "fuzs.tradingpost.mixin.ModMixinConfigPlugin", + "package": "${modGroup}.mixin", "mixins": [ "accessor.MerchantMenuAccessor", "accessor.VillagerAccessor" diff --git a/1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json b/1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json deleted file mode 100644 index d275da3..0000000 --- a/1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json +++ /dev/null @@ -1,5 +0,0 @@ -{ - "replace": false, - "values": [ - ] -} diff --git a/1.20.4/Common/src/main/resources/pack.mcmeta b/1.20.4/Common/src/main/resources/pack.mcmeta index 19bfab2..546f4f1 100755 --- a/1.20.4/Common/src/main/resources/pack.mcmeta +++ b/1.20.4/Common/src/main/resources/pack.mcmeta @@ -1,8 +1,6 @@ { "pack": { "description": "${modDescription}", - "pack_format": ${resourcePackFormat}, - "forge:resource_pack_format": ${resourcePackFormat}, - "forge:data_pack_format": ${dataPackFormat} + "pack_format": ${resourcePackFormat} } } diff --git a/1.20.4/Common/src/main/resources/tradingpost.accesswidener b/1.20.4/Common/src/main/resources/tradingpost.accesswidener new file mode 100644 index 0000000..236e6b1 --- /dev/null +++ b/1.20.4/Common/src/main/resources/tradingpost.accesswidener @@ -0,0 +1 @@ +accessWidener v2 named diff --git a/1.20.4/Fabric/build.gradle b/1.20.4/Fabric/build.gradle index cd8b641..4de494c 100644 --- a/1.20.4/Fabric/build.gradle +++ b/1.20.4/Fabric/build.gradle @@ -1,6 +1,4 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' - -def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/fabric.gradle" dependencies { // Fabric Api @@ -18,12 +16,4 @@ dependencies { // Extensible Enums // modApi(include(libs.extensibleenums.fabric.get())) - - // Quality of Life Mods - versionCatalog.findLibrary("modmenu.fabric").ifPresent { - modLocalRuntime(it) - } - versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { - modLocalRuntime(it) - } } diff --git a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/fabric/TradingPostFabric.java similarity index 80% rename from 1.20.4/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java rename to 1.20.4/Fabric/src/main/java/fuzs/tradingpost/fabric/TradingPostFabric.java index 5fc6ff1..fcdb445 100644 --- a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java +++ b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/fabric/TradingPostFabric.java @@ -1,6 +1,7 @@ -package fuzs.tradingpost; +package fuzs.tradingpost.fabric; import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.tradingpost.TradingPost; import net.fabricmc.api.ModInitializer; public class TradingPostFabric implements ModInitializer { diff --git a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/fabric/client/TradingPostFabricClient.java similarity index 80% rename from 1.20.4/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java rename to 1.20.4/Fabric/src/main/java/fuzs/tradingpost/fabric/client/TradingPostFabricClient.java index c5198a1..a1299fb 100644 --- a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java +++ b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/fabric/client/TradingPostFabricClient.java @@ -1,7 +1,8 @@ -package fuzs.tradingpost.client; +package fuzs.tradingpost.fabric.client; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.client.TradingPostClient; import net.fabricmc.api.ClientModInitializer; public class TradingPostFabricClient implements ClientModInitializer { diff --git a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index 343a1d3..0000000 --- a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.tradingpost.mixin; - -import net.fabricmc.loader.api.FabricLoader; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.util.List; -import java.util.Set; - -public class ModMixinConfigPlugin implements IMixinConfigPlugin { - - @Override - public void onLoad(String mixinPackage) { - - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - return FabricLoader.getInstance().isModLoaded("puzzleslib"); - } - - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - @Override - public List getMixins() { - return null; - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/1.20.4/Fabric/src/main/resources/fabric.mixins.json b/1.20.4/Fabric/src/main/resources/fabric.mixins.json new file mode 100644 index 0000000..b1b7180 --- /dev/null +++ b/1.20.4/Fabric/src/main/resources/fabric.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.fabric.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20.4/Fabric/src/main/resources/fabric.mod.json b/1.20.4/Fabric/src/main/resources/fabric.mod.json index c0c6cfa..bd7ba2d 100644 --- a/1.20.4/Fabric/src/main/resources/fabric.mod.json +++ b/1.20.4/Fabric/src/main/resources/fabric.mod.json @@ -9,7 +9,7 @@ "authors": [ "${modAuthor}" ], - + "contact": { "homepage": "${modPageUrl}", "issues": "${modIssueUrl}", @@ -31,7 +31,8 @@ }, "mixins": [ - "${modId}.common.mixins.json" + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" ], "depends": { diff --git a/1.20.4/Forge/build.gradle b/1.20.4/Forge/build.gradle index dec494a..f9839f1 100644 --- a/1.20.4/Forge/build.gradle +++ b/1.20.4/Forge/build.gradle @@ -1,28 +1,6 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' - -def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/forge.gradle" dependencies { // Puzzles Lib - api fg.deobf(libs.puzzleslib.forge.get()) - - // Quality of Life Mods - versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } - versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } + modApi libs.puzzleslib.forge } - -task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { - onlyIf { project.hasProperty('keyStore') } - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = outputFile = tasks.jarJar.archivePath -} - -jar.finalizedBy 'signJar' -signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/Forge/gradle.properties b/1.20.4/Forge/gradle.properties new file mode 100644 index 0000000..32f842a --- /dev/null +++ b/1.20.4/Forge/gradle.properties @@ -0,0 +1 @@ +loom.platform=forge \ No newline at end of file diff --git a/1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 b/1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 deleted file mode 100644 index 26e7e09..0000000 --- a/1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2023-06-28T11:09:24.480978 Sprite Sources -84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json b/1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json deleted file mode 100644 index 0cfb27c..0000000 --- a/1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "sources": [ - { - "type": "minecraft:single", - "resource": "tradingpost:item/magnifying_glass" - } - ] -} \ No newline at end of file diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java deleted file mode 100644 index 46a80b4..0000000 --- a/1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java +++ /dev/null @@ -1,33 +0,0 @@ -package fuzs.tradingpost; - -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import fuzs.tradingpost.data.ModSpriteSourceProvider; -import net.minecraft.core.HolderLookup; -import net.minecraft.data.DataGenerator; -import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; - -import java.util.concurrent.CompletableFuture; - -@Mod(TradingPost.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) -public class TradingPostForge { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); - } - - @SubscribeEvent - public static void onGatherData(final GatherDataEvent evt) { - final DataGenerator dataGenerator = evt.getGenerator(); - final PackOutput packOutput = dataGenerator.getPackOutput(); - final CompletableFuture lookupProvider = evt.getLookupProvider(); - final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); - dataGenerator.addProvider(true, new ModSpriteSourceProvider(packOutput, fileHelper)); - } -} diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java deleted file mode 100644 index 7ddde99..0000000 --- a/1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java +++ /dev/null @@ -1,22 +0,0 @@ -package fuzs.tradingpost.data; - -import fuzs.puzzleslib.api.data.v1.AbstractSpriteSourceProvider; -import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; -import net.minecraft.client.renderer.texture.atlas.sources.SingleFile; -import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.common.data.SpriteSourceProvider; - -import java.util.Optional; - -public class ModSpriteSourceProvider extends AbstractSpriteSourceProvider { - - public ModSpriteSourceProvider(PackOutput packOutput, ExistingFileHelper fileHelper) { - super(packOutput, fileHelper); - } - - @Override - protected void addSources() { - this.atlas(SpriteSourceProvider.BLOCKS_ATLAS).addSource(new SingleFile(TradingPostScreen.MAGNIFYING_GLASS_LOCATION, Optional.empty())); - } -} diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java new file mode 100644 index 0000000..0f01496 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java @@ -0,0 +1,17 @@ +package fuzs.tradingpost.forge; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.tradingpost.TradingPost; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(TradingPost.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class TradingPostForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java similarity index 87% rename from 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java rename to 1.20.4/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java index 41d3cbf..d400491 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java +++ b/1.20.4/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java @@ -1,7 +1,8 @@ -package fuzs.tradingpost.client; +package fuzs.tradingpost.forge.client; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.client.TradingPostClient; import net.minecraftforge.api.distmarker.Dist; import net.minecraftforge.eventbus.api.SubscribeEvent; import net.minecraftforge.fml.common.Mod; diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index 7528a9e..0000000 --- a/1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.tradingpost.mixin; - -import net.minecraftforge.fml.loading.FMLLoader; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.util.List; -import java.util.Set; - -public class ModMixinConfigPlugin implements IMixinConfigPlugin { - - @Override - public void onLoad(String mixinPackage) { - - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; - } - - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - @Override - public List getMixins() { - return null; - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/1.20.4/Forge/src/main/resources/META-INF/mods.toml b/1.20.4/Forge/src/main/resources/META-INF/mods.toml index 6f39b5f..6c2e585 100644 --- a/1.20.4/Forge/src/main/resources/META-INF/mods.toml +++ b/1.20.4/Forge/src/main/resources/META-INF/mods.toml @@ -1,40 +1,51 @@ -modLoader="javafml" -loaderVersion="[${minFMLVersion},)" +modLoader = "javafml" +loaderVersion = "*" license = "${modLicense}" -issueTrackerURL="${modIssueUrl}" +issueTrackerURL = "${modIssueUrl}" [[mods]] - modId="${modId}" - displayName="${modName}" - description="${modDescription}" - version="${modVersion}" - authors="${modAuthor}" - logoFile="mod_banner.png" - logoBlur=false - displayURL="${modPageUrl}" - updateJSONURL="${modUpdateUrl}" - displayTest="${modForgeDisplayTest}" +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" -[[dependencies.${modId}]] - modId="forge" - mandatory=true - versionRange="[${minForgeVersion},)" - ordering="NONE" - side="BOTH" +[[dependencies.${ modId }]] +modId = "forge" +mandatory = true +type = "required" +versionRange = "[${minForgeVersion},)" +ordering = "NONE" +side = "BOTH" -[[dependencies.${modId}]] - modId="minecraft" - mandatory=true - versionRange="[${minecraftVersion}]" - ordering="NONE" - side="BOTH" +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +type = "required" +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" -[[dependencies.${modId}]] - modId="puzzleslib" - mandatory=true - versionRange="[${minPuzzlesVersion},)" - ordering="NONE" - side="BOTH" +[[dependencies.${ modId }]] +modId = "forgeconfigapiport" +mandatory = true +type = "required" +versionRange = "*" +ordering = "NONE" +side = "BOTH" -[modproperties.${modId}] - catalogueImageIcon="mod_logo.png" +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +type = "required" +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.20.4/Forge/src/main/resources/forge.mixins.json b/1.20.4/Forge/src/main/resources/forge.mixins.json new file mode 100644 index 0000000..df416c0 --- /dev/null +++ b/1.20.4/Forge/src/main/resources/forge.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.forge.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20.4/NeoForge/build.gradle b/1.20.4/NeoForge/build.gradle index dec494a..310efce 100644 --- a/1.20.4/NeoForge/build.gradle +++ b/1.20.4/NeoForge/build.gradle @@ -1,28 +1,6 @@ -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' - -def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/neoforge.gradle" dependencies { // Puzzles Lib - api fg.deobf(libs.puzzleslib.forge.get()) - - // Quality of Life Mods - versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } - versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { - runtimeOnly fg.deobf(it.get()) - } + modApi libs.puzzleslib.neoforge } - -task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { - onlyIf { project.hasProperty('keyStore') } - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = outputFile = tasks.jarJar.archivePath -} - -jar.finalizedBy 'signJar' -signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/NeoForge/gradle.properties b/1.20.4/NeoForge/gradle.properties new file mode 100644 index 0000000..2914393 --- /dev/null +++ b/1.20.4/NeoForge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge \ No newline at end of file diff --git a/1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 b/1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 deleted file mode 100644 index 26e7e09..0000000 --- a/1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 +++ /dev/null @@ -1,2 +0,0 @@ -// 1.20.1 2023-06-28T11:09:24.480978 Sprite Sources -84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json b/1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json deleted file mode 100644 index 0cfb27c..0000000 --- a/1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json +++ /dev/null @@ -1,8 +0,0 @@ -{ - "sources": [ - { - "type": "minecraft:single", - "resource": "tradingpost:item/magnifying_glass" - } - ] -} \ No newline at end of file diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java deleted file mode 100644 index 46a80b4..0000000 --- a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java +++ /dev/null @@ -1,33 +0,0 @@ -package fuzs.tradingpost; - -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import fuzs.tradingpost.data.ModSpriteSourceProvider; -import net.minecraft.core.HolderLookup; -import net.minecraft.data.DataGenerator; -import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.data.event.GatherDataEvent; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; - -import java.util.concurrent.CompletableFuture; - -@Mod(TradingPost.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) -public class TradingPostForge { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); - } - - @SubscribeEvent - public static void onGatherData(final GatherDataEvent evt) { - final DataGenerator dataGenerator = evt.getGenerator(); - final PackOutput packOutput = dataGenerator.getPackOutput(); - final CompletableFuture lookupProvider = evt.getLookupProvider(); - final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); - dataGenerator.addProvider(true, new ModSpriteSourceProvider(packOutput, fileHelper)); - } -} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java deleted file mode 100644 index 7ddde99..0000000 --- a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java +++ /dev/null @@ -1,22 +0,0 @@ -package fuzs.tradingpost.data; - -import fuzs.puzzleslib.api.data.v1.AbstractSpriteSourceProvider; -import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; -import net.minecraft.client.renderer.texture.atlas.sources.SingleFile; -import net.minecraft.data.PackOutput; -import net.minecraftforge.common.data.ExistingFileHelper; -import net.minecraftforge.common.data.SpriteSourceProvider; - -import java.util.Optional; - -public class ModSpriteSourceProvider extends AbstractSpriteSourceProvider { - - public ModSpriteSourceProvider(PackOutput packOutput, ExistingFileHelper fileHelper) { - super(packOutput, fileHelper); - } - - @Override - protected void addSources() { - this.atlas(SpriteSourceProvider.BLOCKS_ATLAS).addSource(new SingleFile(TradingPostScreen.MAGNIFYING_GLASS_LOCATION, Optional.empty())); - } -} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java deleted file mode 100644 index 7528a9e..0000000 --- a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java +++ /dev/null @@ -1,47 +0,0 @@ -package fuzs.tradingpost.mixin; - -import net.minecraftforge.fml.loading.FMLLoader; -import org.objectweb.asm.tree.ClassNode; -import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; -import org.spongepowered.asm.mixin.extensibility.IMixinInfo; - -import java.util.List; -import java.util.Set; - -public class ModMixinConfigPlugin implements IMixinConfigPlugin { - - @Override - public void onLoad(String mixinPackage) { - - } - - @Override - public String getRefMapperConfig() { - return null; - } - - @Override - public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { - return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; - } - - @Override - public void acceptTargets(Set myTargets, Set otherTargets) { - - } - - @Override - public List getMixins() { - return null; - } - - @Override - public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } - - @Override - public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { - - } -} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java new file mode 100644 index 0000000..147d893 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java @@ -0,0 +1,25 @@ +package fuzs.tradingpost.neoforge; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.data.ModBlockLootProvider; +import fuzs.tradingpost.data.ModBlockTagProvider; +import fuzs.tradingpost.data.ModEntityTypeTagProvider; +import fuzs.tradingpost.data.ModRecipeProvider; +import fuzs.tradingpost.data.client.ModLanguageProvider; +import fuzs.tradingpost.data.client.ModModelProvider; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(TradingPost.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class TradingPostNeoForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, ModBlockLootProvider::new, ModBlockTagProvider::new, ModEntityTypeTagProvider::new, ModRecipeProvider::new, ModLanguageProvider::new, ModModelProvider::new); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java similarity index 55% rename from 1.20.4/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java rename to 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java index 41d3cbf..8173684 100644 --- a/1.20.4/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java @@ -1,14 +1,15 @@ -package fuzs.tradingpost.client; +package fuzs.tradingpost.neoforge.client; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.tradingpost.TradingPost; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; +import fuzs.tradingpost.client.TradingPostClient; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; @Mod.EventBusSubscriber(modid = TradingPost.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class TradingPostForgeClient { +public class TradingPostNeoForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { diff --git a/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml index 6f39b5f..ef10121 100644 --- a/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml +++ b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml @@ -1,40 +1,49 @@ -modLoader="javafml" -loaderVersion="[${minFMLVersion},)" +modLoader = "javafml" +loaderVersion = "*" license = "${modLicense}" -issueTrackerURL="${modIssueUrl}" +issueTrackerURL = "${modIssueUrl}" [[mods]] - modId="${modId}" - displayName="${modName}" - description="${modDescription}" - version="${modVersion}" - authors="${modAuthor}" - logoFile="mod_banner.png" - logoBlur=false - displayURL="${modPageUrl}" - updateJSONURL="${modUpdateUrl}" - displayTest="${modForgeDisplayTest}" +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" -[[dependencies.${modId}]] - modId="forge" - mandatory=true - versionRange="[${minForgeVersion},)" - ordering="NONE" - side="BOTH" +[[mixins]] +config="${modId}.common.mixins.json" -[[dependencies.${modId}]] - modId="minecraft" - mandatory=true - versionRange="[${minecraftVersion}]" - ordering="NONE" - side="BOTH" +[[mixins]] +config="${modId}.neoforge.mixins.json" -[[dependencies.${modId}]] - modId="puzzleslib" - mandatory=true - versionRange="[${minPuzzlesVersion},)" - ordering="NONE" - side="BOTH" +[[dependencies.${ modId }]] +modId = "neoforge" +mandatory = true +type = "required" +versionRange = "[${minNeoForgeVersion},)" +ordering = "NONE" +side = "BOTH" -[modproperties.${modId}] - catalogueImageIcon="mod_logo.png" +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +type = "required" +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +type = "required" +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.20.4/NeoForge/src/main/resources/neoforge.mixins.json b/1.20.4/NeoForge/src/main/resources/neoforge.mixins.json new file mode 100644 index 0000000..1fb3919 --- /dev/null +++ b/1.20.4/NeoForge/src/main/resources/neoforge.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.neoforge.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20.4/build.gradle b/1.20.4/build.gradle index fadade3..2417d2e 100644 --- a/1.20.4/build.gradle +++ b/1.20.4/build.gradle @@ -1,12 +1,9 @@ plugins { - alias libs.plugins.loom apply false - alias libs.plugins.quiltflower apply false - alias libs.plugins.forgegradle apply false - alias libs.plugins.mixin apply false - alias libs.plugins.librarian apply false + alias libs.plugins.architecturyloom apply false + alias libs.plugins.architecturyplugin apply false + alias libs.plugins.shadow apply false alias libs.plugins.cursegradle apply false alias libs.plugins.minotaur apply false } -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/main.gradle' -apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/tasks.gradle' +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/main.gradle" diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index 75109d0..03b8ecb 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -1,14 +1,11 @@ -# Sets default memory used for gradle commands. Can be overridden by user or command line properties. -# This is required to provide enough memory for the Minecraft decompilation process. -org.gradle.jvmargs=-Xmx3G +org.gradle.jvmargs=-Xmx4G org.gradle.daemon=false -org.gradle.parallel=true copyBuildJar=true # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=8.0.1 +modVersion=20.4.0 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modLicense=MPL-2.0 @@ -21,15 +18,29 @@ modForgeDisplayTest=MATCH_VERSION # "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod modFabricEnvironment=* +# Version Catalog +dependenciesVersionCatalog=1.20.4-v13 +dependenciesPuzzlesLibVersion=20.4.7 +dependenciesMinPuzzlesLibVersion=20.4.7 + # Mod Publishing projectReleaseType=release projectCurseForgeId=539057 projectModrinthId=8pcjMDgj -dependenciesVersionCatalog=1.20.1-v5 -dependenciesRequiredForgeCurseForge=puzzles-lib dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib -dependenciesRequiredForgeModrinth=puzzles-lib +dependenciesRequiredNeoForgeCurseForge=puzzles-lib +dependenciesRequiredForgeCurseForge=forge-config-api-port-fabric, puzzles-lib dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib -#dependenciesEmbeddedFabricCurseForge=cardinal-components +dependenciesRequiredNeoForgeModrinth=puzzles-lib +dependenciesRequiredForgeModrinth=forge-config-api-port, puzzles-lib + +dependenciesOptionalFabricCurseForge=config-menus-forge +dependenciesOptionalNeoForgeCurseForge=config-menus-forge +dependenciesOptionalForgeCurseForge=config-menus-forge +dependenciesOptionalFabricModrinth=forge-config-screens +dependenciesOptionalNeoForgeModrinth=forge-config-screens +dependenciesOptionalForgeModrinth=forge-config-screens + +#dependenciesEmbeddedFabricCurseForge=cardinal-components-api #dependenciesEmbeddedFabricModrinth=cardinal-components-api diff --git a/1.20.4/gradle/wrapper/gradle-wrapper.properties b/1.20.4/gradle/wrapper/gradle-wrapper.properties index 37aef8d..3499ded 100644 --- a/1.20.4/gradle/wrapper/gradle-wrapper.properties +++ b/1.20.4/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-8.1.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-8.5-bin.zip networkTimeout=10000 zipStoreBase=GRADLE_USER_HOME zipStorePath=wrapper/dists diff --git a/1.20.4/settings.gradle b/1.20.4/settings.gradle index 697dd5f..e401f79 100644 --- a/1.20.4/settings.gradle +++ b/1.20.4/settings.gradle @@ -1,38 +1,13 @@ pluginManagement { repositories { gradlePluginPortal() - maven { - name = 'Fabric' - url = 'https://maven.fabricmc.net/' - } - maven { - name = 'Sponge' - url = 'https://repo.spongepowered.org/repository/maven-public/' - } - maven { - name = 'Quilt' - url = 'https://maven.quiltmc.org/repository/release' - } - maven { - name = 'Minecraft Forge' - url = 'https://maven.minecraftforge.net/' - } + maven { url "https://maven.architectury.dev/" } + maven { url "https://maven.fabricmc.net/" } + maven { url "https://maven.neoforged.net/releases/" } + maven { url "https://maven.minecraftforge.net/" } } } -dependencyResolutionManagement { - repositories { - maven { - name = "Fuzs Mod Resources" - url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" - } - } - versionCatalogs { - libs { - from("fuzs.sharedcatalogs:sharedcatalogs:${dependenciesVersionCatalog}") - } - } -} +include("Common", "Fabric", "NeoForge", "Forge") -rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}-${dependenciesVersionCatalog.replaceAll("-v\\d+", "")}" -include("Common", "Fabric", "Forge") +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From a5bcb026da86f586db4de58bb063a8d323664d67 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 24 Jan 2024 23:17:37 +0100 Subject: [PATCH 10/24] Create ja_jp.json --- .../src/main/resources/assets/tradingpost/lang/ja_jp.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json new file mode 100644 index 0000000..574d205 --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "交易台", + "container.trading_post": "交易台", + "trading_post.no_trader_found": "近くに交易できる村人が居ません", + "trading_post.trader_gone": "交易できる村人が居なくなりました。", + "trading_post.search": "検索..." +} From 157afdcbbbad5c3c0555d254bb1f531dd554ff13 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 25 Jan 2024 13:23:55 +0100 Subject: [PATCH 11/24] fix refmap --- 1.20.4/CHANGELOG.md | 4 ++++ 1.20.4/Fabric/src/main/resources/fabric.mixins.json | 3 ++- 1.20.4/Forge/src/main/resources/forge.mixins.json | 3 ++- 1.20.4/gradle.properties | 2 +- 4 files changed, 9 insertions(+), 3 deletions(-) diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index 3cbbf65..e009718 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v20.4.1-1.20.4] - 2024-01-25 +### Fixed +- Fix missing mixin refmaps on Fabric & Forge + ## [v20.4.0-1.20.4] - 2024-01-24 - Ported to Minecraft 1.20.4 - Ported to NeoForge diff --git a/1.20.4/Fabric/src/main/resources/fabric.mixins.json b/1.20.4/Fabric/src/main/resources/fabric.mixins.json index b1b7180..6bf7940 100644 --- a/1.20.4/Fabric/src/main/resources/fabric.mixins.json +++ b/1.20.4/Fabric/src/main/resources/fabric.mixins.json @@ -9,5 +9,6 @@ ], "injectors": { "defaultRequire": 1 - } + }, + "refmap": "${modId}.fabric.refmap.json" } diff --git a/1.20.4/Forge/src/main/resources/forge.mixins.json b/1.20.4/Forge/src/main/resources/forge.mixins.json index df416c0..f2b4276 100644 --- a/1.20.4/Forge/src/main/resources/forge.mixins.json +++ b/1.20.4/Forge/src/main/resources/forge.mixins.json @@ -9,5 +9,6 @@ ], "injectors": { "defaultRequire": 1 - } + }, + "refmap": "${modId}.forge.refmap.json" } diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index 03b8ecb..b89463e 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=20.4.0 +modVersion=20.4.1 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modLicense=MPL-2.0 From e6b01a86d5d9c331e18a36f53d9f5b7176ef6995 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 31 Jan 2024 10:15:53 +0100 Subject: [PATCH 12/24] migrate animation logic to own class --- .../blockentity/TradingPostRenderer.java | 62 ++++++++++++----- .../TradingPostAnimationController.java | 68 +++++++++++++++++++ .../block/entity/TradingPostBlockEntity.java | 56 +++------------ 3 files changed, 122 insertions(+), 64 deletions(-) create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java index 4ca2973..ad6b88c 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java @@ -2,7 +2,9 @@ import com.mojang.blaze3d.vertex.PoseStack; import com.mojang.math.Axis; +import fuzs.tradingpost.world.level.block.entity.TradingPostAnimationController; import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.client.renderer.LevelRenderer; import net.minecraft.client.renderer.MultiBufferSource; import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; @@ -17,6 +19,8 @@ * Mostly copied from Quark's MatrixEnchantingTableRenderer.java by Vazkii, thanks! */ public class TradingPostRenderer implements BlockEntityRenderer { + private static final ItemStack ITEM_STACK = new ItemStack(Items.EMERALD); + private final ItemRenderer itemRenderer; public TradingPostRenderer(BlockEntityRendererProvider.Context context) { @@ -24,33 +28,55 @@ public TradingPostRenderer(BlockEntityRendererProvider.Context context) { } @Override - public void render(TradingPostBlockEntity blockEntity, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { - float ageInTicks = blockEntity.time + partialTicks; - float nextRotation = blockEntity.rot - blockEntity.oRot; + public void render(TradingPostBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { + // light is normally always 0 since it checks inside the crafting table block which is solid, but contents are rendered in the block above + packedLight = blockEntity.getLevel() != null ? + LevelRenderer.getLightColor(blockEntity.getLevel(), blockEntity.getBlockPos().above()) : + 15728880; + TradingPostAnimationController animationController = blockEntity.getAnimationController(); + float ageInTicks = animationController.time + partialTick; + float nextRotation = animationController.rot - animationController.oRot; while (nextRotation >= Math.PI) { - nextRotation -= (Math.PI * 2F); + nextRotation -= (float) (Math.PI * 2F); } while (nextRotation < -Math.PI) { - nextRotation += (Math.PI * 2F); + nextRotation += (float) (Math.PI * 2F); } - float bookRotation = blockEntity.oRot + nextRotation * partialTicks; - float bookOpen = Mth.lerp(partialTicks, blockEntity.oOpen, blockEntity.open); - this.renderItem(new ItemStack(Items.EMERALD), ageInTicks, bookOpen, bookRotation, matrixStackIn, bufferIn, combinedLightIn, combinedOverlayIn, blockEntity.getLevel()); + float bookRotation = animationController.oRot + nextRotation * partialTick; + float bookOpen = Mth.lerp(partialTick, animationController.oOpen, animationController.open); + this.renderItem(ITEM_STACK, + ageInTicks, + bookOpen, + bookRotation, + poseStack, + multiBufferSource, + packedLight, + packedOverlay, + blockEntity.getLevel() + ); } - private void renderItem(ItemStack stack, float ageInTicks, float bookOpen, float bookRotation, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, Level level) { - matrixStackIn.pushPose(); - matrixStackIn.translate(0.5F, 1.03125F, 0.5F); - matrixStackIn.scale(0.8F, 0.8F, 0.8F); + private void renderItem(ItemStack itemStack, float ageInTicks, float bookOpen, float bookRotation, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay, Level level) { + poseStack.pushPose(); + poseStack.translate(0.5F, 1.03125F, 0.5F); + poseStack.scale(0.8F, 0.8F, 0.8F); bookRotation *= -180.0F / (float) Math.PI; bookRotation -= 90.0F; bookRotation *= bookOpen; - matrixStackIn.mulPose(Axis.YP.rotationDegrees(bookRotation)); - matrixStackIn.translate(0.0F, bookOpen, Math.sin(bookOpen * Math.PI)); - matrixStackIn.mulPose(Axis.XP.rotationDegrees(-90.0F * (bookOpen - 1.0F))); + poseStack.mulPose(Axis.YP.rotationDegrees(bookRotation)); + poseStack.translate(0.0F, bookOpen, Math.sin(bookOpen * Math.PI)); + poseStack.mulPose(Axis.XP.rotationDegrees(-90.0F * (bookOpen - 1.0F))); float hoveringHeight = (float) Math.sin(ageInTicks * 0.06F) * bookOpen * 0.2F; - matrixStackIn.translate(0.0F, hoveringHeight, 0.0F); - this.itemRenderer.renderStatic(stack, ItemDisplayContext.FIXED, combinedLightIn, combinedOverlayIn, matrixStackIn, bufferIn, level, 0); - matrixStackIn.popPose(); + poseStack.translate(0.0F, hoveringHeight, 0.0F); + this.itemRenderer.renderStatic(itemStack, + ItemDisplayContext.FIXED, + packedLight, + packedOverlay, + poseStack, + multiBufferSource, + level, + 0 + ); + poseStack.popPose(); } } diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java new file mode 100644 index 0000000..1844864 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java @@ -0,0 +1,68 @@ +package fuzs.tradingpost.world.level.block.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class TradingPostAnimationController { + private final Vec3 position; + + public int time; + public float open; + public float oOpen; + public float rot; + public float oRot; + public float tRot; + + public TradingPostAnimationController(BlockPos blockPos) { + this.position = blockPos.getCenter(); + } + + public void tick(Level level) { + ++this.time; + this.oOpen = this.open; + this.oRot = this.rot; + this.setOpenness(level); + this.tickAnimation(); + } + + private void setOpenness(Level level) { + Player player = level.getNearestPlayer(this.position.x(), this.position.y(), this.position.z(), 3.0, false); + if (player != null) { + double d0 = player.getX() - this.position.x(); + double d1 = player.getZ() - this.position.z(); + this.tRot = (float) Mth.atan2(d1, d0); + this.open += 0.1F; + } else { + this.tRot += 0.02F; + this.open -= 0.1F; + } + } + + private void tickAnimation() { + while (this.rot >= (float) Math.PI) { + this.rot -= ((float) Math.PI * 2.0F); + } + while (this.rot < -(float) Math.PI) { + this.rot += ((float) Math.PI * 2.0F); + } + while (this.tRot >= (float) Math.PI) { + this.tRot -= ((float) Math.PI * 2.0F); + } + while (this.tRot < -(float) Math.PI) { + this.tRot += ((float) Math.PI * 2.0F); + } + float f2; + f2 = this.tRot - this.rot; + while (f2 >= (float) Math.PI) { + f2 -= ((float) Math.PI * 2.0F); + } + while (f2 < -(float) Math.PI) { + f2 += ((float) Math.PI * 2.0F); + } + this.rot += f2 * 0.4F; + this.open = Mth.clamp(this.open, 0.0F, 1.0F); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java index 956c2cd..6c3b9b7 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java @@ -5,9 +5,7 @@ import net.minecraft.core.BlockPos; import net.minecraft.nbt.CompoundTag; import net.minecraft.network.chat.Component; -import net.minecraft.util.Mth; import net.minecraft.world.Nameable; -import net.minecraft.world.entity.player.Player; import net.minecraft.world.level.block.entity.BlockEntity; import net.minecraft.world.level.block.state.BlockState; import org.jetbrains.annotations.Nullable; @@ -15,16 +13,13 @@ public class TradingPostBlockEntity extends BlockEntity implements Nameable, TickingBlockEntity { public static final Component CONTAINER_COMPONENT = Component.translatable("container.trading_post"); + private final TradingPostAnimationController animationController; + @Nullable private Component name; - public int time; - public float open; - public float oOpen; - public float rot; - public float oRot; - private float tRot; public TradingPostBlockEntity(BlockPos blockPos, BlockState blockState) { super(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(), blockPos, blockState); + this.animationController = new TradingPostAnimationController(blockPos); } @Override @@ -45,42 +40,11 @@ public void load(CompoundTag compoundTag) { @Override public void clientTick() { - if (this.getLevel() == null || !this.getLevel().isClientSide) return; - this.oOpen = this.open; - this.oRot = this.rot; - Player playerentity = this.getLevel().getNearestPlayer((double) this.getBlockPos().getX() + 0.5, (double) this.getBlockPos().getY() + 0.5, (double) this.getBlockPos().getZ() + 0.5, 3.0, false); - if (playerentity != null) { - double d0 = playerentity.getX() - ((double) this.getBlockPos().getX() + 0.5); - double d1 = playerentity.getZ() - ((double) this.getBlockPos().getZ() + 0.5); - this.tRot = (float) Mth.atan2(d1, d0); - this.open += 0.1F; - } else { - this.tRot += 0.02F; - this.open -= 0.1F; - } - while(this.rot >= (float) Math.PI) { - this.rot -= ((float) Math.PI * 2.0F); - } - while(this.rot < -(float) Math.PI) { - this.rot += ((float) Math.PI * 2.0F); - } - while(this.tRot >= (float) Math.PI) { - this.tRot -= ((float) Math.PI * 2.0F); - } - while(this.tRot < -(float) Math.PI) { - this.tRot += ((float) Math.PI * 2.0F); - } - float f2; - f2 = this.tRot - this.rot; - while (f2 >= (float) Math.PI) { - f2 -= ((float) Math.PI * 2.0F); - } - while(f2 < -(float) Math.PI) { - f2 += ((float) Math.PI * 2.0F); - } - this.rot += f2 * 0.4F; - this.open = Mth.clamp(this.open, 0.0F, 1.0F); - ++this.time; + this.animationController.tick(this.getLevel()); + } + + public TradingPostAnimationController getAnimationController() { + return this.animationController; } @Override @@ -88,8 +52,8 @@ public Component getName() { return this.name != null ? this.name : CONTAINER_COMPONENT; } - public void setCustomName(@Nullable Component textComponent) { - this.name = textComponent; + public void setCustomName(@Nullable Component component) { + this.name = component; } @Nullable From 9c30590a1b3e2217c2ad915d179daa15bdd2ceb6 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 31 Jan 2024 10:39:18 +0100 Subject: [PATCH 13/24] Update ModBlockLootProvider.java --- .../main/java/fuzs/tradingpost/data/ModBlockLootProvider.java | 1 + 1 file changed, 1 insertion(+) diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java index 992c48f..637a3ba 100644 --- a/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java @@ -5,6 +5,7 @@ import fuzs.tradingpost.init.ModRegistry; public class ModBlockLootProvider extends AbstractLootProvider.Blocks { + public ModBlockLootProvider(DataProviderContext context) { super(context); } From 101646bd4cce490942c75672806919cc9f6774d6 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 10 Feb 2024 11:31:00 +0100 Subject: [PATCH 14/24] update buildscript --- 1.20.4/CHANGELOG.md | 4 ++++ 1.20.4/gradle.properties | 2 +- 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md index e009718..29c66ee 100644 --- a/1.20.4/CHANGELOG.md +++ b/1.20.4/CHANGELOG.md @@ -4,6 +4,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v20.4.2-1.20.4] - 2024-02-10 +### Fixed +- Update build script to fix missing mixin manifest entry on Forge + ## [v20.4.1-1.20.4] - 2024-01-25 ### Fixed - Fix missing mixin refmaps on Fabric & Forge diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties index b89463e..43638c5 100755 --- a/1.20.4/gradle.properties +++ b/1.20.4/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=20.4.1 +modVersion=20.4.2 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modLicense=MPL-2.0 From f76c6730d540f0fa01be1fd79692a23738cb15ce Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 23 Mar 2024 21:58:28 +0100 Subject: [PATCH 15/24] separate client data gen --- .../fuzs/tradingpost/neoforge/TradingPostNeoForge.java | 9 ++++++--- .../neoforge/client/TradingPostNeoForgeClient.java | 7 +++++++ 2 files changed, 13 insertions(+), 3 deletions(-) diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java index 147d893..45ce2b8 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java @@ -7,8 +7,6 @@ import fuzs.tradingpost.data.ModBlockTagProvider; import fuzs.tradingpost.data.ModEntityTypeTagProvider; import fuzs.tradingpost.data.ModRecipeProvider; -import fuzs.tradingpost.data.client.ModLanguageProvider; -import fuzs.tradingpost.data.client.ModModelProvider; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.Mod; import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; @@ -20,6 +18,11 @@ public class TradingPostNeoForge { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); - DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, ModBlockLootProvider::new, ModBlockTagProvider::new, ModEntityTypeTagProvider::new, ModRecipeProvider::new, ModLanguageProvider::new, ModModelProvider::new); + DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, + ModBlockLootProvider::new, + ModBlockTagProvider::new, + ModEntityTypeTagProvider::new, + ModRecipeProvider::new + ); } } diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java index 8173684..82c4e26 100644 --- a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java @@ -1,8 +1,11 @@ package fuzs.tradingpost.neoforge.client; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.client.TradingPostClient; +import fuzs.tradingpost.data.client.ModLanguageProvider; +import fuzs.tradingpost.data.client.ModModelProvider; import net.neoforged.api.distmarker.Dist; import net.neoforged.bus.api.SubscribeEvent; import net.neoforged.fml.common.Mod; @@ -14,5 +17,9 @@ public class TradingPostNeoForgeClient { @SubscribeEvent public static void onConstructMod(final FMLConstructModEvent evt) { ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); + DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, + ModLanguageProvider::new, + ModModelProvider::new + ); } } From d6d8303c923dbc40ec43dc86f7805ebea0f709d8 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 4 Jul 2024 23:53:37 +0200 Subject: [PATCH 16/24] prepare 1.21 port --- 1.21/CHANGELOG.md | 8 + 1.21/Common/build.gradle | 10 + .../java/fuzs/tradingpost/TradingPost.java | 55 +++ .../tradingpost/client/TradingPostClient.java | 49 +++ .../screens/inventory/TradingPostScreen.java | 342 ++++++++++++++++++ .../blockentity/TradingPostRenderer.java | 82 +++++ .../fuzs/tradingpost/config/ServerConfig.java | 35 ++ .../data/ModBlockLootProvider.java | 17 + .../tradingpost/data/ModBlockTagProvider.java | 19 + .../data/ModEntityTypeTagProvider.java | 18 + .../tradingpost/data/ModRecipeProvider.java | 30 ++ .../data/client/ModLanguageProvider.java | 23 ++ .../data/client/ModModelProvider.java | 18 + .../fuzs/tradingpost/init/ModRegistry.java | 34 ++ .../mixin/accessor/MerchantMenuAccessor.java | 20 + .../mixin/accessor/VillagerAccessor.java | 13 + .../mixin/client/accessor/ButtonAccessor.java | 14 + .../accessor/MerchantScreenAccessor.java | 34 ++ .../accessor/TradeOfferButtonAccessor.java | 16 + .../network/S2CBuildOffersMessage.java | 62 ++++ .../network/S2CMerchantDataMessage.java | 73 ++++ .../network/S2CRemoveMerchantsMessage.java | 59 +++ .../network/client/C2SClearSlotsMessage.java | 34 ++ .../world/entity/npc/LocalMerchant.java | 42 +++ .../world/entity/npc/MerchantCollection.java | 286 +++++++++++++++ .../world/inventory/TradingPostContainer.java | 22 ++ .../world/inventory/TradingPostMenu.java | 207 +++++++++++ .../world/item/trading/TradingPostOffers.java | 58 +++ .../world/level/block/TradingPostBlock.java | 181 +++++++++ .../TradingPostAnimationController.java | 68 ++++ .../block/entity/TradingPostBlockEntity.java | 64 ++++ .../main/resources/architectury.common.json | 3 + .../assets/tradingpost/lang/it_it.json | 7 + .../assets/tradingpost/lang/ja_jp.json | 7 + .../assets/tradingpost/lang/pt_br.json | 7 + .../assets/tradingpost/lang/ru_ru.json | 7 + .../assets/tradingpost/lang/zh_tw.json | 7 + .../models/block/trading_post.json | 63 ++++ .../textures/block/trading_post_bottom.png | Bin 0 -> 1321 bytes .../textures/block/trading_post_front.png | Bin 0 -> 1610 bytes .../textures/block/trading_post_side.png | Bin 0 -> 1585 bytes .../textures/block/trading_post_top.png | Bin 0 -> 1640 bytes .../container/villager/magnifying_glass.png | Bin 0 -> 744 bytes .../src/main/resources/common.mixins.json | 18 + 1.21/Common/src/main/resources/mod_banner.png | Bin 0 -> 20290 bytes 1.21/Common/src/main/resources/mod_logo.png | Bin 0 -> 9609 bytes 1.21/Common/src/main/resources/pack.mcmeta | 6 + .../main/resources/tradingpost.accesswidener | 1 + 1.21/Fabric/build.gradle | 19 + .../tradingpost/fabric/TradingPostFabric.java | 13 + .../client/TradingPostFabricClient.java | 14 + .../src/main/resources/fabric.mixins.json | 14 + .../Fabric/src/main/resources/fabric.mod.json | 45 +++ 1.21/Forge/build.gradle | 6 + 1.21/Forge/gradle.properties | 1 + .../tradingpost/forge/TradingPostForge.java | 17 + .../forge/client/TradingPostForgeClient.java | 18 + .../src/main/resources/META-INF/mods.toml | 51 +++ .../src/main/resources/forge.mixins.json | 14 + 1.21/NeoForge/build.gradle | 6 + 1.21/NeoForge/gradle.properties | 1 + .../neoforge/TradingPostNeoForge.java | 28 ++ .../client/TradingPostNeoForgeClient.java | 25 ++ .../src/main/resources/META-INF/mods.toml | 49 +++ .../src/main/resources/neoforge.mixins.json | 13 + 1.21/build.gradle | 9 + 1.21/gradle.properties | 45 +++ 1.21/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes 1.21/gradle/wrapper/gradle-wrapper.properties | 6 + 1.21/gradlew | 244 +++++++++++++ 1.21/gradlew.bat | 92 +++++ 1.21/settings.gradle | 16 + 72 files changed, 2865 insertions(+) create mode 100644 1.21/CHANGELOG.md create mode 100644 1.21/Common/build.gradle create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java create mode 100644 1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java create mode 100644 1.21/Common/src/main/resources/architectury.common.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/lang/it_it.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/lang/pt_br.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/textures/gui/sprites/container/villager/magnifying_glass.png create mode 100644 1.21/Common/src/main/resources/common.mixins.json create mode 100644 1.21/Common/src/main/resources/mod_banner.png create mode 100644 1.21/Common/src/main/resources/mod_logo.png create mode 100755 1.21/Common/src/main/resources/pack.mcmeta create mode 100644 1.21/Common/src/main/resources/tradingpost.accesswidener create mode 100644 1.21/Fabric/build.gradle create mode 100644 1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/TradingPostFabric.java create mode 100644 1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/client/TradingPostFabricClient.java create mode 100644 1.21/Fabric/src/main/resources/fabric.mixins.json create mode 100644 1.21/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.21/Forge/build.gradle create mode 100644 1.21/Forge/gradle.properties create mode 100644 1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java create mode 100644 1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java create mode 100644 1.21/Forge/src/main/resources/META-INF/mods.toml create mode 100644 1.21/Forge/src/main/resources/forge.mixins.json create mode 100644 1.21/NeoForge/build.gradle create mode 100644 1.21/NeoForge/gradle.properties create mode 100644 1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java create mode 100644 1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java create mode 100644 1.21/NeoForge/src/main/resources/META-INF/mods.toml create mode 100644 1.21/NeoForge/src/main/resources/neoforge.mixins.json create mode 100644 1.21/build.gradle create mode 100755 1.21/gradle.properties create mode 100644 1.21/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.21/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.21/gradlew create mode 100644 1.21/gradlew.bat create mode 100644 1.21/settings.gradle diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md new file mode 100644 index 0000000..168dc2f --- /dev/null +++ b/1.21/CHANGELOG.md @@ -0,0 +1,8 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), +and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). + +## [v21.0.0-1.21] - 2024-07-04 +- Port to Minecraft 1.21 diff --git a/1.21/Common/build.gradle b/1.21/Common/build.gradle new file mode 100644 index 0000000..e1d5c20 --- /dev/null +++ b/1.21/Common/build.gradle @@ -0,0 +1,10 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/common.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common +} + +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).configureEach { + targetNamespace = "named" +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java new file mode 100644 index 0000000..8a3e329 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java @@ -0,0 +1,55 @@ +package fuzs.tradingpost; + +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.core.v1.context.BuildCreativeModeTabContentsContext; +import fuzs.puzzleslib.api.core.v1.context.FuelBurnTimesContext; +import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.network.S2CBuildOffersMessage; +import fuzs.tradingpost.network.S2CMerchantDataMessage; +import fuzs.tradingpost.network.S2CRemoveMerchantsMessage; +import fuzs.tradingpost.network.client.C2SClearSlotsMessage; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTabs; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TradingPost implements ModConstructor { + public static final String MOD_ID = "tradingpost"; + public static final String MOD_NAME = "Trading Post"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID, false); + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).server(ServerConfig.class); + + @Override + public void onConstructMod() { + ModRegistry.touch(); + registerMessages(); + } + + private static void registerMessages() { + NETWORK.registerClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new); + NETWORK.registerClientbound(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new); + NETWORK.registerClientbound(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new); + NETWORK.registerServerbound(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new); + } + + @Override + public void onBuildCreativeModeTabContents(BuildCreativeModeTabContentsContext context) { + context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (itemDisplayParameters, output) -> { + output.accept(ModRegistry.TRADING_POST_ITEM.value()); + }); + } + + @Override + public void onRegisterFuelBurnTimes(FuelBurnTimesContext context) { + context.registerFuel(300, ModRegistry.TRADING_POST_BLOCK.value()); + } + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java new file mode 100644 index 0000000..f459e21 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -0,0 +1,49 @@ +package fuzs.tradingpost.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientAbstractions; +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; +import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import fuzs.tradingpost.client.renderer.blockentity.TradingPostRenderer; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.ChatFormatting; +import net.minecraft.client.searchtree.FullTextSearchTree; +import net.minecraft.client.searchtree.SearchRegistry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; +import net.minecraft.world.item.trading.MerchantOffer; + +import java.util.stream.Stream; + +public class TradingPostClient implements ClientModConstructor { + + public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); + + @Override + public void onClientSetup() { + ClientAbstractions.INSTANCE.getSearchRegistry().register(OFFER_SEARCH_TREE, base -> new FullTextSearchTree<>(offer -> + Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) + .filter(itemStack -> !itemStack.isEmpty()) + .flatMap(itemStack -> itemStack.getTooltipLines(null, TooltipFlag.Default.NORMAL).stream()) + .map(tooltipLine -> ChatFormatting.stripFormatting(tooltipLine.getString()).trim()) + .filter(tooltipString -> !tooltipString.isEmpty()), + offer -> Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) + .filter(itemStack -> !itemStack.isEmpty()) + .map(ItemStack::getItem) + .map(BuiltInRegistries.ITEM::getKey), + base + )); + } + + @Override + public void onRegisterMenuScreens(MenuScreensContext context) { + context.registerMenuScreen(ModRegistry.TRADING_POST_MENU_TYPE.value(), TradingPostScreen::new); + } + + @Override + public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { + context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(), TradingPostRenderer::new); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java new file mode 100644 index 0000000..7a9ddf1 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -0,0 +1,342 @@ +package fuzs.tradingpost.client.gui.screens.inventory; + +import com.mojang.blaze3d.systems.RenderSystem; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.client.TradingPostClient; +import fuzs.tradingpost.mixin.client.accessor.ButtonAccessor; +import fuzs.tradingpost.mixin.client.accessor.MerchantScreenAccessor; +import fuzs.tradingpost.mixin.client.accessor.TradeOfferButtonAccessor; +import fuzs.tradingpost.network.client.C2SClearSlotsMessage; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import fuzs.tradingpost.world.item.trading.TradingPostOffers; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.screens.inventory.MerchantScreen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.searchtree.SearchTree; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ServerboundSelectTradePacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.MerchantMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; + +import java.util.Locale; +import java.util.Objects; + +public class TradingPostScreen extends MerchantScreen { + public static final ResourceLocation MAGNIFYING_GLASS_LOCATION = TradingPost.id("container/villager/magnifying_glass"); + private static final ResourceLocation VILLAGER_LOCATION = new ResourceLocation("textures/gui/container/villager.png"); + private static final ResourceLocation OUT_OF_STOCK_SPRITE = new ResourceLocation("container/villager/out_of_stock"); + private static final ResourceLocation DISCOUNT_STRIKETHRUOGH_SPRITE = new ResourceLocation("container/villager/discount_strikethrough"); + private static final ResourceLocation CREATIVE_INVENTORY_LOCATION = new ResourceLocation("textures/gui/container/creative_inventory/tab_item_search.png"); + public static final Component DEPRECATED_TRADE_COMPONENT = Component.translatable("merchant.deprecated"); + public static final Component MERCHANT_UNAVAILABLE_COMPONENT = Component.translatable("trading_post.trader_gone"); + + private Button[] tradeOfferButtons = new Button[7]; + private EditBox searchBox; + private boolean ignoreTextInput; + + public TradingPostScreen(MerchantMenu container, Inventory playerInventory, Component title) { + super(container, playerInventory, title); + } + + @Override + protected void init() { + super.init(); + this.tradeOfferButtons = this.renderables.stream().filter(Button.class::isInstance).limit(7).map(Button.class::cast).toArray(Button[]::new); + Objects.checkIndex(6, this.tradeOfferButtons.length); + for (Button tradeOfferButton : this.tradeOfferButtons) { + + ((ButtonAccessor) tradeOfferButton).tradingpost$setOnPress(button -> { + + MerchantScreenAccessor accessor = (MerchantScreenAccessor) this; + int shopItem = ((TradeOfferButtonAccessor) button).tradingpost$getIndex() + accessor.tradingpost$getScrollOff(); + MerchantOffers offers = this.getMenu().getOffers(); + accessor.tradingpost$setShopItem(shopItem); + this.getMenu().setSelectionHint(shopItem); + this.getMenu().getTraders().setActiveOffer(offers.get(shopItem)); + this.getMenu().tryMoveItems(shopItem); + // get real index when sending to server + this.minecraft.getConnection().send(new ServerboundSelectTradePacket(offers instanceof TradingPostOffers ? ((TradingPostOffers) offers).getOrigShopItem(shopItem) : shopItem)); + }); + } + + this.searchBox = new EditBox(this.font, this.leftPos + 13, this.topPos + 6, 80, 9, TradingPostBlockEntity.CONTAINER_COMPONENT); + this.searchBox.setMaxLength(50); + this.searchBox.setBordered(false); + this.searchBox.setTextColor(16777215); + this.addWidget(this.searchBox); + } + + @Override + public void resize(Minecraft minecraft, int width, int height) { + String lastSearch = this.searchBox.getValue(); + super.resize(minecraft, width, height); + this.searchBox.setValue(lastSearch); + if (!this.searchBox.getValue().isEmpty()) { + this.refreshSearchResults(); + } + } + + @Override + protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) { + Component title = this.getMenu().getTraders().getDisplayName(); + if (title != null) { + int traderLevel = this.menu.getTraderLevel(); + if (traderLevel > 0 && traderLevel <= 5 && this.menu.showProgressBar()) { + title = title.copy().append(" - ").append(Component.translatable("merchant.level." + traderLevel)); + } + } else { + title = this.title; + } + guiGraphics.drawString(this.font, title, (49 + this.imageWidth / 2 - this.font.width(title) / 2), 6, 0x404040, false); + guiGraphics.drawString(this.font, this.playerInventoryTitle, this.inventoryLabelX, this.inventoryLabelY, 0x404040, false); + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTime) { + + MerchantOffers merchantoffers = this.getMenu().getOffers(); + this.setButtonsActive(merchantoffers); + + int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); + Slot hoveredSlot = this.hoveredSlot; + // set offers to empty to prevent MerchantScreen::render code from running, also disabled buttons drawing tooltips by changing scrollOff, as well as tooltip for hovered slot by removing hovered slot + this.lock(true, merchantoffers.size(), null); + super.render(guiGraphics, mouseX, mouseY, partialTime); + // reset everything so we can do this ourselves + this.lock(false, scrollOff, hoveredSlot); + + if (!merchantoffers.isEmpty()) { + + // normally rendered as part of background, but skipped as offers are empty when it's called + int shopItemIndex = ((MerchantScreenAccessor) this).tradingpost$getShopItem(); + if (shopItemIndex >= 0 && shopItemIndex < merchantoffers.size()) { + + MerchantOffer merchantoffer = merchantoffers.get(shopItemIndex); + if (merchantoffer.isOutOfStock()) { + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + guiGraphics.blitSprite(OUT_OF_STOCK_SPRITE, this.leftPos + 83 + 99, this.topPos + 35, 0, 28, 21); + } + } + + int posX = this.leftPos + 5; + int posY = this.topPos + 16 + 2; + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); + ((MerchantScreenAccessor) this).tradingpost$callRenderScroller(guiGraphics, this.leftPos, this.topPos, merchantoffers); + + for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { + + if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { + + MerchantOffer merchantoffer = merchantoffers.get(i); + // move this call here to render below red overlay + ((MerchantScreenAccessor) this).tradingpost$callRenderButtonArrows(guiGraphics, merchantoffer, this.leftPos, posY + 1); + if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { + + guiGraphics.fill(posX, posY, posX + 88, posY + 20, 822018048); + } + + ItemStack baseCostA = merchantoffer.getBaseCostA(); + ItemStack costA = merchantoffer.getCostA(); + ItemStack costB = merchantoffer.getCostB(); + ItemStack result = merchantoffer.getResult(); + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(0.0F, 0.0F, 100.0F); + + if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { + + RenderSystem.depthFunc(516); + guiGraphics.fill(posX, posY, posX + 88, posY + 20, 822083583); + RenderSystem.depthFunc(515); + } + + this.renderAndDecorateCostA(guiGraphics, posX, posY, baseCostA, costA); + + if (!costB.isEmpty()) { + guiGraphics.renderFakeItem(costB, posX + 35, posY + 1); + guiGraphics.renderItemDecorations(this.font, costB, posX + 35, posY + 1); + } + + guiGraphics.renderFakeItem(result, posX + 68, posY + 1); + guiGraphics.renderItemDecorations(this.font, result, posX + 68, posY + 1); + guiGraphics.pose().popPose(); + posY += 20; + } + } + + MerchantOffer activeOffer = merchantoffers.get(shopItemIndex); + if (this.getMenu().showProgressBar()) { + + ((MerchantScreenAccessor) this).tradingpost$callRenderProgressBar(guiGraphics, this.leftPos, this.topPos, activeOffer); + } + + if (activeOffer.isOutOfStock() && this.isHovering(186, 35, 22, 21, mouseX, mouseY) && this.getMenu().canRestock()) { + + guiGraphics.renderTooltip(this.font, DEPRECATED_TRADE_COMPONENT, mouseX, mouseY); + } + + posY = this.topPos + 16 + 2; + for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { + + if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { + + MerchantOffer merchantoffer = merchantoffers.get(i); + if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { + + if (this.isHovering(posX, posY, 88, 19, mouseX + this.leftPos, mouseY + this.topPos)) { + + guiGraphics.renderTooltip(this.font, MERCHANT_UNAVAILABLE_COMPONENT, mouseX, mouseY); + } + } + + posY += 20; + } + } + RenderSystem.enableDepthTest(); + } + + // move this out of if block above since search may update this + Button[] offerButtons = this.tradeOfferButtons; + for (int i = 0, offerButtonsLength = offerButtons.length; i < offerButtonsLength; i++) { + + Button button = offerButtons[i]; + if (button.active && button.isHoveredOrFocused()) { + + ((TradeOfferButtonAccessor) button).tradingpost$callRenderToolTip(guiGraphics, mouseX, mouseY); + } + + button.visible = i < this.getMenu().getOffers().size(); + } + + this.renderTooltip(guiGraphics, mouseX, mouseY); + } + + private void renderAndDecorateCostA(GuiGraphics guiGraphics, int posX, int posY, ItemStack baseCostA, ItemStack costA) { + guiGraphics.renderFakeItem(costA, posX + 5, posY + 1); + if (baseCostA.getCount() == costA.getCount()) { + guiGraphics.renderItemDecorations(this.font, costA, posX + 5, posY + 1); + } else { + guiGraphics.renderItemDecorations(this.font, baseCostA, posX + 5, posY + 1, baseCostA.getCount() == 1 ? "1" : null); + guiGraphics.renderItemDecorations(this.font, costA, posX + 5 + 14, posY + 1, costA.getCount() == 1 ? "1" : null); + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(0.0F, 0.0F, 300.0F); + guiGraphics.blitSprite(DISCOUNT_STRIKETHRUOGH_SPRITE, posX + 5 + 7, posY + 1 + 12, 0, 9, 2); + guiGraphics.pose().popPose(); + } + } + + private void setButtonsActive(MerchantOffers merchantoffers) { + + if (!merchantoffers.isEmpty()) { + + for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { + + int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); + if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { + + MerchantOffer offer = merchantoffers.get(i); + this.tradeOfferButtons[i - scrollOff].active = this.getMenu().getTraders().checkOffer(offer); + } + } + } + } + + private void lock(boolean lockOffers, int newScrollOff, Slot newHoveredSlot) { + this.getMenu().lockOffers(lockOffers); + ((MerchantScreenAccessor) this).tradingpost$setScrollOff(newScrollOff); + this.hoveredSlot = newHoveredSlot; + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, float partialTicks, int mouseX, int mouseY) { + super.renderBg(guiGraphics, partialTicks, mouseX, mouseY); + guiGraphics.blit(CREATIVE_INVENTORY_LOCATION, this.leftPos + 11, this.topPos + 4, 0, 80.0F, 4.0F, 90, 12, 256, 256); + this.searchBox.render(guiGraphics, mouseX, mouseY, partialTicks); + guiGraphics.blitSprite(MAGNIFYING_GLASS_LOCATION, this.leftPos, this.topPos + 4, 0, 16, 16); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int mouseKey) { + if (this.searchBox.mouseClicked(mouseX, mouseY, mouseKey)) { + this.searchBox.setFocused(true); + return true; + } + return super.mouseClicked(mouseX, mouseY, mouseKey); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifierKeys) { + this.ignoreTextInput = false; + String lastSearch = this.searchBox.getValue().trim(); + if (this.searchBox.keyPressed(keyCode, scanCode, modifierKeys)) { + + if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { + + this.refreshSearchResults(); + } + + return true; + } else if (this.searchBox.isFocused() && this.searchBox.isVisible() && keyCode != 256) { + return true; + } else if (this.minecraft.options.keyChat.matches(keyCode, scanCode) && !this.searchBox.isFocused()) { + this.ignoreTextInput = true; + this.searchBox.setFocused(true); + return true; + } + + return super.keyPressed(keyCode, scanCode, modifierKeys); + } + + @Override + public boolean charTyped(char typedChar, int modifierKeys) { + + String lastSearch = this.searchBox.getValue().trim(); + if (!this.ignoreTextInput && this.searchBox.charTyped(typedChar, modifierKeys)) { + + if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { + + this.refreshSearchResults(); + } + + return true; + } + + return super.charTyped(typedChar, modifierKeys); + } + + public void refreshSearchResults() { + + if (!(this.getMenu().getOffers() instanceof TradingPostOffers offers)) { + return; + } + String query = this.searchBox.getValue().trim(); + if (query.isEmpty()) { + offers.clearFilter(); + } else { + SearchTree isearchtree = this.minecraft.getSearchTree(TradingPostClient.OFFER_SEARCH_TREE); + offers.setFilter(isearchtree.search(query.toLowerCase(Locale.ROOT))); + } + ((MerchantScreenAccessor) this).tradingpost$setScrollOff(0); + ((MerchantScreenAccessor) this).tradingpost$setShopItem(0); + this.getMenu().setSelectionHint(-1); + this.getMenu().getTraders().setActiveOffer(null); + this.getMenu().clearPaymentSlots(); + TradingPost.NETWORK.sendToServer(new C2SClearSlotsMessage()); + } + + @Override + public TradingPostMenu getMenu() { + return (TradingPostMenu) super.getMenu(); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/1.21/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java new file mode 100644 index 0000000..ad6b88c --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java @@ -0,0 +1,82 @@ +package fuzs.tradingpost.client.renderer.blockentity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import fuzs.tradingpost.world.level.block.entity.TradingPostAnimationController; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.client.renderer.LevelRenderer; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; + +/** + * Mostly copied from Quark's MatrixEnchantingTableRenderer.java by Vazkii, thanks! + */ +public class TradingPostRenderer implements BlockEntityRenderer { + private static final ItemStack ITEM_STACK = new ItemStack(Items.EMERALD); + + private final ItemRenderer itemRenderer; + + public TradingPostRenderer(BlockEntityRendererProvider.Context context) { + this.itemRenderer = context.getItemRenderer(); + } + + @Override + public void render(TradingPostBlockEntity blockEntity, float partialTick, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay) { + // light is normally always 0 since it checks inside the crafting table block which is solid, but contents are rendered in the block above + packedLight = blockEntity.getLevel() != null ? + LevelRenderer.getLightColor(blockEntity.getLevel(), blockEntity.getBlockPos().above()) : + 15728880; + TradingPostAnimationController animationController = blockEntity.getAnimationController(); + float ageInTicks = animationController.time + partialTick; + float nextRotation = animationController.rot - animationController.oRot; + while (nextRotation >= Math.PI) { + nextRotation -= (float) (Math.PI * 2F); + } + while (nextRotation < -Math.PI) { + nextRotation += (float) (Math.PI * 2F); + } + float bookRotation = animationController.oRot + nextRotation * partialTick; + float bookOpen = Mth.lerp(partialTick, animationController.oOpen, animationController.open); + this.renderItem(ITEM_STACK, + ageInTicks, + bookOpen, + bookRotation, + poseStack, + multiBufferSource, + packedLight, + packedOverlay, + blockEntity.getLevel() + ); + } + + private void renderItem(ItemStack itemStack, float ageInTicks, float bookOpen, float bookRotation, PoseStack poseStack, MultiBufferSource multiBufferSource, int packedLight, int packedOverlay, Level level) { + poseStack.pushPose(); + poseStack.translate(0.5F, 1.03125F, 0.5F); + poseStack.scale(0.8F, 0.8F, 0.8F); + bookRotation *= -180.0F / (float) Math.PI; + bookRotation -= 90.0F; + bookRotation *= bookOpen; + poseStack.mulPose(Axis.YP.rotationDegrees(bookRotation)); + poseStack.translate(0.0F, bookOpen, Math.sin(bookOpen * Math.PI)); + poseStack.mulPose(Axis.XP.rotationDegrees(-90.0F * (bookOpen - 1.0F))); + float hoveringHeight = (float) Math.sin(ageInTicks * 0.06F) * bookOpen * 0.2F; + poseStack.translate(0.0F, hoveringHeight, 0.0F); + this.itemRenderer.renderStatic(itemStack, + ItemDisplayContext.FIXED, + packedLight, + packedOverlay, + poseStack, + multiBufferSource, + level, + 0 + ); + poseStack.popPose(); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java b/1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java new file mode 100644 index 0000000..936d6a4 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java @@ -0,0 +1,35 @@ +package fuzs.tradingpost.config; + +import com.google.common.collect.Lists; +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; +import fuzs.puzzleslib.api.config.v3.serialization.ConfigDataSet; +import fuzs.tradingpost.TradingPost; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.EntityType; + +import java.util.List; + +public class ServerConfig implements ConfigCore { + @Config(description = "Range on xz plane trading post should search for merchants.") + @Config.IntRange(min = 1, max = 96) + public int horizontalRange = 24; + @Config(description = "Range on y axis trading post should search for merchants.") + @Config.IntRange(min = 1, max = 96) + public int verticalRange = 16; + @Config(description = "Disable traders on the trading screen when they wander out of range.") + public boolean enforceRange = false; + @Config(description = "Teleport xp from trading from villagers on top of the trading post.") + public boolean teleportXp = true; + @Config(name = "close_empty_screen", description = "Close trading post interface when all traders have become unavailable.") + public boolean closeScreen = true; + @Config(name = "trader_blacklist", description = {"Trader entities disabled from being found by the trading post.", "Modders may add their own incompatible trader entities via the \"" + TradingPost.MOD_ID + ":blacklisted_traders\" entity tag.", ConfigDataSet.CONFIG_DESCRIPTION}) + List traderBlacklistRaw = Lists.newArrayList(); + + public ConfigDataSet> traderBlacklist; + + @Override + public void afterConfigReload() { + this.traderBlacklist = ConfigDataSet.from(Registries.ENTITY_TYPE, this.traderBlacklistRaw); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java new file mode 100644 index 0000000..637a3ba --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockLootProvider.java @@ -0,0 +1,17 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractLootProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; + +public class ModBlockLootProvider extends AbstractLootProvider.Blocks { + + public ModBlockLootProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addLootTables() { + this.add(ModRegistry.TRADING_POST_BLOCK.value(), this::createNameableBlockEntityTable); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java new file mode 100644 index 0000000..9eb0a46 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java @@ -0,0 +1,19 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractTagProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.core.HolderLookup; +import net.minecraft.tags.BlockTags; + +public class ModBlockTagProvider extends AbstractTagProvider.Blocks { + + public ModBlockTagProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTags(HolderLookup.Provider provider) { + this.tag(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.TRADING_POST_BLOCK.value()); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java new file mode 100644 index 0000000..e41bf65 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java @@ -0,0 +1,18 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractTagProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.core.HolderLookup; + +public class ModEntityTypeTagProvider extends AbstractTagProvider.EntityTypes { + + public ModEntityTypeTagProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTags(HolderLookup.Provider provider) { + this.tag(ModRegistry.CONCEALED_TRADERS_ENTITY_TYPE_TAG); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java new file mode 100644 index 0000000..9f06de2 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModRecipeProvider.java @@ -0,0 +1,30 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v2.AbstractRecipeProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.data.recipes.RecipeCategory; +import net.minecraft.data.recipes.RecipeOutput; +import net.minecraft.data.recipes.ShapedRecipeBuilder; +import net.minecraft.tags.ItemTags; +import net.minecraft.world.item.Items; + +public class ModRecipeProvider extends AbstractRecipeProvider { + + public ModRecipeProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addRecipes(RecipeOutput recipeOutput) { + ShapedRecipeBuilder.shaped(RecipeCategory.DECORATIONS, ModRegistry.TRADING_POST_BLOCK.value()) + .define('#', ItemTags.PLANKS) + .define('X', Items.EMERALD) + .define('S', Items.STICK) + .pattern(" X ") + .pattern("###") + .pattern("S S") + .unlockedBy(getHasName(Items.EMERALD), has(Items.EMERALD)) + .save(recipeOutput); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java new file mode 100644 index 0000000..a1f0e67 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModLanguageProvider.java @@ -0,0 +1,23 @@ +package fuzs.tradingpost.data.client; + +import fuzs.puzzleslib.api.client.data.v2.AbstractLanguageProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; + +public class ModLanguageProvider extends AbstractLanguageProvider { + + public ModLanguageProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addTranslations(TranslationBuilder builder) { + builder.add(ModRegistry.TRADING_POST_BLOCK.value(), "Trading Post"); + builder.add(TradingPostBlockEntity.CONTAINER_COMPONENT, "Trading Post"); + builder.add(TradingPostScreen.MERCHANT_UNAVAILABLE_COMPONENT, "The trader is no longer available."); + builder.add(TradingPostBlock.MISSING_MERCHANT_COMPONENT, "Couldn't find any available trader nearby"); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java new file mode 100644 index 0000000..5bb580a --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/client/ModModelProvider.java @@ -0,0 +1,18 @@ +package fuzs.tradingpost.data.client; + +import fuzs.puzzleslib.api.client.data.v2.AbstractModelProvider; +import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.data.models.BlockModelGenerators; + +public class ModModelProvider extends AbstractModelProvider { + + public ModModelProvider(DataProviderContext context) { + super(context); + } + + @Override + public void addBlockModels(BlockModelGenerators builder) { + builder.createNonTemplateModelBlock(ModRegistry.TRADING_POST_BLOCK.value()); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java new file mode 100644 index 0000000..4994315 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java @@ -0,0 +1,34 @@ +package fuzs.tradingpost.init; + +import fuzs.puzzleslib.api.init.v3.registry.RegistryManager; +import fuzs.puzzleslib.api.init.v3.tags.BoundTagFactory; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.core.Holder; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraft.world.level.material.MapColor; + +public class ModRegistry { + static final RegistryManager REGISTRY = RegistryManager.from(TradingPost.MOD_ID); + public static final Holder.Reference TRADING_POST_BLOCK = REGISTRY.registerBlock("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.5F).sound(SoundType.WOOD).ignitedByLava())); + public static final Holder.Reference TRADING_POST_ITEM = REGISTRY.registerBlockItem(TRADING_POST_BLOCK); + public static final Holder.Reference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType("trading_post", () -> BlockEntityType.Builder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.value())); + public static final Holder.Reference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); + + static final BoundTagFactory TAGS = BoundTagFactory.make(TradingPost.MOD_ID); + public static final TagKey> CONCEALED_TRADERS_ENTITY_TYPE_TAG = TAGS.registerEntityTypeTag("concealed_traders"); + + public static void touch() { + + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java new file mode 100644 index 0000000..bb02a91 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java @@ -0,0 +1,20 @@ +package fuzs.tradingpost.mixin.accessor; + +import net.minecraft.world.inventory.MerchantContainer; +import net.minecraft.world.inventory.MerchantMenu; +import net.minecraft.world.item.trading.Merchant; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MerchantMenu.class) +public interface MerchantMenuAccessor { + + @Mutable + @Accessor + void setTrader(Merchant trader); + + @Mutable + @Accessor + void setTradeContainer(MerchantContainer tradeContainer); +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java new file mode 100644 index 0000000..730cccc --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java @@ -0,0 +1,13 @@ +package fuzs.tradingpost.mixin.accessor; + +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Villager.class) +public interface VillagerAccessor { + + @Invoker + void callUpdateSpecialPrices(Player player); +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java new file mode 100644 index 0000000..5f844e7 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java @@ -0,0 +1,14 @@ +package fuzs.tradingpost.mixin.client.accessor; + +import net.minecraft.client.gui.components.Button; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Button.class) +public interface ButtonAccessor { + + @Mutable + @Accessor("onPress") + void tradingpost$setOnPress(Button.OnPress onPress); +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java new file mode 100644 index 0000000..a67dadd --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java @@ -0,0 +1,34 @@ +package fuzs.tradingpost.mixin.client.accessor; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.MerchantScreen; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(MerchantScreen.class) +public interface MerchantScreenAccessor { + + @Accessor("shopItem") + int tradingpost$getShopItem(); + + @Accessor("shopItem") + void tradingpost$setShopItem(int shopItem); + + @Accessor("scrollOff") + int tradingpost$getScrollOff(); + + @Accessor("scrollOff") + void tradingpost$setScrollOff(int scrollOff); + + @Invoker("renderScroller") + void tradingpost$callRenderScroller(GuiGraphics guiGraphics, int width, int height, MerchantOffers offers); + + @Invoker("renderButtonArrows") + void tradingpost$callRenderButtonArrows(GuiGraphics guiGraphics, MerchantOffer offer, int width, int height); + + @Invoker("renderProgressBar") + void tradingpost$callRenderProgressBar(GuiGraphics guiGraphics, int width, int height, MerchantOffer activeOffer); +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java new file mode 100644 index 0000000..99e17d4 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java @@ -0,0 +1,16 @@ +package fuzs.tradingpost.mixin.client.accessor; + +import net.minecraft.client.gui.GuiGraphics; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(targets = "net.minecraft.client.gui.screens.inventory.MerchantScreen$TradeOfferButton") +public interface TradeOfferButtonAccessor { + + @Accessor("index") + int tradingpost$getIndex(); + + @Invoker("renderToolTip") + void tradingpost$callRenderToolTip(GuiGraphics guiGraphics, int mouseX, int mouseY); +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java new file mode 100644 index 0000000..48d34fb --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java @@ -0,0 +1,62 @@ +package fuzs.tradingpost.network; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.client.TradingPostClient; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; + +public class S2CBuildOffersMessage implements MessageV2 { + private int containerId; + private Int2IntOpenHashMap idToOfferCount; + + public S2CBuildOffersMessage() { + + } + + public S2CBuildOffersMessage(int containerId, Int2IntOpenHashMap idToOfferCount) { + this.containerId = containerId; + this.idToOfferCount = idToOfferCount; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(this.containerId); + buf.writeVarInt(this.idToOfferCount.size()); + for (Int2IntMap.Entry entry : this.idToOfferCount.int2IntEntrySet()) { + buf.writeInt(entry.getIntKey()); + buf.writeVarInt(entry.getIntValue()); + } + } + + @Override + public void read(FriendlyByteBuf buf) { + this.containerId = buf.readVarInt(); + final Int2IntOpenHashMap idToOfferCount = new Int2IntOpenHashMap(); + final int length = buf.readVarInt(); + for (int i = 0; i < length; i++) { + idToOfferCount.put(buf.readInt(), buf.readVarInt()); + } + this.idToOfferCount = idToOfferCount; + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CBuildOffersMessage message, Player player, Object gameInstance) { + Minecraft minecraft = (Minecraft) gameInstance; + if (message.containerId == player.containerMenu.containerId && player.containerMenu instanceof TradingPostMenu playerMenu && minecraft.screen instanceof TradingPostScreen screen) { + playerMenu.getTraders().buildOffers(message.idToOfferCount); + minecraft.populateSearchTree(TradingPostClient.OFFER_SEARCH_TREE, playerMenu.getOffers()); + screen.refreshSearchResults(); + } + } + }; + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java new file mode 100644 index 0000000..91c9727 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java @@ -0,0 +1,73 @@ +package fuzs.tradingpost.network; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.trading.MerchantOffers; + +public class S2CMerchantDataMessage implements MessageV2 { + private int containerId; + private int merchantId; + private Component merchantTitle; + private MerchantOffers offers; + private int villagerLevel; + private int villagerXp; + private boolean showProgress; + private boolean canRestock; + + public S2CMerchantDataMessage() { + + } + + public S2CMerchantDataMessage(int containerId, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { + this.containerId = containerId; + this.merchantId = merchantId; + this.merchantTitle = merchantTitle; + this.offers = offers; + this.villagerLevel = villagerLevel; + this.villagerXp = villagerXp; + this.showProgress = showProgress; + this.canRestock = canRestock; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(this.containerId); + buf.writeInt(this.merchantId); + buf.writeComponent(this.merchantTitle); + this.offers.writeToStream(buf); + buf.writeVarInt(this.villagerLevel); + buf.writeVarInt(this.villagerXp); + buf.writeBoolean(this.showProgress); + buf.writeBoolean(this.canRestock); + } + + @Override + public void read(FriendlyByteBuf buf) { + this.containerId = buf.readVarInt(); + this.merchantId = buf.readInt(); + this.merchantTitle = buf.readComponent(); + this.offers = MerchantOffers.createFromStream(buf); + this.villagerLevel = buf.readVarInt(); + this.villagerXp = buf.readVarInt(); + this.showProgress = buf.readBoolean(); + this.canRestock = buf.readBoolean(); + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CMerchantDataMessage packet, Player player, Object gameInstance) { + AbstractContainerMenu container = player.containerMenu; + if (packet.containerId == container.containerId && container instanceof TradingPostMenu) { + ((TradingPostMenu) container).addMerchant(player, packet.merchantId, packet.merchantTitle, new MerchantOffers(packet.offers.createTag()), packet.villagerLevel, packet.villagerXp, packet.showProgress, packet.canRestock); + } + } + }; + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java new file mode 100644 index 0000000..8aa0653 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java @@ -0,0 +1,59 @@ +package fuzs.tradingpost.network; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; + +public class S2CRemoveMerchantsMessage implements MessageV2 { + private int containerId; + private IntSet merchantIds; + + public S2CRemoveMerchantsMessage() { + + } + + public S2CRemoveMerchantsMessage(int containerId, IntSet merchantIds) { + this.containerId = containerId; + this.merchantIds = merchantIds; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(this.containerId); + buf.writeVarInt(this.merchantIds.size()); + for (int merchantId : this.merchantIds) { + buf.writeInt(merchantId); + } + } + + @Override + public void read(FriendlyByteBuf buf) { + this.containerId = buf.readVarInt(); + int length = buf.readVarInt(); + IntSet merchantIds = new IntOpenHashSet(); + for (int i = 0; i < length; i++) { + merchantIds.add(buf.readInt()); + } + this.merchantIds = merchantIds; + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CRemoveMerchantsMessage packet, Player player, Object gameInstance) { + AbstractContainerMenu container = player.containerMenu; + if (packet.containerId == container.containerId && container instanceof TradingPostMenu) { + for (int merchantId : packet.merchantIds) { + ((TradingPostMenu) container).getTraders().removeMerchant(merchantId); + } + } + } + }; + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java new file mode 100644 index 0000000..ba5d25a --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java @@ -0,0 +1,34 @@ +package fuzs.tradingpost.network.client; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; + +public class C2SClearSlotsMessage implements MessageV2 { + + @Override + public void write(FriendlyByteBuf buf) { + + } + + @Override + public void read(FriendlyByteBuf buf) { + + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(C2SClearSlotsMessage packet, Player player, Object gameInstance) { + AbstractContainerMenu container = player.containerMenu; + if (container instanceof TradingPostMenu) { + ((TradingPostMenu) container).clearPaymentSlots(); + } + } + }; + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java new file mode 100644 index 0000000..3c7a430 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java @@ -0,0 +1,42 @@ +package fuzs.tradingpost.world.entity.npc; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.npc.ClientSideMerchant; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.trading.MerchantOffers; + +public class LocalMerchant extends ClientSideMerchant { + private final Component merchantTitle; + private final int merchantLevel; + private final boolean showProgressBar; + private final boolean canRestock; + + public LocalMerchant(Player playerEntity, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { + super(playerEntity); + this.merchantTitle = merchantTitle; + this.overrideOffers(offers); + this.merchantLevel = villagerLevel; + this.overrideXp(villagerXp); + this.showProgressBar = showProgress; + this.canRestock = canRestock; + } + + public Component getDisplayName() { + return this.merchantTitle; + } + + public int getMerchantLevel() { + return this.merchantLevel; + } + + @Override + public boolean canRestock() { + return this.canRestock; + } + + @Override + public boolean showProgressBar() { + return this.showProgressBar; + } + +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java new file mode 100644 index 0000000..3328c71 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java @@ -0,0 +1,286 @@ +package fuzs.tradingpost.world.entity.npc; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.network.S2CBuildOffersMessage; +import fuzs.tradingpost.network.S2CMerchantDataMessage; +import fuzs.tradingpost.network.S2CRemoveMerchantsMessage; +import fuzs.tradingpost.world.item.trading.TradingPostOffers; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ExperienceOrb; +import net.minecraft.world.entity.npc.VillagerDataHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.Merchant; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.IntConsumer; +import java.util.stream.Collectors; + +public class MerchantCollection implements Merchant { + private final Int2ObjectOpenHashMap idToMerchant = new Int2ObjectOpenHashMap<>(); + private final Set disabledOffers = Sets.newHashSet(); + private final ContainerLevelAccess access; + + private MerchantOffers allOffers = new MerchantOffers(); + private Object2ObjectOpenHashMap offerToMerchant; + private Merchant currentMerchant; + + public MerchantCollection() { + this(ContainerLevelAccess.NULL); + } + + public MerchantCollection(ContainerLevelAccess access) { + this.access = access; + } + + public void addMerchant(int entityId, Merchant merchant) { + if (!merchant.getOffers().isEmpty()) { + this.idToMerchant.put(entityId, merchant); + } + } + + @Override + @Nullable + public Player getTradingPlayer() { + if (this.currentMerchant != null) { + return this.currentMerchant.getTradingPlayer(); + } + return null; + } + + @Override + public void setTradingPlayer(@Nullable Player player) { + this.idToMerchant.values().forEach(merchant -> merchant.setTradingPlayer(player)); + } + + @Override + public MerchantOffers getOffers() { + return this.allOffers; + } + + public boolean checkOffer(MerchantOffer offer) { + return !this.disabledOffers.contains(offer); + } + + @Override + public void overrideOffers(@Nullable MerchantOffers p_213703_1_) { + // this is vanilla, we do this differently + TradingPost.LOGGER.error("Set offers to stored merchants directly"); + } + + @Override + public void notifyTrade(MerchantOffer offer) { + if (this.currentMerchant != null) { + this.currentMerchant.notifyTrade(offer); + if (!TradingPost.CONFIG.get(ServerConfig.class).teleportXp) return; + // reward xp is spawned at trader location, find it and move to trading post + this.access.execute((level, pos) -> { + + if (this.currentMerchant instanceof Entity entity) { + + Vec3 merchantPos = entity.position().add(0.0, 0.5, 0.0); + final double xpWidth = 0.5, xpHeight = 0.5; + List xpRewards = level.getEntitiesOfClass(ExperienceOrb.class, new AABB(merchantPos.add(-xpWidth, -xpHeight, -xpWidth), merchantPos.add(xpWidth, xpHeight, xpWidth)), Entity::isAlive); + // move xp would be much nicer, unfortunately it'd only be moved on the server, so orbs need to be removed and spawned in again + for (ExperienceOrb xpOrb : xpRewards) { + level.addFreshEntity(new ExperienceOrb(level, pos.getX(), pos.getY() + 1.5, pos.getZ(), xpOrb.getValue())); + xpOrb.discard(); + } + } + }); + } + } + + @Override + public void notifyTradeUpdated(ItemStack stack) { + if (this.currentMerchant != null) { + this.currentMerchant.notifyTradeUpdated(stack); + } + } + + @Override + public boolean isClientSide() { + return this.access == ContainerLevelAccess.NULL; + } + + @Override + public int getVillagerXp() { + if (this.currentMerchant != null) { + return this.currentMerchant.getVillagerXp(); + } + return 0; + } + + public Merchant getCurrentMerchant() { + return this.currentMerchant; + } + + @Override + public boolean canRestock() { + if (this.currentMerchant != null) { + return this.currentMerchant.canRestock(); + } + return false; + } + + @Override + public void overrideXp(int xpValue) { + if (this.currentMerchant != null) { + this.currentMerchant.overrideXp(xpValue); + } + } + + @Override + public boolean showProgressBar() { + if (this.currentMerchant != null) { + return this.currentMerchant.showProgressBar(); + } + return false; + } + + @Override + public SoundEvent getNotifyTradeSound() { + if (this.currentMerchant != null) { + return this.currentMerchant.getNotifyTradeSound(); + } + // unused by client, just a dummy + return SoundEvents.VILLAGER_YES; + } + + public int getTraderLevel() { + if (this.currentMerchant != null) { + Merchant merchant = this.currentMerchant; + if (merchant instanceof LocalMerchant) { + return ((LocalMerchant) merchant).getMerchantLevel(); + } else if (merchant instanceof VillagerDataHolder) { + return ((VillagerDataHolder) merchant).getVillagerData().getLevel(); + } + } + return 0; + } + + @Nullable + public Component getDisplayName() { + if (this.currentMerchant != null) { + Merchant merchant = this.currentMerchant; + if (merchant instanceof LocalMerchant) { + return ((LocalMerchant) merchant).getDisplayName(); + } else if (merchant instanceof Entity) { + return ((Entity) merchant).getDisplayName(); + } + } + return null; + } + + public boolean updateAvailableMerchants(int containerId, BlockPos pos, Player player, boolean testRange) { + IntSet toRemove = new IntOpenHashSet(); + for (Map.Entry entry : this.idToMerchant.int2ObjectEntrySet()) { + if (entry.getValue() instanceof Entity) { + if (entry.getValue().getTradingPlayer() != player || testRange && !this.traderInRange((Entity) entry.getValue(), pos)) { + toRemove.add(entry.getKey().intValue()); + } + } + } + if (!toRemove.isEmpty()) { + toRemove.forEach((IntConsumer) this::removeMerchant); + TradingPost.NETWORK.sendTo(new S2CRemoveMerchantsMessage(containerId, toRemove), (ServerPlayer) player); + } + return !this.idToMerchant.isEmpty(); + } + + private boolean traderInRange(Entity entity, BlockPos pos) { + return this.traderInRange(entity, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + } + + private boolean traderInRange(Entity entity, double posX, double posY, double posZ) { + return Math.abs(entity.getX() - posX) <= TradingPost.CONFIG.get(ServerConfig.class).horizontalRange && Math.abs(entity.getY() - posY) <= TradingPost.CONFIG.get(ServerConfig.class).verticalRange && Math.abs(entity.getZ() - posZ) <= TradingPost.CONFIG.get(ServerConfig.class).horizontalRange; + } + + public void removeMerchant(int merchantId) { + Merchant merchant = this.idToMerchant.get(merchantId); + if (merchant != null) { + this.disabledOffers.addAll(merchant.getOffers()); + this.idToMerchant.remove(merchantId); + merchant.setTradingPlayer(null); + if (this.currentMerchant == merchant) { + this.currentMerchant = null; + } + } + } + + public void setActiveOffer(MerchantOffer offer) { + if (this.offerToMerchant != null) { + this.currentMerchant = offer != null ? this.offerToMerchant.get(offer) : null; + } + } + + public void sendMerchantData(final int containerId, Player player) { + for (Map.Entry entry : this.idToMerchant.int2ObjectEntrySet()) { + Merchant merchant = entry.getValue(); + final Component merchantTitle = merchant instanceof Entity ? ((Entity) merchant).getDisplayName() : TradingPostBlockEntity.CONTAINER_COMPONENT; + final int merchantLevel = merchant instanceof VillagerDataHolder ? ((VillagerDataHolder) merchant).getVillagerData().getLevel() : 0; + S2CMerchantDataMessage message = new S2CMerchantDataMessage(containerId, entry.getKey(), merchantTitle, merchant.getOffers(), merchantLevel, merchant.getVillagerXp(), merchant.showProgressBar(), merchant.canRestock()); + TradingPost.NETWORK.sendTo(message, (ServerPlayer) player); + } + TradingPost.NETWORK.sendTo(new S2CBuildOffersMessage(containerId, this.getIdToOfferCountMap()), (ServerPlayer) player); + } + + public Int2IntOpenHashMap getIdToOfferCountMap() { + return this.idToMerchant.int2ObjectEntrySet().stream() + .collect(Collectors.toMap(Int2ObjectMap.Entry::getIntKey, entry -> entry.getValue().getOffers().size(), (o1, o2) -> o1, Int2IntOpenHashMap::new)); + } + + public void buildOffers(Int2IntOpenHashMap idToOfferCount) { + List sortedEntries = Lists.newArrayList(idToOfferCount.int2IntEntrySet()); + sortedEntries.sort(Comparator.comparingInt(Int2IntMap.Entry::getIntKey)); + MerchantOffers allOffers = new TradingPostOffers(this.disabledOffers); + for (Int2IntMap.Entry entry : sortedEntries) { + Merchant merchant = this.idToMerchant.get(entry.getIntKey()); + for (int i = 0; i < entry.getIntValue(); i++) { + MerchantOffer offer; + if (merchant != null && i < merchant.getOffers().size()) { + offer = merchant.getOffers().get(i); + } else { + // this should never actually happen, but you never know with mods + offer = fakeOffer(); + this.disabledOffers.add(offer); + } + allOffers.add(offer); + } + } + this.allOffers = allOffers; + this.buildOfferToMerchantMap(); + } + + private void buildOfferToMerchantMap() { + Object2ObjectOpenHashMap offerToMerchant = new Object2ObjectOpenHashMap<>(); + for (Merchant merchant : this.idToMerchant.values()) { + merchant.getOffers().forEach(offer -> offerToMerchant.put(offer, merchant)); + } + this.offerToMerchant = offerToMerchant; + } + + private static MerchantOffer fakeOffer() { + return new MerchantOffer(ItemStack.EMPTY, ItemStack.EMPTY, -1, -1, 0.0F); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java new file mode 100644 index 0000000..7a1cd60 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java @@ -0,0 +1,22 @@ +package fuzs.tradingpost.world.inventory; + +import fuzs.tradingpost.world.entity.npc.MerchantCollection; +import net.minecraft.world.inventory.MerchantContainer; + +public class TradingPostContainer extends MerchantContainer { + private final MerchantCollection merchant; + + public TradingPostContainer(MerchantCollection merchant) { + super(merchant); + this.merchant = merchant; + this.setSelectionHint(-1); + } + + @Override + public void updateSellItem() { + super.updateSellItem(); + if (this.getActiveOffer() != null) { + this.merchant.setActiveOffer(this.getActiveOffer()); + } + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java new file mode 100644 index 0000000..c9f9ff3 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java @@ -0,0 +1,207 @@ +package fuzs.tradingpost.world.inventory; + +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.mixin.accessor.MerchantMenuAccessor; +import fuzs.tradingpost.world.entity.npc.LocalMerchant; +import fuzs.tradingpost.world.entity.npc.MerchantCollection; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.*; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.Merchant; +import net.minecraft.world.item.trading.MerchantOffers; +import net.minecraft.world.level.Level; + +import java.util.Optional; + +public class TradingPostMenu extends MerchantMenu { + private final ContainerLevelAccess access; + private final MerchantCollection traders; + private final MerchantContainer tradeContainer; + + private int ticks; + private boolean lockOffers; + + public TradingPostMenu(int containerId, Inventory inventory) { + this(containerId, inventory, new MerchantCollection(), ContainerLevelAccess.NULL); + } + + public TradingPostMenu(int containerId, Inventory inventory, MerchantCollection merchantCollection, ContainerLevelAccess worldPosCallable) { + super(containerId, inventory, merchantCollection); + this.access = worldPosCallable; + this.traders = merchantCollection; + ((MerchantMenuAccessor) this).setTrader(this.traders); + this.tradeContainer = new TradingPostContainer(this.traders); + ((MerchantMenuAccessor) this).setTradeContainer(this.tradeContainer); + this.replaceSlot(0, new Slot(this.tradeContainer, 0, 136, 37)); + this.replaceSlot(1, new Slot(this.tradeContainer, 1, 162, 37)); + this.replaceSlot(2, new MerchantResultSlot(inventory.player, this.traders, this.tradeContainer, 2, 220, 37)); + } + + private void replaceSlot(int index, Slot slot) { + slot.index = index; + this.slots.set(index, slot); + } + + @Override + public MenuType getType() { + return ModRegistry.TRADING_POST_MENU_TYPE.value(); + } + + @Override + public boolean stillValid(Player player) { + // this also updates merchants, so run independent of config option + // don't want this to go off on every tick + Optional anyTrader = this.access.evaluate((Level level, BlockPos pos) -> { + boolean testRange = TradingPost.CONFIG.get(ServerConfig.class).enforceRange && ++this.ticks >= 20; + return this.traders.updateAvailableMerchants(this.containerId, pos, player, testRange); + }); + if (this.ticks >= 20) this.ticks = 0; + if (TradingPost.CONFIG.get(ServerConfig.class).closeScreen && anyTrader.isPresent() && !anyTrader.get()) { + player.displayClientMessage(TradingPostBlock.MISSING_MERCHANT_COMPONENT, false); + return false; + } + return stillValid(this.access, player, ModRegistry.TRADING_POST_BLOCK.value()); + } + + @Override + public ItemStack quickMoveStack(Player player, int slotIndex) { + ItemStack itemstack = ItemStack.EMPTY; + Slot slot = this.slots.get(slotIndex); + if (slot != null && slot.hasItem()) { + + ItemStack itemstack1 = slot.getItem(); + itemstack = itemstack1.copy(); + if (slotIndex == 2) { + + if (!this.moveItemStackTo(itemstack1, 3, 39, true)) { + + return ItemStack.EMPTY; + } + + slot.onQuickCraft(itemstack1, itemstack); + // only replace this, vanilla will throw ClassCastException due to MerchantCollection not being an entity + this.playTradeSound(); + } else { + + return super.quickMoveStack(player, slotIndex); + } + + if (itemstack1.isEmpty()) { + + slot.set(ItemStack.EMPTY); + } else { + + slot.setChanged(); + } + + if (itemstack1.getCount() == itemstack.getCount()) { + + return ItemStack.EMPTY; + } + + slot.onTake(player, itemstack1); + } + + return itemstack; + } + + private void playTradeSound() { + if (!this.traders.isClientSide()) { + Merchant merchant = this.traders.getCurrentMerchant(); + if (merchant instanceof Entity entity) { + entity.level().playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.traders.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false); + } + } + } + + public void clearPaymentSlots() { + ItemStack itemstack = this.tradeContainer.getItem(0); + if (!itemstack.isEmpty()) { + if (!this.moveItemStackTo(itemstack, 3, 39, true)) { + return; + } + + this.tradeContainer.setItem(0, itemstack); + } + + ItemStack itemstack1 = this.tradeContainer.getItem(1); + if (!itemstack1.isEmpty()) { + if (!this.moveItemStackTo(itemstack1, 3, 39, true)) { + return; + } + + this.tradeContainer.setItem(1, itemstack1); + } + } + + @Override + public MerchantOffers getOffers() { + return this.lockOffers ? new MerchantOffers() : super.getOffers(); + } + + public MerchantCollection getTraders() { + return this.traders; + } + + public void lockOffers(boolean lock) { + this.lockOffers = lock; + } + + public void addMerchant(Player playerEntity, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { + LocalMerchant merchant = new LocalMerchant(playerEntity, merchantTitle, offers, villagerLevel, villagerXp, showProgress, canRestock); + this.traders.addMerchant(merchantId, merchant); + } + + @Override + public int getTraderLevel() { + return this.traders.getTraderLevel(); + } + + @Override + public boolean canRestock() { + return this.traders.canRestock(); + } + + @Override + public boolean showProgressBar() { + return this.traders.showProgressBar(); + } + + @Override + public void setShowProgressBar(boolean showProgressBar) { + // Don't throw to not break other mods possibly interfering with the merchant menu. + TradingPost.LOGGER.error("Operation setShowProgressBar no supported on trading post, set showProgressBar to merchants directly"); + } + + @Override + public void setXp(int xpValue) { + // Don't throw to not break other mods possibly interfering with the merchant menu. + TradingPost.LOGGER.error("Operation setXp no supported on trading post, set xp to merchants directly"); + } + + @Override + public void setMerchantLevel(int merchantLevel) { + // Don't throw to not break other mods possibly interfering with the merchant menu. + TradingPost.LOGGER.error("Operation setMerchantLevel no supported on trading post, set level to merchants directly"); + } + + @Override + public void setCanRestock(boolean canRestock) { + // Don't throw to not break other mods possibly interfering with the merchant menu. + TradingPost.LOGGER.error("Operation setCanRestock no supported on trading post, set canRestock to merchants directly"); + } + + @Override + public void setOffers(MerchantOffers offers) { + // Don't throw to not break other mods possibly interfering with the merchant menu. + TradingPost.LOGGER.error("Operation setOffers no supported on trading post, set offers to merchants directly"); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java new file mode 100644 index 0000000..8bde01b --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java @@ -0,0 +1,58 @@ +package fuzs.tradingpost.world.item.trading; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Set; + +public class TradingPostOffers extends MerchantOffers { + private final Set disabledOffers; + private int[] indexToShopItem; + + public TradingPostOffers(Set disabledOffers) { + this.disabledOffers = disabledOffers; + } + + @Nullable + @Override + public MerchantOffer getRecipeFor(ItemStack input1, ItemStack input2, int offerId) { + if (offerId >= 0 && offerId < this.size()) { + MerchantOffer offer = this.get(offerId); + return offer.satisfiedBy(input1, input2) && !this.disabledOffers.contains(offer) ? offer : null; + } + return null; + } + + @Override + public int size() { + return this.indexToShopItem != null ? this.indexToShopItem.length : super.size(); + } + + @Override + public boolean isEmpty() { + return this.size() == 0; + } + + @Override + public MerchantOffer get(int index) { + return super.get(this.indexToShopItem != null ? this.indexToShopItem[index] : index); + } + + public void setFilter(Collection activeOffers) { + this.indexToShopItem = activeOffers.stream() + .filter(this::contains) + .mapToInt(this::indexOf) + .toArray(); + } + + public void clearFilter() { + this.indexToShopItem = null; + } + + public int getOrigShopItem(int filteredShopItem) { + return this.indexToShopItem != null && filteredShopItem < this.indexToShopItem.length ? this.indexToShopItem[filteredShopItem] : filteredShopItem; + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java new file mode 100644 index 0000000..17a2916 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java @@ -0,0 +1,181 @@ +package fuzs.tradingpost.world.level.block; + +import com.mojang.serialization.MapCodec; +import fuzs.puzzleslib.api.block.v1.entity.TickingEntityBlock; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.mixin.accessor.VillagerAccessor; +import fuzs.tradingpost.world.entity.npc.MerchantCollection; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.trading.Merchant; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; + +import java.util.List; +import java.util.OptionalInt; + +public class TradingPostBlock extends BaseEntityBlock implements SimpleWaterloggedBlock, TickingEntityBlock { + public static final Component MISSING_MERCHANT_COMPONENT = Component.translatable("trading_post.no_trader_found"); + public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; + public static final MapCodec CODEC = simpleCodec(TradingPostBlock::new); + private static final VoxelShape LEG1 = Block.box(0.0, 0.0, 0.0, 4.0, 8.0, 4.0); + private static final VoxelShape LEG2 = Block.box(12.0, 0.0, 0.0, 16.0, 8.0, 4.0); + private static final VoxelShape LEG3 = Block.box(0.0, 0.0, 12.0, 4.0, 8.0, 16.0); + private static final VoxelShape LEG4 = Block.box(12.0, 0.0, 12.0, 16.0, 8.0, 16.0); + private static final VoxelShape TOP = Block.box(0.0, 8.0, 0.0, 16.0, 16.0, 16.0); + private static final VoxelShape SHAPE = Shapes.or(TOP, LEG1, LEG2, LEG3, LEG4); + + public TradingPostBlock(Properties blockProperties) { + super(blockProperties); + this.registerDefaultState(this.stateDefinition.any().setValue(WATERLOGGED, Boolean.FALSE)); + } + + @Override + protected MapCodec codec() { + return CODEC; + } + + @Override + public boolean useShapeForLightOcclusion(BlockState state) { + return true; + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter blockReader, BlockPos pos, CollisionContext context) { + return SHAPE; + } + + @Override + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Override + public BlockState updateShape(BlockState state, Direction direction, BlockState oldState, LevelAccessor level, BlockPos newPos, BlockPos oldPos) { + if (state.getValue(WATERLOGGED)) { + level.scheduleTick(newPos, Fluids.WATER, Fluids.WATER.getTickDelay(level)); + } + return super.updateShape(state, direction, oldState, level, newPos, oldPos); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + FluidState fluidState = context.getLevel().getFluidState(context.getClickedPos()); + return this.defaultBlockState().setValue(WATERLOGGED, fluidState.getType() == Fluids.WATER); + } + + @Override + public FluidState getFluidState(BlockState blockState) { + return blockState.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(blockState); + } + + @Override + public BlockEntityType getBlockEntityType() { + return ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(); + } + + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) { + if (level.isClientSide) { + return InteractionResult.SUCCESS; + } else { + Vec3 atCenter = Vec3.atCenterOf(pos); + final int horizontalRange = TradingPost.CONFIG.get(ServerConfig.class).horizontalRange; + final int verticalRange = TradingPost.CONFIG.get(ServerConfig.class).verticalRange; + List traders = level.getEntitiesOfClass(Entity.class, new AABB(atCenter.add(-horizontalRange, -verticalRange, -horizontalRange), atCenter.add(horizontalRange, verticalRange, horizontalRange)), TradingPostBlock::isAllowedToTrade); + if (!traders.isEmpty()) { + ContainerLevelAccess access = ContainerLevelAccess.create(level, pos); + MerchantCollection merchants = new MerchantCollection(access); + for (Entity merchant : traders) { + if (merchant instanceof Villager) { + ((VillagerAccessor) merchant).callUpdateSpecialPrices(player); + } + merchants.addMerchant(merchant.getId(), (Merchant) merchant); + } + merchants.setTradingPlayer(player); + merchants.buildOffers(merchants.getIdToOfferCountMap()); + Component title; + if (level.getBlockEntity(pos) instanceof TradingPostBlockEntity blockEntity) + title = blockEntity.getDisplayName(); + else { + title = TradingPostBlockEntity.CONTAINER_COMPONENT; + } + OptionalInt result = player.openMenu(new SimpleMenuProvider((int containerId, Inventory inventory, Player containerPlayer) -> { + return new TradingPostMenu(containerId, inventory, merchants, access); + }, title)); + result.ifPresent((int containerId) -> { + merchants.sendMerchantData(containerId, player); + }); + } else { + player.displayClientMessage(MISSING_MERCHANT_COMPONENT, false); + } + return InteractionResult.CONSUME; + } + } + + public static boolean isAllowedToTrade(Entity entity) { + if (entity.getType().is(ModRegistry.CONCEALED_TRADERS_ENTITY_TYPE_TAG)) { + return false; + } + + if (!entity.isAlive() || !(entity instanceof Merchant merchant) || merchant.getTradingPlayer() != null || merchant.getOffers().isEmpty()) { + return false; + } + + return !(entity instanceof LivingEntity livingEntity) || !livingEntity.isSleeping() && !livingEntity.isBaby(); + } + + @Override + public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity entity, ItemStack stack) { + if (stack.hasCustomHoverName()) { + if (level.getBlockEntity(pos) instanceof TradingPostBlockEntity blockEntity) { + blockEntity.setCustomName(stack.getHoverName()); + } + } + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(WATERLOGGED); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter blockReader, BlockPos pos, PathComputationType pathType) { + return false; + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java new file mode 100644 index 0000000..1844864 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostAnimationController.java @@ -0,0 +1,68 @@ +package fuzs.tradingpost.world.level.block.entity; + +import net.minecraft.core.BlockPos; +import net.minecraft.util.Mth; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.phys.Vec3; + +public class TradingPostAnimationController { + private final Vec3 position; + + public int time; + public float open; + public float oOpen; + public float rot; + public float oRot; + public float tRot; + + public TradingPostAnimationController(BlockPos blockPos) { + this.position = blockPos.getCenter(); + } + + public void tick(Level level) { + ++this.time; + this.oOpen = this.open; + this.oRot = this.rot; + this.setOpenness(level); + this.tickAnimation(); + } + + private void setOpenness(Level level) { + Player player = level.getNearestPlayer(this.position.x(), this.position.y(), this.position.z(), 3.0, false); + if (player != null) { + double d0 = player.getX() - this.position.x(); + double d1 = player.getZ() - this.position.z(); + this.tRot = (float) Mth.atan2(d1, d0); + this.open += 0.1F; + } else { + this.tRot += 0.02F; + this.open -= 0.1F; + } + } + + private void tickAnimation() { + while (this.rot >= (float) Math.PI) { + this.rot -= ((float) Math.PI * 2.0F); + } + while (this.rot < -(float) Math.PI) { + this.rot += ((float) Math.PI * 2.0F); + } + while (this.tRot >= (float) Math.PI) { + this.tRot -= ((float) Math.PI * 2.0F); + } + while (this.tRot < -(float) Math.PI) { + this.tRot += ((float) Math.PI * 2.0F); + } + float f2; + f2 = this.tRot - this.rot; + while (f2 >= (float) Math.PI) { + f2 -= ((float) Math.PI * 2.0F); + } + while (f2 < -(float) Math.PI) { + f2 += ((float) Math.PI * 2.0F); + } + this.rot += f2 * 0.4F; + this.open = Mth.clamp(this.open, 0.0F, 1.0F); + } +} diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java new file mode 100644 index 0000000..6c3b9b7 --- /dev/null +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java @@ -0,0 +1,64 @@ +package fuzs.tradingpost.world.level.block.entity; + +import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.world.Nameable; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +public class TradingPostBlockEntity extends BlockEntity implements Nameable, TickingBlockEntity { + public static final Component CONTAINER_COMPONENT = Component.translatable("container.trading_post"); + + private final TradingPostAnimationController animationController; + @Nullable + private Component name; + + public TradingPostBlockEntity(BlockPos blockPos, BlockState blockState) { + super(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(), blockPos, blockState); + this.animationController = new TradingPostAnimationController(blockPos); + } + + @Override + protected void saveAdditional(CompoundTag compoundTag) { + super.saveAdditional(compoundTag); + if (this.hasCustomName()) { + compoundTag.putString("CustomName", Component.Serializer.toJson(this.name)); + } + } + + @Override + public void load(CompoundTag compoundTag) { + super.load(compoundTag); + if (compoundTag.contains("CustomName", 8)) { + this.name = Component.Serializer.fromJson(compoundTag.getString("CustomName")); + } + } + + @Override + public void clientTick() { + this.animationController.tick(this.getLevel()); + } + + public TradingPostAnimationController getAnimationController() { + return this.animationController; + } + + @Override + public Component getName() { + return this.name != null ? this.name : CONTAINER_COMPONENT; + } + + public void setCustomName(@Nullable Component component) { + this.name = component; + } + + @Nullable + @Override + public Component getCustomName() { + return this.name; + } +} diff --git a/1.21/Common/src/main/resources/architectury.common.json b/1.21/Common/src/main/resources/architectury.common.json new file mode 100644 index 0000000..e813a5a --- /dev/null +++ b/1.21/Common/src/main/resources/architectury.common.json @@ -0,0 +1,3 @@ +{ + "accessWidener": "tradingpost.accesswidener" +} \ No newline at end of file diff --git a/1.21/Common/src/main/resources/assets/tradingpost/lang/it_it.json b/1.21/Common/src/main/resources/assets/tradingpost/lang/it_it.json new file mode 100644 index 0000000..84afc50 --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/lang/it_it.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Postazione commerciale", + "container.trading_post": "Postazione commerciale", + "trading_post.no_trader_found": "Nessun commerciante disponibile trovato nelle vicinanze", + "trading_post.trader_gone": "Il commerciante non è più disponibile.", + "trading_post.search": "Ricerca..." +} diff --git a/1.21/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json b/1.21/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json new file mode 100644 index 0000000..574d205 --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/lang/ja_jp.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "交易台", + "container.trading_post": "交易台", + "trading_post.no_trader_found": "近くに交易できる村人が居ません", + "trading_post.trader_gone": "交易できる村人が居なくなりました。", + "trading_post.search": "検索..." +} diff --git a/1.21/Common/src/main/resources/assets/tradingpost/lang/pt_br.json b/1.21/Common/src/main/resources/assets/tradingpost/lang/pt_br.json new file mode 100644 index 0000000..e84791f --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/lang/pt_br.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Posto de Comércio", + "container.trading_post": "Posto de Comércio", + "trading_post.no_trader_found": "Não foi possível encontrar nenhum comerciante disponível nas proximidades", + "trading_post.trader_gone": "O comerciante não está mais disponível.", + "trading_post.search": "Procurar..." + } \ No newline at end of file diff --git a/1.21/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json b/1.21/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json new file mode 100644 index 0000000..ef8965c --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Торговый пост", + "container.trading_post": "Торговый пост", + "trading_post.no_trader_found": "Не удалось найти по близости какого-либо торговца.", + "trading_post.trader_gone": "Торговец больше не доступен.", + "trading_post.search": "Поиск..." +} diff --git a/1.21/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json b/1.21/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json new file mode 100644 index 0000000..cc3146e --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "交易站", + "container.trading_post": "交易站", + "trading_post.no_trader_found": "在附近沒有可用的交易", + "trading_post.trader_gone": "交易鎖定.", + "trading_post.search": "搜尋中..." +} diff --git a/1.21/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json b/1.21/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json new file mode 100644 index 0000000..c876239 --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json @@ -0,0 +1,63 @@ +{ "parent": "block/block", + "textures": { + "particle": "tradingpost:block/trading_post_top", + "bottom1": "tradingpost:block/trading_post_bottom", + "bottom2": "minecraft:block/oak_planks", + "top": "tradingpost:block/trading_post_top", + "side": "tradingpost:block/trading_post_side", + "front": "tradingpost:block/trading_post_front" + }, + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 4, 8, 4 ], + "faces": { + "down": { "uv": [ 0, 0, 4, 4 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#side" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#side" } + } + }, + { "from": [ 12, 0, 12 ], + "to": [ 16, 8, 16 ], + "faces": { + "down": { "uv": [ 12, 12, 16, 16 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#side" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#side" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { "from": [ 12, 0, 0 ], + "to": [ 16, 8, 4 ], + "faces": { + "down": { "uv": [ 12, 0, 16, 4 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#front", "cullface": "north" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#front" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#front" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#front", "cullface": "east" } + } + }, + { "from": [ 0, 0, 12 ], + "to": [ 4, 8, 16 ], + "faces": { + "down": { "uv": [ 0, 12, 4, 16 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#front" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#front", "cullface": "south" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#front", "cullface": "west" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#front" } + } + }, + { "from": [ 0, 8, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom2" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 8 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 8 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 8 ], "texture": "#front", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 8 ], "texture": "#front", "cullface": "east" } + } + } + ] +} diff --git a/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png b/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..717082a266c044f6fbeb8c7b99e4bc33637d510f GIT binary patch literal 1321 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n#K_9nFbZMfql=3lR~tp)~GmCm34-ih7k{j%&- zu&UZ#tu3uh<{1Z5wcelKwkBr%{llBGv>&qzX*S$!)o{F#yvBF-${!1*8Qz5%F)hnk zd*w?1!jjw%d@md(UVp6C(st0%echtdiS1!}N1XGPF*BHZiEm!Q&Hias??%7h#hPMQ z?tVC0keDd`^!8GL7T^54AMEBZZd`vRl;?Vs`uX2iJ(5iR{(mU`{{v(0m2=D?%-$bB O#e}D;pUXO@geCx)FpWe2 literal 0 HcmV?d00001 diff --git a/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png b/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png new file mode 100644 index 0000000000000000000000000000000000000000..bff9f1eadce05e63af80b16c493df4164ed7751d GIT binary patch literal 1610 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n*u=`nJPKk0iZZAXHu|8Xh?F!T=^iW!O!#(OK&`M$WXE++#ho3Pl^=V$IEHA5 z)&}nPmJXDue_!-6)@JduDAQR%+DRQQGErQvf)^cPSakm}^1Tfckl9tDQ?kwbU!&7= zy}2zud}}LYb%PYIvLwswd1CV1cJgj-`|0I-yxR6XoPB=%`|0n$JDEQ_R#p}_@!jv* zZ|c@-ZO`w0D)KdbV?jyMa&@(xn|A*WU3a&lFSoi}Y)RQ<*|`t4e|VCaR-twL^5a5Q z#udvlm2^H|>oD3ehdsz0an`~sMH(&00_PQCowo5ZxWKM|Q)|@*n`&n+CtNvTo z2bXxB^}gD0^406|tKC`+S2ytOuXT#3oA~B@TKcx2qko(4gzd|i^E~0RY|^Z@FVp#N z-_H5-``MvOn@^s;6k5UTrab{_P*+ND;t5jwk7wD&n^&UST1ibE%N{H1g*mU z>ujGFE+{$`>)0%QE_6BCvl*>$?nBzoQJ@`wVx zUau|H&K(aA9n!J-wjzF#hT7dt+h(*IE8GkJbwwlQ{`)_y`!@cM-Se+01XPZCy85}S Ib4q9e04ES2V*mgE literal 0 HcmV?d00001 diff --git a/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png b/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png new file mode 100644 index 0000000000000000000000000000000000000000..6eff5bac4a582547c9caf9723b2e705ea5031ef6 GIT binary patch literal 1585 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n*u=`fJPKk0iZZAXHu|8Xh?F!T=^iW!O!#(OK&`M$WXJXQ#W`S}W<2HT;uxYK zS{u06kI7NujxC=BBkMW)11=#=f`QzmBiFbtf3*ey9dKlds33<+-TT1NQ>7Tq2- zHy$lDHZF1hgVs;q6-+yNHDJfldo{+NYikZ)+B);cwQE+Hb8jF2onvLOeT$;ko#*Ml zuebiHC<-yCu2#?bdDrlD>GR7BS64({XRZ0(?ymML*!$4j7vByuOfzKLtQBSZ&)~of zj{WynEpf^7;y1s#NjJS&o{Nq1&SLLGQPWS?mAST$|3jYVn(dD_1+?Hkz>Pd||)xMUoZU zYMTiD>eHK;9lp9W{abgfNFytL+gmeTx#?A+w@zI+7ND3Y*89Cxq&4YM`_&1b1(=`2 gt1YNpxGV3obQI&8)xpbK96`mUr>mdKI;Vst0Pda)^8f$< literal 0 HcmV?d00001 diff --git a/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png b/1.21/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png new file mode 100644 index 0000000000000000000000000000000000000000..c127409bfcbbe6acd67008fdd2510de9967f79c7 GIT binary patch literal 1640 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n*ucujAPQmviZZAXHu|8Xh?F!T=^iW!O!#(OK&`M$WXH9QefD}_R%P^baSYKA zt(|n&TO?4TJ^fr{>6~1xC3B_j>LnRYTeLUe)PxQVrEZSHtKT){ajE=bex>%GS#Zy* zZF^RBD|M_`(Q#;t(vi})$!i_9ua(J7jVw(Ipa1ei;d(2c_V15>?tO2W9=F;2@!yzL zQf(VgPjo&!U1+87#@ye9SGoTC{rmT8%l}il5)4hx9@@U^{r7HJh4(Lq)z=HB3IyzJ z^LY3-AulO!=^K8Yy<$JUn&^G`arkzPM(b1sC&g2ZiQG~zZ%xcsb>Nr1d3)l@TA8z} zJFYRDR{y?k-o86;tS(Fc%11>GB)DX?%udQxLa^$V7`BvU9FJn_F z!#rzm)XcX&)8y{%J$zF{*w*v!-&IRrUOjq2=Qr=iXq73c~b=D8;(--kEc|^q_8Y8|hecp!u}px#zlz+r5{2&ln3r zQ=vj32*Qx)p`Zxt9}$7i(QAJo${>WG2&u;&iptIn9Q4q`Ip6txzdzr{xtL1E8tV_$ z13+UU9!c}s>>PI$zrVi!;56JbLt{e#4=?TgiK{tAB%U4vIMV|#zXb4ux8^?s6h(mT zEP#9!;GlVJDt(=NQznTdS*!?x5-!T=5pp zzi9Z9a!mtlov!Qpc5cecL%UgYk|~%`nOKw;@QZ#)kVK(R%t!%Q>X)UER}^JY)B}x| z|1lH{MN`ZFH+0NC_HjednV=CO6T>W9+Dwi?c=v^lkfTTng@PzfOL@wekiujZTM7yr z1rzJ#?-S(#p3%9Rp-`Jxn#nXn2Rj`bMu})RAcX<}!S9nM?!Jq0anG)}fc2t^2`gIE z0xm>3#!R`lw^SE+%Zsb7z)k*l~zJggsQlhXULgGjJ#2_kZoc@k${{H zBIEHpJYv5S!8BEsao)^fz_x7=jen?;o4fg&3z{kdsw*1Sps-NCPDbtxXBYke*RS2S literal 0 HcmV?d00001 diff --git a/1.21/Common/src/main/resources/common.mixins.json b/1.21/Common/src/main/resources/common.mixins.json new file mode 100644 index 0000000..b0cdaf5 --- /dev/null +++ b/1.21/Common/src/main/resources/common.mixins.json @@ -0,0 +1,18 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.mixin", + "mixins": [ + "accessor.MerchantMenuAccessor", + "accessor.VillagerAccessor" + ], + "client": [ + "client.accessor.ButtonAccessor", + "client.accessor.MerchantScreenAccessor", + "client.accessor.TradeOfferButtonAccessor" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.21/Common/src/main/resources/mod_banner.png b/1.21/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..4aa65be87014905b9ae86260545884645759b5db GIT binary patch literal 20290 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 Zs6PaW6GB^cSBd}t002ovPDHLkV1oN>({lg- literal 0 HcmV?d00001 diff --git a/1.21/Common/src/main/resources/mod_logo.png b/1.21/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fa91dba198b8eba0ea360d3b7cf0877568843326 GIT binary patch literal 9609 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 literal 0 HcmV?d00001 diff --git a/1.21/Common/src/main/resources/pack.mcmeta b/1.21/Common/src/main/resources/pack.mcmeta new file mode 100755 index 0000000..546f4f1 --- /dev/null +++ b/1.21/Common/src/main/resources/pack.mcmeta @@ -0,0 +1,6 @@ +{ + "pack": { + "description": "${modDescription}", + "pack_format": ${resourcePackFormat} + } +} diff --git a/1.21/Common/src/main/resources/tradingpost.accesswidener b/1.21/Common/src/main/resources/tradingpost.accesswidener new file mode 100644 index 0000000..236e6b1 --- /dev/null +++ b/1.21/Common/src/main/resources/tradingpost.accesswidener @@ -0,0 +1 @@ +accessWidener v2 named diff --git a/1.21/Fabric/build.gradle b/1.21/Fabric/build.gradle new file mode 100644 index 0000000..cec9b27 --- /dev/null +++ b/1.21/Fabric/build.gradle @@ -0,0 +1,19 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/fabric.gradle" + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // Puzzles Lib + modApi libs.puzzleslib.fabric + + // Cardinal Components +// modApi(include(libs.cardinalcomponentsbase.fabric.get())) +// modApi(include(libs.cardinalcomponentsentity.fabric.get())) +// modApi(include(libs.cardinalcomponentsblock.fabric.get())) +// modApi(include(libs.cardinalcomponentschunk.fabric.get())) +// modApi(include(libs.cardinalcomponentsworld.fabric.get())) + + // Extensible Enums +// modApi(include(libs.extensibleenums.fabric.get())) +} diff --git a/1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/TradingPostFabric.java b/1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/TradingPostFabric.java new file mode 100644 index 0000000..fcdb445 --- /dev/null +++ b/1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/TradingPostFabric.java @@ -0,0 +1,13 @@ +package fuzs.tradingpost.fabric; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.tradingpost.TradingPost; +import net.fabricmc.api.ModInitializer; + +public class TradingPostFabric implements ModInitializer { + + @Override + public void onInitialize() { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + } +} diff --git a/1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/client/TradingPostFabricClient.java b/1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/client/TradingPostFabricClient.java new file mode 100644 index 0000000..a1299fb --- /dev/null +++ b/1.21/Fabric/src/main/java/fuzs/tradingpost/fabric/client/TradingPostFabricClient.java @@ -0,0 +1,14 @@ +package fuzs.tradingpost.fabric.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.client.TradingPostClient; +import net.fabricmc.api.ClientModInitializer; + +public class TradingPostFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); + } +} diff --git a/1.21/Fabric/src/main/resources/fabric.mixins.json b/1.21/Fabric/src/main/resources/fabric.mixins.json new file mode 100644 index 0000000..6bf7940 --- /dev/null +++ b/1.21/Fabric/src/main/resources/fabric.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.fabric.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "${modId}.fabric.refmap.json" +} diff --git a/1.21/Fabric/src/main/resources/fabric.mod.json b/1.21/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..bd7ba2d --- /dev/null +++ b/1.21/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,45 @@ +{ + "schemaVersion": 1, + "id": "${modId}", + "version": "${modVersion}", + + "name": "${modName}", + "description": "${modDescription}", + + "authors": [ + "${modAuthor}" + ], + + "contact": { + "homepage": "${modPageUrl}", + "issues": "${modIssueUrl}", + "sources": "${modPageUrl}" + }, + + "license": "${modLicense}", + "icon": "mod_logo.png", + + "environment": "${modFabricEnvironment}", + + "entrypoints": { + "main": [ + "${mainEntryPoint}" + ], + "client": [ + "${clientEntryPoint}" + ] + }, + + "mixins": [ + "${modId}.common.mixins.json", + "${modId}.fabric.mixins.json" + ], + + "depends": { + "fabricloader": ">=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.21/Forge/build.gradle b/1.21/Forge/build.gradle new file mode 100644 index 0000000..f9839f1 --- /dev/null +++ b/1.21/Forge/build.gradle @@ -0,0 +1,6 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/forge.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.forge +} diff --git a/1.21/Forge/gradle.properties b/1.21/Forge/gradle.properties new file mode 100644 index 0000000..32f842a --- /dev/null +++ b/1.21/Forge/gradle.properties @@ -0,0 +1 @@ +loom.platform=forge \ No newline at end of file diff --git a/1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java b/1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java new file mode 100644 index 0000000..0f01496 --- /dev/null +++ b/1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java @@ -0,0 +1,17 @@ +package fuzs.tradingpost.forge; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.tradingpost.TradingPost; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(TradingPost.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class TradingPostForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + } +} diff --git a/1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java b/1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java new file mode 100644 index 0000000..d400491 --- /dev/null +++ b/1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java @@ -0,0 +1,18 @@ +package fuzs.tradingpost.forge.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.client.TradingPostClient; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = TradingPost.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class TradingPostForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); + } +} diff --git a/1.21/Forge/src/main/resources/META-INF/mods.toml b/1.21/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..6c2e585 --- /dev/null +++ b/1.21/Forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,51 @@ +modLoader = "javafml" +loaderVersion = "*" +license = "${modLicense}" +issueTrackerURL = "${modIssueUrl}" + +[[mods]] +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" + +[[dependencies.${ modId }]] +modId = "forge" +mandatory = true +type = "required" +versionRange = "[${minForgeVersion},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +type = "required" +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "forgeconfigapiport" +mandatory = true +type = "required" +versionRange = "*" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +type = "required" +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.21/Forge/src/main/resources/forge.mixins.json b/1.21/Forge/src/main/resources/forge.mixins.json new file mode 100644 index 0000000..f2b4276 --- /dev/null +++ b/1.21/Forge/src/main/resources/forge.mixins.json @@ -0,0 +1,14 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.forge.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + }, + "refmap": "${modId}.forge.refmap.json" +} diff --git a/1.21/NeoForge/build.gradle b/1.21/NeoForge/build.gradle new file mode 100644 index 0000000..ca9b9b6 --- /dev/null +++ b/1.21/NeoForge/build.gradle @@ -0,0 +1,6 @@ +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/neoforge.gradle" + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.neoforge +} diff --git a/1.21/NeoForge/gradle.properties b/1.21/NeoForge/gradle.properties new file mode 100644 index 0000000..2914393 --- /dev/null +++ b/1.21/NeoForge/gradle.properties @@ -0,0 +1 @@ +loom.platform=neoforge \ No newline at end of file diff --git a/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java new file mode 100644 index 0000000..45ce2b8 --- /dev/null +++ b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java @@ -0,0 +1,28 @@ +package fuzs.tradingpost.neoforge; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.data.ModBlockLootProvider; +import fuzs.tradingpost.data.ModBlockTagProvider; +import fuzs.tradingpost.data.ModEntityTypeTagProvider; +import fuzs.tradingpost.data.ModRecipeProvider; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; + +@Mod(TradingPost.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class TradingPostNeoForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, + ModBlockLootProvider::new, + ModBlockTagProvider::new, + ModEntityTypeTagProvider::new, + ModRecipeProvider::new + ); + } +} diff --git a/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java new file mode 100644 index 0000000..82c4e26 --- /dev/null +++ b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java @@ -0,0 +1,25 @@ +package fuzs.tradingpost.neoforge.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.neoforge.api.data.v2.core.DataProviderHelper; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.client.TradingPostClient; +import fuzs.tradingpost.data.client.ModLanguageProvider; +import fuzs.tradingpost.data.client.ModModelProvider; +import net.neoforged.api.distmarker.Dist; +import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.common.Mod; +import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = TradingPost.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class TradingPostNeoForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); + DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, + ModLanguageProvider::new, + ModModelProvider::new + ); + } +} diff --git a/1.21/NeoForge/src/main/resources/META-INF/mods.toml b/1.21/NeoForge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..ef10121 --- /dev/null +++ b/1.21/NeoForge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,49 @@ +modLoader = "javafml" +loaderVersion = "*" +license = "${modLicense}" +issueTrackerURL = "${modIssueUrl}" + +[[mods]] +modId = "${modId}" +displayName = "${modName}" +description = "${modDescription}" +version = "${modVersion}" +authors = "${modAuthor}" +logoFile = "mod_banner.png" +logoBlur = false +displayURL = "${modPageUrl}" +updateJSONURL = "${modUpdateUrl}" +displayTest = "${modForgeDisplayTest}" + +[[mixins]] +config="${modId}.common.mixins.json" + +[[mixins]] +config="${modId}.neoforge.mixins.json" + +[[dependencies.${ modId }]] +modId = "neoforge" +mandatory = true +type = "required" +versionRange = "[${minNeoForgeVersion},)" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "minecraft" +mandatory = true +type = "required" +versionRange = "[${minecraftVersion}]" +ordering = "NONE" +side = "BOTH" + +[[dependencies.${ modId }]] +modId = "puzzleslib" +mandatory = true +type = "required" +versionRange = "[${minPuzzlesVersion},)" +ordering = "NONE" +side = "BOTH" + +[modproperties.${ modId }] +catalogueImageIcon = "mod_logo.png" diff --git a/1.21/NeoForge/src/main/resources/neoforge.mixins.json b/1.21/NeoForge/src/main/resources/neoforge.mixins.json new file mode 100644 index 0000000..1fb3919 --- /dev/null +++ b/1.21/NeoForge/src/main/resources/neoforge.mixins.json @@ -0,0 +1,13 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "${modGroup}.neoforge.mixin", + "mixins": [ + ], + "client": [ + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.21/build.gradle b/1.21/build.gradle new file mode 100644 index 0000000..dea2bca --- /dev/null +++ b/1.21/build.gradle @@ -0,0 +1,9 @@ +plugins { + alias libs.plugins.architecturyloom apply false + alias libs.plugins.architecturyplugin apply false + alias libs.plugins.shadow apply false + alias libs.plugins.cursegradle apply false + alias libs.plugins.minotaur apply false +} + +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/${libs.versions.minecraft.get()}/main.gradle" diff --git a/1.21/gradle.properties b/1.21/gradle.properties new file mode 100755 index 0000000..a6bcb90 --- /dev/null +++ b/1.21/gradle.properties @@ -0,0 +1,45 @@ +org.gradle.jvmargs=-Xmx4G +org.gradle.daemon=false +copyBuildJar=true + +# Mod Attributes +modId=tradingpost +modName=Trading Post +modVersion=21.0.0 +modAuthor=Fuzs +modDescription=Rule the village! Trade with every villager at once! +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/tradingpost +modIssueUrl=https://github.com/Fuzss/tradingpost/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/tradingpost.json +modMavenGroup=fuzs.tradingpost +# "MATCH_VERSION" for a mod required on both sides, "IGNORE_SERVER_VERSION" for a server only mod, "IGNORE_ALL_VERSION" for a client only mod +modForgeDisplayTest=MATCH_VERSION +# "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod +modFabricEnvironment=* + +# Version Catalog +dependenciesVersionCatalog=1.21-v5 +#dependenciesPuzzlesLibVersion=21.0.0 +#dependenciesMinPuzzlesLibVersion=21.0.0 + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=539057 +projectModrinthId=8pcjMDgj + +# Required Dependencies +dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredNeoForgeCurseForge=puzzles-lib +dependenciesRequiredForgeCurseForge=forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib +dependenciesRequiredNeoForgeModrinth=puzzles-lib +dependenciesRequiredForgeModrinth=forge-config-api-port, puzzles-lib + +# Optional Dependencies +dependenciesOptionalFabricCurseForge=config-menus-forge +dependenciesOptionalNeoForgeCurseForge=config-menus-forge +dependenciesOptionalForgeCurseForge=config-menus-forge +dependenciesOptionalFabricModrinth=forge-config-screens +dependenciesOptionalNeoForgeModrinth=forge-config-screens +dependenciesOptionalForgeModrinth=forge-config-screens diff --git a/1.21/gradle/wrapper/gradle-wrapper.jar b/1.21/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 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 ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/1.21/gradle/wrapper/gradle-wrapper.properties b/1.21/gradle/wrapper/gradle-wrapper.properties new file mode 100644 index 0000000..2617362 --- /dev/null +++ b/1.21/gradle/wrapper/gradle-wrapper.properties @@ -0,0 +1,6 @@ +distributionBase=GRADLE_USER_HOME +distributionPath=wrapper/dists +distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip +networkTimeout=10000 +zipStoreBase=GRADLE_USER_HOME +zipStorePath=wrapper/dists diff --git a/1.21/gradlew b/1.21/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.21/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/1.21/gradlew.bat b/1.21/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.21/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/1.21/settings.gradle b/1.21/settings.gradle new file mode 100644 index 0000000..5cfe5eb --- /dev/null +++ b/1.21/settings.gradle @@ -0,0 +1,16 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { url "https://maven.architectury.dev/" } + maven { url "https://maven.fabricmc.net/" } + maven { url "https://maven.neoforged.net/releases/" } + maven { url "https://maven.minecraftforge.net/" } + } +} + +include "Common" +include "Fabric" +include "NeoForge" +//include "Forge" + +apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From 7ac63edbf2efc10992d336dfbbf8dafb970c5022 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Fri, 5 Jul 2024 08:09:07 +0200 Subject: [PATCH 17/24] some 1.21 updates --- .../java/fuzs/tradingpost/TradingPost.java | 15 +++----- .../tradingpost/client/TradingPostClient.java | 1 - .../screens/inventory/TradingPostScreen.java | 11 +++--- .../fuzs/tradingpost/config/ServerConfig.java | 16 --------- .../tradingpost/data/ModBlockTagProvider.java | 10 +++--- .../data/ModEntityTypeTagProvider.java | 10 +++--- .../fuzs/tradingpost/init/ModRegistry.java | 2 +- .../mixin/accessor/MerchantMenuAccessor.java | 8 ++--- .../mixin/accessor/VillagerAccessor.java | 4 +-- .../network/S2CMerchantDataMessage.java | 10 +++--- .../world/entity/npc/MerchantCollection.java | 10 +++--- .../world/inventory/TradingPostMenu.java | 5 ++- .../world/level/block/TradingPostBlock.java | 20 +++-------- .../block/entity/TradingPostBlockEntity.java | 35 +++++++++++++++---- .../neoforge/TradingPostNeoForge.java | 7 ++-- .../client/TradingPostNeoForgeClient.java | 8 ++--- 1.21/gradle.properties | 4 +-- 17 files changed, 83 insertions(+), 93 deletions(-) diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java index 8a3e329..431cce2 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java @@ -4,7 +4,8 @@ import fuzs.puzzleslib.api.core.v1.ModConstructor; import fuzs.puzzleslib.api.core.v1.context.BuildCreativeModeTabContentsContext; import fuzs.puzzleslib.api.core.v1.context.FuelBurnTimesContext; -import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; +import fuzs.puzzleslib.api.core.v1.utility.ResourceLocationHelper; +import fuzs.puzzleslib.api.network.v3.NetworkHandlerV3; import fuzs.tradingpost.config.ServerConfig; import fuzs.tradingpost.init.ModRegistry; import fuzs.tradingpost.network.S2CBuildOffersMessage; @@ -21,20 +22,12 @@ public class TradingPost implements ModConstructor { public static final String MOD_NAME = "Trading Post"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID, false); + public static final NetworkHandlerV3 NETWORK = NetworkHandlerV3.builder(MOD_ID).registerLegacyClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new).registerLegacyClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new).registerLegacyClientbound(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new).registerLegacyClientbound(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new).registerLegacyServerbound(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new); public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).server(ServerConfig.class); @Override public void onConstructMod() { ModRegistry.touch(); - registerMessages(); - } - - private static void registerMessages() { - NETWORK.registerClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new); - NETWORK.registerClientbound(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new); - NETWORK.registerClientbound(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new); - NETWORK.registerServerbound(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new); } @Override @@ -50,6 +43,6 @@ public void onRegisterFuelBurnTimes(FuelBurnTimesContext context) { } public static ResourceLocation id(String path) { - return new ResourceLocation(MOD_ID, path); + return ResourceLocationHelper.fromNamespaceAndPath(MOD_ID, path); } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java index f459e21..fb14cb3 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -18,7 +18,6 @@ import java.util.stream.Stream; public class TradingPostClient implements ClientModConstructor { - public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); @Override diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java index 7a9ddf1..0e464ec 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -1,6 +1,7 @@ package fuzs.tradingpost.client.gui.screens.inventory; import com.mojang.blaze3d.systems.RenderSystem; +import fuzs.puzzleslib.api.core.v1.utility.ResourceLocationHelper; import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.client.TradingPostClient; import fuzs.tradingpost.mixin.client.accessor.ButtonAccessor; @@ -32,10 +33,10 @@ public class TradingPostScreen extends MerchantScreen { public static final ResourceLocation MAGNIFYING_GLASS_LOCATION = TradingPost.id("container/villager/magnifying_glass"); - private static final ResourceLocation VILLAGER_LOCATION = new ResourceLocation("textures/gui/container/villager.png"); - private static final ResourceLocation OUT_OF_STOCK_SPRITE = new ResourceLocation("container/villager/out_of_stock"); - private static final ResourceLocation DISCOUNT_STRIKETHRUOGH_SPRITE = new ResourceLocation("container/villager/discount_strikethrough"); - private static final ResourceLocation CREATIVE_INVENTORY_LOCATION = new ResourceLocation("textures/gui/container/creative_inventory/tab_item_search.png"); + private static final ResourceLocation VILLAGER_LOCATION = ResourceLocationHelper.withDefaultNamespace("textures/gui/container/villager.png"); + private static final ResourceLocation OUT_OF_STOCK_SPRITE = ResourceLocationHelper.withDefaultNamespace("container/villager/out_of_stock"); + private static final ResourceLocation DISCOUNT_STRIKETHRUOGH_SPRITE = ResourceLocationHelper.withDefaultNamespace("container/villager/discount_strikethrough"); + private static final ResourceLocation CREATIVE_INVENTORY_LOCATION = ResourceLocationHelper.withDefaultNamespace("textures/gui/container/creative_inventory/tab_item_search.png"); public static final Component DEPRECATED_TRADE_COMPONENT = Component.translatable("merchant.deprecated"); public static final Component MERCHANT_UNAVAILABLE_COMPONENT = Component.translatable("trading_post.trader_gone"); @@ -332,7 +333,7 @@ public void refreshSearchResults() { this.getMenu().setSelectionHint(-1); this.getMenu().getTraders().setActiveOffer(null); this.getMenu().clearPaymentSlots(); - TradingPost.NETWORK.sendToServer(new C2SClearSlotsMessage()); + TradingPost.NETWORK.sendToServer(new C2SClearSlotsMessage().toServerboundMessage()); } @Override diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java b/1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java index 936d6a4..5ab6a25 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java @@ -1,14 +1,7 @@ package fuzs.tradingpost.config; -import com.google.common.collect.Lists; import fuzs.puzzleslib.api.config.v3.Config; import fuzs.puzzleslib.api.config.v3.ConfigCore; -import fuzs.puzzleslib.api.config.v3.serialization.ConfigDataSet; -import fuzs.tradingpost.TradingPost; -import net.minecraft.core.registries.Registries; -import net.minecraft.world.entity.EntityType; - -import java.util.List; public class ServerConfig implements ConfigCore { @Config(description = "Range on xz plane trading post should search for merchants.") @@ -23,13 +16,4 @@ public class ServerConfig implements ConfigCore { public boolean teleportXp = true; @Config(name = "close_empty_screen", description = "Close trading post interface when all traders have become unavailable.") public boolean closeScreen = true; - @Config(name = "trader_blacklist", description = {"Trader entities disabled from being found by the trading post.", "Modders may add their own incompatible trader entities via the \"" + TradingPost.MOD_ID + ":blacklisted_traders\" entity tag.", ConfigDataSet.CONFIG_DESCRIPTION}) - List traderBlacklistRaw = Lists.newArrayList(); - - public ConfigDataSet> traderBlacklist; - - @Override - public void afterConfigReload() { - this.traderBlacklist = ConfigDataSet.from(Registries.ENTITY_TYPE, this.traderBlacklistRaw); - } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java index 9eb0a46..d659f54 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModBlockTagProvider.java @@ -1,19 +1,21 @@ package fuzs.tradingpost.data; -import fuzs.puzzleslib.api.data.v2.AbstractTagProvider; import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.puzzleslib.api.data.v2.tags.AbstractTagProvider; import fuzs.tradingpost.init.ModRegistry; import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; import net.minecraft.tags.BlockTags; +import net.minecraft.world.level.block.Block; -public class ModBlockTagProvider extends AbstractTagProvider.Blocks { +public class ModBlockTagProvider extends AbstractTagProvider { public ModBlockTagProvider(DataProviderContext context) { - super(context); + super(Registries.BLOCK, context); } @Override public void addTags(HolderLookup.Provider provider) { - this.tag(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.TRADING_POST_BLOCK.value()); + this.add(BlockTags.MINEABLE_WITH_AXE).add(ModRegistry.TRADING_POST_BLOCK.value()); } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java index e41bf65..0efaf13 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/data/ModEntityTypeTagProvider.java @@ -1,18 +1,20 @@ package fuzs.tradingpost.data; -import fuzs.puzzleslib.api.data.v2.AbstractTagProvider; import fuzs.puzzleslib.api.data.v2.core.DataProviderContext; +import fuzs.puzzleslib.api.data.v2.tags.AbstractTagProvider; import fuzs.tradingpost.init.ModRegistry; import net.minecraft.core.HolderLookup; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.EntityType; -public class ModEntityTypeTagProvider extends AbstractTagProvider.EntityTypes { +public class ModEntityTypeTagProvider extends AbstractTagProvider> { public ModEntityTypeTagProvider(DataProviderContext context) { - super(context); + super(Registries.ENTITY_TYPE, context); } @Override public void addTags(HolderLookup.Provider provider) { - this.tag(ModRegistry.CONCEALED_TRADERS_ENTITY_TYPE_TAG); + this.add(ModRegistry.EXCLUDE_FROM_TRADING_POST_ENTITY_TYPE_TAG); } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java index 4994315..7438758 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java @@ -26,7 +26,7 @@ public class ModRegistry { public static final Holder.Reference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); static final BoundTagFactory TAGS = BoundTagFactory.make(TradingPost.MOD_ID); - public static final TagKey> CONCEALED_TRADERS_ENTITY_TYPE_TAG = TAGS.registerEntityTypeTag("concealed_traders"); + public static final TagKey> EXCLUDE_FROM_TRADING_POST_ENTITY_TYPE_TAG = TAGS.registerEntityTypeTag("exclude_from_trading_post"); public static void touch() { diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java index bb02a91..47a83b9 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java @@ -11,10 +11,10 @@ public interface MerchantMenuAccessor { @Mutable - @Accessor - void setTrader(Merchant trader); + @Accessor("trader") + void tradingpost$setTrader(Merchant trader); @Mutable - @Accessor - void setTradeContainer(MerchantContainer tradeContainer); + @Accessor("tradeContainer") + void tradingpost$setTradeContainer(MerchantContainer tradeContainer); } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java index 730cccc..7db80bd 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java @@ -8,6 +8,6 @@ @Mixin(Villager.class) public interface VillagerAccessor { - @Invoker - void callUpdateSpecialPrices(Player player); + @Invoker("updateSpecialPrices") + void tradingpost$callUpdateSpecialPrices(Player player); } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java index 91c9727..0caf8ee 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java @@ -3,7 +3,9 @@ import fuzs.puzzleslib.api.network.v2.MessageV2; import fuzs.tradingpost.world.inventory.TradingPostMenu; import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; +import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.trading.MerchantOffers; @@ -37,8 +39,8 @@ public S2CMerchantDataMessage(int containerId, int merchantId, Component merchan public void write(FriendlyByteBuf buf) { buf.writeVarInt(this.containerId); buf.writeInt(this.merchantId); - buf.writeComponent(this.merchantTitle); - this.offers.writeToStream(buf); + ComponentSerialization.TRUSTED_STREAM_CODEC.encode((RegistryFriendlyByteBuf) buf, this.merchantTitle); + MerchantOffers.STREAM_CODEC.encode((RegistryFriendlyByteBuf) buf, this.offers); buf.writeVarInt(this.villagerLevel); buf.writeVarInt(this.villagerXp); buf.writeBoolean(this.showProgress); @@ -49,8 +51,8 @@ public void write(FriendlyByteBuf buf) { public void read(FriendlyByteBuf buf) { this.containerId = buf.readVarInt(); this.merchantId = buf.readInt(); - this.merchantTitle = buf.readComponent(); - this.offers = MerchantOffers.createFromStream(buf); + this.merchantTitle = ComponentSerialization.TRUSTED_STREAM_CODEC.decode((RegistryFriendlyByteBuf) buf); + this.offers = MerchantOffers.STREAM_CODEC.decode((RegistryFriendlyByteBuf) buf); this.villagerLevel = buf.readVarInt(); this.villagerXp = buf.readVarInt(); this.showProgress = buf.readBoolean(); diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java index 3328c71..ceaaf19 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java @@ -22,6 +22,8 @@ import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.ContainerLevelAccess; import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.item.trading.ItemCost; import net.minecraft.world.item.trading.Merchant; import net.minecraft.world.item.trading.MerchantOffer; import net.minecraft.world.item.trading.MerchantOffers; @@ -203,7 +205,7 @@ public boolean updateAvailableMerchants(int containerId, BlockPos pos, Player pl } if (!toRemove.isEmpty()) { toRemove.forEach((IntConsumer) this::removeMerchant); - TradingPost.NETWORK.sendTo(new S2CRemoveMerchantsMessage(containerId, toRemove), (ServerPlayer) player); + TradingPost.NETWORK.sendTo((ServerPlayer) player, new S2CRemoveMerchantsMessage(containerId, toRemove).toClientboundMessage()); } return !this.idToMerchant.isEmpty(); } @@ -240,9 +242,9 @@ public void sendMerchantData(final int containerId, Player player) { final Component merchantTitle = merchant instanceof Entity ? ((Entity) merchant).getDisplayName() : TradingPostBlockEntity.CONTAINER_COMPONENT; final int merchantLevel = merchant instanceof VillagerDataHolder ? ((VillagerDataHolder) merchant).getVillagerData().getLevel() : 0; S2CMerchantDataMessage message = new S2CMerchantDataMessage(containerId, entry.getKey(), merchantTitle, merchant.getOffers(), merchantLevel, merchant.getVillagerXp(), merchant.showProgressBar(), merchant.canRestock()); - TradingPost.NETWORK.sendTo(message, (ServerPlayer) player); + TradingPost.NETWORK.sendTo((ServerPlayer) player, message.toClientboundMessage()); } - TradingPost.NETWORK.sendTo(new S2CBuildOffersMessage(containerId, this.getIdToOfferCountMap()), (ServerPlayer) player); + TradingPost.NETWORK.sendTo((ServerPlayer) player, new S2CBuildOffersMessage(containerId, this.getIdToOfferCountMap()).toClientboundMessage()); } public Int2IntOpenHashMap getIdToOfferCountMap() { @@ -281,6 +283,6 @@ private void buildOfferToMerchantMap() { } private static MerchantOffer fakeOffer() { - return new MerchantOffer(ItemStack.EMPTY, ItemStack.EMPTY, -1, -1, 0.0F); + return new MerchantOffer(new ItemCost(Items.AIR), ItemStack.EMPTY, -1, -1, 0.0F); } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java index c9f9ff3..730adca 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java @@ -13,7 +13,6 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; -import net.minecraft.world.inventory.*; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.Merchant; import net.minecraft.world.item.trading.MerchantOffers; @@ -37,9 +36,9 @@ public TradingPostMenu(int containerId, Inventory inventory, MerchantCollection super(containerId, inventory, merchantCollection); this.access = worldPosCallable; this.traders = merchantCollection; - ((MerchantMenuAccessor) this).setTrader(this.traders); + ((MerchantMenuAccessor) this).tradingpost$setTrader(this.traders); this.tradeContainer = new TradingPostContainer(this.traders); - ((MerchantMenuAccessor) this).setTradeContainer(this.tradeContainer); + ((MerchantMenuAccessor) this).tradingpost$setTradeContainer(this.tradeContainer); this.replaceSlot(0, new Slot(this.tradeContainer, 0, 136, 37)); this.replaceSlot(1, new Slot(this.tradeContainer, 1, 162, 37)); this.replaceSlot(2, new MerchantResultSlot(inventory.player, this.traders, this.tradeContainer, 2, 220, 37)); diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java index 17a2916..03b3948 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java @@ -12,7 +12,6 @@ import net.minecraft.core.BlockPos; import net.minecraft.core.Direction; import net.minecraft.network.chat.Component; -import net.minecraft.world.InteractionHand; import net.minecraft.world.InteractionResult; import net.minecraft.world.SimpleMenuProvider; import net.minecraft.world.entity.Entity; @@ -21,7 +20,6 @@ import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.ContainerLevelAccess; -import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.context.BlockPlaceContext; import net.minecraft.world.item.trading.Merchant; import net.minecraft.world.level.BlockGetter; @@ -110,7 +108,7 @@ public BlockEntityType getBlockEntityType() { } @Override - public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) { + public InteractionResult useWithoutItem(BlockState state, Level level, BlockPos pos, Player player, BlockHitResult hitResult) { if (level.isClientSide) { return InteractionResult.SUCCESS; } else { @@ -123,7 +121,7 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player MerchantCollection merchants = new MerchantCollection(access); for (Entity merchant : traders) { if (merchant instanceof Villager) { - ((VillagerAccessor) merchant).callUpdateSpecialPrices(player); + ((VillagerAccessor) merchant).tradingpost$callUpdateSpecialPrices(player); } merchants.addMerchant(merchant.getId(), (Merchant) merchant); } @@ -144,12 +142,13 @@ public InteractionResult use(BlockState state, Level level, BlockPos pos, Player } else { player.displayClientMessage(MISSING_MERCHANT_COMPONENT, false); } + return InteractionResult.CONSUME; } } public static boolean isAllowedToTrade(Entity entity) { - if (entity.getType().is(ModRegistry.CONCEALED_TRADERS_ENTITY_TYPE_TAG)) { + if (entity.getType().is(ModRegistry.EXCLUDE_FROM_TRADING_POST_ENTITY_TYPE_TAG)) { return false; } @@ -160,22 +159,13 @@ public static boolean isAllowedToTrade(Entity entity) { return !(entity instanceof LivingEntity livingEntity) || !livingEntity.isSleeping() && !livingEntity.isBaby(); } - @Override - public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity entity, ItemStack stack) { - if (stack.hasCustomHoverName()) { - if (level.getBlockEntity(pos) instanceof TradingPostBlockEntity blockEntity) { - blockEntity.setCustomName(stack.getHoverName()); - } - } - } - @Override protected void createBlockStateDefinition(StateDefinition.Builder builder) { builder.add(WATERLOGGED); } @Override - public boolean isPathfindable(BlockState state, BlockGetter blockReader, BlockPos pos, PathComputationType pathType) { + public boolean isPathfindable(BlockState state, PathComputationType pathType) { return false; } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java index 6c3b9b7..b80d8c7 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java @@ -3,7 +3,11 @@ import fuzs.puzzleslib.api.block.v1.entity.TickingBlockEntity; import fuzs.tradingpost.init.ModRegistry; import net.minecraft.core.BlockPos; +import net.minecraft.core.HolderLookup; +import net.minecraft.core.component.DataComponentMap; +import net.minecraft.core.component.DataComponents; import net.minecraft.nbt.CompoundTag; +import net.minecraft.nbt.Tag; import net.minecraft.network.chat.Component; import net.minecraft.world.Nameable; import net.minecraft.world.level.block.entity.BlockEntity; @@ -23,18 +27,18 @@ public TradingPostBlockEntity(BlockPos blockPos, BlockState blockState) { } @Override - protected void saveAdditional(CompoundTag compoundTag) { - super.saveAdditional(compoundTag); + protected void saveAdditional(CompoundTag compoundTag, HolderLookup.Provider registries) { + super.saveAdditional(compoundTag, registries); if (this.hasCustomName()) { - compoundTag.putString("CustomName", Component.Serializer.toJson(this.name)); + compoundTag.putString("CustomName", Component.Serializer.toJson(this.name, registries)); } } @Override - public void load(CompoundTag compoundTag) { - super.load(compoundTag); - if (compoundTag.contains("CustomName", 8)) { - this.name = Component.Serializer.fromJson(compoundTag.getString("CustomName")); + public void loadAdditional(CompoundTag compoundTag, HolderLookup.Provider registries) { + super.loadAdditional(compoundTag, registries); + if (compoundTag.contains("CustomName", Tag.TAG_STRING)) { + this.name = parseCustomNameSafe(compoundTag.getString("CustomName"), registries); } } @@ -61,4 +65,21 @@ public void setCustomName(@Nullable Component component) { public Component getCustomName() { return this.name; } + + @Override + protected void applyImplicitComponents(BlockEntity.DataComponentInput componentInput) { + super.applyImplicitComponents(componentInput); + this.name = componentInput.get(DataComponents.CUSTOM_NAME); + } + + @Override + protected void collectImplicitComponents(DataComponentMap.Builder components) { + super.collectImplicitComponents(components); + components.set(DataComponents.CUSTOM_NAME, this.name); + } + + @Override + public void removeComponentsFromTag(CompoundTag tag) { + tag.remove("CustomName"); + } } diff --git a/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java index 45ce2b8..fcb790f 100644 --- a/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java +++ b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/TradingPostNeoForge.java @@ -7,16 +7,13 @@ import fuzs.tradingpost.data.ModBlockTagProvider; import fuzs.tradingpost.data.ModEntityTypeTagProvider; import fuzs.tradingpost.data.ModRecipeProvider; -import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; -import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; @Mod(TradingPost.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) public class TradingPostNeoForge { - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { + public TradingPostNeoForge(ModContainer modContainer) { ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, ModBlockLootProvider::new, diff --git a/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java index 82c4e26..c0d3ae3 100644 --- a/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java +++ b/1.21/NeoForge/src/main/java/fuzs/tradingpost/neoforge/client/TradingPostNeoForgeClient.java @@ -7,15 +7,13 @@ import fuzs.tradingpost.data.client.ModLanguageProvider; import fuzs.tradingpost.data.client.ModModelProvider; import net.neoforged.api.distmarker.Dist; -import net.neoforged.bus.api.SubscribeEvent; +import net.neoforged.fml.ModContainer; import net.neoforged.fml.common.Mod; -import net.neoforged.fml.event.lifecycle.FMLConstructModEvent; -@Mod.EventBusSubscriber(modid = TradingPost.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +@Mod(value = TradingPost.MOD_ID, dist = Dist.CLIENT) public class TradingPostNeoForgeClient { - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { + public TradingPostNeoForgeClient(ModContainer modContainer) { ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); DataProviderHelper.registerDataProviders(TradingPost.MOD_ID, ModLanguageProvider::new, diff --git a/1.21/gradle.properties b/1.21/gradle.properties index a6bcb90..5edad39 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -20,8 +20,8 @@ modFabricEnvironment=* # Version Catalog dependenciesVersionCatalog=1.21-v5 -#dependenciesPuzzlesLibVersion=21.0.0 -#dependenciesMinPuzzlesLibVersion=21.0.0 +dependenciesPuzzlesLibVersion=21.0.1 +dependenciesMinPuzzlesLibVersion=21.0.0 # Mod Publishing projectReleaseType=release From ab84105eadf03987c0a819e9b5a2b2c0713ef9b3 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 6 Jul 2024 15:19:28 +0200 Subject: [PATCH 18/24] full 1.21 port --- 1.21/CHANGELOG.md | 2 +- .../190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 + .../50b16d832771f8a8317f4d1b88c5121208c8c4f9 | 2 + .../77038cb024c5999ce280bcb6800e72cf1c655fe7 | 3 ++ .../9e953cc4ec64c82f6e78f1ad2800a952d804eb06 | 2 + .../9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e | 3 ++ .../dc1d6e7286e7569a79007c10f809d49635ea1c49 | 3 ++ .../tradingpost/blockstates/trading_post.json | 7 +++ .../assets/tradingpost/lang/en_us.json | 6 +++ .../tradingpost/models/item/trading_post.json | 3 ++ .../data/minecraft/loot_tables/empty.json | 3 ++ .../minecraft/tags/block/mineable/axe.json | 5 ++ .../recipes/decorations/trading_post.json | 32 ++++++++++++ .../loot_tables/blocks/trading_post.json | 30 +++++++++++ .../data/tradingpost/recipe/trading_post.json | 24 +++++++++ .../exclude_from_trading_post.json | 3 ++ .../java/fuzs/tradingpost/TradingPost.java | 8 ++- .../tradingpost/client/TradingPostClient.java | 40 ++++++++------- .../screens/inventory/TradingPostScreen.java | 5 +- .../network/S2CBuildOffersMessage.java | 5 +- .../network/S2CMerchantDataMessage.java | 12 ++--- .../network/S2CRemoveMerchantsMessage.java | 2 +- .../network/client/C2SClearSlotsMessage.java | 4 +- .../world/inventory/TradingPostMenu.java | 20 +++----- .../block/entity/TradingPostBlockEntity.java | 9 ++-- .../assets/tradingpost/lang/zh_cn.json | 7 +++ 1.21/Fabric/build.gradle | 10 ---- 1.21/Forge/build.gradle | 6 --- 1.21/Forge/gradle.properties | 1 - .../tradingpost/forge/TradingPostForge.java | 17 ------- .../forge/client/TradingPostForgeClient.java | 18 ------- .../src/main/resources/META-INF/mods.toml | 51 ------------------- .../src/main/resources/forge.mixins.json | 14 ----- .../{mods.toml => neoforge.mods.toml} | 0 1.21/gradle.properties | 4 +- 1.21/settings.gradle | 1 - 36 files changed, 194 insertions(+), 170 deletions(-) create mode 100644 1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 create mode 100644 1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 create mode 100644 1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 create mode 100644 1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 create mode 100644 1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e create mode 100644 1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 create mode 100644 1.21/Common/src/generated/resources/assets/tradingpost/blockstates/trading_post.json create mode 100644 1.21/Common/src/generated/resources/assets/tradingpost/lang/en_us.json create mode 100644 1.21/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json create mode 100644 1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json create mode 100644 1.21/Common/src/generated/resources/data/minecraft/tags/block/mineable/axe.json create mode 100644 1.21/Common/src/generated/resources/data/tradingpost/advancement/recipes/decorations/trading_post.json create mode 100644 1.21/Common/src/generated/resources/data/tradingpost/loot_tables/blocks/trading_post.json create mode 100644 1.21/Common/src/generated/resources/data/tradingpost/recipe/trading_post.json create mode 100644 1.21/Common/src/generated/resources/data/tradingpost/tags/entity_type/exclude_from_trading_post.json create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/lang/zh_cn.json delete mode 100644 1.21/Forge/build.gradle delete mode 100644 1.21/Forge/gradle.properties delete mode 100644 1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java delete mode 100644 1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java delete mode 100644 1.21/Forge/src/main/resources/META-INF/mods.toml delete mode 100644 1.21/Forge/src/main/resources/forge.mixins.json rename 1.21/NeoForge/src/main/resources/META-INF/{mods.toml => neoforge.mods.toml} (100%) diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index 168dc2f..21aed4c 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,5 +4,5 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). -## [v21.0.0-1.21] - 2024-07-04 +## [v21.0.0-1.21] - 2024-07-06 - Port to Minecraft 1.21 diff --git a/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 new file mode 100644 index 0000000..7ab7db0 --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -0,0 +1,2 @@ +// 1.21 2024-07-06T13:00:21.685243 Language (en_us) +147b78684226f399eeac6159d3fa21f598f5ec2b assets/tradingpost/lang/en_us.json diff --git a/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 b/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 new file mode 100644 index 0000000..523eac7 --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 @@ -0,0 +1,2 @@ +// 1.21 2024-07-06T13:00:21.684792 Tags for minecraft:block mod id vanilla +e37ec5e3a6ed0926dc1d26eb5ad2e1873593f360 data/minecraft/tags/block/mineable/axe.json diff --git a/1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 b/1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 new file mode 100644 index 0000000..b3e8858 --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 @@ -0,0 +1,3 @@ +// 1.21 2024-07-06T13:00:21.685106 Model Definitions +744a7fd8de66b44ea6012a51eb661120ebc8425e assets/tradingpost/blockstates/trading_post.json +cb2e625aee94c9cf690c12865dbd70b3ca956fb5 assets/tradingpost/models/item/trading_post.json diff --git a/1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 b/1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 new file mode 100644 index 0000000..eef469c --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 @@ -0,0 +1,2 @@ +// 1.21 2024-07-06T13:00:21.684951 Tags for minecraft:entity_type mod id vanilla +35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/tradingpost/tags/entity_type/exclude_from_trading_post.json diff --git a/1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e new file mode 100644 index 0000000..90f6ba8 --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -0,0 +1,3 @@ +// 1.21 2024-07-06T13:01:54.234957 Recipes +b01f7336f1d8d20be84e423c0f51f858cfbc30a3 data/tradingpost/advancement/recipes/decorations/trading_post.json +5508e73739200243edbf7b3404bfc9810a5a2acc data/tradingpost/recipe/trading_post.json diff --git a/1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 b/1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 new file mode 100644 index 0000000..27b6c24 --- /dev/null +++ b/1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 @@ -0,0 +1,3 @@ +// 1.21 2024-07-06T13:00:21.684166 Block Loot Tables +1bd1e6b92f9848af7c9eeec6cf7aaeba1adc4796 data/minecraft/loot_tables/empty.json +8dbe8fc577f7fc703cd0269d5de96d6e59d7ff16 data/tradingpost/loot_tables/blocks/trading_post.json diff --git a/1.21/Common/src/generated/resources/assets/tradingpost/blockstates/trading_post.json b/1.21/Common/src/generated/resources/assets/tradingpost/blockstates/trading_post.json new file mode 100644 index 0000000..f9d843d --- /dev/null +++ b/1.21/Common/src/generated/resources/assets/tradingpost/blockstates/trading_post.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "tradingpost:block/trading_post" + } + } +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/assets/tradingpost/lang/en_us.json b/1.21/Common/src/generated/resources/assets/tradingpost/lang/en_us.json new file mode 100644 index 0000000..55eb8e1 --- /dev/null +++ b/1.21/Common/src/generated/resources/assets/tradingpost/lang/en_us.json @@ -0,0 +1,6 @@ +{ + "block.tradingpost.trading_post": "Trading Post", + "container.trading_post": "Trading Post", + "trading_post.no_trader_found": "Couldn't find any available trader nearby", + "trading_post.trader_gone": "The trader is no longer available." +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json b/1.21/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json new file mode 100644 index 0000000..ad10a89 --- /dev/null +++ b/1.21/Common/src/generated/resources/assets/tradingpost/models/item/trading_post.json @@ -0,0 +1,3 @@ +{ + "parent": "tradingpost:block/trading_post" +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json b/1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json new file mode 100644 index 0000000..f6cbde3 --- /dev/null +++ b/1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json @@ -0,0 +1,3 @@ +{ + "type": "minecraft:empty" +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/data/minecraft/tags/block/mineable/axe.json b/1.21/Common/src/generated/resources/data/minecraft/tags/block/mineable/axe.json new file mode 100644 index 0000000..bee9214 --- /dev/null +++ b/1.21/Common/src/generated/resources/data/minecraft/tags/block/mineable/axe.json @@ -0,0 +1,5 @@ +{ + "values": [ + "tradingpost:trading_post" + ] +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/data/tradingpost/advancement/recipes/decorations/trading_post.json b/1.21/Common/src/generated/resources/data/tradingpost/advancement/recipes/decorations/trading_post.json new file mode 100644 index 0000000..99bca06 --- /dev/null +++ b/1.21/Common/src/generated/resources/data/tradingpost/advancement/recipes/decorations/trading_post.json @@ -0,0 +1,32 @@ +{ + "parent": "minecraft:recipes/root", + "criteria": { + "has_emerald": { + "conditions": { + "items": [ + { + "items": "minecraft:emerald" + } + ] + }, + "trigger": "minecraft:inventory_changed" + }, + "has_the_recipe": { + "conditions": { + "recipe": "tradingpost:trading_post" + }, + "trigger": "minecraft:recipe_unlocked" + } + }, + "requirements": [ + [ + "has_the_recipe", + "has_emerald" + ] + ], + "rewards": { + "recipes": [ + "tradingpost:trading_post" + ] + } +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/data/tradingpost/loot_tables/blocks/trading_post.json b/1.21/Common/src/generated/resources/data/tradingpost/loot_tables/blocks/trading_post.json new file mode 100644 index 0000000..dcb5410 --- /dev/null +++ b/1.21/Common/src/generated/resources/data/tradingpost/loot_tables/blocks/trading_post.json @@ -0,0 +1,30 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "bonus_rolls": 0.0, + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ], + "entries": [ + { + "type": "minecraft:item", + "functions": [ + { + "function": "minecraft:copy_components", + "include": [ + "minecraft:custom_name" + ], + "source": "block_entity" + } + ], + "name": "tradingpost:trading_post" + } + ], + "rolls": 1.0 + } + ], + "random_sequence": "tradingpost:blocks/trading_post" +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/data/tradingpost/recipe/trading_post.json b/1.21/Common/src/generated/resources/data/tradingpost/recipe/trading_post.json new file mode 100644 index 0000000..2fd979a --- /dev/null +++ b/1.21/Common/src/generated/resources/data/tradingpost/recipe/trading_post.json @@ -0,0 +1,24 @@ +{ + "type": "minecraft:crafting_shaped", + "category": "misc", + "key": { + "#": { + "tag": "minecraft:planks" + }, + "S": { + "item": "minecraft:stick" + }, + "X": { + "item": "minecraft:emerald" + } + }, + "pattern": [ + " X ", + "###", + "S S" + ], + "result": { + "count": 1, + "id": "tradingpost:trading_post" + } +} \ No newline at end of file diff --git a/1.21/Common/src/generated/resources/data/tradingpost/tags/entity_type/exclude_from_trading_post.json b/1.21/Common/src/generated/resources/data/tradingpost/tags/entity_type/exclude_from_trading_post.json new file mode 100644 index 0000000..f72d209 --- /dev/null +++ b/1.21/Common/src/generated/resources/data/tradingpost/tags/entity_type/exclude_from_trading_post.json @@ -0,0 +1,3 @@ +{ + "values": [] +} \ No newline at end of file diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java index 431cce2..e8a659c 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/TradingPost.java @@ -5,7 +5,7 @@ import fuzs.puzzleslib.api.core.v1.context.BuildCreativeModeTabContentsContext; import fuzs.puzzleslib.api.core.v1.context.FuelBurnTimesContext; import fuzs.puzzleslib.api.core.v1.utility.ResourceLocationHelper; -import fuzs.puzzleslib.api.network.v3.NetworkHandlerV3; +import fuzs.puzzleslib.api.network.v3.NetworkHandler; import fuzs.tradingpost.config.ServerConfig; import fuzs.tradingpost.init.ModRegistry; import fuzs.tradingpost.network.S2CBuildOffersMessage; @@ -22,7 +22,11 @@ public class TradingPost implements ModConstructor { public static final String MOD_NAME = "Trading Post"; public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); - public static final NetworkHandlerV3 NETWORK = NetworkHandlerV3.builder(MOD_ID).registerLegacyClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new).registerLegacyClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new).registerLegacyClientbound(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new).registerLegacyClientbound(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new).registerLegacyServerbound(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new); + public static final NetworkHandler NETWORK = NetworkHandler.builder(MOD_ID) + .registerLegacyClientbound(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new) + .registerLegacyClientbound(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new) + .registerLegacyClientbound(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new) + .registerLegacyServerbound(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new); public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).server(ServerConfig.class); @Override diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java index fb14cb3..bb1f3ba 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -1,39 +1,41 @@ package fuzs.tradingpost.client; -import fuzs.puzzleslib.api.client.core.v1.ClientAbstractions; import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; import fuzs.puzzleslib.api.client.core.v1.context.MenuScreensContext; +import fuzs.puzzleslib.api.client.searchtree.v1.SearchRegistryHelper; +import fuzs.puzzleslib.api.client.searchtree.v1.SearchTreeType; +import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; import fuzs.tradingpost.client.renderer.blockentity.TradingPostRenderer; import fuzs.tradingpost.init.ModRegistry; -import net.minecraft.ChatFormatting; import net.minecraft.client.searchtree.FullTextSearchTree; -import net.minecraft.client.searchtree.SearchRegistry; import net.minecraft.core.registries.BuiltInRegistries; import net.minecraft.world.item.ItemStack; -import net.minecraft.world.item.TooltipFlag; import net.minecraft.world.item.trading.MerchantOffer; +import java.util.List; +import java.util.function.Predicate; import java.util.stream.Stream; public class TradingPostClient implements ClientModConstructor { - public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); + public static final SearchTreeType MERCHANT_OFFERS_SEARCH_TREE = new SearchTreeType<>( + TradingPost.id("merchant_offers")); @Override public void onClientSetup() { - ClientAbstractions.INSTANCE.getSearchRegistry().register(OFFER_SEARCH_TREE, base -> new FullTextSearchTree<>(offer -> - Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) - .filter(itemStack -> !itemStack.isEmpty()) - .flatMap(itemStack -> itemStack.getTooltipLines(null, TooltipFlag.Default.NORMAL).stream()) - .map(tooltipLine -> ChatFormatting.stripFormatting(tooltipLine.getString()).trim()) - .filter(tooltipString -> !tooltipString.isEmpty()), - offer -> Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) - .filter(itemStack -> !itemStack.isEmpty()) - .map(ItemStack::getItem) - .map(BuiltInRegistries.ITEM::getKey), - base - )); + SearchRegistryHelper.register(MERCHANT_OFFERS_SEARCH_TREE, (List values) -> { + return new FullTextSearchTree<>((MerchantOffer offer) -> Stream.of(offer.getBaseCostA(), + offer.getCostB(), + offer.getResult() + ).filter(Predicate.not(ItemStack::isEmpty)).flatMap(SearchRegistryHelper::getTooltipLines), + (MerchantOffer offer) -> Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) + .filter(Predicate.not(ItemStack::isEmpty)) + .map(ItemStack::getItem) + .map(BuiltInRegistries.ITEM::getKey), + values + ); + }); } @Override @@ -43,6 +45,8 @@ public void onRegisterMenuScreens(MenuScreensContext context) { @Override public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { - context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(), TradingPostRenderer::new); + context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.value(), + TradingPostRenderer::new + ); } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java index 0e464ec..e584a87 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -1,6 +1,7 @@ package fuzs.tradingpost.client.gui.screens.inventory; import com.mojang.blaze3d.systems.RenderSystem; +import fuzs.puzzleslib.api.client.searchtree.v1.SearchRegistryHelper; import fuzs.puzzleslib.api.core.v1.utility.ResourceLocationHelper; import fuzs.tradingpost.TradingPost; import fuzs.tradingpost.client.TradingPostClient; @@ -325,8 +326,8 @@ public void refreshSearchResults() { if (query.isEmpty()) { offers.clearFilter(); } else { - SearchTree isearchtree = this.minecraft.getSearchTree(TradingPostClient.OFFER_SEARCH_TREE); - offers.setFilter(isearchtree.search(query.toLowerCase(Locale.ROOT))); + SearchTree searchTree = SearchRegistryHelper.getSearchTree(TradingPostClient.MERCHANT_OFFERS_SEARCH_TREE); + offers.setFilter(searchTree.search(query.toLowerCase(Locale.ROOT))); } ((MerchantScreenAccessor) this).tradingpost$setScrollOff(0); ((MerchantScreenAccessor) this).tradingpost$setShopItem(0); diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java index 48d34fb..6205f2d 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java @@ -1,5 +1,6 @@ package fuzs.tradingpost.network; +import fuzs.puzzleslib.api.client.searchtree.v1.SearchRegistryHelper; import fuzs.puzzleslib.api.network.v2.MessageV2; import fuzs.tradingpost.client.TradingPostClient; import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; @@ -15,7 +16,7 @@ public class S2CBuildOffersMessage implements MessageV2 { private Int2IntOpenHashMap idToOfferCount; public S2CBuildOffersMessage() { - + // NO-OP } public S2CBuildOffersMessage(int containerId, Int2IntOpenHashMap idToOfferCount) { @@ -53,7 +54,7 @@ public void handle(S2CBuildOffersMessage message, Player player, Object gameInst Minecraft minecraft = (Minecraft) gameInstance; if (message.containerId == player.containerMenu.containerId && player.containerMenu instanceof TradingPostMenu playerMenu && minecraft.screen instanceof TradingPostScreen screen) { playerMenu.getTraders().buildOffers(message.idToOfferCount); - minecraft.populateSearchTree(TradingPostClient.OFFER_SEARCH_TREE, playerMenu.getOffers()); + SearchRegistryHelper.populateSearchTree(TradingPostClient.MERCHANT_OFFERS_SEARCH_TREE, playerMenu.getOffers()); screen.refreshSearchResults(); } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java index 0caf8ee..79fa28d 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java @@ -1,11 +1,11 @@ package fuzs.tradingpost.network; import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.puzzleslib.api.network.v3.codec.ExtraStreamCodecs; import fuzs.tradingpost.world.inventory.TradingPostMenu; import net.minecraft.network.FriendlyByteBuf; import net.minecraft.network.RegistryFriendlyByteBuf; import net.minecraft.network.chat.Component; -import net.minecraft.network.chat.ComponentSerialization; import net.minecraft.world.entity.player.Player; import net.minecraft.world.inventory.AbstractContainerMenu; import net.minecraft.world.item.trading.MerchantOffers; @@ -21,7 +21,7 @@ public class S2CMerchantDataMessage implements MessageV2 private boolean canRestock; public S2CMerchantDataMessage() { - + // NO-OP } public S2CMerchantDataMessage(int containerId, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { @@ -39,7 +39,7 @@ public S2CMerchantDataMessage(int containerId, int merchantId, Component merchan public void write(FriendlyByteBuf buf) { buf.writeVarInt(this.containerId); buf.writeInt(this.merchantId); - ComponentSerialization.TRUSTED_STREAM_CODEC.encode((RegistryFriendlyByteBuf) buf, this.merchantTitle); + ExtraStreamCodecs.writeComponent(buf, this.merchantTitle); MerchantOffers.STREAM_CODEC.encode((RegistryFriendlyByteBuf) buf, this.offers); buf.writeVarInt(this.villagerLevel); buf.writeVarInt(this.villagerXp); @@ -51,7 +51,7 @@ public void write(FriendlyByteBuf buf) { public void read(FriendlyByteBuf buf) { this.containerId = buf.readVarInt(); this.merchantId = buf.readInt(); - this.merchantTitle = ComponentSerialization.TRUSTED_STREAM_CODEC.decode((RegistryFriendlyByteBuf) buf); + this.merchantTitle = ExtraStreamCodecs.readComponent(buf); this.offers = MerchantOffers.STREAM_CODEC.decode((RegistryFriendlyByteBuf) buf); this.villagerLevel = buf.readVarInt(); this.villagerXp = buf.readVarInt(); @@ -66,8 +66,8 @@ public MessageHandler makeHandler() { @Override public void handle(S2CMerchantDataMessage packet, Player player, Object gameInstance) { AbstractContainerMenu container = player.containerMenu; - if (packet.containerId == container.containerId && container instanceof TradingPostMenu) { - ((TradingPostMenu) container).addMerchant(player, packet.merchantId, packet.merchantTitle, new MerchantOffers(packet.offers.createTag()), packet.villagerLevel, packet.villagerXp, packet.showProgress, packet.canRestock); + if (packet.containerId == container.containerId && container instanceof TradingPostMenu tradingPostMenu) { + tradingPostMenu.addMerchant(player, packet.merchantId, packet.merchantTitle, packet.offers, packet.villagerLevel, packet.villagerXp, packet.showProgress, packet.canRestock); } } }; diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java index 8aa0653..96fcd74 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java @@ -13,7 +13,7 @@ public class S2CRemoveMerchantsMessage implements MessageV2 { @Override public void write(FriendlyByteBuf buf) { - + // NO-OP } @Override public void read(FriendlyByteBuf buf) { - + // NO-OP } @Override diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java index 730adca..41314de 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java @@ -13,6 +13,7 @@ import net.minecraft.world.entity.Entity; import net.minecraft.world.entity.player.Inventory; import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.*; import net.minecraft.world.item.ItemStack; import net.minecraft.world.item.trading.Merchant; import net.minecraft.world.item.trading.MerchantOffers; @@ -154,8 +155,8 @@ public void lockOffers(boolean lock) { this.lockOffers = lock; } - public void addMerchant(Player playerEntity, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { - LocalMerchant merchant = new LocalMerchant(playerEntity, merchantTitle, offers, villagerLevel, villagerXp, showProgress, canRestock); + public void addMerchant(Player player, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { + LocalMerchant merchant = new LocalMerchant(player, merchantTitle, offers, villagerLevel, villagerXp, showProgress, canRestock); this.traders.addMerchant(merchantId, merchant); } @@ -176,31 +177,26 @@ public boolean showProgressBar() { @Override public void setShowProgressBar(boolean showProgressBar) { - // Don't throw to not break other mods possibly interfering with the merchant menu. - TradingPost.LOGGER.error("Operation setShowProgressBar no supported on trading post, set showProgressBar to merchants directly"); + // NO-OP } @Override public void setXp(int xpValue) { - // Don't throw to not break other mods possibly interfering with the merchant menu. - TradingPost.LOGGER.error("Operation setXp no supported on trading post, set xp to merchants directly"); + // NO-OP } @Override public void setMerchantLevel(int merchantLevel) { - // Don't throw to not break other mods possibly interfering with the merchant menu. - TradingPost.LOGGER.error("Operation setMerchantLevel no supported on trading post, set level to merchants directly"); + // NO-OP } @Override public void setCanRestock(boolean canRestock) { - // Don't throw to not break other mods possibly interfering with the merchant menu. - TradingPost.LOGGER.error("Operation setCanRestock no supported on trading post, set canRestock to merchants directly"); + // NO-OP } @Override public void setOffers(MerchantOffers offers) { - // Don't throw to not break other mods possibly interfering with the merchant menu. - TradingPost.LOGGER.error("Operation setOffers no supported on trading post, set offers to merchants directly"); + // NO-OP } } diff --git a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java index b80d8c7..9f49f64 100644 --- a/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java +++ b/1.21/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java @@ -16,6 +16,7 @@ public class TradingPostBlockEntity extends BlockEntity implements Nameable, TickingBlockEntity { public static final Component CONTAINER_COMPONENT = Component.translatable("container.trading_post"); + public static final String TAG_CUSTOM_NAME = "CustomName"; private final TradingPostAnimationController animationController; @Nullable @@ -30,15 +31,15 @@ public TradingPostBlockEntity(BlockPos blockPos, BlockState blockState) { protected void saveAdditional(CompoundTag compoundTag, HolderLookup.Provider registries) { super.saveAdditional(compoundTag, registries); if (this.hasCustomName()) { - compoundTag.putString("CustomName", Component.Serializer.toJson(this.name, registries)); + compoundTag.putString(TAG_CUSTOM_NAME, Component.Serializer.toJson(this.name, registries)); } } @Override public void loadAdditional(CompoundTag compoundTag, HolderLookup.Provider registries) { super.loadAdditional(compoundTag, registries); - if (compoundTag.contains("CustomName", Tag.TAG_STRING)) { - this.name = parseCustomNameSafe(compoundTag.getString("CustomName"), registries); + if (compoundTag.contains(TAG_CUSTOM_NAME, Tag.TAG_STRING)) { + this.name = parseCustomNameSafe(compoundTag.getString(TAG_CUSTOM_NAME), registries); } } @@ -80,6 +81,6 @@ protected void collectImplicitComponents(DataComponentMap.Builder components) { @Override public void removeComponentsFromTag(CompoundTag tag) { - tag.remove("CustomName"); + tag.remove(TAG_CUSTOM_NAME); } } diff --git a/1.21/Common/src/main/resources/assets/tradingpost/lang/zh_cn.json b/1.21/Common/src/main/resources/assets/tradingpost/lang/zh_cn.json new file mode 100644 index 0000000..6b534ef --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/lang/zh_cn.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "贸易台", + "container.trading_post": "贸易台", + "trading_post.no_trader_found": "附近没有可用交易", + "trading_post.trader_gone": "贸易台", + "trading_post.search": "搜索中……" +} diff --git a/1.21/Fabric/build.gradle b/1.21/Fabric/build.gradle index cec9b27..6eac91e 100644 --- a/1.21/Fabric/build.gradle +++ b/1.21/Fabric/build.gradle @@ -6,14 +6,4 @@ dependencies { // Puzzles Lib modApi libs.puzzleslib.fabric - - // Cardinal Components -// modApi(include(libs.cardinalcomponentsbase.fabric.get())) -// modApi(include(libs.cardinalcomponentsentity.fabric.get())) -// modApi(include(libs.cardinalcomponentsblock.fabric.get())) -// modApi(include(libs.cardinalcomponentschunk.fabric.get())) -// modApi(include(libs.cardinalcomponentsworld.fabric.get())) - - // Extensible Enums -// modApi(include(libs.extensibleenums.fabric.get())) } diff --git a/1.21/Forge/build.gradle b/1.21/Forge/build.gradle deleted file mode 100644 index f9839f1..0000000 --- a/1.21/Forge/build.gradle +++ /dev/null @@ -1,6 +0,0 @@ -apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/forge.gradle" - -dependencies { - // Puzzles Lib - modApi libs.puzzleslib.forge -} diff --git a/1.21/Forge/gradle.properties b/1.21/Forge/gradle.properties deleted file mode 100644 index 32f842a..0000000 --- a/1.21/Forge/gradle.properties +++ /dev/null @@ -1 +0,0 @@ -loom.platform=forge \ No newline at end of file diff --git a/1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java b/1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java deleted file mode 100644 index 0f01496..0000000 --- a/1.21/Forge/src/main/java/fuzs/tradingpost/forge/TradingPostForge.java +++ /dev/null @@ -1,17 +0,0 @@ -package fuzs.tradingpost.forge; - -import fuzs.puzzleslib.api.core.v1.ModConstructor; -import fuzs.tradingpost.TradingPost; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; - -@Mod(TradingPost.MOD_ID) -@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) -public class TradingPostForge { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); - } -} diff --git a/1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java b/1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java deleted file mode 100644 index d400491..0000000 --- a/1.21/Forge/src/main/java/fuzs/tradingpost/forge/client/TradingPostForgeClient.java +++ /dev/null @@ -1,18 +0,0 @@ -package fuzs.tradingpost.forge.client; - -import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; -import fuzs.tradingpost.TradingPost; -import fuzs.tradingpost.client.TradingPostClient; -import net.minecraftforge.api.distmarker.Dist; -import net.minecraftforge.eventbus.api.SubscribeEvent; -import net.minecraftforge.fml.common.Mod; -import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; - -@Mod.EventBusSubscriber(modid = TradingPost.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) -public class TradingPostForgeClient { - - @SubscribeEvent - public static void onConstructMod(final FMLConstructModEvent evt) { - ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); - } -} diff --git a/1.21/Forge/src/main/resources/META-INF/mods.toml b/1.21/Forge/src/main/resources/META-INF/mods.toml deleted file mode 100644 index 6c2e585..0000000 --- a/1.21/Forge/src/main/resources/META-INF/mods.toml +++ /dev/null @@ -1,51 +0,0 @@ -modLoader = "javafml" -loaderVersion = "*" -license = "${modLicense}" -issueTrackerURL = "${modIssueUrl}" - -[[mods]] -modId = "${modId}" -displayName = "${modName}" -description = "${modDescription}" -version = "${modVersion}" -authors = "${modAuthor}" -logoFile = "mod_banner.png" -logoBlur = false -displayURL = "${modPageUrl}" -updateJSONURL = "${modUpdateUrl}" -displayTest = "${modForgeDisplayTest}" - -[[dependencies.${ modId }]] -modId = "forge" -mandatory = true -type = "required" -versionRange = "[${minForgeVersion},)" -ordering = "NONE" -side = "BOTH" - -[[dependencies.${ modId }]] -modId = "minecraft" -mandatory = true -type = "required" -versionRange = "[${minecraftVersion}]" -ordering = "NONE" -side = "BOTH" - -[[dependencies.${ modId }]] -modId = "forgeconfigapiport" -mandatory = true -type = "required" -versionRange = "*" -ordering = "NONE" -side = "BOTH" - -[[dependencies.${ modId }]] -modId = "puzzleslib" -mandatory = true -type = "required" -versionRange = "[${minPuzzlesVersion},)" -ordering = "NONE" -side = "BOTH" - -[modproperties.${ modId }] -catalogueImageIcon = "mod_logo.png" diff --git a/1.21/Forge/src/main/resources/forge.mixins.json b/1.21/Forge/src/main/resources/forge.mixins.json deleted file mode 100644 index f2b4276..0000000 --- a/1.21/Forge/src/main/resources/forge.mixins.json +++ /dev/null @@ -1,14 +0,0 @@ -{ - "required": true, - "minVersion": "0.8", - "compatibilityLevel": "JAVA_17", - "package": "${modGroup}.forge.mixin", - "mixins": [ - ], - "client": [ - ], - "injectors": { - "defaultRequire": 1 - }, - "refmap": "${modId}.forge.refmap.json" -} diff --git a/1.21/NeoForge/src/main/resources/META-INF/mods.toml b/1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml similarity index 100% rename from 1.21/NeoForge/src/main/resources/META-INF/mods.toml rename to 1.21/NeoForge/src/main/resources/META-INF/neoforge.mods.toml diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 5edad39..1114254 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -20,8 +20,8 @@ modFabricEnvironment=* # Version Catalog dependenciesVersionCatalog=1.21-v5 -dependenciesPuzzlesLibVersion=21.0.1 -dependenciesMinPuzzlesLibVersion=21.0.0 +dependenciesPuzzlesLibVersion=21.0.4 +dependenciesMinPuzzlesLibVersion=21.0.4 # Mod Publishing projectReleaseType=release diff --git a/1.21/settings.gradle b/1.21/settings.gradle index 5cfe5eb..5be31f8 100644 --- a/1.21/settings.gradle +++ b/1.21/settings.gradle @@ -11,6 +11,5 @@ pluginManagement { include "Common" include "Fabric" include "NeoForge" -//include "Forge" apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From dec965d32f9810b9c6b8bd3d516b34d07097a176 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 6 Jul 2024 15:56:46 +0200 Subject: [PATCH 19/24] Update settings.gradle --- 1.21/settings.gradle | 1 - 1 file changed, 1 deletion(-) diff --git a/1.21/settings.gradle b/1.21/settings.gradle index 5be31f8..6045c21 100644 --- a/1.21/settings.gradle +++ b/1.21/settings.gradle @@ -4,7 +4,6 @@ pluginManagement { maven { url "https://maven.architectury.dev/" } maven { url "https://maven.fabricmc.net/" } maven { url "https://maven.neoforged.net/releases/" } - maven { url "https://maven.minecraftforge.net/" } } } From 8017f4e4f88d22727bea7d5641959aac40952510 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:42:15 +0200 Subject: [PATCH 20/24] Update settings.gradle --- 1.21/settings.gradle | 2 ++ 1 file changed, 2 insertions(+) diff --git a/1.21/settings.gradle b/1.21/settings.gradle index 6045c21..5cfe5eb 100644 --- a/1.21/settings.gradle +++ b/1.21/settings.gradle @@ -4,11 +4,13 @@ pluginManagement { maven { url "https://maven.architectury.dev/" } maven { url "https://maven.fabricmc.net/" } maven { url "https://maven.neoforged.net/releases/" } + maven { url "https://maven.minecraftforge.net/" } } } include "Common" include "Fabric" include "NeoForge" +//include "Forge" apply from: "https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/v2/settings.gradle" From 7d5c6280ada513659e6febfe59c04d674a4d8e1b Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Sat, 6 Jul 2024 16:45:56 +0200 Subject: [PATCH 21/24] re-run data gen --- 1.21/CHANGELOG.md | 4 ++++ .../resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 | 2 +- .../resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 | 2 +- .../resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 | 2 +- .../resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 | 2 +- .../resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e | 2 +- .../resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 | 3 +-- .../generated/resources/data/minecraft/loot_tables/empty.json | 3 --- 1.21/gradle.properties | 2 +- 9 files changed, 11 insertions(+), 11 deletions(-) delete mode 100644 1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json diff --git a/1.21/CHANGELOG.md b/1.21/CHANGELOG.md index 21aed4c..15441f9 100644 --- a/1.21/CHANGELOG.md +++ b/1.21/CHANGELOG.md @@ -4,5 +4,9 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## [v21.0.1-1.21] - 2024-07-06 +### Fixed +- Remove empty loot table from mod jar + ## [v21.0.0-1.21] - 2024-07-06 - Port to Minecraft 1.21 diff --git a/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 index 7ab7db0..bd350bb 100644 --- a/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 +++ b/1.21/Common/src/generated/resources/.cache/190dc8cc9e260d5273a6d094a2d5cfe3ccdbd9b6 @@ -1,2 +1,2 @@ -// 1.21 2024-07-06T13:00:21.685243 Language (en_us) +// 1.21 2024-07-06T16:44:49.408229 Language (en_us) 147b78684226f399eeac6159d3fa21f598f5ec2b assets/tradingpost/lang/en_us.json diff --git a/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 b/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 index 523eac7..8dd819b 100644 --- a/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 +++ b/1.21/Common/src/generated/resources/.cache/50b16d832771f8a8317f4d1b88c5121208c8c4f9 @@ -1,2 +1,2 @@ -// 1.21 2024-07-06T13:00:21.684792 Tags for minecraft:block mod id vanilla +// 1.21 2024-07-06T16:44:49.407787 Tags for minecraft:block mod id vanilla e37ec5e3a6ed0926dc1d26eb5ad2e1873593f360 data/minecraft/tags/block/mineable/axe.json diff --git a/1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 b/1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 index b3e8858..a984b6a 100644 --- a/1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 +++ b/1.21/Common/src/generated/resources/.cache/77038cb024c5999ce280bcb6800e72cf1c655fe7 @@ -1,3 +1,3 @@ -// 1.21 2024-07-06T13:00:21.685106 Model Definitions +// 1.21 2024-07-06T16:44:49.408087 Model Definitions 744a7fd8de66b44ea6012a51eb661120ebc8425e assets/tradingpost/blockstates/trading_post.json cb2e625aee94c9cf690c12865dbd70b3ca956fb5 assets/tradingpost/models/item/trading_post.json diff --git a/1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 b/1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 index eef469c..0539e09 100644 --- a/1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 +++ b/1.21/Common/src/generated/resources/.cache/9e953cc4ec64c82f6e78f1ad2800a952d804eb06 @@ -1,2 +1,2 @@ -// 1.21 2024-07-06T13:00:21.684951 Tags for minecraft:entity_type mod id vanilla +// 1.21 2024-07-06T16:44:49.407937 Tags for minecraft:entity_type mod id vanilla 35133e95f1c8fdd7a1c21afcc231fc0bffefb9a8 data/tradingpost/tags/entity_type/exclude_from_trading_post.json diff --git a/1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e b/1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e index 90f6ba8..5157b80 100644 --- a/1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e +++ b/1.21/Common/src/generated/resources/.cache/9fb1092f32d4fcbf9e061ffd718d4ec689c6c95e @@ -1,3 +1,3 @@ -// 1.21 2024-07-06T13:01:54.234957 Recipes +// 1.21 2024-07-06T16:44:49.408355 Recipes b01f7336f1d8d20be84e423c0f51f858cfbc30a3 data/tradingpost/advancement/recipes/decorations/trading_post.json 5508e73739200243edbf7b3404bfc9810a5a2acc data/tradingpost/recipe/trading_post.json diff --git a/1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 b/1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 index 27b6c24..f785d93 100644 --- a/1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 +++ b/1.21/Common/src/generated/resources/.cache/dc1d6e7286e7569a79007c10f809d49635ea1c49 @@ -1,3 +1,2 @@ -// 1.21 2024-07-06T13:00:21.684166 Block Loot Tables -1bd1e6b92f9848af7c9eeec6cf7aaeba1adc4796 data/minecraft/loot_tables/empty.json +// 1.21 2024-07-06T16:44:49.40713 Block Loot Tables 8dbe8fc577f7fc703cd0269d5de96d6e59d7ff16 data/tradingpost/loot_tables/blocks/trading_post.json diff --git a/1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json b/1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json deleted file mode 100644 index f6cbde3..0000000 --- a/1.21/Common/src/generated/resources/data/minecraft/loot_tables/empty.json +++ /dev/null @@ -1,3 +0,0 @@ -{ - "type": "minecraft:empty" -} \ No newline at end of file diff --git a/1.21/gradle.properties b/1.21/gradle.properties index 1114254..fea7290 100755 --- a/1.21/gradle.properties +++ b/1.21/gradle.properties @@ -5,7 +5,7 @@ copyBuildJar=true # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=21.0.0 +modVersion=21.0.1 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modLicense=MPL-2.0 From 14a14dc83bb42d23603aa0c3ffedc45b5736d087 Mon Sep 17 00:00:00 2001 From: Joshua Bright Date: Thu, 11 Jul 2024 18:08:12 +0900 Subject: [PATCH 22/24] 100% Koreanized for 1.20.4 --- .../generated/resources/assets/tradingpost/lang/ko_kr.json | 6 ++++++ 1 file changed, 6 insertions(+) create mode 100644 1.20.4/Common/src/generated/resources/assets/tradingpost/lang/ko_kr.json diff --git a/1.20.4/Common/src/generated/resources/assets/tradingpost/lang/ko_kr.json b/1.20.4/Common/src/generated/resources/assets/tradingpost/lang/ko_kr.json new file mode 100644 index 0000000..675bf6a --- /dev/null +++ b/1.20.4/Common/src/generated/resources/assets/tradingpost/lang/ko_kr.json @@ -0,0 +1,6 @@ +{ + "block.tradingpost.trading_post": "교역소", + "container.trading_post": "교역소", + "trading_post.no_trader_found": "주변에 거래 가능한 상인을 찾을 수 없습니다", + "trading_post.trader_gone": "상인을 더 이상 이용할 수 없습니다" +} From 40413434d862ba1f360fd64fa266db4471b8d420 Mon Sep 17 00:00:00 2001 From: Joshua Bright Date: Thu, 11 Jul 2024 18:09:12 +0900 Subject: [PATCH 23/24] 100% Koreanized for 1.20.1 --- .../src/main/resources/assets/tradingpost/lang/ko_kr.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 1.20.1/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json diff --git a/1.20.1/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json b/1.20.1/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json new file mode 100644 index 0000000..1340ec6 --- /dev/null +++ b/1.20.1/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "교역소", + "container.trading_post": "교역소", + "trading_post.no_trader_found": "주변에 거래 가능한 상인을 찾을 수 없습니다", + "trading_post.trader_gone": "상인을 더 이상 이용할 수 없습니다", + "trading_post.search": "검색중..." +} From 04e662c496283a95df59e14b97e5605e215eae8b Mon Sep 17 00:00:00 2001 From: Joshua Bright Date: Thu, 11 Jul 2024 18:10:22 +0900 Subject: [PATCH 24/24] 100% Koreanized for 1.21 --- .../src/main/resources/assets/tradingpost/lang/ko_kr.json | 7 +++++++ 1 file changed, 7 insertions(+) create mode 100644 1.21/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json diff --git a/1.21/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json b/1.21/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json new file mode 100644 index 0000000..1340ec6 --- /dev/null +++ b/1.21/Common/src/main/resources/assets/tradingpost/lang/ko_kr.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "교역소", + "container.trading_post": "교역소", + "trading_post.no_trader_found": "주변에 거래 가능한 상인을 찾을 수 없습니다", + "trading_post.trader_gone": "상인을 더 이상 이용할 수 없습니다", + "trading_post.search": "검색중..." +}

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 ScNgau(U?ep-K_E5zy1%ZQTdPn literal 0 HcmV?d00001 diff --git a/gradle/wrapper/gradle-wrapper.properties b/1.20/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from gradle/wrapper/gradle-wrapper.properties rename to 1.20/gradle/wrapper/gradle-wrapper.properties diff --git a/1.20/gradlew b/1.20/gradlew new file mode 100755 index 0000000..65dcd68 --- /dev/null +++ b/1.20/gradlew @@ -0,0 +1,244 @@ +#!/bin/sh + +# +# Copyright © 2015-2021 the original authors. +# +# Licensed under the Apache License, Version 2.0 (the "License"); +# you may not use this file except in compliance with the License. +# You may obtain a copy of the License at +# +# https://www.apache.org/licenses/LICENSE-2.0 +# +# Unless required by applicable law or agreed to in writing, software +# distributed under the License is distributed on an "AS IS" BASIS, +# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +# See the License for the specific language governing permissions and +# limitations under the License. +# + +############################################################################## +# +# Gradle start up script for POSIX generated by Gradle. +# +# Important for running: +# +# (1) You need a POSIX-compliant shell to run this script. If your /bin/sh is +# noncompliant, but you have some other compliant shell such as ksh or +# bash, then to run this script, type that shell name before the whole +# command line, like: +# +# ksh Gradle +# +# Busybox and similar reduced shells will NOT work, because this script +# requires all of these POSIX shell features: +# * functions; +# * expansions «$var», «${var}», «${var:-default}», «${var+SET}», +# «${var#prefix}», «${var%suffix}», and «$( cmd )»; +# * compound commands having a testable exit status, especially «case»; +# * various built-in commands including «command», «set», and «ulimit». +# +# Important for patching: +# +# (2) This script targets any POSIX shell, so it avoids extensions provided +# by Bash, Ksh, etc; in particular arrays are avoided. +# +# The "traditional" practice of packing multiple parameters into a +# space-separated string is a well documented source of bugs and security +# problems, so this is (mostly) avoided, by progressively accumulating +# options in "$@", and eventually passing that to Java. +# +# Where the inherited environment variables (DEFAULT_JVM_OPTS, JAVA_OPTS, +# and GRADLE_OPTS) rely on word-splitting, this is performed explicitly; +# see the in-line comments for details. +# +# There are tweaks for specific operating systems such as AIX, CygWin, +# Darwin, MinGW, and NonStop. +# +# (3) This script is generated from the Groovy template +# https://github.com/gradle/gradle/blob/HEAD/subprojects/plugins/src/main/resources/org/gradle/api/internal/plugins/unixStartScript.txt +# within the Gradle project. +# +# You can find Gradle at https://github.com/gradle/gradle/. +# +############################################################################## + +# Attempt to set APP_HOME + +# Resolve links: $0 may be a link +app_path=$0 + +# Need this for daisy-chained symlinks. +while + APP_HOME=${app_path%"${app_path##*/}"} # leaves a trailing /; empty if no leading path + [ -h "$app_path" ] +do + ls=$( ls -ld "$app_path" ) + link=${ls#*' -> '} + case $link in #( + /*) app_path=$link ;; #( + *) app_path=$APP_HOME$link ;; + esac +done + +# This is normally unused +# shellcheck disable=SC2034 +APP_BASE_NAME=${0##*/} +APP_HOME=$( cd "${APP_HOME:-./}" && pwd -P ) || exit + +# Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +DEFAULT_JVM_OPTS='"-Xmx64m" "-Xms64m"' + +# Use the maximum available, or set MAX_FD != -1 to use that value. +MAX_FD=maximum + +warn () { + echo "$*" +} >&2 + +die () { + echo + echo "$*" + echo + exit 1 +} >&2 + +# OS specific support (must be 'true' or 'false'). +cygwin=false +msys=false +darwin=false +nonstop=false +case "$( uname )" in #( + CYGWIN* ) cygwin=true ;; #( + Darwin* ) darwin=true ;; #( + MSYS* | MINGW* ) msys=true ;; #( + NONSTOP* ) nonstop=true ;; +esac + +CLASSPATH=$APP_HOME/gradle/wrapper/gradle-wrapper.jar + + +# Determine the Java command to use to start the JVM. +if [ -n "$JAVA_HOME" ] ; then + if [ -x "$JAVA_HOME/jre/sh/java" ] ; then + # IBM's JDK on AIX uses strange locations for the executables + JAVACMD=$JAVA_HOME/jre/sh/java + else + JAVACMD=$JAVA_HOME/bin/java + fi + if [ ! -x "$JAVACMD" ] ; then + die "ERROR: JAVA_HOME is set to an invalid directory: $JAVA_HOME + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." + fi +else + JAVACMD=java + which java >/dev/null 2>&1 || die "ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. + +Please set the JAVA_HOME variable in your environment to match the +location of your Java installation." +fi + +# Increase the maximum file descriptors if we can. +if ! "$cygwin" && ! "$darwin" && ! "$nonstop" ; then + case $MAX_FD in #( + max*) + # In POSIX sh, ulimit -H is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + MAX_FD=$( ulimit -H -n ) || + warn "Could not query maximum file descriptor limit" + esac + case $MAX_FD in #( + '' | soft) :;; #( + *) + # In POSIX sh, ulimit -n is undefined. That's why the result is checked to see if it worked. + # shellcheck disable=SC3045 + ulimit -n "$MAX_FD" || + warn "Could not set maximum file descriptor limit to $MAX_FD" + esac +fi + +# Collect all arguments for the java command, stacking in reverse order: +# * args from the command line +# * the main class name +# * -classpath +# * -D...appname settings +# * --module-path (only if needed) +# * DEFAULT_JVM_OPTS, JAVA_OPTS, and GRADLE_OPTS environment variables. + +# For Cygwin or MSYS, switch paths to Windows format before running java +if "$cygwin" || "$msys" ; then + APP_HOME=$( cygpath --path --mixed "$APP_HOME" ) + CLASSPATH=$( cygpath --path --mixed "$CLASSPATH" ) + + JAVACMD=$( cygpath --unix "$JAVACMD" ) + + # Now convert the arguments - kludge to limit ourselves to /bin/sh + for arg do + if + case $arg in #( + -*) false ;; # don't mess with options #( + /?*) t=${arg#/} t=/${t%%/*} # looks like a POSIX filepath + [ -e "$t" ] ;; #( + *) false ;; + esac + then + arg=$( cygpath --path --ignore --mixed "$arg" ) + fi + # Roll the args list around exactly as many times as the number of + # args, so each arg winds up back in the position where it started, but + # possibly modified. + # + # NB: a `for` loop captures its iteration list before it begins, so + # changing the positional parameters here affects neither the number of + # iterations, nor the values presented in `arg`. + shift # remove old arg + set -- "$@" "$arg" # push replacement arg + done +fi + +# Collect all arguments for the java command; +# * $DEFAULT_JVM_OPTS, $JAVA_OPTS, and $GRADLE_OPTS can contain fragments of +# shell script including quotes and variable substitutions, so put them in +# double quotes to make sure that they get re-expanded; and +# * put everything else in single quotes, so that it's not re-expanded. + +set -- \ + "-Dorg.gradle.appname=$APP_BASE_NAME" \ + -classpath "$CLASSPATH" \ + org.gradle.wrapper.GradleWrapperMain \ + "$@" + +# Stop when "xargs" is not available. +if ! command -v xargs >/dev/null 2>&1 +then + die "xargs is not available" +fi + +# Use "xargs" to parse quoted args. +# +# With -n1 it outputs one arg per line, with the quotes and backslashes removed. +# +# In Bash we could simply go: +# +# readarray ARGS < <( xargs -n1 <<<"$var" ) && +# set -- "${ARGS[@]}" "$@" +# +# but POSIX shell has neither arrays nor command substitution, so instead we +# post-process each arg (as a line of input to sed) to backslash-escape any +# character that might be a shell metacharacter, then use eval to reverse +# that process (while maintaining the separation between arguments), and wrap +# the whole thing up as a single "set" statement. +# +# This will of course break if any of these variables contains a newline or +# an unmatched quote. +# + +eval "set -- $( + printf '%s\n' "$DEFAULT_JVM_OPTS $JAVA_OPTS $GRADLE_OPTS" | + xargs -n1 | + sed ' s~[^-[:alnum:]+,./:=@_]~\\&~g; ' | + tr '\n' ' ' + )" '"$@"' + +exec "$JAVACMD" "$@" diff --git a/1.20/gradlew.bat b/1.20/gradlew.bat new file mode 100644 index 0000000..93e3f59 --- /dev/null +++ b/1.20/gradlew.bat @@ -0,0 +1,92 @@ +@rem +@rem Copyright 2015 the original author or authors. +@rem +@rem Licensed under the Apache License, Version 2.0 (the "License"); +@rem you may not use this file except in compliance with the License. +@rem You may obtain a copy of the License at +@rem +@rem https://www.apache.org/licenses/LICENSE-2.0 +@rem +@rem Unless required by applicable law or agreed to in writing, software +@rem distributed under the License is distributed on an "AS IS" BASIS, +@rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. +@rem See the License for the specific language governing permissions and +@rem limitations under the License. +@rem + +@if "%DEBUG%"=="" @echo off +@rem ########################################################################## +@rem +@rem Gradle startup script for Windows +@rem +@rem ########################################################################## + +@rem Set local scope for the variables with windows NT shell +if "%OS%"=="Windows_NT" setlocal + +set DIRNAME=%~dp0 +if "%DIRNAME%"=="" set DIRNAME=. +@rem This is normally unused +set APP_BASE_NAME=%~n0 +set APP_HOME=%DIRNAME% + +@rem Resolve any "." and ".." in APP_HOME to make it shorter. +for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi + +@rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script. +set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m" + +@rem Find java.exe +if defined JAVA_HOME goto findJavaFromJavaHome + +set JAVA_EXE=java.exe +%JAVA_EXE% -version >NUL 2>&1 +if %ERRORLEVEL% equ 0 goto execute + +echo. +echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:findJavaFromJavaHome +set JAVA_HOME=%JAVA_HOME:"=% +set JAVA_EXE=%JAVA_HOME%/bin/java.exe + +if exist "%JAVA_EXE%" goto execute + +echo. +echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% +echo. +echo Please set the JAVA_HOME variable in your environment to match the +echo location of your Java installation. + +goto fail + +:execute +@rem Setup the command line + +set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar + + +@rem Execute Gradle +"%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %* + +:end +@rem End local scope for the variables with windows NT shell +if %ERRORLEVEL% equ 0 goto mainEnd + +:fail +rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of +rem the _cmd.exe /c_ return code! +set EXIT_CODE=%ERRORLEVEL% +if %EXIT_CODE% equ 0 set EXIT_CODE=1 +if not ""=="%GRADLE_EXIT_CONSOLE%" exit %EXIT_CODE% +exit /b %EXIT_CODE% + +:mainEnd +if "%OS%"=="Windows_NT" endlocal + +:omega diff --git a/1.20/settings.gradle b/1.20/settings.gradle new file mode 100644 index 0000000..697dd5f --- /dev/null +++ b/1.20/settings.gradle @@ -0,0 +1,38 @@ +pluginManagement { + repositories { + gradlePluginPortal() + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + maven { + name = 'Sponge' + url = 'https://repo.spongepowered.org/repository/maven-public/' + } + maven { + name = 'Quilt' + url = 'https://maven.quiltmc.org/repository/release' + } + maven { + name = 'Minecraft Forge' + url = 'https://maven.minecraftforge.net/' + } + } +} + +dependencyResolutionManagement { + repositories { + maven { + name = "Fuzs Mod Resources" + url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" + } + } + versionCatalogs { + libs { + from("fuzs.sharedcatalogs:sharedcatalogs:${dependenciesVersionCatalog}") + } + } +} + +rootProject.name = "${modName.replaceAll("[^a-zA-Z]", "")}-${dependenciesVersionCatalog.replaceAll("-v\\d+", "")}" +include("Common", "Fabric", "Forge") diff --git a/Common/build.gradle b/Common/build.gradle deleted file mode 100644 index 1b574a0..0000000 --- a/Common/build.gradle +++ /dev/null @@ -1,126 +0,0 @@ -apply plugin: 'fabric-loom' -apply plugin: 'io.github.juuxel.loom-quiltflower' - -archivesBaseName = rootProject.name -version = "v${modVersion}-${libs.versions.minecraft.get()}-Common" -group = modMavenGroup - -dependencies { - minecraft "com.mojang:minecraft:${libs.versions.minecraft.get()}" - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${libs.versions.parchmentMinecraft.get()}:${libs.versions.parchment.get()}@zip") - } - - // Puzzles Lib - modApi ("fuzs.puzzleslib:puzzleslib-common:${libs.versions.puzzles.get()}") -} - -loom { - mixin { - // not sure if this is necessary for common... - defaultRefmapName = "${modId}.refmap.json" - // fix for java.lang.NoClassDefFoundError: org/objectweb/asm/tree/MethodNode - useLegacyMixinAp = false - } - - // this should hopeful prevent an empty run directory being generated in common during initial project setup - runs { - client { - client() - setConfigName("Common Client") - ideConfigGenerated(false) - runDir("../run") - } - server { - server() - setConfigName("Common Server") - ideConfigGenerated(false) - runDir("../run") - } - } -} - -processResources { - duplicatesStrategy DuplicatesStrategy.INCLUDE - - // this will ensure that this task is redone when a value changes - inputs.property "modDescription", modDescription - inputs.property "resourcePackFormat", libs.versions.resources.get() - inputs.property "dataPackFormat", libs.versions.data.get() - - // replace stuff in pack.mcmeta - filesMatching('pack.mcmeta') { - expand( - 'modDescription': modDescription, - "resourcePackFormat": libs.versions.resources.get(), - "dataPackFormat": libs.versions.data.get() - ) - } -} - -publishing { - publications { - mavenJava(MavenPublication) { - artifactId = "${modId}-common" - version = modVersion - from components.java - pom { - name = "${modName} [Common]" - description = "${modDescription}" - url = "${modSourceUrl}" - scm { - url = "${modSourceUrl}" - connection = "${modSourceUrl}".replace("https", "scm:git:git").concat(".git") - developerConnection = "${modSourceUrl}".replace("https://github.com/", "scm:git:git@github.com:").concat(".git") - } - issueManagement { - system = 'github' - url = "${modIssueUrl}" - } - licenses { - license { - name = "${modLicense}" - url = "https://spdx.org/licenses/${modLicense}.html" - } - } - developers { - developer { - id = "${modAuthor}".toLowerCase() - name = "${modAuthor}" - } - } - } - } - } - repositories { - maven { - name = 'FuzsModResources' - url "file://" + project.hasProperty('modResources') ? "${project.findProperty('modResources')}/maven" : System.getenv('local_maven') - } - } -} - -signing { - sign publishing.publications.mavenJava -} - -import net.fabricmc.loom.task.AbstractRemapJarTask - -// thanks to lukebemish for this comment: https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 -tasks.withType(AbstractRemapJarTask).each { - it.targetNamespace = "named" -} - -task copyJarToDir(type: Copy) { - onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } - if (project.findProperty('copyBuildJar').toBoolean()) { - from remapJar - into project.findProperty('buildJarOutputDir') - // add build number to be able to distinguish jars when testing thorough official launcher - // build number is stored in global gradle.properties - rename { fileName -> fileName.replace("v${modVersion}", "v${modVersion}.${uniqueBuildNumber}") } - } -} - -build.finalizedBy project.tasks.copyJarToDir, rootProject.tasks.incrementBuildNumber diff --git a/Fabric/build.gradle b/Fabric/build.gradle deleted file mode 100644 index 356bbf5..0000000 --- a/Fabric/build.gradle +++ /dev/null @@ -1,266 +0,0 @@ -apply plugin: 'fabric-loom' -apply plugin: 'io.github.juuxel.loom-quiltflower' -apply plugin: 'me.hypherionmc.cursegradle' -apply plugin: 'com.modrinth.minotaur' - -archivesBaseName = rootProject.name -version = "v${modVersion}-${libs.versions.minecraft.get()}-Fabric" -group = modMavenGroup - -repositories { - maven { - name = "Modmuss" - url = "https://maven.modmuss50.me/" - } - maven { - name = "ladysnake" - url = 'https://ladysnake.jfrog.io/artifactory/mods' - } - maven { - name = "jamieswhiteshirt" - url = "https://maven.jamieswhiteshirt.com/libs-release/" - } -} - -dependencies { - // Common Project - compileOnly(project(path: ":Common", configuration: "namedElements")) { - transitive = false - } - - // Minecraft - minecraft "com.mojang:minecraft:${libs.versions.minecraft.get()}" - mappings loom.layered() { - officialMojangMappings() - parchment("org.parchmentmc.data:parchment-${libs.versions.parchmentMinecraft.get()}:${libs.versions.parchment.get()}@zip") - } - - // Fabric - modApi "net.fabricmc:fabric-loader:${libs.versions.fabric.get()}" - modApi "net.fabricmc.fabric-api:fabric-api:${libs.versions.fabricApi.get()}" - - // Cardinal Components -// modApi(include("dev.onyxstudios.cardinal-components-api:cardinal-components-base:${libs.versions.cardinalcomponents.get()}")) -// modApi(include("dev.onyxstudios.cardinal-components-api:cardinal-components-entity:${libs.versions.cardinalcomponents.get()}")) - - // Quality of Life Mods - modLocalRuntime "com.terraformersmc:modmenu:${libs.versions.modmenu.get()}" - modLocalRuntime "fuzs.forgeconfigscreens:forgeconfigscreens-fabric:${libs.versions.forgeconfigscreens.get()}" - - // Puzzles Lib - modApi "fuzs.puzzleslib:puzzleslib-fabric:${libs.versions.puzzles.get()}" -} - -loom { - mixin.defaultRefmapName = "${modId}.refmap.json" - - runs { - client { - client() - setConfigName("Fabric Client") - ideConfigGenerated(true) - runDir("../run") - vmArg '-Dmixin.debug.export=true' - } - server { - server() - setConfigName("Fabric Server") - ideConfigGenerated(true) - runDir("../run") - vmArg '-Dmixin.debug.export=true' - } - } -} - -processResources { - from(project(":Common").sourceSets.main.resources) - from(project(":Forge").file('src/generated/resources')) { - exclude('.cache/') - } - // Forge's data gen doesn't work with assets placed in the common project, so we place them in Forge and include them here - from(project(":Forge").sourceSets.main.resources) { - include("assets/") - include("data/") - } - - duplicatesStrategy DuplicatesStrategy.INCLUDE - - // this will ensure that this task is redone when a value changes - inputs.property "modId", modId - inputs.property "modName", modName - inputs.property "modVersion", modVersion - inputs.property "modDescription", modDescription - inputs.property "modGroup", project.group - inputs.property "modPageUrl", modSourceUrl - inputs.property "modIssueUrl", modIssueUrl - inputs.property "modAuthor", modAuthor - inputs.property "modLicense", modLicense - inputs.property "minFabricVersion", libs.versions.minFabric.get() - inputs.property "minFabricApiVersion", libs.versions.minFabricApi.get() - inputs.property "minecraftVersion", libs.versions.minecraft.get() - inputs.property "minPuzzlesVersion", libs.versions.minPuzzles.get() - inputs.property "resourcePackFormat", libs.versions.resources.get() - inputs.property "dataPackFormat", libs.versions.data.get() - inputs.property "mainEntryPoint", "${project.group}.${rootProject.name}Fabric" - inputs.property "clientEntryPoint", "${project.group}.client.${rootProject.name}FabricClient" - inputs.property "modFabricEnvironment", modFabricEnvironment - - // replace stuff in fabric.mod.json - filesMatching('fabric.mod.json') { - expand( - 'modId': modId, - 'modName': modName, - 'modVersion': modVersion, - 'modDescription': modDescription, - 'modGroup': project.group, - 'modPageUrl': modSourceUrl, - 'modIssueUrl': modIssueUrl, - 'modAuthor': modAuthor, - 'modLicense': modLicense, - 'minFabricVersion': libs.versions.minFabric.get(), - 'minFabricApiVersion': libs.versions.minFabricApi.get(), - 'minecraftVersion': libs.versions.minecraft.get(), - "minPuzzlesVersion": libs.versions.minPuzzles.get(), - "mainEntryPoint": "${project.group}.${rootProject.name}Fabric", - "clientEntryPoint": "${project.group}.client.${rootProject.name}FabricClient", - "modFabricEnvironment": modFabricEnvironment - ) - } - - // replace stuff in pack.mcmeta - filesMatching('pack.mcmeta') { - expand( - 'modDescription': modDescription, - "resourcePackFormat": libs.versions.resources.get(), - "dataPackFormat": libs.versions.data.get() - ) - } -} - -compileJava { - source project(":Common").sourceSets.main.allSource -} - -sourcesJar { - from project(":Common").sourceSets.main.allJava -} - -javadoc { - source project(":Common").sourceSets.main.allJava -} - -publishing { - publications { - mavenJava(MavenPublication) { - artifactId = "${modId}-fabric" - version = modVersion - from components.java - pom { - name = "${modName} [Fabric]" - description = "${modDescription}" - url = "${modSourceUrl}" - scm { - url = "${modSourceUrl}" - connection = "${modSourceUrl}".replace("https", "scm:git:git").concat(".git") - developerConnection = "${modSourceUrl}".replace("https://github.com/", "scm:git:git@github.com:").concat(".git") - } - issueManagement { - system = 'github' - url = "${modIssueUrl}" - } - licenses { - license { - name = "${modLicense}" - url = "https://spdx.org/licenses/${modLicense}.html" - } - } - developers { - developer { - id = "${modAuthor}".toLowerCase() - name = "${modAuthor}" - } - } - } - } - } - repositories { - maven { - name = 'FuzsModResources' - url "file://" + project.hasProperty('modResources') ? "${project.findProperty('modResources')}/maven" : System.getenv('local_maven') - } - } -} - -signing { - sign publishing.publications.mavenJava -} - -curseforge { - if (!file('../CHANGELOG.md').canRead()) { - throw new FileNotFoundException("Could not read changelog file") - } - apiKey = project.hasProperty('curseApiToken') ? project.findProperty('curseApiToken') : '' - project { - id = projectCurseId - changelogType = 'markdown' - changelog = file('../CHANGELOG.md') - releaseType = projectReleaseType - addGameVersion 'Fabric' - projectGameVersions.split(",").each { - addGameVersion it.trim() - } - mainArtifact(remapJar) { - displayName = "[FABRIC] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" - relations { - requiredDependency 'fabric-api' - requiredDependency 'forge-config-api-port-fabric' - requiredDependency 'puzzles-lib' -// embeddedLibrary 'cardinal-components' - } - } -// addArtifact sourcesJar - } - options { -// debug = true - javaVersionAutoDetect = false - forgeGradleIntegration = false - } -} - -modrinth { - if (!file('../CHANGELOG.md').canRead()) { - throw new FileNotFoundException("Could not read changelog file") - } - token = project.hasProperty('modrinthApiToken') ? project.findProperty('modrinthApiToken') : '' - projectId = projectModrinthId - versionNumber = project.version - versionName = "[FABRIC] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" - changelog = file('../CHANGELOG.md').text - versionType = projectReleaseType - uploadFile = remapJar // This is the java jar task - projectGameVersions.split(",").each { - gameVersions.add it.trim() - } - loaders.add 'fabric' -// additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") - dependencies { - required.project 'fabric-api' - required.project 'forge-config-api-port' - required.project 'puzzles-lib' -// embedded.project 'cardinal-components-api' - } -// debugMode = true -} - -task copyJarToDir(type: Copy) { - onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } - if (project.findProperty('copyBuildJar').toBoolean()) { - from remapJar - into project.findProperty('buildJarOutputDir') - // add build number to be able to distinguish jars when testing thorough official launcher - // build number is stored in global gradle.properties - rename { fileName -> fileName.replace("v${modVersion}", "v${modVersion}.${uniqueBuildNumber}") } - } -} - -build.finalizedBy project.tasks.copyJarToDir, rootProject.tasks.incrementBuildNumber diff --git a/Forge/build.gradle b/Forge/build.gradle deleted file mode 100644 index fb60176..0000000 --- a/Forge/build.gradle +++ /dev/null @@ -1,372 +0,0 @@ -plugins { - id 'net.minecraftforge.gradle' version '6.0.+' - id 'org.spongepowered.mixin' version '0.7.+' - id 'org.parchmentmc.librarian.forgegradle' version '1.+' -} - -apply plugin: 'me.hypherionmc.cursegradle' -apply plugin: 'com.modrinth.minotaur' - -archivesBaseName = rootProject.name -version = "v${modVersion}-${libs.versions.minecraft.get()}-Forge" -group = modMavenGroup - -minecraft { -// mappings channel: 'parchment', version: "${parchmentMappingsVersion}-${parchmentMinecraftVersion}" - mappings channel: 'official', version: "${libs.versions.minecraft.get()}" - - runs { - client { - workingDirectory project.file('../run') - jvmArgs '-Xms1G', '-Xmx4G' - property 'fml.earlyprogresswindow', 'false' - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - arg "-mixin.config=${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - arg "-mixin.config=${modId}.forge.mixins.json" - } - ideaModule "${rootProject.name}.${project.name}.main" - taskName 'Client' - property 'terminal.ansi', 'true' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'mixin.debug.export', 'true' - mods { - modClientRun { - source sourceSets.main - source project(":Common").sourceSets.main - } - } - } - - server { - workingDirectory project.file('../run') - jvmArgs '-Xms1G', '-Xmx4G' - arg 'nogui' - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - arg "-mixin.config=${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - arg "-mixin.config=${modId}.forge.mixins.json" - } - ideaModule "${rootProject.name}.${project.name}.main" - taskName 'Server' - property 'terminal.ansi', 'true' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'mixin.debug.export', 'true' - mods { - modServerRun { - source sourceSets.main - source project(":Common").sourceSets.main - } - } - } - - data { - workingDirectory project.file('../run') - jvmArgs '-Xms1G', '-Xmx4G' - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - arg "-mixin.config=${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - arg "-mixin.config=${modId}.forge.mixins.json" - } - args '--mod', modId, '--all', '--output', file('src/generated/resources/'), '--existing', file('src/main/resources/') - ideaModule "${rootProject.name}.${project.name}.main" - taskName 'Data' - property 'terminal.ansi', 'true' - property 'mixin.env.remapRefMap', 'true' - property 'mixin.env.refMapRemappingFile', "${projectDir}/build/createSrgToMcp/output.srg" - property 'mixin.debug.export', 'true' - mods { - modDataRun { - source sourceSets.main - source project(":Common").sourceSets.main - } - } - } - } -} - -dependencies { - // Common Project - compileOnly(project(":Common")) { - transitive = false - } - - // Minecraft - minecraft "net.minecraftforge:forge:${libs.versions.forge.get()}" - annotationProcessor 'org.spongepowered:mixin:0.8.5:processor' - - // Quality of Life Mods - runtimeOnly fg.deobf("fuzs.bettermodsbutton:bettermodsbutton-forge:${libs.versions.bettermodsbutton.get()}") - runtimeOnly fg.deobf("fuzs.forgeconfigscreens:forgeconfigscreens-forge:${libs.versions.forgeconfigscreens.get()}") - - // Puzzles Lib - api fg.deobf("fuzs.puzzleslib:puzzleslib-forge:${libs.versions.puzzles.get()}") -} - -mixin { - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists() || project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - add project(":Common").sourceSets.main, "${modId}.refmap.json" - } - if (project(":Common").file("src/main/resources/${modId}.common.mixins.json").exists()) { - config "${modId}.common.mixins.json" - } - if (project.file("src/main/resources/${modId}.forge.mixins.json").exists()) { - config "${modId}.forge.mixins.json" - } -} - -processResources { - from(project(":Common").sourceSets.main.resources) - from(file('src/generated/resources')) { - exclude('.cache/') - } - - duplicatesStrategy DuplicatesStrategy.INCLUDE - - // this will ensure that this task is redone when a value changes - inputs.property "modId", modId - inputs.property "modName", modName - inputs.property "modVersion", modVersion - inputs.property "modDescription", modDescription - inputs.property "modGroup", project.group - inputs.property "modPageUrl", modSourceUrl - inputs.property "modUpdateUrl", modUpdateUrl - inputs.property "modIssueUrl", modIssueUrl - inputs.property "modAuthor", modAuthor - inputs.property "modLicense", modLicense - inputs.property "minFMLVersion", libs.versions.minForge.get().replaceAll("\\..*", "") - inputs.property "minForgeVersion", libs.versions.minForge.get() - inputs.property "minecraftVersion", libs.versions.minecraft.get() - inputs.property "minPuzzlesVersion", libs.versions.minPuzzles.get() - inputs.property "resourcePackFormat", libs.versions.resources.get() - inputs.property "dataPackFormat", libs.versions.data.get() - inputs.property "modForgeDisplayTest", modForgeDisplayTest - - // replace stuff in mods.toml - filesMatching('META-INF/mods.toml') { - expand( - 'modId': modId, - 'modName': modName, - 'modVersion': modVersion, - 'modDescription': modDescription, - 'modGroup': project.group, - 'modPageUrl': modSourceUrl, - 'modUpdateUrl': modUpdateUrl, - 'modIssueUrl': modIssueUrl, - 'modAuthor': modAuthor, - 'modLicense': modLicense, - 'minFMLVersion': libs.versions.minForge.get().replaceAll("\\..*", ""), - 'minForgeVersion': libs.versions.minForge.get(), - 'minecraftVersion': libs.versions.minecraft.get(), - 'minPuzzlesVersion': libs.versions.minPuzzles.get(), - 'modForgeDisplayTest': modForgeDisplayTest - ) - } - - // replace stuff in pack.mcmeta - filesMatching('pack.mcmeta') { - expand( - 'modDescription': modDescription, - "resourcePackFormat": libs.versions.resources.get(), - "dataPackFormat": libs.versions.data.get() - ) - } -} - -compileJava { - source project(":Common").sourceSets.main.allSource -} - -sourcesJar { - from project(":Common").sourceSets.main.allJava -} - -javadoc { - source project(":Common").sourceSets.main.allJava -} - -// important: the task may not run before 'compileJava', otherwise overridden/shadowed fields and methods in mixin classes will not be reobfuscated -jar.finalizedBy("configureReobfTaskForReobfJar") -jar.finalizedBy('reobfJar') - -publishing { - publications { - mavenJava(MavenPublication) { - artifactId = "${modId}-forge" - version = modVersion - from components.java - // strip Forge dependency from POM - fg.component(it) - pom { - name = "${modName} [Forge]" - description = "${modDescription}" - url = "${modSourceUrl}" - scm { - url = "${modSourceUrl}" - connection = "${modSourceUrl}".replace("https", "scm:git:git").concat(".git") - developerConnection = "${modSourceUrl}".replace("https://github.com/", "scm:git:git@github.com:").concat(".git") - } - issueManagement { - system = 'github' - url = "${modIssueUrl}" - } - licenses { - license { - name = "${modLicense}" - url = "https://spdx.org/licenses/${modLicense}.html" - } - } - developers { - developer { - id = "${modAuthor}".toLowerCase() - name = "${modAuthor}" - } - } - } - afterEvaluate { - // exclude certain dependencies when publishing to maven - // from https://stackoverflow.com/a/50121790 - pom.withXml { - asNode().dependencies.dependency.each { dep -> - // use this approach to make excluding dependencies from Curse Maven more convenient - if (["curse.maven:", "fuzs.bettermodsbutton:bettermodsbutton-forge"].stream().anyMatch(mod -> "${dep.groupId.last().value().last()}:${dep.artifactId.last().value().last()}".startsWith(mod))) { - assert dep.parent().remove(dep) - } - } - } - } - } - } - repositories { - maven { - name = 'FuzsModResources' - url "file://" + project.hasProperty('modResources') ? "${project.findProperty('modResources')}/maven" : System.getenv('local_maven') - } - } -} - -signing { - sign publishing.publications.mavenJava -} - -task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: jar) { - onlyIf { project.hasProperty('keyStore') } - keyStore = project.findProperty('keyStore') - alias = project.findProperty('keyStoreAlias') - storePass = project.findProperty('keyStorePass') - keyPass = project.findProperty('keyStoreKeyPass') - inputFile = outputFile = jar.archivePath -} - -jar.finalizedBy 'signJar' -signJar.mustRunAfter 'reobfJar' - -curseforge { - if (!file('../CHANGELOG.md').canRead()) { - throw new FileNotFoundException("Could not read changelog file") - } - apiKey = project.hasProperty('curseApiToken') ? project.findProperty('curseApiToken') : '' - project { - id = projectCurseId - changelogType = 'markdown' - changelog = file('../CHANGELOG.md') - releaseType = projectReleaseType - addGameVersion 'Forge' - projectGameVersions.split(",").each { - addGameVersion it.trim() - } - mainArtifact(jar) { - displayName = "[FORGE] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" - relations { - requiredDependency 'puzzles-lib' - } - } -// addArtifact sourcesJar - } - options { -// debug = true - javaVersionAutoDetect = false - forgeGradleIntegration = false - } -} - -modrinth { - if (!file('../CHANGELOG.md').canRead()) { - throw new FileNotFoundException("Could not read changelog file") - } - token = project.hasProperty('modrinthApiToken') ? project.findProperty('modrinthApiToken') : '' - projectId = projectModrinthId - versionNumber = project.version - versionName = "[FORGE] [${libs.versions.minecraft.get()}] ${rootProject.name}-v${modVersion}" - changelog = file('../CHANGELOG.md').text - versionType = projectReleaseType - uploadFile = jar // This is the java jar task - projectGameVersions.split(",").each { - gameVersions.add it.trim() - } - loaders.add 'forge' -// additionalFiles.add file("${project.buildDir}/libs/${project.archivesBaseName}-${project.version}-sources.jar") - dependencies { - required.project 'puzzles-lib' - } -// debugMode = true -} - - -import groovy.json.JsonBuilder -import groovy.json.JsonOutput -import groovy.json.JsonSlurper - -task copyJarToDir(type: Copy) { - onlyIf { project.hasProperty('buildJarOutputDir') && project.hasProperty('uniqueBuildNumber') } - if (project.findProperty('copyBuildJar').toBoolean()) { - // shortcut for jar.outputs.files - from jar - into project.findProperty('buildJarOutputDir') - // add build number to be able to distinguish jars when testing thorough official launcher - // build number is stored in global gradle.properties - rename { fileName -> fileName.replace("v${modVersion}", "v${modVersion}.${uniqueBuildNumber}") } - } -} - -task refreshUpdateJson { - onlyIf { project.hasProperty('modResources') } - doLast { - def updateFile = file(project.findProperty('modResources').concat(File.separator).concat('update').concat(File.separator).concat("${modId}").concat('.json')) - def updateJson - if (updateFile.exists() && updateFile.canRead()) { - updateJson = new JsonSlurper().parseText(updateFile.text) - "${projectGameVersions}".replaceAll(" ", "").split(",").each { version -> - updateJson['promos']["${version}-latest"] = "${modVersion}" - // alpha and beta releases will contain 'a' or 'b' char respectively, don't update recommended for those - if ("${modVersion}".matches("[^a-zA-Z]+")) { - updateJson['promos']["${version}-recommended"] = "${modVersion}" - } - } - } else { - def builder = new JsonBuilder() - updateJson = builder { - homepage "${modSourceUrl}" - promos { - "${projectGameVersions}".replaceAll(" ", "").split(",").each { version -> - "${version}-latest" "${modVersion}" - // alpha and beta releases will contain 'a' or 'b' char respectively, don't update recommended for those - if ("${modVersion}".matches("[^a-zA-Z]+")) { - "${version}-recommended" "${modVersion}" - } - } - } - } - } - def output = new JsonOutput() - updateFile.write(output.prettyPrint(output.toJson(updateJson))) - } -} - -build.finalizedBy project.tasks.copyJarToDir, rootProject.tasks.incrementBuildNumber -[tasks.modrinth, tasks.curseforge].each { it.finalizedBy project.tasks.refreshUpdateJson } diff --git a/build.gradle b/build.gradle deleted file mode 100644 index bffa446..0000000 --- a/build.gradle +++ /dev/null @@ -1,147 +0,0 @@ -plugins { - id 'fabric-loom' version '1.2.+' apply false - id 'io.github.juuxel.loom-quiltflower' version '1.+' apply false - id 'me.hypherionmc.cursegradle' version '2.+' apply false - id 'com.modrinth.minotaur' version '2.+' apply false -} - -apply from: './gradle/tasks.gradle' - -subprojects { - apply plugin: 'java' - apply plugin: 'java-library' - apply plugin: 'maven-publish' - apply plugin: 'signing' - apply plugin: 'idea' - - java.toolchain.languageVersion = JavaLanguageVersion.of(17) - java.withSourcesJar() - java.withJavadocJar() - // silence missing javadoc comments, we just don't care - javadoc.options.addStringOption('Xdoclint:none', '-quiet') - - repositories { - mavenCentral() - mavenLocal() - maven { - name = 'Sponge' - url = 'https://repo.spongepowered.org/repository/maven-public/' - } - maven { - name = 'Jared' - url = 'https://maven.blamejared.com/' - } - maven { - name = 'Jitpack' - url = 'https://jitpack.io' - } - maven { - name = 'Shedaniel' - url = 'https://maven.shedaniel.me/' - } - maven { - name = 'Parchment' - url = 'https://maven.parchmentmc.org' - } - exclusiveContent { - forRepository { - maven { - name = "CurseForge" - url = "https://cursemaven.com" - } - } - filter { - includeGroup "curse.maven" - } - } - exclusiveContent { - forRepository { - maven { - name = "Modrinth" - url = "https://api.modrinth.com/maven" - } - } - filter { - includeGroup "maven.modrinth" - } - } - maven { - name = "Fuzs Mod Resources" - url = "https://raw.githubusercontent.com/Fuzss/modresources/main/maven/" - } - maven { - name = 'Terraformers' - url = "https://maven.terraformersmc.com/" - } - maven { - name = "ModMaven" - url = "https://modmaven.dev" - } - maven { - name = "AppleSkin" - url "https://maven.ryanliptak.com/" - } - flatDir { - dirs 'libs' - } - } - - tasks.withType(JavaCompile).configureEach { - // ensure that the encoding is set to UTF-8, no matter what the system default is - // this fixes some edge cases with special characters not displaying correctly - // see http://yodaconditions.net/blog/fix-for-java-file-encoding-problems-with-gradle.html - // If Javadoc is generated, this must be specified in that task too. - options.encoding = 'UTF-8' - options.release = 17 - } - - tasks.withType(Jar).configureEach { - from rootProject.file("LICENSE.md") - from rootProject.file("LICENSE-ASSETS.md") - from rootProject.file("CHANGELOG.md") - manifest { - attributes([ - "Specification-Title" : modName, - 'Specification-Version' : modVersion, - "Specification-Vendor" : modAuthor, - 'Implementation-Title' : modName, - 'Implementation-Version' : modVersion, - 'Implementation-Vendor' : modAuthor, - 'Implementation-Timestamp' : new Date().format("yyyy-MM-dd'T'HH:mm:ssZ"), - 'Implementation-Timestamp-Milli': System.currentTimeMillis(), - 'Implementation-URL' : modSourceUrl, - 'Built-On-Java' : "${System.getProperty('java.vm.version')} (${System.getProperty('java.vm.vendor')})", - 'Built-On-Minecraft' : libs.versions.minecraft.get() - ]) - } - group 'jar' - } - - tasks.withType(GenerateModuleMetadata) { - // Disables Gradle's custom module metadata from being published to maven. The - // metadata includes mapped dependencies which are not reasonably consumable by - // other mod developers. - enabled = false - } -} - -import java.util.regex.Pattern - -println('Java: ' + System.getProperty('java.version') + ' JVM: ' + System.getProperty('java.vm.version') + '(' + System.getProperty('java.vendor') + ') Arch: ' + System.getProperty('os.arch')) - -task incrementBuildNumber { - onlyIf { project.hasProperty('uniqueBuildNumber') } - doLast { - def propertiesName = 'gradle.properties' - // build number is stored in global gradle.properties - def propertiesFile = new File(project.gradle.gradleUserHomeDir, propertiesName) - if (!propertiesFile.canRead()) { - throw new FileNotFoundException("Could not read file ".concat(propertiesName)) - } - def buildNumberMatcher = Pattern.compile("uniqueBuildNumber=(\\d+)").matcher(propertiesFile.getText()) - buildNumberMatcher.find() - def versionCode = Integer.parseInt(buildNumberMatcher.group(1)) - def propertiesContent = buildNumberMatcher.replaceAll("uniqueBuildNumber=" + ++versionCode) - propertiesFile.write(propertiesContent) - } -} diff --git a/gradle/libs.versions.toml b/gradle/libs.versions.toml deleted file mode 100644 index 7b68bce..0000000 --- a/gradle/libs.versions.toml +++ /dev/null @@ -1,25 +0,0 @@ -[versions] -minecraft = "1.20" -parchment = "2023.03.12" -parchmentMinecraft = "1.19.3" -puzzles = "7.0.2" -minPuzzles = "7.0.2" -resources = "15" -data = "15" - -# Forge -forge = "1.20-46.0.10" -minForge = "46.0.0" - -# Fabric -fabric = "0.14.21" -minFabric = "0.14.21" -fabricApi = "0.83.0+1.20" -minFabricApi = "0.83.0" - -# Mods -modmenu = "7.0.1" -bettermodsbutton = "7.0.0" -forgeconfigscreens = "7.0.0" -cardinalcomponents = "5.2.0" -forgeconfigapiport = "7.0.0" diff --git a/gradle/tasks.gradle b/gradle/tasks.gradle deleted file mode 100644 index 766f674..0000000 --- a/gradle/tasks.gradle +++ /dev/null @@ -1,246 +0,0 @@ -task commonClean(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean' - ] -} - -task forgeClean(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean' - ] -} - -task fabricClean(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean' - ] -} - -task allClean(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean' - ] -} - -task forgeBuild(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:build' - ] -} - -task fabricBuild(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:build' - ] -} - -task allBuild(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Common:build', - ':Forge:build', - ':Fabric:build' - ] -} - -task commonPublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Common:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task forgePublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task fabricPublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task allPublish(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Common:publishMavenJavaPublicationToFuzsModResourcesRepository', - ':Forge:publishMavenJavaPublicationToFuzsModResourcesRepository', - ':Fabric:publishMavenJavaPublicationToFuzsModResourcesRepository' - ] -} - -task forgeUploadCurseForge(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:curseforge' - ] -} - -task fabricUploadCurseForge(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:curseforge' - ] -} - -task allUploadCurseForge(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Forge:curseforge', - ':Fabric:curseforge' - ] -} - -task forgeUploadModrinth(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:modrinth' - ] -} - -task fabricUploadModrinth(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:modrinth' - ] -} - -task allUploadModrinth(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Forge:modrinth', - ':Fabric:modrinth' - ] -} - -task forgeUploadEverywhere(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Forge:curseforge', - ':Forge:modrinth' - ] -} - -task fabricUploadEverywhere(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Fabric:clean', - ':Fabric:curseforge', - ':Fabric:modrinth' - ] -} - -task allUploadEverywhere(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:clean', - ':Forge:clean', - ':Fabric:clean', - ':Forge:curseforge', - ':Forge:modrinth', - ':Fabric:curseforge', - ':Fabric:modrinth' - ] -} - -task commonGenSources(type: GradleBuild) { - group = '_main' - tasks = [ - ':Common:genSourcesWithQuiltflower' - ] -} - -task forgeGenRuns(type: GradleBuild) { - group = '_main' - tasks = [ - ':Forge:genIntellijRuns' - ] -} - -task fabricGenSources(type: GradleBuild) { - group = '_main' - tasks = [ - ':Fabric:genSourcesWithQuiltflower' - ] -} - -task forgeClient(type: GradleBuild) { - group = '_main' - tasks = [ - ':Forge:Client' - ] -} - -task fabricClient(type: GradleBuild) { - group = '_main' - tasks = [ - ':Fabric:runClient' - ] -} - -task forgeServer(type: GradleBuild) { - group = '_main' - tasks = [ - ':Forge:Server' - ] -} - -task fabricServer(type: GradleBuild) { - group = '_main' - tasks = [ - ':Fabric:runServer' - ] -} - -task forgeData(type: GradleBuild) { - group = '_main' - tasks = [ - ':Forge:Data' - ] -} From 300cca35b52612bf53f47ee74d05e2674a995486 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Thu, 13 Jul 2023 13:55:46 +0200 Subject: [PATCH 07/24] fix mixin config plugin --- 1.20/CHANGELOG.md | 4 ++++ .../{ => fuzs/tradingpost}/mixin/ModMixinConfigPlugin.java | 2 +- 1.20/gradle.properties | 2 +- 3 files changed, 6 insertions(+), 2 deletions(-) rename 1.20/Fabric/src/main/java/{ => fuzs/tradingpost}/mixin/ModMixinConfigPlugin.java (97%) diff --git a/1.20/CHANGELOG.md b/1.20/CHANGELOG.md index c7f9a93..d0f42b1 100644 --- a/1.20/CHANGELOG.md +++ b/1.20/CHANGELOG.md @@ -3,6 +3,10 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog]. +## [v8.0.1-1.20.1] - 2023-07-13 +### Fixed +- Fixed Mixin config plugin being configured incorrectly on Fabric + ## [v8.0.0-1.20.1] - 2023-06-27 - Ported to Minecraft 1.20.1 diff --git a/1.20/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java b/1.20/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java similarity index 97% rename from 1.20/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java rename to 1.20/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java index c394fbe..343a1d3 100644 --- a/1.20/Fabric/src/main/java/mixin/ModMixinConfigPlugin.java +++ b/1.20/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java @@ -1,4 +1,4 @@ -package mixin; +package fuzs.tradingpost.mixin; import net.fabricmc.loader.api.FabricLoader; import org.objectweb.asm.tree.ClassNode; diff --git a/1.20/gradle.properties b/1.20/gradle.properties index 1828641..75109d0 100755 --- a/1.20/gradle.properties +++ b/1.20/gradle.properties @@ -8,7 +8,7 @@ copyBuildJar=true # Mod Attributes modId=tradingpost modName=Trading Post -modVersion=8.0.0 +modVersion=8.0.1 modAuthor=Fuzs modDescription=Rule the village! Trade with every villager at once! modLicense=MPL-2.0 From cf4fb39b4cf25681d70d2251e180a28c74c8c423 Mon Sep 17 00:00:00 2001 From: Fuzss <28218241+Fuzss@users.noreply.github.com> Date: Wed, 24 Jan 2024 21:04:06 +0100 Subject: [PATCH 08/24] prepare 1.20.4 port --- .github/ISSUE_TEMPLATE/bug.yml | 46 ++- .github/ISSUE_TEMPLATE/config.yml | 4 +- .github/ISSUE_TEMPLATE/crash.yml | 44 +- .github/ISSUE_TEMPLATE/suggestion.yml | 36 +- .idea/gradle.xml | 44 -- .../.idea}/scopes/Fabric_sources.xml | 0 .../.idea}/scopes/Forge_sources.xml | 0 {1.18 => 1.18.2}/CHANGELOG.md | 0 {1.18 => 1.18.2}/Common/build.gradle | 0 .../main/java/fuzs/examplemod/ExampleMod.java | 0 .../examplemod/client/ExampleModClient.java | 0 .../resources/examplemod.common.mixins.json | 0 .../Common/src/main/resources/mod_banner.png | Bin .../Common/src/main/resources/mod_logo.png | Bin .../Common/src/main/resources/pack.mcmeta | 0 {1.18 => 1.18.2}/Fabric/build.gradle | 0 .../fuzs/examplemod/ExampleModFabric.java | 0 .../client/ExampleModFabricClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../resources/examplemod.fabric.mixins.json | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.18 => 1.18.2}/Forge/build.gradle | 0 .../java/fuzs/examplemod/ExampleModForge.java | 0 .../client/ExampleModForgeClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 .../resources/examplemod.forge.mixins.json | 0 {1.18 => 1.18.2}/build.gradle | 0 {1.18 => 1.18.2}/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {1.18 => 1.18.2}/gradlew | 0 {1.18 => 1.18.2}/gradlew.bat | 0 {1.18 => 1.18.2}/settings.gradle | 0 .../.idea/scopes/Fabric_sources.xml | 0 .../.idea/scopes/Forge_sources.xml | 0 {1.19 => 1.19.2}/CHANGELOG.md | 0 {1.19 => 1.19.2}/Common/build.gradle | 0 .../main/java/fuzs/examplemod/ExampleMod.java | 0 .../examplemod/client/ExampleModClient.java | 0 .../resources/examplemod.common.mixins.json | 0 .../Common/src/main/resources/mod_banner.png | Bin .../Common/src/main/resources/mod_logo.png | Bin .../Common/src/main/resources/pack.mcmeta | 0 {1.19 => 1.19.2}/Fabric/build.gradle | 0 .../fuzs/examplemod/ExampleModFabric.java | 0 .../client/ExampleModFabricClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../resources/examplemod.fabric.mixins.json | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.19 => 1.19.2}/Forge/build.gradle | 0 .../java/fuzs/examplemod/ExampleModForge.java | 0 .../client/ExampleModForgeClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 .../resources/examplemod.forge.mixins.json | 0 {1.19 => 1.19.2}/build.gradle | 0 {1.19 => 1.19.2}/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {1.19 => 1.19.2}/gradlew | 0 {1.19 => 1.19.2}/gradlew.bat | 0 {1.19 => 1.19.2}/settings.gradle | 0 .../.idea/scopes/Fabric_sources.xml | 0 .../.idea/scopes/Forge_sources.xml | 0 {1.20 => 1.20.1}/CHANGELOG.md | 0 {1.20 => 1.20.1}/Common/build.gradle | 0 .../java/fuzs/tradingpost/TradingPost.java | 0 .../tradingpost/client/TradingPostClient.java | 0 .../screens/inventory/TradingPostScreen.java | 0 .../blockentity/TradingPostRenderer.java | 0 .../fuzs/tradingpost/config/ServerConfig.java | 0 .../fuzs/tradingpost/init/ModRegistry.java | 0 .../mixin/accessor/MerchantMenuAccessor.java | 0 .../mixin/accessor/VillagerAccessor.java | 0 .../mixin/client/accessor/ButtonAccessor.java | 0 .../accessor/MerchantScreenAccessor.java | 0 .../accessor/TradeOfferButtonAccessor.java | 0 .../network/S2CBuildOffersMessage.java | 0 .../network/S2CMerchantDataMessage.java | 0 .../network/S2CRemoveMerchantsMessage.java | 0 .../network/client/C2SClearSlotsMessage.java | 0 .../world/entity/npc/LocalMerchant.java | 0 .../world/entity/npc/MerchantCollection.java | 0 .../world/inventory/TradingPostContainer.java | 0 .../world/inventory/TradingPostMenu.java | 0 .../world/item/trading/TradingPostOffers.java | 0 .../world/level/block/TradingPostBlock.java | 0 .../block/entity/TradingPostBlockEntity.java | 0 .../tradingpost/blockstates/trading_post.json | 0 .../assets/tradingpost/lang/en_us.json | 0 .../assets/tradingpost/lang/it_it.json | 0 .../assets/tradingpost/lang/pt_br.json | 0 .../assets/tradingpost/lang/ru_ru.json | 0 .../assets/tradingpost/lang/zh_tw.json | 0 .../models/block/trading_post.json | 0 .../tradingpost/models/item/trading_post.json | 0 .../textures/block/trading_post_bottom.png | Bin .../textures/block/trading_post_front.png | Bin .../textures/block/trading_post_side.png | Bin .../textures/block/trading_post_top.png | Bin .../textures/item/magnifying_glass.png | Bin .../minecraft/tags/blocks/mineable/axe.json | 0 .../loot_tables/blocks/trading_post.json | 0 .../tradingpost/recipes/trading_post.json | 0 .../entity_types/blacklisted_traders.json | 0 .../Common/src/main/resources/mod_banner.png | Bin .../Common/src/main/resources/mod_logo.png | Bin .../Common/src/main/resources/pack.mcmeta | 0 .../resources/tradingpost.common.mixins.json | 0 {1.20 => 1.20.1}/Fabric/build.gradle | 0 .../fuzs/tradingpost/TradingPostFabric.java | 0 .../client/TradingPostFabricClient.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../Fabric/src/main/resources/fabric.mod.json | 0 {1.20 => 1.20.1}/Forge/build.gradle | 0 .../178bb4356f8bea3c4b8966704e26df58ba8fa865 | 0 .../assets/minecraft/atlases/blocks.json | 0 .../fuzs/tradingpost/TradingPostForge.java | 0 .../client/TradingPostForgeClient.java | 0 .../data/ModSpriteSourceProvider.java | 0 .../mixin/ModMixinConfigPlugin.java | 0 .../src/main/resources/META-INF/mods.toml | 0 {1.20 => 1.20.1}/build.gradle | 0 {1.20 => 1.20.1}/gradle.properties | 0 .../gradle/wrapper/gradle-wrapper.jar | Bin .../gradle/wrapper/gradle-wrapper.properties | 0 {1.20 => 1.20.1}/gradlew | 0 {1.20 => 1.20.1}/gradlew.bat | 0 {1.20 => 1.20.1}/settings.gradle | 0 1.20.4/CHANGELOG.md | 13 + 1.20.4/Common/build.gradle | 11 + .../java/fuzs/tradingpost/TradingPost.java | 56 +++ .../tradingpost/client/TradingPostClient.java | 46 +++ .../screens/inventory/TradingPostScreen.java | 379 ++++++++++++++++++ .../blockentity/TradingPostRenderer.java | 58 +++ .../fuzs/tradingpost/config/ServerConfig.java | 35 ++ .../fuzs/tradingpost/init/ModRegistry.java | 32 ++ .../mixin/accessor/MerchantMenuAccessor.java | 20 + .../mixin/accessor/VillagerAccessor.java | 13 + .../mixin/client/accessor/ButtonAccessor.java | 14 + .../accessor/MerchantScreenAccessor.java | 34 ++ .../accessor/TradeOfferButtonAccessor.java | 16 + .../network/S2CBuildOffersMessage.java | 61 +++ .../network/S2CMerchantDataMessage.java | 73 ++++ .../network/S2CRemoveMerchantsMessage.java | 59 +++ .../network/client/C2SClearSlotsMessage.java | 34 ++ .../world/entity/npc/LocalMerchant.java | 42 ++ .../world/entity/npc/MerchantCollection.java | 286 +++++++++++++ .../world/inventory/TradingPostContainer.java | 22 + .../world/inventory/TradingPostMenu.java | 200 +++++++++ .../world/item/trading/TradingPostOffers.java | 58 +++ .../world/level/block/TradingPostBlock.java | 182 +++++++++ .../block/entity/TradingPostBlockEntity.java | 98 +++++ .../tradingpost/blockstates/trading_post.json | 7 + .../assets/tradingpost/lang/en_us.json | 7 + .../assets/tradingpost/lang/it_it.json | 7 + .../assets/tradingpost/lang/pt_br.json | 7 + .../assets/tradingpost/lang/ru_ru.json | 7 + .../assets/tradingpost/lang/zh_tw.json | 7 + .../models/block/trading_post.json | 63 +++ .../tradingpost/models/item/trading_post.json | 3 + .../textures/block/trading_post_bottom.png | Bin 0 -> 1321 bytes .../textures/block/trading_post_front.png | Bin 0 -> 1610 bytes .../textures/block/trading_post_side.png | Bin 0 -> 1585 bytes .../textures/block/trading_post_top.png | Bin 0 -> 1640 bytes .../textures/item/magnifying_glass.png | Bin 0 -> 744 bytes .../minecraft/tags/blocks/mineable/axe.json | 6 + .../loot_tables/blocks/trading_post.json | 19 + .../tradingpost/recipes/trading_post.json | 22 + .../entity_types/blacklisted_traders.json | 5 + .../Common/src/main/resources/mod_banner.png | Bin 0 -> 20290 bytes 1.20.4/Common/src/main/resources/mod_logo.png | Bin 0 -> 9609 bytes 1.20.4/Common/src/main/resources/pack.mcmeta | 8 + .../resources/tradingpost.common.mixins.json | 20 + 1.20.4/Fabric/build.gradle | 29 ++ .../fuzs/tradingpost/TradingPostFabric.java | 12 + .../client/TradingPostFabricClient.java | 13 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../Fabric/src/main/resources/fabric.mod.json | 44 ++ 1.20.4/Forge/build.gradle | 28 ++ .../178bb4356f8bea3c4b8966704e26df58ba8fa865 | 2 + .../assets/minecraft/atlases/blocks.json | 8 + .../fuzs/tradingpost/TradingPostForge.java | 33 ++ .../client/TradingPostForgeClient.java | 17 + .../data/ModSpriteSourceProvider.java | 22 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../src/main/resources/META-INF/mods.toml | 40 ++ 1.20.4/NeoForge/build.gradle | 28 ++ .../178bb4356f8bea3c4b8966704e26df58ba8fa865 | 2 + .../assets/minecraft/atlases/blocks.json | 8 + .../fuzs/tradingpost/TradingPostForge.java | 33 ++ .../client/TradingPostForgeClient.java | 17 + .../data/ModSpriteSourceProvider.java | 22 + .../mixin/ModMixinConfigPlugin.java | 47 +++ .../src/main/resources/META-INF/mods.toml | 40 ++ 1.20.4/build.gradle | 12 + 1.20.4/gradle.properties | 35 ++ 1.20.4/gradle/wrapper/gradle-wrapper.jar | Bin 0 -> 61574 bytes .../gradle/wrapper/gradle-wrapper.properties | 6 + 1.20.4/gradlew | 244 +++++++++++ 1.20.4/gradlew.bat | 92 +++++ 1.20.4/settings.gradle | 38 ++ 1.20/.idea/scopes/Fabric_sources.xml | 3 - 1.20/.idea/scopes/Forge_sources.xml | 3 - 205 files changed, 3091 insertions(+), 85 deletions(-) delete mode 100644 .idea/gradle.xml rename {.idea => 1.18.2/.idea}/scopes/Fabric_sources.xml (100%) rename {.idea => 1.18.2/.idea}/scopes/Forge_sources.xml (100%) rename {1.18 => 1.18.2}/CHANGELOG.md (100%) rename {1.18 => 1.18.2}/Common/build.gradle (100%) rename {1.18 => 1.18.2}/Common/src/main/java/fuzs/examplemod/ExampleMod.java (100%) rename {1.18 => 1.18.2}/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/examplemod.common.mixins.json (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/mod_banner.png (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/mod_logo.png (100%) rename {1.18 => 1.18.2}/Common/src/main/resources/pack.mcmeta (100%) rename {1.18 => 1.18.2}/Fabric/build.gradle (100%) rename {1.18 => 1.18.2}/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java (100%) rename {1.18 => 1.18.2}/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java (100%) rename {1.18 => 1.18.2}/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.18 => 1.18.2}/Fabric/src/main/resources/examplemod.fabric.mixins.json (100%) rename {1.18 => 1.18.2}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.18 => 1.18.2}/Forge/build.gradle (100%) rename {1.18 => 1.18.2}/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java (100%) rename {1.18 => 1.18.2}/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java (100%) rename {1.18 => 1.18.2}/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.18 => 1.18.2}/Forge/src/main/resources/META-INF/mods.toml (100%) rename {1.18 => 1.18.2}/Forge/src/main/resources/examplemod.forge.mixins.json (100%) rename {1.18 => 1.18.2}/build.gradle (100%) rename {1.18 => 1.18.2}/gradle.properties (100%) rename {1.18 => 1.18.2}/gradle/wrapper/gradle-wrapper.jar (100%) rename {1.18 => 1.18.2}/gradle/wrapper/gradle-wrapper.properties (100%) rename {1.18 => 1.18.2}/gradlew (100%) rename {1.18 => 1.18.2}/gradlew.bat (100%) rename {1.18 => 1.18.2}/settings.gradle (100%) rename {1.18 => 1.19.2}/.idea/scopes/Fabric_sources.xml (100%) rename {1.18 => 1.19.2}/.idea/scopes/Forge_sources.xml (100%) rename {1.19 => 1.19.2}/CHANGELOG.md (100%) rename {1.19 => 1.19.2}/Common/build.gradle (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/examplemod/ExampleMod.java (100%) rename {1.19 => 1.19.2}/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/examplemod.common.mixins.json (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/mod_banner.png (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/mod_logo.png (100%) rename {1.19 => 1.19.2}/Common/src/main/resources/pack.mcmeta (100%) rename {1.19 => 1.19.2}/Fabric/build.gradle (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.19 => 1.19.2}/Fabric/src/main/resources/examplemod.fabric.mixins.json (100%) rename {1.19 => 1.19.2}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.19 => 1.19.2}/Forge/build.gradle (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/META-INF/mods.toml (100%) rename {1.19 => 1.19.2}/Forge/src/main/resources/examplemod.forge.mixins.json (100%) rename {1.19 => 1.19.2}/build.gradle (100%) rename {1.19 => 1.19.2}/gradle.properties (100%) rename {1.19 => 1.19.2}/gradle/wrapper/gradle-wrapper.jar (100%) rename {1.19 => 1.19.2}/gradle/wrapper/gradle-wrapper.properties (100%) rename {1.19 => 1.19.2}/gradlew (100%) rename {1.19 => 1.19.2}/gradlew.bat (100%) rename {1.19 => 1.19.2}/settings.gradle (100%) rename {1.19 => 1.20.1}/.idea/scopes/Fabric_sources.xml (100%) rename {1.19 => 1.20.1}/.idea/scopes/Forge_sources.xml (100%) rename {1.20 => 1.20.1}/CHANGELOG.md (100%) rename {1.20 => 1.20.1}/Common/build.gradle (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/TradingPost.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java (100%) rename {1.20 => 1.20.1}/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/lang/en_us.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/lang/it_it.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/lang/pt_br.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/data/tradingpost/recipes/trading_post.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/mod_banner.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/mod_logo.png (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/pack.mcmeta (100%) rename {1.20 => 1.20.1}/Common/src/main/resources/tradingpost.common.mixins.json (100%) rename {1.20 => 1.20.1}/Fabric/build.gradle (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java (100%) rename {1.20 => 1.20.1}/Fabric/src/main/resources/fabric.mod.json (100%) rename {1.20 => 1.20.1}/Forge/build.gradle (100%) rename {1.20 => 1.20.1}/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 (100%) rename {1.20 => 1.20.1}/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java (100%) rename {1.20 => 1.20.1}/Forge/src/main/resources/META-INF/mods.toml (100%) rename {1.20 => 1.20.1}/build.gradle (100%) rename {1.20 => 1.20.1}/gradle.properties (100%) rename {1.20 => 1.20.1}/gradle/wrapper/gradle-wrapper.jar (100%) rename {1.20 => 1.20.1}/gradle/wrapper/gradle-wrapper.properties (100%) rename {1.20 => 1.20.1}/gradlew (100%) rename {1.20 => 1.20.1}/gradlew.bat (100%) rename {1.20 => 1.20.1}/settings.gradle (100%) create mode 100644 1.20.4/CHANGELOG.md create mode 100644 1.20.4/Common/build.gradle create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java create mode 100644 1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/lang/en_us.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/lang/it_it.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/lang/pt_br.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png create mode 100644 1.20.4/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png create mode 100644 1.20.4/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json create mode 100644 1.20.4/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json create mode 100644 1.20.4/Common/src/main/resources/data/tradingpost/recipes/trading_post.json create mode 100644 1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json create mode 100644 1.20.4/Common/src/main/resources/mod_banner.png create mode 100644 1.20.4/Common/src/main/resources/mod_logo.png create mode 100755 1.20.4/Common/src/main/resources/pack.mcmeta create mode 100644 1.20.4/Common/src/main/resources/tradingpost.common.mixins.json create mode 100644 1.20.4/Fabric/build.gradle create mode 100644 1.20.4/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java create mode 100644 1.20.4/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java create mode 100644 1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Fabric/src/main/resources/fabric.mod.json create mode 100644 1.20.4/Forge/build.gradle create mode 100644 1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 create mode 100644 1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json create mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java create mode 100644 1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/Forge/src/main/resources/META-INF/mods.toml create mode 100644 1.20.4/NeoForge/build.gradle create mode 100644 1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 create mode 100644 1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java create mode 100644 1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java create mode 100644 1.20.4/NeoForge/src/main/resources/META-INF/mods.toml create mode 100644 1.20.4/build.gradle create mode 100755 1.20.4/gradle.properties create mode 100644 1.20.4/gradle/wrapper/gradle-wrapper.jar create mode 100644 1.20.4/gradle/wrapper/gradle-wrapper.properties create mode 100755 1.20.4/gradlew create mode 100644 1.20.4/gradlew.bat create mode 100644 1.20.4/settings.gradle delete mode 100644 1.20/.idea/scopes/Fabric_sources.xml delete mode 100644 1.20/.idea/scopes/Forge_sources.xml diff --git a/.github/ISSUE_TEMPLATE/bug.yml b/.github/ISSUE_TEMPLATE/bug.yml index 7726363..a2056ad 100644 --- a/.github/ISSUE_TEMPLATE/bug.yml +++ b/.github/ISSUE_TEMPLATE/bug.yml @@ -1,7 +1,7 @@ -name: Bug Report +name: Report A Bug description: >- - Please use this template when you have encountered a bug in this mod. Please note that only the latest mod version for Minecraft 1.18.2, 1.19.2 and 1.20.1 is supported. -title: '[Bug]: ' + Only Minecraft versions listed on the main branch are supported. Support may additionally vary based on the severity of an issue. +title: "[Bug]: " labels: ["bug"] assignees: - Fuzss @@ -14,35 +14,49 @@ body: id: loader attributes: label: Mod Loader (Required) - description: What mod loader are you using the mod on? + description: What mod loader are you using to play the mod? multiple: false options: - - Forge - - Fabric - - Quilt + - "⸺" + - "Fabric" + - "NeoForge" + - "Forge" + - "Quilt" validations: required: true - type: input id: minecraft attributes: - label: Minecraft Version (Required) - description: What is the Minecraft version you are playing with? + label: Minecraft Version(s) (Required) + description: What Minecraft version(s) are you using the play the mod? placeholder: ex. 1.20.1 validations: required: true - type: input id: version attributes: - label: Mod Version (Required) - description: What version of the mod are you playing with? + label: Mod Version(s) (Required) + description: What mod version(s) are you using to play? placeholder: ex. v8.0.0 validations: required: true + - type: dropdown + id: mods + attributes: + label: Other Mods Involved (Required) + description: Can your issue be reproduced with a minimal set of mods (only this mod + dependencies)? + multiple: false + options: + - "⸺" + - "Yes" + - "No" + validations: + required: true - type: textarea id: notes attributes: label: Notes (Required) - description: Please explain what happens because of the bug (including all the steps required to cause the bug), and what behavior you would expect if the bug were fixed. + description: Please explain what happens because of the issue (including all the steps required to cause it), and what behavior you would expect if the issue were fixed. placeholder: >- ex. @@ -60,6 +74,8 @@ body: - type: input id: latest-log attributes: - label: latest.log (Optional) - description: Please paste the url to your shared `latest.log` file. [To share your `latest.log` here, please follow these steps.](https://gist.github.com/Fuzss/866b384d353912986e37b17eeef7a285) - placeholder: ex. https://gist.github.com// \ No newline at end of file + label: latest.log (Required) + description: Please paste the url to your shared `latest.log` file. Note that issue reports without this file are difficult to solve and unlikely to be processed. [To share your `latest.log` here, please follow these steps.](https://gist.github.com/Fuzss/866b384d353912986e37b17eeef7a285) + placeholder: ex. https://gist.github.com// + validations: + required: true diff --git a/.github/ISSUE_TEMPLATE/config.yml b/.github/ISSUE_TEMPLATE/config.yml index e0133b0..cbe96b9 100644 --- a/.github/ISSUE_TEMPLATE/config.yml +++ b/.github/ISSUE_TEMPLATE/config.yml @@ -1,5 +1,5 @@ blank_issues_enabled: false contact_links: - - name: Questions + - name: Ask A Question url: https://lunapixel.studio/discord - about: "Please ask questions on the Luna Pixel Studios Discord in #fuzs-projects." \ No newline at end of file + about: "Join the Luna Pixel Studios Discord Server in the #fuzs-projects channel for additional support." \ No newline at end of file diff --git a/.github/ISSUE_TEMPLATE/crash.yml b/.github/ISSUE_TEMPLATE/crash.yml index 5ca6180..20493b1 100644 --- a/.github/ISSUE_TEMPLATE/crash.yml +++ b/.github/ISSUE_TEMPLATE/crash.yml @@ -1,8 +1,8 @@ -name: Crash Report +name: Submit A Crash Report description: >- - Please use this template when this mod has caused your game to crash. Please note that only the latest mod version for Minecraft 1.18.2, 1.19.2 and 1.20.1 is supported. -title: '[Crash]: ' -labels: ["bug"] + Only Minecraft versions listed on the main branch are supported. Support may additionally vary based on the severity of an issue. +title: "[Crash]: " +labels: ["bug", "high priority"] assignees: - Fuzss body: @@ -14,35 +14,49 @@ body: id: loader attributes: label: Mod Loader (Required) - description: What mod loader are you using the mod on? + description: What mod loader are you using to play the mod? multiple: false options: - - Forge - - Fabric - - Quilt + - "⸺" + - "Fabric" + - "NeoForge" + - "Forge" + - "Quilt" validations: required: true - type: input id: minecraft attributes: - label: Minecraft Version (Required) - description: What is the Minecraft version you are playing with? + label: Minecraft Version(s) (Required) + description: What Minecraft version(s) are you using the play the mod? placeholder: ex. 1.20.1 validations: required: true - type: input id: version attributes: - label: Mod Version (Required) - description: What version of the mod are you playing with? + label: Mod Version(s) (Required) + description: What mod version(s) are you using to play? placeholder: ex. v8.0.0 validations: required: true + - type: dropdown + id: mods + attributes: + label: Other Mods Involved (Required) + description: Can your issue be reproduced with a minimal set of mods (only this mod + dependencies)? + multiple: false + options: + - "⸺" + - "Yes" + - "No" + validations: + required: true - type: textarea id: notes attributes: label: Notes (Required) - description: Please explain which steps we need to do to reproduce the crash. Please include anything else you'd like to say about the crash. + description: Please explain which steps we need to do to reproduce the issue. Please include anything else you'd like to say about it. placeholder: >- ex. @@ -58,7 +72,7 @@ body: attributes: label: Crash Report (Required) description: >- - Please paste the url to your shared crash report. [To share your crash report here, please follow these steps.](https://gist.github.com/Fuzss/9692f6ed5e8cca485a58004c28c9045b) + Please paste the url to your shared crash report. Note that issue reports without this file are difficult to solve and unlikely to be processed. [To share your crash report here, please follow these steps.](https://gist.github.com/Fuzss/9692f6ed5e8cca485a58004c28c9045b) placeholder: ex. https://gist.github.com// validations: required: true @@ -67,4 +81,4 @@ body: attributes: label: latest.log (Optional) description: Please paste the url to your shared `latest.log` file. [To share your `latest.log` here, please follow these steps.](https://gist.github.com/Fuzss/866b384d353912986e37b17eeef7a285) - placeholder: ex. https://gist.github.com// \ No newline at end of file + placeholder: ex. https://gist.github.com// diff --git a/.github/ISSUE_TEMPLATE/suggestion.yml b/.github/ISSUE_TEMPLATE/suggestion.yml index 0eb9a33..2a25400 100644 --- a/.github/ISSUE_TEMPLATE/suggestion.yml +++ b/.github/ISSUE_TEMPLATE/suggestion.yml @@ -1,11 +1,41 @@ -name: Suggestion +name: Leave A Suggestion description: >- - Please use this template when you want to suggest a feature. Please do not ask for mod updates or ports, they will come when they are ready. -title: '[Suggestion]: ' + Please do not ask for mod updates or ports, they will come when they are ready. +title: "[Suggestion]: " labels: ["enhancement"] assignees: - Fuzss body: + - type: markdown + attributes: + value: | + Thanks for taking the time to fill out this issue report! + - type: dropdown + id: loader + attributes: + label: Mod Loader (Optional) + description: What mod loader are you using to play the mod? + multiple: false + options: + - "⸺" + - "Fabric" + - "NeoForge" + - "Forge" + - "Quilt" + validations: + required: true + - type: input + id: minecraft + attributes: + label: Minecraft Version(s) (Optional) + description: What Minecraft version(s) are you using the play the mod? + placeholder: ex. 1.20.1 + - type: input + id: version + attributes: + label: Mod Version(s) (Optional) + description: What mod version(s) are you using to play? + placeholder: ex. v8.0.0 - type: textarea id: suggestion attributes: diff --git a/.idea/gradle.xml b/.idea/gradle.xml deleted file mode 100644 index 311bce0..0000000 --- a/.idea/gradle.xml +++ /dev/null @@ -1,44 +0,0 @@ - - - - - - - \ No newline at end of file diff --git a/.idea/scopes/Fabric_sources.xml b/1.18.2/.idea/scopes/Fabric_sources.xml similarity index 100% rename from .idea/scopes/Fabric_sources.xml rename to 1.18.2/.idea/scopes/Fabric_sources.xml diff --git a/.idea/scopes/Forge_sources.xml b/1.18.2/.idea/scopes/Forge_sources.xml similarity index 100% rename from .idea/scopes/Forge_sources.xml rename to 1.18.2/.idea/scopes/Forge_sources.xml diff --git a/1.18/CHANGELOG.md b/1.18.2/CHANGELOG.md similarity index 100% rename from 1.18/CHANGELOG.md rename to 1.18.2/CHANGELOG.md diff --git a/1.18/Common/build.gradle b/1.18.2/Common/build.gradle similarity index 100% rename from 1.18/Common/build.gradle rename to 1.18.2/Common/build.gradle diff --git a/1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.18.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java similarity index 100% rename from 1.18/Common/src/main/java/fuzs/examplemod/ExampleMod.java rename to 1.18.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java diff --git a/1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.18.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java similarity index 100% rename from 1.18/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java rename to 1.18.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java diff --git a/1.18/Common/src/main/resources/examplemod.common.mixins.json b/1.18.2/Common/src/main/resources/examplemod.common.mixins.json similarity index 100% rename from 1.18/Common/src/main/resources/examplemod.common.mixins.json rename to 1.18.2/Common/src/main/resources/examplemod.common.mixins.json diff --git a/1.18/Common/src/main/resources/mod_banner.png b/1.18.2/Common/src/main/resources/mod_banner.png similarity index 100% rename from 1.18/Common/src/main/resources/mod_banner.png rename to 1.18.2/Common/src/main/resources/mod_banner.png diff --git a/1.18/Common/src/main/resources/mod_logo.png b/1.18.2/Common/src/main/resources/mod_logo.png similarity index 100% rename from 1.18/Common/src/main/resources/mod_logo.png rename to 1.18.2/Common/src/main/resources/mod_logo.png diff --git a/1.18/Common/src/main/resources/pack.mcmeta b/1.18.2/Common/src/main/resources/pack.mcmeta similarity index 100% rename from 1.18/Common/src/main/resources/pack.mcmeta rename to 1.18.2/Common/src/main/resources/pack.mcmeta diff --git a/1.18/Fabric/build.gradle b/1.18.2/Fabric/build.gradle similarity index 100% rename from 1.18/Fabric/build.gradle rename to 1.18.2/Fabric/build.gradle diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.18.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java similarity index 100% rename from 1.18/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java rename to 1.18.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.18.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java similarity index 100% rename from 1.18/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java rename to 1.18.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java diff --git a/1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.18/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.18.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.18.2/Fabric/src/main/resources/examplemod.fabric.mixins.json similarity index 100% rename from 1.18/Fabric/src/main/resources/examplemod.fabric.mixins.json rename to 1.18.2/Fabric/src/main/resources/examplemod.fabric.mixins.json diff --git a/1.18/Fabric/src/main/resources/fabric.mod.json b/1.18.2/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from 1.18/Fabric/src/main/resources/fabric.mod.json rename to 1.18.2/Fabric/src/main/resources/fabric.mod.json diff --git a/1.18/Forge/build.gradle b/1.18.2/Forge/build.gradle similarity index 100% rename from 1.18/Forge/build.gradle rename to 1.18.2/Forge/build.gradle diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.18.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java similarity index 100% rename from 1.18/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java rename to 1.18.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.18.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java similarity index 100% rename from 1.18/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java rename to 1.18.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java diff --git a/1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.18.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.18/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.18.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.18/Forge/src/main/resources/META-INF/mods.toml b/1.18.2/Forge/src/main/resources/META-INF/mods.toml similarity index 100% rename from 1.18/Forge/src/main/resources/META-INF/mods.toml rename to 1.18.2/Forge/src/main/resources/META-INF/mods.toml diff --git a/1.18/Forge/src/main/resources/examplemod.forge.mixins.json b/1.18.2/Forge/src/main/resources/examplemod.forge.mixins.json similarity index 100% rename from 1.18/Forge/src/main/resources/examplemod.forge.mixins.json rename to 1.18.2/Forge/src/main/resources/examplemod.forge.mixins.json diff --git a/1.18/build.gradle b/1.18.2/build.gradle similarity index 100% rename from 1.18/build.gradle rename to 1.18.2/build.gradle diff --git a/1.18/gradle.properties b/1.18.2/gradle.properties similarity index 100% rename from 1.18/gradle.properties rename to 1.18.2/gradle.properties diff --git a/1.18/gradle/wrapper/gradle-wrapper.jar b/1.18.2/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from 1.18/gradle/wrapper/gradle-wrapper.jar rename to 1.18.2/gradle/wrapper/gradle-wrapper.jar diff --git a/1.18/gradle/wrapper/gradle-wrapper.properties b/1.18.2/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from 1.18/gradle/wrapper/gradle-wrapper.properties rename to 1.18.2/gradle/wrapper/gradle-wrapper.properties diff --git a/1.18/gradlew b/1.18.2/gradlew similarity index 100% rename from 1.18/gradlew rename to 1.18.2/gradlew diff --git a/1.18/gradlew.bat b/1.18.2/gradlew.bat similarity index 100% rename from 1.18/gradlew.bat rename to 1.18.2/gradlew.bat diff --git a/1.18/settings.gradle b/1.18.2/settings.gradle similarity index 100% rename from 1.18/settings.gradle rename to 1.18.2/settings.gradle diff --git a/1.18/.idea/scopes/Fabric_sources.xml b/1.19.2/.idea/scopes/Fabric_sources.xml similarity index 100% rename from 1.18/.idea/scopes/Fabric_sources.xml rename to 1.19.2/.idea/scopes/Fabric_sources.xml diff --git a/1.18/.idea/scopes/Forge_sources.xml b/1.19.2/.idea/scopes/Forge_sources.xml similarity index 100% rename from 1.18/.idea/scopes/Forge_sources.xml rename to 1.19.2/.idea/scopes/Forge_sources.xml diff --git a/1.19/CHANGELOG.md b/1.19.2/CHANGELOG.md similarity index 100% rename from 1.19/CHANGELOG.md rename to 1.19.2/CHANGELOG.md diff --git a/1.19/Common/build.gradle b/1.19.2/Common/build.gradle similarity index 100% rename from 1.19/Common/build.gradle rename to 1.19.2/Common/build.gradle diff --git a/1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java b/1.19.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/examplemod/ExampleMod.java rename to 1.19.2/Common/src/main/java/fuzs/examplemod/ExampleMod.java diff --git a/1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java b/1.19.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java similarity index 100% rename from 1.19/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java rename to 1.19.2/Common/src/main/java/fuzs/examplemod/client/ExampleModClient.java diff --git a/1.19/Common/src/main/resources/examplemod.common.mixins.json b/1.19.2/Common/src/main/resources/examplemod.common.mixins.json similarity index 100% rename from 1.19/Common/src/main/resources/examplemod.common.mixins.json rename to 1.19.2/Common/src/main/resources/examplemod.common.mixins.json diff --git a/1.19/Common/src/main/resources/mod_banner.png b/1.19.2/Common/src/main/resources/mod_banner.png similarity index 100% rename from 1.19/Common/src/main/resources/mod_banner.png rename to 1.19.2/Common/src/main/resources/mod_banner.png diff --git a/1.19/Common/src/main/resources/mod_logo.png b/1.19.2/Common/src/main/resources/mod_logo.png similarity index 100% rename from 1.19/Common/src/main/resources/mod_logo.png rename to 1.19.2/Common/src/main/resources/mod_logo.png diff --git a/1.19/Common/src/main/resources/pack.mcmeta b/1.19.2/Common/src/main/resources/pack.mcmeta similarity index 100% rename from 1.19/Common/src/main/resources/pack.mcmeta rename to 1.19.2/Common/src/main/resources/pack.mcmeta diff --git a/1.19/Fabric/build.gradle b/1.19.2/Fabric/build.gradle similarity index 100% rename from 1.19/Fabric/build.gradle rename to 1.19.2/Fabric/build.gradle diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java b/1.19.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java rename to 1.19.2/Fabric/src/main/java/fuzs/examplemod/ExampleModFabric.java diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java b/1.19.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java rename to 1.19.2/Fabric/src/main/java/fuzs/examplemod/client/ExampleModFabricClient.java diff --git a/1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.19.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.19/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.19.2/Fabric/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json b/1.19.2/Fabric/src/main/resources/examplemod.fabric.mixins.json similarity index 100% rename from 1.19/Fabric/src/main/resources/examplemod.fabric.mixins.json rename to 1.19.2/Fabric/src/main/resources/examplemod.fabric.mixins.json diff --git a/1.19/Fabric/src/main/resources/fabric.mod.json b/1.19.2/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from 1.19/Fabric/src/main/resources/fabric.mod.json rename to 1.19.2/Fabric/src/main/resources/fabric.mod.json diff --git a/1.19/Forge/build.gradle b/1.19.2/Forge/build.gradle similarity index 100% rename from 1.19/Forge/build.gradle rename to 1.19.2/Forge/build.gradle diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java b/1.19.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java rename to 1.19.2/Forge/src/main/java/fuzs/examplemod/ExampleModForge.java diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java b/1.19.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java rename to 1.19.2/Forge/src/main/java/fuzs/examplemod/client/ExampleModForgeClient.java diff --git a/1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java b/1.19.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.19/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java rename to 1.19.2/Forge/src/main/java/fuzs/examplemod/mixin/ModMixinConfigPlugin.java diff --git a/1.19/Forge/src/main/resources/META-INF/mods.toml b/1.19.2/Forge/src/main/resources/META-INF/mods.toml similarity index 100% rename from 1.19/Forge/src/main/resources/META-INF/mods.toml rename to 1.19.2/Forge/src/main/resources/META-INF/mods.toml diff --git a/1.19/Forge/src/main/resources/examplemod.forge.mixins.json b/1.19.2/Forge/src/main/resources/examplemod.forge.mixins.json similarity index 100% rename from 1.19/Forge/src/main/resources/examplemod.forge.mixins.json rename to 1.19.2/Forge/src/main/resources/examplemod.forge.mixins.json diff --git a/1.19/build.gradle b/1.19.2/build.gradle similarity index 100% rename from 1.19/build.gradle rename to 1.19.2/build.gradle diff --git a/1.19/gradle.properties b/1.19.2/gradle.properties similarity index 100% rename from 1.19/gradle.properties rename to 1.19.2/gradle.properties diff --git a/1.19/gradle/wrapper/gradle-wrapper.jar b/1.19.2/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from 1.19/gradle/wrapper/gradle-wrapper.jar rename to 1.19.2/gradle/wrapper/gradle-wrapper.jar diff --git a/1.19/gradle/wrapper/gradle-wrapper.properties b/1.19.2/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from 1.19/gradle/wrapper/gradle-wrapper.properties rename to 1.19.2/gradle/wrapper/gradle-wrapper.properties diff --git a/1.19/gradlew b/1.19.2/gradlew similarity index 100% rename from 1.19/gradlew rename to 1.19.2/gradlew diff --git a/1.19/gradlew.bat b/1.19.2/gradlew.bat similarity index 100% rename from 1.19/gradlew.bat rename to 1.19.2/gradlew.bat diff --git a/1.19/settings.gradle b/1.19.2/settings.gradle similarity index 100% rename from 1.19/settings.gradle rename to 1.19.2/settings.gradle diff --git a/1.19/.idea/scopes/Fabric_sources.xml b/1.20.1/.idea/scopes/Fabric_sources.xml similarity index 100% rename from 1.19/.idea/scopes/Fabric_sources.xml rename to 1.20.1/.idea/scopes/Fabric_sources.xml diff --git a/1.19/.idea/scopes/Forge_sources.xml b/1.20.1/.idea/scopes/Forge_sources.xml similarity index 100% rename from 1.19/.idea/scopes/Forge_sources.xml rename to 1.20.1/.idea/scopes/Forge_sources.xml diff --git a/1.20/CHANGELOG.md b/1.20.1/CHANGELOG.md similarity index 100% rename from 1.20/CHANGELOG.md rename to 1.20.1/CHANGELOG.md diff --git a/1.20/Common/build.gradle b/1.20.1/Common/build.gradle similarity index 100% rename from 1.20/Common/build.gradle rename to 1.20.1/Common/build.gradle diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/TradingPost.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/TradingPost.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/TradingPost.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java diff --git a/1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.20.1/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java similarity index 100% rename from 1.20/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java rename to 1.20.1/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java diff --git a/1.20/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json b/1.20.1/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/lang/en_us.json b/1.20.1/Common/src/main/resources/assets/tradingpost/lang/en_us.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/lang/en_us.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/lang/en_us.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/lang/it_it.json b/1.20.1/Common/src/main/resources/assets/tradingpost/lang/it_it.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/lang/it_it.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/lang/it_it.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/lang/pt_br.json b/1.20.1/Common/src/main/resources/assets/tradingpost/lang/pt_br.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/lang/pt_br.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/lang/pt_br.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json b/1.20.1/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json b/1.20.1/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json b/1.20.1/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json b/1.20.1/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json rename to 1.20.1/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json diff --git a/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png b/1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png rename to 1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png diff --git a/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png b/1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png rename to 1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png diff --git a/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png b/1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png rename to 1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png diff --git a/1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png b/1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png rename to 1.20.1/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png diff --git a/1.20/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png b/1.20.1/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png similarity index 100% rename from 1.20/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png rename to 1.20.1/Common/src/main/resources/assets/tradingpost/textures/item/magnifying_glass.png diff --git a/1.20/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json b/1.20.1/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json similarity index 100% rename from 1.20/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json rename to 1.20.1/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json diff --git a/1.20/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json b/1.20.1/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json similarity index 100% rename from 1.20/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json rename to 1.20.1/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json diff --git a/1.20/Common/src/main/resources/data/tradingpost/recipes/trading_post.json b/1.20.1/Common/src/main/resources/data/tradingpost/recipes/trading_post.json similarity index 100% rename from 1.20/Common/src/main/resources/data/tradingpost/recipes/trading_post.json rename to 1.20.1/Common/src/main/resources/data/tradingpost/recipes/trading_post.json diff --git a/1.20/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json b/1.20.1/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json similarity index 100% rename from 1.20/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json rename to 1.20.1/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json diff --git a/1.20/Common/src/main/resources/mod_banner.png b/1.20.1/Common/src/main/resources/mod_banner.png similarity index 100% rename from 1.20/Common/src/main/resources/mod_banner.png rename to 1.20.1/Common/src/main/resources/mod_banner.png diff --git a/1.20/Common/src/main/resources/mod_logo.png b/1.20.1/Common/src/main/resources/mod_logo.png similarity index 100% rename from 1.20/Common/src/main/resources/mod_logo.png rename to 1.20.1/Common/src/main/resources/mod_logo.png diff --git a/1.20/Common/src/main/resources/pack.mcmeta b/1.20.1/Common/src/main/resources/pack.mcmeta similarity index 100% rename from 1.20/Common/src/main/resources/pack.mcmeta rename to 1.20.1/Common/src/main/resources/pack.mcmeta diff --git a/1.20/Common/src/main/resources/tradingpost.common.mixins.json b/1.20.1/Common/src/main/resources/tradingpost.common.mixins.json similarity index 100% rename from 1.20/Common/src/main/resources/tradingpost.common.mixins.json rename to 1.20.1/Common/src/main/resources/tradingpost.common.mixins.json diff --git a/1.20/Fabric/build.gradle b/1.20.1/Fabric/build.gradle similarity index 100% rename from 1.20/Fabric/build.gradle rename to 1.20.1/Fabric/build.gradle diff --git a/1.20/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java b/1.20.1/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java rename to 1.20.1/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java diff --git a/1.20/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java b/1.20.1/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java rename to 1.20.1/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java diff --git a/1.20/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.1/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.20/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java rename to 1.20.1/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java diff --git a/1.20/Fabric/src/main/resources/fabric.mod.json b/1.20.1/Fabric/src/main/resources/fabric.mod.json similarity index 100% rename from 1.20/Fabric/src/main/resources/fabric.mod.json rename to 1.20.1/Fabric/src/main/resources/fabric.mod.json diff --git a/1.20/Forge/build.gradle b/1.20.1/Forge/build.gradle similarity index 100% rename from 1.20/Forge/build.gradle rename to 1.20.1/Forge/build.gradle diff --git a/1.20/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 b/1.20.1/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 similarity index 100% rename from 1.20/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 rename to 1.20.1/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 diff --git a/1.20/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json b/1.20.1/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json similarity index 100% rename from 1.20/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json rename to 1.20.1/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json diff --git a/1.20/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/1.20.1/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java rename to 1.20.1/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java diff --git a/1.20/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java b/1.20.1/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java rename to 1.20.1/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java diff --git a/1.20/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/1.20.1/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java rename to 1.20.1/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java diff --git a/1.20/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.1/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java similarity index 100% rename from 1.20/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java rename to 1.20.1/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java diff --git a/1.20/Forge/src/main/resources/META-INF/mods.toml b/1.20.1/Forge/src/main/resources/META-INF/mods.toml similarity index 100% rename from 1.20/Forge/src/main/resources/META-INF/mods.toml rename to 1.20.1/Forge/src/main/resources/META-INF/mods.toml diff --git a/1.20/build.gradle b/1.20.1/build.gradle similarity index 100% rename from 1.20/build.gradle rename to 1.20.1/build.gradle diff --git a/1.20/gradle.properties b/1.20.1/gradle.properties similarity index 100% rename from 1.20/gradle.properties rename to 1.20.1/gradle.properties diff --git a/1.20/gradle/wrapper/gradle-wrapper.jar b/1.20.1/gradle/wrapper/gradle-wrapper.jar similarity index 100% rename from 1.20/gradle/wrapper/gradle-wrapper.jar rename to 1.20.1/gradle/wrapper/gradle-wrapper.jar diff --git a/1.20/gradle/wrapper/gradle-wrapper.properties b/1.20.1/gradle/wrapper/gradle-wrapper.properties similarity index 100% rename from 1.20/gradle/wrapper/gradle-wrapper.properties rename to 1.20.1/gradle/wrapper/gradle-wrapper.properties diff --git a/1.20/gradlew b/1.20.1/gradlew similarity index 100% rename from 1.20/gradlew rename to 1.20.1/gradlew diff --git a/1.20/gradlew.bat b/1.20.1/gradlew.bat similarity index 100% rename from 1.20/gradlew.bat rename to 1.20.1/gradlew.bat diff --git a/1.20/settings.gradle b/1.20.1/settings.gradle similarity index 100% rename from 1.20/settings.gradle rename to 1.20.1/settings.gradle diff --git a/1.20.4/CHANGELOG.md b/1.20.4/CHANGELOG.md new file mode 100644 index 0000000..d0f42b1 --- /dev/null +++ b/1.20.4/CHANGELOG.md @@ -0,0 +1,13 @@ +# Changelog +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog]. + +## [v8.0.1-1.20.1] - 2023-07-13 +### Fixed +- Fixed Mixin config plugin being configured incorrectly on Fabric + +## [v8.0.0-1.20.1] - 2023-06-27 +- Ported to Minecraft 1.20.1 + +[Keep a Changelog]: https://keepachangelog.com/en/1.0.0/ diff --git a/1.20.4/Common/build.gradle b/1.20.4/Common/build.gradle new file mode 100644 index 0000000..949b426 --- /dev/null +++ b/1.20.4/Common/build.gradle @@ -0,0 +1,11 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/common.gradle' + +dependencies { + // Puzzles Lib + modApi libs.puzzleslib.common +} + +// @see https://github.com/jaredlll08/MultiLoader-Template/issues/17#issuecomment-1221598082 +tasks.withType(net.fabricmc.loom.task.AbstractRemapJarTask).each { + it.targetNamespace = "named" +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java new file mode 100644 index 0000000..333c896 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/TradingPost.java @@ -0,0 +1,56 @@ +package fuzs.tradingpost; + +import fuzs.puzzleslib.api.config.v3.ConfigHolder; +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.puzzleslib.api.core.v1.context.BuildCreativeModeTabContentsContext; +import fuzs.puzzleslib.api.core.v1.context.FuelBurnTimesContext; +import fuzs.puzzleslib.api.network.v2.MessageDirection; +import fuzs.puzzleslib.api.network.v2.NetworkHandlerV2; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.network.S2CBuildOffersMessage; +import fuzs.tradingpost.network.S2CMerchantDataMessage; +import fuzs.tradingpost.network.S2CRemoveMerchantsMessage; +import fuzs.tradingpost.network.client.C2SClearSlotsMessage; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.item.CreativeModeTabs; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +public class TradingPost implements ModConstructor { + public static final String MOD_ID = "tradingpost"; + public static final String MOD_NAME = "Trading Post"; + public static final Logger LOGGER = LoggerFactory.getLogger(MOD_NAME); + + public static final NetworkHandlerV2 NETWORK = NetworkHandlerV2.build(MOD_ID); + public static final ConfigHolder CONFIG = ConfigHolder.builder(MOD_ID).server(ServerConfig.class); + + @Override + public void onConstructMod() { + ModRegistry.touch(); + registerMessages(); + } + + private static void registerMessages() { + NETWORK.register(S2CMerchantDataMessage.class, S2CMerchantDataMessage::new, MessageDirection.TO_CLIENT); + NETWORK.register(S2CRemoveMerchantsMessage.class, S2CRemoveMerchantsMessage::new, MessageDirection.TO_CLIENT); + NETWORK.register(S2CBuildOffersMessage.class, S2CBuildOffersMessage::new, MessageDirection.TO_CLIENT); + NETWORK.register(C2SClearSlotsMessage.class, C2SClearSlotsMessage::new, MessageDirection.TO_SERVER); + } + + @Override + public void onBuildCreativeModeTabContents(BuildCreativeModeTabContentsContext context) { + context.registerBuildListener(CreativeModeTabs.FUNCTIONAL_BLOCKS, (itemDisplayParameters, output) -> { + output.accept(ModRegistry.TRADING_POST_ITEM.get()); + }); + } + + @Override + public void onRegisterFuelBurnTimes(FuelBurnTimesContext context) { + context.registerFuel(300, ModRegistry.TRADING_POST_BLOCK.get()); + } + + public static ResourceLocation id(String path) { + return new ResourceLocation(MOD_ID, path); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java new file mode 100644 index 0000000..5c4c211 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/TradingPostClient.java @@ -0,0 +1,46 @@ +package fuzs.tradingpost.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.puzzleslib.api.client.core.v1.context.BlockEntityRenderersContext; +import fuzs.puzzleslib.api.client.core.v1.context.SearchRegistryContext; +import fuzs.puzzleslib.api.core.v1.context.ModLifecycleContext; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import fuzs.tradingpost.client.renderer.blockentity.TradingPostRenderer; +import fuzs.tradingpost.init.ModRegistry; +import net.minecraft.ChatFormatting; +import net.minecraft.client.gui.screens.MenuScreens; +import net.minecraft.client.searchtree.FullTextSearchTree; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.TooltipFlag; + +import java.util.stream.Stream; + +public class TradingPostClient implements ClientModConstructor { + + @Override + public void onClientSetup(ModLifecycleContext context) { + MenuScreens.register(ModRegistry.TRADING_POST_MENU_TYPE.get(), TradingPostScreen::new); + } + + @Override + public void onRegisterBlockEntityRenderers(BlockEntityRenderersContext context) { + context.registerBlockEntityRenderer(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), TradingPostRenderer::new); + } + + @Override + public void onRegisterSearchTrees(SearchRegistryContext context) { + context.registerSearchTree(TradingPostScreen.OFFER_SEARCH_TREE, base -> new FullTextSearchTree<>(offer -> + Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) + .filter(itemStack -> !itemStack.isEmpty()) + .flatMap(itemStack -> itemStack.getTooltipLines(null, TooltipFlag.Default.NORMAL).stream()) + .map(tooltipLine -> ChatFormatting.stripFormatting(tooltipLine.getString()).trim()) + .filter(tooltipString -> !tooltipString.isEmpty()), + offer -> Stream.of(offer.getBaseCostA(), offer.getCostB(), offer.getResult()) + .filter(itemStack -> !itemStack.isEmpty()) + .map(ItemStack::getItem) + .map(BuiltInRegistries.ITEM::getKey), + base + )); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java new file mode 100644 index 0000000..58d8d8a --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/gui/screens/inventory/TradingPostScreen.java @@ -0,0 +1,379 @@ +package fuzs.tradingpost.client.gui.screens.inventory; + +import com.mojang.blaze3d.platform.InputConstants; +import com.mojang.blaze3d.systems.RenderSystem; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.mixin.client.accessor.ButtonAccessor; +import fuzs.tradingpost.mixin.client.accessor.MerchantScreenAccessor; +import fuzs.tradingpost.mixin.client.accessor.TradeOfferButtonAccessor; +import fuzs.tradingpost.network.client.C2SClearSlotsMessage; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import fuzs.tradingpost.world.item.trading.TradingPostOffers; +import net.minecraft.client.Minecraft; +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.components.Button; +import net.minecraft.client.gui.components.EditBox; +import net.minecraft.client.gui.components.Renderable; +import net.minecraft.client.gui.screens.inventory.MerchantScreen; +import net.minecraft.client.renderer.GameRenderer; +import net.minecraft.client.renderer.texture.TextureAtlasSprite; +import net.minecraft.client.searchtree.SearchRegistry; +import net.minecraft.client.searchtree.SearchTree; +import net.minecraft.network.chat.Component; +import net.minecraft.network.protocol.game.ServerboundSelectTradePacket; +import net.minecraft.resources.ResourceLocation; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.inventory.InventoryMenu; +import net.minecraft.world.inventory.MerchantMenu; +import net.minecraft.world.inventory.Slot; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; + +import java.util.List; +import java.util.Locale; +import java.util.Objects; + +public class TradingPostScreen extends MerchantScreen { + public static final ResourceLocation MAGNIFYING_GLASS_LOCATION = new ResourceLocation(TradingPost.MOD_ID, "item/magnifying_glass"); + public static final SearchRegistry.Key OFFER_SEARCH_TREE = new SearchRegistry.Key<>(); + private static final ResourceLocation VILLAGER_LOCATION = new ResourceLocation("textures/gui/container/villager2.png"); + private static final ResourceLocation CREATIVE_INVENTORY_LOCATION = new ResourceLocation("textures/gui/container/creative_inventory/tab_item_search.png"); + private static final Component DEPRECATED_TOOLTIP = Component.translatable("merchant.deprecated"); + private static final Component MERCHANT_GONE = Component.translatable("trading_post.trader_gone"); + + private Button[] tradeOfferButtons = new Button[7]; + private EditBox searchBox; + private boolean ignoreTextInput; + + public TradingPostScreen(MerchantMenu container, Inventory playerInventory, Component title) { + + super(container, playerInventory, title); + } + + @Override + protected void init() { + super.init(); + this.tradeOfferButtons = this.getTradeOfferButtons(this.renderables); + for (Button tradeOfferButton : this.tradeOfferButtons) { + + ((ButtonAccessor) tradeOfferButton).tradingpost$setOnPress(button -> { + + MerchantScreenAccessor accessor = (MerchantScreenAccessor) this; + final int shopItem = ((TradeOfferButtonAccessor) button).tradingpost$getIndex() + accessor.tradingpost$getScrollOff(); + MerchantOffers offers = this.getMenu().getOffers(); + accessor.tradingpost$setShopItem(shopItem); + this.getMenu().setSelectionHint(shopItem); + this.getMenu().getTraders().setActiveOffer(offers.get(shopItem)); + this.getMenu().tryMoveItems(shopItem); + // get real index when sending to server + this.minecraft.getConnection().send(new ServerboundSelectTradePacket(offers instanceof TradingPostOffers ? ((TradingPostOffers) offers).getOrigShopItem(shopItem) : shopItem)); + }); + } + + this.searchBox = new EditBox(this.font, this.leftPos + 13, this.topPos + 6, 80, 9, Component.translatable("itemGroup.search")) { + @Override + public boolean mouseClicked(double mouseX, double mouseY, int button) { + // left click clears text + if (this.isVisible() && button == InputConstants.MOUSE_BUTTON_RIGHT) { + this.setValue(""); + TradingPostScreen.this.refreshSearchResults(); + } + return super.mouseClicked(mouseX, mouseY, button); + } + }; + this.searchBox.setMaxLength(50); + this.searchBox.setBordered(false); + this.searchBox.setTextColor(16777215); + this.addWidget(this.searchBox); + } + + private Button[] getTradeOfferButtons(List buttons) { + Button[] tradeOfferButtons = buttons.stream().filter(button -> button instanceof TradeOfferButtonAccessor).map(button -> (Button) button).toArray(Button[]::new); + if (tradeOfferButtons.length != 7) { + TradingPost.LOGGER.warn("Unable to find enough tradeOfferButtons"); + } + return tradeOfferButtons; + } + + @Override + public void resize(Minecraft mc, int newWidth, int newHeight) { + final String lastSearch = this.searchBox.getValue(); + super.resize(mc, newWidth, newHeight); + this.searchBox.setValue(lastSearch); + if (!this.searchBox.getValue().isEmpty()) { + + this.refreshSearchResults(); + } + } + + @Override + protected void renderLabels(GuiGraphics guiGraphics, int mouseX, int mouseY) { + Component title = this.getMenu().getTraders().getDisplayName(); + if (title != null) { + int traderLevel = this.menu.getTraderLevel(); + if (traderLevel > 0 && traderLevel <= 5 && this.menu.showProgressBar()) { + title = title.copy().append(" - ").append(Component.translatable("merchant.level." + traderLevel)); + } + } else { + title = this.title; + } + guiGraphics.drawString(this.font, title, (49 + this.imageWidth / 2 - this.font.width(title) / 2), 6, 0x404040, false); + guiGraphics.drawString(this.font, this.playerInventoryTitle, this.inventoryLabelX, this.inventoryLabelY, 0x404040, false); + } + + @Override + public void render(GuiGraphics guiGraphics, int mouseX, int mouseY, float partialTime) { + + MerchantOffers merchantoffers = this.getMenu().getOffers(); + this.setButtonsActive(merchantoffers); + + final int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); + final Slot hoveredSlot = this.hoveredSlot; + // set offers to empty to prevent MerchantScreen::render code from running, also disabled buttons drawing tooltips by changing scrollOff, as well as tooltip for hovered slot by removing hovered slot + this.lock(true, merchantoffers.size(), null); + super.render(guiGraphics, mouseX, mouseY, partialTime); + // reset everything so we can do this ourselves + this.lock(false, scrollOff, hoveredSlot); + + if (!merchantoffers.isEmpty()) { + + // normally rendered as part of background, but skipped as offers are empty when it's called + final int shopItem = ((MerchantScreenAccessor) this).tradingpost$getShopItem(); + if (shopItem >= 0 && shopItem < merchantoffers.size()) { + + MerchantOffer merchantoffer = merchantoffers.get(shopItem); + if (merchantoffer.isOutOfStock()) { + RenderSystem.setShaderColor(1.0F, 1.0F, 1.0F, 1.0F); + guiGraphics.blit(VILLAGER_LOCATION, this.leftPos + 83 + 99, this.topPos + 35, 0, 311.0F, 0.0F, 28, 21, 512, 256); + } + } + + final int width = (this.width - this.imageWidth) / 2; + final int height = (this.height - this.imageHeight) / 2; + int posX = width + 5; + int posY = height + 16 + 2; + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); + ((MerchantScreenAccessor) this).tradingpost$callRenderScroller(guiGraphics, width, height, merchantoffers); + + for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { + + if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { + + MerchantOffer merchantoffer = merchantoffers.get(i); + // move this call here to render below red overlay + ((MerchantScreenAccessor) this).tradingpost$callRenderButtonArrows(guiGraphics, merchantoffer, width, posY + 1); + if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { + + guiGraphics.fill(posX, posY, posX + 88, posY + 20, 822018048); + } + + ItemStack baseCostA = merchantoffer.getBaseCostA(); + ItemStack costA = merchantoffer.getCostA(); + ItemStack costB = merchantoffer.getCostB(); + ItemStack result = merchantoffer.getResult(); + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(0.0F, 0.0F, 100.0F); + + if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { + + RenderSystem.depthFunc(516); + guiGraphics.fill(posX, posY, posX + 88, posY + 20, 822083583); + RenderSystem.depthFunc(515); + } + + this.renderAndDecorateCostA(guiGraphics, posX, posY, baseCostA, costA); + + if (!costB.isEmpty()) { + guiGraphics.renderFakeItem(costB, posX + 35, posY + 1); + guiGraphics.renderItemDecorations(this.font, costB, posX + 35, posY + 1); + } + + guiGraphics.renderFakeItem(result, posX + 68, posY + 1); + guiGraphics.renderItemDecorations(this.font, result, posX + 68, posY + 1); + guiGraphics.pose().popPose(); + posY += 20; + } + } + + final MerchantOffer activeOffer = merchantoffers.get(shopItem); + if (this.getMenu().showProgressBar()) { + + ((MerchantScreenAccessor) this).tradingpost$callRenderProgressBar(guiGraphics, width, height, activeOffer); + } + + if (activeOffer.isOutOfStock() && this.isHovering(186, 35, 22, 21, mouseX, mouseY) && this.getMenu().canRestock()) { + + guiGraphics.renderTooltip(this.font, DEPRECATED_TOOLTIP, mouseX, mouseY); + } + + posY = height + 16 + 2; + for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { + + if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { + + MerchantOffer merchantoffer = merchantoffers.get(i); + if (!this.getMenu().getTraders().checkOffer(merchantoffer)) { + + if (this.isHovering(posX, posY, 88, 19, mouseX + this.leftPos, mouseY + this.topPos)) { + + guiGraphics.renderTooltip(this.font, MERCHANT_GONE, mouseX, mouseY); + } + } + + posY += 20; + } + } + RenderSystem.enableDepthTest(); + } + + // move this out of if block above since search may update this + Button[] offerButtons = this.tradeOfferButtons; + for (int i = 0, offerButtonsLength = offerButtons.length; i < offerButtonsLength; i++) { + + Button button = offerButtons[i]; + if (button.active && button.isHoveredOrFocused()) { + + ((TradeOfferButtonAccessor) button).tradingpost$callRenderToolTip(guiGraphics, mouseX, mouseY); + } + + button.visible = i < this.getMenu().getOffers().size(); + } + + this.renderTooltip(guiGraphics, mouseX, mouseY); + } + + private void renderAndDecorateCostA(GuiGraphics guiGraphics, int posX, int posY, ItemStack baseCostA, ItemStack costA) { + guiGraphics.renderFakeItem(costA, posX + 5, posY + 1); + if (baseCostA.getCount() == costA.getCount()) { + guiGraphics.renderItemDecorations(this.font, costA, posX + 5, posY + 1); + } else { + guiGraphics.renderItemDecorations(this.font, baseCostA, posX + 5, posY + 1, baseCostA.getCount() == 1 ? "1" : null); + guiGraphics.renderItemDecorations(this.font, costA, posX + 5 + 14, posY + 1, costA.getCount() == 1 ? "1" : null); + guiGraphics.pose().pushPose(); + guiGraphics.pose().translate(0.0F, 0.0F, 300.0F); + guiGraphics.blit(VILLAGER_LOCATION, posX + 5 + 7, posY + 1 + 12, 0, 0.0F, 176.0F, 9, 2, 512, 256); + guiGraphics.pose().popPose(); + } + } + + private void setButtonsActive(MerchantOffers merchantoffers) { + + if (!merchantoffers.isEmpty()) { + + for (int i = 0, merchantoffersSize = merchantoffers.size(); i < merchantoffersSize; i++) { + + int scrollOff = ((MerchantScreenAccessor) this).tradingpost$getScrollOff(); + if (merchantoffers.size() <= 7 || (i >= scrollOff && i < 7 + scrollOff)) { + + MerchantOffer offer = merchantoffers.get(i); + this.tradeOfferButtons[i - scrollOff].active = this.getMenu().getTraders().checkOffer(offer); + } + } + } + } + + private void lock(boolean lockOffers, int newScrollOff, Slot newHoveredSlot) { + + this.getMenu().lockOffers(lockOffers); + ((MerchantScreenAccessor) this).tradingpost$setScrollOff(newScrollOff); + this.hoveredSlot = newHoveredSlot; + } + + @Override + protected void renderBg(GuiGraphics guiGraphics, float partialTicks, int mouseX, int mouseY) { + super.renderBg(guiGraphics, partialTicks, mouseX, mouseY); + this.renderSearchBox(guiGraphics, partialTicks, mouseX, mouseY); + TextureAtlasSprite atlasSprite = this.minecraft.getTextureAtlas(InventoryMenu.BLOCK_ATLAS).apply(MAGNIFYING_GLASS_LOCATION); + guiGraphics.blit(this.leftPos, this.topPos + 4, 0, 16, 16, atlasSprite); + RenderSystem.setShader(GameRenderer::getPositionTexShader); + RenderSystem.setShaderTexture(0, VILLAGER_LOCATION); + } + + private void renderSearchBox(GuiGraphics guiGraphics, float partialTicks, int mouseX, int mouseY) { + int i = (this.width - this.imageWidth) / 2; + int j = (this.height - this.imageHeight) / 2; + guiGraphics.blit(CREATIVE_INVENTORY_LOCATION, i + 11, j + 4, 0, 80.0F, 4.0F, 90, 12, 256, 256); + this.searchBox.render(guiGraphics, mouseX, mouseY, partialTicks); + } + + @Override + public boolean mouseClicked(double mouseX, double mouseY, int mouseKey) { + if (this.searchBox.mouseClicked(mouseX, mouseY, mouseKey)) { + return true; + } + return super.mouseClicked(mouseX, mouseY, mouseKey); + } + + @Override + protected void containerTick() { + this.searchBox.tick(); + } + + @Override + public boolean keyPressed(int keyCode, int scanCode, int modifierKeys) { + this.ignoreTextInput = false; + final String lastSearch = this.searchBox.getValue().trim(); + if (this.searchBox.keyPressed(keyCode, scanCode, modifierKeys)) { + + if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { + + this.refreshSearchResults(); + } + + return true; + } else if (this.searchBox.isFocused() && this.searchBox.isVisible() && keyCode != 256) { + return true; + } else if (this.minecraft.options.keyChat.matches(keyCode, scanCode) && !this.searchBox.isFocused()) { + this.ignoreTextInput = true; + this.searchBox.setFocused(true); + return true; + } + return super.keyPressed(keyCode, scanCode, modifierKeys); + } + + @Override + public boolean charTyped(char typedChar, int modifierKeys) { + + final String lastSearch = this.searchBox.getValue().trim(); + if (!this.ignoreTextInput && this.searchBox.charTyped(typedChar, modifierKeys)) { + + if (!Objects.equals(this.searchBox.getValue().trim(), lastSearch)) { + + this.refreshSearchResults(); + } + + return true; + } + + return super.charTyped(typedChar, modifierKeys); + } + + public void refreshSearchResults() { + + if (!(this.getMenu().getOffers() instanceof TradingPostOffers offers)) { + return; + } + String query = this.searchBox.getValue().trim(); + if (query.isEmpty()) { + offers.clearFilter(); + } else { + SearchTree isearchtree = this.minecraft.getSearchTree(OFFER_SEARCH_TREE); + offers.setFilter(isearchtree.search(query.toLowerCase(Locale.ROOT))); + } + ((MerchantScreenAccessor) this).tradingpost$setScrollOff(0); + ((MerchantScreenAccessor) this).tradingpost$setShopItem(0); + this.getMenu().setSelectionHint(-1); + this.getMenu().getTraders().setActiveOffer(null); + this.getMenu().clearPaymentSlots(); + TradingPost.NETWORK.sendToServer(new C2SClearSlotsMessage()); + } + + @Override + public TradingPostMenu getMenu() { + + return (TradingPostMenu) super.getMenu(); + } + +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java new file mode 100644 index 0000000..5aa684e --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/client/renderer/blockentity/TradingPostRenderer.java @@ -0,0 +1,58 @@ +package fuzs.tradingpost.client.renderer.blockentity; + +import com.mojang.blaze3d.vertex.PoseStack; +import com.mojang.math.Axis; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.client.Minecraft; +import net.minecraft.client.renderer.MultiBufferSource; +import net.minecraft.client.renderer.blockentity.BlockEntityRenderer; +import net.minecraft.client.renderer.blockentity.BlockEntityRendererProvider; +import net.minecraft.client.renderer.entity.ItemRenderer; +import net.minecraft.util.Mth; +import net.minecraft.world.item.ItemDisplayContext; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.Items; +import net.minecraft.world.level.Level; + +/** + * Mostly copied from Quark's MatrixEnchantingTableRenderer.java by Vazkii, thanks! + */ +public class TradingPostRenderer implements BlockEntityRenderer { + + public TradingPostRenderer(BlockEntityRendererProvider.Context context) { + + } + + @Override + public void render(TradingPostBlockEntity blockEntity, float partialTicks, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn) { + float ageInTicks = blockEntity.time + partialTicks; + float nextRotation = blockEntity.rot - blockEntity.oRot; + while (nextRotation >= Math.PI) { + nextRotation -= (Math.PI * 2F); + } + while (nextRotation < -Math.PI) { + nextRotation += (Math.PI * 2F); + } + float bookRotation = blockEntity.oRot + nextRotation * partialTicks; + float bookOpen = Mth.lerp(partialTicks, blockEntity.oOpen, blockEntity.open); + this.renderItem(new ItemStack(Items.EMERALD), ageInTicks, bookOpen, bookRotation, matrixStackIn, bufferIn, combinedLightIn, combinedOverlayIn, blockEntity.getLevel()); + } + + private void renderItem(ItemStack stack, float ageInTicks, float bookOpen, float bookRotation, PoseStack matrixStackIn, MultiBufferSource bufferIn, int combinedLightIn, int combinedOverlayIn, Level level) { + matrixStackIn.pushPose(); + matrixStackIn.translate(0.5F, 1.03125F, 0.5F); + matrixStackIn.scale(0.8F, 0.8F, 0.8F); + bookRotation *= -180.0F / (float) Math.PI; + bookRotation -= 90.0F; + bookRotation *= bookOpen; + matrixStackIn.mulPose(Axis.YP.rotationDegrees(bookRotation)); + matrixStackIn.translate(0.0F, bookOpen, Math.sin(bookOpen * Math.PI)); + matrixStackIn.mulPose(Axis.XP.rotationDegrees(-90.0F * (bookOpen - 1.0F))); + float hoveringHeight = (float) Math.sin(ageInTicks * 0.06F) * bookOpen * 0.2F; + matrixStackIn.translate(0.0F, hoveringHeight, 0.0F); + ItemRenderer itemRenderer = Minecraft.getInstance().getItemRenderer(); + itemRenderer.renderStatic(stack, ItemDisplayContext.FIXED, combinedLightIn, combinedOverlayIn, matrixStackIn, bufferIn, level, 0); + matrixStackIn.popPose(); + } + +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java new file mode 100644 index 0000000..936d6a4 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/config/ServerConfig.java @@ -0,0 +1,35 @@ +package fuzs.tradingpost.config; + +import com.google.common.collect.Lists; +import fuzs.puzzleslib.api.config.v3.Config; +import fuzs.puzzleslib.api.config.v3.ConfigCore; +import fuzs.puzzleslib.api.config.v3.serialization.ConfigDataSet; +import fuzs.tradingpost.TradingPost; +import net.minecraft.core.registries.Registries; +import net.minecraft.world.entity.EntityType; + +import java.util.List; + +public class ServerConfig implements ConfigCore { + @Config(description = "Range on xz plane trading post should search for merchants.") + @Config.IntRange(min = 1, max = 96) + public int horizontalRange = 24; + @Config(description = "Range on y axis trading post should search for merchants.") + @Config.IntRange(min = 1, max = 96) + public int verticalRange = 16; + @Config(description = "Disable traders on the trading screen when they wander out of range.") + public boolean enforceRange = false; + @Config(description = "Teleport xp from trading from villagers on top of the trading post.") + public boolean teleportXp = true; + @Config(name = "close_empty_screen", description = "Close trading post interface when all traders have become unavailable.") + public boolean closeScreen = true; + @Config(name = "trader_blacklist", description = {"Trader entities disabled from being found by the trading post.", "Modders may add their own incompatible trader entities via the \"" + TradingPost.MOD_ID + ":blacklisted_traders\" entity tag.", ConfigDataSet.CONFIG_DESCRIPTION}) + List traderBlacklistRaw = Lists.newArrayList(); + + public ConfigDataSet> traderBlacklist; + + @Override + public void afterConfigReload() { + this.traderBlacklist = ConfigDataSet.from(Registries.ENTITY_TYPE, this.traderBlacklistRaw); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java new file mode 100644 index 0000000..b01649b --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/init/ModRegistry.java @@ -0,0 +1,32 @@ +package fuzs.tradingpost.init; + +import fuzs.puzzleslib.api.init.v2.RegistryManager; +import fuzs.puzzleslib.api.init.v2.RegistryReference; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.tags.TagKey; +import net.minecraft.world.entity.EntityType; +import net.minecraft.world.inventory.MenuType; +import net.minecraft.world.item.Item; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.SoundType; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockBehaviour; +import net.minecraft.world.level.block.state.properties.NoteBlockInstrument; +import net.minecraft.world.level.material.MapColor; + +public class ModRegistry { + static final RegistryManager REGISTRY = RegistryManager.instant(TradingPost.MOD_ID); + public static final RegistryReference TRADING_POST_BLOCK = REGISTRY.registerBlock("trading_post", () -> new TradingPostBlock(BlockBehaviour.Properties.of().mapColor(MapColor.WOOD).instrument(NoteBlockInstrument.BASS).strength(2.5F).sound(SoundType.WOOD).ignitedByLava())); + public static final RegistryReference TRADING_POST_ITEM = REGISTRY.registerBlockItem(TRADING_POST_BLOCK); + public static final RegistryReference> TRADING_POST_BLOCK_ENTITY_TYPE = REGISTRY.registerBlockEntityType("trading_post", () -> BlockEntityType.Builder.of(TradingPostBlockEntity::new, TRADING_POST_BLOCK.get())); + public static final RegistryReference> TRADING_POST_MENU_TYPE = REGISTRY.registerMenuType("trading_post", () -> TradingPostMenu::new); + + public static final TagKey> BLACKLISTED_TRADERS_TAG = REGISTRY.registerEntityTypeTag("blacklisted_traders"); + + public static void touch() { + + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java new file mode 100644 index 0000000..bb02a91 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/MerchantMenuAccessor.java @@ -0,0 +1,20 @@ +package fuzs.tradingpost.mixin.accessor; + +import net.minecraft.world.inventory.MerchantContainer; +import net.minecraft.world.inventory.MerchantMenu; +import net.minecraft.world.item.trading.Merchant; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(MerchantMenu.class) +public interface MerchantMenuAccessor { + + @Mutable + @Accessor + void setTrader(Merchant trader); + + @Mutable + @Accessor + void setTradeContainer(MerchantContainer tradeContainer); +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java new file mode 100644 index 0000000..730cccc --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/accessor/VillagerAccessor.java @@ -0,0 +1,13 @@ +package fuzs.tradingpost.mixin.accessor; + +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.entity.player.Player; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(Villager.class) +public interface VillagerAccessor { + + @Invoker + void callUpdateSpecialPrices(Player player); +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java new file mode 100644 index 0000000..5f844e7 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/ButtonAccessor.java @@ -0,0 +1,14 @@ +package fuzs.tradingpost.mixin.client.accessor; + +import net.minecraft.client.gui.components.Button; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Mutable; +import org.spongepowered.asm.mixin.gen.Accessor; + +@Mixin(Button.class) +public interface ButtonAccessor { + + @Mutable + @Accessor("onPress") + void tradingpost$setOnPress(Button.OnPress onPress); +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java new file mode 100644 index 0000000..a67dadd --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/MerchantScreenAccessor.java @@ -0,0 +1,34 @@ +package fuzs.tradingpost.mixin.client.accessor; + +import net.minecraft.client.gui.GuiGraphics; +import net.minecraft.client.gui.screens.inventory.MerchantScreen; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(MerchantScreen.class) +public interface MerchantScreenAccessor { + + @Accessor("shopItem") + int tradingpost$getShopItem(); + + @Accessor("shopItem") + void tradingpost$setShopItem(int shopItem); + + @Accessor("scrollOff") + int tradingpost$getScrollOff(); + + @Accessor("scrollOff") + void tradingpost$setScrollOff(int scrollOff); + + @Invoker("renderScroller") + void tradingpost$callRenderScroller(GuiGraphics guiGraphics, int width, int height, MerchantOffers offers); + + @Invoker("renderButtonArrows") + void tradingpost$callRenderButtonArrows(GuiGraphics guiGraphics, MerchantOffer offer, int width, int height); + + @Invoker("renderProgressBar") + void tradingpost$callRenderProgressBar(GuiGraphics guiGraphics, int width, int height, MerchantOffer activeOffer); +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java new file mode 100644 index 0000000..99e17d4 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/mixin/client/accessor/TradeOfferButtonAccessor.java @@ -0,0 +1,16 @@ +package fuzs.tradingpost.mixin.client.accessor; + +import net.minecraft.client.gui.GuiGraphics; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.gen.Accessor; +import org.spongepowered.asm.mixin.gen.Invoker; + +@Mixin(targets = "net.minecraft.client.gui.screens.inventory.MerchantScreen$TradeOfferButton") +public interface TradeOfferButtonAccessor { + + @Accessor("index") + int tradingpost$getIndex(); + + @Invoker("renderToolTip") + void tradingpost$callRenderToolTip(GuiGraphics guiGraphics, int mouseX, int mouseY); +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java new file mode 100644 index 0000000..a892cec --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CBuildOffersMessage.java @@ -0,0 +1,61 @@ +package fuzs.tradingpost.network; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import it.unimi.dsi.fastutil.ints.Int2IntMap; +import it.unimi.dsi.fastutil.ints.Int2IntOpenHashMap; +import net.minecraft.client.Minecraft; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; + +public class S2CBuildOffersMessage implements MessageV2 { + private int containerId; + private Int2IntOpenHashMap idToOfferCount; + + public S2CBuildOffersMessage() { + + } + + public S2CBuildOffersMessage(int containerId, Int2IntOpenHashMap idToOfferCount) { + this.containerId = containerId; + this.idToOfferCount = idToOfferCount; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(this.containerId); + buf.writeVarInt(this.idToOfferCount.size()); + for (Int2IntMap.Entry entry : this.idToOfferCount.int2IntEntrySet()) { + buf.writeInt(entry.getIntKey()); + buf.writeVarInt(entry.getIntValue()); + } + } + + @Override + public void read(FriendlyByteBuf buf) { + this.containerId = buf.readVarInt(); + final Int2IntOpenHashMap idToOfferCount = new Int2IntOpenHashMap(); + final int length = buf.readVarInt(); + for (int i = 0; i < length; i++) { + idToOfferCount.put(buf.readInt(), buf.readVarInt()); + } + this.idToOfferCount = idToOfferCount; + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CBuildOffersMessage message, Player player, Object gameInstance) { + Minecraft minecraft = (Minecraft) gameInstance; + if (message.containerId == player.containerMenu.containerId && player.containerMenu instanceof TradingPostMenu playerMenu && minecraft.screen instanceof TradingPostScreen screen) { + playerMenu.getTraders().buildOffers(message.idToOfferCount); + minecraft.populateSearchTree(TradingPostScreen.OFFER_SEARCH_TREE, playerMenu.getOffers()); + screen.refreshSearchResults(); + } + } + }; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java new file mode 100644 index 0000000..91c9727 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CMerchantDataMessage.java @@ -0,0 +1,73 @@ +package fuzs.tradingpost.network; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; +import net.minecraft.world.item.trading.MerchantOffers; + +public class S2CMerchantDataMessage implements MessageV2 { + private int containerId; + private int merchantId; + private Component merchantTitle; + private MerchantOffers offers; + private int villagerLevel; + private int villagerXp; + private boolean showProgress; + private boolean canRestock; + + public S2CMerchantDataMessage() { + + } + + public S2CMerchantDataMessage(int containerId, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { + this.containerId = containerId; + this.merchantId = merchantId; + this.merchantTitle = merchantTitle; + this.offers = offers; + this.villagerLevel = villagerLevel; + this.villagerXp = villagerXp; + this.showProgress = showProgress; + this.canRestock = canRestock; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(this.containerId); + buf.writeInt(this.merchantId); + buf.writeComponent(this.merchantTitle); + this.offers.writeToStream(buf); + buf.writeVarInt(this.villagerLevel); + buf.writeVarInt(this.villagerXp); + buf.writeBoolean(this.showProgress); + buf.writeBoolean(this.canRestock); + } + + @Override + public void read(FriendlyByteBuf buf) { + this.containerId = buf.readVarInt(); + this.merchantId = buf.readInt(); + this.merchantTitle = buf.readComponent(); + this.offers = MerchantOffers.createFromStream(buf); + this.villagerLevel = buf.readVarInt(); + this.villagerXp = buf.readVarInt(); + this.showProgress = buf.readBoolean(); + this.canRestock = buf.readBoolean(); + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CMerchantDataMessage packet, Player player, Object gameInstance) { + AbstractContainerMenu container = player.containerMenu; + if (packet.containerId == container.containerId && container instanceof TradingPostMenu) { + ((TradingPostMenu) container).addMerchant(player, packet.merchantId, packet.merchantTitle, new MerchantOffers(packet.offers.createTag()), packet.villagerLevel, packet.villagerXp, packet.showProgress, packet.canRestock); + } + } + }; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java new file mode 100644 index 0000000..8aa0653 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/S2CRemoveMerchantsMessage.java @@ -0,0 +1,59 @@ +package fuzs.tradingpost.network; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import it.unimi.dsi.fastutil.ints.IntOpenHashSet; +import it.unimi.dsi.fastutil.ints.IntSet; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; + +public class S2CRemoveMerchantsMessage implements MessageV2 { + private int containerId; + private IntSet merchantIds; + + public S2CRemoveMerchantsMessage() { + + } + + public S2CRemoveMerchantsMessage(int containerId, IntSet merchantIds) { + this.containerId = containerId; + this.merchantIds = merchantIds; + } + + @Override + public void write(FriendlyByteBuf buf) { + buf.writeVarInt(this.containerId); + buf.writeVarInt(this.merchantIds.size()); + for (int merchantId : this.merchantIds) { + buf.writeInt(merchantId); + } + } + + @Override + public void read(FriendlyByteBuf buf) { + this.containerId = buf.readVarInt(); + int length = buf.readVarInt(); + IntSet merchantIds = new IntOpenHashSet(); + for (int i = 0; i < length; i++) { + merchantIds.add(buf.readInt()); + } + this.merchantIds = merchantIds; + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(S2CRemoveMerchantsMessage packet, Player player, Object gameInstance) { + AbstractContainerMenu container = player.containerMenu; + if (packet.containerId == container.containerId && container instanceof TradingPostMenu) { + for (int merchantId : packet.merchantIds) { + ((TradingPostMenu) container).getTraders().removeMerchant(merchantId); + } + } + } + }; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java new file mode 100644 index 0000000..ba5d25a --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/network/client/C2SClearSlotsMessage.java @@ -0,0 +1,34 @@ +package fuzs.tradingpost.network.client; + +import fuzs.puzzleslib.api.network.v2.MessageV2; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import net.minecraft.network.FriendlyByteBuf; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.AbstractContainerMenu; + +public class C2SClearSlotsMessage implements MessageV2 { + + @Override + public void write(FriendlyByteBuf buf) { + + } + + @Override + public void read(FriendlyByteBuf buf) { + + } + + @Override + public MessageHandler makeHandler() { + return new MessageHandler<>() { + + @Override + public void handle(C2SClearSlotsMessage packet, Player player, Object gameInstance) { + AbstractContainerMenu container = player.containerMenu; + if (container instanceof TradingPostMenu) { + ((TradingPostMenu) container).clearPaymentSlots(); + } + } + }; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java new file mode 100644 index 0000000..3c7a430 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/LocalMerchant.java @@ -0,0 +1,42 @@ +package fuzs.tradingpost.world.entity.npc; + +import net.minecraft.network.chat.Component; +import net.minecraft.world.entity.npc.ClientSideMerchant; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.trading.MerchantOffers; + +public class LocalMerchant extends ClientSideMerchant { + private final Component merchantTitle; + private final int merchantLevel; + private final boolean showProgressBar; + private final boolean canRestock; + + public LocalMerchant(Player playerEntity, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { + super(playerEntity); + this.merchantTitle = merchantTitle; + this.overrideOffers(offers); + this.merchantLevel = villagerLevel; + this.overrideXp(villagerXp); + this.showProgressBar = showProgress; + this.canRestock = canRestock; + } + + public Component getDisplayName() { + return this.merchantTitle; + } + + public int getMerchantLevel() { + return this.merchantLevel; + } + + @Override + public boolean canRestock() { + return this.canRestock; + } + + @Override + public boolean showProgressBar() { + return this.showProgressBar; + } + +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java new file mode 100644 index 0000000..b0488aa --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/entity/npc/MerchantCollection.java @@ -0,0 +1,286 @@ +package fuzs.tradingpost.world.entity.npc; + +import com.google.common.collect.Lists; +import com.google.common.collect.Sets; +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.network.S2CBuildOffersMessage; +import fuzs.tradingpost.network.S2CMerchantDataMessage; +import fuzs.tradingpost.network.S2CRemoveMerchantsMessage; +import fuzs.tradingpost.world.item.trading.TradingPostOffers; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import it.unimi.dsi.fastutil.ints.*; +import it.unimi.dsi.fastutil.objects.Object2ObjectOpenHashMap; +import net.minecraft.core.BlockPos; +import net.minecraft.network.chat.Component; +import net.minecraft.server.level.ServerPlayer; +import net.minecraft.sounds.SoundEvent; +import net.minecraft.sounds.SoundEvents; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.ExperienceOrb; +import net.minecraft.world.entity.npc.VillagerDataHolder; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.Merchant; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.Vec3; +import org.jetbrains.annotations.Nullable; + +import java.util.Comparator; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.function.IntConsumer; +import java.util.stream.Collectors; + +public class MerchantCollection implements Merchant { + private final Int2ObjectOpenHashMap idToMerchant = new Int2ObjectOpenHashMap<>(); + private final Set disabledOffers = Sets.newHashSet(); + private final ContainerLevelAccess access; + + private MerchantOffers allOffers = new MerchantOffers(); + private Object2ObjectOpenHashMap offerToMerchant; + private Merchant currentMerchant; + + public MerchantCollection() { + this(ContainerLevelAccess.NULL); + } + + public MerchantCollection(ContainerLevelAccess access) { + this.access = access; + } + + public void addMerchant(int entityId, Merchant merchant) { + if (!merchant.getOffers().isEmpty()) { + this.idToMerchant.put(entityId, merchant); + } + } + + @Override + @Nullable + public Player getTradingPlayer() { + if (this.currentMerchant != null) { + return this.currentMerchant.getTradingPlayer(); + } + return null; + } + + @Override + public void setTradingPlayer(@Nullable Player player) { + this.idToMerchant.values().forEach(merchant -> merchant.setTradingPlayer(player)); + } + + @Override + public MerchantOffers getOffers() { + return this.allOffers; + } + + public boolean checkOffer(MerchantOffer offer) { + return !this.disabledOffers.contains(offer); + } + + @Override + public void overrideOffers(@Nullable MerchantOffers p_213703_1_) { + // this is vanilla, we do this differently + TradingPost.LOGGER.error("Set offers to stored merchants directly"); + } + + @Override + public void notifyTrade(MerchantOffer offer) { + if (this.currentMerchant != null) { + this.currentMerchant.notifyTrade(offer); + if (!TradingPost.CONFIG.get(ServerConfig.class).teleportXp) return; + // reward xp is spawned at trader location, find it and move to trading post + this.access.execute((level, pos) -> { + + if (this.currentMerchant instanceof Entity entity) { + + Vec3 merchantPos = entity.position().add(0.0, 0.5, 0.0); + final double xpWidth = 0.5, xpHeight = 0.5; + List xpRewards = level.getEntitiesOfClass(ExperienceOrb.class, new AABB(merchantPos.add(-xpWidth, -xpHeight, -xpWidth), merchantPos.add(xpWidth, xpHeight, xpWidth)), Entity::isAlive); + // move xp would be much nicer, unfortunately it'd only be moved on the server, so orbs need to be removed and spawned in again + for (ExperienceOrb xpOrb : xpRewards) { + level.addFreshEntity(new ExperienceOrb(level, pos.getX(), pos.getY() + 1.5, pos.getZ(), xpOrb.getValue())); + xpOrb.discard(); + } + } + }); + } + } + + @Override + public void notifyTradeUpdated(ItemStack stack) { + if (this.currentMerchant != null) { + this.currentMerchant.notifyTradeUpdated(stack); + } + } + + @Override + public boolean isClientSide() { + return this.access == ContainerLevelAccess.NULL; + } + + @Override + public int getVillagerXp() { + if (this.currentMerchant != null) { + return this.currentMerchant.getVillagerXp(); + } + return 0; + } + + public Merchant getCurrentMerchant() { + return this.currentMerchant; + } + + @Override + public boolean canRestock() { + if (this.currentMerchant != null) { + return this.currentMerchant.canRestock(); + } + return false; + } + + @Override + public void overrideXp(int xpValue) { + if (this.currentMerchant != null) { + this.currentMerchant.overrideXp(xpValue); + } + } + + @Override + public boolean showProgressBar() { + if (this.currentMerchant != null) { + return this.currentMerchant.showProgressBar(); + } + return false; + } + + @Override + public SoundEvent getNotifyTradeSound() { + if (this.currentMerchant != null) { + return this.currentMerchant.getNotifyTradeSound(); + } + // unused by client, just a dummy + return SoundEvents.VILLAGER_YES; + } + + public int getTraderLevel() { + if (this.currentMerchant != null) { + Merchant merchant = this.currentMerchant; + if (merchant instanceof LocalMerchant) { + return ((LocalMerchant) merchant).getMerchantLevel(); + } else if (merchant instanceof VillagerDataHolder) { + return ((VillagerDataHolder) merchant).getVillagerData().getLevel(); + } + } + return 0; + } + + @Nullable + public Component getDisplayName() { + if (this.currentMerchant != null) { + Merchant merchant = this.currentMerchant; + if (merchant instanceof LocalMerchant) { + return ((LocalMerchant) merchant).getDisplayName(); + } else if (merchant instanceof Entity) { + return ((Entity) merchant).getDisplayName(); + } + } + return null; + } + + public boolean updateAvailableMerchants(int containerId, BlockPos pos, Player player, boolean testRange) { + IntSet toRemove = new IntOpenHashSet(); + for (Map.Entry entry : this.idToMerchant.int2ObjectEntrySet()) { + if (entry.getValue() instanceof Entity) { + if (entry.getValue().getTradingPlayer() != player || testRange && !this.traderInRange((Entity) entry.getValue(), pos)) { + toRemove.add(entry.getKey().intValue()); + } + } + } + if (!toRemove.isEmpty()) { + toRemove.forEach((IntConsumer) this::removeMerchant); + TradingPost.NETWORK.sendTo(new S2CRemoveMerchantsMessage(containerId, toRemove), (ServerPlayer) player); + } + return !this.idToMerchant.isEmpty(); + } + + private boolean traderInRange(Entity entity, BlockPos pos) { + return this.traderInRange(entity, pos.getX() + 0.5, pos.getY() + 0.5, pos.getZ() + 0.5); + } + + private boolean traderInRange(Entity entity, double posX, double posY, double posZ) { + return Math.abs(entity.getX() - posX) <= TradingPost.CONFIG.get(ServerConfig.class).horizontalRange && Math.abs(entity.getY() - posY) <= TradingPost.CONFIG.get(ServerConfig.class).verticalRange && Math.abs(entity.getZ() - posZ) <= TradingPost.CONFIG.get(ServerConfig.class).horizontalRange; + } + + public void removeMerchant(int merchantId) { + Merchant merchant = this.idToMerchant.get(merchantId); + if (merchant != null) { + this.disabledOffers.addAll(merchant.getOffers()); + this.idToMerchant.remove(merchantId); + merchant.setTradingPlayer(null); + if (this.currentMerchant == merchant) { + this.currentMerchant = null; + } + } + } + + public void setActiveOffer(MerchantOffer offer) { + if (this.offerToMerchant != null) { + this.currentMerchant = offer != null ? this.offerToMerchant.get(offer) : null; + } + } + + public void sendMerchantData(final int containerId, Player player) { + for (Map.Entry entry : this.idToMerchant.int2ObjectEntrySet()) { + Merchant merchant = entry.getValue(); + final Component merchantTitle = merchant instanceof Entity ? ((Entity) merchant).getDisplayName() : TradingPostBlock.CONTAINER_TITLE; + final int merchantLevel = merchant instanceof VillagerDataHolder ? ((VillagerDataHolder) merchant).getVillagerData().getLevel() : 0; + S2CMerchantDataMessage message = new S2CMerchantDataMessage(containerId, entry.getKey(), merchantTitle, merchant.getOffers(), merchantLevel, merchant.getVillagerXp(), merchant.showProgressBar(), merchant.canRestock()); + TradingPost.NETWORK.sendTo(message, (ServerPlayer) player); + } + TradingPost.NETWORK.sendTo(new S2CBuildOffersMessage(containerId, this.getIdToOfferCountMap()), (ServerPlayer) player); + } + + public Int2IntOpenHashMap getIdToOfferCountMap() { + return this.idToMerchant.int2ObjectEntrySet().stream() + .collect(Collectors.toMap(Int2ObjectMap.Entry::getIntKey, entry -> entry.getValue().getOffers().size(), (o1, o2) -> o1, Int2IntOpenHashMap::new)); + } + + public void buildOffers(Int2IntOpenHashMap idToOfferCount) { + List sortedEntries = Lists.newArrayList(idToOfferCount.int2IntEntrySet()); + sortedEntries.sort(Comparator.comparingInt(Int2IntMap.Entry::getIntKey)); + MerchantOffers allOffers = new TradingPostOffers(this.disabledOffers); + for (Int2IntMap.Entry entry : sortedEntries) { + Merchant merchant = this.idToMerchant.get(entry.getIntKey()); + for (int i = 0; i < entry.getIntValue(); i++) { + MerchantOffer offer; + if (merchant != null && i < merchant.getOffers().size()) { + offer = merchant.getOffers().get(i); + } else { + // this should never actually happen, but you never know with mods + offer = fakeOffer(); + this.disabledOffers.add(offer); + } + allOffers.add(offer); + } + } + this.allOffers = allOffers; + this.buildOfferToMerchantMap(); + } + + private void buildOfferToMerchantMap() { + Object2ObjectOpenHashMap offerToMerchant = new Object2ObjectOpenHashMap<>(); + for (Merchant merchant : this.idToMerchant.values()) { + merchant.getOffers().forEach(offer -> offerToMerchant.put(offer, merchant)); + } + this.offerToMerchant = offerToMerchant; + } + + private static MerchantOffer fakeOffer() { + return new MerchantOffer(ItemStack.EMPTY, ItemStack.EMPTY, -1, -1, 0.0F); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java new file mode 100644 index 0000000..7a1cd60 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostContainer.java @@ -0,0 +1,22 @@ +package fuzs.tradingpost.world.inventory; + +import fuzs.tradingpost.world.entity.npc.MerchantCollection; +import net.minecraft.world.inventory.MerchantContainer; + +public class TradingPostContainer extends MerchantContainer { + private final MerchantCollection merchant; + + public TradingPostContainer(MerchantCollection merchant) { + super(merchant); + this.merchant = merchant; + this.setSelectionHint(-1); + } + + @Override + public void updateSellItem() { + super.updateSellItem(); + if (this.getActiveOffer() != null) { + this.merchant.setActiveOffer(this.getActiveOffer()); + } + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java new file mode 100644 index 0000000..bb7a64b --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/inventory/TradingPostMenu.java @@ -0,0 +1,200 @@ +package fuzs.tradingpost.world.inventory; + +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.mixin.accessor.MerchantMenuAccessor; +import fuzs.tradingpost.world.entity.npc.LocalMerchant; +import fuzs.tradingpost.world.entity.npc.MerchantCollection; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import net.minecraft.network.chat.Component; +import net.minecraft.sounds.SoundSource; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.player.Inventory; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.*; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.Merchant; +import net.minecraft.world.item.trading.MerchantOffers; + +import java.util.Optional; + +public class TradingPostMenu extends MerchantMenu { + private final ContainerLevelAccess access; + private final MerchantCollection traders; + private final MerchantContainer tradeContainer; + + private int ticks; + private boolean lockOffers; + + public TradingPostMenu(int containerId, Inventory inventory) { + this(containerId, inventory, new MerchantCollection(), ContainerLevelAccess.NULL); + } + + public TradingPostMenu(int containerId, Inventory inventory, MerchantCollection merchantCollection, ContainerLevelAccess worldPosCallable) { + super(containerId, inventory, merchantCollection); + this.access = worldPosCallable; + this.traders = merchantCollection; + ((MerchantMenuAccessor) this).setTrader(this.traders); + this.tradeContainer = new TradingPostContainer(this.traders); + ((MerchantMenuAccessor) this).setTradeContainer(this.tradeContainer); + this.replaceSlot(0, new Slot(this.tradeContainer, 0, 136, 37)); + this.replaceSlot(1, new Slot(this.tradeContainer, 1, 162, 37)); + this.replaceSlot(2, new MerchantResultSlot(inventory.player, this.traders, this.tradeContainer, 2, 220, 37)); + } + + private void replaceSlot(int index, Slot slot) { + slot.index = index; + this.slots.set(index, slot); + } + + @Override + public MenuType getType() { + return ModRegistry.TRADING_POST_MENU_TYPE.get(); + } + + @Override + public boolean stillValid(Player player) { + // this also updates merchants, so run independent of config option + // don't want this to go off on every tick + Optional anyTrader = this.access.evaluate((level, pos) -> this.traders.updateAvailableMerchants(this.containerId, pos, player, TradingPost.CONFIG.get(ServerConfig.class).enforceRange && ++this.ticks >= 20)); + if (this.ticks >= 20) this.ticks = 0; + if (TradingPost.CONFIG.get(ServerConfig.class).closeScreen && anyTrader.isPresent() && !anyTrader.get()) { + player.displayClientMessage(TradingPostBlock.NO_MERCHANT_FOUND, false); + return false; + } + return stillValid(this.access, player, ModRegistry.TRADING_POST_BLOCK.get()); + } + + @Override + public ItemStack quickMoveStack(Player player, int slotIndex) { + ItemStack itemstack = ItemStack.EMPTY; + Slot slot = this.slots.get(slotIndex); + if (slot != null && slot.hasItem()) { + + ItemStack itemstack1 = slot.getItem(); + itemstack = itemstack1.copy(); + if (slotIndex == 2) { + + if (!this.moveItemStackTo(itemstack1, 3, 39, true)) { + + return ItemStack.EMPTY; + } + + slot.onQuickCraft(itemstack1, itemstack); + // only replace this, vanilla will throw ClassCastException due to MerchantCollection not being an entity + this.playTradeSound(); + } else { + + return super.quickMoveStack(player, slotIndex); + } + + if (itemstack1.isEmpty()) { + + slot.set(ItemStack.EMPTY); + } else { + + slot.setChanged(); + } + + if (itemstack1.getCount() == itemstack.getCount()) { + + return ItemStack.EMPTY; + } + + slot.onTake(player, itemstack1); + } + + return itemstack; + } + + private void playTradeSound() { + if (!this.traders.isClientSide()) { + Merchant merchant = this.traders.getCurrentMerchant(); + if (merchant instanceof Entity entity) { + entity.level().playLocalSound(entity.getX(), entity.getY(), entity.getZ(), this.traders.getNotifyTradeSound(), SoundSource.NEUTRAL, 1.0F, 1.0F, false); + } + } + } + + public void clearPaymentSlots() { + ItemStack itemstack = this.tradeContainer.getItem(0); + if (!itemstack.isEmpty()) { + if (!this.moveItemStackTo(itemstack, 3, 39, true)) { + return; + } + + this.tradeContainer.setItem(0, itemstack); + } + + ItemStack itemstack1 = this.tradeContainer.getItem(1); + if (!itemstack1.isEmpty()) { + if (!this.moveItemStackTo(itemstack1, 3, 39, true)) { + return; + } + + this.tradeContainer.setItem(1, itemstack1); + } + } + + @Override + public MerchantOffers getOffers() { + return this.lockOffers ? new MerchantOffers() : super.getOffers(); + } + + public MerchantCollection getTraders() { + return this.traders; + } + + public void lockOffers(boolean lock) { + this.lockOffers = lock; + } + + public void addMerchant(Player playerEntity, int merchantId, Component merchantTitle, MerchantOffers offers, int villagerLevel, int villagerXp, boolean showProgress, boolean canRestock) { + + LocalMerchant merchant = new LocalMerchant(playerEntity, merchantTitle, offers, villagerLevel, villagerXp, showProgress, canRestock); + this.traders.addMerchant(merchantId, merchant); + } + + @Override + public int getTraderLevel() { + + return this.traders.getTraderLevel(); + } + + @Override + public boolean canRestock() { + return this.traders.canRestock(); + } + + @Override + public boolean showProgressBar() { + return this.traders.showProgressBar(); + } + + @Override + public void setShowProgressBar(boolean showProgressBar) { + // we don't raise an exception anywhere here as you never know what other mods are up to since this extends vanilla's merchant menu + TradingPost.LOGGER.error("Operation setShowProgressBar no supported on trading post, set showProgressBar to merchants directly"); + } + + @Override + public void setXp(int xpValue) { + TradingPost.LOGGER.error("Operation setXp no supported on trading post, set xp to merchants directly"); + } + + @Override + public void setMerchantLevel(int merchantLevel) { + TradingPost.LOGGER.error("Operation setMerchantLevel no supported on trading post, set level to merchants directly"); + } + + @Override + public void setCanRestock(boolean canRestock) { + TradingPost.LOGGER.error("Operation setCanRestock no supported on trading post, set canRestock to merchants directly"); + } + + @Override + public void setOffers(MerchantOffers offers) { + TradingPost.LOGGER.error("Operation setOffers no supported on trading post, set offers to merchants directly"); + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java new file mode 100644 index 0000000..8bde01b --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/item/trading/TradingPostOffers.java @@ -0,0 +1,58 @@ +package fuzs.tradingpost.world.item.trading; + +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.trading.MerchantOffer; +import net.minecraft.world.item.trading.MerchantOffers; +import org.jetbrains.annotations.Nullable; + +import java.util.Collection; +import java.util.Set; + +public class TradingPostOffers extends MerchantOffers { + private final Set disabledOffers; + private int[] indexToShopItem; + + public TradingPostOffers(Set disabledOffers) { + this.disabledOffers = disabledOffers; + } + + @Nullable + @Override + public MerchantOffer getRecipeFor(ItemStack input1, ItemStack input2, int offerId) { + if (offerId >= 0 && offerId < this.size()) { + MerchantOffer offer = this.get(offerId); + return offer.satisfiedBy(input1, input2) && !this.disabledOffers.contains(offer) ? offer : null; + } + return null; + } + + @Override + public int size() { + return this.indexToShopItem != null ? this.indexToShopItem.length : super.size(); + } + + @Override + public boolean isEmpty() { + return this.size() == 0; + } + + @Override + public MerchantOffer get(int index) { + return super.get(this.indexToShopItem != null ? this.indexToShopItem[index] : index); + } + + public void setFilter(Collection activeOffers) { + this.indexToShopItem = activeOffers.stream() + .filter(this::contains) + .mapToInt(this::indexOf) + .toArray(); + } + + public void clearFilter() { + this.indexToShopItem = null; + } + + public int getOrigShopItem(int filteredShopItem) { + return this.indexToShopItem != null && filteredShopItem < this.indexToShopItem.length ? this.indexToShopItem[filteredShopItem] : filteredShopItem; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java new file mode 100644 index 0000000..9fd17c4 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/TradingPostBlock.java @@ -0,0 +1,182 @@ +package fuzs.tradingpost.world.level.block; + +import fuzs.tradingpost.TradingPost; +import fuzs.tradingpost.config.ServerConfig; +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.mixin.accessor.VillagerAccessor; +import fuzs.tradingpost.world.entity.npc.MerchantCollection; +import fuzs.tradingpost.world.inventory.TradingPostMenu; +import fuzs.tradingpost.world.level.block.entity.TradingPostBlockEntity; +import net.minecraft.core.BlockPos; +import net.minecraft.core.Direction; +import net.minecraft.network.chat.Component; +import net.minecraft.world.InteractionHand; +import net.minecraft.world.InteractionResult; +import net.minecraft.world.Nameable; +import net.minecraft.world.SimpleMenuProvider; +import net.minecraft.world.entity.Entity; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.npc.Villager; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.inventory.ContainerLevelAccess; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.item.context.BlockPlaceContext; +import net.minecraft.world.item.trading.Merchant; +import net.minecraft.world.level.BlockGetter; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.LevelAccessor; +import net.minecraft.world.level.block.BaseEntityBlock; +import net.minecraft.world.level.block.Block; +import net.minecraft.world.level.block.RenderShape; +import net.minecraft.world.level.block.SimpleWaterloggedBlock; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.entity.BlockEntityTicker; +import net.minecraft.world.level.block.entity.BlockEntityType; +import net.minecraft.world.level.block.state.BlockState; +import net.minecraft.world.level.block.state.StateDefinition; +import net.minecraft.world.level.block.state.properties.BlockStateProperties; +import net.minecraft.world.level.block.state.properties.BooleanProperty; +import net.minecraft.world.level.material.FluidState; +import net.minecraft.world.level.material.Fluids; +import net.minecraft.world.level.pathfinder.PathComputationType; +import net.minecraft.world.phys.AABB; +import net.minecraft.world.phys.BlockHitResult; +import net.minecraft.world.phys.Vec3; +import net.minecraft.world.phys.shapes.CollisionContext; +import net.minecraft.world.phys.shapes.Shapes; +import net.minecraft.world.phys.shapes.VoxelShape; +import org.jetbrains.annotations.Nullable; + +import java.util.List; + +@SuppressWarnings("deprecation") +public class TradingPostBlock extends BaseEntityBlock implements SimpleWaterloggedBlock { + public static final Component CONTAINER_TITLE = Component.translatable("container.trading_post"); + public static final Component NO_MERCHANT_FOUND = Component.translatable("trading_post.no_trader_found"); + public static final BooleanProperty WATERLOGGED = BlockStateProperties.WATERLOGGED; + private static final VoxelShape LEG1 = Block.box(0.0, 0.0, 0.0, 4.0, 8.0, 4.0); + private static final VoxelShape LEG2 = Block.box(12.0, 0.0, 0.0, 16.0, 8.0, 4.0); + private static final VoxelShape LEG3 = Block.box(0.0, 0.0, 12.0, 4.0, 8.0, 16.0); + private static final VoxelShape LEG4 = Block.box(12.0, 0.0, 12.0, 16.0, 8.0, 16.0); + private static final VoxelShape TOP = Block.box(0.0, 8.0, 0.0, 16.0, 16.0, 16.0); + private static final VoxelShape SHAPE = Shapes.or(TOP, LEG1, LEG2, LEG3, LEG4); + + public TradingPostBlock(Properties blockProperties) { + super(blockProperties); + this.registerDefaultState(this.stateDefinition.any().setValue(WATERLOGGED, Boolean.FALSE)); + } + + @Override + public boolean useShapeForLightOcclusion(BlockState state) { + return true; + } + + @Override + public VoxelShape getShape(BlockState state, BlockGetter blockReader, BlockPos pos, CollisionContext context) { + return SHAPE; + } + + @Override + public RenderShape getRenderShape(BlockState state) { + return RenderShape.MODEL; + } + + @Override + public BlockState updateShape(BlockState state, Direction direction, BlockState oldState, LevelAccessor level, BlockPos newPos, BlockPos oldPos) { + if (state.getValue(WATERLOGGED)) { + level.scheduleTick(newPos, Fluids.WATER, Fluids.WATER.getTickDelay(level)); + } + return super.updateShape(state, direction, oldState, level, newPos, oldPos); + } + + @Override + public BlockState getStateForPlacement(BlockPlaceContext context) { + FluidState fluidstate = context.getLevel().getFluidState(context.getClickedPos()); + return this.defaultBlockState().setValue(WATERLOGGED, fluidstate.getType() == Fluids.WATER); + } + + @Override + public FluidState getFluidState(BlockState state) { + return state.getValue(WATERLOGGED) ? Fluids.WATER.getSource(false) : super.getFluidState(state); + } + + @Nullable + @Override + public BlockEntity newBlockEntity(BlockPos pPos, BlockState pState) { + return new TradingPostBlockEntity(pPos, pState); + } + + @Nullable + public BlockEntityTicker getTicker(Level pLevel, BlockState pState, BlockEntityType pBlockEntityType) { + return pLevel.isClientSide ? createTickerHelper(pBlockEntityType, ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), TradingPostBlockEntity::tickEmeraldAnimation) : null; + } + + @Override + public InteractionResult use(BlockState state, Level level, BlockPos pos, Player player, InteractionHand hand, BlockHitResult rayTraceResult) { + if (level.isClientSide) { + return InteractionResult.SUCCESS; + } else { + Vec3 blockCenterPos = Vec3.atCenterOf(pos); + final int horizontalRange = TradingPost.CONFIG.get(ServerConfig.class).horizontalRange; + final int verticalRange = TradingPost.CONFIG.get(ServerConfig.class).verticalRange; + List nearbyTraders = level.getEntitiesOfClass(Entity.class, new AABB(blockCenterPos.add(-horizontalRange, -verticalRange, -horizontalRange), blockCenterPos.add(horizontalRange, verticalRange, horizontalRange)), this::canTrade); + if (!nearbyTraders.isEmpty()) { + ContainerLevelAccess access = ContainerLevelAccess.create(level, pos); + MerchantCollection merchants = new MerchantCollection(access); + for (Entity merchant : nearbyTraders) { + if (merchant instanceof Villager) { + ((VillagerAccessor) merchant).callUpdateSpecialPrices(player); + } + merchants.addMerchant(merchant.getId(), (Merchant) merchant); + } + merchants.setTradingPlayer(player); + merchants.buildOffers(merchants.getIdToOfferCountMap()); + Component title = this.getContainerTitle(level, pos); + this.openTradingScreen(player, merchants, title, access); + } else { + player.displayClientMessage(NO_MERCHANT_FOUND, false); + } + return InteractionResult.CONSUME; + } + } + + private boolean canTrade(Entity entity) { + if (TradingPost.CONFIG.get(ServerConfig.class).traderBlacklist.contains(entity.getType()) || entity.getType().is(ModRegistry.BLACKLISTED_TRADERS_TAG)) { + return false; + } + if (!entity.isAlive() || !(entity instanceof Merchant) || ((Merchant) entity).getTradingPlayer() != null || ((Merchant) entity).getOffers().isEmpty()) { + return false; + } + return !(entity instanceof LivingEntity) || (!((LivingEntity) entity).isSleeping() && !((LivingEntity) entity).isBaby()); + } + + private Component getContainerTitle(Level level, BlockPos pos) { + BlockEntity tileentity = level.getBlockEntity(pos); + return tileentity instanceof TradingPostBlockEntity ? ((Nameable) tileentity).getDisplayName() : TradingPostBlock.CONTAINER_TITLE; + } + + private void openTradingScreen(Player player, MerchantCollection merchants, Component title, ContainerLevelAccess worldPosCallable) { + player.openMenu(new SimpleMenuProvider((containerMenuId, playerInventory, playerEntity) -> new TradingPostMenu(containerMenuId, playerInventory, merchants, worldPosCallable), title)) + .ifPresent(containerId -> merchants.sendMerchantData(containerId, player)); + } + + @Override + public void setPlacedBy(Level level, BlockPos pos, BlockState state, LivingEntity entity, ItemStack stack) { + if (stack.hasCustomHoverName()) { + BlockEntity tileentity = level.getBlockEntity(pos); + if (tileentity instanceof TradingPostBlockEntity) { + ((TradingPostBlockEntity) tileentity).setCustomName(stack.getHoverName()); + } + } + } + + @Override + protected void createBlockStateDefinition(StateDefinition.Builder builder) { + builder.add(WATERLOGGED); + } + + @Override + public boolean isPathfindable(BlockState state, BlockGetter blockReader, BlockPos pos, PathComputationType pathType) { + return false; + } +} diff --git a/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java new file mode 100644 index 0000000..33bd5d4 --- /dev/null +++ b/1.20.4/Common/src/main/java/fuzs/tradingpost/world/level/block/entity/TradingPostBlockEntity.java @@ -0,0 +1,98 @@ +package fuzs.tradingpost.world.level.block.entity; + +import fuzs.tradingpost.init.ModRegistry; +import fuzs.tradingpost.world.level.block.TradingPostBlock; +import net.minecraft.core.BlockPos; +import net.minecraft.nbt.CompoundTag; +import net.minecraft.network.chat.Component; +import net.minecraft.util.Mth; +import net.minecraft.world.Nameable; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.level.Level; +import net.minecraft.world.level.block.entity.BlockEntity; +import net.minecraft.world.level.block.state.BlockState; +import org.jetbrains.annotations.Nullable; + +public class TradingPostBlockEntity extends BlockEntity implements Nameable { + private Component name; + public int time; + public float open; + public float oOpen; + public float rot; + public float oRot; + private float tRot; + + public TradingPostBlockEntity(BlockPos pWorldPosition, BlockState pBlockState) { + super(ModRegistry.TRADING_POST_BLOCK_ENTITY_TYPE.get(), pWorldPosition, pBlockState); + } + + @Override + protected void saveAdditional(CompoundTag compoundTag) { + super.saveAdditional(compoundTag); + if (this.hasCustomName()) { + compoundTag.putString("CustomName", Component.Serializer.toJson(this.name)); + } + } + + @Override + public void load(CompoundTag compoundTag) { + super.load(compoundTag); + if (compoundTag.contains("CustomName", 8)) { + this.name = Component.Serializer.fromJson(compoundTag.getString("CustomName")); + } + } + + public static void tickEmeraldAnimation(Level pLevel, BlockPos pPos, BlockState pState, TradingPostBlockEntity pBlockEntity) { + if (pLevel == null || !pLevel.isClientSide) return; + pBlockEntity.oOpen = pBlockEntity.open; + pBlockEntity.oRot = pBlockEntity.rot; + Player playerentity = pLevel.getNearestPlayer((double) pPos.getX() + 0.5, (double) pPos.getY() + 0.5, (double) pPos.getZ() + 0.5, 3.0, false); + if (playerentity != null) { + double d0 = playerentity.getX() - ((double) pPos.getX() + 0.5); + double d1 = playerentity.getZ() - ((double) pPos.getZ() + 0.5); + pBlockEntity.tRot = (float) Mth.atan2(d1, d0); + pBlockEntity.open += 0.1F; + } else { + pBlockEntity.tRot += 0.02F; + pBlockEntity.open -= 0.1F; + } + while(pBlockEntity.rot >= (float) Math.PI) { + pBlockEntity.rot -= ((float) Math.PI * 2.0F); + } + while(pBlockEntity.rot < -(float) Math.PI) { + pBlockEntity.rot += ((float) Math.PI * 2.0F); + } + while(pBlockEntity.tRot >= (float) Math.PI) { + pBlockEntity.tRot -= ((float) Math.PI * 2.0F); + } + while(pBlockEntity.tRot < -(float) Math.PI) { + pBlockEntity.tRot += ((float) Math.PI * 2.0F); + } + float f2; + f2 = pBlockEntity.tRot - pBlockEntity.rot; + while (f2 >= (float) Math.PI) { + f2 -= ((float) Math.PI * 2.0F); + } + while(f2 < -(float) Math.PI) { + f2 += ((float) Math.PI * 2.0F); + } + pBlockEntity.rot += f2 * 0.4F; + pBlockEntity.open = Mth.clamp(pBlockEntity.open, 0.0F, 1.0F); + ++pBlockEntity.time; + } + + @Override + public Component getName() { + return this.name != null ? this.name : TradingPostBlock.CONTAINER_TITLE; + } + + public void setCustomName(@Nullable Component textComponent) { + this.name = textComponent; + } + + @Nullable + @Override + public Component getCustomName() { + return this.name; + } +} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json b/1.20.4/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json new file mode 100644 index 0000000..9ae1fe4 --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/blockstates/trading_post.json @@ -0,0 +1,7 @@ +{ + "variants": { + "": { + "model": "tradingpost:block/trading_post" + } + } +} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/en_us.json b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/en_us.json new file mode 100644 index 0000000..1722313 --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/en_us.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Trading Post", + "container.trading_post": "Trading Post", + "trading_post.no_trader_found": "Couldn't find any available trader nearby", + "trading_post.trader_gone": "The trader is no longer available.", + "trading_post.search": "Search..." +} \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/it_it.json b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/it_it.json new file mode 100644 index 0000000..84afc50 --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/it_it.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Postazione commerciale", + "container.trading_post": "Postazione commerciale", + "trading_post.no_trader_found": "Nessun commerciante disponibile trovato nelle vicinanze", + "trading_post.trader_gone": "Il commerciante non è più disponibile.", + "trading_post.search": "Ricerca..." +} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/pt_br.json b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/pt_br.json new file mode 100644 index 0000000..e84791f --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/pt_br.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Posto de Comércio", + "container.trading_post": "Posto de Comércio", + "trading_post.no_trader_found": "Não foi possível encontrar nenhum comerciante disponível nas proximidades", + "trading_post.trader_gone": "O comerciante não está mais disponível.", + "trading_post.search": "Procurar..." + } \ No newline at end of file diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json new file mode 100644 index 0000000..ef8965c --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/ru_ru.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "Торговый пост", + "container.trading_post": "Торговый пост", + "trading_post.no_trader_found": "Не удалось найти по близости какого-либо торговца.", + "trading_post.trader_gone": "Торговец больше не доступен.", + "trading_post.search": "Поиск..." +} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json new file mode 100644 index 0000000..cc3146e --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/lang/zh_tw.json @@ -0,0 +1,7 @@ +{ + "block.tradingpost.trading_post": "交易站", + "container.trading_post": "交易站", + "trading_post.no_trader_found": "在附近沒有可用的交易", + "trading_post.trader_gone": "交易鎖定.", + "trading_post.search": "搜尋中..." +} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json b/1.20.4/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json new file mode 100644 index 0000000..c876239 --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/models/block/trading_post.json @@ -0,0 +1,63 @@ +{ "parent": "block/block", + "textures": { + "particle": "tradingpost:block/trading_post_top", + "bottom1": "tradingpost:block/trading_post_bottom", + "bottom2": "minecraft:block/oak_planks", + "top": "tradingpost:block/trading_post_top", + "side": "tradingpost:block/trading_post_side", + "front": "tradingpost:block/trading_post_front" + }, + "elements": [ + { "from": [ 0, 0, 0 ], + "to": [ 4, 8, 4 ], + "faces": { + "down": { "uv": [ 0, 0, 4, 4 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#side" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#side", "cullface": "west" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#side" } + } + }, + { "from": [ 12, 0, 12 ], + "to": [ 16, 8, 16 ], + "faces": { + "down": { "uv": [ 12, 12, 16, 16 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#side" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#side" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#side", "cullface": "east" } + } + }, + { "from": [ 12, 0, 0 ], + "to": [ 16, 8, 4 ], + "faces": { + "down": { "uv": [ 12, 0, 16, 4 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#front", "cullface": "north" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#front" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#front" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#front", "cullface": "east" } + } + }, + { "from": [ 0, 0, 12 ], + "to": [ 4, 8, 16 ], + "faces": { + "down": { "uv": [ 0, 12, 4, 16 ], "texture": "#bottom1", "cullface": "down" }, + "north": { "uv": [ 0, 8, 4, 16 ], "texture": "#front" }, + "south": { "uv": [ 4, 8, 8, 16 ], "texture": "#front", "cullface": "south" }, + "west": { "uv": [ 8, 8, 12, 16 ], "texture": "#front", "cullface": "west" }, + "east": { "uv": [ 12, 8, 16, 16 ], "texture": "#front" } + } + }, + { "from": [ 0, 8, 0 ], + "to": [ 16, 16, 16 ], + "faces": { + "down": { "uv": [ 0, 0, 16, 16 ], "texture": "#bottom2" }, + "up": { "uv": [ 0, 0, 16, 16 ], "texture": "#top", "cullface": "up" }, + "north": { "uv": [ 0, 0, 16, 8 ], "texture": "#side", "cullface": "north" }, + "south": { "uv": [ 0, 0, 16, 8 ], "texture": "#side", "cullface": "south" }, + "west": { "uv": [ 0, 0, 16, 8 ], "texture": "#front", "cullface": "west" }, + "east": { "uv": [ 0, 0, 16, 8 ], "texture": "#front", "cullface": "east" } + } + } + ] +} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json b/1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json new file mode 100644 index 0000000..9c7f8ce --- /dev/null +++ b/1.20.4/Common/src/main/resources/assets/tradingpost/models/item/trading_post.json @@ -0,0 +1,3 @@ +{ + "parent": "tradingpost:block/trading_post" +} diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png b/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_bottom.png new file mode 100644 index 0000000000000000000000000000000000000000..717082a266c044f6fbeb8c7b99e4bc33637d510f GIT binary patch literal 1321 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n#K_9nFbZMfql=3lR~tp)~GmCm34-ih7k{j%&- zu&UZ#tu3uh<{1Z5wcelKwkBr%{llBGv>&qzX*S$!)o{F#yvBF-${!1*8Qz5%F)hnk zd*w?1!jjw%d@md(UVp6C(st0%echtdiS1!}N1XGPF*BHZiEm!Q&Hias??%7h#hPMQ z?tVC0keDd`^!8GL7T^54AMEBZZd`vRl;?Vs`uX2iJ(5iR{(mU`{{v(0m2=D?%-$bB O#e}D;pUXO@geCx)FpWe2 literal 0 HcmV?d00001 diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png b/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_front.png new file mode 100644 index 0000000000000000000000000000000000000000..bff9f1eadce05e63af80b16c493df4164ed7751d GIT binary patch literal 1610 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n*u=`nJPKk0iZZAXHu|8Xh?F!T=^iW!O!#(OK&`M$WXE++#ho3Pl^=V$IEHA5 z)&}nPmJXDue_!-6)@JduDAQR%+DRQQGErQvf)^cPSakm}^1Tfckl9tDQ?kwbU!&7= zy}2zud}}LYb%PYIvLwswd1CV1cJgj-`|0I-yxR6XoPB=%`|0n$JDEQ_R#p}_@!jv* zZ|c@-ZO`w0D)KdbV?jyMa&@(xn|A*WU3a&lFSoi}Y)RQ<*|`t4e|VCaR-twL^5a5Q z#udvlm2^H|>oD3ehdsz0an`~sMH(&00_PQCowo5ZxWKM|Q)|@*n`&n+CtNvTo z2bXxB^}gD0^406|tKC`+S2ytOuXT#3oA~B@TKcx2qko(4gzd|i^E~0RY|^Z@FVp#N z-_H5-``MvOn@^s;6k5UTrab{_P*+ND;t5jwk7wD&n^&UST1ibE%N{H1g*mU z>ujGFE+{$`>)0%QE_6BCvl*>$?nBzoQJ@`wVx zUau|H&K(aA9n!J-wjzF#hT7dt+h(*IE8GkJbwwlQ{`)_y`!@cM-Se+01XPZCy85}S Ib4q9e04ES2V*mgE literal 0 HcmV?d00001 diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png b/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_side.png new file mode 100644 index 0000000000000000000000000000000000000000..6eff5bac4a582547c9caf9723b2e705ea5031ef6 GIT binary patch literal 1585 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n*u=`fJPKk0iZZAXHu|8Xh?F!T=^iW!O!#(OK&`M$WXJXQ#W`S}W<2HT;uxYK zS{u06kI7NujxC=BBkMW)11=#=f`QzmBiFbtf3*ey9dKlds33<+-TT1NQ>7Tq2- zHy$lDHZF1hgVs;q6-+yNHDJfldo{+NYikZ)+B);cwQE+Hb8jF2onvLOeT$;ko#*Ml zuebiHC<-yCu2#?bdDrlD>GR7BS64({XRZ0(?ymML*!$4j7vByuOfzKLtQBSZ&)~of zj{WynEpf^7;y1s#NjJS&o{Nq1&SLLGQPWS?mAST$|3jYVn(dD_1+?Hkz>Pd||)xMUoZU zYMTiD>eHK;9lp9W{abgfNFytL+gmeTx#?A+w@zI+7ND3Y*89Cxq&4YM`_&1b1(=`2 gt1YNpxGV3obQI&8)xpbK96`mUr>mdKI;Vst0Pda)^8f$< literal 0 HcmV?d00001 diff --git a/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png b/1.20.4/Common/src/main/resources/assets/tradingpost/textures/block/trading_post_top.png new file mode 100644 index 0000000000000000000000000000000000000000..c127409bfcbbe6acd67008fdd2510de9967f79c7 GIT binary patch literal 1640 zcmeAS@N?(olHy`uVBq!ia0vp^0wB!61SBU+%rFB|vr;2G(|mmyw18|51~x_^24*0O z5eOL=r5ISjYzBrfMrk-Zj!^@u251bUAp^)TQ6Nrh&tzbMs;>dkAm9PSK$9SJKxRd1 zPHtjJevv{zQNDtao}r!*P>yK<6I`Fb0%imoD92z{=c*2*I14-?iy0WWg+Z8+Vb&Z8 z1_tKz%#etZ2wxwoY3;nDA{o-C@9zzrKDK}xwt{K19`Se86_nJR{Hwo z<>h+i#(Mch>H3D2mX`VkM*2oZx=P7{9 zO-#x!EwNQn0$BtH5OG? zRU{TbG=T#H;zk>g3#=l7Qj7C*NS09PrDr9MNtq7f=d6^}4Mo`<(gpqWCg2@V;KqFl;b5rw*LH;u|v(d*YfmLG! zE{#YMNE(4*Z{=K+3d#;4`T03^*m8%BKDsJ21AKu=IVG_q(Iv4Y)y~Mk$WYh7T-V4l z#L&>n*ucujAPQmviZZAXHu|8Xh?F!T=^iW!O!#(OK&`M$WXH9QefD}_R%P^baSYKA zt(|n&TO?4TJ^fr{>6~1xC3B_j>LnRYTeLUe)PxQVrEZSHtKT){ajE=bex>%GS#Zy* zZF^RBD|M_`(Q#;t(vi})$!i_9ua(J7jVw(Ipa1ei;d(2c_V15>?tO2W9=F;2@!yzL zQf(VgPjo&!U1+87#@ye9SGoTC{rmT8%l}il5)4hx9@@U^{r7HJh4(Lq)z=HB3IyzJ z^LY3-AulO!=^K8Yy<$JUn&^G`arkzPM(b1sC&g2ZiQG~zZ%xcsb>Nr1d3)l@TA8z} zJFYRDR{y?k-o86;tS(Fc%11>GB)DX?%udQxLa^$V7`BvU9FJn_F z!#rzm)XcX&)8y{%J$zF{*w*v!-&IRrUOjq2=Qr=iXq73c~b=D8;(--kEc|^q_8Y8|hecp!u}px#zlz+r5{2&ln3r zQ=vj32*Qx)p`Zxt9}$7i(QAJo${>WG2&u;&iptIn9Q4q`Ip6txzdzr{xtL1E8tV_$ z13+UU9!c}s>>PI$zrVi!;56JbLt{e#4=?TgiK{tAB%U4vIMV|#zXb4ux8^?s6h(mT zEP#9!;GlVJDt(=NQznTdS*!?x5-!T=5pp zzi9Z9a!mtlov!Qpc5cecL%UgYk|~%`nOKw;@QZ#)kVK(R%t!%Q>X)UER}^JY)B}x| z|1lH{MN`ZFH+0NC_HjednV=CO6T>W9+Dwi?c=v^lkfTTng@PzfOL@wekiujZTM7yr z1rzJ#?-S(#p3%9Rp-`Jxn#nXn2Rj`bMu})RAcX<}!S9nM?!Jq0anG)}fc2t^2`gIE z0xm>3#!R`lw^SE+%Zsb7z)k*l~zJggsQlhXULgGjJ#2_kZoc@k${{H zBIEHpJYv5S!8BEsao)^fz_x7=jen?;o4fg&3z{kdsw*1Sps-NCPDbtxXBYke*RS2S literal 0 HcmV?d00001 diff --git a/1.20.4/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json b/1.20.4/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json new file mode 100644 index 0000000..1a49ae7 --- /dev/null +++ b/1.20.4/Common/src/main/resources/data/minecraft/tags/blocks/mineable/axe.json @@ -0,0 +1,6 @@ +{ + "replace": false, + "values": [ + "tradingpost:trading_post" + ] +} diff --git a/1.20.4/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json b/1.20.4/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json new file mode 100644 index 0000000..3cfa463 --- /dev/null +++ b/1.20.4/Common/src/main/resources/data/tradingpost/loot_tables/blocks/trading_post.json @@ -0,0 +1,19 @@ +{ + "type": "minecraft:block", + "pools": [ + { + "rolls": 1, + "entries": [ + { + "type": "minecraft:item", + "name": "tradingpost:trading_post" + } + ], + "conditions": [ + { + "condition": "minecraft:survives_explosion" + } + ] + } + ] +} diff --git a/1.20.4/Common/src/main/resources/data/tradingpost/recipes/trading_post.json b/1.20.4/Common/src/main/resources/data/tradingpost/recipes/trading_post.json new file mode 100644 index 0000000..2d26369 --- /dev/null +++ b/1.20.4/Common/src/main/resources/data/tradingpost/recipes/trading_post.json @@ -0,0 +1,22 @@ +{ + "type": "crafting_shaped", + "pattern": [ + " X ", + "###", + "S S" + ], + "key": { + "#": { + "tag": "minecraft:planks" + }, + "X": { + "item": "minecraft:emerald" + }, + "S": { + "item": "minecraft:stick" + } + }, + "result": { + "item": "tradingpost:trading_post" + } +} diff --git a/1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json b/1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json new file mode 100644 index 0000000..d275da3 --- /dev/null +++ b/1.20.4/Common/src/main/resources/data/tradingpost/tags/entity_types/blacklisted_traders.json @@ -0,0 +1,5 @@ +{ + "replace": false, + "values": [ + ] +} diff --git a/1.20.4/Common/src/main/resources/mod_banner.png b/1.20.4/Common/src/main/resources/mod_banner.png new file mode 100644 index 0000000000000000000000000000000000000000..4aa65be87014905b9ae86260545884645759b5db GIT binary patch literal 20290 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 Zs6PaW6GB^cSBd}t002ovPDHLkV1oN>({lg- literal 0 HcmV?d00001 diff --git a/1.20.4/Common/src/main/resources/mod_logo.png b/1.20.4/Common/src/main/resources/mod_logo.png new file mode 100644 index 0000000000000000000000000000000000000000..fa91dba198b8eba0ea360d3b7cf0877568843326 GIT binary patch literal 9609 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 literal 0 HcmV?d00001 diff --git a/1.20.4/Common/src/main/resources/pack.mcmeta b/1.20.4/Common/src/main/resources/pack.mcmeta new file mode 100755 index 0000000..19bfab2 --- /dev/null +++ b/1.20.4/Common/src/main/resources/pack.mcmeta @@ -0,0 +1,8 @@ +{ + "pack": { + "description": "${modDescription}", + "pack_format": ${resourcePackFormat}, + "forge:resource_pack_format": ${resourcePackFormat}, + "forge:data_pack_format": ${dataPackFormat} + } +} diff --git a/1.20.4/Common/src/main/resources/tradingpost.common.mixins.json b/1.20.4/Common/src/main/resources/tradingpost.common.mixins.json new file mode 100644 index 0000000..7833fd6 --- /dev/null +++ b/1.20.4/Common/src/main/resources/tradingpost.common.mixins.json @@ -0,0 +1,20 @@ +{ + "required": true, + "minVersion": "0.8", + "compatibilityLevel": "JAVA_17", + "package": "fuzs.tradingpost.mixin", + "refmap": "tradingpost.refmap.json", + "plugin": "fuzs.tradingpost.mixin.ModMixinConfigPlugin", + "mixins": [ + "accessor.MerchantMenuAccessor", + "accessor.VillagerAccessor" + ], + "client": [ + "client.accessor.ButtonAccessor", + "client.accessor.MerchantScreenAccessor", + "client.accessor.TradeOfferButtonAccessor" + ], + "injectors": { + "defaultRequire": 1 + } +} diff --git a/1.20.4/Fabric/build.gradle b/1.20.4/Fabric/build.gradle new file mode 100644 index 0000000..cd8b641 --- /dev/null +++ b/1.20.4/Fabric/build.gradle @@ -0,0 +1,29 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/fabric.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Fabric Api + modApi libs.fabricapi.fabric + + // Puzzles Lib + modApi libs.puzzleslib.fabric + + // Cardinal Components +// modApi(include(libs.cardinalcomponentsbase.fabric.get())) +// modApi(include(libs.cardinalcomponentsentity.fabric.get())) +// modApi(include(libs.cardinalcomponentsblock.fabric.get())) +// modApi(include(libs.cardinalcomponentschunk.fabric.get())) +// modApi(include(libs.cardinalcomponentsworld.fabric.get())) + + // Extensible Enums +// modApi(include(libs.extensibleenums.fabric.get())) + + // Quality of Life Mods + versionCatalog.findLibrary("modmenu.fabric").ifPresent { + modLocalRuntime(it) + } + versionCatalog.findLibrary("forgeconfigscreens.fabric").ifPresent { + modLocalRuntime(it) + } +} diff --git a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java new file mode 100644 index 0000000..5fc6ff1 --- /dev/null +++ b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/TradingPostFabric.java @@ -0,0 +1,12 @@ +package fuzs.tradingpost; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import net.fabricmc.api.ModInitializer; + +public class TradingPostFabric implements ModInitializer { + + @Override + public void onInitialize() { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + } +} diff --git a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java new file mode 100644 index 0000000..c5198a1 --- /dev/null +++ b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/client/TradingPostFabricClient.java @@ -0,0 +1,13 @@ +package fuzs.tradingpost.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.tradingpost.TradingPost; +import net.fabricmc.api.ClientModInitializer; + +public class TradingPostFabricClient implements ClientModInitializer { + + @Override + public void onInitializeClient() { + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); + } +} diff --git a/1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..343a1d3 --- /dev/null +++ b/1.20.4/Fabric/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.tradingpost.mixin; + +import net.fabricmc.loader.api.FabricLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FabricLoader.getInstance().isModLoaded("puzzleslib"); + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.20.4/Fabric/src/main/resources/fabric.mod.json b/1.20.4/Fabric/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..c0c6cfa --- /dev/null +++ b/1.20.4/Fabric/src/main/resources/fabric.mod.json @@ -0,0 +1,44 @@ +{ + "schemaVersion": 1, + "id": "${modId}", + "version": "${modVersion}", + + "name": "${modName}", + "description": "${modDescription}", + + "authors": [ + "${modAuthor}" + ], + + "contact": { + "homepage": "${modPageUrl}", + "issues": "${modIssueUrl}", + "sources": "${modPageUrl}" + }, + + "license": "${modLicense}", + "icon": "mod_logo.png", + + "environment": "${modFabricEnvironment}", + + "entrypoints": { + "main": [ + "${mainEntryPoint}" + ], + "client": [ + "${clientEntryPoint}" + ] + }, + + "mixins": [ + "${modId}.common.mixins.json" + ], + + "depends": { + "fabricloader": ">=${minFabricVersion}", + "fabric-api": ">=${minFabricApiVersion}", + "puzzleslib": ">=${minPuzzlesVersion}", + "minecraft": "${minecraftVersion}", + "java": ">=17" + } +} diff --git a/1.20.4/Forge/build.gradle b/1.20.4/Forge/build.gradle new file mode 100644 index 0000000..dec494a --- /dev/null +++ b/1.20.4/Forge/build.gradle @@ -0,0 +1,28 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Puzzles Lib + api fg.deobf(libs.puzzleslib.forge.get()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } + versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +} + +task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { + onlyIf { project.hasProperty('keyStore') } + keyStore = project.findProperty('keyStore') + alias = project.findProperty('keyStoreAlias') + storePass = project.findProperty('keyStorePass') + keyPass = project.findProperty('keyStoreKeyPass') + inputFile = outputFile = tasks.jarJar.archivePath +} + +jar.finalizedBy 'signJar' +signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 b/1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 new file mode 100644 index 0000000..26e7e09 --- /dev/null +++ b/1.20.4/Forge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 @@ -0,0 +1,2 @@ +// 1.20.1 2023-06-28T11:09:24.480978 Sprite Sources +84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json b/1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json new file mode 100644 index 0000000..0cfb27c --- /dev/null +++ b/1.20.4/Forge/src/generated/resources/assets/minecraft/atlases/blocks.json @@ -0,0 +1,8 @@ +{ + "sources": [ + { + "type": "minecraft:single", + "resource": "tradingpost:item/magnifying_glass" + } + ] +} \ No newline at end of file diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java new file mode 100644 index 0000000..46a80b4 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/tradingpost/TradingPostForge.java @@ -0,0 +1,33 @@ +package fuzs.tradingpost; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.tradingpost.data.ModSpriteSourceProvider; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +import java.util.concurrent.CompletableFuture; + +@Mod(TradingPost.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class TradingPostForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + final DataGenerator dataGenerator = evt.getGenerator(); + final PackOutput packOutput = dataGenerator.getPackOutput(); + final CompletableFuture lookupProvider = evt.getLookupProvider(); + final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); + dataGenerator.addProvider(true, new ModSpriteSourceProvider(packOutput, fileHelper)); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java new file mode 100644 index 0000000..41d3cbf --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.tradingpost.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.tradingpost.TradingPost; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = TradingPost.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class TradingPostForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java new file mode 100644 index 0000000..7ddde99 --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java @@ -0,0 +1,22 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v1.AbstractSpriteSourceProvider; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import net.minecraft.client.renderer.texture.atlas.sources.SingleFile; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.common.data.SpriteSourceProvider; + +import java.util.Optional; + +public class ModSpriteSourceProvider extends AbstractSpriteSourceProvider { + + public ModSpriteSourceProvider(PackOutput packOutput, ExistingFileHelper fileHelper) { + super(packOutput, fileHelper); + } + + @Override + protected void addSources() { + this.atlas(SpriteSourceProvider.BLOCKS_ATLAS).addSource(new SingleFile(TradingPostScreen.MAGNIFYING_GLASS_LOCATION, Optional.empty())); + } +} diff --git a/1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..7528a9e --- /dev/null +++ b/1.20.4/Forge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.tradingpost.mixin; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.20.4/Forge/src/main/resources/META-INF/mods.toml b/1.20.4/Forge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..6f39b5f --- /dev/null +++ b/1.20.4/Forge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,40 @@ +modLoader="javafml" +loaderVersion="[${minFMLVersion},)" +license = "${modLicense}" +issueTrackerURL="${modIssueUrl}" + +[[mods]] + modId="${modId}" + displayName="${modName}" + description="${modDescription}" + version="${modVersion}" + authors="${modAuthor}" + logoFile="mod_banner.png" + logoBlur=false + displayURL="${modPageUrl}" + updateJSONURL="${modUpdateUrl}" + displayTest="${modForgeDisplayTest}" + +[[dependencies.${modId}]] + modId="forge" + mandatory=true + versionRange="[${minForgeVersion},)" + ordering="NONE" + side="BOTH" + +[[dependencies.${modId}]] + modId="minecraft" + mandatory=true + versionRange="[${minecraftVersion}]" + ordering="NONE" + side="BOTH" + +[[dependencies.${modId}]] + modId="puzzleslib" + mandatory=true + versionRange="[${minPuzzlesVersion},)" + ordering="NONE" + side="BOTH" + +[modproperties.${modId}] + catalogueImageIcon="mod_logo.png" diff --git a/1.20.4/NeoForge/build.gradle b/1.20.4/NeoForge/build.gradle new file mode 100644 index 0000000..dec494a --- /dev/null +++ b/1.20.4/NeoForge/build.gradle @@ -0,0 +1,28 @@ +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/forge.gradle' + +def versionCatalog = extensions.getByType(VersionCatalogsExtension).named("libs") + +dependencies { + // Puzzles Lib + api fg.deobf(libs.puzzleslib.forge.get()) + + // Quality of Life Mods + versionCatalog.findLibrary("bettermodsbutton.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } + versionCatalog.findLibrary("forgeconfigscreens.forge").ifPresent { + runtimeOnly fg.deobf(it.get()) + } +} + +task signJar(type: net.minecraftforge.gradle.common.tasks.SignJar, dependsOn: tasks.reobfJarJar) { + onlyIf { project.hasProperty('keyStore') } + keyStore = project.findProperty('keyStore') + alias = project.findProperty('keyStoreAlias') + storePass = project.findProperty('keyStorePass') + keyPass = project.findProperty('keyStoreKeyPass') + inputFile = outputFile = tasks.jarJar.archivePath +} + +jar.finalizedBy 'signJar' +signJar.mustRunAfter 'reobfJar' diff --git a/1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 b/1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 new file mode 100644 index 0000000..26e7e09 --- /dev/null +++ b/1.20.4/NeoForge/src/generated/resources/.cache/178bb4356f8bea3c4b8966704e26df58ba8fa865 @@ -0,0 +1,2 @@ +// 1.20.1 2023-06-28T11:09:24.480978 Sprite Sources +84b1132cc503d980b133257e14eb97b4fc706c93 assets/minecraft/atlases/blocks.json diff --git a/1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json b/1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json new file mode 100644 index 0000000..0cfb27c --- /dev/null +++ b/1.20.4/NeoForge/src/generated/resources/assets/minecraft/atlases/blocks.json @@ -0,0 +1,8 @@ +{ + "sources": [ + { + "type": "minecraft:single", + "resource": "tradingpost:item/magnifying_glass" + } + ] +} \ No newline at end of file diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java new file mode 100644 index 0000000..46a80b4 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/TradingPostForge.java @@ -0,0 +1,33 @@ +package fuzs.tradingpost; + +import fuzs.puzzleslib.api.core.v1.ModConstructor; +import fuzs.tradingpost.data.ModSpriteSourceProvider; +import net.minecraft.core.HolderLookup; +import net.minecraft.data.DataGenerator; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.data.event.GatherDataEvent; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +import java.util.concurrent.CompletableFuture; + +@Mod(TradingPost.MOD_ID) +@Mod.EventBusSubscriber(bus = Mod.EventBusSubscriber.Bus.MOD) +public class TradingPostForge { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ModConstructor.construct(TradingPost.MOD_ID, TradingPost::new); + } + + @SubscribeEvent + public static void onGatherData(final GatherDataEvent evt) { + final DataGenerator dataGenerator = evt.getGenerator(); + final PackOutput packOutput = dataGenerator.getPackOutput(); + final CompletableFuture lookupProvider = evt.getLookupProvider(); + final ExistingFileHelper fileHelper = evt.getExistingFileHelper(); + dataGenerator.addProvider(true, new ModSpriteSourceProvider(packOutput, fileHelper)); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java new file mode 100644 index 0000000..41d3cbf --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/client/TradingPostForgeClient.java @@ -0,0 +1,17 @@ +package fuzs.tradingpost.client; + +import fuzs.puzzleslib.api.client.core.v1.ClientModConstructor; +import fuzs.tradingpost.TradingPost; +import net.minecraftforge.api.distmarker.Dist; +import net.minecraftforge.eventbus.api.SubscribeEvent; +import net.minecraftforge.fml.common.Mod; +import net.minecraftforge.fml.event.lifecycle.FMLConstructModEvent; + +@Mod.EventBusSubscriber(modid = TradingPost.MOD_ID, bus = Mod.EventBusSubscriber.Bus.MOD, value = Dist.CLIENT) +public class TradingPostForgeClient { + + @SubscribeEvent + public static void onConstructMod(final FMLConstructModEvent evt) { + ClientModConstructor.construct(TradingPost.MOD_ID, TradingPostClient::new); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java new file mode 100644 index 0000000..7ddde99 --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/data/ModSpriteSourceProvider.java @@ -0,0 +1,22 @@ +package fuzs.tradingpost.data; + +import fuzs.puzzleslib.api.data.v1.AbstractSpriteSourceProvider; +import fuzs.tradingpost.client.gui.screens.inventory.TradingPostScreen; +import net.minecraft.client.renderer.texture.atlas.sources.SingleFile; +import net.minecraft.data.PackOutput; +import net.minecraftforge.common.data.ExistingFileHelper; +import net.minecraftforge.common.data.SpriteSourceProvider; + +import java.util.Optional; + +public class ModSpriteSourceProvider extends AbstractSpriteSourceProvider { + + public ModSpriteSourceProvider(PackOutput packOutput, ExistingFileHelper fileHelper) { + super(packOutput, fileHelper); + } + + @Override + protected void addSources() { + this.atlas(SpriteSourceProvider.BLOCKS_ATLAS).addSource(new SingleFile(TradingPostScreen.MAGNIFYING_GLASS_LOCATION, Optional.empty())); + } +} diff --git a/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java new file mode 100644 index 0000000..7528a9e --- /dev/null +++ b/1.20.4/NeoForge/src/main/java/fuzs/tradingpost/mixin/ModMixinConfigPlugin.java @@ -0,0 +1,47 @@ +package fuzs.tradingpost.mixin; + +import net.minecraftforge.fml.loading.FMLLoader; +import org.objectweb.asm.tree.ClassNode; +import org.spongepowered.asm.mixin.extensibility.IMixinConfigPlugin; +import org.spongepowered.asm.mixin.extensibility.IMixinInfo; + +import java.util.List; +import java.util.Set; + +public class ModMixinConfigPlugin implements IMixinConfigPlugin { + + @Override + public void onLoad(String mixinPackage) { + + } + + @Override + public String getRefMapperConfig() { + return null; + } + + @Override + public boolean shouldApplyMixin(String targetClassName, String mixinClassName) { + return FMLLoader.getLoadingModList().getModFileById("puzzleslib") != null; + } + + @Override + public void acceptTargets(Set myTargets, Set otherTargets) { + + } + + @Override + public List getMixins() { + return null; + } + + @Override + public void preApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } + + @Override + public void postApply(String targetClassName, ClassNode targetClass, String mixinClassName, IMixinInfo mixinInfo) { + + } +} diff --git a/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml new file mode 100644 index 0000000..6f39b5f --- /dev/null +++ b/1.20.4/NeoForge/src/main/resources/META-INF/mods.toml @@ -0,0 +1,40 @@ +modLoader="javafml" +loaderVersion="[${minFMLVersion},)" +license = "${modLicense}" +issueTrackerURL="${modIssueUrl}" + +[[mods]] + modId="${modId}" + displayName="${modName}" + description="${modDescription}" + version="${modVersion}" + authors="${modAuthor}" + logoFile="mod_banner.png" + logoBlur=false + displayURL="${modPageUrl}" + updateJSONURL="${modUpdateUrl}" + displayTest="${modForgeDisplayTest}" + +[[dependencies.${modId}]] + modId="forge" + mandatory=true + versionRange="[${minForgeVersion},)" + ordering="NONE" + side="BOTH" + +[[dependencies.${modId}]] + modId="minecraft" + mandatory=true + versionRange="[${minecraftVersion}]" + ordering="NONE" + side="BOTH" + +[[dependencies.${modId}]] + modId="puzzleslib" + mandatory=true + versionRange="[${minPuzzlesVersion},)" + ordering="NONE" + side="BOTH" + +[modproperties.${modId}] + catalogueImageIcon="mod_logo.png" diff --git a/1.20.4/build.gradle b/1.20.4/build.gradle new file mode 100644 index 0000000..fadade3 --- /dev/null +++ b/1.20.4/build.gradle @@ -0,0 +1,12 @@ +plugins { + alias libs.plugins.loom apply false + alias libs.plugins.quiltflower apply false + alias libs.plugins.forgegradle apply false + alias libs.plugins.mixin apply false + alias libs.plugins.librarian apply false + alias libs.plugins.cursegradle apply false + alias libs.plugins.minotaur apply false +} + +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/main.gradle' +apply from: 'https://raw.githubusercontent.com/Fuzss/modresources/main/gradle/tasks.gradle' diff --git a/1.20.4/gradle.properties b/1.20.4/gradle.properties new file mode 100755 index 0000000..75109d0 --- /dev/null +++ b/1.20.4/gradle.properties @@ -0,0 +1,35 @@ +# Sets default memory used for gradle commands. Can be overridden by user or command line properties. +# This is required to provide enough memory for the Minecraft decompilation process. +org.gradle.jvmargs=-Xmx3G +org.gradle.daemon=false +org.gradle.parallel=true +copyBuildJar=true + +# Mod Attributes +modId=tradingpost +modName=Trading Post +modVersion=8.0.1 +modAuthor=Fuzs +modDescription=Rule the village! Trade with every villager at once! +modLicense=MPL-2.0 +modSourceUrl=https://github.com/Fuzss/tradingpost +modIssueUrl=https://github.com/Fuzss/tradingpost/issues +modUpdateUrl=https://raw.githubusercontent.com/Fuzss/modresources/main/update/tradingpost.json +modMavenGroup=fuzs.tradingpost +# "MATCH_VERSION" for a mod required on both sides, "IGNORE_SERVER_VERSION" for a server only mod, "IGNORE_ALL_VERSION" for a client only mod +modForgeDisplayTest=MATCH_VERSION +# "*" for a mod loaded on both sides, "server" for a server only mod, "client" for a client only mod +modFabricEnvironment=* + +# Mod Publishing +projectReleaseType=release +projectCurseForgeId=539057 +projectModrinthId=8pcjMDgj + +dependenciesVersionCatalog=1.20.1-v5 +dependenciesRequiredForgeCurseForge=puzzles-lib +dependenciesRequiredFabricCurseForge=fabric-api, forge-config-api-port-fabric, puzzles-lib +dependenciesRequiredForgeModrinth=puzzles-lib +dependenciesRequiredFabricModrinth=fabric-api, forge-config-api-port, puzzles-lib +#dependenciesEmbeddedFabricCurseForge=cardinal-components +#dependenciesEmbeddedFabricModrinth=cardinal-components-api diff --git a/1.20.4/gradle/wrapper/gradle-wrapper.jar b/1.20.4/gradle/wrapper/gradle-wrapper.jar new file mode 100644 index 0000000000000000000000000000000000000000..943f0cbfa754578e88a3dae77fce6e3dea56edbf GIT binary patch literal 61574 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