13 Commits
Author SHA1 Message Date
caseload 3b13e277f7 Merge pull request #46 from NotPatch/dev
update: bump PacketEvents to version 2.11.2
2026-03-29 12:28:33 -07:00
NotPatch a8bb0f159a update: bump PacketEvents to version 2.11.2
Fixed packetevents could not initalize issue
2026-03-02 00:14:52 +03:00
Jyguy aa76e82b16 Fix incorrect config path for offground sync (#45) 2026-01-17 04:45:09 -05:00
Axionize 9c6f94c10b fix: 1.21.11 Fabric support 2025-12-17 22:53:11 -05:00
Axionize fec77fba15 update: 1.21.11 2025-12-17 18:19:23 -05:00
Axionize 3a5625508b Improve fabric dependency specificity 2025-11-23 20:14:19 -05:00
Axionize cb864f7eba Fix infinite netty listener relocation bug by bumping PacketEvents 2025-11-23 19:01:32 -05:00
Axionize 9d50254dec Fix buildscript issues with gradle version 2025-11-13 04:04:08 -05:00
Axionize 2bfd3c48b6 Fix buildscript, update shadowJar to V9 2025-11-13 03:54:29 -05:00
Axionize c6df9f029a 1.21.9/10 support 2025-11-13 03:04:35 -05:00
Axionize cc6e38c7f2 1.21.8 support 2025-08-11 00:21:57 -04:00
Axionize c22f4f0efe Make Modrinth Fabric version marked as 1.21.4-1.21.7 2025-07-07 00:17:09 -04:00
Axionize 71cd756337 1.21.6/1.21.7 Update 2025-07-01 02:04:28 -04:00
16 changed files with 164 additions and 131 deletions

No files matched your search

+8 -22
View File
@@ -28,11 +28,8 @@ jobs:
cache: '' # ← disable Maven/Gradle cache
# 3. Set up Gradle + dependency cache
- name: Set up Gradle 8.13
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: "8.13" # keep the quotes
# cache-enabled: true # default, uploads ~/.gradle
- name: Set up Gradle
uses: gradle/actions/setup-gradle@v5
- name: Generate build number
id: buildnumber
@@ -40,19 +37,6 @@ jobs:
with:
token: ${{ secrets.GITHUB_TOKEN }}
# Temporary tasks so built jar works because PacketEvents won't merge my fixes for their broken fabric support
- name: Clone Axionize's PacketEvents Repository
run: |
git clone -b fix/fabric-events https://github.com/Axionize/packetevents.git packetevents
cd packetevents
echo "Cloned PacketEvents repository"
- name: Build and Publish PacketEvents to Maven Local
uses: gradle/actions/setup-gradle@v3
with:
build-root-directory: packetevents
arguments: publishToMavenLocal
- name: Update version in build.gradle.kts
id: update_version
run: |
@@ -70,12 +54,12 @@ jobs:
sed -i "s/val snapshot = .*/val snapshot = false/" build.gradle.kts
- name: Build without PE shaded
run: gradle build -PshadePE=false -x test
run: ./gradlew build -PshadePE=false -x test
env:
GITHUB_REPOSITORY: ${{ github.repository }}
- name: Build with PE shaded Gradle
run: gradle build -PshadePE=true -x test
run: ./gradlew build -PshadePE=true -x test
env:
GITHUB_REPOSITORY: ${{ github.repository }}
@@ -214,8 +198,10 @@ jobs:
fabric
game-versions: |
1.21.4
1.21.5
1.21.11
dependencies: |
fabric-api
retry-attempts: 2
retry-delay: 10000
+31 -12
View File
@@ -2,8 +2,31 @@ import java.io.ByteArrayOutputStream
plugins {
id("java")
id("com.gradleup.shadow") version "8.3.3" apply false
id("fabric-loom") version "1.10.5" apply false
id("com.gradleup.shadow") version "9.2.2" apply false
id("fabric-loom") version "1.14.6" apply false
}
fun getGitCommitHash(project: Project): String? {
// Only try to get the hash if the .git directory exists
if (!project.file(".git").isDirectory) {
return null
}
return try {
val process = ProcessBuilder("git", "rev-parse", "--short", "HEAD")
.redirectOutput(ProcessBuilder.Redirect.PIPE)
.redirectError(ProcessBuilder.Redirect.PIPE)
.start()
process.waitFor(5, TimeUnit.SECONDS)
if (process.exitValue() == 0) {
process.inputStream.bufferedReader().readText().trim().takeIf { it.isNotEmpty() }
} else {
null
}
} catch (e: Exception) {
null
}
}
val fullVersion = "1.3.5"
@@ -23,14 +46,10 @@ allprojects {
if (!snapshot) {
return ""
}
var commitHash = ""
if (includeHash && file(".git").isDirectory) {
val stdout = ByteArrayOutputStream()
exec {
commandLine("git", "rev-parse", "--short", "HEAD")
standardOutput = stdout
}
commitHash = "+${stdout.toString().trim()}"
val commitHash = if (includeHash) {
getGitCommitHash(project)?.let { "+$it" } ?: ""
} else {
""
}
return "$commitHash-SNAPSHOT"
}
@@ -41,7 +60,8 @@ allprojects {
ext["githubRepo"] = githubRepo
repositories {
mavenLocal()
// mavenLocal()
maven("https://repo.grim.ac/snapshots")
mavenCentral()
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
maven("https://repo.codemc.io/repository/maven-releases/")
@@ -52,7 +72,6 @@ allprojects {
}
maven("https://libraries.minecraft.net/")
maven("https://maven.neoforged.net/releases")
maven("https://repo.codemc.io/repository/maven-snapshots/")
}
}
+4 -4
View File
@@ -40,11 +40,11 @@ dependencies {
shadeThisThing(implementation("org.kohsuke:github-api:1.326")!!)
if (shadePE) {
shadeThisThing(implementation("com.github.retrooper:packetevents-spigot:2.8.0-SNAPSHOT")!!)
shadeThisThing(implementation("com.github.retrooper:packetevents-spigot:2.11.2")!!)
} else {
compileOnly("com.github.retrooper:packetevents-spigot:2.8.0-SNAPSHOT")
compileOnly("com.github.retrooper:packetevents-spigot:2.11.2")
}
shadeThisThing(implementation("org.incendo:cloud-paper:2.0.0-beta.10")!!)
shadeThisThing(implementation("org.incendo:cloud-paper:2.0.0-beta.14")!!)
shadeThisThing(implementation("org.incendo:cloud-core:2.0.0")!!)
// Required for 1.14.4 support because gson is too old to have JosnParser.parseString()
@@ -60,7 +60,7 @@ tasks.withType<ShadowJar> {
archiveClassifier.set("")
configurations = listOf(shadeThisThing)
isEnableRelocation = true
enableAutoRelocation = true
relocationPrefix = "${project.property("maven_group")}.${project.property("archives_base_name")}.shaded"
}
@@ -1,5 +1,6 @@
package me.caseload.knockbacksync.stats.custom;
/*
* This Metrics class was auto-generated and can be copied into your project if you are
* not using a build tool like Gradle or Maven for dependency management.
+2 -2
View File
@@ -13,9 +13,9 @@ dependencies {
// Shaded in or bundled by platform-specific code
if (shadePE) {
implementation("com.github.retrooper:packetevents-api:2.8.0-SNAPSHOT")
implementation("com.github.retrooper:packetevents-api:2.11.1+60a2c34-SNAPSHOT")
} else {
compileOnly("com.github.retrooper:packetevents-api:2.8.0-SNAPSHOT")
compileOnly("com.github.retrooper:packetevents-api:2.11.1+60a2c34-SNAPSHOT")
}
implementation("org.yaml:snakeyaml:2.0")
@@ -52,10 +52,10 @@ public class ToggleOffGroundSubcommand implements BuilderCommand {
private void loadConfigSettings() {
ConfigWrapper configWrapper = Base.INSTANCE.getConfigManager().getConfigWrapper();
offGroundSyncEnabled = configWrapper.getBoolean("settings.offground.enabled", true);
offGroundSyncEnabled = configWrapper.getBoolean("enable_offground_synchronization", true);
this.offGroundSyncEnableMessage = configWrapper.getString("messages.offground.enable",
"&aSuccessfully enabled offground synchronization.");
this.offGroundSyncDisableMessage = configWrapper.getString("messages.offground.disable",
"&cSuccessfully disabled offground synchronization.");
}
}
}
+5 -6
View File
@@ -1,6 +1,5 @@
plugins {
id("fabric-loom")
id("com.gradleup.shadow")
}
loom {
@@ -38,9 +37,9 @@ dependencies {
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "${rootProject.property("fabric_version")}"))
modImplementation(fabricApi.module("fabric-events-interaction-v0", "${rootProject.property("fabric_version")}"))
include(modImplementation("me.lucko:fabric-permissions-api:0.3.1")!!)
include(modImplementation("com.github.retrooper:packetevents-fabric:2.8.0-SNAPSHOT")!!)
include(modImplementation("org.incendo:cloud-fabric:2.0.0-beta.10")!!)
include(modImplementation("me.lucko:fabric-permissions-api:0.6.1")!!)
include(modImplementation("com.github.retrooper:packetevents-fabric:2.11.1+60a2c34-SNAPSHOT")!!)
include(modImplementation("org.incendo:cloud-fabric:2.0.0-beta.15")!!)
include(implementation("org.incendo:cloud-minecraft-extras:2.0.0-beta.10")!!)
include(implementation("org.yaml:snakeyaml:2.0")!!)
@@ -70,8 +69,8 @@ tasks.processResources {
filesMatching("fabric.mod.json") {
expand(
"version" to project.version,
"minecraft_version" to rootProject.property("minecraft_version"),
"loader_version" to rootProject.property("loader_version")
"minecraft_version" to rootProject.property("minecraft_version")!!,
"loader_version" to rootProject.property("loader_version")!!
)
}
}
@@ -0,0 +1,59 @@
package me.caseload.knockbacksync.mixin;
import me.caseload.knockbacksync.callback.PlayerVelocityEvent;
import net.minecraft.entity.Entity;
import net.minecraft.server.network.EntityTrackerEntry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.Vec3d;
import org.objectweb.asm.Opcodes;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(EntityTrackerEntry.class)
public class EntityTrackerEntryMixin {
@Shadow @Final private Entity entity;
// We inject exactly where 'this.entity.knockedBack = false' is about to happen.
@Inject(method = "tick",
at = @At(value = "FIELD",
target = "Lnet/minecraft/entity/Entity;knockedBack:Z",
opcode = Opcodes.PUTFIELD),
cancellable = true)
private void onKnockbackSync(CallbackInfo ci) {
// This check ensures we are in the "if (entity.knockedBack)" block
// and operating on a Player.
if (this.entity instanceof ServerPlayerEntity serverPlayer) {
// 1. Capture the velocity CURRENTLY on the player
Vec3d currentVelocity = serverPlayer.getVelocity();
// 2. Fire the event
ActionResult result = PlayerVelocityEvent.EVENT.invoker().onVelocityChange(serverPlayer, currentVelocity);
if (result == ActionResult.FAIL) {
// CASE: CANCELLED
// We want to STOP the packet from sending.
// We also want to keep 'knockedBack' as true (technically),
// effectively acting like the block never happened.
ci.cancel();
}
else if (result == ActionResult.SUCCESS) {
// CASE: MODIFIED
// The event handler has already updated the player's velocity:
// player.setVelocity(newVel);
// We do NOT cancel. We let Vanilla proceed.
// Vanilla will:
// 1. Set knockedBack = false;
// 2. Create a NEW packet reading the current velocity (which is now your custom velocity).
// 3. Send it.
}
}
}
}
@@ -14,23 +14,50 @@ import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(PlayerEntity.class)
public class PlayerMixin {
@Inject(method = "attack", at = @At(value = "INVOKE", target = "Lnet/minecraft/network/packet/s2c/play/EntityVelocityUpdateS2CPacket;<init>(Lnet/minecraft/entity/Entity;)V"), cancellable = true)
private void onAttack(Entity target, CallbackInfo ci) {
if (target instanceof ServerPlayerEntity serverPlayer && target.velocityModified) {
Vec3d velocity = target.getVelocity();
ActionResult result = PlayerVelocityEvent.EVENT.invoker().onVelocityChange(serverPlayer, velocity);
@Inject(method = "knockbackTarget",
at = @At(value = "INVOKE",
target = "Lnet/minecraft/server/network/ServerPlayNetworkHandler;sendPacket(Lnet/minecraft/network/packet/Packet;)V"),
cancellable = true)
private void onKnockback(Entity target, float strength, Vec3d playerTargetVelocity, CallbackInfo ci) {
if (target instanceof ServerPlayerEntity serverPlayer && target.knockedBack) {
// 1. Get the "Proposed" Velocity (The knockback calculated lines above)
Vec3d proposedVelocity = target.getVelocity();
// 2. Fire the Event
ActionResult result = PlayerVelocityEvent.EVENT.invoker().onVelocityChange(serverPlayer, proposedVelocity);
if (result == ActionResult.FAIL) {
target.velocityModified = false;
ci.cancel(); // Prevent sending the velocity packet
} else if (result == ActionResult.SUCCESS) {
// Currently unnecessary since we do this in the handler, will move later
target.setVelocity(velocity);
serverPlayer.networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(target));
target.velocityModified = false;
ci.cancel(); // Prevent sending the original velocity packet
// --- REPLICATING PAPER: CANCELLED ---
// In Paper: if (event.isCancelled()) { cancelled = true; }
// In Paper: if (!cancelled) { sendPacket; cleanup; }
// So, if cancelled, we stop EVERYTHING. We do not send packet, we do not reset velocity.
ci.cancel();
return;
}
if (result == ActionResult.SUCCESS) {
// --- REPLICATING PAPER: MODIFIED ---
// In Paper: if (!velocity.equals(event.getVelocity())) { player.setVelocity(...) }
// In Paper: if (!cancelled) { sendPacket; setDeltaMovement(currentMovement); }
// 1. The event listener should have already set the new velocity on the entity.
// 2. We must send a NEW packet (because the one on the stack is old).
serverPlayer.networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(target));
// 3. Replicate the Cleanup: Paper resets velocity to 'currentMovement' (playerTargetVelocity)
// This prevents the server from thinking the player is flying, maintaining Client Authority.
target.knockedBack = false;
target.setVelocity(playerTargetVelocity);
// 4. Cancel the original logic so Vanilla doesn't send the old packet or do double cleanup.
ci.cancel();
}
// CASE: PASS
// Vanilla behaves normally (Sends packet, does cleanup).
}
}
}
}
@@ -1,59 +0,0 @@
package me.caseload.knockbacksync.mixin;
import me.caseload.knockbacksync.callback.PlayerVelocityEvent;
import net.minecraft.entity.Entity;
import net.minecraft.server.network.EntityTrackerEntry;
import net.minecraft.server.network.ServerPlayerEntity;
import net.minecraft.util.ActionResult;
import net.minecraft.util.math.Vec3d;
import org.spongepowered.asm.mixin.Final;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.Shadow;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
@Mixin(EntityTrackerEntry.class)
public class ServerEntityMixin {
@Shadow
@Final
private Entity entity;
// Velocity event
@Inject(method = "tick", at = @At(value = "FIELD", target = "Lnet/minecraft/entity/Entity;velocityModified:Z", ordinal = 1), cancellable = true)
private void onSendChanges(CallbackInfo ci) {
if (this.entity.velocityModified && this.entity instanceof ServerPlayerEntity player) {
Vec3d velocity = player.getVelocity();
ActionResult result = PlayerVelocityEvent.EVENT.invoker().onVelocityChange(player, velocity);
if (result == ActionResult.FAIL) {
this.entity.velocityModified = false;
ci.cancel();
} else if (result == ActionResult.SUCCESS) {
// Currently unnecessary since we do this in the handler, will move later
player.setVelocity(velocity);
}
}
}
// Custom tick intervals
// @Shadow
// private int updateInterval;
// @Accessor("entity")
// Entity getEntity() {
// return null;
// }
// @Invoker("sendChanges")
// void invokeSendChanges() {
//
// }
// @Override
// public void setUpdateInterval(int interval) {
// this.updateInterval = interval;
// }
}
@@ -91,7 +91,7 @@ public class FabricPlayer implements PlatformPlayer {
@Override
public PlatformWorld getWorld() {
return new FabricWorld(fabricPlayer.getWorld());
return new FabricWorld(fabricPlayer.getEntityWorld());
}
@Override
@@ -117,7 +117,7 @@ public class FabricPlayer implements PlatformPlayer {
@Override
public int getMainHandKnockbackLevel() {
RegistryEntry<Enchantment> knockbackEntry = fabricPlayer.getWorld().getRegistryManager().getOrThrow(RegistryKeys.ENCHANTMENT).getOrThrow(Enchantments.KNOCKBACK);
RegistryEntry<Enchantment> knockbackEntry = fabricPlayer.getEntityWorld().getRegistryManager().getOrThrow(RegistryKeys.ENCHANTMENT).getOrThrow(Enchantments.KNOCKBACK);
return EnchantmentHelper.getLevel(knockbackEntry, fabricPlayer.getMainHandStack());
}
@@ -131,7 +131,7 @@ public class FabricPlayer implements PlatformPlayer {
fabricPlayer.setVelocity(adjustedVelocity.x, adjustedVelocity.y, adjustedVelocity.z);
// TODO
// fix paper-ism? for some reason setVelocity() in paper marks the entity as hurt marked every time its called?
fabricPlayer.velocityModified = true;
fabricPlayer.velocityDirty = true;
}
@Override
@@ -29,7 +29,7 @@ public class CustomUpdateIntervals {
for (Entity entity : level.iterateEntities()) {
String entityType = entity.getType().getRegistryEntry().getIdAsString();
if (entityIntervals.containsKey(entityType)) {
ServerChunkLoadingManager.EntityTracker serverEntity = ((ServerChunkManager) entity.getWorld().getChunkManager()).chunkLoadingManager.entityTrackers.get(entity.getId());
ServerChunkLoadingManager.EntityTracker serverEntity = ((ServerChunkManager) entity.getEntityWorld().getChunkManager()).chunkLoadingManager.entityTrackers.get(entity.getId());
if (serverEntity != null) {
((UpdateIntervalAccessor) serverEntity).setUpdateInterval(entityIntervals.get(entityType));
}
+2 -1
View File
@@ -22,7 +22,8 @@
],
"depends": {
"fabricloader": ">=0.15.11",
"fabric": "*",
"fabric-lifecycle-events-v1": "*",
"fabric-events-interaction-v0": "*",
"minecraft": "~${minecraft_version}",
"packetevents": "*"
},
@@ -5,8 +5,8 @@
"compatibilityLevel": "JAVA_21",
"mixins": [
"ChunkMapMixin",
"EntityTrackerEntryMixin",
"PlayerMixin",
"ServerEntityMixin",
"TickRateManagerMixin"
],
"injectors": {
+3 -3
View File
@@ -4,8 +4,8 @@ org.gradle.parallel=true
# Fabric Properties
# check these on https://modmuss50.me/fabric.html
minecraft_version=1.21.5
yarn_mappings=1.21.5+build.1:v2
minecraft_version=1.21.11
yarn_mappings=1.21.11+build.3:v2
loader_version=0.16.13
# Mod Properties
@@ -14,6 +14,6 @@ archives_base_name=knockbacksync
# Dependencies
# check this on https://modmuss50.me/fabric.html
fabric_version=0.121.0+1.21.5
fabric_version=0.140.0+1.21.11
githubRepo=CASELOAD7000/knockback-sync
+1 -1
View File
@@ -1,6 +1,6 @@
distributionBase=GRADLE_USER_HOME
distributionPath=wrapper/dists
distributionUrl=https\://services.gradle.org/distributions/gradle-8.13-bin.zip
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
networkTimeout=10000
validateDistributionUrl=true
zipStoreBase=GRADLE_USER_HOME