Compare commits
48
Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
15984b0a94 | ||
|
|
97de474b79 | ||
|
|
cea13a719d | ||
|
|
faa471b197 | ||
|
|
60f8812efd | ||
|
|
7e82f19961 | ||
|
|
27aae68f14 | ||
|
|
a65f24424f | ||
|
|
bfd3433423 | ||
|
|
09e6cec6ef | ||
|
|
4ffe6f4fc5 | ||
|
|
4aaeb579e7 | ||
|
|
487e9c6590 | ||
|
|
bdf7eb7c06 | ||
|
|
c70e5b8fff | ||
|
|
9599b1c631 | ||
|
|
85b42fa90e | ||
|
|
0c1a6c7775 | ||
|
|
d4508fa36b | ||
|
|
3cb1bb3792 | ||
|
|
faf0c7d3d6 | ||
|
|
c8ff1109e1 | ||
|
|
de0c28beab | ||
|
|
acdacffcc0 | ||
|
|
3cab3fe680 | ||
|
|
880a7b5e74 | ||
|
|
c4848efc8a | ||
|
|
0ddf0b5d22 | ||
|
|
fde6e03b98 | ||
|
|
55c084216d | ||
|
|
f3074e3934 | ||
|
|
748eb398b8 | ||
|
|
dc7f6dca93 | ||
|
|
472415e0d4 | ||
|
|
da61ff673a | ||
|
|
01ca8c894e | ||
|
|
f724d6d78e | ||
|
|
ee6183db90 | ||
|
|
e959ef37db | ||
|
|
f62d8602b8 | ||
|
|
bf44dd6855 | ||
|
|
1beedd77c3 | ||
|
|
c34ad88a13 | ||
|
|
619e7f1404 | ||
|
|
927b330c4b | ||
|
|
bff6854189 | ||
|
|
290bf9032e | ||
|
|
2629536ad7 |
No files matched your search
@@ -39,11 +39,11 @@ jobs:
|
||||
|
||||
steps:
|
||||
- name: Checkout repository
|
||||
uses: actions/checkout@v2
|
||||
uses: actions/checkout@v4
|
||||
|
||||
# Initializes the CodeQL tools for scanning.
|
||||
- name: Initialize CodeQL
|
||||
uses: github/codeql-action/init@v1
|
||||
uses: github/codeql-action/init@v3
|
||||
with:
|
||||
languages: ${{ matrix.language }}
|
||||
# If you wish to specify custom queries, you can do so here or in a config file.
|
||||
@@ -54,7 +54,7 @@ jobs:
|
||||
# Autobuild attempts to build any compiled languages (C/C++, C#, or Java).
|
||||
# If this step fails, then you should remove it and run the build manually (see below)
|
||||
- name: Autobuild
|
||||
uses: github/codeql-action/autobuild@v1
|
||||
uses: github/codeql-action/autobuild@v3
|
||||
|
||||
# ℹ️ Command-line programs to run using the OS shell.
|
||||
# 📚 https://git.io/JvXDl
|
||||
@@ -68,4 +68,4 @@ jobs:
|
||||
# make release
|
||||
|
||||
- name: Perform CodeQL Analysis
|
||||
uses: github/codeql-action/analyze@v1
|
||||
uses: github/codeql-action/analyze@v3
|
||||
@@ -19,9 +19,9 @@ jobs:
|
||||
packages: write
|
||||
|
||||
steps:
|
||||
- uses: actions/checkout@v3
|
||||
- uses: actions/checkout@v4
|
||||
- name: Set up JDK 17
|
||||
uses: actions/setup-java@v3
|
||||
uses: actions/setup-java@v4
|
||||
with:
|
||||
java-version: '17'
|
||||
distribution: 'temurin'
|
||||
@@ -29,10 +29,10 @@ jobs:
|
||||
settings-path: ${{ github.workspace }} # location for the settings.xml file
|
||||
|
||||
- name: Build with Gradle
|
||||
uses: gradle/gradle-build-action@67421db6bd0bf253fb4bd25b31ebb98943c375e1
|
||||
uses: gradle/actions/setup-gradle@v3
|
||||
with:
|
||||
arguments: build
|
||||
- name: Upload a Build Artifact
|
||||
uses: actions/upload-artifact@v3.1.0
|
||||
uses: actions/upload-artifact@v4
|
||||
with:
|
||||
path: /home/runner/work/Grim/Grim/build/libs/**.jar
|
||||
+7
-5
@@ -11,8 +11,8 @@ plugins {
|
||||
group = "ac.grim.grimac"
|
||||
version = "2.3.68"
|
||||
description = "Libre simulation anticheat designed for 1.21 with 1.8-1.21 support, powered by PacketEvents 2.0."
|
||||
java.sourceCompatibility = JavaVersion.VERSION_1_8
|
||||
java.targetCompatibility = JavaVersion.VERSION_1_8
|
||||
java.sourceCompatibility = JavaVersion.VERSION_17
|
||||
java.targetCompatibility = JavaVersion.VERSION_17
|
||||
|
||||
// Set to false for debug builds
|
||||
// You cannot live reload classes if the jar relocates dependencies
|
||||
@@ -44,13 +44,14 @@ dependencies {
|
||||
implementation("it.unimi.dsi:fastutil:8.5.13")
|
||||
implementation("github.scarsz:configuralize:1.4.0")
|
||||
|
||||
implementation("com.github.grimanticheat:grimapi:1193c4fa41")
|
||||
// Used for local testing: implementation("ac.grim.grimac:grimapi:1.0")
|
||||
//implementation("com.github.grimanticheat:grimapi:1193c4fa41")
|
||||
// Used for local testing: implementation("ac.grim.grimac:GRIMAPI:1.0")
|
||||
implementation("com.github.grimanticheat:grimapi:fc5634e444")
|
||||
|
||||
implementation("org.jetbrains:annotations:24.1.0")
|
||||
compileOnly("org.geysermc.floodgate:api:2.0-SNAPSHOT")
|
||||
compileOnly("org.spigotmc:spigot-api:1.18.2-R0.1-SNAPSHOT")
|
||||
compileOnly("com.viaversion:viaversion-api:4.9.4-SNAPSHOT")
|
||||
compileOnly("com.viaversion:viaversion-api:5.0.4-SNAPSHOT")
|
||||
//
|
||||
compileOnly("io.netty:netty-all:4.1.85.Final")
|
||||
}
|
||||
@@ -59,6 +60,7 @@ bukkit {
|
||||
name = "GrimAC"
|
||||
author = "GrimAC"
|
||||
main = "ac.grim.grimac.GrimAC"
|
||||
website = "https://grim.ac/"
|
||||
apiVersion = "1.13"
|
||||
foliaSupported = true
|
||||
|
||||
|
||||
Vendored
BIN
Binary file not shown.
+1
-1
@@ -1,6 +1,6 @@
|
||||
distributionBase=GRADLE_USER_HOME
|
||||
distributionPath=wrapper/dists
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.9-bin.zip
|
||||
distributionUrl=https\://services.gradle.org/distributions/gradle-8.10.1-bin.zip
|
||||
networkTimeout=10000
|
||||
validateDistributionUrl=true
|
||||
zipStoreBase=GRADLE_USER_HOME
|
||||
|
||||
@@ -1,17 +1,16 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.GrimAbstractAPI;
|
||||
import ac.grim.grimac.manager.*;
|
||||
import ac.grim.grimac.manager.config.BaseConfigManager;
|
||||
import ac.grim.grimac.utils.anticheat.PlayerDataManager;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.bukkit.plugin.java.JavaPlugin;
|
||||
|
||||
@Getter
|
||||
public enum GrimAPI {
|
||||
INSTANCE;
|
||||
|
||||
private final BaseConfigManager configManager = new BaseConfigManager();
|
||||
private final AlertManagerImpl alertManager = new AlertManagerImpl();
|
||||
private final SpectateManager spectateManager = new SpectateManager();
|
||||
private final DiscordManager discordManager = new DiscordManager();
|
||||
@@ -19,12 +18,10 @@ public enum GrimAPI {
|
||||
private final TickManager tickManager = new TickManager();
|
||||
private final GrimExternalAPI externalAPI = new GrimExternalAPI(this);
|
||||
private InitManager initManager;
|
||||
private ConfigManager configManager;
|
||||
private JavaPlugin plugin;
|
||||
|
||||
public void load(final JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
this.configManager = new ConfigManager();
|
||||
initManager = new InitManager();
|
||||
initManager.load();
|
||||
}
|
||||
@@ -32,7 +29,6 @@ public enum GrimAPI {
|
||||
public void start(final JavaPlugin plugin) {
|
||||
this.plugin = plugin;
|
||||
initManager.start();
|
||||
Bukkit.getServicesManager().register(GrimAbstractAPI.class, externalAPI, plugin, ServicePriority.Normal);
|
||||
}
|
||||
|
||||
public void stop(final JavaPlugin plugin) {
|
||||
|
||||
@@ -1,25 +1,34 @@
|
||||
package ac.grim.grimac;
|
||||
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.GrimAbstractAPI;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import ac.grim.grimac.api.alerts.AlertManager;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.events.GrimReloadEvent;
|
||||
import ac.grim.grimac.manager.config.ConfigManagerFileImpl;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.common.ConfigReloadObserver;
|
||||
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
|
||||
import io.github.retrooper.packetevents.util.SpigotReflectionUtil;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.plugin.PluginDescriptionFile;
|
||||
import org.bukkit.plugin.ServicePriority;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Map;
|
||||
import java.util.concurrent.CompletableFuture;
|
||||
import java.util.concurrent.ConcurrentHashMap;
|
||||
import java.util.function.Function;
|
||||
|
||||
//This is used for grim's external API. It has its own class just for organization.
|
||||
public class GrimExternalAPI implements GrimAbstractAPI, Initable {
|
||||
|
||||
public class GrimExternalAPI implements GrimAbstractAPI, ConfigReloadObserver, Initable {
|
||||
|
||||
private final GrimAPI api;
|
||||
|
||||
@@ -41,7 +50,8 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
|
||||
@Getter
|
||||
private final Map<String, Function<GrimUser, String>> variableReplacements = new ConcurrentHashMap<>();
|
||||
|
||||
@Getter private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
|
||||
@Getter
|
||||
private final Map<String, String> staticReplacements = new ConcurrentHashMap<>();
|
||||
|
||||
public String replaceVariables(GrimUser user, String content, boolean colors) {
|
||||
if (colors) content = ChatColor.translateAlternateColorCodes('&', content);
|
||||
@@ -56,12 +66,20 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
|
||||
|
||||
@Override
|
||||
public void registerVariable(String string, Function<GrimUser, String> replacement) {
|
||||
variableReplacements.put(string, replacement);
|
||||
if (replacement == null) {
|
||||
variableReplacements.remove(string);
|
||||
} else {
|
||||
variableReplacements.put(string, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void registerVariable(String variable, String replacement) {
|
||||
staticReplacements.put(variable, replacement);
|
||||
if (replacement == null) {
|
||||
staticReplacements.remove(variable);
|
||||
} else {
|
||||
staticReplacements.put(variable, replacement);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -70,34 +88,20 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
|
||||
return description.getVersion();
|
||||
}
|
||||
|
||||
private final Map<String, Function<Object, Object>> functions = new ConcurrentHashMap<>();
|
||||
|
||||
@Override
|
||||
public void registerFunction(String key, Function<Object, Object> function) {
|
||||
|
||||
if (function == null) {
|
||||
functions.remove(key);
|
||||
} else {
|
||||
functions.put(key, function);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public Function<Object, Object> getFunction(String key) {
|
||||
return null;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
GrimAPI.INSTANCE.getConfigManager().reload();
|
||||
//Reload checks for all players
|
||||
for (GrimPlayer grimPlayer : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
|
||||
grimPlayer.onReload();
|
||||
grimPlayer.updatePermissions();
|
||||
grimPlayer.punishmentManager.reload();
|
||||
for (AbstractCheck value : grimPlayer.checkManager.allChecks.values()) {
|
||||
value.reload();
|
||||
}
|
||||
});
|
||||
}
|
||||
//Restart
|
||||
GrimAPI.INSTANCE.getDiscordManager().start();
|
||||
GrimAPI.INSTANCE.getSpectateManager().start();
|
||||
GrimAPI.INSTANCE.getExternalAPI().start();
|
||||
return functions.get(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
@@ -106,16 +110,106 @@ public class GrimExternalAPI implements GrimAbstractAPI, Initable {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void start() {
|
||||
variableReplacements.put("%player%", GrimUser::getName);
|
||||
variableReplacements.put("%uuid%", user -> user.getUniqueId().toString());
|
||||
variableReplacements.put("%ping%", user -> user.getTransactionPing() + "");
|
||||
variableReplacements.put("%brand%", GrimUser::getBrand);
|
||||
variableReplacements.put("%h_sensitivity%", user -> ((int) Math.round(user.getHorizontalSensitivity() * 200)) + "");
|
||||
variableReplacements.put("%v_sensitivity%", user -> ((int) Math.round(user.getVerticalSensitivity() * 200)) + "");
|
||||
variableReplacements.put("%fast_math%", user -> !user.isVanillaMath() + "");
|
||||
variableReplacements.put("%tps%", user -> String.format("%.2f", SpigotReflectionUtil.getTPS()));
|
||||
variableReplacements.put("%version%", GrimUser::getVersionName);
|
||||
variableReplacements.put("%prefix%", user -> ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("prefix", "&bGrim &8»")));
|
||||
public ConfigManager getConfigManager() {
|
||||
return configManager;
|
||||
}
|
||||
|
||||
private ConfigManager configManager = null;
|
||||
private final ConfigManagerFileImpl configManagerFile = new ConfigManagerFileImpl();
|
||||
private boolean started = false;
|
||||
|
||||
// on load, load the config & register the service
|
||||
public void load() {
|
||||
reload(configManagerFile);
|
||||
Bukkit.getServicesManager().register(GrimAbstractAPI.class, this, GrimAPI.INSTANCE.getPlugin(), ServicePriority.Normal);
|
||||
}
|
||||
|
||||
// handles any config loading that's needed to be done after load
|
||||
@Override
|
||||
public void start() {
|
||||
started = true;
|
||||
try {
|
||||
GrimAPI.INSTANCE.getConfigManager().start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload(ConfigManager config) {
|
||||
if (config.isLoadedAsync() && started) {
|
||||
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> successfulReload(config));
|
||||
} else {
|
||||
successfulReload(config);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CompletableFuture<Boolean> reloadAsync(ConfigManager config) {
|
||||
if (config.isLoadedAsync() && started) {
|
||||
CompletableFuture<Boolean> future = new CompletableFuture<>();
|
||||
FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> future.complete(successfulReload(config)));
|
||||
return future;
|
||||
}
|
||||
return CompletableFuture.completedFuture(successfulReload(config));
|
||||
}
|
||||
|
||||
private boolean successfulReload(ConfigManager config) {
|
||||
try {
|
||||
config.reload();
|
||||
GrimAPI.INSTANCE.getConfigManager().load(config);
|
||||
if (started) GrimAPI.INSTANCE.getConfigManager().start();
|
||||
onReload(config);
|
||||
if (started) FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(true)));
|
||||
return true;
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
if (started) FoliaScheduler.getAsyncScheduler().runNow(GrimAPI.INSTANCE.getPlugin(),
|
||||
o -> Bukkit.getPluginManager().callEvent(new GrimReloadEvent(false)));
|
||||
return false;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager newConfig) {
|
||||
if (newConfig == null) {
|
||||
LogUtil.warn("ConfigManager not set. Using default config file manager.");
|
||||
configManager = configManagerFile;
|
||||
} else {
|
||||
configManager = newConfig;
|
||||
}
|
||||
// Update variables
|
||||
updateVariables();
|
||||
// Restart
|
||||
GrimAPI.INSTANCE.getDiscordManager().start();
|
||||
GrimAPI.INSTANCE.getSpectateManager().start();
|
||||
// Don't reload players if the plugin hasn't started yet
|
||||
if (!started) return;
|
||||
// Reload checks for all players
|
||||
for (GrimPlayer grimPlayer : GrimAPI.INSTANCE.getPlayerDataManager().getEntries()) {
|
||||
ChannelHelper.runInEventLoop(grimPlayer.user.getChannel(), () -> {
|
||||
grimPlayer.updatePermissions();
|
||||
grimPlayer.reload(configManager);
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
private void updateVariables() {
|
||||
variableReplacements.putIfAbsent("%player%", GrimUser::getName);
|
||||
variableReplacements.putIfAbsent("%uuid%", user -> user.getUniqueId().toString());
|
||||
variableReplacements.putIfAbsent("%ping%", user -> user.getTransactionPing() + "");
|
||||
variableReplacements.putIfAbsent("%brand%", GrimUser::getBrand);
|
||||
variableReplacements.putIfAbsent("%h_sensitivity%", user -> ((int) Math.round(user.getHorizontalSensitivity() * 200)) + "");
|
||||
variableReplacements.putIfAbsent("%v_sensitivity%", user -> ((int) Math.round(user.getVerticalSensitivity() * 200)) + "");
|
||||
variableReplacements.putIfAbsent("%fast_math%", user -> !user.isVanillaMath() + "");
|
||||
variableReplacements.putIfAbsent("%tps%", user -> String.format("%.2f", SpigotReflectionUtil.getTPS()));
|
||||
variableReplacements.putIfAbsent("%version%", GrimUser::getVersionName);
|
||||
// static variables
|
||||
staticReplacements.putIfAbsent("%prefix%", ChatColor.translateAlternateColorCodes('&', GrimAPI.INSTANCE.getConfigManager().getPrefix()));
|
||||
staticReplacements.putIfAbsent("%grim_version%", getGrimVersion());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,11 +2,12 @@ package ac.grim.grimac.checks;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.events.FlagEvent;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.common.ConfigReloadObserver;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import github.scarsz.configuralize.DynamicConfig;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -14,7 +15,7 @@ import org.bukkit.Bukkit;
|
||||
|
||||
// Class from https://github.com/Tecnio/AntiCheatBase/blob/master/src/main/java/me/tecnio/anticheat/check/Check.java
|
||||
@Getter
|
||||
public class Check implements AbstractCheck {
|
||||
public class Check implements AbstractCheck, ConfigReloadObserver {
|
||||
protected final GrimPlayer player;
|
||||
|
||||
public double violations;
|
||||
@@ -53,7 +54,7 @@ public class Check implements AbstractCheck {
|
||||
this.experimental = checkData.experimental();
|
||||
this.description = checkData.description();
|
||||
}
|
||||
|
||||
//
|
||||
reload();
|
||||
}
|
||||
|
||||
@@ -81,7 +82,7 @@ public class Check implements AbstractCheck {
|
||||
}
|
||||
|
||||
public final boolean flag() {
|
||||
if (player.disableGrim || (experimental && !GrimAPI.INSTANCE.getConfigManager().isExperimentalChecks()) || exempted)
|
||||
if (player.disableGrim || (experimental && !player.isExperimentalChecks()) || exempted)
|
||||
return false; // Avoid calling event if disabled
|
||||
|
||||
FlagEvent event = new FlagEvent(player, this);
|
||||
@@ -107,23 +108,24 @@ public class Check implements AbstractCheck {
|
||||
violations = Math.max(0, violations - decay);
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
decay = getConfig().getDoubleElse(configName + ".decay", decay);
|
||||
setbackVL = getConfig().getDoubleElse(configName + ".setbackvl", setbackVL);
|
||||
|
||||
@Override
|
||||
public void reload(ConfigManager configuration) {
|
||||
decay = configuration.getDoubleElse(configName + ".decay", decay);
|
||||
setbackVL = configuration.getDoubleElse(configName + ".setbackvl", setbackVL);
|
||||
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
|
||||
|
||||
updateExempted();
|
||||
onReload(configuration);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
|
||||
}
|
||||
|
||||
public boolean alert(String verbose) {
|
||||
return player.punishmentManager.handleAlert(player, verbose, this);
|
||||
}
|
||||
|
||||
public DynamicConfig getConfig() {
|
||||
return GrimAPI.INSTANCE.getConfigManager().getConfig();
|
||||
}
|
||||
|
||||
public boolean setbackIfAboveSetbackVL() {
|
||||
if (getViolations() > setbackVL) {
|
||||
return player.getSetbackTeleportUtil().executeViolationSetback();
|
||||
@@ -144,5 +146,10 @@ public class Check implements AbstractCheck {
|
||||
packetType == PacketType.Play.Client.WINDOW_CONFIRMATION;
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
@@ -19,12 +19,14 @@ public class AimModulo360 extends Check implements RotationCheck {
|
||||
|
||||
@Override
|
||||
public void process(final RotationUpdate rotationUpdate) {
|
||||
lastDeltaYaw = rotationUpdate.getDeltaXRot();
|
||||
if (player.packetStateData.lastPacketWasTeleport) return;
|
||||
|
||||
if (player.xRot < 360 && player.xRot > -360 && Math.abs(rotationUpdate.getDeltaXRot()) > 320 && Math.abs(lastDeltaYaw) < 30) {
|
||||
flagAndAlert();
|
||||
} else {
|
||||
reward();
|
||||
}
|
||||
|
||||
lastDeltaYaw = rotationUpdate.getDeltaXRot();
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
@@ -39,10 +40,6 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
return player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || getBlockDamage(player, pos) < 1;
|
||||
}
|
||||
|
||||
private String formatted(Vector3i vec) {
|
||||
return vec == null ? "null" : vec.x + ", " + vec.y + ", " + vec.z;
|
||||
}
|
||||
|
||||
public void handle(PacketReceiveEvent event, WrapperPlayClientPlayerDigging dig) {
|
||||
if (dig.getAction() == DiggingAction.START_DIGGING) {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
@@ -57,7 +54,7 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
final Vector3i pos = dig.getBlockPosition();
|
||||
|
||||
if (shouldExempt(pos)) {
|
||||
lastCancelledBlock = null;
|
||||
lastCancelledBlock = pos;
|
||||
lastLastBlock = null;
|
||||
lastBlock = null;
|
||||
return;
|
||||
@@ -66,7 +63,7 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
if (!pos.equals(lastBlock)) {
|
||||
// https://github.com/GrimAnticheat/Grim/issues/1512
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4) || (!lastBlockWasInstantBreak && pos.equals(lastCancelledBlock))) {
|
||||
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + formatted(lastBlock) + ", pos=" + formatted(pos))) {
|
||||
if (flagAndAlert("action=CANCELLED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
@@ -87,7 +84,7 @@ public class BadPacketsZ extends Check implements PacketCheck {
|
||||
|
||||
// when a player looks away from the mined block, they send a cancel, and if they look at it again, they don't send another start. (thanks mojang!)
|
||||
if (!pos.equals(lastCancelledBlock) && (!lastBlockWasInstantBreak || player.getClientVersion().isOlderThan(ClientVersion.V_1_14_4)) && !pos.equals(lastBlock)) {
|
||||
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + formatted(lastBlock) + ", pos=" + formatted(pos))) {
|
||||
if (flagAndAlert("action=FINISHED_DIGGING" + ", last=" + MessageUtil.toUnlabledString(lastBlock) + ", pos=" + MessageUtil.toUnlabledString(pos))) {
|
||||
if (shouldModifyPackets()) {
|
||||
event.setCancelled(true);
|
||||
player.onPacketCancel();
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
// along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
package ac.grim.grimac.checks.impl.combat;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
@@ -201,8 +202,9 @@ public class Reach extends Check implements PacketCheck {
|
||||
|
||||
// +3 would be 3 + 3 = 6, which is the pre-1.20.5 behaviour, preventing "Missed Hitbox"
|
||||
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_ENTITY_INTERACTION_RANGE) + 3;
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
for (Vector lookVec : possibleLookDirs) {
|
||||
for (double eye : player.getPossibleEyeHeights()) {
|
||||
for (double eye : possibleEyeHeights) {
|
||||
Vector eyePos = new Vector(from.getX(), from.getY() + eye, from.getZ());
|
||||
Vector endReachPos = eyePos.clone().add(new Vector(lookVec.getX() * distance, lookVec.getY() * distance, lookVec.getZ() * distance));
|
||||
|
||||
@@ -236,9 +238,8 @@ public class Reach extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
this.cancelImpossibleHits = getConfig().getBooleanElse("Reach.block-impossible-hits", true);
|
||||
this.threshold = getConfig().getDoubleElse("Reach.threshold", 0.0005);
|
||||
public void onReload(ConfigManager config) {
|
||||
this.cancelImpossibleHits = config.getBooleanElse("Reach.block-impossible-hits", true);
|
||||
this.threshold = config.getDoubleElse("Reach.threshold", 0.0005);
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,10 @@ public class NoFallA extends Check implements PacketCheck {
|
||||
if (!isNearGround(wrapper.isOnGround())) { // If player isn't near ground
|
||||
// 1.8 boats have a mind on their own... only flag if they're not near a boat or are on 1.9+
|
||||
if (!GhostBlockDetector.isGhostBlock(player) && flagWithSetback()) alert("");
|
||||
if (shouldModifyPackets()) wrapper.setOnGround(false);
|
||||
if (shouldModifyPackets()) {
|
||||
wrapper.setOnGround(false);
|
||||
event.markForReEncode(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -59,10 +62,16 @@ public class NoFallA extends Check implements PacketCheck {
|
||||
// Also flip teleports because I don't trust vanilla's handling of teleports and ground
|
||||
if (flipPlayerGroundStatus) {
|
||||
flipPlayerGroundStatus = false;
|
||||
if (shouldModifyPackets()) wrapper.setOnGround(!wrapper.isOnGround());
|
||||
if (shouldModifyPackets()) {
|
||||
wrapper.setOnGround(!wrapper.isOnGround());
|
||||
event.markForReEncode(true);
|
||||
}
|
||||
}
|
||||
if (player.packetStateData.lastPacketWasTeleport) {
|
||||
if (shouldModifyPackets()) wrapper.setOnGround(false);
|
||||
if (shouldModifyPackets()) {
|
||||
wrapper.setOnGround(false);
|
||||
event.markForReEncode(true);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.impl.misc;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.type.BlockPlaceCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
|
||||
@@ -63,10 +64,9 @@ public class GhostBlockMitigation extends BlockPlaceCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
allow = getConfig().getBooleanElse("exploit.allow-building-on-ghostblocks", true);
|
||||
distance = getConfig().getIntElse("exploit.distance-to-check-for-ghostblocks", 2);
|
||||
public void onReload(ConfigManager config) {
|
||||
allow = config.getBooleanElse("exploit.allow-building-on-ghostblocks", true);
|
||||
distance = config.getIntElse("exploit.distance-to-check-for-ghostblocks", 2);
|
||||
|
||||
if (distance < 2 || distance > 4) distance = 2;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.impl.movement;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
@@ -35,8 +36,7 @@ public class NegativeTimerCheck extends TimerCheck implements PostPredictionChec
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
clockDrift = (long) (getConfig().getDoubleElse(getConfigName() + ".drift", 1200.0) * 1e6);
|
||||
public void onReload(ConfigManager config) {
|
||||
clockDrift = (long) (config.getDoubleElse(getConfigName() + ".drift", 1200.0) * 1e6);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.impl.movement;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
@@ -51,8 +52,7 @@ public class NoSlowA extends Check implements PostPredictionCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
offsetToFlag = getConfig().getDoubleElse("NoSlowA.threshold", 0.001);
|
||||
public void onReload(ConfigManager config) {
|
||||
offsetToFlag = config.getDoubleElse("NoSlowA.threshold", 0.001);
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.impl.movement;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
@@ -19,9 +20,9 @@ public class TimerCheck extends Check implements PacketCheck {
|
||||
|
||||
// How long should the player be able to fall back behind their ping?
|
||||
// Default: 120 milliseconds
|
||||
long clockDrift = (long) 120e6;
|
||||
long clockDrift;
|
||||
|
||||
long limitAbuseOverPing = 1000;
|
||||
long limitAbuseOverPing;
|
||||
|
||||
boolean hasGottenMovementAfterTransaction = false;
|
||||
|
||||
@@ -115,9 +116,8 @@ public class TimerCheck extends Check implements PacketCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
clockDrift = (long) (getConfig().getDoubleElse(getConfigName() + ".drift", 120.0) * 1e6);
|
||||
limitAbuseOverPing = (long) (getConfig().getDoubleElse(getConfigName() + ".ping-abuse-limit-threshold", 1000));
|
||||
public void onReload(ConfigManager config) {
|
||||
clockDrift = (long) (config.getDoubleElse(getConfigName() + ".drift", 120.0) * 1e6);
|
||||
limitAbuseOverPing = (long) (config.getDoubleElse(getConfigName() + ".ping-abuse-limit-threshold", 1000));
|
||||
}
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.impl.prediction;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.events.CompletePredictionEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
@@ -99,14 +100,12 @@ public class OffsetHandler extends Check implements PostPredictionCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
setbackDecayMultiplier = getConfig().getDoubleElse("Simulation.setback-decay-multiplier", 0.999);
|
||||
threshold = getConfig().getDoubleElse("Simulation.threshold", 0.001);
|
||||
immediateSetbackThreshold = getConfig().getDoubleElse("Simulation.immediate-setback-threshold", 0.1);
|
||||
maxAdvantage = getConfig().getDoubleElse("Simulation.max-advantage", 1);
|
||||
maxCeiling = getConfig().getDoubleElse("Simulation.max-ceiling", 4);
|
||||
|
||||
public void onReload(ConfigManager config) {
|
||||
setbackDecayMultiplier = config.getDoubleElse("Simulation.setback-decay-multiplier", 0.999);
|
||||
threshold = config.getDoubleElse("Simulation.threshold", 0.001);
|
||||
immediateSetbackThreshold = config.getDoubleElse("Simulation.immediate-setback-threshold", 0.1);
|
||||
maxAdvantage = config.getDoubleElse("Simulation.max-advantage", 1);
|
||||
maxCeiling = config.getDoubleElse("Simulation.max-ceiling", 4);
|
||||
if (maxAdvantage == -1) maxAdvantage = Double.MAX_VALUE;
|
||||
if (immediateSetbackThreshold == -1) immediateSetbackThreshold = Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.impl.scaffolding;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.BlockPlaceCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
@@ -29,8 +30,7 @@ public class AirLiquidPlace extends BlockPlaceCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
this.cancelVL = getConfig().getIntElse(getConfigName() + ".cancelVL", 0);
|
||||
public void onReload(ConfigManager config) {
|
||||
this.cancelVL = config.getIntElse(getConfigName() + ".cancelVL", 0);
|
||||
}
|
||||
}
|
||||
@@ -26,7 +26,8 @@ public class FarPlace extends BlockPlaceCheck {
|
||||
if (place.getMaterial() == StateTypes.SCAFFOLDING) return;
|
||||
|
||||
double min = Double.MAX_VALUE;
|
||||
for (double d : player.getPossibleEyeHeights()) {
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
for (double d : possibleEyeHeights) {
|
||||
SimpleCollisionBox box = new SimpleCollisionBox(blockPos);
|
||||
Vector eyes = new Vector(player.x, player.y + d, player.z);
|
||||
Vector best = VectorUtils.cutBoxToVector(eyes, box);
|
||||
|
||||
@@ -63,7 +63,7 @@ public class MultiPlace extends BlockPlaceCheck {
|
||||
|
||||
@Override
|
||||
public void onPredictionComplete(PredictionComplete predictionComplete) {
|
||||
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && !player.skippedTickInActualMovement) {
|
||||
if (player.getClientVersion().isNewerThan(ClientVersion.V_1_8) && !player.skippedTickInActualMovement && predictionComplete.isChecked()) {
|
||||
for (String verbose : flags) {
|
||||
flagAndAlert(verbose);
|
||||
}
|
||||
|
||||
@@ -28,8 +28,13 @@ public class PositionPlace extends BlockPlaceCheck {
|
||||
// Each position represents the best case scenario to have clicked
|
||||
//
|
||||
// We will now calculate the most optimal position for the player's head to be in
|
||||
double minEyeHeight = Collections.min(player.getPossibleEyeHeights());
|
||||
double maxEyeHeight = Collections.max(player.getPossibleEyeHeights());
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
double minEyeHeight = Double.MAX_VALUE;
|
||||
double maxEyeHeight = Double.MIN_VALUE;
|
||||
for (double height : possibleEyeHeights) {
|
||||
minEyeHeight = Math.min(minEyeHeight, height);
|
||||
maxEyeHeight = Math.max(maxEyeHeight, height);
|
||||
}
|
||||
// I love the idle packet, why did you remove it mojang :(
|
||||
// Don't give 0.03 lenience if the player is a 1.8 player and we know they couldn't have 0.03'd because idle packet
|
||||
double movementThreshold = !player.packetStateData.didLastMovementIncludePosition || player.getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9) ? player.getMovementThreshold() : 0;
|
||||
|
||||
@@ -75,9 +75,15 @@ public class RotationPlace extends BlockPlaceCheck {
|
||||
new Vector3f(player.lastXRot, player.yRot, 0)
|
||||
));
|
||||
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
|
||||
// Start checking if player is in the block
|
||||
double minEyeHeight = Collections.min(player.getPossibleEyeHeights());
|
||||
double maxEyeHeight = Collections.max(player.getPossibleEyeHeights());
|
||||
double minEyeHeight = Double.MAX_VALUE;
|
||||
double maxEyeHeight = Double.MIN_VALUE;
|
||||
for (double height : possibleEyeHeights) {
|
||||
minEyeHeight = Math.min(minEyeHeight, height);
|
||||
maxEyeHeight = Math.max(maxEyeHeight, height);
|
||||
}
|
||||
|
||||
SimpleCollisionBox eyePositions = new SimpleCollisionBox(player.x, player.y + minEyeHeight, player.z, player.x, player.y + maxEyeHeight, player.z);
|
||||
eyePositions.expand(player.getMovementThreshold());
|
||||
@@ -99,7 +105,7 @@ public class RotationPlace extends BlockPlaceCheck {
|
||||
}
|
||||
|
||||
final double distance = player.compensatedEntities.getSelf().getAttributeValue(Attributes.PLAYER_BLOCK_INTERACTION_RANGE);
|
||||
for (double d : player.getPossibleEyeHeights()) {
|
||||
for (double d : possibleEyeHeights) {
|
||||
for (Vector3f lookDir : possibleLookDirs) {
|
||||
// x, y, z are correct for the block placement even after post tick because of code elsewhere
|
||||
Vector3d starting = new Vector3d(player.x, player.y + d, player.z);
|
||||
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.impl.velocity;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
@@ -18,7 +19,6 @@ import com.github.retrooper.packetevents.util.Vector3f;
|
||||
import com.github.retrooper.packetevents.util.Vector3i;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerExplosion;
|
||||
import lombok.Getter;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.util.Vector;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
@@ -256,12 +256,10 @@ public class ExplosionHandler extends Check implements PostPredictionCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
|
||||
offsetToFlag = getConfig().getDoubleElse("Explosion.threshold", 0.00001);
|
||||
setbackVL = getConfig().getDoubleElse("Explosion.setbackvl", 10);
|
||||
|
||||
public void onReload(ConfigManager config) {
|
||||
offsetToFlag = config.getDoubleElse("Explosion.threshold", 0.00001);
|
||||
setbackVL = config.getDoubleElse("Explosion.setbackvl", 10);
|
||||
if (setbackVL == -1) setbackVL = Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
package ac.grim.grimac.checks.impl.velocity;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.CheckData;
|
||||
import ac.grim.grimac.checks.type.PostPredictionCheck;
|
||||
@@ -240,15 +241,14 @@ public class KnockbackHandler extends Check implements PostPredictionCheck {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
offsetToFlag = getConfig().getDoubleElse("Knockback.threshold", 0.001);
|
||||
maxAdv = getConfig().getDoubleElse("Knockback.max-advantage", 1);
|
||||
immediate = getConfig().getDoubleElse("Knockback.immediate-setback-threshold", 0.1);
|
||||
multiplier = getConfig().getDoubleElse("Knockback.setback-decay-multiplier", 0.999);
|
||||
ceiling = getConfig().getDoubleElse("Knockback.max-ceiling", 4);
|
||||
|
||||
public void onReload(ConfigManager config) {
|
||||
offsetToFlag = config.getDoubleElse("Knockback.threshold", 0.001);
|
||||
maxAdv = config.getDoubleElse("Knockback.max-advantage", 1);
|
||||
immediate = config.getDoubleElse("Knockback.immediate-setback-threshold", 0.1);
|
||||
multiplier = config.getDoubleElse("Knockback.setback-decay-multiplier", 0.999);
|
||||
ceiling = config.getDoubleElse("Knockback.max-ceiling", 4);
|
||||
if (maxAdv < 0) maxAdv = Double.MAX_VALUE;
|
||||
if (immediate < 0) immediate = Double.MAX_VALUE;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -1,5 +1,6 @@
|
||||
package ac.grim.grimac.checks.type;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.update.BlockPlace;
|
||||
@@ -33,9 +34,8 @@ public class BlockPlaceCheck extends Check implements RotationCheck, PostPredict
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
super.reload();
|
||||
this.cancelVL = getConfig().getIntElse(getConfigName() + ".cancelVL", 5);
|
||||
public void onReload(ConfigManager config) {
|
||||
this.cancelVL = config.getIntElse(getConfigName() + ".cancelVL", 5);
|
||||
}
|
||||
|
||||
protected boolean shouldCancel() {
|
||||
|
||||
@@ -1,15 +1,11 @@
|
||||
package ac.grim.grimac.commands;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import co.aikar.commands.BaseCommand;
|
||||
import co.aikar.commands.annotation.CommandAlias;
|
||||
import co.aikar.commands.annotation.CommandPermission;
|
||||
import co.aikar.commands.annotation.Subcommand;
|
||||
import com.github.retrooper.packetevents.netty.channel.ChannelHelper;
|
||||
import org.bukkit.ChatColor;
|
||||
import org.bukkit.command.CommandSender;
|
||||
|
||||
@CommandAlias("grim|grimac")
|
||||
@@ -18,14 +14,15 @@ public class GrimReload extends BaseCommand {
|
||||
@CommandPermission("grim.reload")
|
||||
public void onReload(CommandSender sender) {
|
||||
//reload config
|
||||
try {
|
||||
GrimAPI.INSTANCE.getExternalAPI().reload();
|
||||
} catch (RuntimeException e) {
|
||||
sender.sendMessage(ChatColor.RED + e.getMessage());
|
||||
return;
|
||||
}
|
||||
|
||||
sender.sendMessage(MessageUtil.format("%prefix% &fConfig has been reloaded."));
|
||||
sender.sendMessage(MessageUtil.format("%prefix% &7Reloading config..."));
|
||||
GrimAPI.INSTANCE.getExternalAPI().reloadAsync().exceptionally(throwable -> false)
|
||||
.thenAccept(bool -> {
|
||||
if (bool) {
|
||||
sender.sendMessage(MessageUtil.format("%prefix% &fConfig has been reloaded."));
|
||||
} else {
|
||||
sender.sendMessage(MessageUtil.format("%prefix% &cFailed to reload config."));
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -20,7 +20,7 @@ public class GrimSendAlert extends BaseCommand {
|
||||
bukkitPlayer.sendMessage(string);
|
||||
}
|
||||
|
||||
if (GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("alerts.print-to-console", true)) {
|
||||
if (GrimAPI.INSTANCE.getConfigManager().isPrintAlertsToConsole()) {
|
||||
LogUtil.console(string); // Print alert to console
|
||||
}
|
||||
}
|
||||
|
||||
@@ -348,7 +348,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
// Additionally, only yaw/pitch matters: https://github.com/GrimAnticheat/Grim/issues/1275#issuecomment-1872444018
|
||||
// 1.9+ isn't impacted by this packet as much.
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_9)) {
|
||||
if (GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("cancel-duplicate-packet", true)) {
|
||||
if (player.isCancelDuplicatePacket()) {
|
||||
player.packetStateData.cancelDuplicatePacket = true;
|
||||
}
|
||||
} else {
|
||||
@@ -358,7 +358,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
|
||||
player.packetStateData.lastPacketWasOnePointSeventeenDuplicate = true;
|
||||
|
||||
if (!GrimAPI.INSTANCE.getConfigManager().isIgnoreDuplicatePacketRotation()) {
|
||||
if (!player.isIgnoreDuplicatePacketRotation()) {
|
||||
if (player.xRot != location.getYaw() || player.yRot != location.getPitch()) {
|
||||
player.lastXRot = player.xRot;
|
||||
player.lastYRot = player.yRot;
|
||||
@@ -428,7 +428,7 @@ public class CheckManagerListener extends PacketListenerAbstract {
|
||||
if (WrapperPlayClientPlayerFlying.isFlying(event.getPacketType())) {
|
||||
WrapperPlayClientPlayerFlying flying = new WrapperPlayClientPlayerFlying(event);
|
||||
Location pos = flying.getLocation();
|
||||
boolean ignoreRotation = player.packetStateData.lastPacketWasOnePointSeventeenDuplicate && GrimAPI.INSTANCE.getConfigManager().isIgnoreDuplicatePacketRotation();
|
||||
boolean ignoreRotation = player.packetStateData.lastPacketWasOnePointSeventeenDuplicate && player.isIgnoreDuplicatePacketRotation();
|
||||
handleFlying(player, pos.getX(), pos.getY(), pos.getZ(), ignoreRotation ? player.xRot : pos.getYaw(), ignoreRotation ? player.yRot : pos.getPitch(), flying.hasPositionChanged(), flying.hasRotationChanged(), flying.isOnGround(), teleportData, event);
|
||||
}
|
||||
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
package ac.grim.grimac.events.packets;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
@@ -53,7 +53,6 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
private final List<Integer> despawnedEntitiesThisTransaction = new ArrayList<>();
|
||||
|
||||
// Maximum ping when a firework boost is removed from the player.
|
||||
private final int maxFireworkBoostPing = GrimAPI.INSTANCE.getConfigManager().getConfig().getIntElse("max-ping-firework-boost", 1000);
|
||||
|
||||
public PacketEntityReplication(GrimPlayer player) {
|
||||
super(player);
|
||||
@@ -500,4 +499,12 @@ public class PacketEntityReplication extends Check implements PacketCheck {
|
||||
public void tickStartTick() {
|
||||
hasSentPreWavePacket = false;
|
||||
}
|
||||
|
||||
private int maxFireworkBoostPing = 1000;
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
maxFireworkBoostPing = config.getIntElse("max-ping-firework-boost", 1000);
|
||||
}
|
||||
|
||||
}
|
||||
+15
-34
@@ -5,14 +5,11 @@ import ac.grim.grimac.player.GrimPlayer;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerAbstract;
|
||||
import com.github.retrooper.packetevents.event.PacketListenerPriority;
|
||||
import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketType;
|
||||
import com.github.retrooper.packetevents.protocol.packettype.PacketTypeCommon;
|
||||
import com.github.retrooper.packetevents.protocol.player.GameMode;
|
||||
import com.github.retrooper.packetevents.wrapper.play.client.WrapperPlayClientPlayerFlying;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerEntityMetadata;
|
||||
import com.github.retrooper.packetevents.protocol.player.UserProfile;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfo;
|
||||
import com.github.retrooper.packetevents.wrapper.play.server.WrapperPlayServerPlayerInfoUpdate;
|
||||
|
||||
@@ -20,22 +17,15 @@ import java.util.ArrayList;
|
||||
import java.util.EnumSet;
|
||||
import java.util.List;
|
||||
|
||||
public class PacketSetWrapperNull extends PacketListenerAbstract {
|
||||
// It's faster (and less buggy) to simply not re-encode the wrapper unless we changed something
|
||||
// The two packets we change are clientbound entity metadata (to fix a netcode issue)
|
||||
// and the serverbound player flying packets (to patch NoFall)
|
||||
public PacketSetWrapperNull() {
|
||||
public class PacketHidePlayerInfo extends PacketListenerAbstract {
|
||||
|
||||
public PacketHidePlayerInfo() {
|
||||
super(PacketListenerPriority.HIGHEST);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketSend(PacketSendEvent event) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.ENTITY_METADATA) {
|
||||
WrapperPlayServerEntityMetadata wrapper = new WrapperPlayServerEntityMetadata(event);
|
||||
if (wrapper.getEntityId() != event.getUser().getEntityId()) {
|
||||
event.setLastUsedWrapper(null);
|
||||
}
|
||||
} else if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
|
||||
if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO) {
|
||||
//iterate through players and fake their game mode if they are spectating via grim spectate
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_12_2))
|
||||
return;
|
||||
@@ -62,8 +52,8 @@ public class PacketSetWrapperNull extends PacketListenerAbstract {
|
||||
//if amount of hidden players is the amount of players updated & is an update game mode action just cancel it
|
||||
if (hideCount == nmsPlayerInfoDataList.size() && info.getAction() == WrapperPlayServerPlayerInfo.Action.UPDATE_GAME_MODE) {
|
||||
event.setCancelled(true);
|
||||
} else if (hideCount <= 0) {
|
||||
event.setLastUsedWrapper(null);
|
||||
} else if (hideCount > 0) {
|
||||
event.markForReEncode(true);
|
||||
}
|
||||
}
|
||||
} else if (event.getPacketType() == PacketType.Play.Server.PLAYER_INFO_UPDATE) {
|
||||
@@ -81,12 +71,13 @@ public class PacketSetWrapperNull extends PacketListenerAbstract {
|
||||
for (WrapperPlayServerPlayerInfoUpdate.PlayerInfo entry : wrapper.getEntries()) {
|
||||
//check if the player should be hidden
|
||||
WrapperPlayServerPlayerInfoUpdate.PlayerInfo modifiedPacket = null;
|
||||
if (GrimAPI.INSTANCE.getSpectateManager().shouldHidePlayer(receiver, entry.getProfileId())) {
|
||||
final UserProfile gameProfile = entry.getGameProfile();
|
||||
if (GrimAPI.INSTANCE.getSpectateManager().shouldHidePlayer(receiver, gameProfile.getUUID())) {
|
||||
hideCount++;
|
||||
//modify & create a new packet from pre-existing one if they are a spectator
|
||||
if (entry.getGameMode() == GameMode.SPECTATOR) {
|
||||
modifiedPacket = new WrapperPlayServerPlayerInfoUpdate.PlayerInfo(
|
||||
entry.getGameProfile(),
|
||||
gameProfile,
|
||||
entry.isListed(),
|
||||
entry.getLatency(),
|
||||
GameMode.SURVIVAL,
|
||||
@@ -104,30 +95,20 @@ public class PacketSetWrapperNull extends PacketListenerAbstract {
|
||||
} //if only the game mode was updated and the packet was modified, don't send anything
|
||||
|
||||
}
|
||||
//if no hidden players, don't modify packet
|
||||
if (hideCount <= 0) {
|
||||
event.setLastUsedWrapper(null);
|
||||
} else if (hideCount == modified.size()) { //if the amount of hidden players & modified entries are the same
|
||||
|
||||
// if the amount of hidden players & modified entries are the same
|
||||
if (hideCount == modified.size()) {
|
||||
if (onlyGameMode) { // if only the game mode changed, cancel
|
||||
event.setCancelled(true);
|
||||
} else { //if more than the game mode changed, remove the action
|
||||
wrapper.getActions().remove(WrapperPlayServerPlayerInfoUpdate.Action.UPDATE_GAME_MODE);
|
||||
event.markForReEncode(true);
|
||||
}
|
||||
} else { //modify entries
|
||||
wrapper.setEntries(modified);
|
||||
event.markForReEncode(true);
|
||||
}
|
||||
}
|
||||
|
||||
} else if (event.getPacketType() != PacketType.Play.Server.PLAYER_POSITION_AND_LOOK) {
|
||||
event.setLastUsedWrapper(null);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void onPacketReceive(PacketReceiveEvent event) {
|
||||
PacketTypeCommon packetType = event.getPacketType();
|
||||
if (!WrapperPlayClientPlayerFlying.isFlying(packetType) && packetType != PacketType.Play.Client.CLIENT_SETTINGS && !event.isCancelled()) {
|
||||
event.setLastUsedWrapper(null);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package ac.grim.grimac.events.packets;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.type.PacketCheck;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
@@ -37,7 +37,6 @@ public class PacketPlayerAbilities extends Check implements PacketCheck {
|
||||
|
||||
if (lastSentPlayerCanFly && !abilities.isFlightAllowed()) {
|
||||
int noFlying = player.lastTransactionSent.get();
|
||||
int maxFlyingPing = GrimAPI.INSTANCE.getConfigManager().getConfig().getIntElse("max-ping-out-of-flying", 1000);
|
||||
if (maxFlyingPing != -1) {
|
||||
player.runNettyTaskInMs(() -> {
|
||||
if (player.lastTransactionReceived.get() < noFlying) {
|
||||
@@ -56,4 +55,12 @@ public class PacketPlayerAbilities extends Check implements PacketCheck {
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
int maxFlyingPing = 1000;
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
maxFlyingPing = config.getIntElse("max-ping-out-of-flying", 1000);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,6 +24,7 @@ import java.util.List;
|
||||
import java.util.Optional;
|
||||
|
||||
public class PacketSelfMetadataListener extends PacketListenerAbstract {
|
||||
|
||||
public PacketSelfMetadataListener() {
|
||||
super(PacketListenerPriority.HIGH);
|
||||
}
|
||||
@@ -68,6 +69,7 @@ public class PacketSelfMetadataListener extends PacketListenerAbstract {
|
||||
// Remove the pose metadata from the list
|
||||
metadataStuff.removeIf(element -> element.getIndex() == 6);
|
||||
entityMetadata.setEntityMetadata(metadataStuff);
|
||||
event.markForReEncode(true);
|
||||
}
|
||||
|
||||
EntityData watchable = WatchableIndexUtil.getIndex(entityMetadata.getEntityMetadata(), 0);
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
package ac.grim.grimac.manager;
|
||||
|
||||
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.checks.impl.aim.AimDuplicateLook;
|
||||
import ac.grim.grimac.checks.impl.aim.AimModulo360;
|
||||
@@ -33,6 +32,7 @@ import ac.grim.grimac.manager.init.start.SuperDebug;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.predictionengine.GhostBlockDetector;
|
||||
import ac.grim.grimac.predictionengine.SneakingEstimator;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.anticheat.update.*;
|
||||
import ac.grim.grimac.utils.latency.CompensatedCooldown;
|
||||
import ac.grim.grimac.utils.latency.CompensatedFireworks;
|
||||
@@ -42,8 +42,13 @@ import com.github.retrooper.packetevents.event.PacketReceiveEvent;
|
||||
import com.github.retrooper.packetevents.event.PacketSendEvent;
|
||||
import com.google.common.collect.ClassToInstanceMap;
|
||||
import com.google.common.collect.ImmutableClassToInstanceMap;
|
||||
import org.bukkit.Bukkit;
|
||||
import org.bukkit.permissions.Permission;
|
||||
import org.bukkit.permissions.PermissionDefault;
|
||||
|
||||
public class CheckManager {
|
||||
private static boolean inited;
|
||||
|
||||
ClassToInstanceMap<PacketCheck> packetChecks;
|
||||
ClassToInstanceMap<PositionCheck> positionCheck;
|
||||
ClassToInstanceMap<RotationCheck> rotationCheck;
|
||||
@@ -172,6 +177,8 @@ public class CheckManager {
|
||||
.putAll(blockPlaceCheck)
|
||||
.putAll(prePredictionChecks)
|
||||
.build();
|
||||
|
||||
init();
|
||||
}
|
||||
|
||||
@SuppressWarnings("unchecked")
|
||||
@@ -324,4 +331,22 @@ public class CheckManager {
|
||||
public <T extends PostPredictionCheck> T getPostPredictionCheck(Class<T> check) {
|
||||
return (T) postPredictionCheck.get(check);
|
||||
}
|
||||
|
||||
private void init() {
|
||||
if (inited) return;
|
||||
for (AbstractCheck check : allChecks.values()) {
|
||||
if (check.getCheckName() != null) {
|
||||
String permissionName = "grim.exempt." + check.getCheckName().toLowerCase();
|
||||
Permission permission = Bukkit.getPluginManager().getPermission(permissionName);
|
||||
|
||||
if (permission == null) {
|
||||
Bukkit.getPluginManager().addPermission(new Permission(permissionName, PermissionDefault.FALSE));
|
||||
} else {
|
||||
permission.setDefault(PermissionDefault.FALSE);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
inited = true;
|
||||
}
|
||||
}
|
||||
@@ -1,60 +1,72 @@
|
||||
package ac.grim.grimac.manager;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.GrimExternalAPI;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.manager.init.load.PacketEventsInit;
|
||||
import ac.grim.grimac.manager.init.start.*;
|
||||
import ac.grim.grimac.manager.init.stop.TerminatePacketEvents;
|
||||
import com.google.common.collect.ClassToInstanceMap;
|
||||
import com.google.common.collect.ImmutableClassToInstanceMap;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import lombok.Getter;
|
||||
|
||||
public class InitManager {
|
||||
ClassToInstanceMap<Initable> initializersOnLoad;
|
||||
ClassToInstanceMap<Initable> initializersOnStart;
|
||||
ClassToInstanceMap<Initable> initializersOnStop;
|
||||
|
||||
private final ImmutableList<Initable> initializersOnLoad;
|
||||
private final ImmutableList<Initable> initializersOnStart;
|
||||
private final ImmutableList<Initable> initializersOnStop;
|
||||
|
||||
@Getter private boolean loaded = false;
|
||||
@Getter private boolean started = false;
|
||||
@Getter private boolean stopped = false;
|
||||
|
||||
public InitManager() {
|
||||
initializersOnLoad = new ImmutableClassToInstanceMap.Builder<Initable>()
|
||||
.put(PacketEventsInit.class, new PacketEventsInit())
|
||||
initializersOnLoad = ImmutableList.<Initable>builder()
|
||||
.add(new PacketEventsInit())
|
||||
.add(() -> GrimAPI.INSTANCE.getExternalAPI().load())
|
||||
.build();
|
||||
|
||||
initializersOnStart = new ImmutableClassToInstanceMap.Builder<Initable>()
|
||||
.put(ExemptOnlinePlayers.class, new ExemptOnlinePlayers())
|
||||
.put(EventManager.class, new EventManager())
|
||||
.put(PacketManager.class, new PacketManager())
|
||||
.put(ViaBackwardsManager.class, new ViaBackwardsManager())
|
||||
.put(TickRunner.class, new TickRunner())
|
||||
.put(TickEndEvent.class, new TickEndEvent())
|
||||
.put(CommandRegister.class, new CommandRegister())
|
||||
.put(BStats.class, new BStats())
|
||||
.put(PacketLimiter.class, new PacketLimiter())
|
||||
.put(DiscordManager.class, GrimAPI.INSTANCE.getDiscordManager())
|
||||
.put(SpectateManager.class, GrimAPI.INSTANCE.getSpectateManager())
|
||||
.put(GrimExternalAPI.class, GrimAPI.INSTANCE.getExternalAPI())
|
||||
.put(JavaVersion.class, new JavaVersion())
|
||||
initializersOnStart = ImmutableList.<Initable>builder()
|
||||
.add(GrimAPI.INSTANCE.getExternalAPI())
|
||||
.add(new ExemptOnlinePlayers())
|
||||
.add(new EventManager())
|
||||
.add(new PacketManager())
|
||||
.add(new ViaBackwardsManager())
|
||||
.add(new TickRunner())
|
||||
.add(new TickEndEvent())
|
||||
.add(new CommandRegister())
|
||||
.add(new BStats())
|
||||
.add(new PacketLimiter())
|
||||
.add(GrimAPI.INSTANCE.getDiscordManager())
|
||||
.add(GrimAPI.INSTANCE.getSpectateManager())
|
||||
.add(new JavaVersion())
|
||||
.add(new ViaVersion())
|
||||
.build();
|
||||
|
||||
initializersOnStop = new ImmutableClassToInstanceMap.Builder<Initable>()
|
||||
.put(TerminatePacketEvents.class, new TerminatePacketEvents())
|
||||
initializersOnStop = ImmutableList.<Initable>builder()
|
||||
.add(new TerminatePacketEvents())
|
||||
.build();
|
||||
}
|
||||
|
||||
public void load() {
|
||||
for (Initable initable : initializersOnLoad.values()) {
|
||||
initable.start();
|
||||
}
|
||||
for (Initable initable : initializersOnLoad) handle(initable);
|
||||
loaded = true;
|
||||
}
|
||||
|
||||
public void start() {
|
||||
for (Initable initable : initializersOnStart.values()) {
|
||||
initable.start();
|
||||
}
|
||||
for (Initable initable : initializersOnStart) handle(initable);
|
||||
started = true;
|
||||
}
|
||||
|
||||
public void stop() {
|
||||
for (Initable initable : initializersOnStop.values()) {
|
||||
for (Initable initable : initializersOnStop) handle(initable);
|
||||
stopped = true;
|
||||
}
|
||||
|
||||
private void handle(Initable initable) {
|
||||
try {
|
||||
initable.start();
|
||||
} catch (Exception e) {
|
||||
e.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -2,13 +2,14 @@ package ac.grim.grimac.manager;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.api.config.ConfigReloadable;
|
||||
import ac.grim.grimac.api.events.CommandExecuteEvent;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.events.packets.ProxyAlertMessenger;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.anticheat.MessageUtil;
|
||||
import github.scarsz.configuralize.DynamicConfig;
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import lombok.Getter;
|
||||
import lombok.Setter;
|
||||
@@ -17,21 +18,27 @@ import org.bukkit.entity.Player;
|
||||
|
||||
import java.util.*;
|
||||
|
||||
public class PunishmentManager {
|
||||
public class PunishmentManager implements ConfigReloadable {
|
||||
GrimPlayer player;
|
||||
List<PunishGroup> groups = new ArrayList<>();
|
||||
String experimentalSymbol = "*";
|
||||
private String alertString;
|
||||
private boolean testMode;
|
||||
private boolean printToConsole;
|
||||
private String proxyAlertString = "";
|
||||
|
||||
public PunishmentManager(GrimPlayer player) {
|
||||
this.player = player;
|
||||
reload();
|
||||
}
|
||||
|
||||
public void reload() {
|
||||
DynamicConfig config = GrimAPI.INSTANCE.getConfigManager().getConfig();
|
||||
@Override
|
||||
public void reload(ConfigManager config) {
|
||||
List<String> punish = config.getStringListElse("Punishments", new ArrayList<>());
|
||||
experimentalSymbol = config.getStringElse("experimental-symbol", "*");
|
||||
|
||||
alertString = config.getStringElse("alerts-format", "%prefix% &f%player% &bfailed &f%check_name% &f(x&c%vl%&f) &7%verbose%");
|
||||
testMode = config.getBooleanElse("test-mode", false);
|
||||
printToConsole = config.getBooleanElse("verbose.print-to-console", false);
|
||||
proxyAlertString = config.getStringElse("alerts-format-proxy", "%prefix% &f[&cproxy&f] &f%player% &bfailed &f%check_name% &f(x&c%vl%&f) &7%verbose%");
|
||||
try {
|
||||
groups.clear();
|
||||
|
||||
@@ -111,8 +118,6 @@ public class PunishmentManager {
|
||||
}
|
||||
|
||||
public boolean handleAlert(GrimPlayer player, String verbose, Check check) {
|
||||
String alertString = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("alerts-format", "%prefix% &f%player% &bfailed &f%check_name% &f(x&c%vl%&f) &7%verbose%");
|
||||
boolean testMode = GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("test-mode", false);
|
||||
boolean sentDebug = false;
|
||||
|
||||
// Check commands
|
||||
@@ -128,7 +133,7 @@ public class PunishmentManager {
|
||||
for (Player bukkitPlayer : GrimAPI.INSTANCE.getAlertManager().getEnabledVerbose()) {
|
||||
bukkitPlayer.sendMessage(cmd);
|
||||
}
|
||||
if (GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("verbose.print-to-console", false)) {
|
||||
if (printToConsole) {
|
||||
LogUtil.console(cmd); // Print verbose to console
|
||||
}
|
||||
}
|
||||
@@ -146,9 +151,7 @@ public class PunishmentManager {
|
||||
String vl = group.violations.values().stream().filter((e) -> e == check).count() + "";
|
||||
GrimAPI.INSTANCE.getDiscordManager().sendAlert(player, verbose, check.getCheckName(), vl);
|
||||
} else if (command.command.equals("[proxy]")) {
|
||||
String proxyAlertString = GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("alerts-format-proxy", "%prefix% &f[&cproxy&f] &f%player% &bfailed &f%check_name% &f(x&c%vl%&f) &7%verbose%");
|
||||
proxyAlertString = replaceAlertPlaceholders(command.getCommand(), group, check, proxyAlertString, verbose);
|
||||
ProxyAlertMessenger.sendPluginMessage(proxyAlertString);
|
||||
ProxyAlertMessenger.sendPluginMessage(replaceAlertPlaceholders(command.getCommand(), group, check, proxyAlertString, verbose));
|
||||
} else {
|
||||
if (command.command.equals("[alert]")) {
|
||||
sentDebug = true;
|
||||
@@ -160,9 +163,8 @@ public class PunishmentManager {
|
||||
}
|
||||
|
||||
String finalCmd = cmd;
|
||||
FoliaScheduler.getGlobalRegionScheduler().run(GrimAPI.INSTANCE.getPlugin(), (dummy) -> {
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), finalCmd);
|
||||
});
|
||||
FoliaScheduler.getGlobalRegionScheduler().run(GrimAPI.INSTANCE.getPlugin(), (dummy) ->
|
||||
Bukkit.dispatchCommand(Bukkit.getConsoleSender(), finalCmd));
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,63 @@
|
||||
package ac.grim.grimac.manager.config;
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
public class BaseConfigManager {
|
||||
|
||||
/*
|
||||
This is to hold whatever config manager was set via the reload method in the API
|
||||
and any global variables that are the same between players.
|
||||
*/
|
||||
|
||||
@Getter
|
||||
private ConfigManager config = null;
|
||||
|
||||
// initialize the config
|
||||
public void load(ConfigManager config) {
|
||||
this.config = config;
|
||||
//
|
||||
int configuredMaxTransactionTime = config.getIntElse("max-transaction-time", 60);
|
||||
if (configuredMaxTransactionTime > 180 || configuredMaxTransactionTime < 1) {
|
||||
LogUtil.warn("Detected invalid max-transaction-time! This setting is clamped between 1 and 180 to prevent issues. Attempting to disable or set this too high can result in memory usage issues.");
|
||||
}
|
||||
|
||||
ignoredClientPatterns.clear();
|
||||
for (String string : config.getStringList("client-brand.ignored-clients")) {
|
||||
try {
|
||||
ignoredClientPatterns.add(Pattern.compile(string));
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new RuntimeException("Failed to compile client pattern", e);
|
||||
}
|
||||
}
|
||||
|
||||
printAlertsToConsole = config.getBooleanElse("alerts.print-to-console", true);
|
||||
prefix = config.getStringElse("prefix", "&bGrim &8»");
|
||||
}
|
||||
|
||||
// ran on start, can be used to handle things that can't be done while loading
|
||||
public void start() {
|
||||
|
||||
}
|
||||
|
||||
@Getter private boolean printAlertsToConsole = false;
|
||||
|
||||
@Getter private String prefix = "&bGrim &8»";
|
||||
|
||||
private final List<Pattern> ignoredClientPatterns = new ArrayList<>();
|
||||
|
||||
public boolean isIgnoredClient(String brand) {
|
||||
for (Pattern pattern : ignoredClientPatterns) {
|
||||
if (pattern.matcher(brand).find()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
+64
-63
@@ -1,57 +1,43 @@
|
||||
package ac.grim.grimac.manager;
|
||||
package ac.grim.grimac.manager.config;
|
||||
|
||||
import ac.grim.grimac.GrimAC;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.common.BasicReloadable;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import github.scarsz.configuralize.DynamicConfig;
|
||||
import github.scarsz.configuralize.Language;
|
||||
import lombok.Getter;
|
||||
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.nio.file.Files;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.regex.Pattern;
|
||||
import java.util.regex.PatternSyntaxException;
|
||||
|
||||
public class ConfigManager {
|
||||
@Getter
|
||||
public class ConfigManagerFileImpl implements ConfigManager, BasicReloadable {
|
||||
|
||||
private final DynamicConfig config;
|
||||
@Getter
|
||||
private final File configFile = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "config.yml");
|
||||
@Getter
|
||||
private final File messagesFile = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "messages.yml");
|
||||
@Getter
|
||||
private final File discordFile = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "discord.yml");
|
||||
@Getter
|
||||
private final File punishFile = new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), "punishments.yml");
|
||||
@Getter
|
||||
private int maxPingTransaction = 60; // This is just a really hot variable so cache it.
|
||||
@Getter
|
||||
private boolean ignoreDuplicatePacketRotation = false;
|
||||
|
||||
@Getter
|
||||
private boolean experimentalChecks = false;
|
||||
|
||||
private final List<Pattern> ignoredClientPatterns = new ArrayList<>();
|
||||
|
||||
public ConfigManager() {
|
||||
upgrade();
|
||||
|
||||
// load config
|
||||
GrimAPI.INSTANCE.getPlugin().getDataFolder().mkdirs();
|
||||
config = new DynamicConfig();
|
||||
config.addSource(GrimAC.class, "config", getConfigFile());
|
||||
config.addSource(GrimAC.class, "messages", getMessagesFile());
|
||||
config.addSource(GrimAC.class, "discord", getDiscordFile());
|
||||
config.addSource(GrimAC.class, "punishments", getPunishFile());
|
||||
|
||||
reload();
|
||||
private File getConfigFile(String path) {
|
||||
return new File(GrimAPI.INSTANCE.getPlugin().getDataFolder(), path);
|
||||
}
|
||||
|
||||
public ConfigManagerFileImpl() {
|
||||
config = new DynamicConfig();
|
||||
}
|
||||
|
||||
private boolean initialized = false;
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
GrimAPI.INSTANCE.getPlugin().getDataFolder().mkdirs();
|
||||
if (!initialized) {
|
||||
initialized = true;
|
||||
config.addSource(GrimAC.class, "config", getConfigFile("config.yml"));
|
||||
config.addSource(GrimAC.class, "messages", getConfigFile("messages.yml"));
|
||||
config.addSource(GrimAC.class, "discord", getConfigFile("discord.yml"));
|
||||
config.addSource(GrimAC.class, "punishments", getConfigFile("punishments.yml"));
|
||||
}
|
||||
//
|
||||
String languageCode = System.getProperty("user.language").toUpperCase();
|
||||
|
||||
try {
|
||||
@@ -78,32 +64,6 @@ public class ConfigManager {
|
||||
} catch (Exception e) {
|
||||
throw new RuntimeException("Failed to load config", e);
|
||||
}
|
||||
|
||||
final int configuredMaxTransactionTime = config.getIntElse("max-transaction-time", 60);
|
||||
maxPingTransaction = (int) GrimMath.clamp(configuredMaxTransactionTime, 1, 180);
|
||||
if (maxPingTransaction != configuredMaxTransactionTime) {
|
||||
LogUtil.warn("Detected invalid max-transaction-time! This setting is clamped between 1 and 180 to prevent issues. " +
|
||||
"Changed: " + configuredMaxTransactionTime + " -> " + maxPingTransaction);
|
||||
LogUtil.warn("Attempting to disable or set this too high can result in memory usage issues.");
|
||||
}
|
||||
|
||||
ignoredClientPatterns.clear();
|
||||
for (String string : config.getStringList("client-brand.ignored-clients")) {
|
||||
try {
|
||||
ignoredClientPatterns.add(Pattern.compile(string));
|
||||
} catch (PatternSyntaxException e) {
|
||||
throw new RuntimeException("Failed to compile client pattern", e);
|
||||
}
|
||||
}
|
||||
experimentalChecks = config.getBooleanElse("experimental-checks", false);
|
||||
ignoreDuplicatePacketRotation = config.getBooleanElse("ignore-duplicate-packet-rotation", false);
|
||||
}
|
||||
|
||||
public boolean isIgnoredClient(String brand) {
|
||||
for (Pattern pattern : ignoredClientPatterns) {
|
||||
if (pattern.matcher(brand).find()) return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
private void upgrade() {
|
||||
@@ -326,4 +286,45 @@ public class ConfigManager {
|
||||
);
|
||||
Files.write(config.toPath(), configString.getBytes());
|
||||
}
|
||||
|
||||
@Override
|
||||
public String getStringElse(String key, String otherwise) {
|
||||
return config.getStringElse(key, otherwise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStringList(String key) {
|
||||
return config.getStringList(key);
|
||||
}
|
||||
|
||||
@Override
|
||||
public List<String> getStringListElse(String key, List<String> otherwise) {
|
||||
return config.getStringListElse(key, otherwise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public int getIntElse(String key, int other) {
|
||||
return config.getIntElse(key, other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public long getLongElse(String key, long otherwise) {
|
||||
return config.getLongElse(key, otherwise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public double getDoubleElse(String key, double otherwise) {
|
||||
return config.getDoubleElse(key, otherwise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean getBooleanElse(String key, boolean otherwise) {
|
||||
return config.getBooleanElse(key, otherwise);
|
||||
}
|
||||
|
||||
@Override
|
||||
public <T> T get(String key) {
|
||||
return config.get(key);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,8 +4,17 @@ import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.protocol.chat.ChatTypes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.data.EntityDataTypes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.particle.type.ParticleTypes;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
import io.github.retrooper.packetevents.factory.spigot.SpigotPacketEventsBuilder;
|
||||
|
||||
import java.util.concurrent.Executors;
|
||||
|
||||
public class PacketEventsInit implements Initable {
|
||||
@Override
|
||||
public void start() {
|
||||
@@ -16,7 +25,18 @@ public class PacketEventsInit implements Initable {
|
||||
.fullStackTrace(true)
|
||||
.kickOnPacketException(true)
|
||||
.checkForUpdates(false)
|
||||
.reEncodeByDefault(false)
|
||||
.debug(false);
|
||||
PacketEvents.getAPI().load();
|
||||
// This may seem useless, but it causes java to start loading stuff async before we need it
|
||||
Executors.defaultThreadFactory().newThread(() -> {
|
||||
StateTypes.AIR.getName();
|
||||
ItemTypes.AIR.getName();
|
||||
EntityTypes.PLAYER.getParent();
|
||||
EntityDataTypes.BOOLEAN.getName();
|
||||
ChatTypes.CHAT.getName();
|
||||
EnchantmentTypes.ALL_DAMAGE_PROTECTION.getName();
|
||||
ParticleTypes.DUST.getName();
|
||||
}).start();
|
||||
}
|
||||
}
|
||||
@@ -43,7 +43,7 @@ public class PacketManager implements Initable {
|
||||
}
|
||||
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new ProxyAlertMessenger());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketSetWrapperNull());
|
||||
PacketEvents.getAPI().getEventManager().registerListener(new PacketHidePlayerInfo());
|
||||
|
||||
PacketEvents.getAPI().init();
|
||||
}
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
package ac.grim.grimac.manager.init.start;
|
||||
|
||||
import ac.grim.grimac.manager.init.Initable;
|
||||
import ac.grim.grimac.utils.anticheat.LogUtil;
|
||||
import com.viaversion.viaversion.api.Via;
|
||||
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
|
||||
|
||||
public class ViaVersion implements Initable {
|
||||
@Override
|
||||
public void start() {
|
||||
if (!ViaVersionUtil.isAvailable()) return;
|
||||
if (Via.getConfig().getValues().containsKey("fix-1_21-placement-rotation") && Via.getConfig().fix1_21PlacementRotation()) {
|
||||
LogUtil.warn("GrimAC has detected that you are using ViaVersion with the `fix-1_21-placement-rotation` option enabled.");
|
||||
LogUtil.warn("This option is known to cause issues with GrimAC and may result in false positives and bypasses.");
|
||||
LogUtil.warn("Please disable this option in your ViaVersion configuration to prevent these issues.");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@ package ac.grim.grimac.player;
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.AbstractCheck;
|
||||
import ac.grim.grimac.api.GrimUser;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.impl.aim.processor.AimProcessor;
|
||||
import ac.grim.grimac.checks.impl.misc.ClientBrand;
|
||||
@@ -47,6 +48,7 @@ import io.github.retrooper.packetevents.adventure.serializer.legacy.LegacyCompon
|
||||
import io.github.retrooper.packetevents.util.folia.FoliaScheduler;
|
||||
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
|
||||
import io.netty.channel.Channel;
|
||||
import lombok.Getter;
|
||||
import net.kyori.adventure.text.Component;
|
||||
import net.kyori.adventure.text.TranslatableComponent;
|
||||
import org.bukkit.Bukkit;
|
||||
@@ -199,6 +201,8 @@ public class GrimPlayer implements GrimUser {
|
||||
public long lastBlockPlaceUseItem = 0;
|
||||
public AtomicInteger cancelledPackets = new AtomicInteger(0);
|
||||
public MainSupportingBlockData mainSupportingBlockData = new MainSupportingBlockData(null, false);
|
||||
// possibleEyeHeights[0] = Standing eye heights, [1] = Sneaking. [2] = Elytra, Swimming, and Riptide Trident which only exists in 1.9+
|
||||
public double[][] possibleEyeHeights = new double[3][];
|
||||
|
||||
public void onPacketCancel() {
|
||||
if (spamThreshold != -1 && cancelledPackets.incrementAndGet() > spamThreshold) {
|
||||
@@ -217,7 +221,6 @@ public class GrimPlayer implements GrimUser {
|
||||
public GrimPlayer(User user) {
|
||||
this.user = user;
|
||||
this.playerUUID = user.getUUID();
|
||||
onReload();
|
||||
|
||||
boundingBox = GetBoundingBox.getBoundingBoxFromPosAndSizeRaw(x, y, z, 0.6f, 1.8f);
|
||||
|
||||
@@ -240,6 +243,24 @@ public class GrimPlayer implements GrimUser {
|
||||
packetStateData = new PacketStateData();
|
||||
|
||||
uncertaintyHandler.collidingEntities.add(0);
|
||||
|
||||
if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) {
|
||||
final float scale = (float) compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_SCALE);
|
||||
possibleEyeHeights[2] = new double[]{0.4 * scale, 1.62 * scale, 1.27 * scale}; // Elytra, standing, sneaking (1.14)
|
||||
possibleEyeHeights[1] = new double[]{1.27 * scale, 1.62 * scale, 0.4 * scale}; // sneaking (1.14), standing, Elytra
|
||||
possibleEyeHeights[0] = new double[]{1.62 * scale, 1.27 * scale, 0.4 * scale}; // standing, sneaking (1.14), Elytra
|
||||
|
||||
} else if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) { // standing, sneaking Elytra
|
||||
possibleEyeHeights[2] = new double[]{0.4, 1.62, 1.54}; // Elytra, standing, sneaking (1.13)
|
||||
possibleEyeHeights[1] = new double[]{1.54, 1.62, 0.4}; // sneaking (1.9-1.13), standing, Elytra
|
||||
possibleEyeHeights[0] = new double[]{1.62, 1.54, 0.4}; // standing, sneaking (1.9-1.13), Elytra
|
||||
} else {
|
||||
possibleEyeHeights[1] = new double[]{(double) (1.62f - 0.08f), (double) (1.62f)}; // sneaking, standing
|
||||
possibleEyeHeights[0] = new double[]{(double) (1.62f), (double) (1.62f - 0.08f)}; // standing, sneaking
|
||||
}
|
||||
|
||||
// reload last
|
||||
reload();
|
||||
}
|
||||
|
||||
public Set<VectorData> getPossibleVelocities() {
|
||||
@@ -316,7 +337,8 @@ public class GrimPlayer implements GrimUser {
|
||||
// Transactions that we send don't count towards total limit
|
||||
if (packetTracker != null) packetTracker.setIntervalPackets(packetTracker.getIntervalPackets() - 1);
|
||||
|
||||
if (skipped > 0 && System.currentTimeMillis() - joinTime > 5000) checkManager.getPacketCheck(TransactionOrder.class).flagAndAlert("skipped: " + skipped);
|
||||
if (skipped > 0 && System.currentTimeMillis() - joinTime > 5000)
|
||||
checkManager.getPacketCheck(TransactionOrder.class).flagAndAlert("skipped: " + skipped);
|
||||
|
||||
do {
|
||||
data = transactionsSent.poll();
|
||||
@@ -450,7 +472,7 @@ public class GrimPlayer implements GrimUser {
|
||||
if (lastTransSent != 0 && lastTransSent + 80 < System.currentTimeMillis()) {
|
||||
sendTransaction(true); // send on netty thread
|
||||
}
|
||||
if ((System.nanoTime() - getPlayerClockAtLeast()) > GrimAPI.INSTANCE.getConfigManager().getMaxPingTransaction() * 1e9) {
|
||||
if ((System.nanoTime() - getPlayerClockAtLeast()) > maxTransactionTime * 1e9) {
|
||||
timedOut();
|
||||
}
|
||||
|
||||
@@ -515,10 +537,6 @@ public class GrimPlayer implements GrimUser {
|
||||
|
||||
private int spamThreshold = 100;
|
||||
|
||||
public void onReload() {
|
||||
spamThreshold = GrimAPI.INSTANCE.getConfigManager().getConfig().getIntElse("packet-spam-threshold", 100);
|
||||
}
|
||||
|
||||
public boolean isPointThree() {
|
||||
return getClientVersion().isOlderThan(ClientVersion.V_1_18_2);
|
||||
}
|
||||
@@ -548,7 +566,7 @@ public class GrimPlayer implements GrimUser {
|
||||
// - 3 ticks is a magic value, but it should buffer out incorrect predictions somewhat.
|
||||
// 2. The player is in a vehicle
|
||||
public boolean isTickingReliablyFor(int ticks) {
|
||||
return (getClientVersion().isOlderThan(ClientVersion.V_1_9)
|
||||
return (getClientVersion().isOlderThan(ClientVersion.V_1_9)
|
||||
|| !uncertaintyHandler.lastPointThree.hasOccurredSince(ticks))
|
||||
|| compensatedEntities.getSelf().inVehicle();
|
||||
}
|
||||
@@ -561,14 +579,23 @@ public class GrimPlayer implements GrimUser {
|
||||
return checkManager.getInventory();
|
||||
}
|
||||
|
||||
public List<Double> getPossibleEyeHeights() { // We don't return sleeping eye height
|
||||
if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_14)) { // Elytra, sneaking (1.14), standing
|
||||
final float scale = (float) compensatedEntities.getSelf().getAttributeValue(Attributes.GENERIC_SCALE);
|
||||
return Arrays.asList(0.4 * scale, 1.27 * scale, 1.62 * scale);
|
||||
} else if (getClientVersion().isNewerThanOrEquals(ClientVersion.V_1_9)) { // Elytra, sneaking, standing
|
||||
return Arrays.asList(0.4, 1.54, 1.62);
|
||||
} else { // Only sneaking or standing
|
||||
return Arrays.asList((double) (1.62f - 0.08f), (double) (1.62f));
|
||||
public double[] getPossibleEyeHeights() { // We don't return sleeping eye height
|
||||
// 1.8 Players once again ruin my clean switch-case
|
||||
if (this.getClientVersion().isOlderThan(ClientVersion.V_1_9)) {
|
||||
return this.isSneaking ? this.possibleEyeHeights[1] : this.possibleEyeHeights[0];
|
||||
} else {
|
||||
// 1.8 players just have their pose set to standing all the time
|
||||
switch (pose) {
|
||||
case FALL_FLYING: // Elytra gliding
|
||||
case SPIN_ATTACK: // Riptide trident
|
||||
case SWIMMING: // Swimming (includes crawling in 1.14+)
|
||||
return this.possibleEyeHeights[2]; // [swimming/gliding/riptide height, standing height, sneaking height]
|
||||
case NINE_CROUCHING:
|
||||
case CROUCHING:
|
||||
return this.possibleEyeHeights[1]; // [sneaking height, standing height, swimming/gliding/riptide height]
|
||||
default:
|
||||
return this.possibleEyeHeights[0]; // [standing height, sneaking height, swimming/gliding/riptide height]
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -716,10 +743,31 @@ public class GrimPlayer implements GrimUser {
|
||||
return checkManager.allChecks.values();
|
||||
}
|
||||
|
||||
|
||||
public void runNettyTaskInMs(Runnable runnable, int ms) {
|
||||
Channel channel = (Channel) user.getChannel();
|
||||
channel.eventLoop().schedule(runnable, ms, TimeUnit.MILLISECONDS);
|
||||
}
|
||||
|
||||
private int maxTransactionTime = 60;
|
||||
@Getter private boolean ignoreDuplicatePacketRotation = false;
|
||||
@Getter private boolean experimentalChecks = false;
|
||||
@Getter private boolean cancelDuplicatePacket = true;
|
||||
|
||||
@Override
|
||||
public void reload(ConfigManager config) {
|
||||
spamThreshold = config.getIntElse("packet-spam-threshold", 100);
|
||||
maxTransactionTime = (int) GrimMath.clamp(config.getIntElse("max-transaction-time", 60), 1, 180);
|
||||
experimentalChecks = config.getBooleanElse("experimental-checks", false);
|
||||
ignoreDuplicatePacketRotation = config.getBooleanElse("ignore-duplicate-packet-rotation", false);
|
||||
cancelDuplicatePacket = config.getBooleanElse("cancel-duplicate-packet", true);
|
||||
// reload all checks
|
||||
for (AbstractCheck value : checkManager.allChecks.values()) value.reload(config);
|
||||
// reload punishment manager
|
||||
punishmentManager.reload(config);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reload() {
|
||||
reload(GrimAPI.INSTANCE.getConfigManager().getConfig());
|
||||
}
|
||||
}
|
||||
@@ -1,6 +1,6 @@
|
||||
package ac.grim.grimac.predictionengine;
|
||||
|
||||
import ac.grim.grimac.GrimAPI;
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
import ac.grim.grimac.checks.Check;
|
||||
import ac.grim.grimac.checks.impl.movement.EntityControl;
|
||||
import ac.grim.grimac.checks.impl.prediction.Phase;
|
||||
@@ -22,7 +22,6 @@ import ac.grim.grimac.utils.data.packetentity.PacketEntityHorse;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntityRideable;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntityTrackXRot;
|
||||
import ac.grim.grimac.utils.enums.Pose;
|
||||
import ac.grim.grimac.utils.inventory.EnchantmentHelper;
|
||||
import ac.grim.grimac.utils.latency.CompensatedWorld;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import ac.grim.grimac.utils.math.VectorUtils;
|
||||
@@ -32,7 +31,6 @@ import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.attribute.Attributes;
|
||||
import com.github.retrooper.packetevents.protocol.entity.type.EntityTypes;
|
||||
import com.github.retrooper.packetevents.protocol.item.ItemStack;
|
||||
import com.github.retrooper.packetevents.protocol.item.enchantment.type.EnchantmentTypes;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemType;
|
||||
import com.github.retrooper.packetevents.protocol.item.type.ItemTypes;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
@@ -544,8 +542,7 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
player.checkManager.onPredictionFinish(new PredictionComplete(offset, update, wasChecked));
|
||||
|
||||
// Patch sprint jumping with elytra exploit
|
||||
if (player.bukkitPlayer != null && player.isGliding && player.predictedVelocity.isJump() && player.isSprinting
|
||||
&& !GrimAPI.INSTANCE.getConfigManager().getConfig().getBooleanElse("exploit.allow-sprint-jumping-when-using-elytra", true)) {
|
||||
if (player.bukkitPlayer != null && player.isGliding && player.predictedVelocity.isJump() && player.isSprinting && !allowSprintJumpingWithElytra) {
|
||||
SetbackTeleportUtil.SetbackPosWithVector lastKnownGoodPosition = player.getSetbackTeleportUtil().lastKnownGoodPosition;
|
||||
lastKnownGoodPosition.setVector(lastKnownGoodPosition.getVector().multiply(new Vector(0.6 * 0.91, 1, 0.6 * 0.91)));
|
||||
player.getSetbackTeleportUtil().executeNonSimulatingSetback();
|
||||
@@ -635,4 +632,12 @@ public class MovementCheckRunner extends Check implements PositionCheck {
|
||||
// (Patches issues with slime and other desync's)
|
||||
return riptideDiffToGround < riptideDiffToBase;
|
||||
}
|
||||
|
||||
private boolean allowSprintJumpingWithElytra = true;
|
||||
|
||||
@Override
|
||||
public void onReload(ConfigManager config) {
|
||||
allowSprintJumpingWithElytra = config.getBooleanElse("exploit.allow-sprint-jumping-when-using-elytra", true);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -29,13 +29,14 @@ public class MessageUtil {
|
||||
}
|
||||
|
||||
public String formatWithNoColor(String string) {
|
||||
return string.replace("%prefix%", GrimAPI.INSTANCE.getConfigManager().getConfig().getStringElse("prefix", "&bGrim &8»"));
|
||||
return string.replace("%prefix%", GrimAPI.INSTANCE.getConfigManager().getPrefix());
|
||||
}
|
||||
|
||||
private static final Pattern HEX_PATTERN = Pattern.compile("#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})");
|
||||
|
||||
private String translateHexCodes(String message) {
|
||||
final String hexPattern = "#([A-Fa-f0-9]{6}|[A-Fa-f0-9]{8})";
|
||||
Matcher matcher = Pattern.compile(hexPattern).matcher(message);
|
||||
StringBuffer sb = new StringBuffer(message.length());
|
||||
Matcher matcher = HEX_PATTERN.matcher(message);
|
||||
StringBuilder sb = new StringBuilder(message.length());
|
||||
while (matcher.find()) {
|
||||
String hex = matcher.group(1);
|
||||
ChatColor color = ChatColor.of("#" + hex);
|
||||
@@ -44,4 +45,5 @@ public class MessageUtil {
|
||||
matcher.appendTail(sb);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -3,11 +3,12 @@ package ac.grim.grimac.utils.collisions;
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.predictionengine.movementtick.MovementTickerStrider;
|
||||
import ac.grim.grimac.utils.collisions.blocks.*;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicCollisionFence;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicCollisionPane;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicCollisionWall;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicFence;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicPane;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicWall;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.*;
|
||||
import ac.grim.grimac.utils.data.packetentity.PacketEntityStrider;
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import ac.grim.grimac.utils.nmsutil.Materials;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
@@ -24,7 +25,6 @@ import com.viaversion.viaversion.api.Via;
|
||||
import io.github.retrooper.packetevents.util.viaversion.ViaVersionUtil;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
// Warning for major game updates!
|
||||
// Do not use an enum for stuff like Axis and other data types not in 1.7
|
||||
@@ -71,7 +71,9 @@ public enum CollisionData {
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}, StateTypes.LAVA),
|
||||
|
||||
BREWING_STAND((player, version, block, x, y, z) -> {
|
||||
WATER(NoCollisionBox.INSTANCE, StateTypes.WATER),
|
||||
|
||||
BREWINGSTAND((player, version, block, x, y, z) -> {
|
||||
int base = 0;
|
||||
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_13))
|
||||
@@ -84,13 +86,27 @@ public enum CollisionData {
|
||||
}, StateTypes.BREWING_STAND),
|
||||
|
||||
BAMBOO((player, version, block, x, y, z) -> {
|
||||
// ViaVersion replacement, sugarcane
|
||||
if (version.isOlderThan(ClientVersion.V_1_14)) {
|
||||
// ViaVersion replacement block - sugarcane
|
||||
if (version.isOlderThan(ClientVersion.V_1_13_2))
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
return new HexOffsetCollisionBox(block.getType(), 6.5D, 0.0D, 6.5D, 9.5D, 16.0D, 9.5D);
|
||||
|
||||
// Offset taken from NMS
|
||||
long i = (x * 3129871L) ^ (long) z * 116129781L ^ (long) 0;
|
||||
i = i * i * 42317861L + i * 11L;
|
||||
i = i >> 16;
|
||||
|
||||
return new HexCollisionBox(6.5D, 0.0D, 6.5D, 9.5D, 16.0D, 9.5D).offset((((i & 15L) / 15.0F) - 0.5D) * 0.5D, 0, (((i >> 8 & 15L) / 15.0F) - 0.5D) * 0.5D);
|
||||
}, StateTypes.BAMBOO),
|
||||
|
||||
|
||||
BAMBOO_SAPLING((player, version, block, x, y, z) -> {
|
||||
long i = (x * 3129871L) ^ (long) z * 116129781L ^ (long) 0;
|
||||
i = i * i * 42317861L + i * 11L;
|
||||
i = i >> 16;
|
||||
|
||||
return new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, 12.0D, 12.0D).offset((((i & 15L) / 15.0F) - 0.5D) * 0.5D, 0, (((i >> 8 & 15L) / 15.0F) - 0.5D) * 0.5D);
|
||||
}, StateTypes.BAMBOO_SAPLING),
|
||||
|
||||
COMPOSTER((player, version, block, x, y, z) -> {
|
||||
double height = 0.125;
|
||||
|
||||
@@ -143,7 +159,7 @@ public enum CollisionData {
|
||||
}
|
||||
}, BlockTags.ANVIL.getStates().toArray(new StateType[0])),
|
||||
|
||||
WALL(new DynamicCollisionWall(), BlockTags.WALLS.getStates().toArray(new StateType[0])),
|
||||
WALL(new DynamicWall(), BlockTags.WALLS.getStates().toArray(new StateType[0])),
|
||||
|
||||
SLAB((player, version, data, x, y, z) -> {
|
||||
Type slabType = data.getTypeData();
|
||||
@@ -161,7 +177,7 @@ public enum CollisionData {
|
||||
SKULL(new SimpleCollisionBox(0.25F, 0.0F, 0.25F, 0.75F, 0.5F, 0.75F, false),
|
||||
StateTypes.CREEPER_HEAD, StateTypes.ZOMBIE_HEAD, StateTypes.DRAGON_HEAD, StateTypes.PLAYER_HEAD,
|
||||
StateTypes.SKELETON_SKULL, StateTypes.WITHER_SKELETON_SKULL, StateTypes.HEAVY_CORE),
|
||||
|
||||
|
||||
PIGLIN_HEAD(new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 8.0D, 13.0D), StateTypes.PIGLIN_HEAD),
|
||||
|
||||
// Overwrite previous SKULL enum for legacy, where head and wall skull isn't separate
|
||||
@@ -194,6 +210,13 @@ public enum CollisionData {
|
||||
}
|
||||
}, StateTypes.PIGLIN_WALL_HEAD),
|
||||
|
||||
BANNER(new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, 16.0D, 12.0D),
|
||||
BlockTags.BANNERS.getStates().toArray(new StateType[0])),
|
||||
|
||||
CORAL_FAN((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 4.0D, 14.0D);
|
||||
}, BlockTags.CORALS.getStates().toArray(new StateType[0])),
|
||||
|
||||
DOOR(new DoorHandler(), BlockTags.DOORS.getStates().toArray(new StateType[0])),
|
||||
|
||||
HOPPER((player, version, data, x, y, z) -> {
|
||||
@@ -258,31 +281,43 @@ public enum CollisionData {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D);
|
||||
}, StateTypes.STONECUTTER),
|
||||
|
||||
CORAL_FAN(NoCollisionBox.INSTANCE, BlockTags.CORALS.getStates().toArray(new StateType[0])),
|
||||
SWEET_BERRY((player, version, data, x, y, z) -> {
|
||||
if (data.getAge() == 0) {
|
||||
return new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 8.0D, 13.0D);
|
||||
} else if (data.getAge() < 3) {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D);
|
||||
}
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}, StateTypes.SWEET_BERRY_BUSH),
|
||||
|
||||
RAILS(NoCollisionBox.INSTANCE, BlockTags.RAILS.getStates().toArray(new StateType[0])),
|
||||
SAPLING(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D),
|
||||
BlockTags.SAPLINGS.getStates().toArray(new StateType[0])),
|
||||
|
||||
BANNER(NoCollisionBox.INSTANCE, BlockTags.BANNERS.getStates().toArray(new StateType[0])),
|
||||
ROOTS(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 13.0D, 14.0D),
|
||||
StateTypes.WARPED_ROOTS, StateTypes.CRIMSON_ROOTS),
|
||||
|
||||
SMALL_FLOWER(NoCollisionBox.INSTANCE, BlockTags.SMALL_FLOWERS.getStates().toArray(new StateType[0])),
|
||||
FLOWER(new HexCollisionBox(5.0D, 0.0D, 5.0D, 11.0D, 10.0D, 11.0D),
|
||||
BlockTags.SMALL_FLOWERS.getStates().toArray(new StateType[0])),
|
||||
|
||||
TALL_FLOWER(NoCollisionBox.INSTANCE, BlockTags.TALL_FLOWERS.getStates().toArray(new StateType[0])),
|
||||
DEAD_BUSH(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 13.0D, 14.0D), StateTypes.DEAD_BUSH),
|
||||
|
||||
SAPLING(NoCollisionBox.INSTANCE, BlockTags.SAPLINGS.getStates().toArray(new StateType[0])),
|
||||
SUGARCANE(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 16.0D, 14.0D), StateTypes.SUGAR_CANE),
|
||||
|
||||
BUTTON(NoCollisionBox.INSTANCE, BlockTags.BUTTONS.getStates().toArray(new StateType[0])),
|
||||
NETHER_SPROUTS(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 3.0D, 14.0D), StateTypes.NETHER_SPROUTS),
|
||||
|
||||
// All states that unconditionally have no collision and are not in a group where every member also has no collision.
|
||||
NO_COLLISION(NoCollisionBox.INSTANCE, StateTypes.TWISTING_VINES_PLANT, StateTypes.WEEPING_VINES_PLANT,
|
||||
StateTypes.TWISTING_VINES, StateTypes.WEEPING_VINES, StateTypes.CAVE_VINES, StateTypes.CAVE_VINES_PLANT,
|
||||
StateTypes.TALL_SEAGRASS, StateTypes.SEAGRASS, StateTypes.SHORT_GRASS, StateTypes.FERN, StateTypes.NETHER_SPROUTS,
|
||||
StateTypes.DEAD_BUSH, StateTypes.SUGAR_CANE, StateTypes.SWEET_BERRY_BUSH, StateTypes.WARPED_ROOTS,
|
||||
StateTypes.CRIMSON_ROOTS, StateTypes.TORCHFLOWER_CROP, StateTypes.PINK_PETALS, StateTypes.TALL_GRASS,
|
||||
StateTypes.LARGE_FERN, StateTypes.BAMBOO_SAPLING, StateTypes.HANGING_ROOTS,
|
||||
StateTypes.SMALL_DRIPLEAF, StateTypes.END_PORTAL, StateTypes.LEVER, StateTypes.PUMPKIN_STEM, StateTypes.MELON_STEM,
|
||||
StateTypes.ATTACHED_MELON_STEM, StateTypes.ATTACHED_PUMPKIN_STEM, StateTypes.BEETROOTS, StateTypes.POTATOES,
|
||||
StateTypes.WHEAT, StateTypes.CARROTS, StateTypes.NETHER_WART, StateTypes.MOVING_PISTON, StateTypes.AIR, StateTypes.CAVE_AIR,
|
||||
StateTypes.VOID_AIR, StateTypes.LIGHT, StateTypes.WATER),
|
||||
GRASS_FERN(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 13.0D, 14.0D),
|
||||
StateTypes.GRASS, StateTypes.FERN),
|
||||
|
||||
TALL_GRASS(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.TALL_GRASS),
|
||||
|
||||
SEA_GRASS(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D),
|
||||
StateTypes.SEAGRASS),
|
||||
|
||||
CAVE_VINES(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D), StateTypes.CAVE_VINES, StateTypes.CAVE_VINES_PLANT),
|
||||
|
||||
TWISTING_VINES_BLOCK(new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, 15.0D, 12.0D), StateTypes.TWISTING_VINES, StateTypes.WEEPING_VINES),
|
||||
|
||||
TWISTING_VINES(new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, 16.0D, 12.0D), StateTypes.TWISTING_VINES_PLANT, StateTypes.WEEPING_VINES_PLANT),
|
||||
|
||||
KELP(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 9.0D, 16.0D), StateTypes.KELP),
|
||||
// Kelp block is a full block, so it by default is correct
|
||||
@@ -410,6 +445,33 @@ public enum CollisionData {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 15.0D, 15.0D); // post
|
||||
}, StateTypes.HONEY_BLOCK),
|
||||
|
||||
SPORE_BLOSSOM(new HexCollisionBox(2.0D, 13.0D, 2.0D, 14.0D, 16.0D, 14.0D), StateTypes.SPORE_BLOSSOM),
|
||||
|
||||
GLOW_LICHEN((player, version, data, x, y, z) -> {
|
||||
ComplexCollisionBox box = new ComplexCollisionBox();
|
||||
|
||||
if (data.isUp()) {
|
||||
box.add(new HexCollisionBox(0.0D, 15.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.isDown()) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D));
|
||||
}
|
||||
if (data.getWest() == West.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getEast() == East.TRUE) {
|
||||
box.add(new HexCollisionBox(15.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getNorth() == North.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 1.0D));
|
||||
}
|
||||
if (data.getSouth() == South.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 15.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
|
||||
return box;
|
||||
}, StateTypes.GLOW_LICHEN),
|
||||
|
||||
DRAGON_EGG_BLOCK(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D), StateTypes.DRAGON_EGG),
|
||||
|
||||
GRINDSTONE((player, version, data, x, y, z) -> {
|
||||
@@ -505,7 +567,7 @@ public enum CollisionData {
|
||||
|
||||
}, StateTypes.GRINDSTONE),
|
||||
|
||||
PANE(new DynamicCollisionPane(), Materials.getPanes().toArray(new StateType[0])),
|
||||
PANE(new DynamicPane(), Materials.getPanes().toArray(new StateType[0])),
|
||||
|
||||
CHAIN_BLOCK((player, version, data, x, y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_16)) {
|
||||
@@ -542,7 +604,7 @@ public enum CollisionData {
|
||||
|
||||
}, BlockTags.FENCE_GATES.getStates().toArray(new StateType[0])),
|
||||
|
||||
FENCE(new DynamicCollisionFence(), BlockTags.FENCES.getStates().toArray(new StateType[0])),
|
||||
FENCE(new DynamicFence(), BlockTags.FENCES.getStates().toArray(new StateType[0])),
|
||||
|
||||
SNOW((player, version, data, x, y, z) -> {
|
||||
if (data.getLayers() == 1 && version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
|
||||
@@ -620,6 +682,8 @@ public enum CollisionData {
|
||||
|
||||
}, StateTypes.FARMLAND),
|
||||
|
||||
HANGING_ROOTS(new HexCollisionBox(2.0D, 10.0D, 2.0D, 14.0D, 16.0D, 14.0D), StateTypes.HANGING_ROOTS),
|
||||
|
||||
GRASS_PATH((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_9))
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 15.0D, 16.0D);
|
||||
@@ -682,36 +746,17 @@ public enum CollisionData {
|
||||
}, StateTypes.END_ROD, StateTypes.LIGHTNING_ROD),
|
||||
|
||||
CAULDRON((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.getById(467))) { // changed in 19w13a, 1.14 Snapshot
|
||||
return new ComplexCollisionBox(
|
||||
new SimpleCollisionBox(0.0, 0.0, 0.0, 0.125, 1.0, 0.25, false),
|
||||
new SimpleCollisionBox(0.0, 0.0, 0.75, 0.125, 1.0, 1.0, false),
|
||||
new SimpleCollisionBox(0.125, 0.0, 0.0, 0.25, 1.0, 0.125, false),
|
||||
new SimpleCollisionBox(0.125, 0.0, 0.875, 0.25, 1.0, 1.0, false),
|
||||
new SimpleCollisionBox(0.75, 0.0, 0.0, 1.0, 1.0, 0.125, false),
|
||||
new SimpleCollisionBox(0.75, 0.0, 0.875, 1.0, 1.0, 1.0, false),
|
||||
new SimpleCollisionBox(0.875, 0.0, 0.125, 1.0, 1.0, 0.25, false),
|
||||
new SimpleCollisionBox(0.875, 0.0, 0.75, 1.0, 1.0, 0.875, false),
|
||||
new SimpleCollisionBox(0.0, 0.1875, 0.25, 1.0, 0.25, 0.75, false),
|
||||
new SimpleCollisionBox(0.125, 0.1875, 0.125, 0.875, 0.25, 0.25, false),
|
||||
new SimpleCollisionBox(0.125, 0.1875, 0.75, 0.875, 0.25, 0.875, false),
|
||||
new SimpleCollisionBox(0.25, 0.1875, 0.0, 0.75, 1.0, 0.125, false),
|
||||
new SimpleCollisionBox(0.25, 0.1875, 0.875, 0.75, 1.0, 1.0, false),
|
||||
new SimpleCollisionBox(0.0, 0.25, 0.25, 0.125, 1.0, 0.75, false),
|
||||
new SimpleCollisionBox(0.875, 0.25, 0.25, 1.0, 1.0, 0.75, false)
|
||||
);
|
||||
} else {
|
||||
double height = 0.25;
|
||||
if (version.isOlderThan(ClientVersion.V_1_13))
|
||||
height = 0.3125;
|
||||
double height = 0.25;
|
||||
|
||||
return new ComplexCollisionBox(
|
||||
new SimpleCollisionBox(0, 0, 0, 1, height, 1, false),
|
||||
new SimpleCollisionBox(0, height, 0, 0.125, 1, 1, false),
|
||||
new SimpleCollisionBox(1 - 0.125, height, 0, 1, 1, 1, false),
|
||||
new SimpleCollisionBox(0, height, 0, 1, 1, 0.125, false),
|
||||
new SimpleCollisionBox(0, height, 1 - 0.125, 1, 1, 1, false));
|
||||
}
|
||||
if (version.isOlderThan(ClientVersion.V_1_13))
|
||||
height = 0.3125;
|
||||
|
||||
return new ComplexCollisionBox(
|
||||
new SimpleCollisionBox(0, 0, 0, 1, height, 1, false),
|
||||
new SimpleCollisionBox(0, height, 0, 0.125, 1, 1, false),
|
||||
new SimpleCollisionBox(1 - 0.125, height, 0, 1, 1, 1, false),
|
||||
new SimpleCollisionBox(0, height, 0, 1, 1, 0.125, false),
|
||||
new SimpleCollisionBox(0, height, 1 - 0.125, 1, 1, 1, false));
|
||||
}, BlockTags.CAULDRONS.getStates().toArray(new StateType[0])),
|
||||
|
||||
CACTUS(new SimpleCollisionBox(0.0625, 0, 0.0625,
|
||||
@@ -784,18 +829,71 @@ public enum CollisionData {
|
||||
|
||||
CORAL_PLANT((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 15.0D, 14.0D);
|
||||
}, Stream.concat(
|
||||
Arrays.stream(BlockTags.CORAL_PLANTS.getStates().toArray(new StateType[0])),
|
||||
Stream.of(StateTypes.DEAD_HORN_CORAL, StateTypes.DEAD_TUBE_CORAL, StateTypes.DEAD_BRAIN_CORAL,
|
||||
StateTypes.DEAD_BUBBLE_CORAL, StateTypes.DEAD_FIRE_CORAL)
|
||||
)
|
||||
.distinct() // This will remove duplicates
|
||||
.toArray(StateType[]::new)
|
||||
),
|
||||
}, BlockTags.CORAL_PLANTS.getStates().toArray(new StateType[0])),
|
||||
|
||||
SIGN(new SimpleCollisionBox(0.25, 0.0, 0.25, 0.75, 1.0, 0.75, false),
|
||||
BlockTags.STANDING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
BEETROOT((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, (data.getAge() + 1) * 2, 1.0D);
|
||||
}, StateTypes.BEETROOTS),
|
||||
|
||||
WHEAT((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, (data.getAge() + 1) * 2, 1.0D);
|
||||
}, StateTypes.WHEAT),
|
||||
|
||||
CARROT_NETHERWART((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, data.getAge() + 2, 1.0D);
|
||||
}, StateTypes.CARROTS, StateTypes.NETHER_WART),
|
||||
|
||||
NETHER_WART((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 5 + (data.getAge() * 3), 1.0D);
|
||||
}, StateTypes.NETHER_WART),
|
||||
|
||||
BUTTON((player, version, data, x, y, z) -> {
|
||||
double f2 = (float) (data.isPowered() ? 1 : 2) / 16.0;
|
||||
|
||||
switch (data.getFacing()) {
|
||||
case WEST:
|
||||
return new SimpleCollisionBox(0.0, 0.375, 0.3125, f2, 0.625, 0.6875, false);
|
||||
case EAST:
|
||||
return new SimpleCollisionBox(1.0 - f2, 0.375, 0.3125, 1.0, 0.625, 0.6875, false);
|
||||
case NORTH:
|
||||
return new SimpleCollisionBox(0.3125, 0.375, 0.0, 0.6875, 0.625, f2, false);
|
||||
case SOUTH:
|
||||
return new SimpleCollisionBox(0.3125, 0.375, 1.0 - f2, 0.6875, 0.625, 1.0, false);
|
||||
case DOWN:
|
||||
return new SimpleCollisionBox(0.3125, 0.0, 0.375, 0.6875, 0.0 + f2, 0.625, false);
|
||||
case UP:
|
||||
return new SimpleCollisionBox(0.3125, 1.0 - f2, 0.375, 0.6875, 1.0, 0.625, false);
|
||||
}
|
||||
|
||||
return NoCollisionBox.INSTANCE;
|
||||
|
||||
}, BlockTags.BUTTONS.getStates().toArray(new StateType[0])),
|
||||
|
||||
LEVER((player, version, data, x, y, z) -> {
|
||||
double f = 0.1875;
|
||||
|
||||
switch (data.getFacing()) {
|
||||
case WEST:
|
||||
return new SimpleCollisionBox(1.0 - f * 2.0, 0.2, 0.5 - f, 1.0, 0.8, 0.5 + f, false);
|
||||
case EAST:
|
||||
return new SimpleCollisionBox(0.0, 0.2, 0.5 - f, f * 2.0, 0.8, 0.5 + f, false);
|
||||
case NORTH:
|
||||
return new SimpleCollisionBox(0.5 - f, 0.2, 1.0 - f * 2.0, 0.5 + f, 0.8, 1.0, false);
|
||||
case SOUTH:
|
||||
return new SimpleCollisionBox(0.5 - f, 0.2, 0.0, 0.5 + f, 0.8, f * 2.0, false);
|
||||
case DOWN:
|
||||
return new SimpleCollisionBox(0.25, 0.4, 0.25, 0.75, 1.0, 0.75, false);
|
||||
case UP:
|
||||
return new SimpleCollisionBox(0.25, 0.0, 0.25, 0.75, 0.6, 0.75, false);
|
||||
}
|
||||
|
||||
return NoCollisionBox.INSTANCE;
|
||||
|
||||
}, StateTypes.LEVER),
|
||||
|
||||
STONE_PRESSURE_PLATE((player, version, data, x, y, z) -> {
|
||||
if (data.isPowered()) { // Pressed
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 0.5D, 15.0D);
|
||||
@@ -827,6 +925,27 @@ public enum CollisionData {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D);
|
||||
}, StateTypes.TRIPWIRE),
|
||||
|
||||
ATTACHED_PUMPKIN_STEM((player, version, data, x, y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_13))
|
||||
return new HexCollisionBox(7.0D, 0.0D, 7.0D, 9.0D, 16.0D, 9.0D);
|
||||
|
||||
switch (data.getFacing()) {
|
||||
case SOUTH:
|
||||
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 16.0D);
|
||||
case WEST:
|
||||
return new HexCollisionBox(0.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D);
|
||||
case NORTH:
|
||||
return new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 10.0D, 10.0D);
|
||||
case EAST:
|
||||
default:
|
||||
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 16.0D, 10.0D, 10.0D);
|
||||
}
|
||||
}, StateTypes.ATTACHED_MELON_STEM, StateTypes.ATTACHED_PUMPKIN_STEM),
|
||||
|
||||
PUMPKIN_STEM((player, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(7, 0, 7, 9, 2 * (data.getAge() + 1), 9);
|
||||
}, StateTypes.PUMPKIN_STEM, StateTypes.MELON_STEM),
|
||||
|
||||
TRIPWIRE_HOOK((player, version, data, x, y, z) -> {
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
@@ -861,6 +980,20 @@ public enum CollisionData {
|
||||
|
||||
}, StateTypes.WALL_TORCH, StateTypes.REDSTONE_WALL_TORCH),
|
||||
|
||||
RAILS((player, version, data, x, y, z) -> {
|
||||
Shape shape = data.getShape();
|
||||
if (shape == Shape.ASCENDING_EAST || shape == Shape.ASCENDING_WEST ||
|
||||
shape == Shape.ASCENDING_NORTH || shape == Shape.ASCENDING_SOUTH) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D);
|
||||
}
|
||||
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D);
|
||||
|
||||
}, BlockTags.RAILS.getStates().toArray(new StateType[0])),
|
||||
|
||||
// Known as block 36 - has no collision box
|
||||
TECHNICAL_MOVING_PISTON(NoCollisionBox.INSTANCE, StateTypes.MOVING_PISTON),
|
||||
|
||||
// 1.17 blocks
|
||||
CANDLE((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_17)) {
|
||||
@@ -889,13 +1022,7 @@ public enum CollisionData {
|
||||
|
||||
SCULK_SENSOR(new HexCollisionBox(0.0, 0.0, 0.0, 16.0, 8.0, 16.0), StateTypes.SCULK_SENSOR, StateTypes.CALIBRATED_SCULK_SENSOR),
|
||||
|
||||
DECORATED_POT((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_3)) {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0);
|
||||
} else { // ViaVersion replacement is a Brick
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.DECORATED_POT),
|
||||
DECORATED_POT(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0), StateTypes.DECORATED_POT),
|
||||
|
||||
BIG_DRIPLEAF((player, version, data, x, y, z) -> {
|
||||
if (version.isOlderThanOrEquals(ClientVersion.V_1_16_4))
|
||||
@@ -911,29 +1038,34 @@ public enum CollisionData {
|
||||
|
||||
}, StateTypes.BIG_DRIPLEAF),
|
||||
|
||||
POINTED_DRIPSTONE((player, version, data, x, y, z) -> {
|
||||
DRIPSTONE((player, version, data, x, y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_17))
|
||||
return getEndRod(version, BlockFace.UP);
|
||||
|
||||
SimpleCollisionBox box;
|
||||
HexCollisionBox box;
|
||||
|
||||
if (data.getThickness() == Thickness.TIP_MERGE) {
|
||||
box = new HexOffsetCollisionBox(data.getType(), 5.0, 0.0, 5.0, 11.0, 16.0, 11.0);
|
||||
box = new HexCollisionBox(5.0, 0.0, 5.0, 11.0, 16.0, 11.0);
|
||||
} else if (data.getThickness() == Thickness.TIP) {
|
||||
if (data.getVerticalDirection() == VerticalDirection.DOWN) {
|
||||
box = new HexOffsetCollisionBox(data.getType(), 5.0, 5.0, 5.0, 11.0, 16.0, 11.0);
|
||||
box = new HexCollisionBox(5.0, 5.0, 5.0, 11.0, 16.0, 11.0);
|
||||
} else {
|
||||
box = new HexOffsetCollisionBox(data.getType(), 5.0, 0.0, 5.0, 11.0, 11.0, 11.0);
|
||||
box = new HexCollisionBox(5.0, 0.0, 5.0, 11.0, 11.0, 11.0);
|
||||
}
|
||||
} else if (data.getThickness() == Thickness.FRUSTUM) {
|
||||
box = new HexOffsetCollisionBox(data.getType(), 4.0, 0.0, 4.0, 12.0, 16.0, 12.0);
|
||||
box = new HexCollisionBox(4.0, 0.0, 4.0, 12.0, 16.0, 12.0);
|
||||
} else if (data.getThickness() == Thickness.MIDDLE) {
|
||||
box = new HexOffsetCollisionBox(data.getType(), 3.0, 0.0, 3.0, 13.0, 16.0, 13.0);
|
||||
box = new HexCollisionBox(3.0, 0.0, 3.0, 13.0, 16.0, 13.0);
|
||||
} else {
|
||||
box = new HexOffsetCollisionBox(data.getType(), 2.0, 0.0, 2.0, 14.0, 16.0, 14.0);
|
||||
box = new HexCollisionBox(2.0, 0.0, 2.0, 14.0, 16.0, 14.0);
|
||||
}
|
||||
|
||||
return box;
|
||||
// Copied from NMS and it works! That's all you need to know.
|
||||
long i = (x * 3129871L) ^ (long) z * 116129781L ^ (long) 0;
|
||||
i = i * i * 42317861L + i * 11L;
|
||||
i = i >> 16;
|
||||
|
||||
return box.offset(GrimMath.clamp((((i & 15L) / 15.0F) - 0.5D) * 0.5D, -0.125f, 0.125f), 0, GrimMath.clamp((((i >> 8 & 15L) / 15.0F) - 0.5D) * 0.5D, -0.125f, 0.125f));
|
||||
}, StateTypes.POINTED_DRIPSTONE),
|
||||
|
||||
POWDER_SNOW((player, version, data, x, y, z) -> {
|
||||
@@ -960,6 +1092,8 @@ public enum CollisionData {
|
||||
return new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 16.0D, 16.0D);
|
||||
}, StateTypes.NETHER_PORTAL),
|
||||
|
||||
END_PORTAL(new HexCollisionBox(0.0D, 6.0D, 0.0D, 16.0D, 12.0D, 16.0D), StateTypes.END_PORTAL),
|
||||
|
||||
AZALEA((player, version, data, x, y, z) -> {
|
||||
return new ComplexCollisionBox(new HexCollisionBox(0.0, 8.0, 0.0, 16.0, 16.0, 16.0),
|
||||
new HexCollisionBox(6.0, 0.0, 6.0, 10.0, 8.0, 10.0));
|
||||
@@ -1007,34 +1141,30 @@ public enum CollisionData {
|
||||
}
|
||||
}, StateTypes.MANGROVE_PROPAGULE),
|
||||
|
||||
SCULK_SHRIKER((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_18_2)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D);
|
||||
} else {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.SCULK_SHRIEKER),
|
||||
SCULK_SHRIKER(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D), StateTypes.SCULK_SHRIEKER),
|
||||
|
||||
SNIFFER_EGG((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_4)) {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 2.0D, 15.0D, 16.0D, 14.0D);
|
||||
} else {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
FROGSPAWN(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.5D, 16.0D), StateTypes.FROGSPAWN),
|
||||
|
||||
SNIFFER_EGG(new HexCollisionBox(1.0D, 0.0D, 2.0D, 15.0D, 16.0D, 14.0D), StateTypes.SNIFFER_EGG),
|
||||
|
||||
PINK_PETALS_BLOCK(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D), StateTypes.PINK_PETALS),
|
||||
|
||||
TORCHFLOWER_CROP((player, version, data, x, y, z) -> {
|
||||
if (data.getAge() == 0) {
|
||||
return new HexCollisionBox(5.0D, 0.0D, 5.0D, 11.0D, 6.0D, 11.0D);
|
||||
}
|
||||
}, StateTypes.SNIFFER_EGG),
|
||||
// age is 1
|
||||
return new HexCollisionBox(5.0D, 0.0D, 5.0D, 11.0D, 10.0D, 11.0D);
|
||||
}, StateTypes.TORCHFLOWER_CROP),
|
||||
|
||||
PITCHER_CROP((player, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_4)) {
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
|
||||
if (data.getAge() == 0) {
|
||||
return COLLISION_SHAPE_BULB;
|
||||
} else {
|
||||
return data.getHalf() == Half.LOWER ? COLLISION_SHAPE_CROP : NoCollisionBox.INSTANCE;
|
||||
}
|
||||
if (data.getAge() == 0) {
|
||||
return COLLISION_SHAPE_BULB;
|
||||
} else {
|
||||
return NoCollisionBox.INSTANCE;
|
||||
return data.getHalf() == Half.LOWER ? COLLISION_SHAPE_CROP : NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, StateTypes.PITCHER_CROP),
|
||||
|
||||
@@ -1051,6 +1181,8 @@ public enum CollisionData {
|
||||
}
|
||||
}, BlockTags.WALL_HANGING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
NONE(NoCollisionBox.INSTANCE, StateTypes.AIR, StateTypes.CAVE_AIR, StateTypes.VOID_AIR, StateTypes.LIGHT),
|
||||
|
||||
DEFAULT(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.STONE);
|
||||
|
||||
// This should be an array... but a hashmap will do for now...
|
||||
@@ -1122,7 +1254,7 @@ public enum CollisionData {
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
|
||||
public static CollisionBox getCocoa(ClientVersion version, int age, BlockFace direction) {
|
||||
private static CollisionBox getCocoa(ClientVersion version, int age, BlockFace direction) {
|
||||
// From 1.9 - 1.10, the large cocoa block is the same as the medium one
|
||||
// https://bugs.mojang.com/browse/MC-94274
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_9_1) && version.isOlderThan(ClientVersion.V_1_11))
|
||||
@@ -1191,7 +1323,7 @@ public enum CollisionData {
|
||||
// Would pre-computing all states be worth the memory cost? I doubt it
|
||||
public static CollisionData getData(StateType state) { // TODO: Find a better hack for lava and scaffolding
|
||||
// What the fuck mojang, why put noCollision() and then give PITCHER_CROP collision?
|
||||
return state.isSolid() || state == StateTypes.LAVA || state == StateTypes.SCAFFOLDING || state == StateTypes.PITCHER_CROP || state == StateTypes.HEAVY_CORE || BlockTags.WALL_HANGING_SIGNS.contains(state) ? rawLookupMap.getOrDefault(state, DEFAULT) : NO_COLLISION;
|
||||
return state.isSolid() || state == StateTypes.LAVA || state == StateTypes.SCAFFOLDING || state == StateTypes.PITCHER_CROP || state == StateTypes.HEAVY_CORE || BlockTags.WALL_HANGING_SIGNS.contains(state) ? rawLookupMap.getOrDefault(state, DEFAULT) : NONE;
|
||||
}
|
||||
|
||||
// TODO: This is wrong if a block doesn't have any hitbox and isn't specified, light block?
|
||||
|
||||
@@ -1,9 +1,8 @@
|
||||
package ac.grim.grimac.utils.collisions;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicHitboxFence;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicHitboxPane;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicHitboxWall;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicFence;
|
||||
import ac.grim.grimac.utils.collisions.blocks.connecting.DynamicWall;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.*;
|
||||
import ac.grim.grimac.utils.nmsutil.Materials;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
@@ -18,510 +17,9 @@ import java.util.*;
|
||||
|
||||
// Expansion to the CollisionData class, which is different than regular ray tracing hitboxes
|
||||
public enum HitboxData {
|
||||
|
||||
RAILS((player, item, version, data, x, y, z) -> {
|
||||
switch (data.getShape()) {
|
||||
case ASCENDING_NORTH:
|
||||
case ASCENDING_SOUTH:
|
||||
case ASCENDING_EAST:
|
||||
case ASCENDING_WEST:
|
||||
if (version.isOlderThan(ClientVersion.V_1_8)) {
|
||||
StateType railType = data.getType();
|
||||
// Activator rails always appear as flat detector rails in 1.7.10 because of ViaVersion
|
||||
// Ascending power rails in 1.7 have flat rail hitbox https://bugs.mojang.com/browse/MC-9134
|
||||
if (railType == StateTypes.ACTIVATOR_RAIL || (railType == StateTypes.POWERED_RAIL && data.isPowered())) {
|
||||
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F, false);
|
||||
}
|
||||
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F, false);
|
||||
} else if (version.isOlderThan(ClientVersion.V_1_9)) {
|
||||
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.625F, 1.0F, false);
|
||||
} else if (version.isNewerThanOrEquals(ClientVersion.V_1_9) && version.isOlderThan(ClientVersion.V_1_10)) {
|
||||
// https://bugs.mojang.com/browse/MC-89552 sloped rails in 1.9 - it is slightly taller than a regular rail
|
||||
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.1875F, 1.0F, false);
|
||||
} else if (version.isOlderThan(ClientVersion.V_1_11)) {
|
||||
// https://bugs.mojang.com/browse/MC-102638 All sloped rails are full blocks in 1.10
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 8.0D, 16.0D);
|
||||
default:
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D);
|
||||
}
|
||||
}, BlockTags.RAILS.getStates().toArray(new StateType[0])),
|
||||
|
||||
END_PORTAL((player, item, version, data, x, y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_9)) {
|
||||
return new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 0.0625D, 1.0D);
|
||||
} else if (version.isOlderThan(ClientVersion.V_1_17)) {
|
||||
return new SimpleCollisionBox(0.0, 0.0D, 0.0D, 1.0D, 0.75D, 1.0D);
|
||||
}
|
||||
return new HexCollisionBox(0.0D, 6.0D, 0.0D, 16.0D, 12.0D, 16.0D);
|
||||
}, StateTypes.END_PORTAL),
|
||||
|
||||
FENCE_GATE((player, item, version, data, x, y, z) -> {
|
||||
// This technically should be taken from the block data/made multi-version/run block updates... but that's too far even for me
|
||||
// This way is so much easier and works unless the magic stick wand is used
|
||||
boolean isInWall;
|
||||
boolean isXAxis = data.getFacing() == BlockFace.WEST || data.getFacing() == BlockFace.EAST;
|
||||
if (isXAxis) {
|
||||
boolean zPosWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x, y, z + 1));
|
||||
boolean zNegWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x, y, z - 1));
|
||||
isInWall = zPosWall || zNegWall;
|
||||
} else {
|
||||
boolean xPosWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x + 1, y, z));
|
||||
boolean xNegWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x - 1, y, z));
|
||||
isInWall = xPosWall || xNegWall;
|
||||
}
|
||||
|
||||
if (isInWall) {
|
||||
return isXAxis ? new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 13.0D, 16.0D) : new HexCollisionBox(0.0D, 0.0D, 6.0D, 16.0D, 13.0D, 10.0D);
|
||||
}
|
||||
|
||||
return isXAxis ? new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 16.0D, 16.0D) : new HexCollisionBox(0.0D, 0.0D, 6.0D, 16.0D, 16.0D, 10.0D);
|
||||
}, BlockTags.FENCE_GATES.getStates().toArray(new StateType[0])),
|
||||
|
||||
|
||||
FENCE(new DynamicHitboxFence(), BlockTags.FENCES.getStates().toArray(new StateType[0])),
|
||||
|
||||
PANE(new DynamicHitboxPane(), Materials.getPanes().toArray(new StateType[0])),
|
||||
|
||||
LEVER(((player, item, version, data, x, y, z) -> {
|
||||
Face face = data.getFace();
|
||||
BlockFace facing = data.getFacing();
|
||||
if (version.isOlderThan(ClientVersion.V_1_13)) {
|
||||
double f = 0.1875;
|
||||
|
||||
switch (face) {
|
||||
case WALL:
|
||||
switch (facing) {
|
||||
case WEST:
|
||||
return new SimpleCollisionBox(1.0 - f * 2.0, 0.2, 0.5 - f, 1.0, 0.8, 0.5 + f, false);
|
||||
case EAST:
|
||||
return new SimpleCollisionBox(0.0, 0.2, 0.5 - f, f * 2.0, 0.8, 0.5 + f, false);
|
||||
case NORTH:
|
||||
return new SimpleCollisionBox(0.5 - f, 0.2, 1.0 - f * 2.0, 0.5 + f, 0.8, 1.0, false);
|
||||
case SOUTH:
|
||||
return new SimpleCollisionBox(0.5 - f, 0.2, 0.0, 0.5 + f, 0.8, f * 2.0, false);
|
||||
}
|
||||
case CEILING:
|
||||
return new SimpleCollisionBox(0.25, 0.4, 0.25, 0.75, 1.0, 0.75, false);
|
||||
case FLOOR:
|
||||
return new SimpleCollisionBox(0.25, 0.0, 0.25, 0.75, 0.6, 0.75, false);
|
||||
}
|
||||
}
|
||||
|
||||
switch (face) {
|
||||
case FLOOR:
|
||||
// X-AXIS
|
||||
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
|
||||
return new SimpleCollisionBox(0.25, 0.0, 0.3125, 0.75, 0.375, 0.6875, false);
|
||||
}
|
||||
// Z-AXIS
|
||||
return new SimpleCollisionBox(0.3125, 0.0, 0.25, 0.6875, 0.375, 0.75, false);
|
||||
case WALL:
|
||||
switch (facing) {
|
||||
case EAST:
|
||||
return new SimpleCollisionBox(0.0, 0.25, 0.3125, 0.375, 0.75, 0.6875, false);
|
||||
case WEST:
|
||||
return new SimpleCollisionBox(0.625, 0.25, 0.3125, 1.0, 0.75, 0.6875, false);
|
||||
case SOUTH:
|
||||
return new SimpleCollisionBox(0.3125, 0.25, 0.0, 0.6875, 0.75, 0.375, false);
|
||||
case NORTH:
|
||||
default:
|
||||
return new SimpleCollisionBox(0.3125, 0.25, 0.625, 0.6875, 0.75, 1.0, false);
|
||||
}
|
||||
case CEILING:
|
||||
default:
|
||||
// X-AXIS
|
||||
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
|
||||
return new SimpleCollisionBox(0.25, 0.625, 0.3125, 0.75, 1.0, 0.6875, false);
|
||||
}
|
||||
// Z-Axis
|
||||
return new SimpleCollisionBox(0.3125, 0.625, 0.25, 0.6875, 1.0, 0.75, false);
|
||||
}
|
||||
}), StateTypes.LEVER),
|
||||
|
||||
BUTTON((player, item, version, data, x, y, z) -> {
|
||||
final Face face = data.getFace();
|
||||
final BlockFace facing = data.getFacing();
|
||||
final boolean powered = data.isPowered();
|
||||
|
||||
|
||||
if (version.isOlderThan(ClientVersion.V_1_13)) {
|
||||
double f2 = (float) (data.isPowered() ? 1 : 2) / 16.0;
|
||||
|
||||
switch (face) {
|
||||
case WALL:
|
||||
switch (facing) {
|
||||
case WEST:
|
||||
return new SimpleCollisionBox(0.0, 0.375, 0.3125, f2, 0.625, 0.6875, false);
|
||||
case EAST:
|
||||
return new SimpleCollisionBox(1.0 - f2, 0.375, 0.3125, 1.0, 0.625, 0.6875, false);
|
||||
case NORTH:
|
||||
return new SimpleCollisionBox(0.3125, 0.375, 0.0, 0.6875, 0.625, f2, false);
|
||||
case SOUTH:
|
||||
return new SimpleCollisionBox(0.3125, 0.375, 1.0 - f2, 0.6875, 0.625, 1.0, false);
|
||||
}
|
||||
case CEILING:
|
||||
return new SimpleCollisionBox(0.3125, 1.0 - f2, 0.375, 0.6875, 1.0, 0.625, false);
|
||||
case FLOOR:
|
||||
return new SimpleCollisionBox(0.3125, 0.0, 0.375, 0.6875, 0.0 + f2, 0.625, false);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
switch (face) {
|
||||
case WALL:
|
||||
CollisionBox shape;
|
||||
switch (facing) {
|
||||
case EAST:
|
||||
shape = powered ? new HexCollisionBox(0.0, 6.0, 5.0, 1.0, 10.0, 11.0) : new HexCollisionBox(0.0, 6.0, 5.0, 2.0, 10.0, 11.0);
|
||||
break;
|
||||
case WEST:
|
||||
shape = powered ? new HexCollisionBox(15.0, 6.0, 5.0, 16.0, 10.0, 11.0) : new HexCollisionBox(14.0, 6.0, 5.0, 16.0, 10.0, 11.0);
|
||||
break;
|
||||
case SOUTH:
|
||||
shape = powered ? new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 1.0) : new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 2.0);
|
||||
break;
|
||||
case NORTH:
|
||||
case UP:
|
||||
case DOWN:
|
||||
shape = powered ? new HexCollisionBox(5.0, 6.0, 15.0, 11.0, 10.0, 16.0) : new HexCollisionBox(5.0, 6.0, 14.0, 11.0, 10.0, 16.0);
|
||||
break;
|
||||
default:
|
||||
shape = NoCollisionBox.INSTANCE;
|
||||
}
|
||||
|
||||
return shape;
|
||||
case CEILING:
|
||||
// ViaVersion shows lever
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
|
||||
return LEVER.dynamic.fetch(player, item, version, data, x, y, z);
|
||||
}
|
||||
// x axis
|
||||
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
|
||||
return powered ? new HexCollisionBox(6.0, 15.0, 5.0, 10.0, 16.0, 11.0) : new HexCollisionBox(6.0, 14.0, 5.0, 10.0, 16.0, 11.0);
|
||||
} else {
|
||||
return powered ? new HexCollisionBox(5.0, 15.0, 6.0, 11.0, 16.0, 10.0) : new HexCollisionBox(5.0, 14.0, 6.0, 11.0, 16.0, 10.0);
|
||||
}
|
||||
case FLOOR:
|
||||
// ViaVersion shows lever
|
||||
if (player.getClientVersion().isOlderThan(ClientVersion.V_1_8)) {
|
||||
return LEVER.dynamic.fetch(player, item, version, data, x, y, z);
|
||||
}
|
||||
// x axis
|
||||
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
|
||||
return powered ? new HexCollisionBox(6.0, 0.0, 5.0, 10.0, 1.0, 11.0) : new HexCollisionBox(6.0, 0.0, 5.0, 10.0, 2.0, 11.0);
|
||||
}
|
||||
|
||||
return powered ? new HexCollisionBox(5.0, 0.0, 6.0, 11.0, 1.0, 10.0) : new HexCollisionBox(5.0, 0.0, 6.0, 11.0, 2.0, 10.0);
|
||||
default:
|
||||
throw new IllegalStateException("Impossible Hitbox State");
|
||||
}
|
||||
}, BlockTags.BUTTONS.getStates().toArray(new StateType[0])),
|
||||
|
||||
WALL(new DynamicHitboxWall(), BlockTags.WALLS.getStates().toArray(new StateType[0])),
|
||||
|
||||
WALL_SIGN((player, item, version, data, x, y, z) -> {
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
return new HexCollisionBox(0.0, 4.5, 14.0, 16.0, 12.5, 16.0);
|
||||
case SOUTH:
|
||||
return new HexCollisionBox(0.0, 4.5, 0.0, 16.0, 12.5, 2.0);
|
||||
case EAST:
|
||||
return new HexCollisionBox(0.0, 4.5, 0.0, 2.0, 12.5, 16.0);
|
||||
case WEST:
|
||||
return new HexCollisionBox(14.0, 4.5, 0.0, 16.0, 12.5, 16.0);
|
||||
default:
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, BlockTags.WALL_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
WALL_HANGING_SIGN((player, item, version, data, x, y, z) -> {
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
return new ComplexCollisionBox(new HexCollisionBox(0.0D, 14.0D, 6.0D, 16.0D, 16.0D, 10.0D),
|
||||
new HexCollisionBox(1.0D, 0.0D, 7.0D, 15.0D, 10.0D, 9.0D));
|
||||
default:
|
||||
return new ComplexCollisionBox(new HexCollisionBox(6.0D, 14.0D, 0.0D, 10.0D, 16.0D, 16.0D),
|
||||
new HexCollisionBox(7.0D, 0.0D, 1.0D, 9.0D, 10.0D, 15.0D));
|
||||
}
|
||||
}, BlockTags.WALL_HANGING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
STANDING_SIGN((player, item, version, data, x, y, z) ->
|
||||
new HexCollisionBox(4.0, 0.0, 4.0, 12.0, 16.0, 12.0),
|
||||
BlockTags.STANDING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
SAPLING(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D),
|
||||
BlockTags.SAPLINGS.getStates().toArray(new StateType[0])),
|
||||
|
||||
ROOTS(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 13.0D, 14.0D),
|
||||
StateTypes.WARPED_ROOTS, StateTypes.CRIMSON_ROOTS),
|
||||
|
||||
BANNER(new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, 16.0D, 12.0D),
|
||||
StateTypes.WHITE_BANNER, StateTypes.ORANGE_BANNER, StateTypes.MAGENTA_BANNER, StateTypes.LIGHT_BLUE_BANNER,
|
||||
StateTypes.YELLOW_BANNER, StateTypes.LIME_BANNER, StateTypes.PINK_BANNER, StateTypes.GRAY_BANNER,
|
||||
StateTypes.LIGHT_GRAY_BANNER, StateTypes.CYAN_BANNER, StateTypes.PURPLE_BANNER, StateTypes.BLUE_BANNER,
|
||||
StateTypes.BROWN_BANNER, StateTypes.GREEN_BANNER, StateTypes.RED_BANNER, StateTypes.BLACK_BANNER),
|
||||
|
||||
WALL_BANNER((player, item, version, data, x, y, z) -> {
|
||||
// ViaVersion replacement block
|
||||
if (version.isOlderThan(ClientVersion.V_1_8)) {
|
||||
return WALL_SIGN.dynamic.fetch(player, item, version, data, x, y, z);
|
||||
}
|
||||
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
return new HexCollisionBox(0.0, 0.0, 14.0, 16.0, 12.5, 16.0);
|
||||
case EAST:
|
||||
return new HexCollisionBox(0.0, 0.0, 0.0, 2.0, 12.5, 16.0);
|
||||
case WEST:
|
||||
return new HexCollisionBox(14.0, 0.0, 0.0, 16.0, 12.5, 16.0);
|
||||
case SOUTH:
|
||||
return new HexCollisionBox(0.0, 0.0, 0.0, 16.0, 12.5, 2.0);
|
||||
default:
|
||||
throw new IllegalStateException("Impossible Banner Facing State; Something very wrong is going on");
|
||||
}
|
||||
}, StateTypes.WHITE_WALL_BANNER, StateTypes.ORANGE_WALL_BANNER, StateTypes.MAGENTA_WALL_BANNER,
|
||||
StateTypes.LIGHT_BLUE_WALL_BANNER, StateTypes.YELLOW_WALL_BANNER, StateTypes.LIME_WALL_BANNER,
|
||||
StateTypes.PINK_WALL_BANNER, StateTypes.GRAY_WALL_BANNER, StateTypes.LIGHT_GRAY_WALL_BANNER,
|
||||
StateTypes.CYAN_WALL_BANNER, StateTypes.PURPLE_WALL_BANNER, StateTypes.BLUE_WALL_BANNER,
|
||||
StateTypes.BROWN_WALL_BANNER, StateTypes.GREEN_WALL_BANNER, StateTypes.RED_WALL_BANNER, StateTypes.BLACK_WALL_BANNER),
|
||||
|
||||
BREWING_STAND((player, item, version, block, x, y, z) -> {
|
||||
// BEWARE OF https://bugs.mojang.com/browse/MC-85109 FOR 1.8 PLAYERS
|
||||
if (version.isOlderThan(ClientVersion.V_1_13)) {
|
||||
return new SimpleCollisionBox(0.0F, 0.0F, 0.0F, 1.0F, 0.125F, 1.0F);
|
||||
} else {
|
||||
return new ComplexCollisionBox(
|
||||
new HexCollisionBox(1.0, 0.0, 1.0, 15.0, 2.0, 15.0),
|
||||
new SimpleCollisionBox(0.4375, 0.0, 0.4375, 0.5625, 0.875, 0.5625, false));
|
||||
}
|
||||
}, StateTypes.BREWING_STAND),
|
||||
|
||||
SMALL_FLOWER((player, item, version, data, x, y, z) -> player.getClientVersion().isOlderThan(ClientVersion.V_1_13)
|
||||
? new SimpleCollisionBox(0.3125D, 0.0D, 0.3125D, 0.6875D, 0.625D, 0.6875D)
|
||||
: new OffsetCollisionBox(data.getType(), 0.3125D, 0.0D, 0.3125D, 0.6875D, 0.625D, 0.6875D),
|
||||
BlockTags.SMALL_FLOWERS.getStates().toArray(new StateType[0])),
|
||||
|
||||
TALL_FLOWERS(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), BlockTags.TALL_FLOWERS.getStates().toArray(new StateType[0])),
|
||||
|
||||
FIRE((player, item, version, data, x, y, z) -> {
|
||||
// Since 1.16 fire has a small hitbox
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_16)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D);
|
||||
}
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}, BlockTags.FIRE.getStates().toArray(new StateType[0])),
|
||||
|
||||
HONEY_BLOCK(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.HONEY_BLOCK),
|
||||
|
||||
POWDER_SNOW(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.POWDER_SNOW),
|
||||
|
||||
SOUL_SAND(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.SOUL_SAND),
|
||||
|
||||
CACTUS((player, item, version, data, x, y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_13)) {
|
||||
// https://bugs.mojang.com/browse/MC-59610
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D);
|
||||
}, StateTypes.CACTUS),
|
||||
|
||||
SNOW((player, item, version, data, x, y, z) -> {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, data.getLayers() * 0.125, 1);
|
||||
}, StateTypes.SNOW),
|
||||
|
||||
LECTERN_BLOCK((player, item, version, data, x, y, z) -> {
|
||||
ComplexCollisionBox common = new ComplexCollisionBox(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D),
|
||||
new HexCollisionBox(4.0D, 2.0D, 4.0D, 12.0D, 14.0D, 12.0D));
|
||||
|
||||
if (data.getFacing() == BlockFace.WEST) {
|
||||
common.add(new HexCollisionBox(1.0D, 10.0D, 0.0D, 5.333333D, 14.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(5.333333D, 12.0D, 0.0D, 9.666667D, 16.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(9.666667D, 14.0D, 0.0D, 14.0D, 18.0D, 16.0D));
|
||||
} else if (data.getFacing() == BlockFace.NORTH) {
|
||||
common.add(new HexCollisionBox(0.0D, 10.0D, 1.0D, 16.0D, 14.0D, 5.333333D));
|
||||
common.add(new HexCollisionBox(0.0D, 12.0D, 5.333333D, 16.0D, 16.0D, 9.666667D));
|
||||
common.add(new HexCollisionBox(0.0D, 14.0D, 9.666667D, 16.0D, 18.0D, 14.0D));
|
||||
} else if (data.getFacing() == BlockFace.EAST) {
|
||||
common.add(new HexCollisionBox(10.666667D, 10.0D, 0.0D, 15.0D, 14.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(6.333333D, 12.0D, 0.0D, 10.666667D, 16.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(2.0D, 14.0D, 0.0D, 6.333333D, 18.0D, 16.0D));
|
||||
} else { // SOUTH
|
||||
common.add(new HexCollisionBox(0.0D, 10.0D, 10.666667D, 16.0D, 14.0D, 15.0D));
|
||||
common.add(new HexCollisionBox(0.0D, 12.0D, 6.333333D, 16.0D, 16.0D, 10.666667D));
|
||||
common.add(new HexCollisionBox(0.0D, 14.0D, 2.0D, 16.0D, 18.0D, 6.333333D));
|
||||
}
|
||||
|
||||
return common;
|
||||
}, StateTypes.LECTERN),
|
||||
|
||||
GLOW_LICHEN_SCULK_VEIN((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_16_4)) {
|
||||
ComplexCollisionBox box = new ComplexCollisionBox();
|
||||
|
||||
if (data.isUp()) {
|
||||
box.add(new HexCollisionBox(0.0D, 15.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.isDown()) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D));
|
||||
}
|
||||
if (data.getWest() == West.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getEast() == East.TRUE) {
|
||||
box.add(new HexCollisionBox(15.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
if (data.getNorth() == North.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 1.0D));
|
||||
}
|
||||
if (data.getSouth() == South.TRUE) {
|
||||
box.add(new HexCollisionBox(0.0D, 0.0D, 15.0D, 16.0D, 16.0D, 16.0D));
|
||||
}
|
||||
|
||||
return box;
|
||||
} else { // ViaVersion just replaces this with... nothing
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, StateTypes.GLOW_LICHEN, StateTypes.SCULK_CATALYST),
|
||||
|
||||
SPORE_BLOSSOM((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_16_4)) {
|
||||
return new HexCollisionBox(2.0D, 13.0D, 2.0D, 14.0D, 16.0D, 14.0D);
|
||||
} else { // ViaVersion replacement is a Peony
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.SPORE_BLOSSOM),
|
||||
|
||||
PITCHER_CROP((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_19_4)) {
|
||||
final SimpleCollisionBox FULL_UPPER_SHAPE = new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 15.0D, 13.0D);
|
||||
final SimpleCollisionBox FULL_LOWER_SHAPE = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 16.0D, 13.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
final SimpleCollisionBox[] UPPER_SHAPE_BY_AGE = new SimpleCollisionBox[]{new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 11.0D, 13.0D), FULL_UPPER_SHAPE};
|
||||
final SimpleCollisionBox[] LOWER_SHAPE_BY_AGE = new SimpleCollisionBox[]{COLLISION_SHAPE_BULB, new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 14.0D, 13.0D), FULL_LOWER_SHAPE, FULL_LOWER_SHAPE, FULL_LOWER_SHAPE};
|
||||
|
||||
return data.getHalf() == Half.UPPER ? UPPER_SHAPE_BY_AGE[Math.min(Math.abs(4 - (data.getAge() + 1)), UPPER_SHAPE_BY_AGE.length - 1)] : LOWER_SHAPE_BY_AGE[data.getAge()];
|
||||
} else {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
}, StateTypes.PITCHER_CROP),
|
||||
|
||||
WHEAT_BEETROOTS((player, item, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, (data.getAge() + 1) * 2, 16.0D);
|
||||
}, StateTypes.WHEAT, StateTypes.BEETROOTS),
|
||||
|
||||
CARROT_POTATOES((player, item, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, data.getAge() + 2, 16.0D);
|
||||
}, StateTypes.CARROTS, StateTypes.POTATOES),
|
||||
|
||||
NETHER_WART((player, item, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0, 5 + (data.getAge() * 3), 16.0D);
|
||||
}, StateTypes.NETHER_WART),
|
||||
|
||||
ATTACHED_PUMPKIN_STEM((player, item, version, data, x, y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_13))
|
||||
return new HexCollisionBox(7.0D, 0.0D, 7.0D, 9.0D, 16.0D, 9.0D);
|
||||
|
||||
switch (data.getFacing()) {
|
||||
case SOUTH:
|
||||
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 10.0D, 10.0D, 16.0D);
|
||||
case WEST:
|
||||
return new HexCollisionBox(0.0D, 0.0D, 6.0D, 10.0D, 10.0D, 10.0D);
|
||||
case NORTH:
|
||||
return new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 10.0D, 10.0D);
|
||||
case EAST:
|
||||
default:
|
||||
return new HexCollisionBox(6.0D, 0.0D, 6.0D, 16.0D, 10.0D, 10.0D);
|
||||
}
|
||||
}, StateTypes.ATTACHED_MELON_STEM, StateTypes.ATTACHED_PUMPKIN_STEM),
|
||||
|
||||
PUMPKIN_STEM((player, item, version, data, x, y, z) -> {
|
||||
return new HexCollisionBox(7, 0, 7, 9, 2 * (data.getAge() + 1), 9);
|
||||
}, StateTypes.PUMPKIN_STEM, StateTypes.MELON_STEM),
|
||||
|
||||
// Hitbox/Outline is Same as Collision
|
||||
COCOA_BEANS((player, item, version, data, x, y, z) -> {
|
||||
return CollisionData.getCocoa(version, data.getAge(), data.getFacing());
|
||||
}, StateTypes.COCOA),
|
||||
|
||||
|
||||
// Easier to just use no collision box
|
||||
// Redstone wire is very complex with its collision shapes and has many de-syncs
|
||||
REDSTONE_WIRE(NoCollisionBox.INSTANCE, StateTypes.REDSTONE_WIRE),
|
||||
|
||||
SWEET_BERRY((player, item, version, data, x, y, z) -> {
|
||||
if (data.getAge() == 0) {
|
||||
return new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 8.0D, 13.0D);
|
||||
} else if (data.getAge() < 3) {
|
||||
return new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D);
|
||||
}
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}, StateTypes.SWEET_BERRY_BUSH),
|
||||
|
||||
CORAL_FAN(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 4.0D, 14.0D), BlockTags.CORALS.getStates().toArray(new StateType[0])),
|
||||
|
||||
TORCHFLOWER_CROP((player, item, version, data, x, y, z) -> {
|
||||
if (data.getAge() == 0) {
|
||||
return new HexCollisionBox(5.0D, 0.0D, 5.0D, 11.0D, 6.0D, 11.0D);
|
||||
}
|
||||
// age is 1
|
||||
return new HexCollisionBox(5.0D, 0.0D, 5.0D, 11.0D, 10.0D, 11.0D);
|
||||
}, StateTypes.TORCHFLOWER_CROP),
|
||||
|
||||
DEAD_BUSH(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 13.0D, 14.0D), StateTypes.DEAD_BUSH),
|
||||
|
||||
SUGARCANE(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 16.0D, 14.0D), StateTypes.SUGAR_CANE),
|
||||
|
||||
NETHER_SPROUTS(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 3.0D, 14.0D), StateTypes.NETHER_SPROUTS),
|
||||
|
||||
HANGING_ROOTS(new HexCollisionBox(2.0D, 10.0D, 2.0D, 14.0D, 16.0D, 14.0D), StateTypes.HANGING_ROOTS),
|
||||
|
||||
GRASS_FERN((player, item, version, data, x ,y, z) -> {
|
||||
if (version.isOlderThan(ClientVersion.V_1_13)) {
|
||||
return new SimpleCollisionBox(0.1F, 0.0F, 0.1F, 0.9F, 0.8F, 0.9F);
|
||||
}
|
||||
return new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 13.0D, 14.0D);
|
||||
}, StateTypes.SHORT_GRASS, StateTypes.FERN),
|
||||
|
||||
SEA_GRASS(new HexCollisionBox(2.0D, 0.0D, 2.0D, 14.0D, 12.0D, 14.0D),
|
||||
StateTypes.SEAGRASS),
|
||||
|
||||
TALL_SEAGRASS(new HexCollisionBox(2.0, 0.0, 2.0, 14.0, 16.0, 14.0),
|
||||
StateTypes.TALL_SEAGRASS),
|
||||
|
||||
SMALL_DRIPLEAF(new HexCollisionBox(2.0, 0.0, 2.0, 14.0, 13.0, 14.0), StateTypes.SMALL_DRIPLEAF),
|
||||
|
||||
CAVE_VINES(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D), StateTypes.CAVE_VINES, StateTypes.CAVE_VINES_PLANT),
|
||||
|
||||
// Then your enum entries become:
|
||||
TWISTING_VINES_BLOCK((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, false, true), StateTypes.TWISTING_VINES),
|
||||
|
||||
WEEPING_VINES_BLOCK((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, true, true), StateTypes.WEEPING_VINES),
|
||||
|
||||
TWISTING_VINES((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, false, false), StateTypes.TWISTING_VINES_PLANT),
|
||||
|
||||
WEEPING_VINES((player, item, version, data, x, y, z) ->
|
||||
getVineCollisionBox(version, true, false), StateTypes.WEEPING_VINES_PLANT),
|
||||
|
||||
TALL_PLANT(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.TALL_GRASS, StateTypes.LARGE_FERN),
|
||||
|
||||
BAMBOO((player, item, version, data, x, y, z) -> data.getLeaves() == Leaves.LARGE
|
||||
? new HexOffsetCollisionBox(data.getType(), 3.0, 0.0, 3.0, 13.0, 16.0, 13.0)
|
||||
: new HexOffsetCollisionBox(data.getType(), 5.0, 0.0, 5.0, 11.0, 16.0, 11.0), StateTypes.BAMBOO),
|
||||
|
||||
BAMBOO_SAPLING((player, item, version, data, x, y, z) -> {
|
||||
return new HexOffsetCollisionBox(data.getType(), 4.0D, 0.0D, 4.0D, 12.0D, 12.0D, 12.0D);
|
||||
}, StateTypes.BAMBOO_SAPLING),
|
||||
|
||||
SCAFFOLDING((player, item, version, data, x, y, z) -> {
|
||||
// If is holding scaffolding or Via replacement - hay bale
|
||||
if (item == StateTypes.SCAFFOLDING || version.isOlderThan(ClientVersion.V_1_14)) {
|
||||
// If is holding scaffolding
|
||||
if (item == StateTypes.SCAFFOLDING) {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true);
|
||||
}
|
||||
|
||||
@@ -569,54 +67,222 @@ public enum HitboxData {
|
||||
|
||||
}, StateTypes.BIG_DRIPLEAF),
|
||||
|
||||
PINK_PETALS_BLOCK((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_20_2)) {
|
||||
int flowerAmount = data.getFlowerAmount();
|
||||
int horizontalIndex = getHorizontalID(data.getFacing());
|
||||
FENCE_GATE((player, item, version, data, x, y, z) -> {
|
||||
// This technically should be taken from the block data/made multi-version/run block updates... but that's too far even for me
|
||||
// This way is so much easier and works unless the magic stick wand is used
|
||||
boolean isInWall;
|
||||
boolean isXAxis = data.getFacing() == BlockFace.WEST || data.getFacing() == BlockFace.EAST;
|
||||
if (isXAxis) {
|
||||
boolean zPosWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x, y, z + 1));
|
||||
boolean zNegWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x, y, z - 1));
|
||||
isInWall = zPosWall || zNegWall;
|
||||
} else {
|
||||
boolean xPosWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x + 1, y, z));
|
||||
boolean xNegWall = Materials.isWall(player.compensatedWorld.getStateTypeAt(x - 1, y, z));
|
||||
isInWall = xPosWall || xNegWall;
|
||||
}
|
||||
|
||||
CollisionBox result = NoCollisionBox.INSTANCE;
|
||||
if (isInWall) {
|
||||
return isXAxis ? new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 13.0D, 16.0D) : new HexCollisionBox(0.0D, 0.0D, 6.0D, 16.0D, 13.0D, 10.0D);
|
||||
}
|
||||
|
||||
// Pre-defined collision boxes for each quadrant
|
||||
HexCollisionBox[] boxes = new HexCollisionBox[] {
|
||||
new HexCollisionBox(8, 0, 8, 16, 3, 16), // SE
|
||||
new HexCollisionBox(8, 0, 0, 16, 3, 8), // NE
|
||||
new HexCollisionBox(0, 0, 0, 8, 3, 8), // NW
|
||||
new HexCollisionBox(0, 0, 8, 8, 3, 16) // SW
|
||||
};
|
||||
return isXAxis ? new HexCollisionBox(6.0D, 0.0D, 0.0D, 10.0D, 16.0D, 16.0D) : new HexCollisionBox(0.0D, 0.0D, 6.0D, 16.0D, 16.0D, 10.0D);
|
||||
}, BlockTags.FENCE_GATES.getStates().toArray(new StateType[0])),
|
||||
|
||||
// Add boxes based on flower amount and facing
|
||||
for (int i = 0; i < flowerAmount; i++) {
|
||||
int index = Math.floorMod(i - horizontalIndex, 4);
|
||||
result = result.union(boxes[index]);
|
||||
|
||||
FENCE((player, item, version, data, x, y, z) -> {
|
||||
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(x, y, z);
|
||||
|
||||
if (version.isOlderThanOrEquals(ClientVersion.V_1_12_2)) {
|
||||
int i = 0;
|
||||
if (data.getSouth() == South.TRUE) {
|
||||
i |= 0b1;
|
||||
}
|
||||
if (data.getWest() == West.TRUE) {
|
||||
i |= 0b10;
|
||||
}
|
||||
if (data.getNorth() == North.TRUE) {
|
||||
i |= 0b100;
|
||||
}
|
||||
if (data.getEast() == East.TRUE) {
|
||||
i |= 0b1000;
|
||||
}
|
||||
|
||||
return result;
|
||||
} else if (version.isNewerThan(ClientVersion.V_1_19_3)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 3.0D, 16.0D);
|
||||
} else if (version.isNewerThan(ClientVersion.V_1_12_2)) {
|
||||
return CORAL_FAN.dynamic.fetch(player, item, version, data, x, y, z);
|
||||
return DynamicFence.LEGACY_BOUNDING_BOXES[i].copy();
|
||||
}
|
||||
return GRASS_FERN.dynamic.fetch(player, item, version, data, x, y, z);
|
||||
}, StateTypes.PINK_PETALS),
|
||||
|
||||
MANGROVE_PROPAGULE(((player, item, version, data, x, y, z) -> {
|
||||
if (data.isHanging()) {
|
||||
return new HexOffsetCollisionBox(data.getType(), 7.0, 0.0, 7.0, 9.0, 16.0, 9.0);
|
||||
} else {
|
||||
return new HexOffsetCollisionBox(data.getType(), 7.0, getPropaguleMinHeight(data.getAge()), 7.0, 9.0, 16.0, 9.0);
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
CollisionData.getData(state.getType()).getMovementCollisionBox(player, version, state).downCast(boxes);
|
||||
|
||||
for (SimpleCollisionBox box : boxes) {
|
||||
box.maxY = 1;
|
||||
}
|
||||
}), StateTypes.MANGROVE_PROPAGULE),
|
||||
|
||||
FROGSPAWN((player, item, version, data, x, y, z) -> {
|
||||
if (version.isNewerThan(ClientVersion.V_1_18_2)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.5D, 16.0D);
|
||||
} else { // ViaVersion just replaces this with... nothing
|
||||
return NoCollisionBox.INSTANCE;
|
||||
return new ComplexCollisionBox(boxes.toArray(new SimpleCollisionBox[0]));
|
||||
}, BlockTags.FENCES.getStates().toArray(new StateType[0])),
|
||||
|
||||
WALL((player, item, version, data, x, y, z) -> {
|
||||
WrappedBlockState state = player.compensatedWorld.getWrappedBlockStateAt(x, y, z);
|
||||
return new DynamicWall().fetchRegularBox(player, state, version, x, y, z);
|
||||
}, BlockTags.WALLS.getStates().toArray(new StateType[0])),
|
||||
|
||||
HONEY_BLOCK(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.HONEY_BLOCK),
|
||||
|
||||
POWDER_SNOW(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.POWDER_SNOW),
|
||||
|
||||
SOUL_SAND(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.SOUL_SAND),
|
||||
|
||||
CACTUS(new HexCollisionBox(1.0D, 0.0D, 1.0D, 15.0D, 16.0D, 15.0D), StateTypes.CACTUS),
|
||||
|
||||
SNOW((player, item, version, data, x, y, z) -> {
|
||||
return new SimpleCollisionBox(0, 0, 0, 1, data.getLayers() * 0.125, 1);
|
||||
}, StateTypes.SNOW),
|
||||
|
||||
LECTERN_BLOCK((player, item, version, data, x, y, z) -> {
|
||||
ComplexCollisionBox common = new ComplexCollisionBox(new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 2.0D, 16.0D),
|
||||
new HexCollisionBox(4.0D, 2.0D, 4.0D, 12.0D, 14.0D, 12.0D));
|
||||
|
||||
if (data.getFacing() == BlockFace.WEST) {
|
||||
common.add(new HexCollisionBox(1.0D, 10.0D, 0.0D, 5.333333D, 14.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(5.333333D, 12.0D, 0.0D, 9.666667D, 16.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(9.666667D, 14.0D, 0.0D, 14.0D, 18.0D, 16.0D));
|
||||
} else if (data.getFacing() == BlockFace.NORTH) {
|
||||
common.add(new HexCollisionBox(0.0D, 10.0D, 1.0D, 16.0D, 14.0D, 5.333333D));
|
||||
common.add(new HexCollisionBox(0.0D, 12.0D, 5.333333D, 16.0D, 16.0D, 9.666667D));
|
||||
common.add(new HexCollisionBox(0.0D, 14.0D, 9.666667D, 16.0D, 18.0D, 14.0D));
|
||||
} else if (data.getFacing() == BlockFace.EAST) {
|
||||
common.add(new HexCollisionBox(10.666667D, 10.0D, 0.0D, 15.0D, 14.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(6.333333D, 12.0D, 0.0D, 10.666667D, 16.0D, 16.0D));
|
||||
common.add(new HexCollisionBox(2.0D, 14.0D, 0.0D, 6.333333D, 18.0D, 16.0D));
|
||||
} else { // SOUTH
|
||||
common.add(new HexCollisionBox(0.0D, 10.0D, 10.666667D, 16.0D, 14.0D, 15.0D));
|
||||
common.add(new HexCollisionBox(0.0D, 12.0D, 6.333333D, 16.0D, 16.0D, 10.666667D));
|
||||
common.add(new HexCollisionBox(0.0D, 14.0D, 2.0D, 16.0D, 18.0D, 6.333333D));
|
||||
}
|
||||
}, StateTypes.FROGSPAWN),
|
||||
|
||||
// always a fullblock hitbox. Via replacement is obsidian
|
||||
SCULK_SHRIKER(new SimpleCollisionBox(0, 0, 0, 1, 1, 1, true), StateTypes.SCULK_SHRIEKER);
|
||||
return common;
|
||||
}, StateTypes.LECTERN),
|
||||
|
||||
WALL_HANGING_SIGNS((player, item, version, data, x, y, z) -> {
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
return new ComplexCollisionBox(new HexCollisionBox(0.0D, 14.0D, 6.0D, 16.0D, 16.0D, 10.0D),
|
||||
new HexCollisionBox(1.0D, 0.0D, 7.0D, 15.0D, 10.0D, 9.0D));
|
||||
case WEST:
|
||||
case EAST:
|
||||
return new ComplexCollisionBox(new HexCollisionBox(6.0D, 14.0D, 0.0D, 10.0D, 16.0D, 16.0D),
|
||||
new HexCollisionBox(7.0D, 0.0D, 1.0D, 9.0D, 10.0D, 15.0D));
|
||||
default:
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, BlockTags.WALL_HANGING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
PITCHER_CROP((player, item, version, data, x, y, z) -> {
|
||||
final SimpleCollisionBox FULL_UPPER_SHAPE = new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 15.0D, 13.0D);
|
||||
final SimpleCollisionBox FULL_LOWER_SHAPE = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 16.0D, 13.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_BULB = new HexCollisionBox(5.0D, -1.0D, 5.0D, 11.0D, 3.0D, 11.0D);
|
||||
final SimpleCollisionBox COLLISION_SHAPE_CROP = new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 5.0D, 13.0D);
|
||||
final SimpleCollisionBox[] UPPER_SHAPE_BY_AGE = new SimpleCollisionBox[]{new HexCollisionBox(3.0D, 0.0D, 3.0D, 13.0D, 11.0D, 13.0D), FULL_UPPER_SHAPE};
|
||||
final SimpleCollisionBox[] LOWER_SHAPE_BY_AGE = new SimpleCollisionBox[]{COLLISION_SHAPE_BULB, new HexCollisionBox(3.0D, -1.0D, 3.0D, 13.0D, 14.0D, 13.0D), FULL_LOWER_SHAPE, FULL_LOWER_SHAPE, FULL_LOWER_SHAPE};
|
||||
|
||||
return data.getHalf() == Half.UPPER ? UPPER_SHAPE_BY_AGE[Math.min(Math.abs(4 - (data.getAge() + 1)), UPPER_SHAPE_BY_AGE.length - 1)] : LOWER_SHAPE_BY_AGE[data.getAge()];
|
||||
}, StateTypes.PITCHER_CROP),
|
||||
|
||||
BUTTON((player, item, version, data, x, y, z) -> {
|
||||
final BlockFace facing = data.getFacing();
|
||||
final boolean powered = data.isPowered();
|
||||
switch (data.getFace()) {
|
||||
case FLOOR:
|
||||
// x axis
|
||||
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
|
||||
return powered ? new HexCollisionBox(6.0, 0.0, 5.0, 10.0, 1.0, 11.0) : new HexCollisionBox(6.0, 0.0, 5.0, 10.0, 2.0, 11.0);
|
||||
}
|
||||
|
||||
return powered ? new HexCollisionBox(5.0, 0.0, 6.0, 11.0, 1.0, 10.0) : new HexCollisionBox(5.0, 0.0, 6.0, 11.0, 2.0, 10.0);
|
||||
case WALL:
|
||||
CollisionBox shape;
|
||||
switch (facing) {
|
||||
case EAST:
|
||||
shape = powered ? new HexCollisionBox(0.0, 6.0, 5.0, 1.0, 10.0, 11.0) : new HexCollisionBox(0.0, 6.0, 5.0, 2.0, 10.0, 11.0);
|
||||
break;
|
||||
case WEST:
|
||||
shape = powered ? new HexCollisionBox(15.0, 6.0, 5.0, 16.0, 10.0, 11.0) : new HexCollisionBox(14.0, 6.0, 5.0, 16.0, 10.0, 11.0);
|
||||
break;
|
||||
case SOUTH:
|
||||
shape = powered ? new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 1.0) : new HexCollisionBox(5.0, 6.0, 0.0, 11.0, 10.0, 2.0);
|
||||
break;
|
||||
case NORTH:
|
||||
case UP:
|
||||
case DOWN:
|
||||
shape = powered ? new HexCollisionBox(5.0, 6.0, 15.0, 11.0, 10.0, 16.0) : new HexCollisionBox(5.0, 6.0, 14.0, 11.0, 10.0, 16.0);
|
||||
break;
|
||||
default:
|
||||
shape = NoCollisionBox.INSTANCE;
|
||||
}
|
||||
|
||||
return shape;
|
||||
case CEILING:
|
||||
default:
|
||||
// x axis
|
||||
if (facing == BlockFace.EAST || facing == BlockFace.WEST) {
|
||||
return powered ? new HexCollisionBox(6.0, 15.0, 5.0, 10.0, 16.0, 11.0) : new HexCollisionBox(6.0, 14.0, 5.0, 10.0, 16.0, 11.0);
|
||||
} else {
|
||||
return powered ? new HexCollisionBox(5.0, 15.0, 6.0, 11.0, 16.0, 10.0) : new HexCollisionBox(5.0, 14.0, 6.0, 11.0, 16.0, 10.0);
|
||||
}
|
||||
}
|
||||
}, BlockTags.BUTTONS.getStates().toArray(new StateType[0])),
|
||||
|
||||
WALL_SIGN((player, item, version, data, x, y, z) -> {
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
return new HexCollisionBox(0.0, 4.5, 14.0, 16.0, 12.5, 16.0);
|
||||
case SOUTH:
|
||||
return new HexCollisionBox(0.0, 4.5, 0.0, 16.0, 12.5, 2.0);
|
||||
case EAST:
|
||||
return new HexCollisionBox(0.0, 4.5, 0.0, 2.0, 12.5, 16.0);
|
||||
case WEST:
|
||||
return new HexCollisionBox(14.0, 4.5, 0.0, 16.0, 12.5, 16.0);
|
||||
default:
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}
|
||||
}, BlockTags.WALL_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
WALL_HANGING_SIGN((player, item, version, data, x, y, z) -> {
|
||||
switch (data.getFacing()) {
|
||||
case NORTH:
|
||||
case SOUTH:
|
||||
return new ComplexCollisionBox(new HexCollisionBox(0.0D, 14.0D, 6.0D, 16.0D, 16.0D, 10.0D),
|
||||
new HexCollisionBox(1.0D, 0.0D, 7.0D, 15.0D, 10.0D, 9.0D));
|
||||
default:
|
||||
return new ComplexCollisionBox(new HexCollisionBox(6.0D, 14.0D, 0.0D, 10.0D, 16.0D, 16.0D),
|
||||
new HexCollisionBox(7.0D, 0.0D, 1.0D, 9.0D, 10.0D, 15.0D));
|
||||
}
|
||||
}, BlockTags.WALL_HANGING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
STANDING_SIGN((player, item, version, data, x, y, z) ->
|
||||
new HexCollisionBox(4.0, 0.0, 4.0, 12.0, 16.0, 12.0),
|
||||
BlockTags.STANDING_SIGNS.getStates().toArray(new StateType[0])),
|
||||
|
||||
REDSTONE_WIRE((player, item, version, data, x, y, z) ->
|
||||
// Easier to just use no collision box
|
||||
// Redstone wire is very complex with its collision shapes and has many de-syncs
|
||||
NoCollisionBox.INSTANCE,
|
||||
StateTypes.REDSTONE_WIRE),
|
||||
|
||||
FIRE((player, item, version, data, x, y, z) -> {
|
||||
// Since 1.16 fire has a small hitbox
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_16)) {
|
||||
return new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 1.0D, 16.0D);
|
||||
}
|
||||
|
||||
return NoCollisionBox.INSTANCE;
|
||||
}, BlockTags.FIRE.getStates().toArray(new StateType[0])),
|
||||
|
||||
BANNER(((player, item, version, data, x, y, z) ->
|
||||
new SimpleCollisionBox(4.0, 0.0, 4.0, 12.0, 16.0, 12.0)),
|
||||
BlockTags.BANNERS.getStates().toArray(new StateType[0]));
|
||||
|
||||
|
||||
private static final Map<StateType, HitboxData> lookup = new HashMap<>();
|
||||
|
||||
@@ -663,59 +329,6 @@ public enum HitboxData {
|
||||
return data.box.copy().offset(x, y, z);
|
||||
|
||||
// Allow this class to override collision boxes when they aren't the same as regular boxes
|
||||
HitBoxFactory hitBoxFactory = data.dynamic;
|
||||
CollisionBox collisionBox = hitBoxFactory.fetch(player, heldItem, version, block, x, y, z);
|
||||
collisionBox.offset(x, y, z);
|
||||
return collisionBox;
|
||||
}
|
||||
|
||||
private static int getPropaguleMinHeight(int age) {
|
||||
switch (age) {
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
return 13 - age * 3;
|
||||
case 3:
|
||||
case 4:
|
||||
return (4 - age) * 3;
|
||||
}
|
||||
throw new IllegalStateException("Impossible Propagule Height");
|
||||
}
|
||||
|
||||
private static CollisionBox getVineCollisionBox(ClientVersion version, boolean isWeeping, boolean isBlock) {
|
||||
if (version.isNewerThan(ClientVersion.V_1_15_2)) {
|
||||
if (isWeeping) {
|
||||
return isBlock
|
||||
? new HexCollisionBox(4.0, 9.0, 4.0, 12.0, 16.0, 12.0)
|
||||
: new HexCollisionBox(1.0, 0.0, 1.0, 15.0, 16.0, 15.0);
|
||||
} else {
|
||||
return new HexCollisionBox(4.0D, 0.0D, 4.0D, 12.0D, isBlock ? 15.0D : 16.0D, 12.0D);
|
||||
}
|
||||
} else {
|
||||
// Via replacement - 4 sided vine
|
||||
return new ComplexCollisionBox(
|
||||
new HexCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 16.0D, 16.0D),
|
||||
new HexCollisionBox(15.0D, 0.0D, 0.0D, 16.0D, 16.0D, 16.0D),
|
||||
new HexCollisionBox(0.0D, 0.0D, 0.0D, 16.0D, 16.0D, 1.0D),
|
||||
new HexCollisionBox(0.0D, 0.0D, 15.0D, 16.0D, 16.0D, 16.0D)
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
private static int getHorizontalID(BlockFace facing) {
|
||||
switch (facing) {
|
||||
case DOWN:
|
||||
case UP:
|
||||
return -1;
|
||||
case NORTH:
|
||||
return 2;
|
||||
case SOUTH:
|
||||
return 0;
|
||||
case WEST:
|
||||
return 1;
|
||||
case EAST:
|
||||
return 3;
|
||||
}
|
||||
throw new IllegalStateException("Impossible blockface for getHorizontalID");
|
||||
return HitboxData.getData(block.getType()).dynamic.fetch(player, heldItem, version, block, x, y, z).offset(x, y, z);
|
||||
}
|
||||
}
|
||||
+3
-1
@@ -18,9 +18,11 @@ import com.github.retrooper.packetevents.protocol.world.states.enums.West;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
|
||||
public class DynamicCollisionFence extends DynamicConnecting implements CollisionFactory {
|
||||
public class DynamicFence extends DynamicConnecting implements CollisionFactory {
|
||||
private static final CollisionBox[] COLLISION_BOXES = makeShapes(2.0F, 2.0F, 24.0F, 0.0F, 24.0F, true);
|
||||
|
||||
public static SimpleCollisionBox[] LEGACY_BOUNDING_BOXES = new SimpleCollisionBox[] {new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D)};
|
||||
|
||||
@Override
|
||||
public CollisionBox fetch(GrimPlayer player, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
|
||||
boolean east;
|
||||
-86
@@ -1,86 +0,0 @@
|
||||
package ac.grim.grimac.utils.collisions.blocks.connecting;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.CollisionData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.CollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.ComplexCollisionBox;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.HitBoxFactory;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.SimpleCollisionBox;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.enums.*;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
|
||||
public class DynamicHitboxFence extends DynamicConnecting implements HitBoxFactory {
|
||||
private static final CollisionBox[] MODERN_HITBOXES = makeShapes(2.0F, 2.0F, 24.0F, 0.0F, 24.0F, true);
|
||||
|
||||
public static SimpleCollisionBox[] LEGACY_HITBOXES = new SimpleCollisionBox[] {new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 0.625D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.375D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.375D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 0.625D), new SimpleCollisionBox(0.0D, 0.0D, 0.0D, 1.0D, 1.0D, 1.0D)};
|
||||
|
||||
static {
|
||||
for (int i = 0; i < MODERN_HITBOXES.length; i++) {
|
||||
CollisionBox collisionBox = MODERN_HITBOXES[i];
|
||||
List<SimpleCollisionBox> boxes = new ArrayList<>();
|
||||
collisionBox.downCast(boxes);
|
||||
|
||||
for (SimpleCollisionBox box : boxes) {
|
||||
if (box.maxY > 1) {
|
||||
box.maxY = 1;
|
||||
}
|
||||
}
|
||||
|
||||
MODERN_HITBOXES[i] = new ComplexCollisionBox(boxes.toArray(new SimpleCollisionBox[0]));
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollisionBox fetch(GrimPlayer player, StateType heldItem, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
|
||||
boolean east;
|
||||
boolean north;
|
||||
boolean south;
|
||||
boolean west;
|
||||
|
||||
// 1.13+ servers on 1.13+ clients send the full fence data
|
||||
if (PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)
|
||||
&& version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
|
||||
east = block.getEast() != East.FALSE;
|
||||
north = block.getNorth() != North.FALSE;
|
||||
south = block.getSouth() != South.FALSE;
|
||||
west = block.getWest() != West.FALSE;
|
||||
} else {
|
||||
east = connectsTo(player, version, x, y, z, BlockFace.EAST);
|
||||
north = connectsTo(player, version, x, y, z, BlockFace.NORTH);
|
||||
south = connectsTo(player, version, x, y, z, BlockFace.SOUTH);
|
||||
west = connectsTo(player, version, x, y, z, BlockFace.WEST);
|
||||
}
|
||||
|
||||
return version.isNewerThanOrEquals(ClientVersion.V_1_12_2)
|
||||
? getModernCollisionBox(north, east, south, west)
|
||||
: getLegacyCollisionBox(north, east, south, west);
|
||||
|
||||
|
||||
}
|
||||
|
||||
private CollisionBox getLegacyCollisionBox(boolean north, boolean east, boolean south, boolean west) {
|
||||
return LEGACY_HITBOXES[getAABBIndex(north, east, south, west)].copy();
|
||||
}
|
||||
|
||||
private CollisionBox getModernCollisionBox(boolean north, boolean east, boolean south, boolean west) {
|
||||
return MODERN_HITBOXES[getAABBIndex(north, east, south, west)].copy();
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkCanConnect(GrimPlayer player, WrappedBlockState state, StateType one, StateType two, BlockFace direction) {
|
||||
if (BlockTags.FENCES.contains(one))
|
||||
return !(one == StateTypes.NETHER_BRICK_FENCE) && !(two == StateTypes.NETHER_BRICK_FENCE);
|
||||
else
|
||||
return BlockTags.FENCES.contains(one) || CollisionData.getData(one).getMovementCollisionBox(player, player.getClientVersion(), state, 0, 0, 0).isSideFullBlock(direction);
|
||||
}
|
||||
}
|
||||
-109
@@ -1,109 +0,0 @@
|
||||
package ac.grim.grimac.utils.collisions.blocks.connecting;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.CollisionData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.*;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.enums.*;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
|
||||
public class DynamicHitboxPane extends DynamicConnecting implements HitBoxFactory {
|
||||
|
||||
private static final CollisionBox[] COLLISION_BOXES = makeShapes(1.0F, 1.0F, 16.0F, 0.0F, 16.0F, true);
|
||||
|
||||
@Override
|
||||
public CollisionBox fetch(GrimPlayer player, StateType item, ClientVersion version, WrappedBlockState block, int x, int y, int z) {
|
||||
boolean east, north, south, west;
|
||||
|
||||
// 1.13+ servers on 1.13+ clients send the full fence data
|
||||
if (isModernVersion(version)) {
|
||||
east = block.getEast() != East.FALSE;
|
||||
north = block.getNorth() != North.FALSE;
|
||||
south = block.getSouth() != South.FALSE;
|
||||
west = block.getWest() != West.FALSE;
|
||||
} else {
|
||||
east = connectsTo(player, version, x, y, z, BlockFace.EAST);
|
||||
north = connectsTo(player, version, x, y, z, BlockFace.NORTH);
|
||||
south = connectsTo(player, version, x, y, z, BlockFace.SOUTH);
|
||||
west = connectsTo(player, version, x, y, z, BlockFace.WEST);
|
||||
}
|
||||
|
||||
// On 1.7 and 1.8 clients, and 1.13+ clients on 1.7 and 1.8 servers, the glass pane is + instead of |
|
||||
if (shouldUseOldPaneShape(version, north, south, east, west)) {
|
||||
north = south = east = west = true;
|
||||
}
|
||||
|
||||
return version.isNewerThanOrEquals(ClientVersion.V_1_9)
|
||||
? getModernCollisionBox(north, east, south, west)
|
||||
: getLegacyCollisionBox(north, east, south, west);
|
||||
}
|
||||
|
||||
private boolean isModernVersion(ClientVersion version) {
|
||||
return PacketEvents.getAPI().getServerManager().getVersion().isNewerThanOrEquals(ServerVersion.V_1_13)
|
||||
&& version.isNewerThanOrEquals(ClientVersion.V_1_13);
|
||||
}
|
||||
|
||||
private boolean shouldUseOldPaneShape(ClientVersion version, boolean north, boolean south, boolean east, boolean west) {
|
||||
return (!north && !south && !east && !west) &&
|
||||
(version.isOlderThanOrEquals(ClientVersion.V_1_8) ||
|
||||
(PacketEvents.getAPI().getServerManager().getVersion().isOlderThanOrEquals(ServerVersion.V_1_8_8) &&
|
||||
version.isNewerThanOrEquals(ClientVersion.V_1_13)));
|
||||
}
|
||||
|
||||
private CollisionBox getModernCollisionBox(boolean north, boolean east, boolean south, boolean west) {
|
||||
return COLLISION_BOXES[getAABBIndex(north, east, south, west)].copy();
|
||||
}
|
||||
|
||||
private CollisionBox getLegacyCollisionBox(boolean north, boolean east, boolean south, boolean west) {
|
||||
float minX = 0.4375F;
|
||||
float maxX = 0.5625F;
|
||||
float minZ = 0.4375F;
|
||||
float maxZ = 0.5625F;
|
||||
|
||||
if ((!west || !east) && (west || east || north || south)) {
|
||||
if (west) {
|
||||
minX = 0.0F;
|
||||
} else if (east) {
|
||||
maxX = 1.0F;
|
||||
}
|
||||
} else {
|
||||
minX = 0.0F;
|
||||
maxX = 1.0F;
|
||||
}
|
||||
|
||||
if ((!north || !south) && (west || east || north || south)) {
|
||||
if (north) {
|
||||
minZ = 0.0F;
|
||||
} else if (south) {
|
||||
maxZ = 1.0F;
|
||||
}
|
||||
} else {
|
||||
minZ = 0.0F;
|
||||
maxZ = 1.0F;
|
||||
}
|
||||
|
||||
return new SimpleCollisionBox(minX, 0.0F, minZ, maxX, 1.0F, maxZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean canConnectToGlassBlock() {
|
||||
return true;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkCanConnect(GrimPlayer player, WrappedBlockState state, StateType one, StateType two, BlockFace direction) {
|
||||
if (BlockTags.GLASS_PANES.contains(one) || one == StateTypes.IRON_BARS) {
|
||||
return true;
|
||||
} else {
|
||||
return CollisionData.getData(one)
|
||||
.getMovementCollisionBox(player, player.getClientVersion(), state, 0, 0, 0)
|
||||
.isSideFullBlock(direction);
|
||||
}
|
||||
}
|
||||
}
|
||||
-111
@@ -1,111 +0,0 @@
|
||||
package ac.grim.grimac.utils.collisions.blocks.connecting;
|
||||
|
||||
import ac.grim.grimac.player.GrimPlayer;
|
||||
import ac.grim.grimac.utils.collisions.CollisionData;
|
||||
import ac.grim.grimac.utils.collisions.datatypes.*;
|
||||
import com.github.retrooper.packetevents.PacketEvents;
|
||||
import com.github.retrooper.packetevents.manager.server.ServerVersion;
|
||||
import com.github.retrooper.packetevents.protocol.player.ClientVersion;
|
||||
import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.WrappedBlockState;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.enums.*;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
|
||||
public class DynamicHitboxWall extends DynamicConnecting implements HitBoxFactory {
|
||||
private static final CollisionBox[] HIT_BOXES = makeShapes(4.0F, 3.0F, 16.0F, 0.0F, 16.0F, false);
|
||||
|
||||
@Override
|
||||
public CollisionBox fetch(GrimPlayer player, StateType heldItem, ClientVersion version, WrappedBlockState state, int x, int y, int z) {
|
||||
int[] connections = getConnections(player, version, state, x, y, z);
|
||||
int north = connections[0], south = connections[1], west = connections[2], east = connections[3], up = connections[4];
|
||||
|
||||
if (version.isNewerThanOrEquals(ClientVersion.V_1_13)) {
|
||||
return getModernHitBox(north, south, west, east, up);
|
||||
} else {
|
||||
return getLegacyHitBox(north, south, west, east);
|
||||
}
|
||||
}
|
||||
|
||||
private int[] getConnections(GrimPlayer player, ClientVersion version, WrappedBlockState state, int x, int y, int z) {
|
||||
int north = 0, south = 0, west = 0, east = 0, up = 0;
|
||||
|
||||
if (isModernServer()) {
|
||||
boolean sixteen = PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_16);
|
||||
north = getConnectionValue(state.getNorth(), sixteen);
|
||||
east = getConnectionValue(state.getEast(), sixteen);
|
||||
south = getConnectionValue(state.getSouth(), sixteen);
|
||||
west = getConnectionValue(state.getWest(), sixteen);
|
||||
up = state.isUp() ? 1 : 0;
|
||||
} else {
|
||||
north = connectsTo(player, version, x, y, z, BlockFace.NORTH) ? 1 : 0;
|
||||
south = connectsTo(player, version, x, y, z, BlockFace.SOUTH) ? 1 : 0;
|
||||
west = connectsTo(player, version, x, y, z, BlockFace.WEST) ? 1 : 0;
|
||||
east = connectsTo(player, version, x, y, z, BlockFace.EAST) ? 1 : 0;
|
||||
up = 1;
|
||||
}
|
||||
|
||||
return new int[]{north, south, west, east, up};
|
||||
}
|
||||
|
||||
private boolean isModernServer() {
|
||||
return PacketEvents.getAPI().getServerManager().getVersion().isNewerThan(ServerVersion.V_1_12_2);
|
||||
}
|
||||
|
||||
private int getConnectionValue(Enum<?> direction, boolean sixteen) {
|
||||
if (direction == North.NONE || direction == East.NONE || direction == South.NONE || direction == West.NONE) {
|
||||
return 0;
|
||||
}
|
||||
return (direction == North.LOW || direction == East.LOW || direction == South.LOW || direction == West.LOW || sixteen) ? 1 : 2;
|
||||
}
|
||||
|
||||
private CollisionBox getModernHitBox(int north, int south, int west, int east, int up) {
|
||||
ComplexCollisionBox box = new ComplexCollisionBox();
|
||||
if (up == 1) {
|
||||
box.add(new HexCollisionBox(4, 0, 4, 12, 16, 12));
|
||||
}
|
||||
|
||||
addDirectionalBox(box, north, 5, 0, 0.0D, 11, 14, 11);
|
||||
addDirectionalBox(box, south, 5, 0, 5, 11, 14, 16);
|
||||
addDirectionalBox(box, west, 0, 0, 5, 11, 14, 11);
|
||||
addDirectionalBox(box, east, 5, 0, 5, 16, 14, 11);
|
||||
|
||||
return box;
|
||||
}
|
||||
|
||||
private void addDirectionalBox(ComplexCollisionBox box, int direction, double x1, double y1, double z1, double x2, double y2, double z2) {
|
||||
if (direction == 1) {
|
||||
box.add(new HexCollisionBox(x1, y1, z1, x2, y2, z2));
|
||||
} else if (direction == 2) {
|
||||
box.add(new HexCollisionBox(x1, y1, z1, x2, 16, z2));
|
||||
}
|
||||
}
|
||||
|
||||
private CollisionBox getLegacyHitBox(int north, int south, int west, int east) {
|
||||
float minX = 0.25F, maxX = 0.75F, minZ = 0.25F, maxZ = 0.75F;
|
||||
float maxY = 1.0F;
|
||||
|
||||
if (north == 1) minZ = 0.0F;
|
||||
if (south == 1) maxZ = 1.0F;
|
||||
if (west == 1) minX = 0.0F;
|
||||
if (east == 1) maxX = 1.0F;
|
||||
|
||||
if (north == 1 && south == 1 && west == 0 && east == 0) {
|
||||
maxY = 0.8125F;
|
||||
minX = 0.3125F;
|
||||
maxX = 0.6875F;
|
||||
} else if (west == 1 && east == 1 && north == 0 && south == 0) {
|
||||
maxY = 0.8125F;
|
||||
minZ = 0.3125F;
|
||||
maxZ = 0.6875F;
|
||||
}
|
||||
|
||||
return new SimpleCollisionBox(minX, 0.0F, minZ, maxX, maxY, maxZ);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean checkCanConnect(GrimPlayer player, WrappedBlockState state, StateType one, StateType two, BlockFace direction) {
|
||||
return BlockTags.WALLS.contains(one) ||
|
||||
CollisionData.getData(one).getMovementCollisionBox(player, player.getClientVersion(), state, 0, 0, 0).isSideFullBlock(direction);
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -19,7 +19,7 @@ import com.github.retrooper.packetevents.protocol.world.states.enums.West;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
|
||||
public class DynamicCollisionPane extends DynamicConnecting implements CollisionFactory {
|
||||
public class DynamicPane extends DynamicConnecting implements CollisionFactory {
|
||||
|
||||
private static final CollisionBox[] COLLISION_BOXES = makeShapes(1.0F, 1.0F, 16.0F, 0.0F, 16.0F, true);
|
||||
|
||||
+1
-5
@@ -15,16 +15,12 @@ import com.github.retrooper.packetevents.protocol.world.states.enums.South;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.enums.West;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
|
||||
public class DynamicCollisionWall extends DynamicConnecting implements CollisionFactory {
|
||||
public class DynamicWall extends DynamicConnecting implements CollisionFactory {
|
||||
public static final CollisionBox[] BOXES = makeShapes(4.0F, 3.0F, 16.0F, 0.0F, 16.0F, false);
|
||||
// https://bugs.mojang.com/browse/MC-9565
|
||||
// https://bugs.mojang.com/browse/MC-94016
|
||||
private static final CollisionBox[] COLLISION_BOXES = makeShapes(4.0F, 3.0F, 24.0F, 0.0F, 24.0F, false);
|
||||
|
||||
/**
|
||||
* @deprecated use DynamicHitboxWall
|
||||
*/
|
||||
@Deprecated
|
||||
public CollisionBox fetchRegularBox(GrimPlayer player, WrappedBlockState state, ClientVersion version, int x, int y, int z) {
|
||||
int north, south, west, east, up;
|
||||
north = south = west = east = up = 0;
|
||||
@@ -5,8 +5,6 @@ import com.github.retrooper.packetevents.protocol.world.BlockFace;
|
||||
import java.util.List;
|
||||
|
||||
public interface CollisionBox {
|
||||
CollisionBox union(SimpleCollisionBox other);
|
||||
|
||||
boolean isCollided(SimpleCollisionBox other);
|
||||
|
||||
boolean isIntersected(SimpleCollisionBox other);
|
||||
|
||||
@@ -16,12 +16,6 @@ public class ComplexCollisionBox implements CollisionBox {
|
||||
return boxes.add(collisionBox);
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
add(other);
|
||||
return this;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollided(SimpleCollisionBox other) {
|
||||
for (CollisionBox box : boxes) {
|
||||
|
||||
@@ -21,14 +21,6 @@ public class DynamicCollisionBox implements CollisionBox {
|
||||
this.block = block;
|
||||
}
|
||||
|
||||
// Untested but currently unused
|
||||
// *should* work because every single one of these eventually becomes a Complex, Simple, or NoCollision Box
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
CollisionBox dynamicBox = box.fetch(player, version, block, x, y, z).offset(x, y, z);
|
||||
return dynamicBox.union(other);
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollided(SimpleCollisionBox other) {
|
||||
return box.fetch(player, version, block, x, y, z).offset(x, y, z).isCollided(other);
|
||||
|
||||
@@ -2,18 +2,6 @@ package ac.grim.grimac.utils.collisions.datatypes;
|
||||
|
||||
public class HexCollisionBox extends SimpleCollisionBox {
|
||||
|
||||
/**
|
||||
* Creates a box defined by two points in 3d space; used to represent hitboxes and collision boxes.
|
||||
* Mojang's block hitbox values are all based on chunks, so they're stored in game as 16 * the actual size
|
||||
* When copying block hitbox values, it may be easier to simple copy the multiplied values and use this class
|
||||
* If your min/max values are < 1 you should probably check out {@link SimpleCollisionBox}
|
||||
* @param minX 16 * x position of first corner
|
||||
* @param minY 16 * y position of first corner
|
||||
* @param minZ 16 * z position of first corner
|
||||
* @param maxX 16 * x position of second corner
|
||||
* @param maxY 16 * y position of second corner
|
||||
* @param maxZ 16 * z position of second corner
|
||||
*/
|
||||
public HexCollisionBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
this.minX = minX / 16d;
|
||||
this.minY = minY / 16d;
|
||||
|
||||
@@ -1,10 +0,0 @@
|
||||
package ac.grim.grimac.utils.collisions.datatypes;
|
||||
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
|
||||
// Exists for the same reason as HexCollisionBox but for offset blocks; read comments there if unsure
|
||||
public class HexOffsetCollisionBox extends OffsetCollisionBox {
|
||||
public HexOffsetCollisionBox(StateType block, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
super(block, minX / 16d, minY / 16d, minZ / 16d, maxX / 16d, maxY / 16d, maxZ / 16d);
|
||||
}
|
||||
}
|
||||
@@ -9,11 +9,6 @@ public class NoCollisionBox implements CollisionBox {
|
||||
private NoCollisionBox() {
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
return other;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean isCollided(SimpleCollisionBox other) {
|
||||
return false;
|
||||
|
||||
@@ -1,105 +0,0 @@
|
||||
package ac.grim.grimac.utils.collisions.datatypes;
|
||||
|
||||
import ac.grim.grimac.utils.math.GrimMath;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.defaulttags.BlockTags;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateType;
|
||||
import com.github.retrooper.packetevents.protocol.world.states.type.StateTypes;
|
||||
|
||||
import java.util.HashSet;
|
||||
|
||||
public class OffsetCollisionBox extends SimpleCollisionBox {
|
||||
|
||||
public static enum OffsetType {
|
||||
NONE,
|
||||
XZ,
|
||||
XYZ,
|
||||
}
|
||||
|
||||
float maxHorizontalModelOffset = 0.25F;
|
||||
float maxVerticalModelOffset = 0.2F;
|
||||
double offsetX = 0;
|
||||
double offsetY = 0;
|
||||
double offsetZ = 0;
|
||||
|
||||
OffsetType offsetType;
|
||||
|
||||
private static final HashSet<StateType> XZ_OFFSET_BLOCKSTATES = new HashSet<>();
|
||||
private static final HashSet<StateType> XYZ_OFFSET_BLOCKSTATES = new HashSet<>();
|
||||
|
||||
static {
|
||||
// Can we add a hasOffSet to StateType() ?
|
||||
// Or a new BlockTag for XZ and XYZ Offset ?
|
||||
XZ_OFFSET_BLOCKSTATES.add(StateTypes.MANGROVE_PROPAGULE);
|
||||
|
||||
XZ_OFFSET_BLOCKSTATES.addAll(BlockTags.SMALL_FLOWERS.getStates());
|
||||
XZ_OFFSET_BLOCKSTATES.add(StateTypes.BAMBOO_SAPLING);
|
||||
XZ_OFFSET_BLOCKSTATES.add(StateTypes.BAMBOO);
|
||||
XZ_OFFSET_BLOCKSTATES.add(StateTypes.POINTED_DRIPSTONE);
|
||||
// Only offsets rendering HitBox on XZ // we should document this somewhere for future reference
|
||||
// XZ_OFFSET_BLOCKSTATES.addAll(BlockTags.TALL_FLOWERS.getStates());
|
||||
// XZ_OFFSET_BLOCKSTATES.add(StateTypes.TALL_SEAGRASS);
|
||||
// XZ_OFFSET_BLOCKSTATES.add(StateTypes.TALL_GRASS);
|
||||
// XZ_OFFSET_BLOCKSTATES.add(StateTypes.LARGE_FERN);
|
||||
// XZ_OFFSET_BLOCKSTATES.add(StateTypes.WARPED_ROOTS);
|
||||
// XZ_OFFSET_BLOCKSTATES.add(StateTypes.NETHER_SPROUTS);
|
||||
// XZ_OFFSET_BLOCKSTATES.add(StateTypes.CRIMSON_ROOTS);
|
||||
// XZ_OFFSET_BLOCKSTATES.add(StateTypes.HANGING_ROOTS);
|
||||
|
||||
// Only offsets rendering on XYZ, not HitBox
|
||||
// XYZ_OFFSET_BLOCKSTATES.add(StateTypes.SHORT_GRASS);
|
||||
// XYZ_OFFSET_BLOCKSTATES.add(StateTypes.FERN);
|
||||
// XYZ_OFFSET_BLOCKSTATES.add(StateTypes.SMALL_DRIPLEAF);
|
||||
}
|
||||
|
||||
public OffsetCollisionBox(StateType block, double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
super(minX, minY, minZ, maxX, maxY, maxZ);
|
||||
if (block.equals(StateTypes.POINTED_DRIPSTONE)) {
|
||||
maxHorizontalModelOffset = 0.125F;
|
||||
}
|
||||
// else if (block.equals(StateTypes.SMALL_DRIPLEAF)) {
|
||||
// maxVerticalModelOffset = 0.1F;
|
||||
// }
|
||||
|
||||
if (XZ_OFFSET_BLOCKSTATES.contains(block)) {
|
||||
offsetType = OffsetType.XZ;
|
||||
return;
|
||||
} else if (XYZ_OFFSET_BLOCKSTATES.contains(block)) {
|
||||
offsetType = OffsetType.XYZ;
|
||||
return;
|
||||
}
|
||||
throw new RuntimeException("Invalid State Type for OffSetCollisionBox: " + block);
|
||||
}
|
||||
|
||||
@Override
|
||||
public SimpleCollisionBox offset(double x, double y, double z) {
|
||||
// In case you want to call .offset() again or get the box values without offset.
|
||||
resetBlockStateOffSet();
|
||||
long l;
|
||||
switch (offsetType) {
|
||||
case NONE:
|
||||
return super.offset(x, y, z);
|
||||
case XZ:
|
||||
l = GrimMath.hashCode(x, 0, z);
|
||||
offsetX = GrimMath.clamp(((double)((float)(l & 15L) / 15.0F) - 0.5) * 0.5, (double)(-maxHorizontalModelOffset), (double)maxHorizontalModelOffset);
|
||||
offsetZ = GrimMath.clamp(((double)((float)(l >> 8 & 15L) / 15.0F) - 0.5) * 0.5, (double)(-maxHorizontalModelOffset), (double)maxHorizontalModelOffset);
|
||||
return super.offset(x + offsetX, y, z + offsetZ);
|
||||
case XYZ:
|
||||
l = GrimMath.hashCode(x, 0, z);
|
||||
offsetY = ((double)((float)(l >> 4 & 15L) / 15.0F) - 1.0) * (double) maxVerticalModelOffset;
|
||||
offsetX = GrimMath.clamp(((double)((float)(l & 15L) / 15.0F) - 0.5) * 0.5, (double)(-maxHorizontalModelOffset), (double)maxHorizontalModelOffset);
|
||||
offsetZ = GrimMath.clamp(((double)((float)(l >> 8 & 15L) / 15.0F) - 0.5) * 0.5, (double)(-maxHorizontalModelOffset), (double)maxHorizontalModelOffset);
|
||||
return super.offset(x + offsetX, offsetY, z + offsetZ);
|
||||
}
|
||||
// You *really* shouldn't be using this class if offsetType = null
|
||||
return null;
|
||||
}
|
||||
|
||||
public void resetBlockStateOffSet() {
|
||||
this.minX += offsetX;
|
||||
this.minY += offsetY;
|
||||
this.minZ += offsetZ;
|
||||
this.maxX += offsetX;
|
||||
this.maxY += offsetY;
|
||||
this.maxZ += offsetZ;
|
||||
}
|
||||
}
|
||||
@@ -24,17 +24,6 @@ public class SimpleCollisionBox implements CollisionBox {
|
||||
this(0, 0, 0, 0, 0, 0, false);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a box defined by two points in 3d space; used to represent hitboxes and collision boxes.
|
||||
* If your min/max values are > 1 you should probably check out {@link HexCollisionBox}
|
||||
* @param minX x position of first corner
|
||||
* @param minY y position of first corner
|
||||
* @param minZ z position of first corner
|
||||
* @param maxX x position of second corner
|
||||
* @param maxY y position of second corner
|
||||
* @param maxZ z position of second corner
|
||||
* @param fullBlock - whether on not the box is a perfect 1x1x1 sized block
|
||||
*/
|
||||
public SimpleCollisionBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ, boolean fullBlock) {
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
@@ -58,17 +47,7 @@ public class SimpleCollisionBox implements CollisionBox {
|
||||
this(minX, minY, minZ, minX + 1, minY + 1, minZ + 1, true);
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a box defined by two points in 3d space; used to represent hitboxes and collision boxes.
|
||||
* If your min/max values are > 1 you should probably check out {@link HexCollisionBox}
|
||||
* Use only if you don't know the fullBlock status, which is rare
|
||||
* @param minX x position of first corner
|
||||
* @param minY y position of first corner
|
||||
* @param minZ z position of first corner
|
||||
* @param maxX x position of second corner
|
||||
* @param maxY y position of second corner
|
||||
* @param maxZ z position of second corner
|
||||
*/
|
||||
// Use only if you don't know the fullBlock status, which is rare
|
||||
public SimpleCollisionBox(double minX, double minY, double minZ, double maxX, double maxY, double maxZ) {
|
||||
this.minX = minX;
|
||||
this.maxX = maxX;
|
||||
@@ -163,8 +142,7 @@ public class SimpleCollisionBox implements CollisionBox {
|
||||
return vectors;
|
||||
}
|
||||
|
||||
@Override
|
||||
public CollisionBox union(SimpleCollisionBox other) {
|
||||
public SimpleCollisionBox union(SimpleCollisionBox other) {
|
||||
this.minX = Math.min(this.minX, other.minX);
|
||||
this.minY = Math.min(this.minY, other.minY);
|
||||
this.minZ = Math.min(this.minZ, other.minZ);
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
package ac.grim.grimac.utils.common;
|
||||
|
||||
|
||||
import ac.grim.grimac.api.config.ConfigManager;
|
||||
|
||||
public interface ConfigReloadObserver {
|
||||
|
||||
void onReload(ConfigManager config);
|
||||
|
||||
}
|
||||
@@ -101,29 +101,29 @@ public final class ValuedAttribute {
|
||||
}
|
||||
|
||||
public double with(WrapperPlayServerUpdateAttributes.Property property) {
|
||||
double d0 = property.getValue();
|
||||
double baseValue = property.getValue();
|
||||
double additionSum = 0;
|
||||
double multiplyBaseSum = 0;
|
||||
double multiplyTotalProduct = 1.0;
|
||||
|
||||
List<WrapperPlayServerUpdateAttributes.PropertyModifier> modifiers = property.getModifiers();
|
||||
modifiers.removeIf(modifier -> modifier.getUUID().equals(SPRINTING_MODIFIER_UUID) || modifier.getName().getKey().equals("sprinting"));
|
||||
|
||||
for (WrapperPlayServerUpdateAttributes.PropertyModifier attributemodifier : modifiers) {
|
||||
if (attributemodifier.getOperation() == WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.ADDITION)
|
||||
d0 += attributemodifier.getAmount();
|
||||
for (WrapperPlayServerUpdateAttributes.PropertyModifier modifier : modifiers) {
|
||||
switch (modifier.getOperation()) {
|
||||
case ADDITION:
|
||||
additionSum += modifier.getAmount();
|
||||
break;
|
||||
case MULTIPLY_BASE:
|
||||
multiplyBaseSum += modifier.getAmount();
|
||||
break;
|
||||
case MULTIPLY_TOTAL:
|
||||
multiplyTotalProduct *= (1.0 + modifier.getAmount());
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
double d1 = d0;
|
||||
|
||||
for (WrapperPlayServerUpdateAttributes.PropertyModifier attributemodifier : modifiers) {
|
||||
if (attributemodifier.getOperation() == WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.MULTIPLY_BASE)
|
||||
d1 += d0 * attributemodifier.getAmount();
|
||||
}
|
||||
|
||||
for (WrapperPlayServerUpdateAttributes.PropertyModifier attributemodifier : modifiers) {
|
||||
if (attributemodifier.getOperation() == WrapperPlayServerUpdateAttributes.PropertyModifier.Operation.MULTIPLY_TOTAL)
|
||||
d1 *= 1.0D + attributemodifier.getAmount();
|
||||
}
|
||||
|
||||
double newValue = GrimMath.clampFloat((float) d1, (float) min, (float) max);
|
||||
double newValue = GrimMath.clamp((baseValue + additionSum) * (1 + multiplyBaseSum) * multiplyTotalProduct, min, max);
|
||||
if (setRewriter != null) {
|
||||
newValue = setRewriter.apply(this.value, newValue);
|
||||
}
|
||||
|
||||
@@ -99,14 +99,19 @@ public class PacketEntity extends TypedPacketEntity {
|
||||
}
|
||||
|
||||
public void setAttribute(Attribute attribute, double value) {
|
||||
ValuedAttribute property = getAttribute(attribute).orElse(null);
|
||||
if (property == null) throw new IllegalArgumentException("Cannot set attribute " + attribute.getName() + " for entity " + getType().getName().toString() + "!");
|
||||
ValuedAttribute property = attributeMap.get(attribute);
|
||||
if (property == null) {
|
||||
throw new IllegalArgumentException("Cannot set attribute " + attribute.getName() + " for entity " + getType().getName().toString() + "!");
|
||||
}
|
||||
property.override(value);
|
||||
}
|
||||
|
||||
public double getAttributeValue(Attribute attribute) {
|
||||
return getAttribute(attribute).map(ValuedAttribute::get)
|
||||
.orElseThrow(() -> new IllegalArgumentException("Cannot get attribute " + attribute.getName() + " for entity " + getType().getName().toString() + "!"));
|
||||
final ValuedAttribute property = attributeMap.get(attribute);
|
||||
if (property == null) {
|
||||
throw new IllegalArgumentException("Cannot get attribute " + attribute.getName() + " for entity " + getType().getName().toString() + "!");
|
||||
}
|
||||
return property.get();
|
||||
}
|
||||
|
||||
public void resetAttributes() {
|
||||
|
||||
@@ -47,6 +47,28 @@ public class PacketEntitySelf extends PacketEntity {
|
||||
setAttribute(Attributes.GENERIC_STEP_HEIGHT, 0.5f);
|
||||
}
|
||||
|
||||
getAttribute(Attributes.GENERIC_SCALE).get().withSetRewriter((oldValue, newValue) -> {
|
||||
if (player.getClientVersion().isOlderThanOrEquals(ClientVersion.V_1_20_5) || (newValue).equals(oldValue)) {
|
||||
return oldValue;
|
||||
} else {
|
||||
// Elytra, standing, sneaking (1.14)
|
||||
player.possibleEyeHeights[2][0] = 0.4 * newValue;
|
||||
player.possibleEyeHeights[2][1] = 1.62 * newValue;
|
||||
player.possibleEyeHeights[2][2] = 1.27 * newValue;
|
||||
|
||||
// sneaking (1.14), standing, Elytra
|
||||
player.possibleEyeHeights[1][0] = 1.27 * newValue;
|
||||
player.possibleEyeHeights[1][1] = 1.62 * newValue;
|
||||
player.possibleEyeHeights[1][2] = 0.4 * newValue;
|
||||
|
||||
// standing, sneaking (1.14), Elytra
|
||||
player.possibleEyeHeights[0][0] = 1.62 * newValue;
|
||||
player.possibleEyeHeights[0][1] = 1.27 * newValue;
|
||||
player.possibleEyeHeights[0][2] = 0.4 * newValue;
|
||||
return newValue;
|
||||
}
|
||||
});
|
||||
|
||||
final ValuedAttribute movementSpeed = ValuedAttribute.ranged(Attributes.GENERIC_MOVEMENT_SPEED, 0.1f, 0, 1024);
|
||||
movementSpeed.with(new WrapperPlayServerUpdateAttributes.Property("MOVEMENT_SPEED", 0.1f, new ArrayList<>()));
|
||||
trackAttribute(movementSpeed);
|
||||
|
||||
@@ -105,10 +105,4 @@ public class GrimMath {
|
||||
public static boolean isNearlySame(double a, double b, double epoch) {
|
||||
return Math.abs(a-b) < epoch;
|
||||
}
|
||||
|
||||
public static long hashCode(double x, int y, double z) {
|
||||
long l = (long)(x * 3129871) ^ (long)z * 116129781L ^ (long)y;
|
||||
l = l * l * 42317861L + l * 11L;
|
||||
return l >> 16;
|
||||
}
|
||||
}
|
||||
@@ -181,7 +181,8 @@ public class ReachUtils {
|
||||
|
||||
double lowest = Double.MAX_VALUE;
|
||||
|
||||
for (double eyes : player.getPossibleEyeHeights()) {
|
||||
final double[] possibleEyeHeights = player.getPossibleEyeHeights();
|
||||
for (double eyes : possibleEyeHeights) {
|
||||
if (giveMovementThresholdLenience) targetBox.expand(player.getMovementThreshold());
|
||||
Vector from = new Vector(player.x, player.y + eyes, player.z);
|
||||
Vector closestPoint = VectorUtils.cutBoxToVector(from, targetBox);
|
||||
|
||||
@@ -87,7 +87,7 @@ RotationPlace:
|
||||
# Vérification de no-slow basée sur la prédiction.
|
||||
# Grim tient compte des problèmes de netcode ici... difficile à tromper même en spamant le clic droit et le bouton de la main secondaire.
|
||||
# Bien plus stable que les autres anti-triche, mais veuillez signaler toute fausse détection... J'ai corrigé de nombreux problèmes de netcode ici.
|
||||
NoSlow:
|
||||
NoSlowA:
|
||||
# Quel est le niveau d'écart considéré comme "triche"
|
||||
# Par défaut, cela est inférieur à d'autres écarts.
|
||||
# Génère des avertissements avec des valeurs comprises entre 0,03 et 0,2 lors de l'utilisation de NoSlow
|
||||
|
||||
Reference in new issue
Block a user