mirror of
https://github.com/CASELOAD7000/knockback-sync.git
synced 2026-11-07 10:02:43 -05:00
Compare commits
11
Commits
b45
...
old-kb-algo
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
fe395f2cbd | ||
|
|
581bef78fe | ||
|
|
35e19c56b1 | ||
|
|
50bde1375a | ||
|
|
6ce4469db9 | ||
|
|
d63e4a0c29 | ||
|
|
e5b70523bc | ||
|
|
cf0e5decd7 | ||
|
|
cbe1c3c46e | ||
|
|
1db1e02c8b | ||
|
|
7a9fee6e2d |
No files matched your search
@@ -204,7 +204,7 @@ jobs:
|
||||
purpur
|
||||
|
||||
game-versions: |
|
||||
>=1.14.4
|
||||
>=1.12.2
|
||||
|
||||
retry-attempts: 2
|
||||
retry-delay: 10000
|
||||
@@ -222,7 +222,7 @@ jobs:
|
||||
|
||||
name: KnockbackSync-${{ env.NEW_VERSION }}
|
||||
version: ${{ env.NEW_VERSION }}
|
||||
version-type: beta
|
||||
version-type: alpha
|
||||
|
||||
loaders: |
|
||||
fabric
|
||||
|
||||
@@ -9,7 +9,6 @@ target/
|
||||
|
||||
|
||||
.gradle/
|
||||
gradle/
|
||||
build/
|
||||
|
||||
run/
|
||||
@@ -29,7 +29,7 @@ tasks.named<JavaCompile>("compileTestJava") {
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
|
||||
compileOnly("org.spigotmc:spigot-api:1.14.4-R0.1-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
||||
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
|
||||
|
||||
compileOnly("org.projectlombok:lombok:1.18.34")
|
||||
|
||||
@@ -16,6 +16,7 @@ import me.caseload.knockbacksync.sender.Sender;
|
||||
import me.caseload.knockbacksync.stats.custom.BukkitStatsManager;
|
||||
import me.caseload.knockbacksync.stats.custom.PluginJarHashProvider;
|
||||
import me.caseload.knockbacksync.world.BukkitServer;
|
||||
import org.bukkit.event.EventHandler;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
@@ -1,18 +1,20 @@
|
||||
package me.caseload.knockbacksync.player;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
|
||||
import com.github.retrooper.packetevents.protocol.world.Location;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import me.caseload.knockbacksync.world.PlatformWorld;
|
||||
import me.caseload.knockbacksync.world.SpigotWorld;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.Location;
|
||||
import org.bukkit.enchantments.Enchantment;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
@@ -23,21 +25,44 @@ public class BukkitPlayer implements PlatformPlayer {
|
||||
private static Class<?> craftPlayerClass;
|
||||
private static Method getHandleMethod;
|
||||
private static Method getAttackStrengthScaleMethod;
|
||||
private static ServerVersion currentVersion = PacketEvents.getAPI().getServerManager().getVersion();
|
||||
|
||||
// 1.12.2 support
|
||||
static {
|
||||
try {
|
||||
String bukkitversion = Bukkit.getServer().getClass().getPackage()
|
||||
.getName();
|
||||
// Step 1: Load the CraftPlayer class
|
||||
craftPlayerClass = Class.forName(bukkitversion + ".entity.CraftPlayer");
|
||||
// Step 2: Get the getHandle method
|
||||
getHandleMethod = craftPlayerClass.getMethod("getHandle");
|
||||
// Step 3: Get the getAttackStrengthScale method from the EntityPlayer class
|
||||
Class<?> entityPlayerClass = Class.forName("net.minecraft.server." + bukkitversion + ".EntityPlayer");
|
||||
getAttackStrengthScaleMethod = entityPlayerClass.getDeclaredMethod("getAttackStrengthScale", float.class);
|
||||
getAttackStrengthScaleMethod.setAccessible(true);
|
||||
// Check the current server versio
|
||||
|
||||
// If the version is greater than 1.14.4, use the Player method directly
|
||||
if (currentVersion.isOlderThan(ServerVersion.V_1_15)) {
|
||||
Object server = Bukkit.getServer().getClass().getDeclaredMethod("getServer").invoke(Bukkit.getServer());
|
||||
String nmsPackage = server.getClass().getPackage().getName();
|
||||
String bukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
|
||||
|
||||
// Step 1: Load the CraftPlayer class
|
||||
craftPlayerClass = Class.forName(bukkitPackage + ".entity.CraftPlayer");
|
||||
// Step 2: Get the getHandle method
|
||||
getHandleMethod = craftPlayerClass.getMethod("getHandle");
|
||||
// Step 3: Get the getAttackStrengthScale method from the EntityPlayer class
|
||||
Class<?> entityPlayerClass = Class.forName(nmsPackage + ".EntityPlayer");
|
||||
String getAttackStrengthScaleMethodName = "";
|
||||
|
||||
// Determine the method name based on the version
|
||||
if (currentVersion.isOlderThan(ServerVersion.V_1_13)) {
|
||||
getAttackStrengthScaleMethodName = "n";
|
||||
} else if (currentVersion.isOlderThan(ServerVersion.V_1_14)) {
|
||||
getAttackStrengthScaleMethodName = "r";
|
||||
} else if (currentVersion.isOlderThan(ServerVersion.V_1_15)) {
|
||||
getAttackStrengthScaleMethodName = "s";
|
||||
}
|
||||
|
||||
// Get the attack strength scale method for EntityPlayer
|
||||
getAttackStrengthScaleMethod = entityPlayerClass.getMethod(getAttackStrengthScaleMethodName, float.class);
|
||||
getAttackStrengthScaleMethod.setAccessible(true);
|
||||
}
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
throw new IllegalStateException("Method of Class required to support this version not found via reflection" + e);
|
||||
} catch (InvocationTargetException | IllegalAccessException e) {
|
||||
throw new RuntimeException("Cannot access required methods via reflection to support this version" + e);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -93,7 +118,11 @@ public class BukkitPlayer implements PlatformPlayer {
|
||||
|
||||
@Override
|
||||
public int getPing() {
|
||||
return PacketEvents.getAPI().getPlayerManager().getPing(bukkitPlayer);
|
||||
if (currentVersion.isNewerThanOrEquals(ServerVersion.V_1_16_5)) {
|
||||
return bukkitPlayer.getPing();
|
||||
} else {
|
||||
return PacketEvents.getAPI().getPlayerManager().getPing(bukkitPlayer);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -107,9 +136,9 @@ public class BukkitPlayer implements PlatformPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3d getLocation() {
|
||||
Location location = bukkitPlayer.getLocation();
|
||||
return new Vector3d(location.getX(), location.getY(), location.getZ());
|
||||
public Location getLocation() {
|
||||
org.bukkit.Location location = bukkitPlayer.getLocation();
|
||||
return new Location(location.getX(), location.getY(), location.getZ(), location.getYaw(), location.getPitch());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -119,16 +148,19 @@ public class BukkitPlayer implements PlatformPlayer {
|
||||
|
||||
@Override
|
||||
public double getAttackCooldown() {
|
||||
try {
|
||||
// Step 1: Get the CraftPlayer instance
|
||||
Object craftPlayer = craftPlayerClass.cast(bukkitPlayer);
|
||||
// Step 2: Get the handle (NMS EntityPlayer)
|
||||
Object entityPlayer = getHandleMethod.invoke(craftPlayer);
|
||||
// Step 3: Invoke the getAttackStrengthScale method
|
||||
return (float) getAttackStrengthScaleMethod.invoke(entityPlayer, 0.5f);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return -1; // Return -1 if an error occurs
|
||||
if (currentVersion.isNewerThan(ServerVersion.V_1_14_4)) {
|
||||
return bukkitPlayer.getAttackCooldown();
|
||||
} else {
|
||||
try {
|
||||
// Step 1: Get the CraftPlayer instance
|
||||
// Object craftPlayer = craftPlayerClass.cast(bukkitPlayer);
|
||||
// Step 2: Get the handle (NMS EntityPlayer)
|
||||
Object entityPlayer = getHandleMethod.invoke(bukkitPlayer);
|
||||
// Step 3: Invoke the getAttackStrengthScale method
|
||||
return (float) getAttackStrengthScaleMethod.invoke(entityPlayer, 0.5f);
|
||||
} catch (Exception e) {
|
||||
throw new IllegalStateException("This plugin will not work. NMS mapping for getAttackCooldown() failed!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -151,4 +183,10 @@ public class BukkitPlayer implements PlatformPlayer {
|
||||
public void setVelocity(Vector3d adjustedVelocity) {
|
||||
bukkitPlayer.setVelocity(new Vector(adjustedVelocity.x, adjustedVelocity.y, adjustedVelocity.z));
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox getBoundingBox() {
|
||||
org.bukkit.util.BoundingBox boundingBox = bukkitPlayer.getBoundingBox();
|
||||
return new BoundingBox(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
|
||||
}
|
||||
}
|
||||
@@ -1,19 +1,58 @@
|
||||
package me.caseload.knockbacksync.world;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import me.caseload.knockbacksync.world.raytrace.FluidHandling;
|
||||
import me.caseload.knockbacksync.world.raytrace.RayTraceResult;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.FluidCollisionMode;
|
||||
import org.bukkit.World;
|
||||
import org.bukkit.block.Block;
|
||||
import org.bukkit.util.Vector;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
|
||||
public class SpigotWorld implements PlatformWorld {
|
||||
private final World world;
|
||||
|
||||
// Reflection variables
|
||||
private static Class<?> craftWorldClass;
|
||||
private static Class<?> vec3DClass;
|
||||
private static Class<?> movingObjectPositionClass;
|
||||
private static Class<?> enumDirectionClass;
|
||||
private static Method craftWorldGetHandleMethod;
|
||||
private static Method rayTraceMethod;
|
||||
private static Method vec3DAddMethod;
|
||||
|
||||
static {
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThan(ServerVersion.V_1_13)) {
|
||||
try {
|
||||
Object server = Bukkit.getServer().getClass().getDeclaredMethod("getServer").invoke(Bukkit.getServer());
|
||||
String nmsPackage = server.getClass().getPackage().getName();
|
||||
String bukkitPackage = Bukkit.getServer().getClass().getPackage().getName();
|
||||
|
||||
// Load necessary classes dynamically for Minecraft 1.12.2
|
||||
craftWorldClass = Class.forName(bukkitPackage + ".CraftWorld");
|
||||
vec3DClass = Class.forName(nmsPackage + ".Vec3D");
|
||||
movingObjectPositionClass = Class.forName(nmsPackage + ".MovingObjectPosition");
|
||||
enumDirectionClass = Class.forName(nmsPackage + ".EnumDirection");
|
||||
|
||||
// CraftWorld
|
||||
|
||||
// Get method
|
||||
craftWorldGetHandleMethod = craftWorldClass.getMethod("getHandle");
|
||||
rayTraceMethod = Class.forName(nmsPackage + ".World").getMethod("rayTrace", vec3DClass, vec3DClass, boolean.class, boolean.class, boolean.class);
|
||||
vec3DAddMethod = vec3DClass.getMethod("add", double.class, double.class, double.class);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public SpigotWorld(World world) {
|
||||
this.world = world;
|
||||
}
|
||||
@@ -50,22 +89,80 @@ public class SpigotWorld implements PlatformWorld {
|
||||
|
||||
@Override
|
||||
public RayTraceResult rayTraceBlocks(Vector3d start, Vector3d direction, double maxDistance, FluidHandling fluidHandling, boolean ignorePassableBlocks) {
|
||||
Vector startVec = new Vector(start.getX(), start.getY(), start.getZ());
|
||||
Vector directionVec = new Vector(direction.getX(), direction.getY(), direction.getZ());
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_12_2)) {
|
||||
Vector startVec = new Vector(start.getX(), start.getY(), start.getZ());
|
||||
Vector directionVec = new Vector(direction.getX(), direction.getY(), direction.getZ());
|
||||
|
||||
FluidCollisionMode fluidMode = (fluidHandling == FluidHandling.NONE) ? FluidCollisionMode.NEVER :
|
||||
(fluidHandling == FluidHandling.SOURCE_ONLY) ? FluidCollisionMode.SOURCE_ONLY :
|
||||
FluidCollisionMode.ALWAYS;
|
||||
FluidCollisionMode fluidMode = (fluidHandling == FluidHandling.NONE) ? FluidCollisionMode.NEVER :
|
||||
(fluidHandling == FluidHandling.SOURCE_ONLY) ? FluidCollisionMode.SOURCE_ONLY :
|
||||
FluidCollisionMode.ALWAYS;
|
||||
|
||||
org.bukkit.util.RayTraceResult result = world.rayTraceBlocks(startVec.toLocation(world), directionVec, maxDistance, fluidMode, ignorePassableBlocks);
|
||||
org.bukkit.util.RayTraceResult result = world.rayTraceBlocks(startVec.toLocation(world), directionVec, maxDistance, fluidMode, ignorePassableBlocks);
|
||||
|
||||
if (result == null) return null;
|
||||
if (result == null) return null;
|
||||
|
||||
return new RayTraceResult(
|
||||
new Vector3d(result.getHitPosition().getX(), result.getHitPosition().getY(), result.getHitPosition().getZ()),
|
||||
getBlockFaceFrom(result.getHitBlockFace()),
|
||||
new Vector3i(result.getHitBlock().getX(), result.getHitBlock().getY(), result.getHitBlock().getZ()),
|
||||
result.getHitBlock() != null ? WrappedBlockState.getByString(result.getHitBlock().getType().name()) : null
|
||||
);
|
||||
return new RayTraceResult(
|
||||
new Vector3d(result.getHitPosition().getX(), result.getHitPosition().getY(), result.getHitPosition().getZ()),
|
||||
getBlockFaceFrom(result.getHitBlockFace()),
|
||||
new Vector3i(result.getHitBlock().getX(), result.getHitBlock().getY(), result.getHitBlock().getZ()),
|
||||
result.getHitBlock() != null ? WrappedBlockState.getByString(result.getHitBlock().getType().name()) : null
|
||||
);
|
||||
// Only tested on 1.12.2
|
||||
} else {
|
||||
try {
|
||||
// Create start and end positions
|
||||
Object startPos = vec3DClass.getConstructor(double.class, double.class, double.class)
|
||||
.newInstance(start.getX(), start.getY(), start.getZ());
|
||||
Object endPos = vec3DAddMethod.invoke(startPos, direction.getX(), direction.getY(), direction.getZ());
|
||||
|
||||
// Call rayTrace method
|
||||
Object hitResult = rayTraceMethod.invoke(craftWorldGetHandleMethod.invoke(world), startPos, endPos, false, true, false);
|
||||
if (hitResult == null) return null;
|
||||
|
||||
// Extract hit position and direction
|
||||
Vector3d hitPosition = new Vector3d(
|
||||
(double) hitResult.getClass().getField("pos").get(hitResult),
|
||||
(double) hitResult.getClass().getField("pos").get(hitResult).getClass().getField("y").get(hitResult.getClass().getField("pos").get(hitResult)),
|
||||
(double) hitResult.getClass().getField("pos").get(hitResult).getClass().getField("z").get(hitResult.getClass().getField("pos").get(hitResult))
|
||||
);
|
||||
|
||||
Object hitDirection = hitResult.getClass().getField("direction").get(hitResult);
|
||||
Object hitBlock = hitResult.getClass().getField("e").get(hitResult); // e = BlockHitResult
|
||||
|
||||
return new RayTraceResult(
|
||||
hitPosition,
|
||||
getHitBlockFace(hitDirection),
|
||||
new Vector3i((int) hitBlock.getClass().getField("x").get(hitBlock),
|
||||
(int) hitBlock.getClass().getField("y").get(hitBlock),
|
||||
(int) hitBlock.getClass().getField("z").get(hitBlock)),
|
||||
hitBlock != null ? WrappedBlockState.getByString(hitBlock.getClass().getField("type").get(hitBlock).toString()) : null
|
||||
);
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
return null; // Return null if there was an error during ray tracing
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static BlockFace getHitBlockFace(Object enumDirection) {
|
||||
try {
|
||||
// Match the EnumDirection to the corresponding BlockFace
|
||||
if (enumDirection.equals(SpigotWorld.enumDirectionClass.getField("NORTH").get(null))) {
|
||||
return BlockFace.NORTH;
|
||||
} else if (enumDirection.equals(SpigotWorld.enumDirectionClass.getField("SOUTH").get(null))) {
|
||||
return BlockFace.SOUTH;
|
||||
} else if (enumDirection.equals(SpigotWorld.enumDirectionClass.getField("EAST").get(null))) {
|
||||
return BlockFace.EAST;
|
||||
} else if (enumDirection.equals(SpigotWorld.enumDirectionClass.getField("WEST").get(null))) {
|
||||
return BlockFace.WEST;
|
||||
} else if (enumDirection.equals(SpigotWorld.enumDirectionClass.getField("UP").get(null))) {
|
||||
return BlockFace.UP;
|
||||
} else if (enumDirection.equals(SpigotWorld.enumDirectionClass.getField("DOWN").get(null))) {
|
||||
return BlockFace.DOWN;
|
||||
}
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
throw new IllegalStateException("Unexpected value: " + enumDirection);
|
||||
}
|
||||
}
|
||||
@@ -1,8 +1,8 @@
|
||||
name: KnockbackSync
|
||||
version: ${version}
|
||||
main: me.caseload.knockbacksync.KBSyncBukkitLoaderPlugin
|
||||
api-version: '1.14'
|
||||
authors: [ Caseload ]
|
||||
api-version: '1.13' # We actually support 1.12.2, api-version was added later though
|
||||
authors: [ Caseload, Axionize ]
|
||||
description: Synchronizes player knockback for smoother gameplay.
|
||||
folia-supported: true
|
||||
permissions:
|
||||
|
||||
@@ -9,6 +9,9 @@ import me.caseload.knockbacksync.command.subcommand.PingCommand;
|
||||
import me.caseload.knockbacksync.command.subcommand.ReloadCommand;
|
||||
import me.caseload.knockbacksync.command.subcommand.StatusCommand;
|
||||
import me.caseload.knockbacksync.command.subcommand.ToggleCommand;
|
||||
import me.caseload.knockbacksync.event.Event;
|
||||
import me.caseload.knockbacksync.event.EventBus;
|
||||
import me.caseload.knockbacksync.event.OptimizedEventBus;
|
||||
import me.caseload.knockbacksync.listener.packetevents.AttributeChangeListener;
|
||||
import me.caseload.knockbacksync.listener.packetevents.PingReceiveListener;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
@@ -39,6 +42,7 @@ public abstract class KnockbackSyncBase {
|
||||
@Getter protected SchedulerAdapter scheduler;
|
||||
@Getter protected ConfigManager configManager;
|
||||
protected CommandManager<Sender> commandManager;
|
||||
private final EventBus simpleEventBus = new OptimizedEventBus();
|
||||
|
||||
@Getter
|
||||
protected AbstractPlayerSelectorParser<Sender> playerSelectorParser;
|
||||
@@ -102,6 +106,7 @@ public abstract class KnockbackSyncBase {
|
||||
new AttributeChangeListener(),
|
||||
new PingReceiveListener()
|
||||
);
|
||||
Event.setEventBus(simpleEventBus);
|
||||
}
|
||||
|
||||
protected abstract void registerPlatformListeners();
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import me.caseload.knockbacksync.ConfigWrapper;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import me.caseload.knockbacksync.event.ConfigReloadEvent;
|
||||
import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
import me.caseload.knockbacksync.sender.Sender;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
@@ -39,4 +42,6 @@ public class PingCommand implements BuilderCommand {
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+29
-17
@@ -2,6 +2,8 @@ package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.event.ConfigReloadEvent;
|
||||
import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.sender.Sender;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
@@ -11,27 +13,37 @@ import org.incendo.cloud.permission.PredicatePermission;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ReloadCommand implements BuilderCommand {
|
||||
|
||||
private final ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
private String rawReloadMessage = configManager.getConfigWrapper().getString("reload_message", "&aSuccessfully reloaded KnockbackSync.");
|
||||
|
||||
public void register(CommandManager<Sender> manager) {
|
||||
manager.command(
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
.literal("reload")
|
||||
.permission((sender -> {
|
||||
final String permission = "knockbacksync.reload";
|
||||
Predicate<Sender> senderPredicate = (s) -> {
|
||||
return s.hasPermission(permission, false);
|
||||
};
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
.literal("reload")
|
||||
.permission((sender -> {
|
||||
final String permission = "knockbacksync.reload";
|
||||
Predicate<Sender> senderPredicate = (s) -> {
|
||||
return s.hasPermission(permission, false);
|
||||
};
|
||||
|
||||
return PredicatePermission.of(senderPredicate).testPermission(sender);
|
||||
}))
|
||||
.handler(context -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
configManager.loadConfig(true);
|
||||
return PredicatePermission.of(senderPredicate).testPermission(sender);
|
||||
}))
|
||||
.handler(context -> {
|
||||
configManager.loadConfig(true);
|
||||
|
||||
String rawReloadMessage = configManager.getReloadMessage();
|
||||
String reloadMessage = ChatUtil.translateAlternateColorCodes('&', rawReloadMessage);
|
||||
// Fire the ConfigReloadEvent
|
||||
new ConfigReloadEvent(configManager).post();
|
||||
|
||||
context.sender().sendMessage(reloadMessage);
|
||||
})
|
||||
String reloadMessage = ChatUtil.translateAlternateColorCodes('&', rawReloadMessage);
|
||||
|
||||
context.sender().sendMessage(reloadMessage);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
@KBSyncEventHandler
|
||||
public void onConfigReload(ConfigReloadEvent event) {
|
||||
rawReloadMessage = event.getConfigManager().getConfigWrapper().getString("reload_message", "&aSuccessfully reloaded KnockbackSync.");
|
||||
}
|
||||
}
|
||||
+45
-27
@@ -1,8 +1,11 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import me.caseload.knockbacksync.ConfigWrapper;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import me.caseload.knockbacksync.event.ConfigReloadEvent;
|
||||
import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
@@ -20,6 +23,14 @@ public class StatusCommand implements BuilderCommand {
|
||||
private static final String STATUS_SELF_PERMISSION = "knockbacksync.status.self";
|
||||
private static final String STATUS_OTHER_PERMISSION = "knockbacksync.status.other";
|
||||
|
||||
private String globalStatusMessage;
|
||||
private String playerStatusMessage;
|
||||
private String playerDisabledGlobalMessage;
|
||||
|
||||
public StatusCommand() {
|
||||
updateConfigValues();
|
||||
}
|
||||
|
||||
public void register(CommandManager<Sender> manager) {
|
||||
manager.command(
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
@@ -35,53 +46,60 @@ public class StatusCommand implements BuilderCommand {
|
||||
.handler(context -> {
|
||||
Sender sender = context.sender();
|
||||
PlayerSelector targetSelector = context.getOrDefault("target", null);
|
||||
if (targetSelector == null) {
|
||||
// Show global status
|
||||
boolean globalStatus = configManager.isToggled();
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("global_status_message", "&eGlobal KnockbackSync status: ")) +
|
||||
(globalStatus
|
||||
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
|
||||
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled")));
|
||||
if (targetSelector == null) {
|
||||
// Show global status
|
||||
boolean globalStatus = configManager.isToggled();
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', globalStatusMessage) +
|
||||
(globalStatus
|
||||
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
|
||||
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled")));
|
||||
|
||||
if (sender.hasPermission(STATUS_SELF_PERMISSION, true)) {
|
||||
// Show player status for the sender (no target specified)
|
||||
if (!sender.isConsole()) {
|
||||
showPlayerStatus(sender, KnockbackSyncBase.INSTANCE.platformServer.getPlayer(sender.getUniqueId()), configManager);
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou do not have permisssion to check your knockbacksync status."));
|
||||
if (sender.hasPermission(STATUS_SELF_PERMISSION, true)) {
|
||||
// Show player status for the sender (no target specified)
|
||||
if (!sender.isConsole()) {
|
||||
showPlayerStatus(sender, KnockbackSyncBase.INSTANCE.platformServer.getPlayer(sender.getUniqueId()));
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou do not have permission to check your knockbacksync status."));
|
||||
}
|
||||
} else {
|
||||
if (sender.hasPermission(STATUS_OTHER_PERMISSION)) {
|
||||
PlatformPlayer target = targetSelector.getSinglePlayer();
|
||||
showPlayerStatus(sender, target, configManager);
|
||||
showPlayerStatus(sender, target);
|
||||
} else {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou do not have permisssion to check the status of other players!"));
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou do not have permission to check the status of other players!"));
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private static void showPlayerStatus(Sender sender, PlatformPlayer target, ConfigManager configManager) {
|
||||
private void showPlayerStatus(Sender sender, PlatformPlayer target) {
|
||||
boolean globalStatus = configManager.isToggled();
|
||||
UUID uuid = target.getUUID();
|
||||
boolean playerStatus = PlayerDataManager.containsPlayerData(uuid);
|
||||
|
||||
String statusMessage = ChatUtil.translateAlternateColorCodes('&', playerStatusMessage.replace("%player%", target.getName()));
|
||||
|
||||
if (!globalStatus) {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("player_status_message", "&e%player%'s KnockbackSync status: ")
|
||||
.replace("%player%", target.getName()) +
|
||||
ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("player_disabled_global_message", "&cDisabled (Global toggle is off)"))));
|
||||
sender.sendMessage(statusMessage + ChatUtil.translateAlternateColorCodes('&', playerDisabledGlobalMessage));
|
||||
} else {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("player_status_message", "&e%player%'s KnockbackSync status: ")
|
||||
.replace("%player%", target.getName()) +
|
||||
sender.sendMessage(statusMessage +
|
||||
(playerStatus
|
||||
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
|
||||
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled"))));
|
||||
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled")));
|
||||
}
|
||||
}
|
||||
|
||||
@KBSyncEventHandler
|
||||
public void onConfigReload(ConfigReloadEvent event) {
|
||||
updateConfigValues();
|
||||
}
|
||||
|
||||
private void updateConfigValues() {
|
||||
ConfigWrapper config = configManager.getConfigWrapper();
|
||||
this.globalStatusMessage = config.getString("global_status_message", "&eGlobal KnockbackSync status: ");
|
||||
this.playerStatusMessage = config.getString("player_status_message", "&e%player%'s KnockbackSync status: ");
|
||||
this.playerDisabledGlobalMessage = config.getString("player_disabled_global_message", "&cDisabled (Global toggle is off)");
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,14 @@
|
||||
package me.caseload.knockbacksync.event;
|
||||
|
||||
import lombok.Getter;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
|
||||
@Getter
|
||||
public class ConfigReloadEvent extends Event {
|
||||
private final ConfigManager configManager;
|
||||
|
||||
public ConfigReloadEvent(ConfigManager configManager) {
|
||||
this.configManager = configManager;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,23 @@
|
||||
package me.caseload.knockbacksync.event;
|
||||
|
||||
import lombok.Setter;
|
||||
import me.caseload.knockbacksync.event.OptimizedEventBus;
|
||||
|
||||
public abstract class Event {
|
||||
@Setter
|
||||
private static EventBus eventBus;
|
||||
@Setter
|
||||
private boolean cancelled = false;
|
||||
|
||||
public void post() {
|
||||
if (eventBus != null) {
|
||||
eventBus.post(this);
|
||||
} else {
|
||||
throw new IllegalStateException("EventBus has not been set");
|
||||
}
|
||||
}
|
||||
|
||||
public boolean isCancelled() {
|
||||
return cancelled;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
package me.caseload.knockbacksync.event;
|
||||
|
||||
public interface EventBus {
|
||||
void registerListeners(Object listener);
|
||||
void unregisterListeners(Object listener);
|
||||
void post(Event event);
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
package me.caseload.knockbacksync.event;
|
||||
|
||||
import java.lang.annotation.ElementType;
|
||||
import java.lang.annotation.Retention;
|
||||
import java.lang.annotation.RetentionPolicy;
|
||||
import java.lang.annotation.Target;
|
||||
|
||||
@Retention(RetentionPolicy.RUNTIME)
|
||||
@Target(ElementType.METHOD)
|
||||
public @interface KBSyncEventHandler {
|
||||
int priority() default 0;
|
||||
}
|
||||
@@ -0,0 +1,69 @@
|
||||
package me.caseload.knockbacksync.event;
|
||||
|
||||
import java.lang.invoke.MethodHandle;
|
||||
import java.lang.invoke.MethodHandles;
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.ArrayList;
|
||||
import java.util.HashMap;
|
||||
import java.util.List;
|
||||
import java.util.Map;
|
||||
|
||||
public class OptimizedEventBus implements EventBus {
|
||||
private final Map<Class<? extends Event>, List<OptimizedListener>> listenerMap = new HashMap<>();
|
||||
private final MethodHandles.Lookup lookup = MethodHandles.lookup();
|
||||
|
||||
@Override
|
||||
public void registerListeners(Object listener) {
|
||||
for (Method method : listener.getClass().getDeclaredMethods()) {
|
||||
KBSyncEventHandler annotation = method.getAnnotation(KBSyncEventHandler.class);
|
||||
if (annotation != null && method.getParameterCount() == 1) {
|
||||
Class<?> eventType = method.getParameterTypes()[0];
|
||||
if (Event.class.isAssignableFrom(eventType)) {
|
||||
try {
|
||||
MethodHandle handle = lookup.unreflect(method);
|
||||
OptimizedListener optimizedListener = new OptimizedListener(listener, handle, annotation.priority());
|
||||
listenerMap.computeIfAbsent((Class<? extends Event>) eventType, k -> new ArrayList<>()).add(optimizedListener);
|
||||
} catch (IllegalAccessException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Sort listeners by priority
|
||||
listenerMap.values().forEach(list -> list.sort((a, b) -> Integer.compare(b.priority, a.priority)));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void unregisterListeners(Object listener) {
|
||||
listenerMap.values().forEach(list -> list.removeIf(l -> l.listener == listener));
|
||||
}
|
||||
|
||||
@Override
|
||||
public void post(Event event) {
|
||||
List<OptimizedListener> listeners = listenerMap.get(event.getClass());
|
||||
if (listeners != null) {
|
||||
for (OptimizedListener listener : listeners) {
|
||||
try {
|
||||
listener.handle.invoke(listener.listener, event);
|
||||
if (event.isCancelled()) {
|
||||
break;
|
||||
}
|
||||
} catch (Throwable throwable) {
|
||||
throwable.printStackTrace();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static class OptimizedListener {
|
||||
final Object listener;
|
||||
final MethodHandle handle;
|
||||
final int priority;
|
||||
|
||||
OptimizedListener(Object listener, MethodHandle handle, int priority) {
|
||||
this.listener = listener;
|
||||
this.handle = handle;
|
||||
this.priority = priority;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -35,7 +35,6 @@ public class ConfigManager {
|
||||
private String playerEnableMessage;
|
||||
private String playerDisableMessage;
|
||||
private String playerIneligibleMessage;
|
||||
private String reloadMessage;
|
||||
|
||||
private AbstractTaskHandle pingTask;
|
||||
|
||||
@@ -117,7 +116,6 @@ public class ConfigManager {
|
||||
playerEnableMessage = config.getString("player_enable_message", "&aSuccessfully enabled KnockbackSync for %player%.");
|
||||
playerDisableMessage = config.getString("player_disable_message", "&cSuccessfully disabled KnockbackSync for %player%.");
|
||||
playerIneligibleMessage = config.getString("player_ineligible_message", "&c%player% is ineligible for KnockbackSync. If you believe this is an error, please open an issue on the github page.");
|
||||
reloadMessage = config.getString("reload_message", "&aSuccessfully reloaded KnockbackSync.");
|
||||
}
|
||||
|
||||
public void updateConfig() {
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
package me.caseload.knockbacksync.player;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
|
||||
import com.github.retrooper.packetevents.protocol.world.Location;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import me.caseload.knockbacksync.world.PlatformWorld;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -30,7 +32,7 @@ public interface PlatformPlayer {
|
||||
|
||||
PlatformWorld getWorld();
|
||||
|
||||
Vector3d getLocation();
|
||||
Location getLocation();
|
||||
|
||||
void sendMessage(@NotNull String s);
|
||||
|
||||
@@ -43,5 +45,7 @@ public interface PlatformPlayer {
|
||||
@Nullable Integer getNoDamageTicks();
|
||||
|
||||
void setVelocity(Vector3d adjustedVelocity);
|
||||
|
||||
BoundingBox getBoundingBox();
|
||||
// Add more methods as needed
|
||||
}
|
||||
@@ -7,6 +7,8 @@ import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
|
||||
import com.github.retrooper.packetevents.protocol.ConnectionState;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.User;
|
||||
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
|
||||
import com.github.retrooper.packetevents.protocol.world.Location;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
@@ -43,8 +45,8 @@ public class PlayerData {
|
||||
public final List<Pair<Integer, Long>> transactionsSent = new LinkedList<>();
|
||||
public final List<Pair<Long, Long>> keepaliveMap = new LinkedList<>();
|
||||
|
||||
private static final short MAIN_THREAD_TRANSACTION_ID = -1;
|
||||
private static final short NETTY_THREAD_TRANSACTION_ID = -2;
|
||||
private static final short MAIN_THREAD_TRANSACTION_ID = 31407;
|
||||
private static final short NETTY_THREAD_TRANSACTION_ID = 31408;
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -177,7 +179,7 @@ public class PlayerData {
|
||||
* @return <code>true</code> if the Player is on the ground; <code>false</code> otherwise.
|
||||
*/
|
||||
public boolean isOnGround(double verticalVelocity) {
|
||||
WrappedBlockState blockState = platformPlayer.getWorld().getBlockStateAt(platformPlayer.getLocation());
|
||||
WrappedBlockState blockState = platformPlayer.getWorld().getBlockStateAt(platformPlayer.getLocation().getPosition());
|
||||
|
||||
if (platformPlayer.isGliding() ||
|
||||
blockState.getType() == StateTypes.WATER ||
|
||||
@@ -215,13 +217,13 @@ public class PlayerData {
|
||||
|
||||
PlatformWorld world = platformPlayer.getWorld();
|
||||
|
||||
for (Vector3d corner : getBBCorners()) {
|
||||
RayTraceResult result = world.rayTraceBlocks(corner, new Vector3d(0, -1, 0), 5, FluidHandling.NONE, true);
|
||||
for (Location corner : getBBCorners()) {
|
||||
RayTraceResult result = world.rayTraceBlocks(corner.getPosition(), new Vector3d(0, -1, 0), 5, FluidHandling.NONE, true);
|
||||
|
||||
if (result == null || result.getHitPosition() == null)
|
||||
if (result == null || result.getHitBlock() == null)
|
||||
continue;
|
||||
|
||||
collisionDist = Math.min(collisionDist, corner.getY() - result.getHitPosition().getY());
|
||||
collisionDist = Math.min(collisionDist, corner.getY() - result.getHitBlockPosition().getY());
|
||||
}
|
||||
|
||||
return collisionDist - 1;
|
||||
@@ -232,17 +234,17 @@ public class PlayerData {
|
||||
*
|
||||
* @return An array of locations representing the corners of the bounding box.
|
||||
*/
|
||||
private Vector3d[] getBBCorners() {
|
||||
Vector3d playerPos = platformPlayer.getLocation();
|
||||
double width = 0.6; // typical player width
|
||||
// double height = 1.8; // typical player height
|
||||
double adjustment = 0.01;
|
||||
private Location[] getBBCorners() {
|
||||
BoundingBox boundingBox = platformPlayer.getBoundingBox();
|
||||
Location location = platformPlayer.getLocation();
|
||||
|
||||
return new Vector3d[]{
|
||||
new Vector3d(playerPos.getX() - width / 2 + adjustment, playerPos.getY(), playerPos.getZ() - width / 2 + adjustment),
|
||||
new Vector3d(playerPos.getX() - width / 2 + adjustment, playerPos.getY(), playerPos.getZ() + width / 2 - adjustment),
|
||||
new Vector3d(playerPos.getX() + width / 2 - adjustment, playerPos.getY(), playerPos.getZ() - width / 2 + adjustment),
|
||||
new Vector3d(playerPos.getX() + width / 2 - adjustment, playerPos.getY(), playerPos.getZ() + width / 2 - adjustment)
|
||||
double adjustment = 0.01; // To ensure the bounding box isn't clipping inside a wall
|
||||
|
||||
return new Location[] {
|
||||
new Location(boundingBox.getMinX() + adjustment, location.getY(), boundingBox.getMinZ() + adjustment, 0, 0),
|
||||
new Location(boundingBox.getMinX() + adjustment, location.getY(), boundingBox.getMaxZ() - adjustment, 0, 0),
|
||||
new Location(boundingBox.getMaxX() - adjustment, location.getY(), boundingBox.getMinZ() + adjustment,0 , 0),
|
||||
new Location(boundingBox.getMaxX() - adjustment, location.getY(), boundingBox.getMaxZ() - adjustment,0, 0)
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
@@ -49,7 +49,7 @@ public class ChatUtil {
|
||||
if (playerData.getPing() == null) {
|
||||
rawReturnString = String.format("Pong not received. %s estimated ping is &b" + playerData.getPlatformPlayer().getPing() + "&rms.", noun);
|
||||
} else {
|
||||
rawReturnString = String.format("%s last ping packet took &b %.3f&rms. Jitter: &b%.3f&rms.", noun, playerData.getPing(), playerData.getJitter());
|
||||
rawReturnString = String.format("%s last ping packet took &b%.3f&rms. Jitter: &b%.3f&rms.", noun, playerData.getPing(), playerData.getJitter());
|
||||
}
|
||||
return ChatUtil.translateAlternateColorCodes('&', rawReturnString);
|
||||
}
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
#########################################
|
||||
|
||||
# Do not modify!
|
||||
config-version: 2
|
||||
config_version: 3
|
||||
|
||||
# Plugin enabled state
|
||||
# Toggleable using /knockbacksync toggle
|
||||
@@ -52,3 +52,142 @@ player_status_message: "&e%player%'s KnockbackSync status: "
|
||||
player_disabled_global_message: "&cDisabled (Global toggle is off)"
|
||||
enable_experimental_offground_message: "&aSuccessfully enabled offground experiment."
|
||||
disable_experimental_offground_message: "&cSuccessfully disabled offground experiment."
|
||||
|
||||
# This is the rate the server will use for (amongst other things) sending packets about entities to players
|
||||
# In other words it defines how often clients get updated velocity for other entities in the world
|
||||
# Note that certain events mark velocity as dirty and causes it to be immediately updated for 1 tick regardless of the tick interval
|
||||
# These include but are not limited to jumping, taking knockback, swimming, and a target entity being affected by a special mob attack
|
||||
# Such as the enderdragon's huge knockback
|
||||
# If an entity below doesn't exist in the version of the game your server is running in, changing the config for it will do nothing
|
||||
entity_tick_intervals:
|
||||
player: 1 # This is 2 by default in vanilla and paper
|
||||
allay: 2
|
||||
area_effect_cloud: Integer.MAX_VALUE
|
||||
armadillo: 3
|
||||
armor_stand: 3
|
||||
arrow: 20
|
||||
axolotl: 3
|
||||
bat: 3
|
||||
bee: 3
|
||||
blaze: 3
|
||||
block_display: 1
|
||||
boat: 3
|
||||
bogged: 3
|
||||
breeze: 3
|
||||
breeze_wind_charge: 10
|
||||
camel: 3
|
||||
cat: 3
|
||||
cave_spider: 3
|
||||
chest_boat: 3
|
||||
chest_minecart: 3
|
||||
chicken: 3
|
||||
cod: 3
|
||||
command_block_minecart: 3
|
||||
cow: 3
|
||||
creeper: 3
|
||||
dolphin: 3
|
||||
donkey: 3
|
||||
dragon_fireball: 10
|
||||
drowned: 3
|
||||
egg: 10
|
||||
elder_guardian: 3
|
||||
end_crystal: Integer.MAX_VALUE
|
||||
ender_dragon: 3
|
||||
ender_pearl: 10
|
||||
enderman: 3
|
||||
endermite: 3
|
||||
evoker: 3
|
||||
evoker_fangs: 2
|
||||
experience_bottle: 10
|
||||
experience_orb: 20
|
||||
eye_of_ender: 4
|
||||
falling_block: 20
|
||||
firework_rocket: 10
|
||||
fox: 3
|
||||
frog: 3
|
||||
furnace_minecart: 3
|
||||
ghast: 3
|
||||
giant: 3
|
||||
glow_item_frame: Integer.MAX_VALUE
|
||||
glow_squid: 3
|
||||
goat: 3
|
||||
guardian: 3
|
||||
hoglin: 3
|
||||
hopper_minecart: 3
|
||||
horse: 3
|
||||
husk: 3
|
||||
illusioner: 3
|
||||
interaction: 3
|
||||
iron_golem: 3
|
||||
item: 20
|
||||
item_display: 1
|
||||
item_frame: Integer.MAX_VALUE
|
||||
ominous_item_spawner: 3
|
||||
fireball: 10
|
||||
leash_knot: Integer.MAX_VALUE
|
||||
lightning_bolt: Integer.MAX_VALUE
|
||||
llama: 3
|
||||
llama_spit: 10
|
||||
magma_cube: 3
|
||||
marker: 3
|
||||
minecart: 3
|
||||
mooshroom: 3
|
||||
mule: 3
|
||||
ocelot: 3
|
||||
painting: Integer.MAX_VALUE
|
||||
panda: 3
|
||||
parrot: 3
|
||||
phantom: 3
|
||||
pig: 3
|
||||
piglin: 3
|
||||
piglin_brute: 3
|
||||
pillager: 3
|
||||
polar_bear: 3
|
||||
potion: 10
|
||||
pufferfish: 3
|
||||
rabbit: 3
|
||||
ravager: 3
|
||||
salmon: 3
|
||||
sheep: 3
|
||||
shulker: 3
|
||||
shulker_bullet: 3
|
||||
silverfish: 3
|
||||
skeleton: 3
|
||||
skeleton_horse: 3
|
||||
slime: 3
|
||||
small_fireball: 10
|
||||
sniffer: 3
|
||||
snow_golem: 3
|
||||
snowball: 10
|
||||
spawner_minecart: 3
|
||||
spectral_arrow: 20
|
||||
spider: 3
|
||||
squid: 3
|
||||
stray: 3
|
||||
strider: 3
|
||||
tadpole: 3
|
||||
text_display: 1
|
||||
tnt: 10
|
||||
tnt_minecart: 3
|
||||
trader_llama: 3
|
||||
trident: 20
|
||||
tropical_fish: 3
|
||||
turtle: 3
|
||||
vex: 3
|
||||
villager: 3
|
||||
vindicator: 3
|
||||
wandering_trader: 3
|
||||
warden: 3
|
||||
wind_charge: 10
|
||||
witch: 3
|
||||
wither: 3
|
||||
wither_skeleton: 3
|
||||
wither_skull: 10
|
||||
wolf: 3
|
||||
zoglin: 3
|
||||
zombie: 3
|
||||
zombie_horse: 3
|
||||
zombie_villager: 3
|
||||
zombified_piglin: 3
|
||||
fishing_bobber: 5
|
||||
|
||||
@@ -3,6 +3,10 @@ plugins {
|
||||
id("com.gradleup.shadow")
|
||||
}
|
||||
|
||||
loom {
|
||||
accessWidenerPath = file("src/main/resources/knockbacksync.accesswidener")
|
||||
}
|
||||
|
||||
base {
|
||||
archivesName.set("${rootProject.property("archives_base_name")}-fabric")
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
package me.caseload.knockbacksync.entity;
|
||||
|
||||
import me.caseload.knockbacksync.ConfigWrapper;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.event.ConfigReloadEvent;
|
||||
import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
public class EntityTickManager {
|
||||
private static final Map<EntityType<?>, Integer> customTickIntervals = new HashMap<>();
|
||||
|
||||
static {
|
||||
updateTickIntervals(KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper());
|
||||
}
|
||||
|
||||
@KBSyncEventHandler
|
||||
public static void updateTickIntervals(ConfigReloadEvent configReloadEvent) {
|
||||
ConfigWrapper configWrapper = configReloadEvent.getConfigManager().getConfigWrapper();
|
||||
updateTickIntervals(configWrapper);
|
||||
}
|
||||
|
||||
private static void updateTickIntervals(ConfigWrapper configWrapper) {
|
||||
customTickIntervals.clear();
|
||||
for (String entityKey : configWrapper.getKeys("entity_tick_intervals")) {
|
||||
try {
|
||||
Optional<EntityType<?>> entityType = EntityType.byString(entityKey.toUpperCase());
|
||||
if (entityType.isPresent()) {
|
||||
int interval = configWrapper.getInt("entity_tick_intervals." + entityKey, entityType.get().updateInterval());
|
||||
customTickIntervals.put(entityType.get(), interval);
|
||||
}
|
||||
} catch (IllegalArgumentException e) {
|
||||
System.err.println("Invalid entity type in config: " + entityKey);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static int getCustomUpdateInterval(EntityType<?> entityType) {
|
||||
return customTickIntervals.getOrDefault(entityType.getDescription().getString().toLowerCase(), entityType.updateInterval());
|
||||
}
|
||||
}
|
||||
-12
@@ -17,18 +17,6 @@ public class FabricPlayerDamageListener extends PlayerDamageListener {
|
||||
onPlayerDamage((ServerPlayer) player, entity);
|
||||
return InteractionResult.PASS;
|
||||
});
|
||||
|
||||
// Sending ping packets on tick if runnable is disabled
|
||||
// ServerTickEvents.END_SERVER_TICK.register(server -> {
|
||||
// if (!KnockbackSyncBase.INSTANCE.getConfigManager().isRunnableEnabled()) {
|
||||
// for (ServerPlayerEntity player : server.getPlayerList()) {
|
||||
// PlayerData playerData = PlayerDataManager.getPlayerData(player);
|
||||
// if (playerData != null) {
|
||||
// playerData.sendPing();
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// });
|
||||
}
|
||||
|
||||
private void onPlayerDamage(ServerPlayer attacker, Entity victimEntity) {
|
||||
|
||||
@@ -0,0 +1,30 @@
|
||||
package me.caseload.knockbacksync.mixin;
|
||||
|
||||
import com.google.common.collect.Maps;
|
||||
import me.caseload.knockbacksync.ConfigWrapper;
|
||||
import me.caseload.knockbacksync.entity.EntityTickManager;
|
||||
import me.caseload.knockbacksync.event.ConfigReloadEvent;
|
||||
import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
import net.minecraft.core.registries.BuiltInRegistries;
|
||||
import net.minecraft.resources.ResourceLocation;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
import net.minecraft.world.entity.EntityType;
|
||||
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.Redirect;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
|
||||
@Mixin(ChunkMap.class)
|
||||
public abstract class ChunkMapMixin {
|
||||
|
||||
@Redirect(method = "addEntity", at = @At(value = "INVOKE", target = "Lnet/minecraft/world/entity/EntityType;updateInterval()I"))
|
||||
private int getCustomUpdateInterval(EntityType<?> entityType) {
|
||||
// BuiltInRegistries.ENTITY_TYPE.get(ResourceLocation.parse());
|
||||
// Check if we have a custom interval for this entity type
|
||||
return EntityTickManager.getCustomUpdateInterval(entityType);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,86 @@
|
||||
//package me.caseload.knockbacksync.mixin;
|
||||
//
|
||||
//import me.caseload.knockbacksync.ConfigWrapper;
|
||||
//import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
//import me.caseload.knockbacksync.event.ConfigReloadEvent;
|
||||
//import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
//import me.caseload.knockbacksync.util.CustomUpdateIntervals;
|
||||
//import net.minecraft.Util;
|
||||
//import net.minecraft.server.level.ChunkMap;
|
||||
//import net.minecraft.server.level.ServerLevel;
|
||||
//import net.minecraft.server.level.ServerPlayer;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//import net.minecraft.world.entity.EntityType;
|
||||
//import net.minecraft.world.entity.boss.EnderDragonPart;
|
||||
//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;
|
||||
//
|
||||
//import java.util.HashMap;
|
||||
//import java.util.Map;
|
||||
//
|
||||
//@Mixin(ChunkMap.class)
|
||||
//public class ChunkMapMixin {
|
||||
//
|
||||
// @Shadow @Final
|
||||
// private Map<Integer, ChunkMap.TrackedEntity> entityMap;
|
||||
// @Shadow @Final private ServerLevel level;
|
||||
//
|
||||
// @Inject(method = "addEntity", at = @At("HEAD"), cancellable = true)
|
||||
// private void onAddEntity(Entity entity, CallbackInfo ci) {
|
||||
// if (!(entity instanceof EnderDragonPart)) {
|
||||
// EntityType<?> entityType = entity.getType();
|
||||
// int trackingRange = entityType.clientTrackingRange() * 16;
|
||||
//
|
||||
// if (trackingRange != 0) {
|
||||
// String entityTypeName = entityType.builtInRegistryHolder().getRegisteredName();
|
||||
// ConfigWrapper config = KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper();
|
||||
//
|
||||
// int defaultInterval = entityType.updateInterval();
|
||||
// int customInterval = config.getInt("entity_update_intervals." + entityTypeName, defaultInterval);
|
||||
//
|
||||
// if (this.entityMap.containsKey(entity.getId())) {
|
||||
// throw (IllegalStateException) Util.pauseInIde(new IllegalStateException("Entity is already tracked!"));
|
||||
// } else {
|
||||
// ChunkMap.TrackedEntity trackedEntity = new ChunkMap.TrackedEntity(entity, trackingRange, customInterval, entityType.trackDeltas());
|
||||
// this.entityMap.put(entity.getId(), trackedEntity);
|
||||
// trackedEntity.updatePlayers(this.level.players());
|
||||
//
|
||||
// if (entity instanceof ServerPlayer serverPlayer) {
|
||||
// this.updatePlayerStatus(serverPlayer, true);
|
||||
//
|
||||
// for (ChunkMap.TrackedEntity trackedEntity2 : this.entityMap.values()) {
|
||||
// if (trackedEntity2.entity != serverPlayer) {
|
||||
// trackedEntity2.updatePlayer(serverPlayer);
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
// }
|
||||
//
|
||||
// ci.cancel();
|
||||
// }
|
||||
//
|
||||
// @Shadow
|
||||
// private void updatePlayerStatus(ServerPlayer player, boolean track) {
|
||||
// // This is a shadow method, implementation is provided by Minecraft
|
||||
// }
|
||||
//
|
||||
// @KBSyncEventHandler
|
||||
// public void onConfigReload(ConfigReloadEvent event) {
|
||||
// Map<String, Integer> newIntervals = CustomUpdateIntervals.loadEntityIntervalsFromConfig();
|
||||
//
|
||||
// for (ChunkMap.TrackedEntity trackedEntity : this.entityMap.values()) {
|
||||
// Entity entity = trackedEntity.entity;
|
||||
// String entityTypeName = entity.getType().builtInRegistryHolder().getRegisteredName();
|
||||
// int newInterval = newIntervals.getOrDefault(entityTypeName, entity.getType().updateInterval());
|
||||
//
|
||||
// // Assuming TrackedEntity has a method to update its update interval
|
||||
// trackedEntity.setUpdateInterval(newInterval);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,7 +1,16 @@
|
||||
package me.caseload.knockbacksync.mixin;
|
||||
|
||||
import me.caseload.knockbacksync.KBSyncFabricLoaderMod;
|
||||
import me.caseload.knockbacksync.callback.PlayerVelocityEvent;
|
||||
import me.caseload.knockbacksync.event.ConfigReloadEvent;
|
||||
import me.caseload.knockbacksync.event.KBSyncEventHandler;
|
||||
import me.caseload.knockbacksync.util.CustomUpdateIntervals;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.impl.FabricLoaderImpl;
|
||||
import net.minecraft.server.MinecraftServer;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.InteractionResult;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
@@ -9,32 +18,65 @@ import net.minecraft.world.phys.Vec3;
|
||||
import org.spongepowered.asm.mixin.Final;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
import org.spongepowered.asm.mixin.gen.Invoker;
|
||||
import org.spongepowered.asm.mixin.injection.At;
|
||||
import org.spongepowered.asm.mixin.injection.Inject;
|
||||
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
//
|
||||
//import java.util.Map;
|
||||
//
|
||||
//@Mixin(ServerEntity.class)
|
||||
//public class ServerEntityMixin implements UpdateIntervalAccessor {
|
||||
|
||||
@Mixin(ServerEntity.class)
|
||||
public class ServerEntityMixin {
|
||||
|
||||
|
||||
@Shadow
|
||||
@Final
|
||||
private Entity entity;
|
||||
|
||||
@Inject(method = "sendChanges", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/Entity;hurtMarked:Z", ordinal = 1), cancellable = true)
|
||||
private void onSendChanges(CallbackInfo ci) {
|
||||
if (this.entity.hurtMarked && this.entity instanceof ServerPlayer player) {
|
||||
Vec3 velocity = player.getDeltaMovement();
|
||||
|
||||
InteractionResult result = PlayerVelocityEvent.EVENT.invoker().onVelocityChange(player, velocity);
|
||||
|
||||
if (result == InteractionResult.FAIL) {
|
||||
this.entity.hurtMarked = false;
|
||||
ci.cancel();
|
||||
} else if (result == InteractionResult.SUCCESS) {
|
||||
// Currently unnecessary since we do this in the handler, will move later
|
||||
player.setDeltaMovement(velocity);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
//
|
||||
// @Shadow
|
||||
// @Final
|
||||
// private Entity entity;
|
||||
//
|
||||
// // Velocity event
|
||||
// @Inject(method = "sendChanges", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/Entity;hurtMarked:Z", ordinal = 1), cancellable = true)
|
||||
// private void onSendChanges(CallbackInfo ci) {
|
||||
// if (this.entity.hurtMarked && this.entity instanceof ServerPlayer player) {
|
||||
// Vec3 velocity = player.getDeltaMovement();
|
||||
//
|
||||
// InteractionResult result = PlayerVelocityEvent.EVENT.invoker().onVelocityChange(player, velocity);
|
||||
//
|
||||
// if (result == InteractionResult.FAIL) {
|
||||
// this.entity.hurtMarked = false;
|
||||
// ci.cancel();
|
||||
// } else if (result == InteractionResult.SUCCESS) {
|
||||
// // Currently unnecessary since we do this in the handler, will move later
|
||||
// player.setDeltaMovement(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;
|
||||
// }
|
||||
//
|
||||
//
|
||||
// @KBSyncEventHandler
|
||||
// public void onConfigReload(ConfigReloadEvent event) {
|
||||
// Map<String, Integer> entityIntervals = CustomUpdateIntervals.loadEntityIntervalsFromConfig();
|
||||
// for (ServerLevel level : KBSyncFabricLoaderMod.getServer().getAllLevels()) {
|
||||
// CustomUpdateIntervals.updateIntervals(level, entityIntervals);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.caseload.knockbacksync.mixin;
|
||||
|
||||
import me.caseload.knockbacksync.callback.TickRateChangeEvent;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.TickRateManager;
|
||||
import org.spongepowered.asm.mixin.Mixin;
|
||||
import org.spongepowered.asm.mixin.Shadow;
|
||||
|
||||
@@ -0,0 +1,41 @@
|
||||
//package me.caseload.knockbacksync.mixin;
|
||||
//
|
||||
//import me.caseload.knockbacksync.ConfigWrapper;
|
||||
//import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
//import net.minecraft.core.SectionPos;
|
||||
//import net.minecraft.server.level.ChunkMap;
|
||||
//import net.minecraft.server.level.ServerEntity;
|
||||
//import net.minecraft.world.entity.Entity;
|
||||
//import org.spongepowered.asm.mixin.Mixin;
|
||||
//import org.spongepowered.asm.mixin.Shadow;
|
||||
//import org.spongepowered.asm.mixin.gen.Accessor;
|
||||
//import org.spongepowered.asm.mixin.injection.At;
|
||||
//import org.spongepowered.asm.mixin.injection.Inject;
|
||||
//import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;
|
||||
//
|
||||
//@Mixin(ChunkMap.TrackedEntity.class)
|
||||
//public class TrackedEntityMixin {
|
||||
// @Shadow
|
||||
// ServerEntity serverEntity;
|
||||
// Entity entity;
|
||||
// int range;
|
||||
// SectionPos lastSectionPos;
|
||||
//
|
||||
// @Inject(method = "<init>", at = @At("HEAD"))
|
||||
// private void onInit(ChunkMap outer, Entity entity, int range, int updateInterval, boolean trackDelta, CallbackInfo ci) {
|
||||
//
|
||||
// String entityTypeName = entity.getType().builtInRegistryHolder().getRegisteredName();
|
||||
// ConfigWrapper config = KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper();
|
||||
// int customInterval = config.getInt("entity_update_intervals." + entityTypeName, updateInterval);
|
||||
//
|
||||
// this.serverEntity = new ServerEntity(ChunkMap.this.level, entity, customInterval, trackDelta, this::broadcast);
|
||||
// this.entity = entity;
|
||||
// this.range = range;
|
||||
// this.lastSectionPos = SectionPos.of(entity);
|
||||
// }
|
||||
//
|
||||
//// @Accessor("updateInterval")
|
||||
//// public void setUpdateInterval(int interval) {
|
||||
// // This method will be implemented by the mixin system
|
||||
//// }
|
||||
//}
|
||||
@@ -0,0 +1,5 @@
|
||||
package me.caseload.knockbacksync.mixin;
|
||||
|
||||
public interface UpdateIntervalAccessor {
|
||||
void setUpdateInterval(int interval);
|
||||
}
|
||||
@@ -1,5 +1,7 @@
|
||||
package me.caseload.knockbacksync.player;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
|
||||
import com.github.retrooper.packetevents.protocol.world.Location;
|
||||
import com.github.retrooper.packetevents.util.Vector3d;
|
||||
import me.caseload.knockbacksync.world.FabricWorld;
|
||||
import me.caseload.knockbacksync.world.PlatformWorld;
|
||||
@@ -11,6 +13,7 @@ import net.minecraft.server.level.ServerPlayer;
|
||||
import net.minecraft.world.item.enchantment.Enchantment;
|
||||
import net.minecraft.world.item.enchantment.EnchantmentHelper;
|
||||
import net.minecraft.world.item.enchantment.Enchantments;
|
||||
import net.minecraft.world.phys.AABB;
|
||||
import net.minecraft.world.phys.Vec3;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
@@ -81,9 +84,8 @@ public class FabricPlayer implements PlatformPlayer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public Vector3d getLocation() {
|
||||
Vec3 pos = fabricPlayer.position();
|
||||
return new Vector3d(pos.x, pos.y, pos.z);
|
||||
public Location getLocation() {
|
||||
return new Location(fabricPlayer.getX(), fabricPlayer.getY(), fabricPlayer.getZ(), fabricPlayer.getYRot(), fabricPlayer.getXRot());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -125,5 +127,11 @@ public class FabricPlayer implements PlatformPlayer {
|
||||
fabricPlayer.hurtMarked = true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public BoundingBox getBoundingBox() {
|
||||
AABB boundingBox = fabricPlayer.getBoundingBox();
|
||||
return new BoundingBox(boundingBox.minX, boundingBox.minY, boundingBox.minZ, boundingBox.maxX, boundingBox.minY, boundingBox.maxZ);
|
||||
}
|
||||
|
||||
// Implement other methods
|
||||
}
|
||||
@@ -0,0 +1,58 @@
|
||||
package me.caseload.knockbacksync.util;
|
||||
|
||||
import me.caseload.knockbacksync.ConfigWrapper;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.mixin.UpdateIntervalAccessor;
|
||||
import net.minecraft.server.level.ChunkMap;
|
||||
import net.minecraft.server.level.ServerChunkCache;
|
||||
import net.minecraft.server.level.ServerEntity;
|
||||
import net.minecraft.server.level.ServerLevel;
|
||||
import net.minecraft.world.entity.Entity;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.Map;
|
||||
|
||||
public class CustomUpdateIntervals {
|
||||
private static final Map<String, Integer> entityIntervals = new HashMap<>();
|
||||
|
||||
public static void setInterval(String entityType, int interval) {
|
||||
entityIntervals.put(entityType, interval);
|
||||
}
|
||||
|
||||
public static int getInterval(String entityType, int defaultInterval) {
|
||||
return entityIntervals.getOrDefault(entityType, defaultInterval);
|
||||
}
|
||||
|
||||
public static void clear() {
|
||||
entityIntervals.clear();
|
||||
}
|
||||
|
||||
public static void updateIntervals(ServerLevel level, Map<String, Integer> entityIntervals) {
|
||||
for (Entity entity : level.getAllEntities()) {
|
||||
String entityType = entity.getType().builtInRegistryHolder().getRegisteredName();
|
||||
if (entityIntervals.containsKey(entityType)) {
|
||||
ChunkMap.TrackedEntity serverEntity = ((ServerChunkCache) entity.level().getChunkSource()).chunkMap.entityMap.get(entity.getId());
|
||||
if (serverEntity != null) {
|
||||
((UpdateIntervalAccessor) serverEntity).setUpdateInterval(entityIntervals.get(entityType));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public static Map<String, Integer> loadEntityIntervalsFromConfig() {
|
||||
Map<String, Integer> intervals = new HashMap<>();
|
||||
ConfigWrapper config = KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper();
|
||||
|
||||
String basePath = "entity_update_intervals";
|
||||
if (config.contains(basePath)) {
|
||||
for (String entityType : config.getKeys(basePath)) {
|
||||
int interval = config.getInt(basePath + "." + entityType, -1);
|
||||
if (interval > 0) {
|
||||
intervals.put(entityType, interval);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return intervals;
|
||||
}
|
||||
}
|
||||
@@ -21,5 +21,6 @@
|
||||
"fabricloader": ">=${loader_version}",
|
||||
"fabric": "*",
|
||||
"minecraft": "~${minecraft_version}"
|
||||
}
|
||||
},
|
||||
"accessWidener": "knockbacksync.accesswidener"
|
||||
}
|
||||
@@ -0,0 +1,6 @@
|
||||
accessWidener v2 named
|
||||
|
||||
# We don't actually need this right now, but it's useful to keep an access widener around for when we do need one
|
||||
accessible field net/minecraft/server/level/ChunkMap entityMap Lit/unimi/dsi/fastutil/ints/Int2ObjectMap;
|
||||
accessible class net/minecraft/server/level/ChunkMap$TrackedEntity
|
||||
accessible method net/minecraft/server/level/ChunkMap$TrackedEntity updatePlayers (Ljava/util/List;)V
|
||||
@@ -4,10 +4,12 @@
|
||||
"package": "me.caseload.knockbacksync.mixin",
|
||||
"compatibilityLevel": "JAVA_21",
|
||||
"mixins": [
|
||||
"ChunkMapMixin",
|
||||
"CommandStackSourceAccessor",
|
||||
"PlayerMixin",
|
||||
"ServerEntityMixin",
|
||||
"TickRateManagerMixin"
|
||||
// "ServerEntityMixin",
|
||||
"TickRateManagerMixin",
|
||||
// "TrackedEntityMixin"
|
||||
],
|
||||
"injectors": {
|
||||
"defaultRequire": 1
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+7
@@ -0,0 +1,7 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.8-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
zipStorePath=wrapper/dists
|
||||
Reference in new issue
Block a user