Author SHA1 Message Date
Axionize 7e94b5ab84 Fix hacky grim detect 2024-10-28 00:43:53 -04:00
Axionize 2f34adeeb2 Grim offground 2024-10-28 00:28:57 -04:00
Axionize 73ab2388dc Remove building packetevents from actions script 2024-10-27 05:38:39 -04:00
Axionize 7c129185c5 Fix plugin loading on bukkit after refactor 2024-10-26 22:48:25 -04:00
Axionize ac5bd598f0 Bump gradle version in github actions to min required for packetevents-fabric 2.6.0 2024-10-26 22:32:47 -04:00
Axionize 98f23966db Fix clientBrand for fabricPlayer 2024-10-26 22:27:57 -04:00
Axionize 0803d2800f Remove redundant code 2024-10-26 22:26:34 -04:00
Axionize 83dab3cb8c Merge branch 'booky-packets' into dev 2024-10-26 22:25:45 -04:00
Axionize 768bc20e14 Packetevents 2.6.0 fabric fixes 2024-10-26 22:25:28 -04:00
Axionize f3bd42ff2f Add new ClientBrands pie 2024-10-26 22:14:17 -04:00
Axionize a56fd79d29 Initial work to port to 2.6.0 packetevents-fabric 2024-10-26 21:24:00 -04:00
Axionize e1b2487396 Try booky10 fabric fail 2024-10-26 18:34:00 -04:00
Axionize f19499205f Add showing offground sync status 2024-10-26 18:05:06 -04:00
Axionize 39e8cbddcb Config fixes - Fix reloading toggleoffground 2024-10-26 17:45:21 -04:00
Axionize 42c3129060 Merge remote-tracking branch 'origin/workspace' into dev-upstream
# Conflicts:
#	common/src/main/java/me/caseload/knockbacksync/listener/PlayerKnockbackListener.java
#	common/src/main/java/me/caseload/knockbacksync/player/PlayerData.java
#	common/src/main/java/me/caseload/knockbacksync/util/ChatUtil.java
#	common/src/main/java/me/caseload/knockbacksync/util/MathUtil.java
2024-10-26 17:27:20 -04:00
Axionize a6a2577e07 Config fixes 2024-10-26 17:11:19 -04:00
Axionize 619e50dd6a Revert to getHitBlockPosition() 2024-10-26 17:08:53 -04:00
Axionize 98cbf4adfc Make every message besides root configureable 2024-10-26 17:00:59 -04:00
Axionize 7b5949dba6 /tick rate support on Bukkit 2024-10-26 15:40:18 -04:00
Axionize 0be787c1e2 Make all base variables consistently encapsulated 2024-10-26 15:08:08 -04:00
32 changed files with 516 additions and 206 deletions

No files matched your search

+3 -26
View File
@@ -26,33 +26,10 @@ jobs:
distribution: 'adopt'
cache: gradle
- name: Setup Gradle
uses: gradle/gradle-build-action@v2
- name: Setup Gradle 8.10
uses: gradle/actions/setup-gradle@v4
with:
gradle-version: 8.8
# Temporary workaround to packetevents bugs, use custom fork build
- name: Checkout packetevents repository
uses: actions/checkout@v3
with:
repository: Axionize/packetevents
ref: 2.0-fabric-serverside-fix
path: packetevents
- name: Update version in packetevents
run: |
cd packetevents
sed -i 's/val fullVersion = ".*"/val fullVersion = "2.5.8"/' build.gradle.kts
- name: Build packetevents with Gradle
run: |
cd packetevents
gradle build -x test
- name: Publish packetevents to Maven Local
run: |
cd packetevents
gradle publishToMavenLocal
gradle-version: "8.10" # Quotes required to prevent YAML converting to number
- name: Generate build number
id: buildnumber
+1
View File
@@ -44,6 +44,7 @@ allprojects {
}
maven("https://libraries.minecraft.net/")
maven("https://maven.neoforged.net/releases")
maven("https://repo.codemc.io/repository/maven-snapshots/")
}
}
@@ -18,6 +18,7 @@ import me.caseload.knockbacksync.stats.custom.BukkitStatsManager;
import me.caseload.knockbacksync.stats.custom.PluginJarHashProvider;
import me.caseload.knockbacksync.world.BukkitServer;
import org.bukkit.Bukkit;
import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.entity.Player;
import org.bukkit.event.Listener;
@@ -29,6 +30,9 @@ import org.incendo.cloud.paper.LegacyPaperCommandManager;
import java.io.File;
import java.io.InputStream;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -43,14 +47,36 @@ public class BukkitBase extends Base {
private int playerUpdateInterval;
private final MethodHandle tickRateMethodHandle;
public BukkitBase(JavaPlugin plugin) {
this.plugin = plugin;
super.configManager = new ConfigManager();
super.playerSelectorParser = new BukkitPlayerSelectorParser<>();
super.statsManager = new BukkitStatsManager();
super.statsManager = new BukkitStatsManager(plugin);
super.platformServer = new BukkitServer();
super.pluginJarHashProvider = new PluginJarHashProvider(this.getClass().getProtectionDomain().getCodeSource().getLocation());
this.playerUpdateInterval = this.getConfigManager().getConfigWrapper().getInt("entity_tick_intervals.player", 2);
MethodHandle handle = null;
try {
Server craftServer = Bukkit.getServer();
MethodHandles.Lookup lookup = MethodHandles.lookup();
// Get handle for getServerTickManager
MethodHandle getServerTickManager = lookup.findVirtual(craftServer.getClass(),
"getServerTickManager", MethodType.methodType(Object.class));
Object serverTickManager = getServerTickManager.invoke(craftServer);
// Get handle for getTickRate
handle = lookup.findVirtual(serverTickManager.getClass(),
"getTickRate", MethodType.methodType(float.class));
} catch (Throwable t) {
// If anything fails, handle will remain null
}
this.tickRateMethodHandle = handle;
}
@Override
@@ -77,13 +103,7 @@ public class BukkitBase extends Base {
@Override
public void enable() {
super.enable();
initializeScheduler();
saveDefaultConfig();
configManager.updateConfig();
configManager.loadConfig(false);
statsManager.init();
checkForUpdates();
super.simpleEventBus.registerListeners(this);
super.eventBus.registerListeners(this);
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_20_5)) {
scheduler.runTaskTimerAsynchronously(this::setUpdateIntervals, 1, 1);
}
@@ -91,7 +111,7 @@ public class BukkitBase extends Base {
@Override
public void initializeScheduler() {
switch (platform) {
switch (getPlatform()) {
case BUKKIT:
super.scheduler = new BukkitSchedulerAdapter(this.plugin);
break;
@@ -143,6 +163,18 @@ public class BukkitBase extends Base {
return permissionChecker;
}
@Override
public float getTickRate() {
if (tickRateMethodHandle != null) {
try {
return (float) tickRateMethodHandle.invoke();
} catch (Throwable t) {
return 20.0f;
}
}
return 20.0f;
}
private void registerPluginListeners(Listener... listeners) {
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
for (Listener listener : listeners)
@@ -2,6 +2,7 @@ package me.caseload.knockbacksync.player;
import com.github.retrooper.packetevents.PacketEvents;
import com.github.retrooper.packetevents.manager.server.ServerVersion;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
import com.github.retrooper.packetevents.util.Vector3d;
import me.caseload.knockbacksync.world.PlatformWorld;
@@ -21,6 +22,7 @@ import java.util.UUID;
public class BukkitPlayer implements PlatformPlayer {
public final Player bukkitPlayer;
private String clientBrand = "vanilla";
// Reflection variables
private static Class<?> craftPlayerClass;
@@ -208,4 +210,19 @@ public class BukkitPlayer implements PlatformPlayer {
org.bukkit.util.BoundingBox boundingBox = bukkitPlayer.getBoundingBox();
return new BoundingBox(boundingBox.getMinX(), boundingBox.getMinY(), boundingBox.getMinZ(), boundingBox.getMaxX(), boundingBox.getMaxY(), boundingBox.getMaxZ());
}
@Override
public User getUser() {
return PacketEvents.getAPI().getPlayerManager().getUser(bukkitPlayer);
}
@Override
public void setClientBrand(String brand) {
this.clientBrand = brand;
}
@Override
public String getClientBrand() {
return this.clientBrand;
}
}
@@ -1,17 +1,11 @@
package me.caseload.knockbacksync.stats.custom;
import me.caseload.knockbacksync.Base;
import org.bukkit.plugin.Plugin;
public class BukkitStatsManager extends StatsManager {
@Override
public void init() {
Base.INSTANCE.getScheduler().runTaskAsynchronously(() -> {
BuildTypePie.determineBuildType(); // Function to calculate hash
MetricsBukkit metrics = new MetricsBukkit(23568);
metrics.addCustomChart(new PlayerVersionsPie());
metrics.addCustomChart(new BuildTypePie());
super.metrics = metrics;
});
public BukkitStatsManager(Plugin plugin) {
super(new MetricsBukkit(plugin, 23568));
}
}
@@ -34,12 +34,11 @@ import java.util.logging.Level;
public class MetricsBukkit implements Metrics {
private final Plugin plugin;
private final MetricsBase metricsBase;
public MetricsBukkit(int serviceId) {
this.plugin = BukkitLoaderPlugin.getPlugin(BukkitLoaderPlugin.class);
public MetricsBukkit(Plugin plugin, int serviceId) {
this.plugin = plugin;
// Get the config file
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
File configFile = new File(bStatsFolder, "config.yml");
@@ -14,11 +14,13 @@ 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.ClientBrandListener;
import me.caseload.knockbacksync.listener.packetevents.PingReceiveListener;
import me.caseload.knockbacksync.manager.ConfigManager;
import me.caseload.knockbacksync.permission.PermissionChecker;
import me.caseload.knockbacksync.scheduler.SchedulerAdapter;
import me.caseload.knockbacksync.sender.Sender;
import me.caseload.knockbacksync.stats.custom.ClientBrandsPie;
import me.caseload.knockbacksync.stats.custom.PluginJarHashProvider;
import me.caseload.knockbacksync.stats.custom.StatsManager;
import me.caseload.knockbacksync.world.PlatformServer;
@@ -35,24 +37,24 @@ public abstract class Base {
public static Logger LOGGER;
public static Base INSTANCE;
public final Platform platform;
public StatsManager statsManager;
public PlatformServer platformServer;
@Getter private final Platform platform;
@Getter protected StatsManager statsManager;
@Getter protected PlatformServer platformServer;
@Getter protected PluginJarHashProvider pluginJarHashProvider;
@Getter protected SchedulerAdapter scheduler;
@Getter protected ConfigManager configManager;
protected CommandManager<Sender> commandManager;
@Getter protected final EventBus simpleEventBus = new OptimizedEventBus();
@Getter protected CommandManager<Sender> commandManager;
@Getter protected final EventBus eventBus = new OptimizedEventBus();
@Getter
protected AbstractPlayerSelectorParser<Sender> playerSelectorParser;
protected Base() {
this.platform = getPlatform();
this.platform = detectPlatform();
INSTANCE = this;
}
private Platform getPlatform() {
private Platform detectPlatform() {
final Map<String, Platform> platforms = Collections.unmodifiableMap(new HashMap<String, Platform>() {{
put("io.papermc.paper.threadedregions.RegionizedServer", Platform.FOLIA);
put("org.bukkit.Bukkit", Platform.BUKKIT);
@@ -90,6 +92,10 @@ public abstract class Base {
registerCommonListeners();
registerPlatformListeners();
registerCommands();
initializeScheduler();
configManager.loadConfig(false);
statsManager.init();
checkForUpdates();
}
public abstract void initializeScheduler();
@@ -105,9 +111,10 @@ public abstract class Base {
protected void registerCommonListeners() {
PacketEvents.getAPI().getEventManager().registerListeners(
new AttributeChangeListener(),
new PingReceiveListener()
new PingReceiveListener(),
new ClientBrandListener()
);
Event.setEventBus(simpleEventBus);
Event.setEventBus(eventBus);
}
protected abstract void registerPlatformListeners();
@@ -220,6 +227,7 @@ public abstract class Base {
public abstract PermissionChecker getPermissionChecker();
public abstract float getTickRate();
}
@@ -1,16 +1,36 @@
package me.caseload.knockbacksync.command.subcommand;
import me.caseload.knockbacksync.Base;
import me.caseload.knockbacksync.ConfigWrapper;
import me.caseload.knockbacksync.command.generic.BuilderCommand;
import me.caseload.knockbacksync.command.generic.PlayerSelector;
import me.caseload.knockbacksync.event.KBSyncEventHandler;
import me.caseload.knockbacksync.event.events.ConfigReloadEvent;
import me.caseload.knockbacksync.manager.PlayerDataManager;
import me.caseload.knockbacksync.player.PlayerData;
import me.caseload.knockbacksync.sender.Sender;
import me.caseload.knockbacksync.util.ChatUtil;
import org.incendo.cloud.CommandManager;
import org.incendo.cloud.permission.PredicatePermission;
import java.util.UUID;
import java.util.function.Predicate;
public class PingCommand implements BuilderCommand {
private String pingSelfAvailableMessage;
private String pingSelfUnavailableMessage;
private String pingOtherAvailableMessage;
private String pingOtherUnavailableMessage;
private String mustSpecifyPlayerFromConsoleMessage;
private String knockbacksyncDisabledForYouMessage;
private String knockbacksyncDisabledForTargetMessage;
public PingCommand() {
loadConfig();
}
public void register(CommandManager<Sender> manager) {
manager.command(
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
@@ -29,16 +49,76 @@ public class PingCommand implements BuilderCommand {
if (targetSelector == null) {
if (context.sender().isConsole()) {
context.sender().sendMessage("You must specify a player to use this command from the console.");
context.sender().sendMessage(ChatUtil.translateAlternateColorCodes('&', mustSpecifyPlayerFromConsoleMessage));
} else {
context.sender().sendMessage(ChatUtil.getPingMessage(context.sender().getUniqueId(), null));
context.sender().sendMessage(getPingMessage(context.sender().getUniqueId(), null));
}
} else {
context.sender().sendMessage(ChatUtil.getPingMessage(context.sender().getUniqueId(), targetSelector.getSinglePlayer().getUUID()));
context.sender().sendMessage(getPingMessage(context.sender().getUniqueId(), targetSelector.getSinglePlayer().getUUID()));
}
})
);
Base.INSTANCE.getEventBus().registerListeners(this);
}
private void loadConfig() {
ConfigWrapper configWrapper = Base.INSTANCE.getConfigManager().getConfigWrapper();
pingSelfAvailableMessage = configWrapper.getString("messages.ping.self.available",
"Your real ping is &b%ping%&rms. Jitter: &b%jitter%&rms. Spike: &b%spike%&r. Compensated ping: &b%compensated%&rms.");
pingSelfUnavailableMessage = configWrapper.getString("messages.ping.self.unavailable",
"Accurate ping unavailable. Your estimated ping is &b%ping%&rms.");
pingOtherAvailableMessage = configWrapper.getString("messages.ping.other.available",
"%player%'s real ping is &b%ping%&rms. Jitter: &b%jitter%&rms. Spike: &b%spike%&r. Compensated ping: &b%compensated%&rms.");
pingOtherUnavailableMessage = configWrapper.getString("messages.ping.other.unavailable",
"Accurate ping unavailable. %player%'s estimated ping is &b%ping%&rms.");
mustSpecifyPlayerFromConsoleMessage = configWrapper.getString("messages.console.must_specify_player",
"&cYou must specify a player to use the knockbacksync ping command from the console.");
knockbacksyncDisabledForYouMessage = configWrapper.getString("messages.disabled.self",
"&cKnockback synchronization is currently disabled for you!");
knockbacksyncDisabledForTargetMessage = configWrapper.getString("messages.disabled.target",
"&cKnockback synchronization is currently disabled for the target player.");
}
private String getPingMessage(UUID senderUUID, UUID targetUUID) {
PlayerData playerData = null;
boolean isSelf = senderUUID.equals(targetUUID) || targetUUID == null;
if (senderUUID == null) {
senderUUID = targetUUID;
}
if (isSelf) {
playerData = PlayerDataManager.getPlayerData(senderUUID);
if (playerData == null) {
return ChatUtil.translateAlternateColorCodes('&', knockbacksyncDisabledForYouMessage);
}
} else {
playerData = PlayerDataManager.getPlayerData(targetUUID);
if (playerData == null) {
return ChatUtil.translateAlternateColorCodes('&', knockbacksyncDisabledForTargetMessage);
}
}
String rawReturnString;
if (playerData.getPing() == null) {
rawReturnString = isSelf ? pingSelfUnavailableMessage : pingOtherUnavailableMessage;
} else {
rawReturnString = isSelf ? pingSelfAvailableMessage : pingOtherAvailableMessage;
}
rawReturnString = rawReturnString
.replace("%player%", playerData.getPlatformPlayer().getName())
.replace("%ping%", playerData.getPing() == null ?
String.valueOf(playerData.getPlatformPlayer().getPing()) :
String.format("%.3f", playerData.getPing()))
.replace("%jitter%", String.format("%.3f", playerData.getJitter()))
.replace("%spike%", String.valueOf(playerData.isSpike()))
.replace("%compensated%", String.format("%.3f", playerData.getCompensatedPing()));
return ChatUtil.translateAlternateColorCodes('&', rawReturnString);
}
@KBSyncEventHandler
public void onConfigReload(ConfigReloadEvent event) {
loadConfig();
}
}
@@ -15,7 +15,7 @@ import java.util.function.Predicate;
public class ReloadCommand implements BuilderCommand {
private final ConfigManager configManager = Base.INSTANCE.getConfigManager();
private String rawReloadMessage = configManager.getConfigWrapper().getString("reload_message", "&aSuccessfully reloaded KnockbackSync.");
private String rawReloadMessage = configManager.getConfigWrapper().getString("messages.reload.success", "&aSuccessfully reloaded KnockbackSync.");
public void register(CommandManager<Sender> manager) {
manager.command(
@@ -40,11 +40,11 @@ public class ReloadCommand implements BuilderCommand {
context.sender().sendMessage(reloadMessage);
})
);
Base.INSTANCE.getSimpleEventBus().registerListeners(this);
Base.INSTANCE.getEventBus().registerListeners(this);
}
@KBSyncEventHandler
public void onConfigReload(ConfigReloadEvent event) {
rawReloadMessage = event.getConfigManager().getConfigWrapper().getString("reload_message", "&aSuccessfully reloaded KnockbackSync.");
rawReloadMessage = event.getConfigManager().getConfigWrapper().getString("messages.reload.success", "&aSuccessfully reloaded KnockbackSync.");
}
}
@@ -23,9 +23,15 @@ 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;
private String globalStatusEnabledMessage;
private String globalStatusDisabledMessage;
private String globalOffGroundStatusEnabledMessage;
private String globalOffGroundStatusDisabledMessage;
private String playerStatusEnabledMessage;
private String playerStatusDisabledMessage;
private String playerStatusGlobalDisabledMessage;
private String noSelfPermissionMessage;
private String noOtherPermissionMessage;
public StatusCommand() {
updateConfigValues();
@@ -49,30 +55,33 @@ public class StatusCommand implements BuilderCommand {
if (targetSelector == null) {
// Show global status
boolean globalStatus = configManager.isToggled();
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', globalStatusMessage) +
(globalStatus
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled")));
sender.sendMessage(
ChatUtil.translateAlternateColorCodes('&',
(globalStatus ? globalStatusEnabledMessage : globalStatusDisabledMessage))
+ "\n"
+ ChatUtil.translateAlternateColorCodes('&',
globalStatus ? globalOffGroundStatusEnabledMessage : globalOffGroundStatusDisabledMessage)
);
if (sender.hasPermission(STATUS_SELF_PERMISSION, true)) {
// Show player status for the sender (no target specified)
if (!sender.isConsole()) {
showPlayerStatus(sender, Base.INSTANCE.platformServer.getPlayer(sender.getUniqueId()));
showPlayerStatus(sender, Base.INSTANCE.getPlatformServer().getPlayer(sender.getUniqueId()));
}
} else {
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou do not have permisssion to check your knockbacksync status."));
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', noSelfPermissionMessage));
}
} else {
if (sender.hasPermission(STATUS_OTHER_PERMISSION, true)) {
PlatformPlayer target = targetSelector.getSinglePlayer();
showPlayerStatus(sender, target);
} else {
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou do not have permission to check the status of other players!"));
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', noOtherPermissionMessage));
}
}
})
);
Base.INSTANCE.getSimpleEventBus().registerListeners(this);
Base.INSTANCE.getEventBus().registerListeners(this);
}
private void showPlayerStatus(Sender sender, PlatformPlayer target) {
@@ -80,16 +89,13 @@ public class StatusCommand implements BuilderCommand {
UUID uuid = target.getUUID();
boolean playerStatus = PlayerDataManager.containsPlayerData(uuid);
String statusMessage = ChatUtil.translateAlternateColorCodes('&', playerStatusMessage.replace("%player%", target.getName()));
String statusMessage;
if (!globalStatus) {
sender.sendMessage(statusMessage + ChatUtil.translateAlternateColorCodes('&', playerDisabledGlobalMessage));
statusMessage = playerStatusGlobalDisabledMessage.replace("%player%", target.getName());
} else {
sender.sendMessage(statusMessage +
(playerStatus
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled")));
statusMessage = (playerStatus ? this.playerStatusEnabledMessage : this.playerStatusDisabledMessage).replace("%player%", target.getName());
}
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', statusMessage));
}
@KBSyncEventHandler
@@ -99,8 +105,23 @@ public class StatusCommand implements BuilderCommand {
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)");
this.globalStatusEnabledMessage = config.getString("messages.status.global.enabled",
"&eKnockbackSync global status: &aEnabled");
this.globalStatusDisabledMessage = config.getString("messages.status.global.disabled",
"&eKnockbackSync global status: &cDisabled");
this.globalOffGroundStatusEnabledMessage = config.getString("messages.status.offground.enabled",
"&eKnockbackSync off-ground status: &aEnabled");
this.globalOffGroundStatusDisabledMessage = config.getString("messages.status.offground.disabled",
"&eKnockbackSync off-ground status: &cDisabled");
this.playerStatusEnabledMessage = config.getString("messages.status.player.enabled",
"&e%player%'s KnockbackSync status: &aEnabled");
this.playerStatusDisabledMessage = config.getString("messages.status.player.disabled",
"&e%player%'s KnockbackSync status: &cDisabled");
this.playerStatusGlobalDisabledMessage = config.getString("messages.status.player.global_disabled",
"&e%player%'s KnockbackSync status: &cDisabled (Global toggle is off)");
this.noSelfPermissionMessage = config.getString("messages.status.permission.no_self",
"&cYou do not have permission to check your knockbacksync status.");
this.noOtherPermissionMessage = config.getString("messages.status.permission.no_other",
"&cYou do not have permission to check the status of other players!");
}
}
@@ -1,5 +1,6 @@
package me.caseload.knockbacksync.command.subcommand;
import me.caseload.knockbacksync.Base;
import me.caseload.knockbacksync.ConfigWrapper;
import me.caseload.knockbacksync.command.generic.BuilderCommand;
import me.caseload.knockbacksync.command.generic.PlayerSelector;
import me.caseload.knockbacksync.event.events.ToggleOnOffEvent;
@@ -24,6 +25,26 @@ public class ToggleCommand implements BuilderCommand {
private static final String TOGGLE_SELF_PERMISSION = "knockbacksync.toggle.self";
private static final String TOGGLE_OTHER_PERMISSION = "knockbacksync.toggle.other";
private String noGlobalPermissionMessage;
private String noSelfPermissionMessage;
private String noOtherPermissionMessage;
private String serverDisabledMessage;
public ToggleCommand() {
loadConfig();
}
private void loadConfig() {
ConfigWrapper configWrapper = configManager.getConfigWrapper();
noGlobalPermissionMessage = configWrapper.getString("messages.toggle.permission.no_global",
"&cYou don't have permission to toggle the global setting.");
noSelfPermissionMessage = configWrapper.getString("messages.toggle.permission.no_self",
"&cYou do not have permission to toggle your knockback.");
noOtherPermissionMessage = configWrapper.getString("messages.toggle.permission.no_other",
"&cYou do not have permission to toggle the knockback of other player's.");
serverDisabledMessage = configWrapper.getString("messages.toggle.server_disabled",
"&cKnockbacksync is currently disabled on this server. Contact your server administrator for more information.");
}
@Override
public void register(CommandManager<Sender> manager) {
@@ -48,21 +69,21 @@ public class ToggleCommand implements BuilderCommand {
if (permissionChecker.hasPermission(sender, TOGGLE_GLOBAL_PERMISSION, false)) {
toggleGlobalKnockback(configManager, sender);
} else {
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou don't have permission to toggle the global setting."));
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', noGlobalPermissionMessage));
}
} else {
PlatformPlayer target = targetSelector.getSinglePlayer();
boolean senderIsTarget = sender.getUniqueId() == target.getUUID();
if (!senderIsTarget && !permissionChecker.hasPermission(sender, TOGGLE_OTHER_PERMISSION, false)) {
sender.sendMessage("You do not have permission to toggle the knockback of other player's.");
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', noOtherPermissionMessage));
return;
} else if (senderIsTarget && !permissionChecker.hasPermission(sender, TOGGLE_SELF_PERMISSION, true)) {
sender.sendMessage("You do not have permission to toggle your knockback.");
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', noSelfPermissionMessage));
return;
}
if (!configManager.isToggled()) {
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cKnockbacksync is currently disabled on this server. Contact your server administrator for more information."));
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', serverDisabledMessage));
} else {
togglePlayerKnockback(target, configManager, sender);
}
@@ -107,7 +128,7 @@ public class ToggleCommand implements BuilderCommand {
if (hasPlayerData)
PlayerDataManager.removePlayerData(uuid);
else {
PlayerDataManager.addPlayerData(uuid, new PlayerData(Base.INSTANCE.platformServer.getPlayer(uuid)));
PlayerDataManager.addPlayerData(uuid, new PlayerData(Base.INSTANCE.getPlatformServer().getPlayer(uuid)));
}
String message = ChatUtil.translateAlternateColorCodes('&',
@@ -15,9 +15,9 @@ import java.util.function.Predicate;
public class ToggleOffGroundSubcommand implements BuilderCommand {
private String enableOffGroundSyncMessage;
private String disableOffGroundSyncMessage;
private boolean offGroundSyncEnabled;
public static boolean offGroundSyncEnabled = true;
private String offGroundSyncEnableMessage;
private String offGroundSyncDisableMessage;
public ToggleOffGroundSubcommand() {
loadConfigSettings();
@@ -36,11 +36,11 @@ public class ToggleOffGroundSubcommand implements BuilderCommand {
return PredicatePermission.of(senderPredicate).testPermission(sender);
}))
.handler(commandContext -> {
boolean toggledState = !offGroundSyncEnabled;
Base.INSTANCE.getConfigManager().getConfigWrapper().set("enable_offground_synchronization", toggledState);
offGroundSyncEnabled = !offGroundSyncEnabled;
Base.INSTANCE.getConfigManager().getConfigWrapper().set("enable_offground_synchronization", offGroundSyncEnabled);
Base.INSTANCE.getConfigManager().saveConfig();
String message = ChatUtil.translateAlternateColorCodes('&',
toggledState ? enableOffGroundSyncMessage : disableOffGroundSyncMessage);
offGroundSyncEnabled ? offGroundSyncEnableMessage : offGroundSyncDisableMessage);
commandContext.sender().sendMessage(message);
}));
}
@@ -52,8 +52,10 @@ public class ToggleOffGroundSubcommand implements BuilderCommand {
private void loadConfigSettings() {
ConfigWrapper configWrapper = Base.INSTANCE.getConfigManager().getConfigWrapper();
offGroundSyncEnabled = configWrapper.getBoolean("enable_offground_synchronization", false);
enableOffGroundSyncMessage = configWrapper.getString("enable_offground_synchronization_message", "&aSuccessfully enabled offground experiment.");
disableOffGroundSyncMessage = configWrapper.getString("disable_offground_synchronization_message", "&cSuccessfully disabled offground experiment.");
offGroundSyncEnabled = configWrapper.getBoolean("settings.offground.enabled", true);
this.offGroundSyncEnableMessage = configWrapper.getString("messages.offground.enable",
"&aSuccessfully enabled offground synchronization.");
this.offGroundSyncDisableMessage = configWrapper.getString("messages.offground.disable",
"&cSuccessfully disabled offground synchronization.");
}
}
@@ -40,6 +40,8 @@ public abstract class PlayerKnockbackListener {
Vector3d adjustedVelocity;
if (victimPlayerData.isOnGroundClientSide(velocity.getY(), distanceToGround))
adjustedVelocity = velocity.withY(victimPlayerData.getVerticalVelocity()); // Should be impossible to produce a NPE in this context
// Todo FIX
// This can be spoofed! Clients can just say they're onGround to take less KB!
else if (victimPlayerData.isOffGroundSyncEnabled())
adjustedVelocity = velocity.withY(victimPlayerData.getCompensatedOffGroundVelocity());
else
@@ -0,0 +1,37 @@
package me.caseload.knockbacksync.listener.packetevents;
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPluginMessage;
import me.caseload.knockbacksync.Base;
public class ClientBrandListener extends PacketListenerAbstract {
String brand = "vanilla";
boolean hasBrand = false;
@Override
public void onPacketReceive(final PacketReceiveEvent event) {
if (event.getPacketType() == PacketType.Play.Client.PLUGIN_MESSAGE) {
WrapperPlayClientPluginMessage packet = new WrapperPlayClientPluginMessage(event);
String channelName = packet.getChannelName();
handle(channelName, packet.getData());
Base.INSTANCE.getPlatformServer().getPlayer(event.getUser().getUUID()).setClientBrand(brand);
}
}
public void handle(String channel, byte[] data) {
if (channel.equalsIgnoreCase("minecraft:brand") || // 1.13+
channel.equals("MC|Brand")) { // 1.12
if (data.length > 64 || data.length == 0) {
brand = "sent " + data.length + " bytes as brand";
} else if (!hasBrand) {
byte[] minusLength = new byte[data.length - 1];
System.arraycopy(data, 1, minusLength, 0, minusLength.length);
brand = new String(minusLength).replace(" (Velocity)", ""); //removes velocity's brand suffix
}
hasBrand = true;
}
}
}
@@ -19,7 +19,7 @@ import java.util.Map;
@Setter
public class ConfigManager {
public static final long CONFIG_VERSION = 4;
public static final long CONFIG_VERSION = 6;
private boolean toggled;
private boolean runnableEnabled;
@@ -105,7 +105,7 @@ public class ConfigManager {
long initialDelay = 0L;
long pingTaskRunnableInterval = runnableInterval;
// Folia does not allow 0 ticks of wait time
if (Base.INSTANCE.platform == Platform.FOLIA) {
if (Base.INSTANCE.getPlatform() == Platform.FOLIA) {
initialDelay = 1L;
pingTaskRunnableInterval = Math.max(pingTaskRunnableInterval, 1L);
}
@@ -115,11 +115,11 @@ public class ConfigManager {
notifyUpdate = configWrapper.getBoolean("notify_updates", true);
combatTimer = configWrapper.getLong("runnable.timer", 30L);
spikeThreshold = configWrapper.getLong("spike_threshold", 20L);
enableMessage = configWrapper.getString("enable_message", "&aSuccessfully enabled KnockbackSync.");
disableMessage = configWrapper.getString("disable_message", "&cSuccessfully disabled KnockbackSync.");
playerEnableMessage = configWrapper.getString("player_enable_message", "&aSuccessfully enabled KnockbackSync for %player%.");
playerDisableMessage = configWrapper.getString("player_disable_message", "&cSuccessfully disabled KnockbackSync for %player%.");
playerIneligibleMessage = configWrapper.getString("player_ineligible_message", "&c%player% is ineligible for KnockbackSync. If you believe this is in error, please contact your server administrators.");
enableMessage = configWrapper.getString("messages.toggle.global.enable", "&aSuccessfully enabled KnockbackSync.");
disableMessage = configWrapper.getString("messages.toggle.global.disable", "&cSuccessfully disabled KnockbackSync.");
playerEnableMessage = configWrapper.getString("messages.toggle.player.enable", "&aSuccessfully enabled KnockbackSync for %player%.");
playerDisableMessage = configWrapper.getString("messages.toggle.player.disable", "&aSuccessfully &cdisabled &aKnockbackSync for %player%.");
playerIneligibleMessage = configWrapper.getString("messages.toggle.player.ineligible", "&c%player% is ineligible for KnockbackSync. If you believe this is in error, please contact your server administrators.");
}
public void updateConfig() {
@@ -21,14 +21,14 @@ public class PlayerDataManager {
public static void addPlayerData(@NotNull UUID uuid, @NotNull PlayerData playerData) {
if (!shouldExempt(uuid)) {
playerDataMap.put(uuid, playerData);
Base.INSTANCE.getSimpleEventBus().registerListeners(playerData);
Base.INSTANCE.getEventBus().registerListeners(playerData);
}
}
public static void removePlayerData(@NotNull UUID uuid) {
PlayerData playerData = playerDataMap.remove(uuid);
if (playerData != null)
Base.INSTANCE.getSimpleEventBus().unregisterListeners(playerData);
Base.INSTANCE.getEventBus().unregisterListeners(playerData);
}
public static boolean containsPlayerData(@NotNull UUID uuid) {
@@ -1,5 +1,6 @@
package me.caseload.knockbacksync.player;
import com.github.retrooper.packetevents.protocol.player.User;
import com.github.retrooper.packetevents.protocol.world.BoundingBox;
import com.github.retrooper.packetevents.util.Vector3d;
import me.caseload.knockbacksync.world.PlatformWorld;
@@ -50,5 +51,11 @@ public interface PlatformPlayer {
double getJumpPower();
BoundingBox getBoundingBox();
User getUser();
void setClientBrand(String brand);
String getClientBrand();
// Add more methods as needed
}
@@ -18,6 +18,7 @@ import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerWi
import lombok.Getter;
import lombok.Setter;
import me.caseload.knockbacksync.Base;
import me.caseload.knockbacksync.command.subcommand.ToggleOffGroundSubcommand;
import me.caseload.knockbacksync.event.KBSyncEventHandler;
import me.caseload.knockbacksync.event.events.ConfigReloadEvent;
import me.caseload.knockbacksync.event.events.ToggleOnOffEvent;
@@ -32,24 +33,29 @@ import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;
@Getter
public class PlayerData {
// Please read the GitHub FAQ before adjusting.
private static final short MAIN_THREAD_TRANSACTION_ID = 31407;
private static final short NETTY_THREAD_TRANSACTION_ID = 31408;
public static final long PING_OFFSET = 25;
public static float TICK_RATE = 20.0F;
private static Field playerField;
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 = 31407;
private static final short NETTY_THREAD_TRANSACTION_ID = 31408;
private static Object grimPlayerDataManager = null;
private static Method getGrimPlayerFromUserMethod = null;
static {
try {
switch (Base.INSTANCE.platform) {
switch (Base.INSTANCE.getPlatform()) {
case BUKKIT:
case FOLIA:
Class<?> bukkitPlayerClass = Class.forName("me.caseload.knockbacksync.player.BukkitPlayer");
@@ -60,12 +66,26 @@ public class PlayerData {
playerField = fabricPlayerClass.getDeclaredField("fabricPlayer");
break;
default:
throw new IllegalStateException("Unexpected platform: " + Base.INSTANCE.platform);
throw new IllegalStateException("Unexpected platform: " + Base.INSTANCE.getPlatform());
}
} catch (Exception e) {
playerField.setAccessible(true);
// Step 1: Get the GrimAPI enum class dynamically
Class<?> grimAPIClass = Class.forName("ac.grim.grimac.GrimAPI");
// Step 2: Access the INSTANCE of GrimAPI (it's a singleton enum)
Object grimAPIInstance = Enum.valueOf((Class<? extends Enum>) grimAPIClass, "INSTANCE");
// Step 3: Get the PlayerDataManager instance
Method getPlayerDataManagerMethod = grimAPIClass.getDeclaredMethod("getPlayerDataManager");
grimPlayerDataManager = getPlayerDataManagerMethod.invoke(grimAPIInstance);
// Step 4: Get the getPlayer method from PlayerDataManager
Class<?> playerDataManagerClass = grimPlayerDataManager.getClass();
getGrimPlayerFromUserMethod = playerDataManagerClass.getDeclaredMethod("getPlayer", Class.forName("org.bukkit.entity.Player"));
} catch (ClassNotFoundException | NoSuchMethodException | IllegalAccessException | InvocationTargetException | NoSuchFieldException e) {
e.printStackTrace();
}
playerField.setAccessible(true); // May not be needed since it's already public
}
public final User user;
@@ -81,7 +101,6 @@ public class PlayerData {
@Nullable @Setter private Integer lastDamageTicks;
@Setter private double gravityAttribute = 0.08;
@Setter private double knockbackResistanceAttribute = 0.0;
private boolean offGroundSyncEnabled;
public PlayerData(PlatformPlayer platformPlayer) {
this.uuid = platformPlayer.getUUID();
@@ -102,8 +121,6 @@ public class PlayerData {
}
this.user = tempUser;
this.offGroundSyncEnabled = Base.INSTANCE.getConfigManager().getConfigWrapper().getBoolean("enable_offground_synchronization",
true);
}
public double getNotNullPing() {
@@ -130,11 +147,11 @@ public class PlayerData {
}
public int getCompensatedTicks() {
return (int) Math.ceil(getCompensatedPing() * TICK_RATE / 1000); // Multiply ping by seconds per tick
return (int) Math.ceil(getCompensatedPing() * Base.INSTANCE.getTickRate() / 1000); // Multiply ping by seconds per tick
}
public int getTicks() {
return (int) Math.ceil(getNotNullPing() * TICK_RATE / 1000); // Multiply ping by seconds per tick
return (int) Math.ceil(getNotNullPing() * Base.INSTANCE.getTickRate() / 1000); // Multiply ping by seconds per tick
}
public boolean isSpike() {
@@ -197,17 +214,35 @@ public class PlayerData {
* @return <code>true</code> if the Player is on the ground; <code>false</code> otherwise.
*/
public boolean isOnGroundClientSide(double verticalVelocity, double distanceToGround) {
try {
if (getGrimPlayerFromUserMethod != null) {
// Step 5: Invoke getPlayer to get PlayerData
Object playerData = getGrimPlayerFromUserMethod.invoke(grimPlayerDataManager, playerField.get(platformPlayer));
// Step 6: Access the 'onGround' field in PlayerData
Field onGroundField = playerData.getClass().getDeclaredField("onGround");
onGroundField.setAccessible(true); // Bypass private access
System.out.println(this.platformPlayer.getName() + " is located at " + platformPlayer.getX() + ", " + platformPlayer.getY() + ", " + platformPlayer.getZ() + " serverside");
System.out.println("Grim onGround for player " + this.platformPlayer.getName() + " is " + onGroundField.get(playerData));
// Step 7: Get the value of the 'onGround' field
return (boolean) onGroundField.get(playerData);
}
} catch (NoSuchFieldException | IllegalAccessException | InvocationTargetException e) {
throw new RuntimeException(e);
}
int tMax = verticalVelocity > 0 ? MathUtil.calculateTimeToMaxVelocity(verticalVelocity, gravityAttribute) : 0;
if (tMax == -1)
return false; // reached the max tick limit, not safe to predict
if (tMax == -1)
return false; // reached the max tick limit, not safe to predict
double mH = verticalVelocity > 0 ? MathUtil.calculateDistanceTraveled(verticalVelocity, tMax, gravityAttribute) : 0;
int tFall = MathUtil.calculateFallTime(verticalVelocity, mH + distanceToGround, gravityAttribute);
double mH = verticalVelocity > 0 ? MathUtil.calculateDistanceTraveled(verticalVelocity, tMax, gravityAttribute) : 0;
int tFall = MathUtil.calculateFallTime(verticalVelocity, mH + distanceToGround, gravityAttribute);
if (tFall == -1)
return false; // reached the max tick limit, not safe to predict
if (tFall == -1)
return false; // reached the max tick limit, not safe to predict
return (tMax + tFall) - getCompensatedTicks() <= 0 && distanceToGround <= 1.3;
return (tMax + tFall) - getCompensatedTicks() <= 0 && distanceToGround <= 1.3;
}
/**
@@ -216,7 +251,7 @@ public class PlayerData {
*/
public boolean isOffGroundSyncEnabled() {
// TODO, per-player offground sync toggles?
return offGroundSyncEnabled;
return ToggleOffGroundSubcommand.offGroundSyncEnabled;
}
/**
@@ -344,10 +379,4 @@ public class PlayerData {
keepaliveMap.clear();
}
}
@KBSyncEventHandler
public void onConfigReloadEvent(ConfigReloadEvent event) {
this.offGroundSyncEnabled = Base.INSTANCE.getConfigManager().getConfigWrapper().getBoolean("enable_offground_synchronization",
true);
}
}
@@ -0,0 +1,31 @@
package me.caseload.knockbacksync.stats.custom;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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.stats.AdvancedPie;
import java.util.HashMap;
import java.util.Map;
public class ClientBrandsPie extends AdvancedPie {
// Gets the client versions of players online
public ClientBrandsPie() {
super("client_brands", () -> {
Map<String, Integer> valueMap = new HashMap<>();
for (PlatformPlayer player : Base.INSTANCE.getPlatformServer().getOnlinePlayers()) {
User user = player.getUser();
if (user == null || user.getClientVersion() == null) {
valueMap.put("vanilla", valueMap.getOrDefault("vanilla", 0) + 1);
} else {
valueMap.put(player.getClientBrand(), valueMap.getOrDefault(player.getClientBrand(), 0) + 1);
}
}
return valueMap;
});
}
}
@@ -1,5 +1,9 @@
package me.caseload.knockbacksync.stats.custom;
import me.caseload.knockbacksync.stats.CustomChart;
public interface Metrics {
void addCustomChart(CustomChart chart);
void shutdown();
}
@@ -1,5 +1,7 @@
package me.caseload.knockbacksync.stats.custom;
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
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;
@@ -15,9 +17,13 @@ public class PlayerVersionsPie extends AdvancedPie {
public PlayerVersionsPie() {
super("player_version", () -> {
Map<String, Integer> valueMap = new HashMap<>();
for (PlatformPlayer player : Base.INSTANCE.platformServer.getOnlinePlayers()) {
PlayerData playerData = PlayerDataManager.getPlayerData(player.getUUID());
valueMap.put(playerData.getClientVersion().toString(), valueMap.getOrDefault(playerData.getClientVersion().toString(), 0) + 1);
for (PlatformPlayer player : Base.INSTANCE.getPlatformServer().getOnlinePlayers()) {
User user = player.getUser();
if (user == null || user.getClientVersion() == null) {
valueMap.put(ClientVersion.UNKNOWN.toString(), valueMap.getOrDefault(ClientVersion.UNKNOWN.toString(), 0) + 1);
} else {
valueMap.put(user.getClientVersion().toString(), valueMap.getOrDefault(user.getClientVersion().toString(), 0) + 1);
}
}
return valueMap;
});
@@ -1,13 +1,23 @@
package me.caseload.knockbacksync.stats.custom;
import lombok.Getter;
import me.caseload.knockbacksync.Base;
@Getter
public abstract class StatsManager {
Metrics metrics;
public StatsManager(Metrics metrics) {
this.metrics = metrics;
}
public void init() {
throw new IllegalStateException("Empty stats class!");
Base.INSTANCE.getScheduler().runTaskAsynchronously(() -> {
BuildTypePie.determineBuildType(); // Function to calculate hash
metrics.addCustomChart(new PlayerVersionsPie());
metrics.addCustomChart(new BuildTypePie());
metrics.addCustomChart(new ClientBrandsPie());
});
}
}
@@ -1,13 +1,10 @@
package me.caseload.knockbacksync.util;
import com.google.common.base.Preconditions;
import me.caseload.knockbacksync.manager.PlayerDataManager;
import me.caseload.knockbacksync.player.PlayerData;
import org.jetbrains.annotations.NotNull;
import java.util.UUID;
public class ChatUtil {
public static @NotNull String translateAlternateColorCodes(char altColorChar, @NotNull String textToTranslate) {
Preconditions.checkArgument(textToTranslate != null, "Cannot translate null text");
char[] b = textToTranslate.toCharArray();
@@ -21,35 +18,4 @@ public class ChatUtil {
return new String(b);
}
public static String getPingMessage(UUID senderUUID, UUID targetUUID) {
String noun = "";
PlayerData playerData = null;
if (senderUUID == null) {
senderUUID = targetUUID;
}
if (senderUUID.equals(targetUUID) || targetUUID == null) {
playerData = PlayerDataManager.getPlayerData(senderUUID);
if (playerData == null) {
return ChatUtil.translateAlternateColorCodes('&', "&cKnockback synchronization is currently disabled for you!");
}
noun = "Your";
} else {
playerData = PlayerDataManager.getPlayerData(targetUUID);
if (playerData == null) {
return ChatUtil.translateAlternateColorCodes('&', "&cKnockback synchronization is currently disabled for the target player.");
}
noun = playerData.getPlatformPlayer().getName() + "'s";
}
String rawReturnString = null;
if (playerData.getPing() == null) {
rawReturnString = String.format("Accurate ping unavailable. %s estimated ping is &b" + playerData.getPlatformPlayer().getPing() + "&rms.", noun);
} else {
rawReturnString = String.format("%s real ping is &b%.3f&rms. Jitter: &b%.3f&rms. Spike: &b%s&r. Compensated ping: &b%.3f&rms.", noun, playerData.getPing(), playerData.getJitter(), playerData.isSpike(), playerData.getCompensatedPing());
}
return ChatUtil.translateAlternateColorCodes('&', rawReturnString);
}
}
@@ -19,7 +19,7 @@ public class GeyserUtil {
public static boolean isGeyserPlayer(UUID uuid) {
if (!CHECKED_FOR_GEYSER) {
try {
switch (Base.INSTANCE.platform) {
switch (Base.INSTANCE.getPlatform()) {
case BUKKIT:
case FOLIA:
ClassLoader classLoader = PacketEvents.getAPI().getPlugin().getClass().getClassLoader();
@@ -40,7 +40,7 @@ public class GeyserUtil {
if (GEYSER_PRESENT) {
if (GEYSER_API_CLASS == null) {
try {
switch (Base.INSTANCE.platform) {
switch (Base.INSTANCE.getPlatform()) {
case BUKKIT:
case FOLIA:
ClassLoader classLoader = PacketEvents.getAPI().getPlugin().getClass().getClassLoader();
@@ -2,7 +2,7 @@ package me.caseload.knockbacksync.util;
import me.caseload.knockbacksync.player.PlayerData;
import static me.caseload.knockbacksync.player.PlayerData.TICK_RATE;
import me.caseload.knockbacksync.Base;
public class MathUtil {
+54 -14
View File
@@ -3,7 +3,7 @@
#########################################
# Do not modify!
config_version: 5
config_version: 6
# Plugin enabled state
# Toggleable using /knockbacksync toggle
@@ -41,23 +41,11 @@ ping_strategy: "KEEPALIVE"
# Whether to try to detect when player is offground and apply less kb
enable_offground_synchronization: true
enable_message: "&aSuccessfully enabled KnockbackSync."
disable_message: "&cSuccessfully disabled KnockbackSync."
player_enable_message: "&aSuccessfully enabled KnockbackSync for %player%."
player_disable_message: "&aSuccessfully &cdisabled &aKnockbackSync for %player%."
player_ineligible_message: '&c%player% is ineligible for KnockbackSync. If you believe this is in error, please contact your server administrators.'
reload_message: "&aSuccessfully reloaded KnockbackSync config."
global_status_message: "&eGlobal KnockbackSync status: "
player_status_message: "&e%player%'s KnockbackSync status: "
player_disabled_global_message: "&cDisabled (Global toggle is off)"
enable_offground_synchronization_message: "&aSuccessfully enabled offground synchronization."
disable_offground_synchronization_message: "&cSuccessfully disabled offground synchronization."
# 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
# Such as the Ender Dragon's knockback attacks
# 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
# Currently only modifying the player's tick interval is supported on Bukkit/Spigot/Paper + Folia
# Modifying the tick interval of any entity is supported on Fabric.
@@ -193,3 +181,55 @@ entity_tick_intervals:
zombified_piglin: 3
fishing_bobber: 5
messages:
toggle:
global:
enable: "&aSuccessfully enabled KnockbackSync."
disable: "&cSuccessfully disabled KnockbackSync."
player:
enable: "&aSuccessfully enabled KnockbackSync for %player%."
disable: "&aSuccessfully &cdisabled &aKnockbackSync for %player%."
ineligible: "&c%player% is ineligible for KnockbackSync. If you believe this is in error, please contact your server administrators."
permission:
no_global: "&cYou don't have permission to toggle the global setting."
no_self: "&cYou do not have permission to toggle your knockback."
no_other: "&cYou do not have permission to toggle the knockback of other player's."
self:
enable: "&aSuccessfully enabled KnockbackSync."
disable: "&cSuccessfully disabled KnockbackSync."
other:
enable: "&aSuccessfully enabled KnockbackSync for %player%."
disable: "&aSuccessfully &cdisabled &aKnockbackSync for %player%."
ineligible: "&c%player% is ineligible for KnockbackSync. If you believe this is in error, please contact your server administrators."
server_disabled: "&cKnockbacksync is currently disabled on this server. Contact your server administrator for more information."
offground:
enable: "&aSuccessfully enabled offground synchronization."
disable: "&cSuccessfully disabled offground synchronization."
reload:
success: "&aSuccessfully reloaded KnockbackSync."
status:
global:
enabled: "&eKnockbackSync global status: &aEnabled"
disabled: "&eKnockbackSync global status: &cDisabled"
offground:
enabled: "&eKnockbackSync off-ground status: &aEnabled"
disabled: "&eKnockbackSync off-ground status: &cDisabled"
player:
enabled: "&e%player%'s KnockbackSync status: &aEnabled"
disabled: "&e%player%'s KnockbackSync status: &cDisabled"
global_disabled: "&e%player%'s KnockbackSync status: &cDisabled (Global toggle is off)"
permission:
no_self: "&cYou do not have permission to check your knockbacksync status."
no_other: "&cYou do not have permission to check the status of other players!"
console:
must_specify_player: "&cYou must specify a player to use the knockbacksync ping command from the console."
disabled:
self: "&cKnockback synchronization is currently disabled for you!"
target: "&cKnockback synchronization is currently disabled for the target player."
ping:
self:
unavailable: "Accurate ping unavailable. Your estimated ping is &b%ping%&rms."
available: "Your real ping is &b%ping%&rms. Jitter: &b%jitter%&rms. Spike: &b%spike%&r. Compensated ping: &b%compensated%&rms."
other:
unavailable: "Accurate ping unavailable. %player%'s estimated ping is &b%ping%&rms."
available: "%player%'s real ping is &b%ping%&rms. Jitter: &b%jitter%&rms. Spike: &b%spike%&r. Compensated ping: &b%compensated%&rms."
+1 -1
View File
@@ -42,7 +42,7 @@ dependencies {
modImplementation("net.fabricmc.fabric-api:fabric-api:${rootProject.property("fabric_version")}")
include(modImplementation("me.lucko:fabric-permissions-api:0.3.1")!!)
include(modImplementation("com.github.retrooper:packetevents-fabric:2.5.0")!!)
include(modImplementation("com.github.retrooper:packetevents-fabric:2.6.0-SNAPSHOT")!!)
include(modImplementation("org.incendo:cloud-fabric:2.0.0-beta.9")!!)
include(implementation("org.yaml:snakeyaml:2.0")!!)
@@ -1,7 +1,7 @@
package me.caseload.knockbacksync;
import com.github.retrooper.packetevents.PacketEvents;
import io.github.retrooper.packetevents.factory.fabric.FabricPacketEventsBuilder;
import io.github.retrooper.packetevents.factory.fabric.FabricPacketEventsAPI;
import lombok.Getter;
import me.caseload.knockbacksync.entity.EntityTickManager;
import me.caseload.knockbacksync.listener.fabric.FabricPlayerDamageListener;
@@ -9,7 +9,6 @@ import me.caseload.knockbacksync.listener.fabric.FabricPlayerJoinQuitListener;
import me.caseload.knockbacksync.listener.fabric.FabricPlayerKnockbackListener;
import me.caseload.knockbacksync.listener.fabric.FabricTickRateChangeListener;
import me.caseload.knockbacksync.manager.ConfigManager;
import me.caseload.knockbacksync.mixin.ServerEntityMixin;
import me.caseload.knockbacksync.permission.FabricPermissionChecker;
import me.caseload.knockbacksync.permission.PermissionChecker;
import me.caseload.knockbacksync.scheduler.FabricSchedulerAdapter;
@@ -18,6 +17,7 @@ import me.caseload.knockbacksync.sender.FabricSenderFactory;
import me.caseload.knockbacksync.stats.custom.FabricStatsManager;
import me.caseload.knockbacksync.stats.custom.PluginJarHashProvider;
import me.caseload.knockbacksync.world.FabricServer;
import net.fabricmc.api.EnvType;
import net.fabricmc.loader.api.FabricLoader;
import net.fabricmc.loader.api.ModContainer;
import org.incendo.cloud.execution.ExecutionCoordinator;
@@ -38,6 +38,7 @@ public class FabricBase extends Base {
private final FabricPermissionChecker permissionChecker = new FabricPermissionChecker();
@Getter
private final FabricSenderFactory fabricSenderFactory = new FabricSenderFactory(this);
private float tickRate = 20.0F;
public FabricBase() {
super.configManager = new ConfigManager();
@@ -68,10 +69,15 @@ public class FabricBase extends Base {
@Override
public void load() {
PacketEvents.setAPI(FabricPacketEventsBuilder.build("knockbacksync"));
PacketEvents.setAPI(new FabricPacketEventsAPI("knockbacksync", EnvType.SERVER));
PacketEvents.getAPI().load();
}
@Override
public void enable() {
super.enable();
}
@Override
public void initializeScheduler() {
scheduler = new FabricSchedulerAdapter();
@@ -83,7 +89,7 @@ public class FabricBase extends Base {
new FabricPlayerDamageListener().register();
new FabricPlayerKnockbackListener().register();
new FabricTickRateChangeListener().register();
super.simpleEventBus.registerStaticListeners(EntityTickManager.class);
super.eventBus.registerStaticListeners(EntityTickManager.class);
}
@Override
@@ -112,6 +118,15 @@ public class FabricBase extends Base {
return permissionChecker;
}
@Override
public float getTickRate() {
return this.tickRate;
}
public void setTickRate(float tickRate) {
this.tickRate = tickRate;
}
private URL getJarURL() {
URL jarUrl = null;
Optional<ModContainer> modContainer = FabricLoader.getInstance().getModContainer("knockbacksync");
@@ -1,13 +1,14 @@
package me.caseload.knockbacksync.listener.fabric;
import me.caseload.knockbacksync.Base;
import me.caseload.knockbacksync.FabricBase;
import me.caseload.knockbacksync.callback.TickRateChangeEvent;
import me.caseload.knockbacksync.player.PlayerData;
public class FabricTickRateChangeListener {
public void register() {
TickRateChangeEvent.EVENT.register((oldTickRate, newTickRate) -> {
if (oldTickRate != newTickRate) {
PlayerData.TICK_RATE = newTickRate;
((FabricBase) Base.INSTANCE).setTickRate(newTickRate);
}
});
}
@@ -1,5 +1,7 @@
package me.caseload.knockbacksync.player;
import com.github.retrooper.packetevents.PacketEvents;
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.util.Vector3d;
@@ -25,6 +27,7 @@ import java.util.UUID;
public class FabricPlayer implements PlatformPlayer {
public final ServerPlayer fabricPlayer;
private String clientBrand = "fabric";
public FabricPlayer(ServerPlayer player) {
this.fabricPlayer = player;
@@ -152,5 +155,18 @@ public class FabricPlayer implements PlatformPlayer {
return new BoundingBox(boundingBox.minX, boundingBox.minY, boundingBox.minZ, boundingBox.maxX, boundingBox.minY, boundingBox.maxZ);
}
// Implement other methods
@Override
public User getUser() {
return PacketEvents.getAPI().getPlayerManager().getUser(fabricPlayer);
}
@Override
public void setClientBrand(String brand) {
this.clientBrand = brand;
}
@Override
public String getClientBrand() {
return this.clientBrand;
}
}
@@ -3,14 +3,7 @@ package me.caseload.knockbacksync.stats.custom;
import me.caseload.knockbacksync.Base;
public class FabricStatsManager extends StatsManager {
@Override
public void init() {
Base.INSTANCE.getScheduler().runTaskAsynchronously(() -> {
BuildTypePie.determineBuildType(); // Function to calculate hash
MetricsFabric metrics = new MetricsFabric(23568);
metrics.addCustomChart(new PlayerVersionsPie());
metrics.addCustomChart(new BuildTypePie());
super.metrics = metrics;
});
public FabricStatsManager() {
super(new MetricsFabric(23568));
}
}
+2 -1
View File
@@ -20,7 +20,8 @@
"depends": {
"fabricloader": ">=${loader_version}",
"fabric": "*",
"minecraft": "~${minecraft_version}"
"minecraft": "~${minecraft_version}",
"packetevents": "*"
},
"accessWidener": "knockbacksync.accesswidener"
}