Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
addb077133 | ||
|
|
1fcbd33a62 | ||
|
|
f6e2498722 | ||
|
|
e6367842ed | ||
|
|
380174dade | ||
|
|
dab6b7a85b | ||
|
|
4124c3ade3 | ||
|
|
9abe7259a2 | ||
|
|
79656875c3 | ||
|
|
bc6872d56f | ||
|
|
fb24f31146 | ||
|
|
4df4b6c637 | ||
|
|
c15caa32e3 | ||
|
|
833559eec9 | ||
|
|
c3e6f06b9f | ||
|
|
af39cda3b8 | ||
|
|
98d39570d8 | ||
|
|
be88498fe5 | ||
|
|
1250cc1abc |
No files matched your search
@@ -115,35 +115,53 @@ jobs:
|
||||
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
|
||||
run: |
|
||||
# Download the current dev-builds.txt
|
||||
curl -L -o dev-builds.txt https://github.com/Axionize/knockback-sync/releases/download/hashlist/dev-builds.txt
|
||||
curl -L -o dev-builds.txt https://github.com/CASELOAD7000/knockback-sync/releases/latest/download/dev-builds.txt
|
||||
|
||||
# Ensure the file ends with a newline, then append new information
|
||||
# Create a copy of the original file
|
||||
cp dev-builds.txt dev-builds.txt.original
|
||||
|
||||
# Ensure the file ends with a newline
|
||||
sed -i -e '$a\' dev-builds.txt
|
||||
# echo "KnockBackSync-${{ env.NEW_VERSION }}.jar" >> dev-builds.txt
|
||||
echo "${{ env.ORIGINAL_HASH }}" >> dev-builds.txt
|
||||
# echo "KnockBackSync-${{ env.NEW_VERSION }}-remapped.jar" >> dev-builds.txt
|
||||
echo "${{ env.REMAPPED_HASH }}" >> dev-builds.txt
|
||||
|
||||
echo "${{ env.FABRIC_HASH }}" >> dev-builds.txt
|
||||
# Function to add hash if it doesn't exist
|
||||
add_hash_if_new() {
|
||||
if ! grep -q "$1" dev-builds.txt; then
|
||||
echo "$1" >> dev-builds.txt
|
||||
fi
|
||||
}
|
||||
|
||||
# Get the release ID for the 'hashlist' release
|
||||
RELEASE_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/Axionize/knockback-sync/releases/tags/hashlist" | jq -r .id)
|
||||
# Add new hashes if they don't exist
|
||||
add_hash_if_new "${{ env.ORIGINAL_HASH }}"
|
||||
add_hash_if_new "${{ env.REMAPPED_HASH }}"
|
||||
add_hash_if_new "${{ env.FABRIC_HASH }}"
|
||||
|
||||
# Delete the old dev-builds.txt asset
|
||||
ASSET_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/Axionize/knockback-sync/releases/$RELEASE_ID/assets" | \
|
||||
jq -r '.[] | select(.name == "dev-builds.txt") | .id')
|
||||
if [ ! -z "$ASSET_ID" ]; then
|
||||
curl -X DELETE -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/Axionize/knockback-sync/releases/assets/$ASSET_ID"
|
||||
# Check if the file has changed
|
||||
if cmp -s dev-builds.txt dev-builds.txt.original; then
|
||||
echo "No changes to dev-builds.txt, skipping upload."
|
||||
else
|
||||
echo "Changes detected in dev-builds.txt, uploading new version."
|
||||
|
||||
# Get the latest release ID
|
||||
RELEASE_ID=$(curl -s "https://api.github.com/repos/CASELOAD7000/knockback-sync/releases/latest" | jq -r .id)
|
||||
|
||||
# Delete the old dev-builds.txt asset
|
||||
ASSET_ID=$(curl -s -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/CASELOAD7000/knockback-sync/releases/$RELEASE_ID/assets" | \
|
||||
jq -r '.[] | select(.name == "dev-builds.txt") | .id')
|
||||
if [ ! -z "$ASSET_ID" ]; then
|
||||
curl -X DELETE -H "Authorization: token $GITHUB_TOKEN" \
|
||||
"https://api.github.com/repos/CASELOAD7000/knockback-sync/releases/assets/$ASSET_ID"
|
||||
fi
|
||||
|
||||
# Upload the new dev-builds.txt
|
||||
curl -X POST -H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @dev-builds.txt \
|
||||
"https://uploads.github.com/repos/CASELOAD7000/knockback-sync/releases/$RELEASE_ID/assets?name=dev-builds.txt"
|
||||
fi
|
||||
|
||||
# Upload the new dev-builds.txt
|
||||
curl -X POST -H "Authorization: token $GITHUB_TOKEN" \
|
||||
-H "Content-Type: application/octet-stream" \
|
||||
--data-binary @dev-builds.txt \
|
||||
"https://uploads.github.com/repos/Axionize/knockback-sync/releases/$RELEASE_ID/assets?name=dev-builds.txt"
|
||||
# Clean up
|
||||
rm dev-builds.txt.original
|
||||
|
||||
- name: Create artifacts directory
|
||||
run: mkdir -p artifacts
|
||||
@@ -183,9 +201,10 @@ jobs:
|
||||
spigot
|
||||
paper
|
||||
folia
|
||||
purpur
|
||||
|
||||
game-versions: |
|
||||
>=1.16.5
|
||||
>=1.14.4
|
||||
|
||||
retry-attempts: 2
|
||||
retry-delay: 10000
|
||||
@@ -203,7 +222,7 @@ jobs:
|
||||
|
||||
name: KnockbackSync-${{ env.NEW_VERSION }}
|
||||
version: ${{ env.NEW_VERSION }}
|
||||
version-type: alpha
|
||||
version-type: beta
|
||||
|
||||
loaders: |
|
||||
fabric
|
||||
|
||||
@@ -18,6 +18,7 @@ Official Discord: https://discord.gg/nnpqpAtyVW
|
||||
### How does this change benefit high ping players?
|
||||
**Knockback control.** For example, it will be easier to escape crit chains and punish crit.
|
||||
|
||||
<<<<<<< Updated upstream
|
||||
### How do I change the ping offset?
|
||||
Open up `config.yml` and edit the line that says `ping_offset: 25`. Replace 25 with your desired ping offset.
|
||||
;
|
||||
@@ -26,6 +27,14 @@ Then just type
|
||||
/knockbacksync reload
|
||||
```
|
||||
or restart your server.
|
||||
=======
|
||||
### Why was the configurability of ping offset removed?
|
||||
**It promotes consistency across all servers.** Extensive testing with top players has shown that an offset of 25 provides a balanced experience for everyone.
|
||||
|
||||
### How do I change the ping offset?
|
||||
**You must run a modified build of KnockbackSync.** The variable can be changed inside of the [PlayerData](common/src/main/java/me/caseload/knockbacksync/player/PlayerData.java) class.
|
||||
|
||||
>>>>>>> Stashed changes
|
||||
|
||||
## What servers are using this plugin?
|
||||
| IP | Location | Region | Ping Offset | spike_threshold |
|
||||
@@ -169,4 +178,4 @@ This command reloads the KnockbackSync plugin's configuration file.
|
||||
## License
|
||||
GNU General Public License v3.0 or later
|
||||
|
||||
See [LICENSE](LICENSE) to see the full text.
|
||||
See [LICENSE](https://www.gnu.org/licenses/gpl-3.0.en.html) to see the full text.
|
||||
@@ -52,21 +52,4 @@ subprojects {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
|
||||
// if (project.name != "common") {
|
||||
// tasks.withType<JavaCompile> {
|
||||
// source(project(":common").sourceSets.main.get().allSource)
|
||||
// }
|
||||
// tasks.withType<Javadoc> {
|
||||
// source(project(":common").sourceSets.main.get().allJava)
|
||||
// }
|
||||
|
||||
// tasks.named<Jar>("sourcesJar") {
|
||||
// from(project(":common").sourceSets.main.get().allSource)
|
||||
// }
|
||||
|
||||
// tasks.named<JavaCompile>("compileTestJava") {
|
||||
// exclude("**/*")
|
||||
// }
|
||||
// }
|
||||
}
|
||||
+9
-60
@@ -2,12 +2,8 @@ import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
|
||||
|
||||
plugins {
|
||||
id("com.gradleup.shadow")
|
||||
// id("io.papermc.paperweight.userdev") version "1.7.3"
|
||||
// id("net.neoforged.moddev") version "1.0.11"
|
||||
}
|
||||
|
||||
//paperweight.reobfArtifactConfiguration = io.papermc.paperweight.userdev.ReobfArtifactConfiguration.REOBF_PRODUCTION
|
||||
|
||||
base {
|
||||
archivesName.set("${rootProject.property("archives_base_name")}-bukkit")
|
||||
}
|
||||
@@ -17,23 +13,9 @@ val shadeThisThing: Configuration by configurations.creating {
|
||||
isTransitive = true
|
||||
}
|
||||
|
||||
//sourceSets {
|
||||
// main {
|
||||
// java {
|
||||
// srcDir(project(":common").sourceSets.main.get().java.srcDirs)
|
||||
// }
|
||||
// resources {
|
||||
// srcDir(project(":common").sourceSets.main.get().resources.srcDirs)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO migrate to only including sourceset for compile, test and javadoc tasks
|
||||
// Currently must build with gradle build -x test to skip test
|
||||
// TODO migrate to only including sources sets for compile, test and javadoc tasks
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
source(project(":common").sourceSets.main.get().java.srcDirs)
|
||||
source(project(":common").sourceSets.main.get().resources.srcDirs())
|
||||
options.annotationProcessorPath = configurations["annotationProcessor"] + configurations["compileClasspath"]
|
||||
source(project(":common").sourceSets.main.get().allSource)
|
||||
}
|
||||
|
||||
tasks.withType<Javadoc>().configureEach {
|
||||
@@ -44,60 +26,37 @@ tasks.named<JavaCompile>("compileTestJava") {
|
||||
exclude("**/*")
|
||||
}
|
||||
|
||||
// Dirty hack exists so the build process will finish running
|
||||
//tasks.withType<Test>().configureEach {
|
||||
// classpath += project(":common").sourceSets["main"].output + configurations["compileClasspath"] + configurations["runtimeClasspath"]
|
||||
//}
|
||||
|
||||
|
||||
dependencies {
|
||||
// shadeThisThing(implementation(project(":common"))!!)
|
||||
implementation(project(":common"))
|
||||
|
||||
// paperweight.paperDevBundle("1.16.5-R0.1-SNAPSHOT")
|
||||
// compileOnly("com.mojang:brigadier:1.0.18")
|
||||
compileOnly("org.spigotmc:spigot-api:1.16.5-R0.1-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot-api:1.14.4-R0.1-SNAPSHOT")
|
||||
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
|
||||
// compileOnly("dev.folia:folia-api:1.20.4-R0.1-SNAPSHOT")
|
||||
|
||||
compileOnly("org.projectlombok:lombok:1.18.34")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.34")
|
||||
|
||||
shadeThisThing(implementation("org.kohsuke:github-api:1.326")!!)
|
||||
|
||||
// shadeThisThing(implementation("org.kohsuke:github-api:1.326") {
|
||||
// exclude(group = "commons-io", module = "commons-io")
|
||||
// exclude(group = "org.apache.commons", module = "commons-lang3")
|
||||
// })
|
||||
|
||||
|
||||
shadeThisThing(implementation("com.fasterxml.jackson.core:jackson-databind:2.17.2")!!)
|
||||
shadeThisThing(implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.2")!!)
|
||||
|
||||
shadeThisThing(implementation("com.github.retrooper:packetevents-spigot:2.5.0")!!)
|
||||
shadeThisThing(implementation("dev.jorel:commandapi-bukkit-shade:9.5.3")!!)
|
||||
// shadeThisThing(implementation("net.kyori:adventure-platform-bukkit:4.3.4")!!)
|
||||
shadeThisThing(implementation("org.incendo:cloud-paper:2.0.0-beta.10")!!)
|
||||
shadeThisThing(implementation("org.incendo:cloud-core:2.0.0")!!)
|
||||
|
||||
// Required for 1.14.4 support because gson is too old to have JosnParser.parseString()
|
||||
shadeThisThing(implementation("com.google.code.gson:gson:2.11.0")!!)
|
||||
}
|
||||
|
||||
tasks.withType<ShadowJar> {
|
||||
// Exclude Java 21 specific classes
|
||||
// exclude("META-INF/**")
|
||||
|
||||
// archiveClassifier.set("-all")
|
||||
configurations = listOf(shadeThisThing)
|
||||
isEnableRelocation = true
|
||||
relocationPrefix = "${project.property("maven_group")}.${project.property("archives_base_name")}.shaded"
|
||||
}
|
||||
|
||||
//tasks.named("reobfJar") {
|
||||
// dependsOn(tasks.named("shadowJar"))
|
||||
//}
|
||||
|
||||
tasks.build {
|
||||
// dependsOn(tasks.named("reobfJar"))
|
||||
dependsOn(tasks.shadowJar)
|
||||
}
|
||||
|
||||
|
||||
tasks.processResources {
|
||||
from(project(":common").sourceSets.main.get().resources)
|
||||
inputs.property("version", project.version)
|
||||
@@ -108,14 +67,4 @@ tasks.processResources {
|
||||
"version" to project.version,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
//neoForge {
|
||||
// Look for versions on https://projects.neoforged.net/neoforged/neoform
|
||||
// neoFormVersion.set("1.21-20240613.152323")
|
||||
//}
|
||||
|
||||
java {
|
||||
sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
targetCompatibility = JavaVersion.VERSION_1_8
|
||||
}
|
||||
@@ -0,0 +1,138 @@
|
||||
package me.caseload.knockbacksync;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
import me.caseload.knockbacksync.listener.bukkit.BukkitPlayerDamageListener;
|
||||
import me.caseload.knockbacksync.listener.bukkit.BukkitPlayerJoinQuitListener;
|
||||
import me.caseload.knockbacksync.listener.bukkit.BukkitPlayerKnockbackListener;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
import me.caseload.knockbacksync.permission.PluginPermissionChecker;
|
||||
import me.caseload.knockbacksync.scheduler.BukkitSchedulerAdapter;
|
||||
import me.caseload.knockbacksync.scheduler.FoliaSchedulerAdapter;
|
||||
import me.caseload.knockbacksync.sender.BukkitPlayerSelectorParser;
|
||||
import me.caseload.knockbacksync.sender.BukkitSenderFactory;
|
||||
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.Listener;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
import org.incendo.cloud.bukkit.CloudBukkitCapabilities;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.paper.LegacyPaperCommandManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public class KBSyncBukkitBase extends KnockbackSyncBase {
|
||||
|
||||
private final JavaPlugin plugin;
|
||||
private final BukkitSenderFactory bukkitSenderFactory = new BukkitSenderFactory(this);
|
||||
private final PluginPermissionChecker permissionChecker = new PluginPermissionChecker();
|
||||
|
||||
public KBSyncBukkitBase(JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
super.configManager = new ConfigManager();
|
||||
super.playerSelectorParser = new BukkitPlayerSelectorParser<>();
|
||||
super.statsManager = new BukkitStatsManager();
|
||||
super.platformServer = new BukkitServer();
|
||||
super.pluginJarHashProvider = new PluginJarHashProvider(this.getClass().getProtectionDomain().getCodeSource().getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return this.plugin.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return this.plugin.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResource(String filename) {
|
||||
return this.plugin.getResource(filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(this.plugin));
|
||||
PacketEvents.getAPI().load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
super.enable();
|
||||
initializeScheduler();
|
||||
configManager.loadConfig(false);
|
||||
statsManager.init();
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeScheduler() {
|
||||
switch (platform) {
|
||||
case BUKKIT:
|
||||
super.scheduler = new BukkitSchedulerAdapter(this.plugin);
|
||||
break;
|
||||
case FOLIA:
|
||||
super.scheduler = new FoliaSchedulerAdapter(this.plugin);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerPlatformListeners() {
|
||||
registerPluginListeners(
|
||||
new BukkitPlayerDamageListener(),
|
||||
new BukkitPlayerKnockbackListener(),
|
||||
new BukkitPlayerJoinQuitListener()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerCommands() {
|
||||
super.commandManager = new LegacyPaperCommandManager<>(
|
||||
this.plugin,
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
bukkitSenderFactory
|
||||
);
|
||||
if (commandManager instanceof LegacyPaperCommandManager) {
|
||||
LegacyPaperCommandManager<Sender> legacyPaperCommandManager = (LegacyPaperCommandManager<Sender>) commandManager;
|
||||
if (legacyPaperCommandManager.hasCapability(CloudBukkitCapabilities.NATIVE_BRIGADIER)) {
|
||||
legacyPaperCommandManager.registerBrigadier();
|
||||
} else if (commandManager.hasCapability(CloudBukkitCapabilities.ASYNCHRONOUS_COMPLETION)) {
|
||||
legacyPaperCommandManager.registerAsynchronousCompletions();
|
||||
}
|
||||
}
|
||||
super.registerCommands();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getVersion() {
|
||||
return this.plugin.getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveDefaultConfig() {
|
||||
this.plugin.saveDefaultConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionChecker getPermissionChecker() {
|
||||
return permissionChecker;
|
||||
}
|
||||
|
||||
private void registerPluginListeners(Listener... listeners) {
|
||||
PluginManager pluginManager = this.plugin.getServer().getPluginManager();
|
||||
for (Listener listener : listeners)
|
||||
pluginManager.registerEvents(listener, this.plugin);
|
||||
}
|
||||
|
||||
public BukkitSenderFactory getSenderFactory() {
|
||||
return this.bukkitSenderFactory;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,24 @@
|
||||
package me.caseload.knockbacksync;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
public final class KBSyncBukkitLoaderPlugin extends JavaPlugin {
|
||||
|
||||
private final KnockbackSyncBase core = new KBSyncBukkitBase(this);
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
core.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
core.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
PacketEvents.getAPI().terminate();
|
||||
}
|
||||
}
|
||||
@@ -1,139 +0,0 @@
|
||||
package me.caseload.knockbacksync;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import dev.jorel.commandapi.CommandAPI;
|
||||
import dev.jorel.commandapi.CommandAPIBukkitConfig;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
import me.caseload.knockbacksync.command.bukkit.MainCommand;
|
||||
import me.caseload.knockbacksync.listener.bukkit.BukkitPlayerDamageListener;
|
||||
import me.caseload.knockbacksync.listener.bukkit.BukkitPlayerJoinQuitListener;
|
||||
import me.caseload.knockbacksync.listener.bukkit.BukkitPlayerKnockbackListener;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
import me.caseload.knockbacksync.permission.PluginPermissionChecker;
|
||||
import me.caseload.knockbacksync.scheduler.BukkitSchedulerAdapter;
|
||||
import me.caseload.knockbacksync.scheduler.FoliaSchedulerAdapter;
|
||||
import me.caseload.knockbacksync.stats.custom.BukkitStatsManager;
|
||||
import me.caseload.knockbacksync.stats.custom.PluginJarHashProvider;
|
||||
import me.caseload.knockbacksync.world.BukkitServer;
|
||||
import org.bukkit.event.Listener;
|
||||
import org.bukkit.plugin.PluginManager;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
public final class KnockbackSyncPlugin extends JavaPlugin {
|
||||
|
||||
private final KnockbackSyncBase core = new KnockbackSyncBase() {
|
||||
|
||||
private final PluginPermissionChecker permissionChecker = new PluginPermissionChecker();
|
||||
|
||||
{
|
||||
statsManager = new BukkitStatsManager();
|
||||
platformServer = new BukkitServer();
|
||||
pluginJarHashProvider = new PluginJarHashProvider(this.getClass().getProtectionDomain().getCodeSource().getLocation());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Logger getLogger() {
|
||||
return KnockbackSyncPlugin.this.getLogger();
|
||||
}
|
||||
|
||||
@Override
|
||||
public File getDataFolder() {
|
||||
return KnockbackSyncPlugin.this.getDataFolder();
|
||||
}
|
||||
|
||||
@Override
|
||||
public InputStream getResource(String filename) {
|
||||
return KnockbackSyncPlugin.this.getResource(filename);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void load() {
|
||||
PacketEvents.setAPI(SpigotPacketEventsBuilder.build(KnockbackSyncPlugin.this));
|
||||
PacketEvents.getAPI().load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void enable() {
|
||||
super.enable();
|
||||
initializeScheduler();
|
||||
configManager.loadConfig(false);
|
||||
statsManager.init();
|
||||
checkForUpdates();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializeScheduler() {
|
||||
switch (platform) {
|
||||
case BUKKIT:
|
||||
super.scheduler = new BukkitSchedulerAdapter(KnockbackSyncPlugin.this);
|
||||
break;
|
||||
case FOLIA:
|
||||
super.scheduler = new FoliaSchedulerAdapter(KnockbackSyncPlugin.this);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerPlatformListeners() {
|
||||
registerPluginListeners(
|
||||
new BukkitPlayerDamageListener(),
|
||||
new BukkitPlayerKnockbackListener(),
|
||||
new BukkitPlayerJoinQuitListener()
|
||||
);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerCommands() {
|
||||
new MainCommand().register();
|
||||
// CommandDispatcher dispatcher = Brigadier.getCommandDispatcher();
|
||||
// dispatcher.register(KnockbackSyncCommand.build());
|
||||
// dispatcher.register(
|
||||
// Commands.literal("kbsync")
|
||||
// .redirect(dispatcher.getRoot().getChild("knockbacksync"))
|
||||
// );
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getVersion() {
|
||||
return getDescription().getVersion();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void saveDefaultConfig() {
|
||||
KnockbackSyncPlugin.this.saveDefaultConfig();
|
||||
}
|
||||
|
||||
@Override
|
||||
public PermissionChecker getPermissionChecker() {
|
||||
return permissionChecker;
|
||||
}
|
||||
};
|
||||
|
||||
@Override
|
||||
public void onLoad() {
|
||||
CommandAPI.onLoad(new CommandAPIBukkitConfig(this));
|
||||
core.load();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onEnable() {
|
||||
CommandAPI.onEnable();
|
||||
core.enable();
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onDisable() {
|
||||
CommandAPI.onDisable();
|
||||
PacketEvents.getAPI().terminate();
|
||||
}
|
||||
|
||||
private void registerPluginListeners(Listener... listeners) {
|
||||
PluginManager pluginManager = getServer().getPluginManager();
|
||||
for (Listener listener : listeners)
|
||||
pluginManager.registerEvents(listener, this);
|
||||
}
|
||||
}
|
||||
@@ -1,27 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.bukkit;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import me.caseload.knockbacksync.command.bukkit.subcommand.PingSubcommand;
|
||||
import me.caseload.knockbacksync.command.bukkit.subcommand.ReloadSubcommand;
|
||||
import me.caseload.knockbacksync.command.bukkit.subcommand.StatusSubcommand;
|
||||
import me.caseload.knockbacksync.command.bukkit.subcommand.ToggleSubcommand;
|
||||
import org.bukkit.ChatColor;
|
||||
|
||||
public class MainCommand {
|
||||
|
||||
public void register() {
|
||||
new CommandAPICommand("knockbacksync")
|
||||
.withAliases("kbsync")
|
||||
.withSubcommand(new PingSubcommand().getCommand())
|
||||
.withSubcommand(new ToggleSubcommand().getCommand())
|
||||
.withSubcommand(new ReloadSubcommand().getCommand())
|
||||
.withSubcommand(new StatusSubcommand().getCommand())
|
||||
.executes((sender, args) -> {
|
||||
sender.sendMessage(ChatColor.translateAlternateColorCodes(
|
||||
'&',
|
||||
"&6This server is running the &eKnockbackSync &6plugin. &bhttps://github.com/CASELOAD7000/knockback-sync"
|
||||
));
|
||||
})
|
||||
.register();
|
||||
}
|
||||
}
|
||||
-37
@@ -1,37 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.bukkit.subcommand;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.arguments.PlayerArgument;
|
||||
import me.caseload.knockbacksync.command.PlatformSender;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.player.PlayerData;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PingSubcommand {
|
||||
|
||||
public CommandAPICommand getCommand() {
|
||||
return new CommandAPICommand("ping")
|
||||
.withPermission("knockbacksync.ping")
|
||||
.withOptionalArguments(new PlayerArgument("target"))
|
||||
.executes((sender, args) -> {
|
||||
Player target = (Player) args.get("target");
|
||||
if (target == null) {
|
||||
if (sender instanceof ConsoleCommandSender) {
|
||||
sender.sendMessage(ChatColor.RED + "You must specify a player to use this command from the console.");
|
||||
} else if (sender instanceof Player) {
|
||||
sender.sendMessage(ChatUtil.getPingMessage(((Player) sender).getUniqueId(), null));
|
||||
}
|
||||
} else {
|
||||
if (sender instanceof ConsoleCommandSender) {
|
||||
sender.sendMessage(ChatUtil.getPingMessage(PlatformSender.CONSOLE_UUID, target.getUniqueId()));
|
||||
} else if (sender instanceof Player) {
|
||||
sender.sendMessage(ChatUtil.getPingMessage(((Player) sender).getUniqueId(), target.getUniqueId()));
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.bukkit.subcommand;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
public class ReloadSubcommand implements Listener {
|
||||
|
||||
public CommandAPICommand getCommand() {
|
||||
return new CommandAPICommand("reload")
|
||||
.withPermission("knockbacksync.reload")
|
||||
.executes((sender, args) -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
configManager.loadConfig(true);
|
||||
|
||||
String reloadMessage = ChatColor.translateAlternateColorCodes('&',
|
||||
configManager.getReloadMessage()
|
||||
);
|
||||
|
||||
sender.sendMessage(reloadMessage);
|
||||
});
|
||||
}
|
||||
}
|
||||
-58
@@ -1,58 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.bukkit.subcommand;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.CommandPermission;
|
||||
import dev.jorel.commandapi.arguments.PlayerArgument;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class StatusSubcommand implements Listener {
|
||||
|
||||
public CommandAPICommand getCommand() {
|
||||
return new CommandAPICommand("status")
|
||||
.withPermission(CommandPermission.NONE)
|
||||
.withOptionalArguments(new PlayerArgument("target"))
|
||||
.executes((sender, args) -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
Player target = (Player) args.get("target");
|
||||
|
||||
// Show global status
|
||||
boolean globalStatus = configManager.isToggled();
|
||||
sender.sendMessage(ChatColor.YELLOW + "Global KnockbackSync status: " +
|
||||
(globalStatus ? ChatColor.GREEN + "Enabled" : ChatColor.RED + "Disabled"));
|
||||
|
||||
// Show player status
|
||||
if (target == null && sender instanceof Player)
|
||||
target = (Player) sender;
|
||||
|
||||
if (target == null)
|
||||
return;
|
||||
|
||||
if (sender.hasPermission("knockbacksync.status.self") ||
|
||||
(sender.hasPermission("knockbacksync.status.other") && !sender.equals(target))) {
|
||||
|
||||
UUID uuid = target.getUniqueId();
|
||||
boolean playerStatus = PlayerDataManager.containsPlayerData(uuid);
|
||||
|
||||
if (!globalStatus) {
|
||||
sender.sendMessage(ChatColor.YELLOW + target.getName() + "'s KnockbackSync status: " +
|
||||
ChatColor.RED + "Disabled (Global toggle is off)");
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.YELLOW + target.getName() + "'s KnockbackSync status: " +
|
||||
(playerStatus ? ChatColor.GREEN + "Enabled" : ChatColor.RED + "Disabled"));
|
||||
}
|
||||
} else {
|
||||
sender.sendMessage(ChatColor.RED + "You don't have the "
|
||||
+ (sender.equals(target) ? "knockbacksync.status.self" : "knockbacksync.status.other") +
|
||||
" permission needed to check status for " +
|
||||
(sender.equals(target) ? "yourself" : "other players") + ".");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
-87
@@ -1,87 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.bukkit.subcommand;
|
||||
|
||||
import dev.jorel.commandapi.CommandAPICommand;
|
||||
import dev.jorel.commandapi.CommandPermission;
|
||||
import dev.jorel.commandapi.arguments.PlayerArgument;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.player.BukkitPlayer;
|
||||
import me.caseload.knockbacksync.player.PlayerData;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.Listener;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class ToggleSubcommand implements Listener {
|
||||
|
||||
public CommandAPICommand getCommand() {
|
||||
return new CommandAPICommand("toggle")
|
||||
.withPermission(CommandPermission.NONE)
|
||||
.withOptionalArguments(new PlayerArgument("target"))
|
||||
.executes((sender, args) -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
Player target = (Player) args.get("target");
|
||||
String message;
|
||||
|
||||
if (target == null) {
|
||||
// Global toggle
|
||||
if (sender.hasPermission("knockbacksync.toggle.global")) {
|
||||
boolean toggledState = !configManager.isToggled();
|
||||
configManager.setToggled(toggledState);
|
||||
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().set("enabled", toggledState);
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().saveConfig();
|
||||
|
||||
message = ChatColor.translateAlternateColorCodes('&',
|
||||
toggledState ? configManager.getEnableMessage() : configManager.getDisableMessage()
|
||||
);
|
||||
} else {
|
||||
message = ChatColor.RED + "You don't have permission to toggle the global setting.";
|
||||
}
|
||||
sender.sendMessage(message);
|
||||
} else {
|
||||
// Player-specific toggle
|
||||
if (!configManager.isToggled()) {
|
||||
message = ChatColor.RED + "Knockbacksync is currently disabled on this server. Contact your server administrator for more information.";
|
||||
sender.sendMessage(message);
|
||||
} else if (sender instanceof Player && sender.equals(target) && sender.hasPermission("knockbacksync.toggle.self")) {
|
||||
togglePlayerKnockback(target, configManager, sender);
|
||||
} else if (sender.hasPermission("knockbacksync.toggle.other")) {
|
||||
togglePlayerKnockback(target, configManager, sender);
|
||||
} else {
|
||||
message = ChatColor.RED + "You don't have permission to toggle knockback for " +
|
||||
(sender.equals(target) ? "yourself" : "other players") + ".";
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
private void togglePlayerKnockback(Player target, ConfigManager configManager, CommandSender sender) {
|
||||
UUID uuid = target.getUniqueId();
|
||||
|
||||
if (PlayerDataManager.shouldExempt(uuid)) {
|
||||
String message = ChatColor.translateAlternateColorCodes('&',
|
||||
configManager.getPlayerIneligibleMessage()
|
||||
).replace("%player%", target.getName());
|
||||
|
||||
sender.sendMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasPlayerData = PlayerDataManager.containsPlayerData(uuid);
|
||||
if (hasPlayerData)
|
||||
PlayerDataManager.removePlayerData(uuid);
|
||||
else
|
||||
PlayerDataManager.addPlayerData(uuid, new PlayerData(new BukkitPlayer(target)));
|
||||
|
||||
String message = ChatColor.translateAlternateColorCodes('&',
|
||||
hasPlayerData ? configManager.getPlayerDisableMessage() : configManager.getPlayerEnableMessage()
|
||||
).replace("%player%", target.getName());
|
||||
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
+10
-5
@@ -1,8 +1,10 @@
|
||||
package me.caseload.knockbacksync.permission;
|
||||
|
||||
import me.caseload.knockbacksync.command.PlatformSender;
|
||||
import me.caseload.knockbacksync.player.BukkitPlayer;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
import me.caseload.knockbacksync.sender.Sender;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
|
||||
public class PluginPermissionChecker implements PermissionChecker {
|
||||
|
||||
@@ -18,13 +20,16 @@ public class PluginPermissionChecker implements PermissionChecker {
|
||||
|
||||
// Currently shouldn't be called
|
||||
@Override
|
||||
public boolean hasPermission(Object CommandSourceStack, String s, boolean defaultIfUnset) {
|
||||
return false;
|
||||
public boolean hasPermission(Object nativeType, String s, boolean defaultIfUnset) {
|
||||
if (nativeType instanceof CommandSender) {
|
||||
return ((CommandSender) nativeType).hasPermission(s);
|
||||
}
|
||||
throw new IllegalArgumentException("Attempted to check permission of an object that wasn't a platformplayer or Sender. This should never happen on Bukkit!");
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(PlatformSender source, String s, boolean defaultIfUnset) {
|
||||
return false;
|
||||
public boolean hasPermission(Sender source, String s, boolean defaultIfUnset) {
|
||||
return source.hasPermission(s, defaultIfUnset);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -1,8 +1,11 @@
|
||||
package me.caseload.knockbacksync.player;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.PacketEventsAPI;
|
||||
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;
|
||||
@@ -10,11 +13,34 @@ import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Method;
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitPlayer implements PlatformPlayer {
|
||||
public final Player bukkitPlayer;
|
||||
|
||||
// Reflection variables
|
||||
private static Class<?> craftPlayerClass;
|
||||
private static Method getHandleMethod;
|
||||
private static Method getAttackStrengthScaleMethod;
|
||||
|
||||
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);
|
||||
} catch (ClassNotFoundException | NoSuchMethodException e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
public BukkitPlayer(Player player) {
|
||||
this.bukkitPlayer = player;
|
||||
}
|
||||
@@ -56,12 +82,18 @@ public class BukkitPlayer implements PlatformPlayer {
|
||||
|
||||
@Override
|
||||
public boolean isOnGround() {
|
||||
/* Inconsistent with Entity.isOnGround()
|
||||
/ Checks to see if this player is currently standing on a block.
|
||||
/ This information may not be reliable, as it is a state provided by the client, and may therefore not be accurate.
|
||||
/ It can also easily be spoofed. We may want to cast to LivingEntity and call isOnGround() instead
|
||||
*/
|
||||
return bukkitPlayer.isOnGround();
|
||||
}
|
||||
|
||||
|
||||
@Override
|
||||
public int getPing() {
|
||||
return bukkitPlayer.getPing();
|
||||
return PacketEvents.getAPI().getPlayerManager().getPing(bukkitPlayer);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -87,7 +119,17 @@ public class BukkitPlayer implements PlatformPlayer {
|
||||
|
||||
@Override
|
||||
public double getAttackCooldown() {
|
||||
return bukkitPlayer.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
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
@@ -5,7 +5,7 @@ import org.bukkit.scheduler.BukkitTask;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
public class BukkitTaskHandle implements AbstractTaskHandle {
|
||||
private BukkitTask bukkitTask;
|
||||
private final BukkitTask bukkitTask;
|
||||
private boolean cancelled;
|
||||
|
||||
public BukkitTaskHandle(@NotNull BukkitTask bukkitTask) {
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import me.caseload.knockbacksync.player.BukkitPlayer;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class BukkitPlayerSelectorAdapter implements PlayerSelector {
|
||||
private final org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector;
|
||||
|
||||
public BukkitPlayerSelectorAdapter(org.incendo.cloud.bukkit.data.SinglePlayerSelector bukkitSelector) {
|
||||
this.bukkitSelector = bukkitSelector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPlayer getSinglePlayer() {
|
||||
return new BukkitPlayer(bukkitSelector.single());
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PlatformPlayer> getPlayers() {
|
||||
return Collections.singletonList(new BukkitPlayer(bukkitSelector.single()));
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputString() {
|
||||
return bukkitSelector.inputString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.command.generic.AbstractPlayerSelectorParser;
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import org.incendo.cloud.bukkit.parser.selector.SinglePlayerSelectorParser;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class BukkitPlayerSelectorParser<C> extends AbstractPlayerSelectorParser<C> {
|
||||
|
||||
@Override
|
||||
public ParserDescriptor<C, PlayerSelector> descriptor() {
|
||||
return createDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParserDescriptor<C, ?> getPlatformSpecificDescriptor() {
|
||||
return SinglePlayerSelectorParser.singlePlayerSelectorParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<PlayerSelector> adaptToCommonSelector(CommandContext<C> context, Object platformSpecificSelector) {
|
||||
return CompletableFuture.completedFuture(new BukkitPlayerSelectorAdapter((org.incendo.cloud.bukkit.data.SinglePlayerSelector) platformSpecificSelector));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.KBSyncBukkitBase;
|
||||
import org.bukkit.command.CommandSender;
|
||||
import org.bukkit.command.ConsoleCommandSender;
|
||||
import org.bukkit.command.RemoteConsoleCommandSender;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class BukkitSenderFactory extends SenderFactory<KBSyncBukkitBase, CommandSender> implements SenderMapper<CommandSender, Sender> {
|
||||
// private final BukkitAudiences audiences;
|
||||
|
||||
public BukkitSenderFactory(KBSyncBukkitBase kbSyncBukkitBase) {
|
||||
super(kbSyncBukkitBase);
|
||||
// this.audiences = BukkitAudiences.create(kbSyncBukkitBase.getLoader());
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return sender.getName();
|
||||
}
|
||||
return Sender.CONSOLE_NAME;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected UUID getUniqueId(CommandSender sender) {
|
||||
if (sender instanceof Player) {
|
||||
return ((Player) sender).getUniqueId();
|
||||
}
|
||||
return Sender.CONSOLE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void sendMessage(CommandSender sender, String message) {
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
|
||||
// @Override
|
||||
// protected void sendMessage(CommandSender sender, Component message) {
|
||||
// // we can safely send async for players and the console - otherwise, send it sync
|
||||
// if (sender instanceof Player || sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender) {
|
||||
// this.audiences.sender(sender).sendMessage(message);
|
||||
// } else {
|
||||
// getPlugin().getBootstrap().getScheduler().executeSync(() -> this.audiences.sender(sender).sendMessage(message));
|
||||
// }
|
||||
// }
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node) {
|
||||
return sender.hasPermission(node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSender sender, String node, boolean defaultIfUnset) {
|
||||
return sender.hasPermission(new Permission(node, defaultIfUnset ? PermissionDefault.TRUE : PermissionDefault.FALSE));
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommand(CommandSender sender, String command) {
|
||||
//
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean isConsole(CommandSender sender) {
|
||||
return sender instanceof ConsoleCommandSender || sender instanceof RemoteConsoleCommandSender;
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Sender map(@NonNull CommandSender base) {
|
||||
return this.wrap(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CommandSender reverse(@NonNull Sender mapped) {
|
||||
return this.unwrap(mapped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
|
||||
}
|
||||
}
|
||||
@@ -15,8 +15,8 @@ package me.caseload.knockbacksync.stats.custom;
|
||||
* Violations will result in a ban of your plugin and account from bStats.
|
||||
*/
|
||||
|
||||
import me.caseload.knockbacksync.KBSyncBukkitLoaderPlugin;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.KnockbackSyncPlugin;
|
||||
import me.caseload.knockbacksync.stats.CustomChart;
|
||||
import me.caseload.knockbacksync.stats.JsonObjectBuilder;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -39,7 +39,7 @@ public class MetricsBukkit implements Metrics {
|
||||
|
||||
|
||||
public MetricsBukkit(int serviceId) {
|
||||
this.plugin = KnockbackSyncPlugin.getPlugin(KnockbackSyncPlugin.class);
|
||||
this.plugin = KBSyncBukkitLoaderPlugin.getPlugin(KBSyncBukkitLoaderPlugin.class);
|
||||
// Get the config file
|
||||
File bStatsFolder = new File(plugin.getDataFolder().getParentFile(), "bStats");
|
||||
File configFile = new File(bStatsFolder, "config.yml");
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
name: KnockbackSync
|
||||
version: ${version}
|
||||
main: me.caseload.knockbacksync.KnockbackSyncPlugin
|
||||
api-version: '1.16'
|
||||
main: me.caseload.knockbacksync.KBSyncBukkitLoaderPlugin
|
||||
api-version: '1.14'
|
||||
authors: [ Caseload ]
|
||||
description: Synchronizes player knockback for smoother gameplay.
|
||||
folia-supported: true
|
||||
|
||||
+4
-20
@@ -23,7 +23,9 @@ dependencies {
|
||||
exclude(group = "commons-io", module = "commons-io")
|
||||
exclude(group = "org.apache.commons", module = "commons-lang3")
|
||||
}
|
||||
implementation("dev.jorel:commandapi-bukkit-shade:9.5.3")
|
||||
|
||||
implementation("org.incendo:cloud-core:2.0.0")
|
||||
implementation("org.incendo:cloud-minecraft-extras:2.0.0-beta.10")
|
||||
}
|
||||
|
||||
repositories {
|
||||
@@ -32,22 +34,4 @@ repositories {
|
||||
|
||||
tasks.named("remapJar").configure {
|
||||
enabled = false
|
||||
}
|
||||
|
||||
// Using neoforge in vanilla mode so common code compiles
|
||||
//neoForge {
|
||||
// Look for versions on https://projects.neoforged.net/neoforged/neoform
|
||||
// neoFormVersion.set("1.21-20240613.152323")
|
||||
|
||||
// runs {
|
||||
// create("client") {
|
||||
// client()
|
||||
// }
|
||||
// create("server") {
|
||||
// server()
|
||||
// }
|
||||
// create("data") {
|
||||
// data()
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
@@ -3,7 +3,9 @@ package me.caseload.knockbacksync;
|
||||
import me.caseload.knockbacksync.util.NumberConversions;
|
||||
|
||||
import java.util.HashMap;
|
||||
import java.util.HashSet;
|
||||
import java.util.Map;
|
||||
import java.util.Set;
|
||||
|
||||
public class ConfigWrapper {
|
||||
private final Map<String, Object> configMap;
|
||||
@@ -61,4 +63,20 @@ public class ConfigWrapper {
|
||||
}
|
||||
current.put(parts[parts.length - 1], value);
|
||||
}
|
||||
|
||||
public boolean contains(String path) {
|
||||
return getValue(path) != null;
|
||||
}
|
||||
|
||||
public Object get(String path) {
|
||||
return getValue(path);
|
||||
}
|
||||
|
||||
public Set<String> getKeys(String path) {
|
||||
Object value = getValue(path);
|
||||
if (value instanceof Map) {
|
||||
return ((Map<String, Object>) value).keySet();
|
||||
}
|
||||
return new HashSet<>();
|
||||
}
|
||||
}
|
||||
@@ -2,43 +2,50 @@ package me.caseload.knockbacksync;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.caseload.knockbacksync.command.SenderFactory;
|
||||
import me.caseload.knockbacksync.command.MainCommand;
|
||||
import me.caseload.knockbacksync.command.generic.AbstractPlayerSelectorParser;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
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.listener.packetevents.AttributeChangeListener;
|
||||
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.PluginJarHashProvider;
|
||||
import me.caseload.knockbacksync.stats.custom.StatsManager;
|
||||
import me.caseload.knockbacksync.world.PlatformServer;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
import org.kohsuke.github.GitHub;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.InputStream;
|
||||
import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.logging.Logger;
|
||||
|
||||
// Base class
|
||||
public abstract class KnockbackSyncBase {
|
||||
public static Logger LOGGER;
|
||||
public static KnockbackSyncBase INSTANCE;
|
||||
public Platform platform;
|
||||
|
||||
public final Platform platform;
|
||||
public StatsManager statsManager;
|
||||
public PlatformServer platformServer;
|
||||
public PluginJarHashProvider pluginJarHashProvider;
|
||||
@Getter
|
||||
protected SchedulerAdapter scheduler;
|
||||
@Getter
|
||||
protected ConfigManager configManager;
|
||||
@Getter protected PluginJarHashProvider pluginJarHashProvider;
|
||||
@Getter protected SchedulerAdapter scheduler;
|
||||
@Getter protected ConfigManager configManager;
|
||||
protected CommandManager<Sender> commandManager;
|
||||
|
||||
@Setter
|
||||
@Getter
|
||||
private SenderFactory<? extends KnockbackSyncBase, ?> senderFactory;
|
||||
protected AbstractPlayerSelectorParser<Sender> playerSelectorParser;
|
||||
|
||||
protected KnockbackSyncBase() {
|
||||
this.platform = getPlatform();
|
||||
INSTANCE = this;
|
||||
configManager = new ConfigManager();
|
||||
}
|
||||
|
||||
private Platform getPlatform() {
|
||||
@@ -99,7 +106,17 @@ public abstract class KnockbackSyncBase {
|
||||
|
||||
protected abstract void registerPlatformListeners();
|
||||
|
||||
protected abstract void registerCommands();
|
||||
protected void registerCommands() {
|
||||
List<BuilderCommand> list = Arrays.asList(
|
||||
new MainCommand(),
|
||||
new ReloadCommand(),
|
||||
new PingCommand(),
|
||||
new StatusCommand(),
|
||||
new ToggleCommand()
|
||||
);
|
||||
list.forEach(command -> command.register(commandManager));
|
||||
}
|
||||
|
||||
|
||||
protected abstract String getVersion();
|
||||
|
||||
|
||||
@@ -1,4 +0,0 @@
|
||||
package me.caseload.knockbacksync.command;
|
||||
|
||||
public interface CommandSource {
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
package me.caseload.knockbacksync.command;
|
||||
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.sender.Sender;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
public class MainCommand implements BuilderCommand {
|
||||
public void register(CommandManager<Sender> manager) {
|
||||
manager.command(
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
.handler(context -> {
|
||||
context.sender().sendMessage(
|
||||
ChatUtil.translateAlternateColorCodes(
|
||||
'&',
|
||||
"&6This server is running the &eKnockbackSync &6plugin. &bhttps://github.com/CASELOAD7000/knockback-sync"
|
||||
)
|
||||
);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
package me.caseload.knockbacksync.command.generic;
|
||||
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public abstract class AbstractPlayerSelectorParser<C> {
|
||||
|
||||
public abstract ParserDescriptor<C, PlayerSelector> descriptor();
|
||||
|
||||
protected abstract ParserDescriptor<C, ?> getPlatformSpecificDescriptor();
|
||||
|
||||
protected abstract CompletableFuture<PlayerSelector> adaptToCommonSelector(CommandContext<C> context, Object platformSpecificSelector);
|
||||
|
||||
// Helper method to create the ParserDescriptor
|
||||
protected ParserDescriptor<C, PlayerSelector> createDescriptor() {
|
||||
return ParserDescriptor.of(
|
||||
getPlatformSpecificDescriptor().parser().mapSuccess(this::adaptToCommonSelector),
|
||||
PlayerSelector.class
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,9 @@
|
||||
package me.caseload.knockbacksync.command.generic;
|
||||
|
||||
import me.caseload.knockbacksync.sender.Sender;
|
||||
import org.incendo.cloud.CommandManager;
|
||||
|
||||
public interface BuilderCommand {
|
||||
|
||||
void register(CommandManager<Sender> manager);
|
||||
}
|
||||
@@ -0,0 +1,15 @@
|
||||
package me.caseload.knockbacksync.command.generic;
|
||||
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
|
||||
import java.util.Collection;
|
||||
|
||||
public interface PlayerSelector {
|
||||
boolean isSingle();
|
||||
|
||||
PlatformPlayer getSinglePlayer(); // Throws an exception if not a single selection
|
||||
|
||||
Collection<PlatformPlayer> getPlayers();
|
||||
|
||||
String inputString();
|
||||
}
|
||||
@@ -0,0 +1,42 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
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.function.Predicate;
|
||||
|
||||
public class PingCommand implements BuilderCommand {
|
||||
public void register(CommandManager<Sender> manager) {
|
||||
manager.command(
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
.permission((sender -> {
|
||||
final String permission = "knockbacksync.ping";
|
||||
Predicate<Sender> senderPredicate = (s) -> {
|
||||
return s.hasPermission(permission, true);
|
||||
};
|
||||
|
||||
return PredicatePermission.of(senderPredicate).testPermission(sender);
|
||||
}))
|
||||
.literal("ping")
|
||||
.optional("target", KnockbackSyncBase.INSTANCE.getPlayerSelectorParser().descriptor())
|
||||
.handler(context -> {
|
||||
PlayerSelector targetSelector = context.getOrDefault("target", null);
|
||||
|
||||
if (targetSelector == null) {
|
||||
if (context.sender().isConsole()) {
|
||||
context.sender().sendMessage("You must specify a player to use this command from the console.");
|
||||
} else {
|
||||
context.sender().sendMessage(ChatUtil.getPingMessage(context.sender().getUniqueId(), null));
|
||||
}
|
||||
} else {
|
||||
context.sender().sendMessage(ChatUtil.getPingMessage(context.sender().getUniqueId(), targetSelector.getSinglePlayer().getUUID()));
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,37 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
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.function.Predicate;
|
||||
|
||||
public class ReloadCommand implements BuilderCommand {
|
||||
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);
|
||||
};
|
||||
|
||||
return PredicatePermission.of(senderPredicate).testPermission(sender);
|
||||
}))
|
||||
.handler(context -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
configManager.loadConfig(true);
|
||||
|
||||
String rawReloadMessage = configManager.getReloadMessage();
|
||||
String reloadMessage = ChatUtil.translateAlternateColorCodes('&', rawReloadMessage);
|
||||
|
||||
context.sender().sendMessage(reloadMessage);
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
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 StatusCommand implements BuilderCommand {
|
||||
|
||||
private static final ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
private static final String STATUS_SELF_PERMISSION = "knockbacksync.status.self";
|
||||
private static final String STATUS_OTHER_PERMISSION = "knockbacksync.status.other";
|
||||
|
||||
public void register(CommandManager<Sender> manager) {
|
||||
manager.command(
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
.literal("status")
|
||||
.optional("target", KnockbackSyncBase.INSTANCE.getPlayerSelectorParser().descriptor())
|
||||
.permission((sender -> {
|
||||
Predicate<Sender> senderPredicate = (s) -> {
|
||||
return s.hasPermission(STATUS_SELF_PERMISSION, true) || sender.hasPermission(STATUS_OTHER_PERMISSION, false);
|
||||
};
|
||||
|
||||
return PredicatePermission.of(senderPredicate).testPermission(sender);
|
||||
}))
|
||||
.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 (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."));
|
||||
}
|
||||
} else {
|
||||
if (sender.hasPermission(STATUS_OTHER_PERMISSION)) {
|
||||
PlatformPlayer target = targetSelector.getSinglePlayer();
|
||||
showPlayerStatus(sender, target, configManager);
|
||||
} else {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cYou do not have permisssion to check the status of other players!"));
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
private static void showPlayerStatus(Sender sender, PlatformPlayer target, ConfigManager configManager) {
|
||||
boolean globalStatus = configManager.isToggled();
|
||||
UUID uuid = target.getUUID();
|
||||
boolean playerStatus = PlayerDataManager.containsPlayerData(uuid);
|
||||
|
||||
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)"))));
|
||||
} else {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("player_status_message", "&e%player%'s KnockbackSync status: ")
|
||||
.replace("%player%", target.getName()) +
|
||||
(playerStatus
|
||||
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
|
||||
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled"))));
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,114 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
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.Permission;
|
||||
import org.incendo.cloud.permission.PredicatePermission;
|
||||
|
||||
import java.util.UUID;
|
||||
import java.util.function.Predicate;
|
||||
|
||||
public class ToggleCommand implements BuilderCommand {
|
||||
|
||||
private static final ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
private static final PermissionChecker permissionChecker = KnockbackSyncBase.INSTANCE.getPermissionChecker();
|
||||
private static final String TOGGLE_GLOBAL_PERMISSION = "knockbacksync.toggle.global";
|
||||
private static final String TOGGLE_SELF_PERMISSION = "knockbacksync.toggle.self";
|
||||
private static final String TOGGLE_OTHER_PERMISSION = "knockbacksync.toggle.other";
|
||||
|
||||
|
||||
@Override
|
||||
public void register(CommandManager<Sender> manager) {
|
||||
manager.command(
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
.literal("toggle")
|
||||
.optional("target", KnockbackSyncBase.INSTANCE.getPlayerSelectorParser().descriptor())
|
||||
.permission((sender -> {
|
||||
Predicate<Sender> senderPredicate = (s) -> {
|
||||
return s.hasPermission(TOGGLE_GLOBAL_PERMISSION, false)
|
||||
|| sender.hasPermission(TOGGLE_SELF_PERMISSION, true)
|
||||
|| sender.hasPermission(TOGGLE_OTHER_PERMISSION, false);
|
||||
};
|
||||
|
||||
return PredicatePermission.of(senderPredicate).testPermission(sender);
|
||||
}))
|
||||
.handler(context -> {
|
||||
Sender sender = context.sender();
|
||||
PlayerSelector targetSelector = context.getOrDefault("target", null);
|
||||
if (targetSelector == null) {
|
||||
// Global toggle
|
||||
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."));
|
||||
}
|
||||
} 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.");
|
||||
return;
|
||||
} else if (senderIsTarget && !permissionChecker.hasPermission(sender, TOGGLE_SELF_PERMISSION, true)) {
|
||||
sender.sendMessage("You do not have permission to toggle your knockback.");
|
||||
return;
|
||||
}
|
||||
|
||||
if (!configManager.isToggled()) {
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', "&cKnockbacksync is currently disabled on this server. Contact your server administrator for more information."));
|
||||
} else {
|
||||
togglePlayerKnockback(target, configManager, sender);
|
||||
}
|
||||
}
|
||||
})
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
private static void toggleGlobalKnockback(ConfigManager configManager, Sender sender) {
|
||||
boolean toggledState = !configManager.isToggled();
|
||||
configManager.setToggled(toggledState);
|
||||
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().set("enabled", toggledState);
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().saveConfig();
|
||||
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
toggledState ? configManager.getEnableMessage() : configManager.getDisableMessage()
|
||||
);
|
||||
sender.sendMessage(ChatUtil.translateAlternateColorCodes('&', message));
|
||||
}
|
||||
|
||||
private static void togglePlayerKnockback(PlatformPlayer target, ConfigManager configManager, Sender sender) {
|
||||
UUID uuid = target.getUUID();
|
||||
|
||||
if (PlayerDataManager.shouldExempt(uuid)) {
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getPlayerIneligibleMessage()
|
||||
).replace("%player%", target.getName());
|
||||
|
||||
sender.sendMessage(message);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasPlayerData = PlayerDataManager.containsPlayerData(uuid);
|
||||
if (hasPlayerData)
|
||||
PlayerDataManager.removePlayerData(uuid);
|
||||
else {
|
||||
PlayerDataManager.addPlayerData(uuid, new PlayerData(KnockbackSyncBase.INSTANCE.platformServer.getPlayer(uuid)));
|
||||
}
|
||||
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
hasPlayerData ? configManager.getPlayerDisableMessage() : configManager.
|
||||
getPlayerEnableMessage()
|
||||
).replace("%player%", target.getName());
|
||||
|
||||
sender.sendMessage(message);
|
||||
}
|
||||
}
|
||||
+39
@@ -0,0 +1,39 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.generic.BuilderCommand;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
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.function.Predicate;
|
||||
|
||||
public class ToggleOffGroundSubcommand implements BuilderCommand {
|
||||
|
||||
@Override
|
||||
public void register(CommandManager<Sender> manager) {
|
||||
manager.command(
|
||||
manager.commandBuilder("knockbacksync", "kbsync", "kbs")
|
||||
.literal("toggleoffground")
|
||||
.permission((sender -> {
|
||||
final String permission = "knockbacksync.toggleoffground";
|
||||
Predicate<Sender> senderPredicate = (s) -> {
|
||||
return s.hasPermission(permission, false);
|
||||
};
|
||||
|
||||
return PredicatePermission.of(senderPredicate).testPermission(sender);
|
||||
}))
|
||||
.handler(commandContext -> {
|
||||
boolean toggledState = !KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().getBoolean("enable_experimental_offground", false);
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().set("enable_experimental_offground", toggledState);
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().saveConfig();
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
toggledState ?
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().getString("enable_experimental_offground_message", "&aSuccessfully enabled offground experiment.") :
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().getString("disable_experimental_offground_message", "&cSuccessfully disabled offground experiment."));
|
||||
commandContext.sender().sendMessage(message);
|
||||
}));
|
||||
}
|
||||
}
|
||||
+3
-3
@@ -18,9 +18,9 @@ public class AttributeChangeListener extends PacketListenerAbstract {
|
||||
public static final UUID SPRINTING_MODIFIER_UUID =
|
||||
UUID.fromString("662A6B8D-DA3E-4C1C-8813-96EA6097278D");
|
||||
|
||||
double minGravity = -1;
|
||||
double maxGravity = 1;
|
||||
double defaultGravity = 0.08;
|
||||
final double minGravity = -1;
|
||||
final double maxGravity = 1;
|
||||
final double defaultGravity = 0.08;
|
||||
double currentGravity;
|
||||
|
||||
public AttributeChangeListener() {
|
||||
|
||||
+79
-19
@@ -2,42 +2,102 @@ 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.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientKeepAlive;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPong;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientWindowConfirmation;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerKeepAlive;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPing;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerWindowConfirmation;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.player.PlayerData;
|
||||
import me.caseload.knockbacksync.util.data.Pair;
|
||||
|
||||
import java.util.List;
|
||||
|
||||
public class PingReceiveListener extends PacketListenerAbstract {
|
||||
// TODO supplment our own ping calculations with over keepalive sent by the server with
|
||||
// @Override
|
||||
// public void onPacketSend(PacketSendEvent event) {
|
||||
// if (event.getPacketType() == PacketType.Play.Server.KEEP_ALIVE) {
|
||||
// }
|
||||
// }
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
PacketTypeCommon packetType = event.getPacketType();
|
||||
if (packetType.equals(PacketType.Play.Server.KEEP_ALIVE)) {
|
||||
WrapperPlayServerKeepAlive keepAlive = new WrapperPlayServerKeepAlive(event);
|
||||
long id = keepAlive.getId();
|
||||
|
||||
PlayerData playerData = PlayerDataManager.getPlayerData(event.getUser().getUUID());
|
||||
if (playerData == null) return;
|
||||
|
||||
playerData.keepaliveMap.add(new Pair<>(id, System.nanoTime()));
|
||||
} else if (packetType.equals(PacketType.Play.Server.PING)) {
|
||||
WrapperPlayServerPing ping = new WrapperPlayServerPing(event);
|
||||
int id = ping.getId();
|
||||
|
||||
PlayerData playerData = PlayerDataManager.getPlayerData(event.getUser().getUUID());
|
||||
if (playerData == null) return;
|
||||
|
||||
playerData.transactionsSent.add(new Pair<>(id, System.nanoTime()));
|
||||
} else if (packetType.equals(PacketType.Play.Server.WINDOW_CONFIRMATION)) {
|
||||
WrapperPlayServerWindowConfirmation confirmation = new WrapperPlayServerWindowConfirmation(event);
|
||||
int id = confirmation.getActionId();
|
||||
|
||||
PlayerData playerData = PlayerDataManager.getPlayerData(event.getUser().getUUID());
|
||||
if (playerData == null) return;
|
||||
|
||||
playerData.transactionsSent.add(new Pair<>(id, System.nanoTime()));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
if (!KnockbackSyncBase.INSTANCE.getConfigManager().isToggled()) return;
|
||||
if (event.getPacketType() != PacketType.Play.Client.KEEP_ALIVE) return;
|
||||
|
||||
WrapperPlayClientKeepAlive keepAlive = new WrapperPlayClientKeepAlive(event);
|
||||
PlayerData playerData = PlayerDataManager.getPlayerData(event.getUser().getUUID());
|
||||
if (playerData == null) return;
|
||||
PacketTypeCommon packetType = event.getPacketType();
|
||||
if (packetType == PacketType.Play.Client.KEEP_ALIVE) {
|
||||
|
||||
long receivedId = keepAlive.getId();
|
||||
WrapperPlayClientKeepAlive keepAlive = new WrapperPlayClientKeepAlive(event);
|
||||
PlayerData playerData = PlayerDataManager.getPlayerData(event.getUser().getUUID());
|
||||
if (playerData == null) return;
|
||||
|
||||
if (playerData.isKeepAliveIDOurs(receivedId)) {
|
||||
long pingNanos = (System.nanoTime() - receivedId);
|
||||
// Calculate the remainder nanoseconds for fractional milliseconds
|
||||
double diffMillisDouble = pingNanos / 1_000_000.0;
|
||||
long receivedId = keepAlive.getId();
|
||||
|
||||
playerData.setPreviousPing(playerData.getPing());
|
||||
playerData.setPing(diffMillisDouble);
|
||||
handlePingCalculationPackets(event, playerData, receivedId, playerData.keepaliveMap);
|
||||
} else if (packetType == PacketType.Play.Client.PONG) {
|
||||
WrapperPlayClientPong pong = new WrapperPlayClientPong(event);
|
||||
PlayerData playerData = PlayerDataManager.getPlayerData(event.getUser().getUUID());
|
||||
if (playerData == null) return;
|
||||
|
||||
playerData.getJitterCalculator().addPing(pingNanos);
|
||||
double jitter = playerData.getJitterCalculator().calculateJitter();
|
||||
playerData.setJitter(jitter);
|
||||
int id = pong.getId();
|
||||
|
||||
handlePingCalculationPackets(event, playerData, id, playerData.transactionsSent);
|
||||
} else if (packetType == PacketType.Play.Client.WINDOW_CONFIRMATION) {
|
||||
WrapperPlayClientWindowConfirmation windowConfirmation = new WrapperPlayClientWindowConfirmation(event);
|
||||
PlayerData playerData = PlayerDataManager.getPlayerData(event.getUser().getUUID());
|
||||
if (playerData == null) return;
|
||||
|
||||
int id = windowConfirmation.getActionId();
|
||||
|
||||
handlePingCalculationPackets(event, playerData, id, playerData.transactionsSent);
|
||||
}
|
||||
}
|
||||
|
||||
private <T extends Number> void handlePingCalculationPackets(PacketReceiveEvent event, PlayerData playerData, long id, List<Pair<T, Long>> packetSentList) {
|
||||
long pingNanos = (System.nanoTime() - packetSentList.remove(0).getSecond());
|
||||
double diffMillisDouble = pingNanos / 1_000_000.0;
|
||||
|
||||
playerData.setPreviousPing(playerData.getPing());
|
||||
playerData.setPing(diffMillisDouble);
|
||||
|
||||
playerData.getJitterCalculator().addPing(pingNanos);
|
||||
double jitter = playerData.getJitterCalculator().calculateJitter();
|
||||
playerData.setJitter(jitter);
|
||||
|
||||
// We can cancel for all 3 cases
|
||||
if (playerData.didWeSendThatPacket(id)) {
|
||||
// Pong not needed as vanilla ignores the packet, its needed for packet limiters
|
||||
// We want to cancel Window Confirmations that we send, and ...
|
||||
// Minecraft kicks players that send invalid keepAliveID packets
|
||||
// Since Minecraft doesn't know we just sent a keepalive, we gotta cancel it
|
||||
// To stop MC from processing it and kicking the player
|
||||
|
||||
@@ -7,7 +7,6 @@ import lombok.Setter;
|
||||
import me.caseload.knockbacksync.ConfigWrapper;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.Platform;
|
||||
import me.caseload.knockbacksync.player.PlayerData;
|
||||
import me.caseload.knockbacksync.runnable.PingRunnable;
|
||||
import me.caseload.knockbacksync.scheduler.AbstractTaskHandle;
|
||||
|
||||
@@ -20,6 +19,8 @@ import java.util.Map;
|
||||
@Setter
|
||||
public class ConfigManager {
|
||||
|
||||
public static final long CONFIG_VERSION = 2;
|
||||
|
||||
private boolean toggled;
|
||||
private boolean runnableEnabled;
|
||||
private boolean updateAvailable;
|
||||
@@ -117,6 +118,54 @@ public class ConfigManager {
|
||||
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.");
|
||||
PlayerData.PING_OFFSET = config.getInt("ping_offset", 25);
|
||||
}
|
||||
|
||||
public void updateConfig() {
|
||||
ConfigWrapper oldConfig = getConfigWrapper();
|
||||
long oldConfigVersion = oldConfig.getLong("config_version", 0);
|
||||
|
||||
if (oldConfigVersion < CONFIG_VERSION) {
|
||||
// Backup old config
|
||||
File backupFile = new File(configFile.getParentFile(), "config-version-" + oldConfigVersion + ".yml");
|
||||
if (configFile.renameTo(backupFile)) {
|
||||
KnockbackSyncBase.INSTANCE.getLogger().info("Backed up old config to " + backupFile.getName());
|
||||
} else {
|
||||
KnockbackSyncBase.INSTANCE.getLogger().warning("Failed to backup old config");
|
||||
}
|
||||
|
||||
// Create new config with default values
|
||||
KnockbackSyncBase.INSTANCE.saveDefaultConfig();
|
||||
reloadConfig();
|
||||
|
||||
// Transfer existing settings
|
||||
ConfigWrapper newConfig = getConfigWrapper();
|
||||
transferAllSettings(oldConfig, newConfig);
|
||||
|
||||
// Set new config version
|
||||
newConfig.set("config_version", CONFIG_VERSION);
|
||||
|
||||
// Save updated config
|
||||
saveConfig();
|
||||
|
||||
KnockbackSyncBase.INSTANCE.getLogger().info("Config updated to version " + CONFIG_VERSION);
|
||||
}
|
||||
}
|
||||
|
||||
private void transferAllSettings(ConfigWrapper oldConfig, ConfigWrapper newConfig) {
|
||||
transferSettingsRecursive(oldConfig, newConfig, "");
|
||||
}
|
||||
|
||||
private void transferSettingsRecursive(ConfigWrapper oldConfig, ConfigWrapper newConfig, String currentPath) {
|
||||
for (String key : oldConfig.getKeys(currentPath)) {
|
||||
String fullPath = currentPath.isEmpty() ? key : currentPath + "." + key;
|
||||
if (newConfig.contains(fullPath)) {
|
||||
Object value = oldConfig.get(fullPath);
|
||||
if (value instanceof Map) {
|
||||
transferSettingsRecursive(oldConfig, newConfig, fullPath);
|
||||
} else {
|
||||
newConfig.set(fullPath, value);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,12 +1,12 @@
|
||||
package me.caseload.knockbacksync.permission;
|
||||
|
||||
import me.caseload.knockbacksync.command.PlatformSender;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
import me.caseload.knockbacksync.sender.Sender;
|
||||
|
||||
public interface PermissionChecker {
|
||||
boolean hasPermission(Object CommandSourceStack, String s, boolean defaultIfUnset);
|
||||
boolean hasPermission(Object nativeType, String s, boolean defaultIfUnset);
|
||||
|
||||
boolean hasPermission(PlatformSender source, String s, boolean defaultIfUnset);
|
||||
boolean hasPermission(Sender source, String s, boolean defaultIfUnset);
|
||||
|
||||
boolean hasPermission(PlatformPlayer platform, String s);
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package me.caseload.knockbacksync.player;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
public class JitterCalculator {
|
||||
private final int SAMPLE_SIZE = 15;
|
||||
@@ -31,7 +32,7 @@ public class JitterCalculator {
|
||||
double upperBound = q3 + 1.5 * iqr;
|
||||
List<Long> filteredPings = sortedPings.stream()
|
||||
.filter(p -> p >= lowerBound && p <= upperBound)
|
||||
.toList();
|
||||
.collect(Collectors.toList());
|
||||
|
||||
// Calculate standard deviation
|
||||
double mean = filteredPings.stream().mapToLong(Long::longValue).average().orElse(0);
|
||||
|
||||
@@ -2,6 +2,7 @@ package me.caseload.knockbacksync.player;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.player.PlayerManager;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
|
||||
import com.github.retrooper.packetevents.protocol.ConnectionState;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
@@ -9,7 +10,10 @@ import com.github.retrooper.packetevents.protocol.player.User;
|
||||
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;
|
||||
import com.github.retrooper.packetevents.wrapper.PacketWrapper;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerKeepAlive;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPing;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerWindowConfirmation;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
@@ -20,22 +24,27 @@ import me.caseload.knockbacksync.util.data.Pair;
|
||||
import me.caseload.knockbacksync.world.PlatformWorld;
|
||||
import me.caseload.knockbacksync.world.raytrace.FluidHandling;
|
||||
import me.caseload.knockbacksync.world.raytrace.RayTraceResult;
|
||||
import org.incendo.cloud.CloudCapability;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.lang.reflect.Field;
|
||||
import java.util.LinkedList;
|
||||
import java.util.Queue;
|
||||
import java.util.Random;
|
||||
import java.util.UUID;
|
||||
import java.util.*;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.concurrent.ConcurrentLinkedQueue;
|
||||
|
||||
@Getter
|
||||
public class PlayerData {
|
||||
|
||||
// Please read the GitHub FAQ before adjusting.
|
||||
public static long PING_OFFSET;
|
||||
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 = -1;
|
||||
private static final short NETTY_THREAD_TRANSACTION_ID = -2;
|
||||
|
||||
static {
|
||||
try {
|
||||
@@ -61,30 +70,16 @@ public class PlayerData {
|
||||
public final User user;
|
||||
private final PlatformPlayer platformPlayer;
|
||||
private final UUID uuid;
|
||||
@NotNull
|
||||
private final Random random = new Random();
|
||||
public Queue<Pair<Long, Long>> keepaliveMap = new LinkedList<>();
|
||||
@NotNull private final Random random = new Random();
|
||||
public long lastKeepAliveID = 0;
|
||||
@Getter
|
||||
private JitterCalculator jitterCalculator = new JitterCalculator();
|
||||
@Getter
|
||||
@Setter
|
||||
private double jitter;
|
||||
@Nullable
|
||||
private AbstractTaskHandle combatTask;
|
||||
@Nullable
|
||||
@Setter
|
||||
private Double ping, previousPing;
|
||||
@Nullable
|
||||
@Setter
|
||||
private Double verticalVelocity;
|
||||
@Nullable
|
||||
@Setter
|
||||
private Integer lastDamageTicks;
|
||||
@Setter
|
||||
private double gravityAttribute = 0.08;
|
||||
@Setter
|
||||
private double knockbackResistanceAttribute = 0.0;
|
||||
@Getter private final JitterCalculator jitterCalculator = new JitterCalculator();
|
||||
@Setter private double jitter;
|
||||
@Nullable private AbstractTaskHandle combatTask;
|
||||
@Nullable @Setter private Double ping, previousPing;
|
||||
@Nullable @Setter private Double verticalVelocity;
|
||||
@Nullable @Setter private Integer lastDamageTicks;
|
||||
@Setter private double gravityAttribute = 0.08;
|
||||
@Setter private double knockbackResistanceAttribute = 0.0;
|
||||
|
||||
public PlayerData(PlatformPlayer platformPlayer) {
|
||||
this.uuid = platformPlayer.getUUID();
|
||||
@@ -122,24 +117,47 @@ public class PlayerData {
|
||||
return Math.max(1, ping - PING_OFFSET);
|
||||
}
|
||||
|
||||
public boolean isKeepAliveIDOurs(long id) {
|
||||
return id == lastKeepAliveID;
|
||||
}
|
||||
// public boolean isKeepAliveIDOurs(long id) {
|
||||
// return id == lastKeepAliveID;
|
||||
// }
|
||||
|
||||
// Doesn't actually send a ping, sends a keepalive, more accurate and processed faster
|
||||
public void sendPing(boolean async) {
|
||||
if (user == null || user.getEncoderState() != ConnectionState.PLAY) return;
|
||||
|
||||
if (async) {
|
||||
ChannelHelper.runInEventLoop(user.getChannel(), () -> {
|
||||
// We call sendPacket instead of writePacket because it flushes immediately
|
||||
// Making our time measurement more accurate since we don't call, System.nanoTime(), wait until flush
|
||||
// And then actually send packet
|
||||
user.sendPacket(new WrapperPlayServerKeepAlive(lastKeepAliveID = System.nanoTime()));
|
||||
});
|
||||
} else {
|
||||
user.sendPacket(new WrapperPlayServerKeepAlive(lastKeepAliveID = System.nanoTime()));
|
||||
}
|
||||
String pingStrategy = KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().getString("ping_strategy", "KEEPALIVE");
|
||||
switch (pingStrategy) {
|
||||
case "KEEPALIVE":
|
||||
long keepAliveID = async ? NETTY_THREAD_TRANSACTION_ID : MAIN_THREAD_TRANSACTION_ID;
|
||||
if (async) {
|
||||
ChannelHelper.runInEventLoop(user.getChannel(), () -> {
|
||||
// We call sendPacket instead of writePacket because it flushes immediately
|
||||
// Making our time measurement more accurate since we don't call, System.nanoTime(), wait until flush
|
||||
// And then actually send packet
|
||||
user.sendPacket(new WrapperPlayServerKeepAlive(keepAliveID));
|
||||
});
|
||||
} else {
|
||||
user.sendPacket(new WrapperPlayServerKeepAlive(keepAliveID));
|
||||
}
|
||||
break;
|
||||
case "PING":
|
||||
case "TRANSACTION":
|
||||
PacketWrapper<?> packet;
|
||||
short pingTransactionID = async ? NETTY_THREAD_TRANSACTION_ID : MAIN_THREAD_TRANSACTION_ID;
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_17)) {
|
||||
packet = new WrapperPlayServerPing(pingTransactionID);
|
||||
} else {
|
||||
packet = new WrapperPlayServerWindowConfirmation((byte) 0, pingTransactionID, false);
|
||||
}
|
||||
|
||||
if (async) {
|
||||
ChannelHelper.runInEventLoop(user.getChannel(), () -> {
|
||||
user.writePacket(packet);
|
||||
});
|
||||
} else {
|
||||
user.writePacket(packet);
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -305,4 +323,8 @@ public class PlayerData {
|
||||
public long getKeepAliveSendTime() {
|
||||
return lastKeepAliveID;
|
||||
}
|
||||
|
||||
public boolean didWeSendThatPacket(long receivedId) {
|
||||
return receivedId == NETTY_THREAD_TRANSACTION_ID || receivedId == MAIN_THREAD_TRANSACTION_ID;
|
||||
}
|
||||
}
|
||||
@@ -2,7 +2,7 @@ package me.caseload.knockbacksync.scheduler;
|
||||
|
||||
public interface AbstractTaskHandle {
|
||||
|
||||
public boolean getCancelled();
|
||||
boolean getCancelled();
|
||||
|
||||
public void cancel();
|
||||
void cancel();
|
||||
}
|
||||
+8
-3
@@ -1,15 +1,15 @@
|
||||
package me.caseload.knockbacksync.command;
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
/**
|
||||
* Simple implementation of {@link PlatformSender} using a {@link SenderFactory}
|
||||
* Simple implementation of {@link Sender} using a {@link SenderFactory}
|
||||
*
|
||||
* @param <T> the command sender type
|
||||
*/
|
||||
public final class AbstractSender<T> implements PlatformSender {
|
||||
public final class AbstractSender<T> implements Sender {
|
||||
private final KnockbackSyncBase plugin;
|
||||
private final SenderFactory<?, T> factory;
|
||||
private final T sender;
|
||||
@@ -52,6 +52,11 @@ public final class AbstractSender<T> implements PlatformSender {
|
||||
return isConsole() || this.factory.hasPermission(this.sender, permission);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(String permission, boolean defaultIfUnset) {
|
||||
return isConsole() || this.factory.hasPermission(this.sender, permission, defaultIfUnset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void performCommand(String commandLine) {
|
||||
this.factory.performCommand(this.sender, commandLine);
|
||||
+4
-2
@@ -1,4 +1,4 @@
|
||||
package me.caseload.knockbacksync.command;
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
|
||||
@@ -7,7 +7,7 @@ import java.util.UUID;
|
||||
/**
|
||||
* Wrapper interface to represent a CommandSender/CommandSource within the common command implementations.
|
||||
*/
|
||||
public interface PlatformSender {
|
||||
public interface Sender {
|
||||
|
||||
/**
|
||||
* The uuid used by the console sender.
|
||||
@@ -63,6 +63,8 @@ public interface PlatformSender {
|
||||
*/
|
||||
boolean hasPermission(String permission);
|
||||
|
||||
boolean hasPermission(String permission, boolean defaultIfUnset);
|
||||
|
||||
/**
|
||||
* Makes the sender perform a command.
|
||||
*
|
||||
+8
-5
@@ -1,4 +1,4 @@
|
||||
package me.caseload.knockbacksync.command;
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
|
||||
@@ -30,6 +30,8 @@ public abstract class SenderFactory<P extends KnockbackSyncBase, T> implements A
|
||||
|
||||
protected abstract boolean hasPermission(T sender, String node);
|
||||
|
||||
protected abstract boolean hasPermission(T sender, String node, boolean defaultIfUnset);
|
||||
|
||||
protected abstract void performCommand(T sender, String command);
|
||||
|
||||
protected abstract boolean isConsole(T sender);
|
||||
@@ -38,13 +40,14 @@ public abstract class SenderFactory<P extends KnockbackSyncBase, T> implements A
|
||||
return isConsole(sender);
|
||||
}
|
||||
|
||||
public final PlatformSender wrap(T sender) {
|
||||
public final Sender wrap(T sender) {
|
||||
Objects.requireNonNull(sender, "sender");
|
||||
return new AbstractSender<>(this.plugin, this, sender);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() {
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
public final T unwrap(Sender sender) {
|
||||
Objects.requireNonNull(sender, "sender");
|
||||
return (T) sender.getSender();
|
||||
}
|
||||
}
|
||||
@@ -8,12 +8,8 @@ import org.kohsuke.github.GHAsset;
|
||||
import org.kohsuke.github.GHRelease;
|
||||
import org.kohsuke.github.GitHub;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.*;
|
||||
import java.net.URL;
|
||||
import java.nio.charset.StandardCharsets;
|
||||
import java.nio.file.Files;
|
||||
import java.nio.file.Paths;
|
||||
import java.util.List;
|
||||
@@ -39,7 +35,7 @@ public class BuildTypePie extends SimplePie {
|
||||
|
||||
private static String calculateBuildType() {
|
||||
try {
|
||||
String currentHash = KnockbackSyncBase.INSTANCE.pluginJarHashProvider.getPluginJarHash();
|
||||
String currentHash = KnockbackSyncBase.INSTANCE.getPluginJarHashProvider().getPluginJarHash();
|
||||
downloadBuildFiles();
|
||||
|
||||
if (isHashInFile(currentHash, new File(dataFolder, RELEASES_FILE))) {
|
||||
@@ -57,7 +53,7 @@ public class BuildTypePie extends SimplePie {
|
||||
|
||||
private static void downloadBuildFiles() throws IOException {
|
||||
GitHub gitHub = GitHub.connectAnonymously();
|
||||
GHRelease latestRelease = gitHub.getRepository("Axionize/knockback-sync")
|
||||
GHRelease latestRelease = gitHub.getRepository("CASELOAD7000/knockback-sync")
|
||||
.getLatestRelease();
|
||||
List<GHAsset> assets = latestRelease.listAssets().toList();
|
||||
for (GHAsset asset : assets) {
|
||||
@@ -68,9 +64,12 @@ public class BuildTypePie extends SimplePie {
|
||||
JsonObject jsonObject = JsonParser.parseString(jsonContent).getAsJsonObject();
|
||||
String downloadUrl = jsonObject.get("browser_download_url").getAsString();
|
||||
|
||||
try (InputStream inputStream = new URL(downloadUrl).openStream();
|
||||
FileOutputStream outputStream = new FileOutputStream(new File(dataFolder, asset.getName()))) {
|
||||
inputStream.transferTo(outputStream);
|
||||
try (InputStream inputStream = new URL(downloadUrl).openStream(); FileOutputStream outputStream = new FileOutputStream(new File(dataFolder, asset.getName()))) {
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
outputStream.write(buffer, 0, bytesRead);
|
||||
}
|
||||
}
|
||||
|
||||
KnockbackSyncBase.INSTANCE.getLogger().info("Downloaded: " + asset.getName());
|
||||
@@ -88,7 +87,13 @@ public class BuildTypePie extends SimplePie {
|
||||
|
||||
private static String readStringFromURL(String urlString) throws IOException {
|
||||
try (InputStream inputStream = new URL(urlString).openStream()) {
|
||||
return new String(inputStream.readAllBytes(), StandardCharsets.UTF_8);
|
||||
ByteArrayOutputStream result = new ByteArrayOutputStream();
|
||||
byte[] buffer = new byte[4096];
|
||||
int bytesRead;
|
||||
while ((bytesRead = inputStream.read(buffer)) != -1) {
|
||||
result.write(buffer, 0, bytesRead);
|
||||
}
|
||||
return result.toString("UTF-8");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,5 @@
|
||||
package me.caseload.knockbacksync.stats.custom;
|
||||
|
||||
public interface Metrics {
|
||||
public void shutdown();
|
||||
void shutdown();
|
||||
}
|
||||
@@ -2,6 +2,7 @@ package me.caseload.knockbacksync.stats.custom;
|
||||
|
||||
import me.caseload.knockbacksync.stats.CustomChart;
|
||||
import me.caseload.knockbacksync.stats.JsonObjectBuilder;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
import javax.net.ssl.HttpsURLConnection;
|
||||
import java.io.*;
|
||||
@@ -94,20 +95,7 @@ public class MetricsBase {
|
||||
boolean logSentData,
|
||||
boolean logResponseStatusText,
|
||||
boolean skipRelocateCheck) {
|
||||
ScheduledThreadPoolExecutor scheduler =
|
||||
new ScheduledThreadPoolExecutor(
|
||||
1,
|
||||
task -> {
|
||||
Thread thread = new Thread(task, "bStats-Metrics");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
// We want delayed tasks (non-periodic) that will execute in the future to be
|
||||
// cancelled when the scheduler is shutdown.
|
||||
// Otherwise, we risk preventing the server from shutting down even when
|
||||
// MetricsBase#shutdown() is called
|
||||
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
this.scheduler = scheduler;
|
||||
this.scheduler = getScheduledThreadPoolExecutor();
|
||||
this.platform = platform;
|
||||
this.serverUuid = serverUuid;
|
||||
this.serviceId = serviceId;
|
||||
@@ -131,6 +119,23 @@ public class MetricsBase {
|
||||
}
|
||||
}
|
||||
|
||||
private static @NotNull ScheduledThreadPoolExecutor getScheduledThreadPoolExecutor() {
|
||||
ScheduledThreadPoolExecutor scheduler =
|
||||
new ScheduledThreadPoolExecutor(
|
||||
1,
|
||||
task -> {
|
||||
Thread thread = new Thread(task, "bStats-Metrics");
|
||||
thread.setDaemon(true);
|
||||
return thread;
|
||||
});
|
||||
// We want delayed tasks (non-periodic) that will execute in the future to be
|
||||
// cancelled when the scheduler is shutdown.
|
||||
// Otherwise, we risk preventing the server from shutting down even when
|
||||
// MetricsBase#shutdown() is called
|
||||
scheduler.setExecuteExistingDelayedTasksAfterShutdownPolicy(false);
|
||||
return scheduler;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gzips the given string.
|
||||
*
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@ import java.security.MessageDigest;
|
||||
|
||||
public class PluginJarHashProvider {
|
||||
|
||||
protected URL jarURL;
|
||||
protected final URL jarURL;
|
||||
|
||||
public PluginJarHashProvider(URL jarURL) {
|
||||
this.jarURL = jarURL;
|
||||
|
||||
@@ -1,13 +1,12 @@
|
||||
package me.caseload.knockbacksync.stats.custom;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
@Getter
|
||||
public abstract class StatsManager {
|
||||
|
||||
Metrics metrics;
|
||||
|
||||
public Metrics getMetrics() {
|
||||
return metrics;
|
||||
}
|
||||
|
||||
public void init() {
|
||||
throw new IllegalStateException("Empty stats class!");
|
||||
}
|
||||
|
||||
@@ -9,8 +9,7 @@ public class NumberConversions {
|
||||
} else {
|
||||
try {
|
||||
return Long.parseLong(object.toString());
|
||||
} catch (NumberFormatException var2) {
|
||||
} catch (NullPointerException var3) {
|
||||
} catch (NumberFormatException | NullPointerException ignored) {
|
||||
}
|
||||
|
||||
return defaultValue;
|
||||
@@ -23,8 +22,7 @@ public class NumberConversions {
|
||||
} else {
|
||||
try {
|
||||
return Integer.parseInt(object.toString());
|
||||
} catch (NumberFormatException var2) {
|
||||
} catch (NullPointerException var3) {
|
||||
} catch (NumberFormatException | NullPointerException ignored) {
|
||||
}
|
||||
|
||||
return def;
|
||||
|
||||
@@ -1,7 +1,10 @@
|
||||
package me.caseload.knockbacksync.util.data;
|
||||
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.Objects;
|
||||
|
||||
@Getter
|
||||
public class Pair<A, B> {
|
||||
private final A first;
|
||||
private final B second;
|
||||
@@ -15,14 +18,6 @@ public class Pair<A, B> {
|
||||
return new Pair<T, K>(a, b);
|
||||
}
|
||||
|
||||
public A getFirst() {
|
||||
return first;
|
||||
}
|
||||
|
||||
public B getSecond() {
|
||||
return second;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(Object o) {
|
||||
if (!(o instanceof Pair)) {
|
||||
|
||||
@@ -2,6 +2,9 @@
|
||||
# KnockbackSync Configuration #
|
||||
#########################################
|
||||
|
||||
# Do not modify!
|
||||
config-version: 2
|
||||
|
||||
# Plugin enabled state
|
||||
# Toggleable using /knockbacksync toggle
|
||||
# Required permission: knockbacksync.toggle
|
||||
@@ -15,7 +18,7 @@ notify_updates: true
|
||||
# Disabling this may lead to inaccuracies in calculations
|
||||
runnable:
|
||||
enabled: true # Runnable enabled state
|
||||
interval: 5 # The interval in ticks between sending out pings to players
|
||||
interval: 20 # The interval in ticks between sending out pings to players
|
||||
combat_timer: 30 # The timer in ticks before being considered out of combat
|
||||
|
||||
# The minimum change in ping required for it to be considered a lag spike.
|
||||
@@ -23,6 +26,19 @@ runnable:
|
||||
# the threshold, the previous ping value is used to avoid calculation inaccuracies.
|
||||
spike_threshold: 20
|
||||
|
||||
# OPTIONS: KEEPALIVE, PING, TRANSACTION - PING and TRANSACTION are aliases for each other and are effectively the same
|
||||
# The packet type used to measure ping by the runnable.
|
||||
# KEEPALIVE is the most accurate however sending too many of them too often (such as using a runnable with a low interval)
|
||||
# - May disconnect players, especially laggy ones if sent too often
|
||||
# - The default interval of 20 ticks or 1 second
|
||||
# means it is in theory possible for a player to have a ping spike in-between two sword attacks
|
||||
# and have it immediately spike back down, slightly throwing off knockback synchronization
|
||||
# in practice this is very rare and the extra ping accuracy and precision is more valued
|
||||
# PING/TRANSACTION can be sent more often (and therefore better detect ping spikes) but are less precise
|
||||
# ping measured in ms with PING/TRANSACTION is typically within ± 5ms of actual but can be up to 50ms off
|
||||
ping_strategy: "KEEPALIVE"
|
||||
|
||||
# This setting has yet to be implemented. Enable if you want it to be enabled as soon as the next update add support
|
||||
enable_experimental_offground: false
|
||||
|
||||
enable_message: "&aSuccessfully enabled KnockbackSync."
|
||||
@@ -36,6 +52,3 @@ 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."
|
||||
|
||||
# Read FAQ!
|
||||
ping_offset: 25
|
||||
+1
-33
@@ -12,17 +12,6 @@ val shadeThisThing: Configuration by configurations.creating {
|
||||
isTransitive = true
|
||||
}
|
||||
|
||||
//sourceSets {
|
||||
// main {
|
||||
// java {
|
||||
// srcDir(project(":common").sourceSets.main.get().java.srcDirs)
|
||||
// }
|
||||
// resources {
|
||||
// srcDir(project(":common").sourceSets.main.get().resources.srcDirs)
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
|
||||
// TODO migrate to only including sourceset for compile, test and javadoc tasks
|
||||
// Currently must build with gradle build -x test to skip test
|
||||
tasks.withType<JavaCompile>().configureEach {
|
||||
@@ -37,19 +26,6 @@ tasks.named<JavaCompile>("compileTestJava") {
|
||||
exclude("**/*")
|
||||
}
|
||||
|
||||
//tasks.withType<Test>().configureEach {
|
||||
// classpath += project(":common").sourceSets["main"].output + configurations["testRuntimeClasspath"]
|
||||
//}
|
||||
|
||||
//tasks.named<Jar>("sourcesJar") {
|
||||
// from(project(":common").sourceSets.main.get().allSource)
|
||||
//}
|
||||
|
||||
tasks.jar {
|
||||
// from(project(":common").sourceSets.named("main").get().output)
|
||||
// from(project(":common").sourceSets.main.get().resources)
|
||||
}
|
||||
|
||||
dependencies {
|
||||
implementation(project(":common"))
|
||||
|
||||
@@ -63,20 +39,12 @@ dependencies {
|
||||
|
||||
include(modImplementation("me.lucko:fabric-permissions-api:0.3.1")!!)
|
||||
include(modImplementation("com.github.retrooper:packetevents-fabric:2.5.8-SNAPSHOT")!!)
|
||||
include(modImplementation("org.incendo:cloud-fabric:2.0.0-beta.9")!!)
|
||||
|
||||
shadeThisThing(implementation("com.fasterxml.jackson.core:jackson-databind:2.17.2")!!)
|
||||
shadeThisThing(implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.2")!!)
|
||||
shadeThisThing(implementation("org.kohsuke:github-api:1.326")!!)
|
||||
|
||||
// include(implementation("com.fasterxml.jackson.core:jackson-databind:2.17.2")!!)
|
||||
// include(implementation("com.fasterxml.jackson.dataformat:jackson-dataformat-yaml:2.17.2")!!)
|
||||
// include(implementation("org.kohsuke:github-api:1.326")!!)
|
||||
|
||||
// include(implementation("org.kohsuke:github-api:1.326") {
|
||||
// exclude(group = "commons-io", module = "commons-io")
|
||||
// exclude(group = "org.apache.commons", module = "commons-lang3")
|
||||
// })
|
||||
|
||||
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
|
||||
compileOnly("org.projectlombok:lombok:1.18.34")
|
||||
annotationProcessor("org.projectlombok:lombok:1.18.34")
|
||||
|
||||
+32
-43
@@ -1,24 +1,25 @@
|
||||
package me.caseload.knockbacksync.world;
|
||||
package me.caseload.knockbacksync;
|
||||
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import io.github.retrooper.packetevents.factory.fabric.FabricPacketEventsBuilder;
|
||||
import me.caseload.knockbacksync.KBSyncFabricLoaderMod;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.FabricSenderFactory;
|
||||
import me.caseload.knockbacksync.command.KnockbackSyncCommand;
|
||||
import lombok.Getter;
|
||||
import me.caseload.knockbacksync.listener.fabric.FabricPlayerDamageListener;
|
||||
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.permission.FabricPermissionChecker;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
import me.caseload.knockbacksync.scheduler.FabricSchedulerAdapter;
|
||||
import me.caseload.knockbacksync.sender.FabricPlayerSelectorParser;
|
||||
import me.caseload.knockbacksync.sender.FabricSenderFactory;
|
||||
import me.caseload.knockbacksync.stats.custom.FabricStatsManager;
|
||||
import me.caseload.knockbacksync.stats.custom.PluginJarHashProvider;
|
||||
import net.fabricmc.fabric.api.command.v2.CommandRegistrationCallback;
|
||||
import me.caseload.knockbacksync.world.FabricServer;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
import net.fabricmc.loader.api.ModContainer;
|
||||
import net.minecraft.commands.Commands;
|
||||
import org.incendo.cloud.execution.ExecutionCoordinator;
|
||||
import org.incendo.cloud.fabric.FabricServerCommandManager;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
@@ -33,23 +34,19 @@ public class KBSyncFabricBase extends KnockbackSyncBase {
|
||||
|
||||
private final Logger logger = Logger.getLogger(KBSyncFabricLoaderMod.class.getName());
|
||||
private final FabricPermissionChecker permissionChecker = new FabricPermissionChecker();
|
||||
@Getter
|
||||
private final FabricSenderFactory fabricSenderFactory = new FabricSenderFactory(this);
|
||||
|
||||
public KBSyncFabricBase() {
|
||||
statsManager = new FabricStatsManager();
|
||||
platformServer = new FabricServer();
|
||||
URL jarUrl = null;
|
||||
Optional<ModContainer> modContainer = FabricLoader.getInstance().getModContainer("knockbacksync");
|
||||
if (modContainer.isPresent()) {
|
||||
String jarPath = modContainer.get().getRootPath().getFileSystem().toString();
|
||||
jarPath = jarPath.replaceAll("^jar:", "").replaceAll("!/$", "");
|
||||
try {
|
||||
jarUrl = new File(jarPath).toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
pluginJarHashProvider = new PluginJarHashProvider(jarUrl);
|
||||
super.setSenderFactory(new FabricSenderFactory(this));
|
||||
super.configManager = new ConfigManager();
|
||||
super.playerSelectorParser = new FabricPlayerSelectorParser<>();
|
||||
super.commandManager = new FabricServerCommandManager<>(
|
||||
ExecutionCoordinator.simpleCoordinator(),
|
||||
fabricSenderFactory
|
||||
);
|
||||
super.statsManager = new FabricStatsManager();
|
||||
super.platformServer = new FabricServer();
|
||||
super.pluginJarHashProvider = new PluginJarHashProvider(getJarURL());
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -86,20 +83,6 @@ public class KBSyncFabricBase extends KnockbackSyncBase {
|
||||
new FabricTickRateChangeListener().register();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void registerCommands() {
|
||||
// ServerLifecycleEvents.SERVER_STARTED.register(server -> {
|
||||
// CommandDispatcher<CommandSourceStack> dispatcher = server.getCommands().getDispatcher();
|
||||
// dispatcher.register(KnockbackSyncCommand.build());
|
||||
// });
|
||||
CommandRegistrationCallback.EVENT.register((dispatcher, registryAccess, environment) -> {
|
||||
dispatcher.register(KnockbackSyncCommand.build());
|
||||
dispatcher.register(
|
||||
Commands.literal("kbsync")
|
||||
.redirect(dispatcher.getRoot().getChild("knockbacksync")));
|
||||
});
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getVersion() {
|
||||
return FabricLoader.getInstance().getModContainer("knockbacksync")
|
||||
@@ -126,12 +109,18 @@ public class KBSyncFabricBase extends KnockbackSyncBase {
|
||||
return permissionChecker;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void initializePacketEvents() {
|
||||
PacketEvents.getAPI().getSettings()
|
||||
.checkForUpdates(false)
|
||||
.debug(false);
|
||||
|
||||
PacketEvents.getAPI().init();
|
||||
private URL getJarURL() {
|
||||
URL jarUrl = null;
|
||||
Optional<ModContainer> modContainer = FabricLoader.getInstance().getModContainer("knockbacksync");
|
||||
if (modContainer.isPresent()) {
|
||||
String jarPath = modContainer.get().getRootPath().getFileSystem().toString();
|
||||
jarPath = jarPath.replaceAll("^jar:", "").replaceAll("!/$", "");
|
||||
try {
|
||||
jarUrl = new File(jarPath).toURI().toURL();
|
||||
} catch (MalformedURLException e) {
|
||||
throw new RuntimeException(e);
|
||||
}
|
||||
}
|
||||
return jarUrl;
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,5 @@
|
||||
package me.caseload.knockbacksync;
|
||||
|
||||
import me.caseload.knockbacksync.world.KBSyncFabricBase;
|
||||
import net.fabricmc.api.ModInitializer;
|
||||
import net.fabricmc.fabric.api.event.lifecycle.v1.ServerLifecycleEvents;
|
||||
import net.fabricmc.loader.api.FabricLoader;
|
||||
@@ -9,8 +8,6 @@ import net.minecraft.server.MinecraftServer;
|
||||
|
||||
public class KBSyncFabricLoaderMod implements PreLaunchEntrypoint, ModInitializer {
|
||||
|
||||
// private static MinecraftServer SERVER;
|
||||
|
||||
private final KnockbackSyncBase core = new KBSyncFabricBase();
|
||||
|
||||
public static MinecraftServer getServer() {
|
||||
@@ -20,13 +17,6 @@ public class KBSyncFabricLoaderMod implements PreLaunchEntrypoint, ModInitialize
|
||||
@Override
|
||||
public void onPreLaunch() {
|
||||
core.load();
|
||||
// ServerLifecycleEvents.SERVER_STARTING.register((minecraftServer -> {
|
||||
// SERVER = minecraftServer;
|
||||
// core.initializeScheduler();
|
||||
// core.configManager.loadConfig(false);
|
||||
// core.statsManager.init();
|
||||
// core.checkForUpdates();
|
||||
// }));
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -40,8 +30,5 @@ public class KBSyncFabricLoaderMod implements PreLaunchEntrypoint, ModInitialize
|
||||
core.scheduler.shutdown();
|
||||
core.statsManager.getMetrics().shutdown();
|
||||
});
|
||||
|
||||
// SenderFactory<KnockbackSyncBase, FabricCommandSource> fabricSenderFactory = new FabricSenderFactory(null);
|
||||
// LiteralArgumentBuilder<FabricCommandSource> fabricCommand = ReloadSubCommand.build(fabricSenderFactory);
|
||||
}
|
||||
}
|
||||
@@ -1,33 +0,0 @@
|
||||
package me.caseload.knockbacksync.command;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import me.caseload.knockbacksync.command.subcommand.*;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import me.caseload.knockbacksync.util.CommandUtil;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
|
||||
public class KnockbackSyncCommand implements Command<CommandSourceStack> {
|
||||
|
||||
public static LiteralArgumentBuilder<CommandSourceStack> build() {
|
||||
return Commands.literal("knockbacksync")
|
||||
.then(PingSubCommand.build())
|
||||
.then(ReloadSubCommand.build())
|
||||
.then(StatusSubCommand.build())
|
||||
.then(ToggleSubCommand.build())
|
||||
.then(ToggleOffGroundSubcommand.build())
|
||||
.executes(new KnockbackSyncCommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
||||
CommandUtil.sendSuccessMessage(context, ChatUtil.translateAlternateColorCodes(
|
||||
'&',
|
||||
"&6This server is running the &eKnockbackSync &6plugin. &bhttps://github.com/CASELOAD7000/knockback-sync"
|
||||
));
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
@@ -1,44 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.command.PlatformSender;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.player.PlayerData;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import me.caseload.knockbacksync.util.CommandUtil;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.commands.arguments.selector.EntitySelector;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import static me.caseload.knockbacksync.util.ChatUtil.getPingMessage;
|
||||
|
||||
public class PingSubCommand {
|
||||
public static LiteralArgumentBuilder<CommandSourceStack> build() {
|
||||
return Commands.literal("ping")
|
||||
.requires(source -> true)
|
||||
.executes(context -> { // Added .executes() here to handle no target
|
||||
if (context.getSource().getEntity() instanceof ServerPlayer sender) {
|
||||
CommandUtil.sendSuccessMessage(context, () -> Component.literal(getPingMessage(sender.getUUID(), null)));
|
||||
} else {
|
||||
CommandUtil.sendFailureMessage(context, "You must specify a player to use this command from the console.");
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
.then(Commands.argument("target", EntityArgument.player())
|
||||
.executes(context -> {
|
||||
EntitySelector selector = context.getArgument("target", EntitySelector.class);
|
||||
ServerPlayer target = selector.findSinglePlayer(context.getSource());
|
||||
if (context.getSource().getEntity() instanceof ServerPlayer sender) {
|
||||
CommandUtil.sendSuccessMessage(context, getPingMessage(sender.getUUID(), target.getUUID()));
|
||||
} else {
|
||||
CommandUtil.sendSuccessMessage(context, getPingMessage(PlatformSender.CONSOLE_UUID, target.getUUID()));
|
||||
}
|
||||
return 1;
|
||||
})
|
||||
);
|
||||
}
|
||||
}
|
||||
-29
@@ -1,29 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import me.caseload.knockbacksync.util.CommandUtil;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
|
||||
public class ReloadSubCommand {
|
||||
public static LiteralArgumentBuilder<CommandSourceStack> build() {
|
||||
return Commands.literal("reload")
|
||||
.requires(source -> KnockbackSyncBase.INSTANCE.getPermissionChecker().hasPermission(source, "knockbacksync.reload", false))
|
||||
.executes(context -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
configManager.loadConfig(true);
|
||||
|
||||
String rawReloadMessage = configManager.getReloadMessage();
|
||||
String reloadMessage = ChatUtil.translateAlternateColorCodes('&', rawReloadMessage);
|
||||
|
||||
// Send the message to the command source (the player or console that executed the command)
|
||||
CommandUtil.sendSuccessMessage(context, reloadMessage);
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
});
|
||||
}
|
||||
}
|
||||
-81
@@ -1,81 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import me.caseload.knockbacksync.util.CommandUtil;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.commands.arguments.selector.EntitySelector;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class StatusSubCommand implements Command<CommandSourceStack> {
|
||||
|
||||
private static final PermissionChecker permissionChecker = KnockbackSyncBase.INSTANCE.getPermissionChecker();
|
||||
|
||||
public static LiteralArgumentBuilder<CommandSourceStack> build() {
|
||||
return Commands.literal("status")
|
||||
.requires(source -> permissionChecker.hasPermission(source, "knockbacksync.status.self", true)) // Requires at least self permission
|
||||
.executes(new StatusSubCommand()) // Execute for self status
|
||||
.then(Commands.argument("target", EntityArgument.player())
|
||||
.requires(source -> permissionChecker.hasPermission(source, "knockbacksync.status.other", true)) // Requires other permission for target
|
||||
.executes(context -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
EntitySelector selector = context.getArgument("target", EntitySelector.class);
|
||||
ServerPlayer target = selector.findSinglePlayer(context.getSource());
|
||||
ServerPlayer sender = context.getSource().getPlayer();
|
||||
showPlayerStatus(context, null, target, configManager);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}));
|
||||
}
|
||||
|
||||
private static void showPlayerStatus(CommandContext<CommandSourceStack> context, ServerPlayer sender, ServerPlayer target, ConfigManager configManager) {
|
||||
boolean globalStatus = configManager.isToggled();
|
||||
UUID uuid = target.getUUID();
|
||||
boolean playerStatus = PlayerDataManager.containsPlayerData(uuid);
|
||||
|
||||
if (!globalStatus) {
|
||||
CommandUtil.sendSuccessMessage(context, ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("player_status_message", "&e%player%'s KnockbackSync status: ")
|
||||
.replace("%player%", target.getDisplayName().getString())) +
|
||||
ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("player_disabled_global_message", "&cDisabled (Global toggle is off)")));
|
||||
} else {
|
||||
CommandUtil.sendSuccessMessage(context, ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("player_status_message", "&e%player%'s KnockbackSync status: ")
|
||||
.replace("%player%", target.getDisplayName().getString())) +
|
||||
(playerStatus
|
||||
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
|
||||
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled")));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
|
||||
// Show global status
|
||||
boolean globalStatus = configManager.isToggled();
|
||||
CommandUtil.sendSuccessMessage(context, ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getConfigWrapper().getString("global_status_message", "&eGlobal KnockbackSync status: ")) +
|
||||
(globalStatus
|
||||
? ChatUtil.translateAlternateColorCodes('&', "&aEnabled")
|
||||
: ChatUtil.translateAlternateColorCodes('&', "&cDisabled")));
|
||||
|
||||
// Show player status for the sender (no target specified)
|
||||
if (context.getSource().getEntity() instanceof ServerPlayer sender) {
|
||||
showPlayerStatus(context, sender, sender, configManager);
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
-36
@@ -1,36 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import me.caseload.knockbacksync.util.CommandUtil;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
|
||||
public class ToggleOffGroundSubcommand implements Command<CommandSourceStack> {
|
||||
|
||||
private static final PermissionChecker permissionChecker = KnockbackSyncBase.INSTANCE.getPermissionChecker();
|
||||
|
||||
public static LiteralArgumentBuilder<CommandSourceStack> build() {
|
||||
return Commands.literal("toggleoffground")
|
||||
.requires(source -> permissionChecker.hasPermission(source, "knockbacksync.toggleoffground", false))
|
||||
.executes(new ToggleOffGroundSubcommand());
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(CommandContext<CommandSourceStack> context) {
|
||||
boolean toggledState = !KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().getBoolean("enable_experimental_offground", false);
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().set("enable_experimental_offground", toggledState);
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().saveConfig();
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
toggledState ?
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().getString("enable_experimental_offground_message", "&aSuccessfully enabled offground experiment.") :
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().getString("disable_experimental_offground_message", "&cSuccessfully disabled offground experiment.")
|
||||
);
|
||||
CommandUtil.sendSuccessMessage(context, message);
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
-118
@@ -1,118 +0,0 @@
|
||||
package me.caseload.knockbacksync.command.subcommand;
|
||||
|
||||
import com.mojang.brigadier.Command;
|
||||
import com.mojang.brigadier.builder.LiteralArgumentBuilder;
|
||||
import com.mojang.brigadier.context.CommandContext;
|
||||
import com.mojang.brigadier.exceptions.CommandSyntaxException;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.manager.ConfigManager;
|
||||
import me.caseload.knockbacksync.manager.PlayerDataManager;
|
||||
import me.caseload.knockbacksync.permission.PermissionChecker;
|
||||
import me.caseload.knockbacksync.player.PlayerData;
|
||||
import me.caseload.knockbacksync.util.ChatUtil;
|
||||
import me.caseload.knockbacksync.util.CommandUtil;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.commands.Commands;
|
||||
import net.minecraft.commands.arguments.EntityArgument;
|
||||
import net.minecraft.commands.arguments.selector.EntitySelector;
|
||||
import net.minecraft.server.level.ServerPlayer;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
import static me.caseload.knockbacksync.util.CommandUtil.sendFailureMessage;
|
||||
import static me.caseload.knockbacksync.util.CommandUtil.sendSuccessMessage;
|
||||
|
||||
public class ToggleSubCommand implements Command<CommandSourceStack> {
|
||||
|
||||
private static final PermissionChecker permissionChecker = KnockbackSyncBase.INSTANCE.getPermissionChecker();
|
||||
|
||||
public static LiteralArgumentBuilder<CommandSourceStack> build() {
|
||||
return Commands.literal("toggle")
|
||||
.requires(source -> permissionChecker.hasPermission(source, "knockbacksync.toggle.self", true)) // Requires at least self permission
|
||||
.executes(new ToggleSubCommand()) // Execute for self toggle
|
||||
.then(Commands.argument("target", EntityArgument.player())
|
||||
// .requires(source -> permissionChecker.hasPermission(source, "knockbacksync.toggle.other", true)) // Requires other permission for target
|
||||
.executes(context -> {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
EntitySelector selector = context.getArgument("target", EntitySelector.class);
|
||||
ServerPlayer target = selector.findSinglePlayer(context.getSource());
|
||||
ServerPlayer sender = context.getSource().getPlayerOrException();
|
||||
if (!target.equals(sender) && permissionChecker.hasPermission(context.getSource(), "knockbacksync.toggle.self", true)) {
|
||||
CommandUtil.sendFailureMessage(context, "You do not have permission to toggle the knockback of other player's.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (!configManager.isToggled()) {
|
||||
sendSuccessMessage(context, ChatUtil.translateAlternateColorCodes('&', "&cKnockbacksync is currently disabled on this server. Contact your server administrator for more information."));
|
||||
} else {
|
||||
togglePlayerKnockback(target, configManager, context);
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}));
|
||||
}
|
||||
|
||||
private static void toggleGlobalKnockback(ConfigManager configManager, CommandContext<CommandSourceStack> context) {
|
||||
boolean toggledState = !configManager.isToggled();
|
||||
configManager.setToggled(toggledState);
|
||||
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().getConfigWrapper().set("enabled", toggledState);
|
||||
KnockbackSyncBase.INSTANCE.getConfigManager().saveConfig();
|
||||
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
toggledState ? configManager.getEnableMessage() : configManager.getDisableMessage()
|
||||
);
|
||||
sendSuccessMessage(context, message);
|
||||
}
|
||||
|
||||
private static void togglePlayerKnockback(ServerPlayer target, ConfigManager configManager, CommandContext<CommandSourceStack> context) {
|
||||
UUID uuid = target.getUUID();
|
||||
|
||||
if (PlayerDataManager.shouldExempt(uuid)) {
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
configManager.getPlayerIneligibleMessage()
|
||||
).replace("%player%", target.getDisplayName().getString());
|
||||
|
||||
sendSuccessMessage(context, message);
|
||||
return;
|
||||
}
|
||||
|
||||
boolean hasPlayerData = PlayerDataManager.containsPlayerData(uuid);
|
||||
if (hasPlayerData)
|
||||
PlayerDataManager.removePlayerData(uuid);
|
||||
else {
|
||||
PlayerDataManager.addPlayerData(uuid, new PlayerData(KnockbackSyncBase.INSTANCE.platformServer.getPlayer(uuid)));
|
||||
// switch (KnockbackSyncBase.INSTANCE.platform) {
|
||||
// case BUKKIT:
|
||||
// case FOLIA:
|
||||
// org.bukkit.entity.Player player = org.bukkit.Bukkit.getPlayer(target.getUUID());
|
||||
// PlayerDataManager.addPlayerData(uuid, new PlayerData(target.getUUID());
|
||||
// case FABRIC:
|
||||
// PlayerDataManager.addPlayerData(uuid, new PlayerData(target));
|
||||
// }
|
||||
|
||||
}
|
||||
|
||||
String message = ChatUtil.translateAlternateColorCodes('&',
|
||||
hasPlayerData ? configManager.getPlayerDisableMessage() : configManager.
|
||||
getPlayerEnableMessage()
|
||||
).replace("%player%", target.getDisplayName().getString());
|
||||
|
||||
sendSuccessMessage(context, message);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int run(CommandContext<CommandSourceStack> context) throws CommandSyntaxException {
|
||||
ConfigManager configManager = KnockbackSyncBase.INSTANCE.getConfigManager();
|
||||
ServerPlayer sender = context.getSource().getPlayerOrException();
|
||||
|
||||
// Global toggle
|
||||
if (permissionChecker.hasPermission(context.getSource(), "knockbacksync.toggle.global", false)) {
|
||||
toggleGlobalKnockback(configManager, context);
|
||||
} else {
|
||||
sendSuccessMessage(context, ChatUtil.translateAlternateColorCodes('&', "&cYou don't have permission to toggle the global setting."));
|
||||
}
|
||||
|
||||
return Command.SINGLE_SUCCESS;
|
||||
}
|
||||
}
|
||||
@@ -21,7 +21,7 @@ public class ServerEntityMixin {
|
||||
@Final
|
||||
private Entity entity;
|
||||
|
||||
@Inject(method = "sendChanges", at = @At(value = "FIELD", target = "Lnet/minecraft/world/entity/Entity;hurtMarked:Z", ordinal = 1))
|
||||
@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();
|
||||
|
||||
+10
-6
@@ -1,28 +1,32 @@
|
||||
package me.caseload.knockbacksync.permission;
|
||||
|
||||
import me.caseload.knockbacksync.command.PlatformSender;
|
||||
import me.caseload.knockbacksync.player.FabricPlayer;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
import me.caseload.knockbacksync.sender.Sender;
|
||||
import me.lucko.fabric.api.permissions.v0.Permissions;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
|
||||
public class FabricPermissionChecker implements PermissionChecker {
|
||||
|
||||
public boolean hasPermission(CommandSourceStack source, String permission) {
|
||||
return Permissions.check(source, permission);
|
||||
return Permissions.check(source, permission, false);
|
||||
}
|
||||
|
||||
public boolean hasPermission(CommandSourceStack source, String permission, boolean defaultIfUnset) {
|
||||
return Permissions.check(source, permission, defaultIfUnset);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(Object object, String s, boolean defaultIfUnset) {
|
||||
if (object instanceof CommandSourceStack commandSourceStack) {
|
||||
public boolean hasPermission(Object nativeType, String s, boolean defaultIfUnset) {
|
||||
if (nativeType instanceof CommandSourceStack commandSourceStack) {
|
||||
return Permissions.check(commandSourceStack, s, defaultIfUnset);
|
||||
}
|
||||
throw new IllegalArgumentException();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean hasPermission(PlatformSender source, String s, boolean defaultIfUnset) {
|
||||
return false;
|
||||
public boolean hasPermission(Sender source, String s, boolean defaultIfUnset) {
|
||||
return source.hasPermission(s);
|
||||
}
|
||||
|
||||
@Override
|
||||
|
||||
+36
@@ -0,0 +1,36 @@
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import me.caseload.knockbacksync.player.FabricPlayer;
|
||||
import me.caseload.knockbacksync.player.PlatformPlayer;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
public class FabricPlayerSelectorAdapter implements PlayerSelector {
|
||||
private final org.incendo.cloud.minecraft.modded.data.SinglePlayerSelector fabricSelector;
|
||||
|
||||
public FabricPlayerSelectorAdapter(org.incendo.cloud.minecraft.modded.data.SinglePlayerSelector fabricSelector) {
|
||||
this.fabricSelector = fabricSelector;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isSingle() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public PlatformPlayer getSinglePlayer() {
|
||||
return new FabricPlayer(fabricSelector.single()); // Assuming your ServerPlayer can be cast to Player
|
||||
}
|
||||
|
||||
@Override
|
||||
public Collection<PlatformPlayer> getPlayers() {
|
||||
return Collections.singletonList(new FabricPlayer(fabricSelector.single())); // Assuming your ServerPlayer can be cast to Player
|
||||
}
|
||||
|
||||
@Override
|
||||
public String inputString() {
|
||||
return fabricSelector.inputString();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,27 @@
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.command.generic.AbstractPlayerSelectorParser;
|
||||
import me.caseload.knockbacksync.command.generic.PlayerSelector;
|
||||
import org.incendo.cloud.context.CommandContext;
|
||||
import org.incendo.cloud.minecraft.modded.parser.VanillaArgumentParsers;
|
||||
import org.incendo.cloud.parser.ParserDescriptor;
|
||||
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
|
||||
public class FabricPlayerSelectorParser<C> extends AbstractPlayerSelectorParser<C> {
|
||||
|
||||
@Override
|
||||
public ParserDescriptor<C, PlayerSelector> descriptor() {
|
||||
return createDescriptor();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected ParserDescriptor<C, ?> getPlatformSpecificDescriptor() {
|
||||
return VanillaArgumentParsers.singlePlayerSelectorParser();
|
||||
}
|
||||
|
||||
@Override
|
||||
protected CompletableFuture<PlayerSelector> adaptToCommonSelector(CommandContext<C> context, Object platformSpecificSelector) {
|
||||
return CompletableFuture.completedFuture(new FabricPlayerSelectorAdapter((org.incendo.cloud.minecraft.modded.data.SinglePlayerSelector) platformSpecificSelector));
|
||||
}
|
||||
}
|
||||
+27
-5
@@ -1,17 +1,19 @@
|
||||
package me.caseload.knockbacksync.command;
|
||||
package me.caseload.knockbacksync.sender;
|
||||
|
||||
import me.caseload.knockbacksync.KBSyncFabricBase;
|
||||
import me.caseload.knockbacksync.KnockbackSyncBase;
|
||||
import me.caseload.knockbacksync.mixin.CommandStackSourceAccessor;
|
||||
import me.caseload.knockbacksync.permission.FabricPermissionChecker;
|
||||
import me.caseload.knockbacksync.world.KBSyncFabricBase;
|
||||
import net.minecraft.commands.CommandSource;
|
||||
import net.minecraft.commands.CommandSourceStack;
|
||||
import net.minecraft.network.chat.Component;
|
||||
import net.minecraft.server.rcon.RconConsoleSource;
|
||||
import org.checkerframework.checker.nullness.qual.NonNull;
|
||||
import org.incendo.cloud.SenderMapper;
|
||||
|
||||
import java.util.UUID;
|
||||
|
||||
public class FabricSenderFactory extends SenderFactory<KBSyncFabricBase, CommandSourceStack> {
|
||||
public class FabricSenderFactory extends SenderFactory<KBSyncFabricBase, CommandSourceStack> implements SenderMapper<CommandSourceStack, Sender> {
|
||||
private final KBSyncFabricBase plugin;
|
||||
|
||||
public FabricSenderFactory(KBSyncFabricBase kbSyncFabricBase) {
|
||||
@@ -29,14 +31,14 @@ public class FabricSenderFactory extends SenderFactory<KBSyncFabricBase, Command
|
||||
if (commandSource.getEntity() != null) {
|
||||
return commandSource.getEntity().getUUID();
|
||||
}
|
||||
return PlatformSender.CONSOLE_UUID;
|
||||
return Sender.CONSOLE_UUID;
|
||||
}
|
||||
|
||||
@Override
|
||||
protected String getName(CommandSourceStack commandSource) {
|
||||
String name = commandSource.getTextName();
|
||||
if (commandSource.getEntity() != null && name.equals("Server")) {
|
||||
return PlatformSender.CONSOLE_NAME;
|
||||
return Sender.CONSOLE_NAME;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
@@ -59,6 +61,11 @@ public class FabricSenderFactory extends SenderFactory<KBSyncFabricBase, Command
|
||||
return ((FabricPermissionChecker) KnockbackSyncBase.INSTANCE.getPermissionChecker()).hasPermission(commandSource, node);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected boolean hasPermission(CommandSourceStack commandSource, String node, boolean defaultIfUnset) {
|
||||
return ((FabricPermissionChecker) KnockbackSyncBase.INSTANCE.getPermissionChecker()).hasPermission(commandSource, node, defaultIfUnset);
|
||||
}
|
||||
|
||||
@Override
|
||||
protected void performCommand(CommandSourceStack sender, String command) {
|
||||
// sender.getServer().getCommandManager().executeWithPrefix(sender, command);
|
||||
@@ -72,6 +79,21 @@ public class FabricSenderFactory extends SenderFactory<KBSyncFabricBase, Command
|
||||
(output == CommandSource.NULL && sender.getTextName().equals("")); // Functions
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull Sender map(@NonNull CommandSourceStack base) {
|
||||
return this.wrap(base);
|
||||
}
|
||||
|
||||
@Override
|
||||
public @NonNull CommandSourceStack reverse(@NonNull Sender mapped) {
|
||||
return this.unwrap(mapped);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void close() throws Exception {
|
||||
|
||||
}
|
||||
|
||||
// public static Text toNativeText(Component component) {
|
||||
// return Text.Serialization.fromJsonTree(GsonComponentSerializer.gson().serializeToTree(component), DynamicRegistryManager.EMPTY);
|
||||
// }
|
||||
Reference in new issue
Block a user