Compare commits

...

5 Commits

Author SHA1 Message Date
lowercasebtw
e8d42e5033 Small changes 2025-11-23 20:28:15 -05:00
lowercasebtw
8764c2a251 Add midnightlib to required deps on neoforge 2025-11-23 20:19:10 -05:00
lowercasebtw
85126b5927 1.21.10/fix 2025-11-23 17:27:48 -05:00
lowercasebtw
a0f7125b89 1.21.10 2025-11-23 17:26:49 -05:00
lowercasebtw
1ad6c1f588 Mojmap + Stonecutter 2025-11-23 17:08:22 -05:00
50 changed files with 955 additions and 755 deletions

6
.editorconfig Normal file
View File

@@ -0,0 +1,6 @@
[*]
end_of_line = lf
[{*.json,*.toml}]
indent_style = tab
indent_size = 4

19
.gitignore vendored
View File

@@ -1,9 +1,13 @@
# gradle # gradle
.gradle/ .gradle/
build/
out/ out/
classes/ classes/
build/
# eclipse
*.launch
# idea # idea
@@ -20,6 +24,17 @@ bin/
.classpath .classpath
.project .project
# macos
*.DS_Store
# fabric # fabric
run/ run/
# java
hs_err_*.log
replay_*.log
*.hprof
*.jfr

View File

@@ -1,3 +1,3 @@
# Sword Blocking # Sword Blocking
A minecraft fabric clientside mod to restore sword blocking, you just need a shield in your offhand. A minecraft fabric clientside mod to restore sword blocking, you just need a shield in your offhand.
Works especially well if you want to use 1.16 on an 1.8 server which is running ViaVersion. Works especially well if you want to use 1.16 on an 1.8 server which is running ViaVersion.

View File

@@ -1,80 +0,0 @@
plugins {
id "architectury-plugin" version "3.4-SNAPSHOT"
id "dev.architectury.loom" version "1.10-SNAPSHOT" apply false
id "me.shedaniel.unified-publishing" version "0.1.+" apply false
id 'com.github.johnrengelman.shadow' version '8.1.1' apply false
}
architectury {
minecraft = rootProject.minecraft_version
}
repositories {
maven {
url = "https://api.modrinth.com/maven"
}
}
subprojects {
apply plugin: "dev.architectury.loom"
repositories {
maven {
url = "https://api.modrinth.com/maven"
}
maven { url 'https://jitpack.io' }
}
dependencies {
minecraft "com.mojang:minecraft:${rootProject.minecraft_version}"
// The following line declares the mojmap mappings, you may use other mappings as well
//mappings loom.officialMojangMappings()
// The following line declares the yarn mappings you may select this one as well.
mappings loom.layered {
it.mappings("net.fabricmc:yarn:$rootProject.yarn_mappings:v2")
it.mappings("dev.architectury:yarn-mappings-patch-neoforge:$rootProject.yarn_mappings_patch_neoforge_version")
}
}
}
allprojects {
apply plugin: "java"
apply plugin: "architectury-plugin"
apply plugin: "maven-publish"
archivesBaseName = rootProject.archives_base_name
version = rootProject.mod_version
group = rootProject.maven_group
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.
}
tasks.withType(JavaCompile) {
options.encoding = "UTF-8"
options.release = 21
}
ext {
releaseChangelog = {
def changes = new StringBuilder()
changes << "## SwordBlocking v$project.version for $project.minecraft_version\n[View the changelog](https://www.github.com/TeamMidnightDust/SwordBlocking/commits/)"
def proc = "git log --max-count=1 --pretty=format:%s".execute()
proc.in.eachLine { line ->
def processedLine = line.toString()
if (!processedLine.contains("New translations") && !processedLine.contains("Merge") && !processedLine.contains("branch")) {
changes << "\n- ${processedLine.capitalize()}"
}
}
proc.waitFor()
return changes.toString()
}
}
java {
withSourcesJar()
}
}

226
build.gradle.kts Normal file
View File

@@ -0,0 +1,226 @@
plugins {
alias(libs.plugins.kotlin.jvm)
alias(libs.plugins.loom)
alias(libs.plugins.publishing)
alias(libs.plugins.blossom)
alias(libs.plugins.ksp)
alias(libs.plugins.fletchingtable.fabric)
}
repositories {
maven("https://pkgs.dev.azure.com/djtheredstoner/DevAuth/_packaging/public/maven/v1") // DevAuth
maven("https://maven.parchmentmc.org") // Parchment
maven("https://maven.neoforged.net/releases") // NeoForge
maven("https://maven.bawnorton.com/releases") // MixinSquared
maven("https://maven.terraformersmc.com/") // Mod Menu
maven("https://api.modrinth.com/maven") // MidnightLib
}
class ModData {
val id = property("mod.id") as String
val name = property("mod.name") as String
val version = property("mod.version") as String
val group = property("mod.group") as String
val description = property("mod.description") as String
val source = property("mod.source") as String
val issues = property("mod.issues") as String
val license = property("mod.license") as String
val modrinth = property("mod.modrinth") as String
val curseforge = property("mod.curseforge") as String
val discord = property("mod.discord") as String
val minecraftVersion = property("mod.minecraft_version") as String
val minecraftVersionRange = property("mod.minecraft_version_range") as String
}
class Dependencies {
val fabricLoaderVersion = property("deps.fabric_loader_version") as String?
val midnightLibVersion = property("deps.midnightlib_version") as String?
val devAuthVersion = property("deps.devauth_version") as String?
val lombokVersion = property("deps.lombok_version") as String?
val mixinConstraintsVersion = property("deps.mixinconstraints_version") as String?
val mixinSquaredVersion = property("deps.mixinsquared_version") as String?
// Versioned
val neoForgeVersion = property("deps.neoforge_version") as String?
val fabricApiVersion = property("deps.fabric_api_version") as String?
}
class LoaderData {
val name = loom.platform.get().name.lowercase()
val isFabric = name == "fabric"
val isNeoForge = name == "neoforge"
}
val mod = ModData()
val deps = Dependencies()
val loader = LoaderData()
group = mod.group
base {
archivesName.set("${mod.id}-${mod.version}+${mod.minecraftVersion}-${loader.name}")
}
java {
val requiredJava = when {
stonecutter.eval(stonecutter.current.version, ">=1.20.6") -> JavaVersion.VERSION_21
stonecutter.eval(stonecutter.current.version, ">=1.18") -> JavaVersion.VERSION_17
stonecutter.eval(stonecutter.current.version, ">=1.17") -> JavaVersion.VERSION_16
else -> JavaVersion.VERSION_1_8
}
sourceCompatibility = requiredJava
targetCompatibility = requiredJava
}
stonecutter {
replacements.string {
direction = eval(current.version, ">=1.21.11")
replace("ResourceLocation", "Identifier")
}
}
val currentCommitHash: String by lazy {
Runtime.getRuntime()
.exec("git rev-parse --verify --short HEAD", null, rootDir)
.inputStream.bufferedReader().readText().trim()
}
blossom {
replaceToken("@MODID@", mod.id)
replaceToken("@VERSION@", mod.version)
replaceToken("@COMMIT@", currentCommitHash)
}
loom {
silentMojangMappingsLicense()
runConfigs.all {
ideConfigGenerated(stonecutter.current.isActive)
runDir = "../../run"
}
runConfigs.remove(runConfigs["server"]) // Removes server run configs
}
loom.runs {
afterEvaluate {
val mixinJarFile = configurations.runtimeClasspath.get().incoming.artifactView {
componentFilter {
it is ModuleComponentIdentifier && it.group == "net.fabricmc" && it.module == "sponge-mixin"
}
}.files.first()
configureEach {
vmArg("-javaagent:$mixinJarFile")
property("mixin.hotSwap", "true")
property("mixin.debug.export", "true") // Puts mixin outputs in /run/.mixin.out
property("devauth.enabled", "true")
property("devauth.account", "main")
}
}
}
fletchingTable {
mixins.create("main") {
mixin("default", "${mod.id}.mixins.json")
}
lang.create("main") {
patterns.add("assets/${mod.id}/lang/**")
}
}
dependencies {
minecraft("com.mojang:minecraft:${mod.minecraftVersion}")
@Suppress("UnstableApiUsage")
mappings(loom.layered {
officialMojangMappings()
// Parchment mappings (it adds parameter mappings & javadoc)
optionalProp("deps.parchment_version") {
parchment("org.parchmentmc.data:parchment-${mod.minecraftVersion}:$it@zip")
}
})
modImplementation("maven.modrinth:midnightlib:${deps.midnightLibVersion}+${mod.minecraftVersion}-${loader.name}")
compileOnly("org.projectlombok:lombok:${deps.lombokVersion}")
annotationProcessor("org.projectlombok:lombok:${deps.lombokVersion}")
modRuntimeOnly("me.djtheredstoner:DevAuth-${loader.name}:${deps.devAuthVersion}")
include(implementation("com.moulberry:mixinconstraints:${deps.mixinConstraintsVersion}")!!)!!
include(implementation(annotationProcessor("com.github.bawnorton.mixinsquared:mixinsquared-${loader.name}:${deps.mixinSquaredVersion}")!!)!!)
if (loader.isFabric) {
modImplementation("net.fabricmc:fabric-loader:${deps.fabricLoaderVersion}")!!
modImplementation("net.fabricmc.fabric-api:fabric-api:${deps.fabricApiVersion}")
optionalProp("deps.modmenu_version") { prop ->
modImplementation("com.terraformersmc:modmenu:$prop") {
exclude(group, "net.fabricmc.fabric-api")
}
}
} else if (loader.isNeoForge) {
"neoForge"("net.neoforged:neoforge:${deps.neoForgeVersion}")
}
}
publishMods {
}
tasks {
processResources {
val props = buildMap {
put("id", mod.id)
put("name", mod.name)
put("version", mod.version)
put("description", mod.description)
put("source", mod.source)
put("issues", mod.issues)
put("license", mod.license)
put("modrinth", mod.modrinth)
put("curseforge", mod.curseforge)
put("discord", mod.discord)
put("minecraft_version_range", mod.minecraftVersionRange)
if (loader.isFabric) {
put("fabric_api_version", deps.fabricApiVersion?.trim())
put("fabric_loader_version", deps.fabricLoaderVersion?.trim())
} else if (loader.isNeoForge) {
put("neoforge_version", deps.neoForgeVersion?.trim())
}
}
props.forEach(inputs::property)
filesMatching("**/lang/en_us.json") { // Defaults description to English translation
expand(props)
filteringCharset = "UTF-8"
}
if (loader.isFabric) {
filesMatching("fabric.mod.json") { expand(props) }
exclude(listOf("META-INF/neoforge.mods.toml"))
}
if (loader.isNeoForge) {
filesMatching("META-INF/neoforge.mods.toml") { expand(props) }
exclude(listOf("fabric.mod.json"))
}
}
// Builds the version into a shared folder in `build/libs/${mod version}/`
register<Copy>("buildAndCollect") {
group = "build"
from(remapJar.map { it.archiveFile }, remapSourcesJar.map { it.archiveFile })
into(rootProject.layout.buildDirectory.file("libs/${project.property("mod.version")}"))
dependsOn("build")
}
}
if (stonecutter.current.isActive) {
rootProject.tasks.register("buildActive") {
group = "project"
dependsOn(tasks.named("build"))
}
}
fun <T> optionalProp(property: String, block: (String) -> T?): T? =
findProperty(property)?.toString()?.takeUnless { it.isBlank() }?.let(block)

View File

@@ -1,24 +0,0 @@
architectury {
common(rootProject.enabled_platforms.split(","))
}
dependencies {
// We depend on fabric loader here to use the fabric @Environment annotations and get the mixin dependencies
// Do NOT use other classes from fabric loader
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modCompileOnlyApi "maven.modrinth:midnightlib:${rootProject.midnightlib_version}-fabric"
}
publishing {
publications {
mavenCommon(MavenPublication) {
artifactId = rootProject.archives_base_name
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.
}
}

View File

@@ -1,37 +0,0 @@
package eu.midnightdust.swordblocking;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.component.DataComponentTypes;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.*;
import java.util.HashMap;
import java.util.Map;
public class SwordBlockingClient {
public static final String MOD_ID = "swordblocking";
public static Map<BipedEntityRenderState, LivingEntity> RENDER_STATE_TO_ENTITY_MAP = new HashMap<>();
public static void init() {
SwordBlockingConfig.init(MOD_ID, SwordBlockingConfig.class);
}
public static boolean isEntityBlocking(LivingEntity entity) {
return SwordBlockingConfig.enabled && entity.isUsingItem() && canShieldSwordBlock(entity);
}
public static boolean canShieldSwordBlock(LivingEntity entity) {
if (SwordBlockingConfig.enabled && (entity.getOffHandStack().getItem() instanceof ShieldItem || entity.getMainHandStack().getItem() instanceof ShieldItem)) {
Item weaponItem = entity.getOffHandStack().getItem() instanceof ShieldItem ? entity.getMainHandStack().getItem() : entity.getOffHandStack().getItem();
return weaponItem.getComponents().contains(DataComponentTypes.DAMAGE);
} else {
return false;
}
}
public static boolean shouldHideShield(LivingEntity entity, ItemStack stack) {
return SwordBlockingConfig.enabled && (SwordBlockingConfig.alwaysHideShield && SwordBlockingConfig.hideShield && stack.getItem() instanceof ShieldItem)
|| (SwordBlockingConfig.hideShield && stack.getItem() instanceof ShieldItem && SwordBlockingClient.canShieldSwordBlock(entity));
}
}

View File

@@ -1,13 +0,0 @@
package eu.midnightdust.swordblocking.config;
import eu.midnightdust.lib.config.MidnightConfig;
public class SwordBlockingConfig extends MidnightConfig {
@Entry public static boolean enabled = true;
@Entry public static boolean hideShield = true;
@Entry public static boolean alwaysHideShield = true;
@Entry public static boolean hideOffhandSlot = false;
@Entry public static boolean disableUseEquipAnimation = false;
@Entry public static boolean lockBlockingArmPosition = false;
@Entry public static boolean blockHitAnimation = false;
}

View File

@@ -1,43 +0,0 @@
package eu.midnightdust.swordblocking.mixin;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ShieldItem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(BipedEntityModel.class)
public abstract class MixinBipedEntityModel<T extends BipedEntityRenderState> {
@Shadow
protected abstract void positionRightArm(T entityRenderState, BipedEntityModel.ArmPose armPose);
@Shadow
protected abstract void positionLeftArm(T entityRenderState, BipedEntityModel.ArmPose armPose);
@Inject(method = "setAngles(Lnet/minecraft/client/render/entity/state/BipedEntityRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/entity/model/BipedEntityModel;animateArms(Lnet/minecraft/client/render/entity/state/BipedEntityRenderState;F)V", shift = At.Shift.BEFORE))
private void swordBlocking$setBlockingAngles(T bipedEntityRenderState, CallbackInfo ci) {
LivingEntity livingEntity = SwordBlockingClient.RENDER_STATE_TO_ENTITY_MAP.get(bipedEntityRenderState);
if (livingEntity == null || !SwordBlockingClient.isEntityBlocking(livingEntity))
return;
if (livingEntity.getOffHandStack().getItem() instanceof ShieldItem)
this.positionRightArm(bipedEntityRenderState, BipedEntityModel.ArmPose.BLOCK);
else
this.positionLeftArm(bipedEntityRenderState, BipedEntityModel.ArmPose.BLOCK);
}
@Redirect(method = "positionBlockingArm", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/math/MathHelper;clamp(FFF)F"))
private float swordBlocking$lockArmPosition(float value, float min, float max) {
if (SwordBlockingConfig.enabled && SwordBlockingConfig.lockBlockingArmPosition) {
return 0F;
} else {
return value;
}
}
}

View File

@@ -1,21 +0,0 @@
package eu.midnightdust.swordblocking.mixin;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import net.minecraft.client.item.ItemModelManager;
import net.minecraft.client.render.entity.BipedEntityRenderer;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.client.render.entity.state.BipedEntityRenderState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.entity.mob.MobEntity;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(BipedEntityRenderer.class)
public abstract class MixinBipedEntityRenderer<T extends MobEntity, S extends BipedEntityRenderState, M extends BipedEntityModel<S>> {
@Inject(method = "updateBipedRenderState", at = @At("TAIL"))
private static void swordBlocking$storeEntity(LivingEntity entity, BipedEntityRenderState state, float tickDelta, ItemModelManager itemModelResolver, CallbackInfo ci) {
SwordBlockingClient.RENDER_STATE_TO_ENTITY_MAP.put(state, entity);
}
}

View File

@@ -1,31 +0,0 @@
package eu.midnightdust.swordblocking.mixin;
import com.llamalad7.mixinextras.sugar.Local;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.client.render.entity.feature.HeldItemFeatureRenderer;
import net.minecraft.client.render.entity.model.EntityModel;
import net.minecraft.client.render.entity.model.ModelWithArms;
import net.minecraft.client.render.entity.state.ArmedEntityRenderState;
import net.minecraft.client.render.item.ItemRenderState;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.util.Arm;
import net.minecraft.util.Hand;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(HeldItemFeatureRenderer.class)
public abstract class MixinHeldItemFeatureRenderer<S extends ArmedEntityRenderState, M extends EntityModel<S> & ModelWithArms> {
@Redirect(method = "renderItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/ItemRenderState;isEmpty()Z"))
private boolean swordBlocking$hideShield(ItemRenderState instance, @Local(argsOnly = true) Arm arm, @Local(argsOnly = true) S entityState) {
LivingEntity livingEntity = SwordBlockingClient.RENDER_STATE_TO_ENTITY_MAP.get(entityState);
if (SwordBlockingConfig.enabled && livingEntity != null) {
ItemStack itemStack = livingEntity.getStackInHand(arm == Arm.LEFT ? Hand.OFF_HAND : Hand.MAIN_HAND);
return SwordBlockingClient.shouldHideShield(livingEntity, itemStack);
}
return instance.isEmpty();
}
}

View File

@@ -1,80 +0,0 @@
package eu.midnightdust.swordblocking.mixin;
import com.llamalad7.mixinextras.sugar.Local;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.client.MinecraftClient;
import net.minecraft.client.network.AbstractClientPlayerEntity;
import net.minecraft.client.render.VertexConsumerProvider;
import net.minecraft.client.render.item.HeldItemRenderer;
import net.minecraft.client.util.math.MatrixStack;
import net.minecraft.entity.LivingEntity;
import net.minecraft.item.ItemDisplayContext;
import net.minecraft.item.ItemStack;
import net.minecraft.item.consume.UseAction;
import net.minecraft.util.Arm;
import net.minecraft.util.Hand;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(HeldItemRenderer.class)
public abstract class MixinHeldItemRenderer {
@Shadow
@Final
private MinecraftClient client;
@Shadow
protected abstract void applySwingOffset(MatrixStack matrices, Arm arm, float swingProgress);
@Inject(method = "renderItem(Lnet/minecraft/entity/LivingEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/item/ItemDisplayContext;Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/client/render/VertexConsumerProvider;I)V", at = @At("HEAD"), cancellable = true)
public void swordBlocking$hideShield(LivingEntity entity, ItemStack stack, ItemDisplayContext renderMode, MatrixStack matrices, VertexConsumerProvider vertexConsumer, int light, CallbackInfo ci) {
if (SwordBlockingClient.shouldHideShield(entity, stack)) {
ci.cancel();
}
}
@Redirect(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/network/AbstractClientPlayerEntity;getActiveHand()Lnet/minecraft/util/Hand;", ordinal = 1))
private Hand swordBlocking$changeActiveHand(AbstractClientPlayerEntity player) {
Hand activeHand = player.getActiveHand();
if (SwordBlockingClient.isEntityBlocking(player)) {
return swordBlocking$getBlockingHand(activeHand);
} else {
return activeHand;
}
}
@Redirect(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/item/ItemStack;getUseAction()Lnet/minecraft/item/consume/UseAction;"))
private UseAction swordBlocking$changeItemAction(ItemStack stack, @Local(argsOnly = true) AbstractClientPlayerEntity player, @Local(argsOnly = true) Hand hand) {
UseAction defaultUseAction = stack.getUseAction();
if (SwordBlockingClient.isEntityBlocking(player)) {
return swordBlocking$getBlockingHand(player.getActiveHand()) == hand ? UseAction.BLOCK : defaultUseAction;
} else {
return defaultUseAction;
}
}
@Inject(method = "renderFirstPersonItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/render/item/HeldItemRenderer;applyEquipOffset(Lnet/minecraft/client/util/math/MatrixStack;Lnet/minecraft/util/Arm;F)V", ordinal = 3, shift = At.Shift.AFTER))
private void swordBlocking$applySwingOffset(AbstractClientPlayerEntity player, float tickDelta, float pitch, Hand hand, float swingProgress, ItemStack item, float equipProgress, MatrixStack matrices, VertexConsumerProvider vertexConsumers, int light, CallbackInfo ci, @Local Arm arm) {
if (SwordBlockingConfig.enabled && SwordBlockingConfig.blockHitAnimation) {
applySwingOffset(matrices, arm, swingProgress);
}
}
@Inject(method = "resetEquipProgress", at = @At("HEAD"), cancellable = true)
private void swordBlocking$disableEquipAnimation(Hand hand, CallbackInfo ci) {
if (SwordBlockingConfig.disableUseEquipAnimation && this.client.player != null && this.client.player.isUsingItem()) {
ci.cancel();
}
}
@Unique
private Hand swordBlocking$getBlockingHand(Hand activeHand) {
return activeHand == Hand.MAIN_HAND ? Hand.OFF_HAND : Hand.MAIN_HAND;
}
}

View File

@@ -1,35 +0,0 @@
package eu.midnightdust.swordblocking.mixin;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.fabricmc.api.EnvType;
import net.fabricmc.api.Environment;
import net.minecraft.client.render.entity.PlayerEntityRenderer;
import net.minecraft.client.render.entity.model.BipedEntityModel;
import net.minecraft.entity.player.PlayerEntity;
import net.minecraft.item.ItemStack;
import net.minecraft.item.ShieldItem;
import net.minecraft.util.Hand;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
@Mixin(PlayerEntityRenderer.class)
public abstract class MixinPlayerEntityRenderer {
@Environment(EnvType.CLIENT)
@Inject(method = "getArmPose(Lnet/minecraft/entity/player/PlayerEntity;Lnet/minecraft/item/ItemStack;Lnet/minecraft/util/Hand;)Lnet/minecraft/client/render/entity/model/BipedEntityModel$ArmPose;", at = @At(value = "RETURN"), cancellable = true)
private static void swordBlocking$getArmPose(PlayerEntity player, ItemStack stack, Hand hand, CallbackInfoReturnable<BipedEntityModel.ArmPose> cir) {
if (SwordBlockingConfig.enabled) {
ItemStack handStack = player.getStackInHand(hand);
ItemStack offStack = player.getStackInHand(hand.equals(Hand.MAIN_HAND) ? Hand.OFF_HAND : Hand.MAIN_HAND);
if (!SwordBlockingConfig.alwaysHideShield && (handStack.getItem() instanceof ShieldItem) && !SwordBlockingClient.canShieldSwordBlock(player))
return;
if (offStack.getItem() instanceof ShieldItem && SwordBlockingClient.isEntityBlocking(player)) {
cir.setReturnValue(BipedEntityModel.ArmPose.BLOCK);
} else if (handStack.getItem() instanceof ShieldItem && SwordBlockingConfig.hideShield && (cir.getReturnValue() == BipedEntityModel.ArmPose.ITEM || cir.getReturnValue() == BipedEntityModel.ArmPose.BLOCK)) {
cir.setReturnValue(BipedEntityModel.ArmPose.EMPTY);
}
}
}
}

View File

@@ -1,17 +0,0 @@
{
"required": true,
"minVersion": "0.8",
"package": "eu.midnightdust.swordblocking.mixin",
"compatibilityLevel": "JAVA_17",
"client": [
"MixinBipedEntityModel",
"MixinBipedEntityRenderer",
"MixinHeldItemFeatureRenderer",
"MixinHeldItemRenderer",
"MixinInGameHud",
"MixinPlayerEntityRenderer"
],
"injectors": {
"defaultRequire": 1
}
}

View File

@@ -1,102 +0,0 @@
plugins {
id 'com.github.johnrengelman.shadow'
id "me.shedaniel.unified-publishing"
}
architectury {
platformSetupLoomIde()
fabric()
}
loom {
}
configurations {
common
shadowCommon // Don't use shadow from the shadow plugin since it *excludes* files.
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentFabric.extendsFrom common
archivesBaseName = rootProject.archives_base_name + "-fabric"
}
dependencies {
modImplementation "net.fabricmc:fabric-loader:${rootProject.fabric_loader_version}"
modApi "net.fabricmc.fabric-api:fabric-api:${rootProject.fabric_api_version}"
modImplementation include ("maven.modrinth:midnightlib:${rootProject.midnightlib_version}-fabric")
common(project(path: ":common", configuration: "namedElements")) { transitive false }
shadowCommon(project(path: ":common", configuration: "transformProductionFabric")) { transitive false }
}
processResources {
inputs.property "version", project.version
filesMatching("fabric.mod.json") {
expand "version": project.version
}
}
shadowJar {
exclude "architectury.common.json"
configurations = [project.configurations.shadowCommon]
archiveClassifier = "dev-shadow"
}
remapJar {
input.set shadowJar.archiveFile
dependsOn shadowJar
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
unifiedPublishing {
project {
displayName = "SwordBlocking $project.version - Fabric $project.minecraft_version"
releaseType = "$project.release_type"
changelog = releaseChangelog()
gameVersions = []
gameLoaders = ["fabric","quilt"]
mainPublication remapJar
relations {
depends {
curseforge = "fabric-api"
modrinth = "fabric-api"
}
includes {
curseforge = "midnightlib"
modrinth = "midnightlib"
}
}
var CURSEFORGE_TOKEN = project.findProperty("CURSEFORGE_TOKEN") ?: System.getenv("CURSEFORGE_TOKEN")
if (CURSEFORGE_TOKEN != null) {
curseforge {
token = CURSEFORGE_TOKEN
id = rootProject.curseforge_id
gameVersions.addAll "Java 21", project.minecraft_version
}
}
var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN")
if (MODRINTH_TOKEN != null) {
modrinth {
token = MODRINTH_TOKEN
id = rootProject.modrinth_id
version = "$project.version-$project.name"
gameVersions.addAll project.minecraft_version
}
}
}
}

View File

@@ -1,11 +0,0 @@
package eu.midnightdust.swordblocking.fabric;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import net.fabricmc.api.ClientModInitializer;
public class SwordBlockingClientFabric implements ClientModInitializer {
@Override
public void onInitializeClient() {
SwordBlockingClient.init();
}
}

View File

@@ -1,32 +0,0 @@
{
"schemaVersion": 1,
"id": "swordblocking",
"version": "${version}",
"name": "Sword Blocking",
"description": "Adds sword blocking to new versions, you just need a shield in your offhand (or ViaVersion)!",
"authors": [
"Motschen",
"TeamMidnightDust",
"lowercasebtw"
],
"contact": {
"homepage": "https://www.midnightdust.eu/",
"sources": "https://github.com/TeamMidnightDust/SwordBlocking",
"issues": "https://github.com/TeamMidnightDust/SwordBlocking/issues"
},
"license": "MIT",
"icon": "assets/swordblocking/icon.png",
"environment": "client",
"entrypoints": {
"client": [
"eu.midnightdust.swordblocking.fabric.SwordBlockingClientFabric"
]
},
"mixins": [
"swordblocking.mixins.json"
],
"depends": {
"fabric-api": "*",
"midnightlib": "*"
}
}

View File

@@ -1,24 +1,44 @@
org.gradle.jvmargs=-Xmx3G # Done to increase the memory available to Gradle.
org.gradle.jvmargs=-Xmx4G
org.gradle.parallel=true org.gradle.parallel=true
# Game Version # IntelliJ IDEA is not yet fully compatible with configuration cache, see: https://github.com/FabricMC/fabric-loom/issues/1349
minecraft_version=1.21.6 org.gradle.configuration-cache=false
yarn_mappings=1.21.6+build.1
yarn_mappings_patch_neoforge_version=1.21+build.4 # Mod properties
enabled_platforms=fabric,neoforge mod.name=SwordBlocking
mod.id=swordblocking
mod.version=1.0
mod.group=eu.midnightdust.swordblocking
mod.description=Adds sword blocking to new versions, you just need a shield in your offhand (or ViaVersion)!
mod.source=https://github.com/TeamMidnightDust/SwordBlocking
mod.issues=https://github.com/TeamMidnightDust/SwordBlocking/issues
mod.license=MIT
mod.modrinth=https://modrinth.com/mod/sword-blocking
mod.curseforge=http://curseforge.com/minecraft/mc-mods/sword-blocking
mod.discord=https://discord.gg/jAGnWYHm3r
# Publishing
publish.modrinth=
publish.curseforge=
# Dependencies # Dependencies
midnightlib_version=1.7.5+1.21.6 deps.fabric_loader_version=0.17.3
deps.midnightlib_version=1.9.1
fabric_loader_version=0.16.14 deps.devauth_version=1.2.1
fabric_api_version=0.127.1+1.21.6 deps.lombok_version=1.18.42
deps.mixinconstraints_version=1.1.0
deps.mixinsquared_version=0.2.0
neoforge_version=21.6.0-beta # Build Plugins
# in libs.versions.toml
# Information # Minecraft properties
archives_base_name=swordblocking mod.mc_dep=[VERSIONED]
mod_version=2.2.2 mod.mc_version=[VERSIONED]
maven_group=eu.midnightdust
release_type=release # Versioned
curseforge_id=427738 deps.parchment_version=[VERSIONED]
modrinth_id=4q52b4lD deps.fabric_api_version=[VERSIONED]
deps.neoforge_version=[VERSIONED]

16
gradle/libs.versions.toml Normal file
View File

@@ -0,0 +1,16 @@
[versions]
kotlin-jvm = "2.2.0"
loom = "1.13-SNAPSHOT"
publishing = "0.8.4"
blossom = "1.3.2"
ksp = "2.2.0-2.0.2"
fletchingtable = "0.1.0-alpha.13"
[plugins]
kotlin-jvm = { id = "org.jetbrains.kotlin.jvm", version.ref = "kotlin-jvm" }
loom = { id = "dev.architectury.loom", version.ref = "loom" }
publishing = { id = "me.modmuss50.mod-publish-plugin", version.ref = "publishing" }
blossom = { id = "net.kyori.blossom", version.ref = "blossom" }
ksp = { id = "com.google.devtools.ksp", version.ref = "ksp" }
fletchingtable-fabric = { id = "dev.kikugie.fletching-table.fabric", version.ref = "fletchingtable" }
fletchingtable-neoforge = { id = "dev.kikugie.fletching-table.neoforge", version.ref = "fletchingtable" }

Binary file not shown.

View File

@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.14.2-bin.zip distributionUrl=https\://services.gradle.org/distributions/gradle-9.0.0-bin.zip
networkTimeout=10000 networkTimeout=10000
validateDistributionUrl=true validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME zipStoreBase=GRADLE_USER_HOME

2
gradlew vendored
View File

@@ -1,7 +1,7 @@
#!/bin/sh #!/bin/sh
# #
# Copyright © 2015-2021 the original authors. # Copyright © 2015 the original authors.
# #
# Licensed under the Apache License, Version 2.0 (the "License"); # Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License. # you may not use this file except in compliance with the License.

20
gradlew.bat vendored
View File

@@ -43,11 +43,11 @@ set JAVA_EXE=java.exe
%JAVA_EXE% -version >NUL 2>&1 %JAVA_EXE% -version >NUL 2>&1
if %ERRORLEVEL% equ 0 goto execute if %ERRORLEVEL% equ 0 goto execute
echo. 1>&2 echo.
echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH. 1>&2 echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
echo. 1>&2 echo.
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. 1>&2 echo location of your Java installation.
goto fail goto fail
@@ -57,11 +57,11 @@ set JAVA_EXE=%JAVA_HOME%/bin/java.exe
if exist "%JAVA_EXE%" goto execute if exist "%JAVA_EXE%" goto execute
echo. 1>&2 echo.
echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME% 1>&2 echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
echo. 1>&2 echo.
echo Please set the JAVA_HOME variable in your environment to match the 1>&2 echo Please set the JAVA_HOME variable in your environment to match the
echo location of your Java installation. 1>&2 echo location of your Java installation.
goto fail goto fail

View File

@@ -1,111 +0,0 @@
plugins {
id 'com.github.johnrengelman.shadow'
id "me.shedaniel.unified-publishing"
}
repositories {
maven {
name = 'NeoForged'
url = 'https://maven.neoforged.net/releases'
}
}
architectury {
platformSetupLoomIde()
neoForge()
}
loom {
accessWidenerPath = project(":common").loom.accessWidenerPath
}
configurations {
common {
canBeResolved = true
canBeConsumed = false
}
compileClasspath.extendsFrom common
runtimeClasspath.extendsFrom common
developmentNeoForge.extendsFrom common
// Files in this configuration will be bundled into your mod using the Shadow plugin.
// Don't use the `shadow` configuration from the plugin itself as it's meant for excluding files.
shadowBundle {
canBeResolved = true
canBeConsumed = false
}
archivesBaseName = rootProject.archives_base_name + "-neoforge"
}
dependencies {
neoForge "net.neoforged:neoforge:$rootProject.neoforge_version"
modImplementation include ("maven.modrinth:midnightlib:${rootProject.midnightlib_version}-neoforge")
common(project(path: ':common', configuration: 'namedElements')) { transitive false }
shadowBundle project(path: ':common', configuration: 'transformProductionNeoForge')
}
processResources {
inputs.property 'version', project.version
filesMatching('META-INF/neoforge.mods.toml') {
expand version: project.version
}
}
shadowJar {
configurations = [project.configurations.shadowBundle]
archiveClassifier = 'dev-shadow'
}
remapJar {
input.set shadowJar.archiveFile
}
sourcesJar {
def commonSources = project(":common").sourcesJar
dependsOn commonSources
from commonSources.archiveFile.map { zipTree(it) }
}
components.java {
withVariantsFromConfiguration(project.configurations.shadowRuntimeElements) {
skip()
}
}
unifiedPublishing {
project {
displayName = "SwordBlocking $project.version - NeoForge $project.minecraft_version"
releaseType = "$project.release_type"
changelog = releaseChangelog()
gameVersions = []
gameLoaders = ["neoforge"]
mainPublication remapJar
relations {
includes {
curseforge = "midnightlib"
modrinth = "midnightlib"
}
}
var CURSEFORGE_TOKEN = project.findProperty("CURSEFORGE_TOKEN") ?: System.getenv("CURSEFORGE_TOKEN")
if (CURSEFORGE_TOKEN != null) {
curseforge {
token = CURSEFORGE_TOKEN
id = rootProject.curseforge_id
gameVersions.addAll "Java 21", project.minecraft_version
}
}
var MODRINTH_TOKEN = project.findProperty("MODRINTH_TOKEN") ?: System.getenv("MODRINTH_TOKEN")
if (MODRINTH_TOKEN != null) {
modrinth {
token = MODRINTH_TOKEN
id = rootProject.modrinth_id
version = "$project.version-$project.name"
gameVersions.addAll project.minecraft_version
}
}
}
}

View File

@@ -1 +0,0 @@
loom.platform=neoforge

View File

@@ -1,15 +0,0 @@
package eu.midnightdust.swordblocking.neoforge;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.common.Mod;
import static eu.midnightdust.swordblocking.SwordBlockingClient.MOD_ID;
@SuppressWarnings("all")
@Mod(value = MOD_ID, dist = Dist.CLIENT)
public class SwordBlockingClientNeoForge {
public SwordBlockingClientNeoForge() {
SwordBlockingClient.init();
}
}

View File

@@ -1,38 +0,0 @@
modLoader = "javafml"
loaderVersion = "[2,)"
#issueTrackerURL = ""
license = "MIT License"
[[mods]]
modId = "swordblocking"
version = "${version}"
displayName = "Sword Blocking"
logoFile = "icon.png"
authors = "Motschen, TeamMidnightDust, lowercasebtw"
description = '''
Adds sword blocking to new versions, you just need a shield in your offhand (or ViaVersion)!
'''
[[mixins]]
config = "swordblocking.mixins.json"
[[dependencies.visualoverhaul]]
modId = "neoforge"
mandatory = true
versionRange = "[21.0,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.visualoverhaul]]
modId = "minecraft"
mandatory = true
versionRange = "[1.21,)"
ordering = "NONE"
side = "BOTH"
[[dependencies.visualoverhaul]]
modId = "picturesign"
mandatory = true
versionRange = "[1.0,)"
ordering = "AFTER"
side = "BOTH"

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,15 +0,0 @@
pluginManagement {
repositories {
maven { url "https://maven.fabricmc.net/" }
maven { url "https://maven.architectury.dev/" }
maven { url "https://maven.neoforged.net/releases" }
gradlePluginPortal()
}
}
include("common")
include("fabric")
//include("quilt")
include("neoforge")
rootProject.name = "swordblocking"

40
settings.gradle.kts Normal file
View File

@@ -0,0 +1,40 @@
pluginManagement {
repositories {
mavenCentral()
gradlePluginPortal()
maven("https://maven.fabricmc.net")
maven("https://maven.architectury.dev")
maven("https://maven.kikugie.dev/snapshots")
maven("https://maven.kikugie.dev/releases")
maven("https://repo.polyfrost.cc/releases")
}
}
plugins {
id("dev.kikugie.stonecutter") version "0.7.10"
}
stonecutter {
kotlinController = true
centralScript = "build.gradle.kts"
create(rootProject) {
fun mc(mcVersion: String, loaders: Iterable<String>) {
for (loader in loaders) {
version("$mcVersion-$loader", mcVersion)
}
}
mc("1.21.8", listOf("fabric", "neoforge"))
mc("1.21.10", listOf("fabric", "neoforge"))
vcsVersion = "1.21.8-fabric"
}
}
dependencyResolutionManagement {
versionCatalogs {
create("libs")
}
}
rootProject.name = "SwordBlocking"

View File

@@ -0,0 +1,66 @@
package eu.midnightdust.swordblocking;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.core.component.DataComponents;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ShieldItem;
//? fabric {
import dev.kikugie.fletching_table.annotation.fabric.Entrypoint;
import net.fabricmc.api.ClientModInitializer;
//?} else {
/*import net.neoforged.api.distmarker.Dist;
import net.neoforged.fml.common.Mod;
*///?}
//? fabric
@Entrypoint
//? neoforge
/*@Mod(value = SwordBlockingClient.MOD_ID, dist = Dist.CLIENT)*/
public final class SwordBlockingClient
//? fabric
implements ClientModInitializer
{
public static final String MOD_ID = "@MODID@";
// TODO/NOTE: I know this can be condensed more but i'm tired so will recheck later
public static boolean canEntityBlock(ItemStack mainHandStack, ItemStack offHandStack) {
return SwordBlockingConfig.enabled && canShieldSwordBlock(mainHandStack, offHandStack);
}
// TODO/NOTE: I know this can be condensed more but i'm tired so will recheck later
public static boolean canShieldSwordBlock(ItemStack mainHandStack, ItemStack offHandStack) {
if (SwordBlockingConfig.enabled && (offHandStack.getItem() instanceof ShieldItem || mainHandStack.getItem() instanceof ShieldItem)) {
final Item weaponItem = offHandStack.getItem() instanceof ShieldItem ? mainHandStack.getItem() : offHandStack.getItem();
return weaponItem.components().has(DataComponents.DAMAGE);
} else {
return false;
}
}
// TODO/NOTE: I know this can be condensed more but i'm tired so will recheck later
public static boolean shouldHideShield(ItemStack mainHandStack, ItemStack offHandStack, ItemStack stack) {
if (SwordBlockingConfig.enabled && stack.getItem() instanceof ShieldItem) {
return (SwordBlockingConfig.alwaysHideShield && SwordBlockingConfig.hideShield) ||
(SwordBlockingConfig.hideShield && SwordBlockingClient.canShieldSwordBlock(mainHandStack, offHandStack));
} else {
return false;
}
}
private void initialize() {
SwordBlockingConfig.init(MOD_ID, SwordBlockingConfig.class);
}
//? neoforge {
/*public SwordBlockingClient() {
initialize();
}
*///?} else {
@Override
public void onInitializeClient() {
initialize();
}
//?}
}

View File

@@ -0,0 +1,26 @@
package eu.midnightdust.swordblocking.config;
import eu.midnightdust.lib.config.MidnightConfig;
public class SwordBlockingConfig extends MidnightConfig {
@Entry
public static boolean enabled = true;
@Entry
public static boolean hideShield = true;
@Entry
public static boolean alwaysHideShield = true;
@Entry
public static boolean hideOffhandSlot = false;
@Entry
public static boolean disableUseEquipAnimation = false;
@Entry
public static boolean lockBlockingArmPosition = false;
@Entry
public static boolean blockHitAnimation = false;
}

View File

@@ -0,0 +1,16 @@
package eu.midnightdust.swordblocking.ducks;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.item.ItemStack;
public interface ArmedItemStackData {
ItemStack swordblocking$getItemHeldByArm(HumanoidArm humanoidArm);
ItemStack swordblocking$getOffHandItem();
void swordblocking$setOffHandItem(ItemStack stack);
ItemStack swordblocking$getMainHandItem();
void swordblocking$setMainHandItem(ItemStack stack);
}

View File

@@ -0,0 +1,60 @@
package eu.midnightdust.swordblocking.mixins;
import eu.midnightdust.swordblocking.ducks.ArmedItemStackData;
import net.minecraft.client.renderer.entity.state.ArmedEntityRenderState;
import net.minecraft.client.renderer.item.ItemModelResolver;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemStack;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(ArmedEntityRenderState.class)
public abstract class MixinArmedEntityRenderState implements ArmedItemStackData {
@Unique
private ItemStack swordblocking$offHandStack = ItemStack.EMPTY;
@Unique
private ItemStack swordblocking$mainHandStack = ItemStack.EMPTY;
@Inject(method = "extractArmedEntityRenderState", at = @At("TAIL"))
private static void swordBlocking$storeRequiredData(LivingEntity livingEntity, ArmedEntityRenderState armedEntityRenderState, ItemModelResolver itemModelResolver, CallbackInfo ci) {
ArmedItemStackData armedItemStackData = (ArmedItemStackData) armedEntityRenderState;
armedItemStackData.swordblocking$setOffHandItem(livingEntity.getOffhandItem());
armedItemStackData.swordblocking$setMainHandItem(livingEntity.getMainHandItem());
}
@Override
public ItemStack swordblocking$getItemHeldByArm(HumanoidArm arm) {
if (arm == HumanoidArm.LEFT) {
return swordblocking$offHandStack;
} else if (arm == HumanoidArm.RIGHT) {
return swordblocking$mainHandStack;
} else {
throw new UnsupportedOperationException();
}
}
@Override
public ItemStack swordblocking$getOffHandItem() {
return this.swordblocking$offHandStack;
}
@Override
public void swordblocking$setOffHandItem(ItemStack stack) {
this.swordblocking$offHandStack = stack;
}
@Override
public ItemStack swordblocking$getMainHandItem() {
return this.swordblocking$mainHandStack;
}
@Override
public void swordblocking$setMainHandItem(ItemStack stack) {
this.swordblocking$mainHandStack = stack;
}
}

View File

@@ -1,16 +1,16 @@
package eu.midnightdust.swordblocking.mixin; package eu.midnightdust.swordblocking.mixins;
import com.llamalad7.mixinextras.injector.ModifyExpressionValue; import com.llamalad7.mixinextras.injector.ModifyExpressionValue;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig; import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.client.gui.hud.InGameHud; import net.minecraft.client.gui.Gui;
import net.minecraft.item.ItemStack; import net.minecraft.world.item.ItemStack;
import net.minecraft.item.ShieldItem; import net.minecraft.world.item.ShieldItem;
import org.spongepowered.asm.mixin.Mixin; import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At; import org.spongepowered.asm.mixin.injection.At;
@Mixin(InGameHud.class) @Mixin(Gui.class)
public abstract class MixinInGameHud { public abstract class MixinGui {
@ModifyExpressionValue(at = @At(value = "INVOKE", target = "Lnet/minecraft/entity/player/PlayerEntity;getOffHandStack()Lnet/minecraft/item/ItemStack;"), method = "renderHotbarVanilla") @ModifyExpressionValue(method = "renderItemHotbar", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/player/Player;getOffhandItem()Lnet/minecraft/world/item/ItemStack;"))
public ItemStack swordBlocking$hideOffHandSlot(ItemStack original) { public ItemStack swordBlocking$hideOffHandSlot(ItemStack original) {
if (SwordBlockingConfig.enabled && SwordBlockingConfig.hideOffhandSlot && original.getItem() instanceof ShieldItem) { if (SwordBlockingConfig.enabled && SwordBlockingConfig.hideOffhandSlot && original.getItem() instanceof ShieldItem) {
return ItemStack.EMPTY; return ItemStack.EMPTY;

View File

@@ -0,0 +1,48 @@
package eu.midnightdust.swordblocking.mixins;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import eu.midnightdust.swordblocking.ducks.ArmedItemStackData;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.client.renderer.entity.state.HumanoidRenderState;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ShieldItem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(HumanoidModel.class)
public abstract class MixinHumanoidModel {
@Shadow
protected abstract void poseLeftArm(HumanoidRenderState renderState, HumanoidModel.ArmPose pose);
@Shadow
protected abstract void poseRightArm(HumanoidRenderState renderState, HumanoidModel.ArmPose pose);
@Inject(method = "setupAnim(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;)V", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/model/HumanoidModel;setupAttackAnimation(Lnet/minecraft/client/renderer/entity/state/HumanoidRenderState;F)V", shift = At.Shift.BEFORE))
private void swordBlocking$setBlockingAngles(HumanoidRenderState renderState, CallbackInfo ci) {
final ArmedItemStackData armedItemStackData = (ArmedItemStackData) renderState;
final ItemStack offHandStack = armedItemStackData.swordblocking$getOffHandItem();
final ItemStack mainHandStack = armedItemStackData.swordblocking$getMainHandItem();
if (renderState.isUsingItem && SwordBlockingClient.canEntityBlock(mainHandStack, offHandStack)) {
if (offHandStack.getItem() instanceof ShieldItem) {
this.poseRightArm(renderState, HumanoidModel.ArmPose.BLOCK);
} else {
this.poseLeftArm(renderState, HumanoidModel.ArmPose.BLOCK);
}
}
}
@Redirect(method = "poseBlockingArm", at = @At(value = "INVOKE", target = "Lnet/minecraft/util/Mth;clamp(FFF)F"))
private float swordBlocking$lockArmPosition(float value, float min, float max) {
if (SwordBlockingConfig.enabled && SwordBlockingConfig.lockBlockingArmPosition) {
return 0F;
} else {
return value;
}
}
}

View File

@@ -0,0 +1,35 @@
package eu.midnightdust.swordblocking.mixins;
import com.llamalad7.mixinextras.sugar.Local;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import eu.midnightdust.swordblocking.ducks.ArmedItemStackData;
import net.minecraft.client.model.ArmedModel;
import net.minecraft.client.model.EntityModel;
import net.minecraft.client.renderer.entity.layers.ItemInHandLayer;
import net.minecraft.client.renderer.entity.state.ArmedEntityRenderState;
import net.minecraft.client.renderer.item.ItemStackRenderState;
import net.minecraft.world.entity.HumanoidArm;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Redirect;
@Mixin(ItemInHandLayer.class)
public abstract class MixinItemInHandLayer<S extends ArmedEntityRenderState, M extends EntityModel<S> & ArmedModel> {
@Redirect(
//? >=1.21.10 {
method = "submitArmWithItem",
//? } else {
/*method = "renderArmWithItem",
*///? }
at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/item/ItemStackRenderState;isEmpty()Z")
)
private boolean swordBlocking$hideShield(ItemStackRenderState instance, @Local(argsOnly = true) S renderState, @Local(argsOnly = true) HumanoidArm arm) {
if (SwordBlockingConfig.enabled) {
final ArmedItemStackData armedItemStackData = (ArmedItemStackData) renderState;
return SwordBlockingClient.shouldHideShield(armedItemStackData.swordblocking$getMainHandItem(), armedItemStackData.swordblocking$getOffHandItem(), armedItemStackData.swordblocking$getItemHeldByArm(arm));
}
return instance.isEmpty();
}
}

View File

@@ -0,0 +1,116 @@
package eu.midnightdust.swordblocking.mixins;
import com.llamalad7.mixinextras.injector.wrapmethod.WrapMethod;
import com.llamalad7.mixinextras.injector.wrapoperation.Operation;
import com.llamalad7.mixinextras.sugar.Local;
import com.mojang.blaze3d.vertex.PoseStack;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.client.Minecraft;
import net.minecraft.client.player.AbstractClientPlayer;
import net.minecraft.client.renderer.ItemInHandRenderer;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.entity.HumanoidArm;
import net.minecraft.world.entity.LivingEntity;
import net.minecraft.world.item.ItemDisplayContext;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ItemUseAnimation;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.Unique;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.Redirect;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
//? >=1.21.10 {
import net.minecraft.client.renderer.SubmitNodeCollector;
//? } else {
/*import net.minecraft.client.renderer.MultiBufferSource;
*///? }
@Mixin(ItemInHandRenderer.class)
public abstract class MixinItemInHandRenderer {
@Shadow
@Final
private Minecraft minecraft;
@Shadow
protected abstract void applyItemArmAttackTransform(PoseStack poseStack, HumanoidArm hand, float swingProgress);
@WrapMethod(method = "renderItem")
public void swordBlocking$hideShield(
LivingEntity entity,
ItemStack stack,
ItemDisplayContext displayContext,
PoseStack poseStack,
//? >=1.21.10 {
SubmitNodeCollector bufferSource,
//? } else {
/*MultiBufferSource bufferSource,
*///? }
int packedLight,
Operation<Void> original
) {
if (!SwordBlockingClient.shouldHideShield(entity.getMainHandItem(), entity.getOffhandItem(), stack)) {
original.call(entity, stack, displayContext, poseStack, bufferSource, packedLight);
}
}
@Redirect(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/player/AbstractClientPlayer;getUsedItemHand()Lnet/minecraft/world/InteractionHand;", ordinal = 1))
private InteractionHand swordBlocking$changeActiveHand(AbstractClientPlayer instance) {
final InteractionHand activeHand = instance.getUsedItemHand();
if (SwordBlockingClient.canEntityBlock(instance.getMainHandItem(), instance.getOffhandItem())) {
return swordBlocking$getBlockingHand(activeHand);
} else {
return activeHand;
}
}
@Redirect(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/item/ItemStack;getUseAnimation()Lnet/minecraft/world/item/ItemUseAnimation;"))
private ItemUseAnimation swordBlocking$changeItemAction(ItemStack stack, @Local(argsOnly = true) AbstractClientPlayer player, @Local(argsOnly = true) InteractionHand interactionHand) {
final ItemUseAnimation defaultUseAction = stack.getUseAnimation();
if (SwordBlockingClient.canEntityBlock(player.getMainHandItem(), player.getOffhandItem())) {
return swordBlocking$getBlockingHand(player.getUsedItemHand()) == interactionHand ? ItemUseAnimation.BLOCK : defaultUseAction;
} else {
return defaultUseAction;
}
}
@Inject(method = "renderArmWithItem", at = @At(value = "INVOKE", target = "Lnet/minecraft/client/renderer/ItemInHandRenderer;applyItemArmTransform(Lcom/mojang/blaze3d/vertex/PoseStack;Lnet/minecraft/world/entity/HumanoidArm;F)V", ordinal = 3, shift = At.Shift.AFTER))
private void swordBlocking$applySwingOffset(
AbstractClientPlayer player,
float partialTicks,
float pitch,
InteractionHand hand,
float swingProgress,
ItemStack stack,
float equippedProgress,
PoseStack poseStack,
//? >=1.21.10 {
SubmitNodeCollector bufferSource,
//? } else {
/*MultiBufferSource bufferSource,
*///? }
int combinedLight,
CallbackInfo ci,
@Local HumanoidArm arm
) {
if (SwordBlockingConfig.enabled && SwordBlockingConfig.blockHitAnimation) {
this.applyItemArmAttackTransform(poseStack, arm, swingProgress);
}
}
@WrapMethod(method = "itemUsed")
private void swordBlocking$disableEquipAnimation(InteractionHand hand, Operation<Void> original) {
if (!SwordBlockingConfig.disableUseEquipAnimation || this.minecraft.player == null || !this.minecraft.player.isUsingItem()) {
original.call(hand);
}
}
@Unique
private InteractionHand swordBlocking$getBlockingHand(InteractionHand interactionHand) {
return interactionHand == InteractionHand.MAIN_HAND ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND;
}
}

View File

@@ -0,0 +1,70 @@
package eu.midnightdust.swordblocking.mixins;
import eu.midnightdust.swordblocking.SwordBlockingClient;
import eu.midnightdust.swordblocking.config.SwordBlockingConfig;
import net.minecraft.client.model.HumanoidModel;
import net.minecraft.world.InteractionHand;
import net.minecraft.world.item.ItemStack;
import net.minecraft.world.item.ShieldItem;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable;
//? >=1.21.10 {
import net.minecraft.client.renderer.entity.player.AvatarRenderer;
import net.minecraft.world.entity.Avatar;
//? } else {
/*import net.minecraft.client.renderer.entity.player.PlayerRenderer;
import net.minecraft.world.entity.player.Player;
*///? }
//? fabric {
import net.fabricmc.api.Environment;
import net.fabricmc.api.EnvType;
//?}
@Mixin(
//? >=1.21.10 {
AvatarRenderer.class
//? } else {
/*PlayerRenderer.class
*///? }
)
public abstract class MixinPlayerRenderer {
//? fabric
@Environment(EnvType.CLIENT)
@Inject(
//? >=1.21.10 {
method = "getArmPose(Lnet/minecraft/world/entity/Avatar;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/client/model/HumanoidModel$ArmPose;",
//? } else {
/*method = "getArmPose(Lnet/minecraft/world/entity/player/Player;Lnet/minecraft/world/item/ItemStack;Lnet/minecraft/world/InteractionHand;)Lnet/minecraft/client/model/HumanoidModel$ArmPose;",
*///? }
at = @At(value = "RETURN"),
cancellable = true
)
private static void swordBlocking$getArmPose(
//? >=1.21.10 {
Avatar player,
//? } else {
/*Player player,
*///? }
ItemStack stack,
InteractionHand hand,
CallbackInfoReturnable<HumanoidModel.ArmPose> cir
) {
if (SwordBlockingConfig.enabled) {
final ItemStack handStack = player.getItemInHand(hand);
final ItemStack offStack = player.getItemInHand(hand.equals(InteractionHand.MAIN_HAND) ? InteractionHand.OFF_HAND : InteractionHand.MAIN_HAND);
if (!SwordBlockingConfig.alwaysHideShield && (handStack.getItem() instanceof ShieldItem) && !SwordBlockingClient.canShieldSwordBlock(player.getMainHandItem(), player.getOffhandItem())) {
return;
}
if (offStack.getItem() instanceof ShieldItem && SwordBlockingClient.canEntityBlock(player.getMainHandItem(), player.getOffhandItem())) {
cir.setReturnValue(HumanoidModel.ArmPose.BLOCK);
} else if (handStack.getItem() instanceof ShieldItem && SwordBlockingConfig.hideShield && (cir.getReturnValue() == HumanoidModel.ArmPose.ITEM || cir.getReturnValue() == HumanoidModel.ArmPose.BLOCK)) {
cir.setReturnValue(HumanoidModel.ArmPose.EMPTY);
}
}
}
}

View File

@@ -0,0 +1,37 @@
modLoader = "javafml"
loaderVersion = "[1,)"
license = "${license}"
issueTrackerURL = "${issues}"
[[mods]]
modId = "${id}"
version = "${version}"
displayName = "${name}"
description = "${description}"
logoFile = "assets/${id}/icon.png"
authors = ["Motschen", "TeamMidnightDust", "lowercasebtw"]
displayURL = "${modrinth}"
[[mixins]]
config = "${id}.mixins.json"
[[dependencies.${id}]]
modId = "neoforge"
mandatory = true
versionRange = "[${neoforge_version},)"
ordering = "NONE"
side = "CLIENT"
[[dependencies.${id}]]
modId = "minecraft"
mandatory = true
versionRange = "${minecraft_version_range}"
ordering = "NONE"
side = "CLIENT"
[[dependencies.${id}]]
modId = "midnightlib"
mandatory = true
versionRange = ""
ordering = "AFTER"
side = "CLIENT"

View File

Before

Width:  |  Height:  |  Size: 3.4 KiB

After

Width:  |  Height:  |  Size: 3.4 KiB

View File

@@ -1,11 +1,11 @@
{ {
"swordblocking.midnightconfig.title": "Конфигурация Sword Blocking", "swordblocking.midnightconfig.title": "Конфигурация Sword Blocking",
"swordblocking.midnightconfig.enabled": "Включено", "swordblocking.midnightconfig.enabled": "Включено",
"swordblocking.midnightconfig.hideShield": "Спрятать щит", "swordblocking.midnightconfig.hideShield": "Спрятать щит",
"swordblocking.midnightconfig.alwaysHideShield": "Всегда прятать щит", "swordblocking.midnightconfig.alwaysHideShield": "Всегда прятать щит",
"swordblocking.midnightconfig.hideOffhandSlot": "Скрывать слот второй руки", "swordblocking.midnightconfig.hideOffhandSlot": "Скрывать слот второй руки",
"swordblocking.midnightconfig.hideOffhandSlot.tooltip": "Скрывает слот второй руки, если в ней находится щит.", "swordblocking.midnightconfig.hideOffhandSlot.tooltip": "Скрывает слот второй руки, если в ней находится щит.",
"swordblocking.midnightconfig.disableUseEquipAnimation": "Удалять анимацию оснащения при блокировании.", "swordblocking.midnightconfig.disableUseEquipAnimation": "Удалять анимацию оснащения при блокировании.",
"swordblocking.midnightconfig.lockBlockingArmPosition": "Отключить движение руки при блокировании.", "swordblocking.midnightconfig.lockBlockingArmPosition": "Отключить движение руки при блокировании.",
"swordblocking.midnightconfig.blockHitAnimation": "Включить анимацию удара по блоку." "swordblocking.midnightconfig.blockHitAnimation": "Включить анимацию удара по блоку."
} }

View File

@@ -0,0 +1,35 @@
{
"schemaVersion": 1,
"id": "${id}",
"version": "${version}",
"name": "${name}",
"description": "${description}",
"authors": [
"Motschen",
"TeamMidnightDust",
"lowercasebtw"
],
"contact": {
"sources": "${source}",
"issues": "${issues}"
},
"license": "${license}",
"icon": "assets/${id}/icon.png",
"environment": "client",
"depends": {
"fabricloader": ">=${fabric_loader_version}",
"minecraft": "${minecraft_version_range}",
"fabric-api": "*",
"midnightlib": "*"
},
"custom": {
"modmenu": {
"links": {
"modmenu.discord": "${discord}",
"modmenu.modrinth": "${modrinth}",
"modmenu.curseforge": "${curseforge}"
},
"update_checker": true
}
}
}

View File

@@ -0,0 +1,19 @@
{
"required": true,
"package": "eu.midnightdust.swordblocking.mixins",
"compatibilityLevel": "JAVA_17",
"client": [
"MixinGui",
"MixinArmedEntityRenderState",
"MixinHumanoidModel",
"MixinItemInHandLayer",
"MixinItemInHandRenderer",
"MixinPlayerRenderer"
],
"injectors": {
"defaultRequire": 1
},
"mixinextras": {
"minVersion": "0.5.0"
}
}

25
stonecutter.gradle.kts Normal file
View File

@@ -0,0 +1,25 @@
import dev.kikugie.stonecutter.data.tree.struct.ProjectNode
plugins {
id("dev.kikugie.stonecutter")
alias(libs.plugins.publishing)
}
stonecutter active "1.21.10-fabric" /* [SC] DO NOT EDIT */
stonecutter tasks {
val ordering = Comparator
.comparing<ProjectNode, _> { stonecutter.parse(it.metadata.version) }
.thenComparingInt { if (it.metadata.project.endsWith("fabric")) 1 else 0 }
order("publishMods", ordering)
}
stonecutter parameters {
val loader = node.project.property("loom.platform")
constants["fabric"] = loader == "fabric"
constants["neoforge"] = loader == "neoforge"
}
tasks.named("publishMods") {
group = "build"
}

View File

@@ -0,0 +1,8 @@
loom.platform=fabric
deps.parchment_version=2025.10.12
deps.fabric_api_version=0.138.3+1.21.10
deps.modmenu_version=16.0.0-rc.1
mod.minecraft_version=1.21.10
mod.minecraft_version_range=>=1.21.9 <=1.21.10

View File

@@ -0,0 +1,7 @@
loom.platform=neoforge
deps.parchment_version=2025.10.12
deps.neoforge_version=21.10.55-beta
mod.minecraft_version=1.21.10
mod.minecraft_version_range=[1.21.9, 1.21.10]

View File

@@ -0,0 +1,8 @@
loom.platform=fabric
deps.parchment_version=2025.09.14
deps.fabric_api_version=0.136.1+1.21.8
deps.modmenu_version=15.0.0
mod.minecraft_version=1.21.8
mod.minecraft_version_range=>=1.21.6 <=1.21.8

View File

@@ -0,0 +1,7 @@
loom.platform=neoforge
deps.parchment_version=2025.09.14
deps.neoforge_version=21.8.51
mod.minecraft_version=1.21.8
mod.minecraft_version_range=[1.21.6, 1.21.7, 1.21.8]