diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml new file mode 100644 index 0000000..2ca3795 --- /dev/null +++ b/.github/workflows/build.yml @@ -0,0 +1,40 @@ +# Automatically build the project and run any configured tests for every push +# and submitted pull request. This can help catch issues that only occur on +# certain platforms or Java versions, and provides a first line of defence +# against bad commits. + +name: build +on: [pull_request, push] + +jobs: + build: + strategy: + matrix: + # Use these Java versions + java: [ + 17, # Current Java LTS & minimum supported by Minecraft + ] + # and run on both Linux and Windows + os: [ubuntu-22.04, windows-2022] + runs-on: ${{ matrix.os }} + steps: + - name: checkout repository + uses: actions/checkout@v3 + - name: validate gradle wrapper + uses: gradle/wrapper-validation-action@v1 + - name: setup jdk ${{ matrix.java }} + uses: actions/setup-java@v3 + with: + java-version: ${{ matrix.java }} + distribution: 'microsoft' + - name: make gradle wrapper executable + if: ${{ runner.os != 'Windows' }} + run: chmod +x ./gradlew + - name: build + run: ./gradlew build + - name: capture build artifacts + if: ${{ runner.os == 'Linux' && matrix.java == '17' }} # Only upload artifacts built from latest java on one OS + uses: actions/upload-artifact@v3 + with: + name: Artifacts + path: build/libs/ \ No newline at end of file diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..c476faf --- /dev/null +++ b/.gitignore @@ -0,0 +1,40 @@ +# gradle + +.gradle/ +build/ +out/ +classes/ + +# eclipse + +*.launch + +# idea + +.idea/ +*.iml +*.ipr +*.iws + +# vscode + +.settings/ +.vscode/ +bin/ +.classpath +.project + +# macos + +*.DS_Store + +# fabric + +run/ + +# java + +hs_err_*.log +replay_*.log +*.hprof +*.jfr diff --git a/LICENSE b/LICENSE new file mode 100644 index 0000000..accb62f --- /dev/null +++ b/LICENSE @@ -0,0 +1,21 @@ +MIT License + +Copyright (c) 2019 simibubi + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/build.gradle b/build.gradle new file mode 100644 index 0000000..9c463cc --- /dev/null +++ b/build.gradle @@ -0,0 +1,85 @@ +plugins { + id 'fabric-loom' version '1.2-SNAPSHOT' + id 'maven-publish' +} + +version = project.mod_version +group = project.maven_group + +base { + archivesName = project.archives_base_name +} + +repositories { + // Add repositories to retrieve artifacts from in here. + // You should only use this when depending on other mods because + // Loom adds the essential maven repositories to download Minecraft and libraries from automatically. + // See https://docs.gradle.org/current/userguide/declaring_repositories.html + // for more information about repositories. + maven { url "https://api.modrinth.com/maven" } + maven { url 'https://oss.sonatype.org/content/repositories/snapshots' } + maven { url 'https://maven.nucleoid.xyz' } +} + +dependencies { + // To change the versions see the gradle.properties file + minecraft "com.mojang:minecraft:${project.minecraft_version}" + mappings "net.fabricmc:yarn:${project.yarn_mappings}:v2" + modImplementation "net.fabricmc:fabric-loader:${project.loader_version}" + + // Fabric API. This is technically optional, but you probably want it anyway. + modImplementation "net.fabricmc.fabric-api:fabric-api:${project.fabric_version}" + + + include(modImplementation("maven.modrinth:server-api:${project.serverapi_version}")) + + include(modImplementation('me.lucko:fabric-permissions-api:0.2-SNAPSHOT')) + + modImplementation include("eu.pb4:polymer-core:${project.polymer_version}") + modImplementation include("xyz.nucleoid:server-translations-api:${project.server_translations_api_version}") +} + +processResources { + inputs.property "version", project.version + + filesMatching("fabric.mod.json") { + expand "version": project.version + } +} + +tasks.withType(JavaCompile).configureEach { + it.options.release = 17 +} + +java { + // Loom will automatically attach sourcesJar to a RemapSourcesJar task and to the "build" task + // if it is present. + // If you remove this line, sources will not be generated. + withSourcesJar() + + sourceCompatibility = JavaVersion.VERSION_17 + targetCompatibility = JavaVersion.VERSION_17 +} + +jar { + from("LICENSE") { + rename { "${it}_${project.archivesBaseName}"} + } +} + +// configure the maven publication +publishing { + publications { + mavenJava(MavenPublication) { + from components.java + } + } + + // See https://docs.gradle.org/current/userguide/publishing_maven.html for information on how to set up publishing. + repositories { + // Add repositories to publish to here. + // Notice: This block does NOT have the same function as the block in the top level. + // The repositories here will be used for publishing your artifact, not for + // retrieving dependencies. + } +} \ No newline at end of file diff --git a/gradle.properties b/gradle.properties new file mode 100644 index 0000000..018aaa8 --- /dev/null +++ b/gradle.properties @@ -0,0 +1,20 @@ +# Done to increase the memory available to gradle. +org.gradle.jvmargs=-Xmx1G +org.gradle.parallel=true + +# Fabric Properties +# check these on https://fabricmc.net/develop +minecraft_version=1.20.1 +yarn_mappings=1.20.1+build.8 +loader_version=0.14.21 + +# Mod Properties +mod_version=1.0.0+1.20.1 +maven_group=dev.venomcode.wanda +archives_base_name=wanda + +# Dependencies +fabric_version=0.84.0+1.20.1 +serverapi_version=1.0.6+1.20.1 +polymer_version=0.5.2+1.20.1 +server_translations_api_version=2.0.0+1.20 \ No newline at end of file diff --git a/settings.gradle b/settings.gradle new file mode 100644 index 0000000..75c4d72 --- /dev/null +++ b/settings.gradle @@ -0,0 +1,10 @@ +pluginManagement { + repositories { + maven { + name = 'Fabric' + url = 'https://maven.fabricmc.net/' + } + mavenCentral() + gradlePluginPortal() + } +} \ No newline at end of file diff --git a/src/main/java/dev/venomcode/wanda/WandaMod.java b/src/main/java/dev/venomcode/wanda/WandaMod.java new file mode 100644 index 0000000..2c9908d --- /dev/null +++ b/src/main/java/dev/venomcode/wanda/WandaMod.java @@ -0,0 +1,99 @@ +package dev.venomcode.wanda; + +import dev.venomcode.serverapi.api.ServerAPI; +import dev.venomcode.serverapi.api.ServerUtils; +import dev.venomcode.wanda.api.IWandaPlayer; +import dev.venomcode.wanda.configs.WandaConfig; +import dev.venomcode.wanda.items.WandItem; +import net.fabricmc.api.ModInitializer; +import net.fabricmc.fabric.api.event.player.AttackBlockCallback; +import net.fabricmc.fabric.api.item.v1.FabricItemSettings; +import net.minecraft.item.Item; +import net.minecraft.registry.Registries; +import net.minecraft.registry.Registry; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.Identifier; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; +import org.spongepowered.configurate.CommentedConfigurationNode; +import org.spongepowered.configurate.ConfigurateException; +import org.spongepowered.configurate.hocon.HoconConfigurationLoader; + +import java.nio.file.Path; + +public class WandaMod implements ModInitializer { + // This logger is used to write text to the console and the log file. + // It is considered best practice to use your mod id as the logger's name. + // That way, it's clear which mod wrote info, warnings, and errors. + public static final String MODID = "wanda"; + public static final Logger LOGGER = LoggerFactory.getLogger(MODID); + + @Override + public void onInitialize() { + + WandaConfig config = getConfig(); + saveConfig(); + + Identifier wandItemProxyTag = config.getWandDisplayItem(); + if(wandItemProxyTag.getPath().equalsIgnoreCase(MODID)) + { + wandItemProxyTag = new Identifier("minecraft:nether_star"); + } + + Item wandItemProxy = Registries.ITEM.get(wandItemProxyTag); + + WAND_ITEM = new WandItem(new FabricItemSettings().maxCount(1), wandItemProxy); + Registry.register(Registries.ITEM, new Identifier(MODID, "wanda"), WAND_ITEM); + + AttackBlockCallback.EVENT.register(((player, world, hand, pos, direction) -> { + if(!player.getWorld().isClient) { + ServerPlayerEntity serverPlayer = (ServerPlayerEntity) player; + IWandaPlayer wandaPlayer = (IWandaPlayer) serverPlayer; + + wandaPlayer.setSelected(pos, true); + + serverPlayer.sendMessage(ServerUtils.getText("[Wanda] Set PRIMARY selection to " + pos.toShortString(), Formatting.GOLD)); + return ActionResult.SUCCESS; + } + return ActionResult.PASS; + })); + + } + + public static WandaConfig getConfig() { + if(_configCached != null) + return _configCached; + + try { + CommentedConfigurationNode node = configLoader.load(); + + _configCached = node.get(WandaConfig.class); + } + catch (ConfigurateException ex) { + LOGGER.error(ServerAPI.Logger.Error("[ERROR]Failed to load wanda config.")); + } + + return _configCached; + } + + public static void saveConfig() { + CommentedConfigurationNode node = CommentedConfigurationNode.root(); + try { + node.set(WandaConfig.class, _configCached); + configLoader.save(node); + } + catch (ConfigurateException ex) { + LOGGER.error(ServerAPI.Logger.Error("[ERROR]Failed to save wanda config.")); + } + } + + public WandItem WAND_ITEM; + + private static final HoconConfigurationLoader configLoader = HoconConfigurationLoader.builder() + .path(Path.of(ServerAPI.CONFIG_PATH + "wanda.conf")) + .build(); + private static WandaConfig _configCached = null; + +} diff --git a/src/main/java/dev/venomcode/wanda/api/IWandaPlayer.java b/src/main/java/dev/venomcode/wanda/api/IWandaPlayer.java new file mode 100644 index 0000000..62e42e2 --- /dev/null +++ b/src/main/java/dev/venomcode/wanda/api/IWandaPlayer.java @@ -0,0 +1,10 @@ +package dev.venomcode.wanda.api; + +import net.minecraft.util.math.BlockPos; + +public interface IWandaPlayer { + public BlockPos getSelectedPrimary(); + public BlockPos getSelectedSecondary(); + + public void setSelected(BlockPos pos, boolean isPrimary); +} diff --git a/src/main/java/dev/venomcode/wanda/api/WandaAPI.java b/src/main/java/dev/venomcode/wanda/api/WandaAPI.java new file mode 100644 index 0000000..26881d4 --- /dev/null +++ b/src/main/java/dev/venomcode/wanda/api/WandaAPI.java @@ -0,0 +1,13 @@ +package dev.venomcode.wanda.api; + +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.Pair; +import net.minecraft.util.math.BlockPos; + +public class WandaAPI { + public Pair getPlayersSelected(ServerPlayerEntity serverPlayer) { + IWandaPlayer wandaPlayer = (IWandaPlayer) serverPlayer; + return new Pair<>(wandaPlayer.getSelectedPrimary(), wandaPlayer.getSelectedSecondary()); + } + +} diff --git a/src/main/java/dev/venomcode/wanda/configs/WandaConfig.java b/src/main/java/dev/venomcode/wanda/configs/WandaConfig.java new file mode 100644 index 0000000..7c2e9db --- /dev/null +++ b/src/main/java/dev/venomcode/wanda/configs/WandaConfig.java @@ -0,0 +1,18 @@ +package dev.venomcode.wanda.configs; + +import net.minecraft.util.Identifier; +import org.spongepowered.configurate.objectmapping.ConfigSerializable; +import org.spongepowered.configurate.objectmapping.meta.Comment; +import org.spongepowered.configurate.objectmapping.meta.Setting; + +@ConfigSerializable +public class WandaConfig { + @Comment("The display item for the wand. Use a tag such as minecraft:stick") + @Setting("wand_display_item") + String wandDisplayItem = "minecraft:nether_star"; + + public Identifier getWandDisplayItem() + { + return new Identifier(wandDisplayItem); + } +} diff --git a/src/main/java/dev/venomcode/wanda/items/WandItem.java b/src/main/java/dev/venomcode/wanda/items/WandItem.java new file mode 100644 index 0000000..ba543f1 --- /dev/null +++ b/src/main/java/dev/venomcode/wanda/items/WandItem.java @@ -0,0 +1,38 @@ +package dev.venomcode.wanda.items; + +import dev.venomcode.serverapi.api.ServerUtils; +import dev.venomcode.wanda.api.IWandaPlayer; +import eu.pb4.polymer.core.api.item.SimplePolymerItem; +import net.minecraft.block.BlockState; +import net.minecraft.entity.LivingEntity; +import net.minecraft.item.Item; +import net.minecraft.item.ItemStack; +import net.minecraft.item.ItemUsageContext; +import net.minecraft.server.network.ServerPlayerEntity; +import net.minecraft.util.ActionResult; +import net.minecraft.util.Formatting; +import net.minecraft.util.math.BlockPos; +import net.minecraft.world.World; + +public class WandItem extends SimplePolymerItem { + public WandItem(Settings settings, Item polymerItem) { + super(settings, polymerItem); + } + + @Override + public ActionResult useOnBlock(ItemUsageContext context) { + if(context.getWorld().isClient) + return ActionResult.PASS; + + ServerPlayerEntity serverPlayer = (ServerPlayerEntity) context.getPlayer(); + IWandaPlayer wandaPlayer = (IWandaPlayer)serverPlayer; + + wandaPlayer.setSelected(context.getBlockPos(), false); + + serverPlayer.sendMessage(ServerUtils.getText("[Wanda] Set SECONDARY selection to " + context.getBlockPos().toShortString(), Formatting.GOLD)); + + + return ActionResult.PASS; + } + +} diff --git a/src/main/java/dev/venomcode/wanda/mixin/MixinPlayerEntity.java b/src/main/java/dev/venomcode/wanda/mixin/MixinPlayerEntity.java new file mode 100644 index 0000000..86ee5a2 --- /dev/null +++ b/src/main/java/dev/venomcode/wanda/mixin/MixinPlayerEntity.java @@ -0,0 +1,31 @@ +package dev.venomcode.wanda.mixin; + +import dev.venomcode.wanda.api.IWandaPlayer; +import net.minecraft.entity.player.PlayerEntity; +import net.minecraft.util.math.BlockPos; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.injection.Inject; + +@Mixin(PlayerEntity.class) +public abstract class MixinPlayerEntity implements IWandaPlayer { + @Override + public BlockPos getSelectedPrimary() { + return selectedPrimary; + } + + @Override + public BlockPos getSelectedSecondary() { + return selectedSecondary; + } + + @Override + public void setSelected(BlockPos pos, boolean isPrimary) { + if(isPrimary) + selectedPrimary = pos; + else + selectedSecondary = pos; + } + + private BlockPos selectedPrimary = null; + private BlockPos selectedSecondary = null; +} diff --git a/src/main/resources/assets/wanda/icon.png b/src/main/resources/assets/wanda/icon.png new file mode 100644 index 0000000..047b91f Binary files /dev/null and b/src/main/resources/assets/wanda/icon.png differ diff --git a/src/main/resources/data/wanda/lang/en_us.json b/src/main/resources/data/wanda/lang/en_us.json new file mode 100644 index 0000000..2835468 --- /dev/null +++ b/src/main/resources/data/wanda/lang/en_us.json @@ -0,0 +1,3 @@ +{ + "item.wanda.wanda": "Selection Wand" +} \ No newline at end of file diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json new file mode 100644 index 0000000..1a064b5 --- /dev/null +++ b/src/main/resources/fabric.mod.json @@ -0,0 +1,34 @@ +{ + "schemaVersion": 1, + "id": "wanda", + "version": "${version}", + "name": "Wanda", + "description": "This is an example description! Tell everyone what your mod is about!", + "authors": [ + "VenomCodeDev" + ], + "contact": { + "homepage": "https://fabricmc.net/", + "sources": "https://github.com/FabricMC/fabric-example-mod" + }, + "license": "MIT", + "icon": "assets/wanda/icon.png", + "environment": "*", + "entrypoints": { + "main": [ + "dev.venomcode.wanda.WandaMod" + ] + }, + "mixins": [ + "wanda.mixins.json" + ], + "depends": { + "fabricloader": ">=0.14.21", + "minecraft": "~1.20.1", + "java": ">=17", + "fabric-api": "*" + }, + "suggests": { + "another-mod": "*" + } +} \ No newline at end of file diff --git a/src/main/resources/wanda.mixins.json b/src/main/resources/wanda.mixins.json new file mode 100644 index 0000000..fe6f8da --- /dev/null +++ b/src/main/resources/wanda.mixins.json @@ -0,0 +1,11 @@ +{ + "required": true, + "package": "dev.venomcode.wanda.mixin", + "compatibilityLevel": "JAVA_17", + "mixins": [ + "MixinPlayerEntity" + ], + "injectors": { + "defaultRequire": 1 + } +} \ No newline at end of file