Skip to content

Commit

Permalink
Added ReflectUtil class, successfully replaced the crossbow registry …
Browse files Browse the repository at this point in the history
…entry with a custom class.
  • Loading branch information
rolyPolyVole committed Aug 11, 2024
1 parent 9b9690e commit 792bfdd
Show file tree
Hide file tree
Showing 7 changed files with 295 additions and 38 deletions.
20 changes: 10 additions & 10 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -15,21 +15,21 @@ plugins {
}

val groupStringSeparator = "."
val kebabcaseStringSeparator = "-"
val snakecaseStringSeparator = "_"
val kebabCaseStringSeparator = "-"
val snakeCaseStringSeparator = "_"

fun capitalizeFirstLetter(string: String): String {
return string.first().uppercase() + string.slice(IntRange(1, string.length - 1))
}

fun snakecase(kebabcaseString: String): String {
return kebabcaseString.lowercase().replace(kebabcaseStringSeparator, snakecaseStringSeparator)
fun snakeCase(kebabCaseString: String): String {
return kebabCaseString.lowercase().replace(kebabCaseStringSeparator, snakeCaseStringSeparator)
}

fun pascalcase(kebabcaseString: String): String {
fun pascalCase(kebabCaseString: String): String {
var pascalCaseString = ""

val splitString = kebabcaseString.split(kebabcaseStringSeparator)
val splitString = kebabCaseString.split(kebabCaseStringSeparator)

for (part in splitString) {
pascalCaseString += capitalizeFirstLetter(part)
Expand All @@ -41,13 +41,13 @@ fun pascalcase(kebabcaseString: String): String {
description = "A Minecraft Paper plugin that adds a firework-focused PvP gamemode."

val mainProjectAuthor = "Slqmy"
val projectAuthors = listOfNotNull(mainProjectAuthor, "rolyPolyVole")
val mainestProjectAuthor = "rolyPolyVole"
val projectAuthors = listOfNotNull(mainProjectAuthor, mainestProjectAuthor)

val topLevelDomain = "net"

val projectNameString = rootProject.name

group = topLevelDomain + groupStringSeparator + mainProjectAuthor.lowercase() + groupStringSeparator + snakecase(projectNameString)
group = topLevelDomain + groupStringSeparator + mainProjectAuthor.lowercase() + groupStringSeparator + snakeCase(projectNameString)
version = "1.0.0"

val buildDirectoryString = buildDir.toString()
Expand Down Expand Up @@ -97,7 +97,7 @@ tasks {
bukkitPluginYaml {
authors = projectAuthors

main = projectGroupString + groupStringSeparator + pascalcase(projectNameString)
main = projectGroupString + groupStringSeparator + pascalCase(projectNameString)
apiVersion = paperApiVersion

load = BukkitPluginYaml.PluginLoadOrder.STARTUP
Expand Down
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
package net.slqmy.firework_wars_plugin;

import net.slqmy.firework_wars_plugin.util.PersistentDataManager;
import org.bukkit.event.EventHandler;
import org.bukkit.event.Listener;
import org.bukkit.event.player.PlayerJoinEvent;
import org.bukkit.inventory.ItemStack;
import org.bukkit.plugin.java.JavaPlugin;
import org.checkerframework.checker.nullness.qual.NonNull;
import org.checkerframework.framework.qual.DefaultQualifier;
Expand All @@ -15,8 +19,10 @@
import net.slqmy.firework_wars_plugin.items.manager.CustomItemManager;
import net.slqmy.firework_wars_plugin.language.LanguageManager;

@DefaultQualifier(NonNull.class)
public final class FireworkWarsPlugin extends JavaPlugin {
import java.util.logging.Logger;

public final class FireworkWarsPlugin extends JavaPlugin implements Listener {
public static Logger LOGGER;

private PlayerDataManager playerDataManager;
private LanguageManager languageManager;
Expand Down Expand Up @@ -49,6 +55,10 @@ public PersistentDataManager getPdcManager() {
return this.pdcManager;
}

public FireworkWarsPlugin() {
LOGGER = getLogger();
}

@Override
public void onEnable() {
getDataFolder().mkdir();
Expand All @@ -68,6 +78,8 @@ public void onEnable() {

new SetLanguageCommand(this);
new ArenaCommand(this);

getServer().getPluginManager().registerEvents(this, this);
}

@Override
Expand All @@ -76,4 +88,12 @@ public void onDisable() {
playerDataManager.save();
}
}

@EventHandler
public void onPlayerJoin(PlayerJoinEvent event) {
ItemStack item1 = customItemManager.getItem("firework_rifle_ammo").getItem(event.getPlayer());
ItemStack item2 = customItemManager.getItem("firework_rifle").getItem(event.getPlayer());

event.getPlayer().getInventory().addItem(item1, item2);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -29,13 +29,13 @@ public FireworkRifleItem(FireworkWarsPlugin plugin) {
}

@Override
protected ItemStack getItem(Player player) {
public ItemStack getItem(Player player) {
return new ItemBuilder<CrossbowMeta>(plugin, itemMaterial)
.setName(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE, player))
.setLore(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE_LORE, player))
.setEnchanted(true)
.setUnbreakable(true)
.itemSupplier(() -> plugin.getCustomItemManager().getNMSItem("firework_rifle_crossbow").getDefaultInstance().asBukkitCopy())
.itemSupplier(() -> plugin.getCustomItemManager().getBukkitItemStackFromNMS("crossbow"))
.modifyMeta(meta -> meta.addEnchant(Enchantment.QUICK_CHARGE, 3, true))
.build();
}
Expand All @@ -46,17 +46,21 @@ public void onCrossbowLoad(EntityLoadCrossbowEvent event) {
return;
}

CrossbowMeta crossbowMeta = (CrossbowMeta) event.getCrossbow().getItemMeta();
FireworkWarsGame game = plugin.getGameManager().getFireworkWarsGame(player);

ItemStack firework = new ItemStack(Material.FIREWORK_ROCKET);
FireworkMeta fireworkMeta = (FireworkMeta) firework.getItemMeta();
if (game == null) {
return;
}

FireworkWarsGame game = plugin.getGameManager().getFireworkWarsGame(player);
FireworkWarsTeam team = game.getTeam(player);

ItemStack firework = new ItemStack(Material.FIREWORK_ROCKET);
FireworkMeta fireworkMeta = (FireworkMeta) firework.getItemMeta();

addFireworkStars(fireworkMeta, team.getConfiguredTeam().getColor());
firework.setItemMeta(fireworkMeta);

CrossbowMeta crossbowMeta = (CrossbowMeta) event.getCrossbow().getItemMeta();
crossbowMeta.setChargedProjectiles(List.of(firework));
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@ public RifleAmmo(FireworkWarsPlugin plugin) {
}

@Override
protected ItemStack getItem(Player player) {
public ItemStack getItem(Player player) {
return new ItemBuilder<FireworkMeta>(plugin, itemMaterial)
.setName(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE_AMMO, player))
.setLore(plugin.getLanguageManager().getMessage(Message.FIREWORK_RIFLE_AMMO_LORE, player))
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -55,5 +55,5 @@ protected ItemStack getBaseItemStack() {
return new ItemStack(itemMaterial);
}

protected abstract ItemStack getItem(Player player);
public abstract ItemStack getItem(Player player);
}
Original file line number Diff line number Diff line change
@@ -1,18 +1,30 @@
package net.slqmy.firework_wars_plugin.items.manager;

import com.mojang.serialization.Lifecycle;
import it.unimi.dsi.fastutil.objects.ObjectArrayList;
import it.unimi.dsi.fastutil.objects.Reference2IntOpenHashMap;
import it.unimi.dsi.fastutil.objects.ReferenceList;
import net.minecraft.core.DefaultedMappedRegistry;
import net.minecraft.core.Holder;
import net.minecraft.core.MappedRegistry;
import net.minecraft.core.RegistrationInfo;
import net.minecraft.core.registries.BuiltInRegistries;
import net.minecraft.resources.ResourceKey;
import net.minecraft.resources.ResourceLocation;
import net.minecraft.world.item.Item;
import net.minecraft.world.item.Items;
import net.slqmy.firework_wars_plugin.FireworkWarsPlugin;
import net.slqmy.firework_wars_plugin.items.FireworkRifleItem;
import net.slqmy.firework_wars_plugin.items.RifleAmmo;
import net.slqmy.firework_wars_plugin.items.nms.CustomCrossbow;
import net.slqmy.firework_wars_plugin.util.ReflectUtil;
import org.bukkit.craftbukkit.inventory.CraftItemStack;
import org.bukkit.inventory.ItemStack;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.sql.Ref;
import java.util.HashMap;
import java.util.IdentityHashMap;
import java.util.Map;
Expand All @@ -29,11 +41,12 @@ public CustomItemManager(FireworkWarsPlugin plugin) {
registerItem(new FireworkRifleItem(plugin));
registerItem(new RifleAmmo(plugin));

reopenItemRegistry();
reopenItemRegistry(); //Prevent error

registerNMSItem(
"firework_rifle_crossbow",
new CustomCrossbow(CustomCrossbow.PROPERTIES, getItem("firework_rifle_ammo")));
"crossbow",
new CustomCrossbow(CustomCrossbow.PROPERTIES, getItem("firework_rifle_ammo")),
Items.CROSSBOW);

BuiltInRegistries.ITEM.freeze();
}
Expand All @@ -51,30 +64,74 @@ public AbstractItem getItem(String itemId) {
}

public Item getNMSItem(String itemId) {
return nmsItemRegistry.get(itemId);
return nmsItemRegistry.get(itemId);
}

public ItemStack getBukkitItemStackFromNMS(String itemId) {
net.minecraft.world.item.ItemStack nmsItemStack = nmsItemRegistry.get(itemId).getDefaultInstance();
ItemStack itemStack = nmsItemStack.asBukkitCopy();

itemStack.setItemMeta(CraftItemStack.getItemMeta(nmsItemStack));
return itemStack;
}

private void registerItem(AbstractItem item) {
itemRegistry.put(item.getItemId(), item);
}

private void registerNMSItem(String id, Item item) {
Items.registerItem(id, item);
private void registerNMSItem(String id, Item item, Item override) {
overrideItemRegistryEntry(id, item, override);

nmsItemRegistry.put(id, item);
}

private void reopenItemRegistry() {
try {
Field frozenField = MappedRegistry.class.getDeclaredField("frozen");
Field unregisteredHoldersField = MappedRegistry.class.getDeclaredField("unregisteredIntrusiveHolders");

frozenField.setAccessible(true);
unregisteredHoldersField.setAccessible(true);

frozenField.setBoolean(BuiltInRegistries.ITEM, false);
unregisteredHoldersField.set(BuiltInRegistries.ITEM, new IdentityHashMap<>());
} catch (IllegalAccessException | NoSuchFieldException e) {
plugin.getLogger().severe("Failed to reopen the item registry! " + e.getMessage());
}
ReflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> {
ReflectUtil.setFieldValue("frozen", false);
ReflectUtil.setFieldValue("unregisteredIntrusiveHolders", new IdentityHashMap<>());
});
}

private void overrideItemRegistryEntry(String id, Item item, Item override) {
ResourceKey<Item> key = ResourceKey.create(
BuiltInRegistries.ITEM.key(), ResourceLocation.withDefaultNamespace(id));

RegistrationInfo info = RegistrationInfo.BUILT_IN;

Holder.Reference<Item> holder = ReflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> {
Map<Item, Holder.Reference<Item>> map = ReflectUtil.getFieldValue("unregisteredIntrusiveHolders");
return map.get(item);
});

ReflectUtil.reflect(Holder.Reference.class, holder, () -> {
ReflectUtil.invokeMethod("bindKey", new Class<?>[] {ResourceKey.class}, key);
});

ReflectUtil.reflect(MappedRegistry.class, BuiltInRegistries.ITEM, () -> {
HashMap<ResourceKey<Item>, Holder.Reference<Item>> byKey = ReflectUtil.getFieldValue("byKey");
byKey.put(key, holder);

HashMap<ResourceLocation, Holder.Reference<Item>> byLocation = ReflectUtil.getFieldValue("byLocation");
byLocation.put(key.location(), holder);

IdentityHashMap<Item, Holder.Reference<Item>> byValue = ReflectUtil.getFieldValue("byValue");
byValue.put(item, holder);

ObjectArrayList<Holder.Reference<Item>> byId = ReflectUtil.getFieldValue("byId");
byId.set(byId.indexOf(byValue.remove(override)), holder);

Reference2IntOpenHashMap<Item> toId = ReflectUtil.getFieldValue("toId");
toId.put(item, toId.getInt(override));
toId.removeInt(override);

IdentityHashMap<ResourceKey<Item>, RegistrationInfo> registrationInfos = ReflectUtil.getFieldValue("registrationInfos");
registrationInfos.put(key, info);

Lifecycle lifecycle = ReflectUtil.getFieldValue("registryLifecycle");
ReflectUtil.setFieldValue("registryLifecycle", lifecycle.add(info.lifecycle()));

Map<Item, Holder.Reference<Item>> unregisteredHolders = ReflectUtil.getFieldValue("unregisteredIntrusiveHolders");
unregisteredHolders.remove(item);
});
}
}
Loading

0 comments on commit 792bfdd

Please sign in to comment.