Skip to content

Commit

Permalink
Use 'sun.misc.Unsafe' to change the 'final field flagsList from World…
Browse files Browse the repository at this point in the history
…Guard' at 1.7.10

Add several warnings in case it does not work (as it might not work on java after 2025)

Now it will try things on this order:
 1- Check if is a modified WorldGuard version with the extra method 'addFlag'
 2- If not, try the normal reflection way (should work on java 8)
 3- Try using UNSAFE to change the field, should work on java 21 (for now)
 4- If no one works, warn the player about the problem.
  • Loading branch information
EverNife committed Jun 15, 2024
1 parent d70d1cd commit cdff455
Show file tree
Hide file tree
Showing 3 changed files with 76 additions and 13 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
package br.com.finalcraft.evernifecore.unsafereflecton;

import sun.misc.Unsafe;

import java.lang.reflect.Field;

public class UnsafeUtil {

static Field theUnsafe;
static Unsafe UNSAFE;
static {
try {
theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
theUnsafe.setAccessible(true);
UNSAFE = (Unsafe) theUnsafe.get(null); // Cache this
}catch (Throwable e){

}
}

// As noted here https://github.com/GTNewHorizons/lwjgl3ify?tab=readme-ov-file#javabasejavalangreflect-classes-are-protected-from-reflective-access
// this method 'MIGHT' work until java 2025
public static void setField(Field data, Object object, Object value) {
if (object == null) {
long offset = UNSAFE.staticFieldOffset(data);
Object base = UNSAFE.staticFieldBase(data);
UNSAFE.putObject(base, offset, value);
} else {
long offset = UNSAFE.objectFieldOffset(data);
UNSAFE.putObject(object, offset, value);
}
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -61,6 +61,10 @@ public FCWorldGuardRegion wrapRegion(World world, ProtectedRegion protectedRegio

@Override
public void registerFlag(@NotNull Flag<?> flag, @NotNull Plugin plugin) {
if (ImpIFCFlagRegistry.errorOnFlagRegistering){
plugin.getLogger().info("[EverNifeCore -> WorldGuard] There was an error on EverNifeCore's WorldGuard Flag's Integration at the Startup, read the message over there! Skipping flag registration of name: " + flag.getName());
return;
}
getFlagRegistry().register(flag);
plugin.getLogger().info("[EverNifeCore -> WorldGuard] Custom Flag registered: " + flag.getName());
schedulWorldGuardReload();
Expand Down
Original file line number Diff line number Diff line change
@@ -1,10 +1,13 @@
package br.com.finalcraft.evernifecore.compat.v1_7_R4.protection.worldguard.wrappers;

import br.com.finalcraft.evernifecore.protection.worldguard.IFCFlagRegistry;
import br.com.finalcraft.evernifecore.unsafereflecton.UnsafeUtil;
import com.sk89q.worldguard.protection.flags.DefaultFlag;
import com.sk89q.worldguard.protection.flags.Flag;
import org.bukkit.plugin.java.JavaPlugin;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
import sun.misc.Unsafe;

import java.lang.reflect.Field;
import java.lang.reflect.Modifier;
Expand All @@ -17,24 +20,42 @@ public class ImpIFCFlagRegistry implements IFCFlagRegistry {

private static boolean modifiedWorldguard = false;
private static Field flagsListField = null;
private static boolean shouldUseUnsafe = false;
public static boolean errorOnFlagRegistering;

public ImpIFCFlagRegistry() {
try {
DefaultFlag.class.getDeclaredMethod("addFlag", Flag.class);
//We have a MODIFIED WorldGuard.jar with the extra method 'addFlag'
DefaultFlag.class.getDeclaredMethod("addFlag", Flag.class);
modifiedWorldguard = true;
}catch (Exception e){

return;
}catch (Throwable e){
//ignore
}
if (modifiedWorldguard == false){
try {
flagsListField = DefaultFlag.class.getDeclaredField("flagsList");
flagsListField.setAccessible(true);
try {
flagsListField = DefaultFlag.class.getDeclaredField("flagsList");
flagsListField.setAccessible(true);

Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(flagsListField, flagsListField.getModifiers() & ~Modifier.FINAL);
}catch (Exception e){
e.printStackTrace();
Field modifiersField = Field.class.getDeclaredField("modifiers");
modifiersField.setAccessible(true);
modifiersField.setInt(flagsListField, flagsListField.getModifiers() & ~Modifier.FINAL);
}catch (Throwable e1){
try {
Field theUnsafe = Unsafe.class.getDeclaredField("theUnsafe");
if (theUnsafe != null){
shouldUseUnsafe = true;
return;
}
}catch (Throwable e2){
errorOnFlagRegistering = true;
JavaPlugin everNifeCore = JavaPlugin.getProvidingPlugin(ImpIFCFlagRegistry.class);
everNifeCore.getLogger().severe("There was an error Injecting ImpIFCFlagRegistry reflection.");
everNifeCore.getLogger().severe("This error will prevent EverNifeCore from registering WorldGuardFlags!");
everNifeCore.getLogger().severe("This error can possibly be solved by using a custom version of WorldGuard for 1.7.10, Ask EverNife for it!");
everNifeCore.getLogger().severe("First Error when trying to use Normal Reflection\n\n");
e1.printStackTrace();
everNifeCore.getLogger().severe("\n\nSecond Error when trying to use sun.unsafe.UNSAFE.class \n\n");
e2.printStackTrace();
}
}
}
Expand All @@ -52,7 +73,12 @@ public void register(Flag<?> flag) {
theNewFlagsArray[theNewFlagsArray.length - 1] = flag;

//Reset the final field of DefautlFlags.flags
flagsListField.set(null,theNewFlagsArray);
if (shouldUseUnsafe){
UnsafeUtil.setField(flagsListField, null, theNewFlagsArray);
}else {
flagsListField.set(null,theNewFlagsArray);
}

}catch (Exception e){
throw new RuntimeException(e);
}
Expand Down

0 comments on commit cdff455

Please sign in to comment.