Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
0d31816ede | ||
|
|
ff35ca78dd | ||
|
|
aa76e82b16 | ||
|
|
9c6f94c10b | ||
|
|
fec77fba15 | ||
|
|
3a5625508b | ||
|
|
cb864f7eba | ||
|
|
9d50254dec | ||
|
|
2bfd3c48b6 | ||
|
|
c6df9f029a | ||
|
|
cc6e38c7f2 | ||
|
|
c22f4f0efe | ||
|
|
71cd756337 |
No files matched your search
@@ -28,11 +28,8 @@ jobs:
|
|||||||
cache: '' # ← disable Maven/Gradle cache
|
cache: '' # ← disable Maven/Gradle cache
|
||||||
|
|
||||||
# 3. Set up Gradle + dependency cache
|
# 3. Set up Gradle + dependency cache
|
||||||
- name: Set up Gradle 8.13
|
- name: Set up Gradle
|
||||||
uses: gradle/actions/setup-gradle@v4
|
uses: gradle/actions/setup-gradle@v5
|
||||||
with:
|
|
||||||
gradle-version: "8.13" # keep the quotes
|
|
||||||
# cache-enabled: true # default, uploads ~/.gradle
|
|
||||||
|
|
||||||
- name: Generate build number
|
- name: Generate build number
|
||||||
id: buildnumber
|
id: buildnumber
|
||||||
@@ -40,19 +37,6 @@ jobs:
|
|||||||
with:
|
with:
|
||||||
token: ${{ secrets.GITHUB_TOKEN }}
|
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
|
- name: Update version in build.gradle.kts
|
||||||
id: update_version
|
id: update_version
|
||||||
run: |
|
run: |
|
||||||
@@ -70,12 +54,12 @@ jobs:
|
|||||||
sed -i "s/val snapshot = .*/val snapshot = false/" build.gradle.kts
|
sed -i "s/val snapshot = .*/val snapshot = false/" build.gradle.kts
|
||||||
|
|
||||||
- name: Build without PE shaded
|
- name: Build without PE shaded
|
||||||
run: gradle build -PshadePE=false -x test
|
run: ./gradlew build -PshadePE=false -x test
|
||||||
env:
|
env:
|
||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||||
|
|
||||||
- name: Build with PE shaded Gradle
|
- name: Build with PE shaded Gradle
|
||||||
run: gradle build -PshadePE=true -x test
|
run: ./gradlew build -PshadePE=true -x test
|
||||||
env:
|
env:
|
||||||
GITHUB_REPOSITORY: ${{ github.repository }}
|
GITHUB_REPOSITORY: ${{ github.repository }}
|
||||||
|
|
||||||
@@ -214,8 +198,10 @@ jobs:
|
|||||||
fabric
|
fabric
|
||||||
|
|
||||||
game-versions: |
|
game-versions: |
|
||||||
1.21.4
|
1.21.11
|
||||||
1.21.5
|
|
||||||
|
dependencies: |
|
||||||
|
fabric-api
|
||||||
|
|
||||||
retry-attempts: 2
|
retry-attempts: 2
|
||||||
retry-delay: 10000
|
retry-delay: 10000
|
||||||
|
|||||||
+31
-12
@@ -2,8 +2,31 @@ import java.io.ByteArrayOutputStream
|
|||||||
|
|
||||||
plugins {
|
plugins {
|
||||||
id("java")
|
id("java")
|
||||||
id("com.gradleup.shadow") version "8.3.3" apply false
|
id("com.gradleup.shadow") version "9.2.2" apply false
|
||||||
id("fabric-loom") version "1.10.5" 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"
|
val fullVersion = "1.3.5"
|
||||||
@@ -23,14 +46,10 @@ allprojects {
|
|||||||
if (!snapshot) {
|
if (!snapshot) {
|
||||||
return ""
|
return ""
|
||||||
}
|
}
|
||||||
var commitHash = ""
|
val commitHash = if (includeHash) {
|
||||||
if (includeHash && file(".git").isDirectory) {
|
getGitCommitHash(project)?.let { "+$it" } ?: ""
|
||||||
val stdout = ByteArrayOutputStream()
|
} else {
|
||||||
exec {
|
""
|
||||||
commandLine("git", "rev-parse", "--short", "HEAD")
|
|
||||||
standardOutput = stdout
|
|
||||||
}
|
|
||||||
commitHash = "+${stdout.toString().trim()}"
|
|
||||||
}
|
}
|
||||||
return "$commitHash-SNAPSHOT"
|
return "$commitHash-SNAPSHOT"
|
||||||
}
|
}
|
||||||
@@ -41,7 +60,8 @@ allprojects {
|
|||||||
ext["githubRepo"] = githubRepo
|
ext["githubRepo"] = githubRepo
|
||||||
|
|
||||||
repositories {
|
repositories {
|
||||||
mavenLocal()
|
// mavenLocal()
|
||||||
|
maven("https://repo.grim.ac/snapshots")
|
||||||
mavenCentral()
|
mavenCentral()
|
||||||
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
maven("https://hub.spigotmc.org/nexus/content/repositories/snapshots/")
|
||||||
maven("https://repo.codemc.io/repository/maven-releases/")
|
maven("https://repo.codemc.io/repository/maven-releases/")
|
||||||
@@ -52,7 +72,6 @@ allprojects {
|
|||||||
}
|
}
|
||||||
maven("https://libraries.minecraft.net/")
|
maven("https://libraries.minecraft.net/")
|
||||||
maven("https://maven.neoforged.net/releases")
|
maven("https://maven.neoforged.net/releases")
|
||||||
maven("https://repo.codemc.io/repository/maven-snapshots/")
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -40,11 +40,11 @@ dependencies {
|
|||||||
|
|
||||||
shadeThisThing(implementation("org.kohsuke:github-api:1.326")!!)
|
shadeThisThing(implementation("org.kohsuke:github-api:1.326")!!)
|
||||||
if (shadePE) {
|
if (shadePE) {
|
||||||
shadeThisThing(implementation("com.github.retrooper:packetevents-spigot:2.8.0-SNAPSHOT")!!)
|
shadeThisThing(implementation("com.github.retrooper:packetevents-spigot:2.11.1+60a2c34-SNAPSHOT")!!)
|
||||||
} else {
|
} else {
|
||||||
compileOnly("com.github.retrooper:packetevents-spigot:2.8.0-SNAPSHOT")
|
compileOnly("com.github.retrooper:packetevents-spigot:2.11.1+60a2c34-SNAPSHOT")
|
||||||
}
|
}
|
||||||
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")!!)
|
shadeThisThing(implementation("org.incendo:cloud-core:2.0.0")!!)
|
||||||
|
|
||||||
// Required for 1.14.4 support because gson is too old to have JosnParser.parseString()
|
// Required for 1.14.4 support because gson is too old to have JosnParser.parseString()
|
||||||
@@ -60,7 +60,7 @@ tasks.withType<ShadowJar> {
|
|||||||
archiveClassifier.set("")
|
archiveClassifier.set("")
|
||||||
|
|
||||||
configurations = listOf(shadeThisThing)
|
configurations = listOf(shadeThisThing)
|
||||||
isEnableRelocation = true
|
enableAutoRelocation = true
|
||||||
relocationPrefix = "${project.property("maven_group")}.${project.property("archives_base_name")}.shaded"
|
relocationPrefix = "${project.property("maven_group")}.${project.property("archives_base_name")}.shaded"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -232,4 +232,19 @@ public class BukkitPlayer implements PlatformPlayer {
|
|||||||
public String getClientBrand() {
|
public String getClientBrand() {
|
||||||
return this.clientBrand;
|
return this.clientBrand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFlying() {
|
||||||
|
return bukkitPlayer.isFlying();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getSpeed() {
|
||||||
|
return bukkitPlayer.getWalkSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFlyingSpeed() {
|
||||||
|
return bukkitPlayer.getFlySpeed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -1,5 +1,6 @@
|
|||||||
package me.caseload.knockbacksync.stats.custom;
|
package me.caseload.knockbacksync.stats.custom;
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* This Metrics class was auto-generated and can be copied into your project if you are
|
* 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.
|
* not using a build tool like Gradle or Maven for dependency management.
|
||||||
|
|||||||
@@ -13,9 +13,9 @@ dependencies {
|
|||||||
|
|
||||||
// Shaded in or bundled by platform-specific code
|
// Shaded in or bundled by platform-specific code
|
||||||
if (shadePE) {
|
if (shadePE) {
|
||||||
implementation("com.github.retrooper:packetevents-api:2.8.0-SNAPSHOT")
|
implementation("com.github.retrooper:packetevents-api:2.11.1+60a2c34-SNAPSHOT")
|
||||||
} else {
|
} 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")
|
implementation("org.yaml:snakeyaml:2.0")
|
||||||
|
|||||||
+2
-2
@@ -52,10 +52,10 @@ public class ToggleOffGroundSubcommand implements BuilderCommand {
|
|||||||
|
|
||||||
private void loadConfigSettings() {
|
private void loadConfigSettings() {
|
||||||
ConfigWrapper configWrapper = Base.INSTANCE.getConfigManager().getConfigWrapper();
|
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",
|
this.offGroundSyncEnableMessage = configWrapper.getString("messages.offground.enable",
|
||||||
"&aSuccessfully enabled offground synchronization.");
|
"&aSuccessfully enabled offground synchronization.");
|
||||||
this.offGroundSyncDisableMessage = configWrapper.getString("messages.offground.disable",
|
this.offGroundSyncDisableMessage = configWrapper.getString("messages.offground.disable",
|
||||||
"&cSuccessfully disabled offground synchronization.");
|
"&cSuccessfully disabled offground synchronization.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
-3
@@ -11,9 +11,6 @@ import me.caseload.knockbacksync.player.PlatformPlayer;
|
|||||||
import me.caseload.knockbacksync.player.PlayerData;
|
import me.caseload.knockbacksync.player.PlayerData;
|
||||||
import me.caseload.knockbacksync.util.ChatUtil;
|
import me.caseload.knockbacksync.util.ChatUtil;
|
||||||
import org.jetbrains.annotations.NotNull;
|
import org.jetbrains.annotations.NotNull;
|
||||||
import org.jetbrains.annotations.Nullable;
|
|
||||||
|
|
||||||
import java.util.UUID;
|
|
||||||
|
|
||||||
public class PacketPlayerJoinQuit extends PacketListenerAbstract {
|
public class PacketPlayerJoinQuit extends PacketListenerAbstract {
|
||||||
@Override
|
@Override
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import me.caseload.knockbacksync.Base;
|
|||||||
import me.caseload.knockbacksync.Platform;
|
import me.caseload.knockbacksync.Platform;
|
||||||
import me.caseload.knockbacksync.config.YamlConfiguration;
|
import me.caseload.knockbacksync.config.YamlConfiguration;
|
||||||
import me.caseload.knockbacksync.runnable.PingRunnable;
|
import me.caseload.knockbacksync.runnable.PingRunnable;
|
||||||
|
import me.caseload.knockbacksync.runnable.TickRunnable;
|
||||||
import me.caseload.knockbacksync.scheduler.AbstractTaskHandle;
|
import me.caseload.knockbacksync.scheduler.AbstractTaskHandle;
|
||||||
|
|
||||||
import java.io.File;
|
import java.io.File;
|
||||||
@@ -39,6 +40,7 @@ public class ConfigManager {
|
|||||||
private String playerDisconnectedWhileExecutingCommand;
|
private String playerDisconnectedWhileExecutingCommand;
|
||||||
|
|
||||||
private AbstractTaskHandle pingTask;
|
private AbstractTaskHandle pingTask;
|
||||||
|
private AbstractTaskHandle tickTask;
|
||||||
|
|
||||||
private Map<String, Object> config;
|
private Map<String, Object> config;
|
||||||
private File configFile;
|
private File configFile;
|
||||||
@@ -114,6 +116,8 @@ public class ConfigManager {
|
|||||||
pingTask = Base.INSTANCE.getScheduler().runTaskTimerAsynchronously(new PingRunnable(), initialDelay, pingTaskRunnableInterval);
|
pingTask = Base.INSTANCE.getScheduler().runTaskTimerAsynchronously(new PingRunnable(), initialDelay, pingTaskRunnableInterval);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tickTask = Base.INSTANCE.getScheduler().runTaskTimer(new TickRunnable(), 0L, 1L);
|
||||||
|
|
||||||
notifyUpdate = configWrapper.getBoolean("notify_updates", true);
|
notifyUpdate = configWrapper.getBoolean("notify_updates", true);
|
||||||
autoUpdate = configWrapper.getBoolean("auto_update", true);
|
autoUpdate = configWrapper.getBoolean("auto_update", true);
|
||||||
combatTimer = configWrapper.getLong("runnable.timer", 30L);
|
combatTimer = configWrapper.getLong("runnable.timer", 30L);
|
||||||
|
|||||||
@@ -63,4 +63,10 @@ public interface PlatformPlayer {
|
|||||||
|
|
||||||
String getClientBrand();
|
String getClientBrand();
|
||||||
// Add more methods as needed
|
// Add more methods as needed
|
||||||
|
|
||||||
|
boolean isFlying();
|
||||||
|
|
||||||
|
float getSpeed();
|
||||||
|
|
||||||
|
float getFlyingSpeed();
|
||||||
}
|
}
|
||||||
@@ -88,11 +88,14 @@ public class PlayerData {
|
|||||||
@Setter private double knockbackResistanceAttribute = 0.0;
|
@Setter private double knockbackResistanceAttribute = 0.0;
|
||||||
public PingStrategy pingStrategy; // this is currently shared between all instances, but can be made per-player later
|
public PingStrategy pingStrategy; // this is currently shared between all instances, but can be made per-player later
|
||||||
|
|
||||||
|
@Getter private final SimulatedPlayer simulatedPlayer;
|
||||||
|
|
||||||
public PlayerData(User user, PlatformPlayer platformPlayer) {
|
public PlayerData(User user, PlatformPlayer platformPlayer) {
|
||||||
this.uuid = platformPlayer.getUUID();
|
this.uuid = platformPlayer.getUUID();
|
||||||
this.user = user;
|
this.user = user;
|
||||||
this.platformPlayer = platformPlayer;
|
this.platformPlayer = platformPlayer;
|
||||||
this.pingStrategy = loadPingStrategy(Base.INSTANCE.getConfigManager());
|
this.pingStrategy = loadPingStrategy(Base.INSTANCE.getConfigManager());
|
||||||
|
this.simulatedPlayer = new SimulatedPlayer(this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public double getNotNullPing() {
|
public double getNotNullPing() {
|
||||||
|
|||||||
@@ -0,0 +1,62 @@
|
|||||||
|
package me.caseload.knockbacksync.player;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.protocol.potion.PotionEffect;
|
||||||
|
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
|
||||||
|
import com.github.retrooper.packetevents.util.Vector3d;
|
||||||
|
import com.github.retrooper.packetevents.util.Vector3i;
|
||||||
|
import lombok.Getter;
|
||||||
|
import me.caseload.knockbacksync.Base;
|
||||||
|
import me.caseload.knockbacksync.util.data.Vec2d;
|
||||||
|
|
||||||
|
import java.util.function.Consumer;
|
||||||
|
|
||||||
|
public final class SimulatedPlayer {
|
||||||
|
|
||||||
|
private final PlayerData playerData;
|
||||||
|
private final PlatformPlayer platformPlayer;
|
||||||
|
private Vec2d position;
|
||||||
|
@Getter private double yCoordinate;
|
||||||
|
@Getter private double verticalVelocity;
|
||||||
|
@Getter private BoundingBox boundingBox;
|
||||||
|
@Getter private boolean isOnGround;
|
||||||
|
|
||||||
|
public SimulatedPlayer(PlayerData playerData) {
|
||||||
|
this.playerData = playerData;
|
||||||
|
this.platformPlayer = playerData.getPlatformPlayer();
|
||||||
|
this.position = new Vec2d(platformPlayer.getX(), platformPlayer.getZ());
|
||||||
|
this.yCoordinate = platformPlayer.getY();
|
||||||
|
this.verticalVelocity = platformPlayer.getVelocity().y;
|
||||||
|
this.boundingBox = platformPlayer.getBoundingBox();
|
||||||
|
this.isOnGround = platformPlayer.isOnGround(); // not safe but its only for a single tick
|
||||||
|
}
|
||||||
|
|
||||||
|
public void tick() {
|
||||||
|
Vector3d location = playerData.getPlatformPlayer().getLocation();
|
||||||
|
Vec2d newPosition = new Vec2d(location.x, location.z);
|
||||||
|
|
||||||
|
if (!position.equals(newPosition)) {
|
||||||
|
double dx = newPosition.x - position.x;
|
||||||
|
double dz = newPosition.z - position.z;
|
||||||
|
boundingBox.shift(dx, 0, dz);
|
||||||
|
position = newPosition;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (platformPlayer.isFlying() || platformPlayer.isGliding()) {
|
||||||
|
double newY = platformPlayer.getY();
|
||||||
|
double shiftY = newY - yCoordinate;
|
||||||
|
boundingBox.shift(0, shiftY, 0);
|
||||||
|
yCoordinate = newY;
|
||||||
|
verticalVelocity = platformPlayer.getVelocity().getY();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
verticalVelocity += playerData.getGravityAttribute();
|
||||||
|
verticalVelocity = Math.min(verticalVelocity, 3.92);
|
||||||
|
verticalVelocity *= 0.98;
|
||||||
|
|
||||||
|
double newY = yCoordinate -= verticalVelocity;
|
||||||
|
double shiftY = newY - yCoordinate;
|
||||||
|
boundingBox.shift(0, shiftY, 0);
|
||||||
|
yCoordinate = newY;
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,33 @@
|
|||||||
|
package me.caseload.knockbacksync.runnable;
|
||||||
|
|
||||||
|
import com.github.retrooper.packetevents.protocol.player.User;
|
||||||
|
import me.caseload.knockbacksync.Base;
|
||||||
|
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||||
|
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||||
|
import me.caseload.knockbacksync.player.PlayerData;
|
||||||
|
import me.caseload.knockbacksync.player.SimulatedPlayer;
|
||||||
|
|
||||||
|
public class TickRunnable implements Runnable {
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public void run() {
|
||||||
|
if (!Base.INSTANCE.getConfigManager().isToggled())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (PlatformPlayer player : Base.INSTANCE.getPlatformServer().getOnlinePlayers()) {
|
||||||
|
User user = player.getUser();
|
||||||
|
if (user == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
PlayerData playerData = PlayerDataManager.getPlayerData(user);
|
||||||
|
if (playerData == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
SimulatedPlayer simulatedPlayer = playerData.getSimulatedPlayer();
|
||||||
|
if (simulatedPlayer == null)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
simulatedPlayer.tick();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -0,0 +1,36 @@
|
|||||||
|
package me.caseload.knockbacksync.util.data;
|
||||||
|
|
||||||
|
import java.util.Objects;
|
||||||
|
|
||||||
|
public final class Vec2d {
|
||||||
|
|
||||||
|
public final double x;
|
||||||
|
public final double z;
|
||||||
|
|
||||||
|
public Vec2d(double x, double z) {
|
||||||
|
this.x = x;
|
||||||
|
this.z = z;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean equals(Object object) {
|
||||||
|
if (this == object)
|
||||||
|
return true;
|
||||||
|
|
||||||
|
if (!(object instanceof Vec2d))
|
||||||
|
return false;
|
||||||
|
|
||||||
|
Vec2d v = (Vec2d) object;
|
||||||
|
return Double.compare(v.x, x) == 0 && Double.compare(v.z, z) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public int hashCode() {
|
||||||
|
return Objects.hash(x, z);
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public String toString() {
|
||||||
|
return "Vec2d(" + x + ", " + z + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1,6 +1,5 @@
|
|||||||
plugins {
|
plugins {
|
||||||
id("fabric-loom")
|
id("fabric-loom")
|
||||||
id("com.gradleup.shadow")
|
|
||||||
}
|
}
|
||||||
|
|
||||||
loom {
|
loom {
|
||||||
@@ -38,9 +37,9 @@ dependencies {
|
|||||||
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "${rootProject.property("fabric_version")}"))
|
modImplementation(fabricApi.module("fabric-lifecycle-events-v1", "${rootProject.property("fabric_version")}"))
|
||||||
modImplementation(fabricApi.module("fabric-events-interaction-v0", "${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("me.lucko:fabric-permissions-api:0.6.1")!!)
|
||||||
include(modImplementation("com.github.retrooper:packetevents-fabric:2.8.0-SNAPSHOT")!!)
|
include(modImplementation("com.github.retrooper:packetevents-fabric:2.11.1+60a2c34-SNAPSHOT")!!)
|
||||||
include(modImplementation("org.incendo:cloud-fabric:2.0.0-beta.10")!!)
|
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.incendo:cloud-minecraft-extras:2.0.0-beta.10")!!)
|
||||||
include(implementation("org.yaml:snakeyaml:2.0")!!)
|
include(implementation("org.yaml:snakeyaml:2.0")!!)
|
||||||
@@ -70,8 +69,8 @@ tasks.processResources {
|
|||||||
filesMatching("fabric.mod.json") {
|
filesMatching("fabric.mod.json") {
|
||||||
expand(
|
expand(
|
||||||
"version" to project.version,
|
"version" to project.version,
|
||||||
"minecraft_version" to rootProject.property("minecraft_version"),
|
"minecraft_version" to rootProject.property("minecraft_version")!!,
|
||||||
"loader_version" to rootProject.property("loader_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)
|
@Mixin(PlayerEntity.class)
|
||||||
public class PlayerMixin {
|
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) {
|
if (result == ActionResult.FAIL) {
|
||||||
target.velocityModified = false;
|
// --- REPLICATING PAPER: CANCELLED ---
|
||||||
ci.cancel(); // Prevent sending the velocity packet
|
// In Paper: if (event.isCancelled()) { cancelled = true; }
|
||||||
} else if (result == ActionResult.SUCCESS) {
|
// In Paper: if (!cancelled) { sendPacket; cleanup; }
|
||||||
// Currently unnecessary since we do this in the handler, will move later
|
|
||||||
target.setVelocity(velocity);
|
// So, if cancelled, we stop EVERYTHING. We do not send packet, we do not reset velocity.
|
||||||
serverPlayer.networkHandler.sendPacket(new EntityVelocityUpdateS2CPacket(target));
|
ci.cancel();
|
||||||
target.velocityModified = false;
|
return;
|
||||||
ci.cancel(); // Prevent sending the original velocity packet
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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
|
@Override
|
||||||
public PlatformWorld getWorld() {
|
public PlatformWorld getWorld() {
|
||||||
return new FabricWorld(fabricPlayer.getWorld());
|
return new FabricWorld(fabricPlayer.getEntityWorld());
|
||||||
}
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
@@ -117,7 +117,7 @@ public class FabricPlayer implements PlatformPlayer {
|
|||||||
|
|
||||||
@Override
|
@Override
|
||||||
public int getMainHandKnockbackLevel() {
|
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());
|
return EnchantmentHelper.getLevel(knockbackEntry, fabricPlayer.getMainHandStack());
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -131,7 +131,7 @@ public class FabricPlayer implements PlatformPlayer {
|
|||||||
fabricPlayer.setVelocity(adjustedVelocity.x, adjustedVelocity.y, adjustedVelocity.z);
|
fabricPlayer.setVelocity(adjustedVelocity.x, adjustedVelocity.y, adjustedVelocity.z);
|
||||||
// TODO
|
// TODO
|
||||||
// fix paper-ism? for some reason setVelocity() in paper marks the entity as hurt marked every time its called?
|
// 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
|
@Override
|
||||||
@@ -171,4 +171,19 @@ public class FabricPlayer implements PlatformPlayer {
|
|||||||
public String getClientBrand() {
|
public String getClientBrand() {
|
||||||
return this.clientBrand;
|
return this.clientBrand;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean isFlying() {
|
||||||
|
return this.fabricPlayer.getAbilities().flying;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getSpeed() {
|
||||||
|
return this.fabricPlayer.getAbilities().getWalkSpeed();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public float getFlyingSpeed() {
|
||||||
|
return this.fabricPlayer.getAbilities().getFlySpeed();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -29,7 +29,7 @@ public class CustomUpdateIntervals {
|
|||||||
for (Entity entity : level.iterateEntities()) {
|
for (Entity entity : level.iterateEntities()) {
|
||||||
String entityType = entity.getType().getRegistryEntry().getIdAsString();
|
String entityType = entity.getType().getRegistryEntry().getIdAsString();
|
||||||
if (entityIntervals.containsKey(entityType)) {
|
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) {
|
if (serverEntity != null) {
|
||||||
((UpdateIntervalAccessor) serverEntity).setUpdateInterval(entityIntervals.get(entityType));
|
((UpdateIntervalAccessor) serverEntity).setUpdateInterval(entityIntervals.get(entityType));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -22,7 +22,8 @@
|
|||||||
],
|
],
|
||||||
"depends": {
|
"depends": {
|
||||||
"fabricloader": ">=0.15.11",
|
"fabricloader": ">=0.15.11",
|
||||||
"fabric": "*",
|
"fabric-lifecycle-events-v1": "*",
|
||||||
|
"fabric-events-interaction-v0": "*",
|
||||||
"minecraft": "~${minecraft_version}",
|
"minecraft": "~${minecraft_version}",
|
||||||
"packetevents": "*"
|
"packetevents": "*"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -5,8 +5,8 @@
|
|||||||
"compatibilityLevel": "JAVA_21",
|
"compatibilityLevel": "JAVA_21",
|
||||||
"mixins": [
|
"mixins": [
|
||||||
"ChunkMapMixin",
|
"ChunkMapMixin",
|
||||||
|
"EntityTrackerEntryMixin",
|
||||||
"PlayerMixin",
|
"PlayerMixin",
|
||||||
"ServerEntityMixin",
|
|
||||||
"TickRateManagerMixin"
|
"TickRateManagerMixin"
|
||||||
],
|
],
|
||||||
"injectors": {
|
"injectors": {
|
||||||
|
|||||||
+3
-3
@@ -4,8 +4,8 @@ org.gradle.parallel=true
|
|||||||
|
|
||||||
# Fabric Properties
|
# Fabric Properties
|
||||||
# check these on https://modmuss50.me/fabric.html
|
# check these on https://modmuss50.me/fabric.html
|
||||||
minecraft_version=1.21.5
|
minecraft_version=1.21.11
|
||||||
yarn_mappings=1.21.5+build.1:v2
|
yarn_mappings=1.21.11+build.3:v2
|
||||||
loader_version=0.16.13
|
loader_version=0.16.13
|
||||||
|
|
||||||
# Mod Properties
|
# Mod Properties
|
||||||
@@ -14,6 +14,6 @@ archives_base_name=knockbacksync
|
|||||||
|
|
||||||
# Dependencies
|
# Dependencies
|
||||||
# check this on https://modmuss50.me/fabric.html
|
# 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
|
githubRepo=CASELOAD7000/knockback-sync
|
||||||
+1
-1
@@ -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.13-bin.zip
|
distributionUrl=https\://services.gradle.org/distributions/gradle-9.2.0-bin.zip
|
||||||
networkTimeout=10000
|
networkTimeout=10000
|
||||||
validateDistributionUrl=true
|
validateDistributionUrl=true
|
||||||
zipStoreBase=GRADLE_USER_HOME
|
zipStoreBase=GRADLE_USER_HOME
|
||||||
|
|||||||
Reference in new issue
Block a user