From cd60db0f99b6d78e297b7f1545db36e253798caa Mon Sep 17 00:00:00 2001 From: masterpatrickpl-coder Date: Sun, 29 Mar 2026 13:03:25 +0800 Subject: [PATCH] Rework mod for Minecraft 26.1 --- .github/workflows/ci.yml | 4 +- README.md | 11 ++- build.gradle.kts | 18 ++-- gradle.properties | 2 +- gradle/wrapper/gradle-wrapper.properties | 2 +- .../com/example/oneshot/OneShotHandler.java | 86 ++++++++----------- .../java/com/example/oneshot/OneShotMod.java | 63 +++----------- .../example/oneshot/item/OneShotSword.java | 20 +++-- src/main/resources/fabric.mod.json | 4 +- src/main/resources/pack.mcmeta | 2 +- 10 files changed, 88 insertions(+), 124 deletions(-) diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index 5dff019..d787566 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -23,11 +23,11 @@ jobs: if: runner.os != 'Windows' run: chmod +x gradlew - - name: Set up JDK 21 + - name: Set up JDK 25 uses: actions/setup-java@v4 with: distribution: temurin - java-version: "21" + java-version: "25" cache: gradle - name: Validate Gradle wrapper diff --git a/README.md b/README.md index e401195..fd3f696 100644 --- a/README.md +++ b/README.md @@ -1,7 +1,9 @@ -OneShot Sword — Fabric mod for Minecraft +OneShot Sword — Fabric mod for Minecraft 26.1 Overpowered sword that deletes most mobs/players on hit and buffs the attacker. Single-player or controlled servers only. +Versioning note +- Minecraft now uses the `year.drop.hotfix` scheme (for example, `26.1`). Build (PowerShell) ```powershell @@ -9,8 +11,13 @@ Build (PowerShell) ``` Jar: build/libs/ +Requirements +- Java 25 +- Fabric Loader 0.18.5+ +- Fabric API 0.144.3+26.1 + Notes -- Pack format 42; assets under src/main/resources/assets/oneshot/ +- Resource pack format 84; assets under src/main/resources/assets/oneshot/ - Texture is a placeholder; replace textures/item/oneshot_sword.png - Sword applies heavy status effects (Speed/Jump boosted, Dolphin’s Grace, Night Vision) and attempts an instant kill. diff --git a/build.gradle.kts b/build.gradle.kts index 6773006..bdbfeda 100644 --- a/build.gradle.kts +++ b/build.gradle.kts @@ -1,14 +1,13 @@ // Minimal Fabric Loom buildscript wiring (buildscript/classpath + apply) plugins { - id("fabric-loom") version "1.14.6" + id("net.fabricmc.fabric-loom") version "1.15-SNAPSHOT" java `maven-publish` } -val minecraftVersion = "1.21.11" -val yarnMappings = "1.21.11+build.1" -val loaderVersion = "0.18.2" -val fabricApiVersion = "0.139.5+1.21.11" +val minecraftVersion = "26.1" +val loaderVersion = "0.18.5" +val fabricApiVersion = "0.144.3+26.1" repositories { mavenCentral() @@ -19,16 +18,15 @@ repositories { dependencies { minecraft("com.mojang:minecraft:$minecraftVersion") - mappings("net.fabricmc:yarn:$yarnMappings:v2") - modImplementation("net.fabricmc:fabric-loader:$loaderVersion") - modImplementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") + implementation("net.fabricmc:fabric-loader:$loaderVersion") + implementation("net.fabricmc.fabric-api:fabric-api:$fabricApiVersion") } java { - toolchain.languageVersion.set(JavaLanguageVersion.of(21)) + toolchain.languageVersion.set(JavaLanguageVersion.of(25)) } tasks.withType().configureEach { - options.release.set(21) + options.release.set(25) } \ No newline at end of file diff --git a/gradle.properties b/gradle.properties index 8768a65..262c69c 100644 --- a/gradle.properties +++ b/gradle.properties @@ -1,2 +1,2 @@ org.gradle.jvmargs=-Xmx3G -java.toolchain.languageVersion=21 +java.toolchain.languageVersion=25 diff --git a/gradle/wrapper/gradle-wrapper.properties b/gradle/wrapper/gradle-wrapper.properties index 23449a2..dbc3ce4 100644 --- a/gradle/wrapper/gradle-wrapper.properties +++ b/gradle/wrapper/gradle-wrapper.properties @@ -1,6 +1,6 @@ distributionBase=GRADLE_USER_HOME distributionPath=wrapper/dists -distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.1-bin.zip +distributionUrl=https\://services.gradle.org/distributions/gradle-9.4.0-bin.zip networkTimeout=10000 validateDistributionUrl=true zipStoreBase=GRADLE_USER_HOME diff --git a/src/main/java/com/example/oneshot/OneShotHandler.java b/src/main/java/com/example/oneshot/OneShotHandler.java index 4df8cfa..7df80c7 100644 --- a/src/main/java/com/example/oneshot/OneShotHandler.java +++ b/src/main/java/com/example/oneshot/OneShotHandler.java @@ -1,10 +1,13 @@ package com.example.oneshot; -import net.minecraft.entity.LivingEntity; -import net.minecraft.entity.player.PlayerEntity; -import net.minecraft.entity.effect.StatusEffectInstance; -import net.minecraft.entity.effect.StatusEffects; -import net.minecraft.item.ItemStack; +import net.minecraft.server.level.ServerLevel; +import net.minecraft.world.damagesource.DamageSource; +import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.effect.MobEffects; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.entity.player.Player; +import net.minecraft.world.item.ItemStack; +import net.minecraft.world.level.Level; /** * OneShotHandler: standalone handler for the sword's effect so the Item class doesn't run @@ -15,71 +18,56 @@ public class OneShotHandler { private static final int EFFECT_DURATION = 20 * 60 * 60; // 1 hour in ticks public static void onAttack(LivingEntity target, LivingEntity attacker, ItemStack stack) { - // Defensive runtime guards: only run server-side and ensure attacker is a LivingEntity - net.minecraft.world.World world = target.getEntityWorld(); - if (world == null || world.isClient()) { + Level world = target.level(); + if (!(world instanceof ServerLevel serverLevel) || world.isClientSide()) { return; } - net.minecraft.entity.LivingEntity livingAttacker = null; - if (attacker instanceof net.minecraft.entity.LivingEntity) { - livingAttacker = (net.minecraft.entity.LivingEntity) attacker; - } - // For players, wipe inventory before kill so nothing drops - if (target instanceof PlayerEntity playerTarget) { + if (target instanceof Player playerTarget) { try { - playerTarget.getInventory().clear(); + playerTarget.getInventory().clearContent(); } catch (Throwable ignored) {} } - // Attempt a proper instant-kill using DamageSources when attacker exists - if (livingAttacker != null) { - try { - net.minecraft.entity.damage.DamageSource ds = target.getDamageSources().mobAttack(livingAttacker); - try { - target.sidedDamage(ds, Float.MAX_VALUE); - } catch (Throwable inner) { - target.setHealth(0.0F); - } - } catch (Throwable t) { - try { target.setHealth(0.0F); } catch (Throwable ignored) {} - } - } else { + try { + DamageSource ds = target.damageSources().mobAttack(attacker); + target.hurtServer(serverLevel, ds, Float.MAX_VALUE); + } catch (Throwable t) { try { target.setHealth(0.0F); } catch (Throwable ignored) {} } try { attacker.heal(99999.0F); } catch (Throwable ignored) {} - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.ABSORPTION, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.RESISTANCE, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.STRENGTH, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.REGENERATION, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.ABSORPTION, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.RESISTANCE, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.STRENGTH, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.REGENERATION, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); // Speed level 9 -> amplifier 8 (doubled) - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.SPEED, EFFECT_DURATION, 8, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.HASTE, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.SPEED, EFFECT_DURATION, 8, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.HASTE, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); // Jump Boost level 5 -> amplifier 4 (doubled) - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.JUMP_BOOST, EFFECT_DURATION, 4, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.SATURATION, EFFECT_DURATION, 5, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.GLOWING, EFFECT_DURATION, 0, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.INVISIBILITY, EFFECT_DURATION, 0, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.DOLPHINS_GRACE, EFFECT_DURATION, 2, false, true, true)); - attacker.addStatusEffect(new StatusEffectInstance(StatusEffects.NIGHT_VISION, EFFECT_DURATION, 0, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.JUMP_BOOST, EFFECT_DURATION, 4, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.SATURATION, EFFECT_DURATION, 5, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.GLOWING, EFFECT_DURATION, 0, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.INVISIBILITY, EFFECT_DURATION, 0, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.DOLPHINS_GRACE, EFFECT_DURATION, 2, false, true, true)); + attacker.addEffect(new MobEffectInstance(MobEffects.NIGHT_VISION, EFFECT_DURATION, 0, false, true, true)); if (target.isAlive()) { try { - if (target instanceof PlayerEntity) { - ((PlayerEntity) target).getInventory().clear(); + if (target instanceof Player playerTarget) { + playerTarget.getInventory().clearContent(); } } catch (Throwable ignored) {} - target.addStatusEffect(new StatusEffectInstance(StatusEffects.WITHER, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - target.addStatusEffect(new StatusEffectInstance(StatusEffects.POISON, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - target.addStatusEffect(new StatusEffectInstance(StatusEffects.WEAKNESS, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - target.addStatusEffect(new StatusEffectInstance(StatusEffects.SLOWNESS, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - target.addStatusEffect(new StatusEffectInstance(StatusEffects.BLINDNESS, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); - target.addStatusEffect(new StatusEffectInstance(StatusEffects.INSTANT_DAMAGE, 1, EFFECT_AMPLIFIER, false, true, true)); - target.addStatusEffect(new StatusEffectInstance(StatusEffects.LEVITATION, 60, 10, false, true, true)); + target.addEffect(new MobEffectInstance(MobEffects.WITHER, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + target.addEffect(new MobEffectInstance(MobEffects.POISON, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + target.addEffect(new MobEffectInstance(MobEffects.WEAKNESS, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + target.addEffect(new MobEffectInstance(MobEffects.SLOWNESS, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + target.addEffect(new MobEffectInstance(MobEffects.BLINDNESS, EFFECT_DURATION, EFFECT_AMPLIFIER, false, true, true)); + target.addEffect(new MobEffectInstance(MobEffects.INSTANT_DAMAGE, 1, EFFECT_AMPLIFIER, false, true, true)); + target.addEffect(new MobEffectInstance(MobEffects.LEVITATION, 60, 10, false, true, true)); } } } diff --git a/src/main/java/com/example/oneshot/OneShotMod.java b/src/main/java/com/example/oneshot/OneShotMod.java index b170c10..a1a4385 100644 --- a/src/main/java/com/example/oneshot/OneShotMod.java +++ b/src/main/java/com/example/oneshot/OneShotMod.java @@ -1,67 +1,28 @@ package com.example.oneshot; -import com.example.oneshot.OneShotHandler; +import com.example.oneshot.item.OneShotSword; import net.fabricmc.api.ModInitializer; -import net.minecraft.item.Item; -import net.minecraft.item.Item.Settings; -import net.minecraft.item.ItemGroups; -import net.minecraft.util.Identifier; -import net.minecraft.registry.Registries; -import net.minecraft.registry.Registry; -import net.minecraft.registry.RegistryKey; -import net.minecraft.registry.RegistryKeys; -import net.fabricmc.fabric.api.itemgroup.v1.ItemGroupEvents; +import net.minecraft.core.Registry; +import net.minecraft.core.registries.BuiltInRegistries; +import net.minecraft.core.registries.Registries; +import net.minecraft.resources.Identifier; +import net.minecraft.resources.ResourceKey; +import net.minecraft.world.item.Item; public class OneShotMod implements ModInitializer { public static final String MOD_ID = "oneshot"; - // Avoid calling Settings.group(...) because the signature can vary between mappings. - // Defer creating the Item instance until onInitialize to prevent Minecraft code from - // running during static class initialization (fixes "Item id not set" NPE on startup). public static Item ONE_SHOT_SWORD; @Override public void onInitialize() { - // Register the item inline. Avoid wrapping in a broad try/catch because creating an - // Item before a failing register() call can leave an intrusive holder unregistered. - Identifier swordId = Identifier.of(MOD_ID, "oneshot_sword"); + Identifier swordId = Identifier.fromNamespaceAndPath(MOD_ID, "oneshot_sword"); - // Safety: if the ID is already present, skip creating a second Item instance. - if (Registries.ITEM.containsId(swordId)) { - System.err.println("[OneShotMod] Item ID already registered: " + swordId + " — skipping duplicate registration."); - ONE_SHOT_SWORD = Registries.ITEM.get(swordId); + if (BuiltInRegistries.ITEM.containsKey(swordId)) { + ONE_SHOT_SWORD = BuiltInRegistries.ITEM.getValue(swordId); } else { - System.out.println("[OneShotMod][Diag] About to construct Item settings (assigning registry key early); classloader=" + OneShotMod.class.getClassLoader()); - // In modern 1.21.x, Items expect their registry key to be pre-associated in Settings - // before construction, otherwise the constructor will throw the 'Item id not set' NPE. - RegistryKey swordKey = RegistryKey.of(RegistryKeys.ITEM, swordId); - Settings settings = new Settings().registryKey(swordKey).maxCount(1); - System.out.println("[OneShotMod][Diag] Settings built: " + settings); - System.out.println("[OneShotMod][Diag] Calling Registry.register for id=" + swordId); - ONE_SHOT_SWORD = Registry.register(Registries.ITEM, swordId, new Item(settings)); - System.out.println("[OneShotMod][Diag] Registry.register returned instance=" + ONE_SHOT_SWORD + " class=" + ONE_SHOT_SWORD.getClass().getName()); - Identifier fetched = Registries.ITEM.getId(ONE_SHOT_SWORD); - System.out.println("[OneShotMod][Diag] Post-registration fetched id=" + fetched); - if (fetched == null) { - throw new IllegalStateException("[OneShotMod][Diag] Fetched null id for sword AFTER registration; registry corruption?"); - } + ResourceKey swordKey = ResourceKey.create(Registries.ITEM, swordId); + ONE_SHOT_SWORD = Registry.register(BuiltInRegistries.ITEM, swordKey, new OneShotSword(new Item.Properties())); } - - // Only register callbacks if the sword successfully registered - if (ONE_SHOT_SWORD != null) { - // Add to Combat creative tab for visibility - ItemGroupEvents.modifyEntriesEvent(ItemGroups.COMBAT).register(entries -> entries.add(ONE_SHOT_SWORD.getDefaultStack())); - net.fabricmc.fabric.api.event.player.AttackEntityCallback.EVENT.register((player, world, hand, entity, hitResult) -> { - if (world == null || world.isClient()) return net.minecraft.util.ActionResult.PASS; - if (player.getMainHandStack() == null) return net.minecraft.util.ActionResult.PASS; - if (player.getMainHandStack().getItem() != ONE_SHOT_SWORD) return net.minecraft.util.ActionResult.PASS; - if (entity instanceof net.minecraft.entity.LivingEntity) { - OneShotHandler.onAttack((net.minecraft.entity.LivingEntity) entity, player, player.getMainHandStack()); - } - return net.minecraft.util.ActionResult.PASS; - }); - } - - System.out.println("[OneShotMod][Diag] onInitialize complete."); } } diff --git a/src/main/java/com/example/oneshot/item/OneShotSword.java b/src/main/java/com/example/oneshot/item/OneShotSword.java index 0de5663..02070f5 100644 --- a/src/main/java/com/example/oneshot/item/OneShotSword.java +++ b/src/main/java/com/example/oneshot/item/OneShotSword.java @@ -1,8 +1,18 @@ package com.example.oneshot.item; -// Clean stub-only placeholder: doesn't extend Item and contains no game logic. -// This ensures there is no accidental early instantiation of an Item subclass -// that depends on Minecraft internals. -public final class OneShotSword { - private OneShotSword() {} +import com.example.oneshot.OneShotHandler; +import net.minecraft.world.entity.LivingEntity; +import net.minecraft.world.item.Item; +import net.minecraft.world.item.ItemStack; + +public class OneShotSword extends Item { + public OneShotSword(Properties properties) { + super(properties); + } + + @Override + public void hurtEnemy(ItemStack stack, LivingEntity target, LivingEntity attacker) { + OneShotHandler.onAttack(target, attacker, stack); + super.hurtEnemy(stack, target, attacker); + } } diff --git a/src/main/resources/fabric.mod.json b/src/main/resources/fabric.mod.json index 8b7a9d0..f6c95e5 100644 --- a/src/main/resources/fabric.mod.json +++ b/src/main/resources/fabric.mod.json @@ -11,8 +11,8 @@ ] }, "depends": { - "fabricloader": ">=0.18.2", + "fabricloader": ">=0.18.5", "fabric": "*", - "minecraft": "1.21.11" + "minecraft": "26.1" } } diff --git a/src/main/resources/pack.mcmeta b/src/main/resources/pack.mcmeta index 122620d..3cdac28 100644 --- a/src/main/resources/pack.mcmeta +++ b/src/main/resources/pack.mcmeta @@ -1,6 +1,6 @@ { "pack": { - "pack_format": 42, + "pack_format": 84, "description": "OneShot Sword assets" } }