diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftSpawnCategoryMixin.java b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftSpawnCategoryMixin.java new file mode 100644 index 00000000..bfd09ca3 --- /dev/null +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mixin/bukkit/CraftSpawnCategoryMixin.java @@ -0,0 +1,33 @@ +package io.izzel.arclight.common.mixin.bukkit; + +import net.minecraft.world.entity.MobCategory; +import org.bukkit.craftbukkit.v.util.CraftSpawnCategory; +import org.bukkit.entity.SpawnCategory; +import org.spongepowered.asm.mixin.Mixin; +import org.spongepowered.asm.mixin.Overwrite; +import org.spongepowered.asm.mixin.injection.At; +import org.spongepowered.asm.mixin.injection.Inject; +import org.spongepowered.asm.mixin.injection.callback.CallbackInfoReturnable; + +@Mixin(value = CraftSpawnCategory.class, remap = false) +public class CraftSpawnCategoryMixin { + + /** + * @author IzzelAliz + * @reason + */ + @Overwrite + public static boolean isValidForLimits(SpawnCategory spawnCategory) { + return spawnCategory != null && spawnCategory.ordinal() < SpawnCategory.MISC.ordinal(); + } + + @Inject(method = "toBukkit", cancellable = true, at = @At(value = "NEW", target = "java/lang/UnsupportedOperationException")) + private static void arclight$modToBukkit(MobCategory mobCategory, CallbackInfoReturnable cir) { + cir.setReturnValue(SpawnCategory.valueOf(mobCategory.name())); + } + + @Inject(method = "toNMS", cancellable = true, at = @At(value = "NEW", target = "java/lang/UnsupportedOperationException")) + private static void arclight$bukkitToMod(SpawnCategory spawnCategory, CallbackInfoReturnable cir) { + cir.setReturnValue(MobCategory.valueOf(spawnCategory.name())); + } +} diff --git a/arclight-common/src/main/java/io/izzel/arclight/common/mod/server/BukkitRegistry.java b/arclight-common/src/main/java/io/izzel/arclight/common/mod/server/BukkitRegistry.java index 709536fe..286f9217 100644 --- a/arclight-common/src/main/java/io/izzel/arclight/common/mod/server/BukkitRegistry.java +++ b/arclight-common/src/main/java/io/izzel/arclight/common/mod/server/BukkitRegistry.java @@ -23,6 +23,7 @@ import net.minecraft.stats.StatType; import net.minecraft.stats.Stats; import net.minecraft.world.effect.MobEffect; import net.minecraft.world.effect.MobEffectInstance; +import net.minecraft.world.entity.MobCategory; import net.minecraft.world.entity.decoration.Motive; import net.minecraft.world.entity.npc.VillagerProfession; import net.minecraft.world.item.CreativeModeTab; @@ -48,9 +49,11 @@ import org.bukkit.craftbukkit.v.inventory.CraftCreativeCategory; import org.bukkit.craftbukkit.v.potion.CraftPotionUtil; import org.bukkit.craftbukkit.v.util.CraftMagicNumbers; import org.bukkit.craftbukkit.v.util.CraftNamespacedKey; +import org.bukkit.craftbukkit.v.util.CraftSpawnCategory; import org.bukkit.enchantments.Enchantment; import org.bukkit.entity.Entity; import org.bukkit.entity.EntityType; +import org.bukkit.entity.SpawnCategory; import org.bukkit.entity.Villager; import org.bukkit.inventory.CreativeCategory; import org.bukkit.potion.PotionEffectType; @@ -100,6 +103,23 @@ public class BukkitRegistry { loadArts(); loadStats(); loadCreativeTab(); + loadSpawnCategory(); + } + + private static void loadSpawnCategory() { + var id = SpawnCategory.values().length; + var newTypes = new ArrayList(); + for (var category : MobCategory.values()) { + try { + CraftSpawnCategory.toBukkit(category); + } catch (Exception e) { + var name = category.name(); + var spawnCategory = EnumHelper.makeEnum(SpawnCategory.class, name, id++, List.of(), List.of()); + newTypes.add(spawnCategory); + ArclightMod.LOGGER.debug("Registered {} as spawn category {}", name, spawnCategory); + } + } + EnumHelper.addEnums(SpawnCategory.class, newTypes); } private static void loadCreativeTab() { diff --git a/arclight-common/src/main/resources/mixins.arclight.bukkit.json b/arclight-common/src/main/resources/mixins.arclight.bukkit.json index 0cc19038..91307403 100644 --- a/arclight-common/src/main/resources/mixins.arclight.bukkit.json +++ b/arclight-common/src/main/resources/mixins.arclight.bukkit.json @@ -34,6 +34,7 @@ "CraftRegionAccessorMixin", "CraftSchedulerMixin", "CraftServerMixin", + "CraftSpawnCategoryMixin", "CraftVillagerMixin", "CraftWorldMixin", "EntityTypeMixin", diff --git a/arclight-forge/src/main/java/io/izzel/arclight/boot/asm/ArclightImplementer.java b/arclight-forge/src/main/java/io/izzel/arclight/boot/asm/ArclightImplementer.java index 4d197f49..0a330dea 100644 --- a/arclight-forge/src/main/java/io/izzel/arclight/boot/asm/ArclightImplementer.java +++ b/arclight-forge/src/main/java/io/izzel/arclight/boot/asm/ArclightImplementer.java @@ -54,6 +54,7 @@ public class ArclightImplementer implements ILaunchPluginService { this.implementers.put("switch", SwitchTableFixer.INSTANCE); this.implementers.put("async", AsyncCatcher.INSTANCE); this.implementers.put("entitytype", EntityTypePatcher.INSTANCE); + this.implementers.put("enum", new EnumDefinalizer()); if (this.logger) { this.implementers.put("logger", new LoggerTransformer()); } diff --git a/arclight-forge/src/main/java/io/izzel/arclight/boot/asm/EnumDefinalizer.java b/arclight-forge/src/main/java/io/izzel/arclight/boot/asm/EnumDefinalizer.java new file mode 100644 index 00000000..056d60b6 --- /dev/null +++ b/arclight-forge/src/main/java/io/izzel/arclight/boot/asm/EnumDefinalizer.java @@ -0,0 +1,48 @@ +package io.izzel.arclight.boot.asm; + +import cpw.mods.modlauncher.serviceapi.ILaunchPluginService; +import org.objectweb.asm.Opcodes; +import org.objectweb.asm.tree.ClassNode; +import org.objectweb.asm.tree.FieldNode; + +import java.lang.reflect.Modifier; +import java.util.Set; + +public class EnumDefinalizer implements Implementer { + + private static final Set ENUM = Set.of( + "org/bukkit/Material", + "org/bukkit/potion/PotionType", + "org/bukkit/entity/EntityType", + "org/bukkit/entity/Villager$Profession", + "org/bukkit/block/Biome", + "org/bukkit/Art", + "org/bukkit/Statistic", + "org/bukkit/inventory/CreativeCategory", + "org/bukkit/entity/SpawnCategory" + ); + + @Override + public boolean processClass(ClassNode node, ILaunchPluginService.ITransformerLoader transformerLoader) { + if (ENUM.contains(node.name)) { + var find = false; + for (FieldNode field : node.fields) { + if (Modifier.isStatic(field.access) && Modifier.isFinal(field.access) + && field.name.equals("ENUM$VALUES")) { + field.access &= ~Opcodes.ACC_FINAL; + ArclightImplementer.LOGGER.debug("Definalize enum class {} values field {}", node.name, field.name); + if (find) { + throw new IllegalStateException("Duplicate static final field found for " + node.name + ": " + field.name); + } else { + find = true; + } + } + } + if (!find) { + throw new IllegalStateException("No static final field found for " + node.name); + } + return true; + } + return false; + } +}