2
0
Эх сурвалжийг харах

First creation of an NMS Handler. Not sure if relocation works yet.

Signed-off-by: Gabriel Harris-Rouquette <gabizou@me.com>
Gabriel Harris-Rouquette 6 жил өмнө
parent
commit
cb01515451

+ 106 - 0
bukkit/1_12/src/main/java/com/gmail/nossr50/bukkit/v1_12/NmsHandler.java

@@ -0,0 +1,106 @@
+package com.gmail.nossr50.bukkit.v1_12;
+
+import com.gmail.nossr50.VersionedHandler;
+import com.gmail.nossr50.mcMMO;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import net.minecraft.server.v1_12_R1.Chunk;
+import net.minecraft.server.v1_12_R1.EntityTypes;
+import net.minecraft.server.v1_12_R1.IBlockData;
+import net.minecraft.server.v1_12_R1.IBlockState;
+import net.minecraft.server.v1_12_R1.MinecraftKey;
+import net.minecraft.server.v1_12_R1.RegistryBlocks;
+import net.minecraft.server.v1_12_R1.RegistryMaterials;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.craftbukkit.v1_12_R1.CraftChunk;
+import org.bukkit.craftbukkit.v1_12_R1.block.CraftBlockState;
+import org.bukkit.craftbukkit.v1_12_R1.entity.CraftEntity;
+import org.bukkit.entity.Entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class NmsHandler extends VersionedHandler {
+    /**
+     * Static reference to the block registry. Don't really care about the fact that
+     * it is being stored as a reference here, but for imports reasons, it's smaller
+     * line length makes it optimal to read for method usages.
+     */
+    private static final RegistryBlocks<MinecraftKey, net.minecraft.server.v1_12_R1.Block> BLOCK_REGISTRY = net.minecraft.server.v1_12_R1.Block.REGISTRY;
+    /**
+     * We can keep track of block state id's by generating them on demand, i.e., when
+     * they're being requested from Blocks, or BlockDatas.
+     */
+    private static final RegistryMaterials<MinecraftKey, IBlockData> BLOCK_STATE_REGISTRY = new RegistryMaterials<>();
+
+    NmsHandler(mcMMO plugin) {
+        super(plugin);
+    }
+
+    @Override
+    public String getIdFor(Block block) {
+        // We have to get the underlying nms block by the block, which might as well just be the type id.
+        final Chunk chunk = ((CraftChunk) block.getChunk()).getHandle();
+        // Get the block state from the underlying chunk (stored by reference in CraftBlock)
+        final IBlockData blockState = chunk.a(block.getX(), block.getY(), block.getZ());
+        // Sadly, Mojang doesn't store the string id onto blocks, states, or any of their types, they just call the registry.
+        final MinecraftKey key = BLOCK_REGISTRY.b(blockState.getBlock());
+        return key.toString();
+    }
+
+    @Override
+    public String getIdFor(Entity entity) {
+        // Every entity knows it's "type". Here, we just use the right method getter to get the EntityTypes instance for that entity
+        final net.minecraft.server.v1_12_R1.Entity nmsEntity = ((CraftEntity) entity).getHandle();
+        // And then... well. we get the string id from the registry, based on the entity class to id mapping in EntityTypes.
+        final MinecraftKey key = EntityTypes.a(nmsEntity);
+        // If the key is null, well, we've got bigger problems...
+        return key == null ? "minecraft:slime" : key.toString();
+    }
+
+    @SuppressWarnings("Duplicates")
+    @Override
+    public String getIdFor(BlockState block) {
+        // Since we don't really want to trust what "BlockState" gives us, and the API doesn't give us anything but
+        // what the API wants to give us, we have to dig into internals to get the true BlockState representation
+        final CraftBlockState craftState = (CraftBlockState) block;
+        // Because CraftBlock also stores the chunk reference, we can short cut in to use the chunk, instead of pinging
+        // the chunk map on WorldServer
+        final CraftChunk craftChunk = (CraftChunk) craftState.getChunk();
+        // Then query for the block state from the chunk.
+        final IBlockData nmsState = craftChunk.getHandle().a(block.getX(), block.getY(), block.getZ());
+        // And then we're gucci
+        final net.minecraft.server.v1_12_R1.Block nmsBlock = nmsState.getBlock();
+        final MinecraftKey blockKey = BLOCK_REGISTRY.b(nmsBlock);
+        // Now we can check if our blockstate registry actually has the block state.
+        final MinecraftKey stateKey = BLOCK_STATE_REGISTRY.b(nmsState);
+        if (stateKey != null) { // If the state has been registered by the handler, then by all means.
+            return stateKey.toString();
+        }
+        // If not, well, it needs to have a key generated and registered.
+        final String nameSpace = blockKey.getKey();
+        StringBuilder builder = new StringBuilder();
+        builder.append(nameSpace); // We only want to get the block id, not the domain id, since that's going to be appended later
+
+        // Get the full Property -> Value mapping for the block state
+        final ImmutableMap<IBlockState<?>, Comparable<?>> properties = nmsState.t();
+        if (!properties.isEmpty()) {
+            builder.append('[');
+            Joiner joiner = Joiner.on(',');
+            List<String> propertyValues = new ArrayList<>();
+            // Yadadadada, go through all property entries and add each as a string for the "propertyName=value" (like "variant=oak")
+            for (Map.Entry<IBlockState<?>, Comparable<?>> entry : properties.entrySet()) {
+                // a() gets the inputted "name" for the state, the value, well, that gets the value, which is always toStringable.
+                propertyValues.add(entry.getKey().a() + "=" + entry.getValue());
+            }
+            builder.append(joiner.join(propertyValues));
+            builder.append(']');
+        }
+        // Now we can make the MinecraftKey...
+        final MinecraftKey newKey = new MinecraftKey(builder.toString());
+        BLOCK_STATE_REGISTRY.a(newKey, nmsState);
+        return newKey.toString();
+    }
+}

+ 101 - 0
bukkit/1_13/src/main/java/com/gmail/nossr50/bukkit/v1_13/NmsHandler.java

@@ -0,0 +1,101 @@
+package com.gmail.nossr50.bukkit.v1_13;
+
+import com.gmail.nossr50.VersionedHandler;
+import com.gmail.nossr50.mcMMO;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import net.minecraft.server.v1_13_R2.EntityTypes;
+import net.minecraft.server.v1_13_R2.IBlockData;
+import net.minecraft.server.v1_13_R2.IBlockState;
+import net.minecraft.server.v1_13_R2.IRegistry;
+import net.minecraft.server.v1_13_R2.MinecraftKey;
+import net.minecraft.server.v1_13_R2.RegistryMaterials;
+import net.minecraft.server.v1_13_R2.WorldServer;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlock;
+import org.bukkit.craftbukkit.v1_13_R2.block.CraftBlockState;
+import org.bukkit.craftbukkit.v1_13_R2.entity.CraftEntity;
+import org.bukkit.entity.Entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+public class NmsHandler extends VersionedHandler {
+
+    private static final IRegistry<net.minecraft.server.v1_13_R2.Block> BLOCK_REGISTRY = IRegistry.BLOCK;
+    private static final IRegistry<EntityTypes<?>> ENTITY_REGISTRY = IRegistry.ENTITY_TYPE;
+    /**
+     * We use {@link RegistryMaterials} because we don't want to default to another block state,
+     * if a {@link IBlockData} is not registered, we need to generate an ID and register that key to
+     * that {@link IBlockData}. By default, this should be populated during plugin startup by
+     * calling some init method, but that will be determined later.
+     */
+    private static final IRegistry<IBlockData> BLOCK_STATE_REGISTRY = new RegistryMaterials<>();
+
+    NmsHandler(mcMMO plugin) {
+        super(plugin);
+    }
+
+    @Override
+    public String getIdFor(Block block) {
+        // We have to get the underlying nms block by the block, which might as well just be the type id.
+        final WorldServer world = ((CraftBlock) block).getCraftWorld().getHandle();
+        // The registry.c(T) will return MinecraftKey, and the toString() returns the "$mod:$name", so "minecraft:stone"
+        final IBlockData blockState = world.getType(((CraftBlock) block).getPosition());
+        // Sadly, Mojang doesn't store the string id onto blocks, states, or any of their types, they just call the registry.
+        final MinecraftKey key = BLOCK_REGISTRY.getKey(blockState.getBlock());
+        // Sometimes, there's a rare case with mods where the key is going to be null, but should never happen in bukkit/spigot.
+        return key == null ? "minecraft:air" : key.toString();
+    }
+
+    @Override
+    public String getIdFor(Entity entity) {
+        // Every entity knows it's "type". Here, we just use the right method getter to get the EntityTypes instance for that entity
+        final EntityTypes<?> entityType = ((CraftEntity) entity).getHandle().P();
+        // And then... well. we get the string id from the registry!
+        final MinecraftKey key = ENTITY_REGISTRY.getKey(entityType);
+        // If the key is null, well, we've got bigger problems...
+        return key == null ? "minecraft:slime" : key.toString();
+    }
+
+    @SuppressWarnings("Duplicates")
+    @Override
+    public String getIdFor(BlockState block) {
+        // Much like #getIdFor(Block) except here we have the "state" by numerical id. So.. we have to grab it from
+        // the world.
+        final CraftBlockState craftState = (CraftBlockState) block;
+        final IBlockData nmsState = craftState.getHandle();
+        final net.minecraft.server.v1_13_R2.Block nmsBlock = nmsState.getBlock();
+        final MinecraftKey blockKey = BLOCK_REGISTRY.getKey(nmsBlock);
+        // Now we can check if our blockstate registry actually has the block state.
+        final MinecraftKey stateKey = BLOCK_STATE_REGISTRY.getKey(nmsState);
+        if (stateKey != null) { // If the state has been registered by the handler, then by all means.
+            return stateKey.toString();
+        }
+        // If not, well, it needs to have a key generated and registered.
+        final String nameSpace = blockKey.getKey();
+        StringBuilder builder = new StringBuilder();
+        builder.append(nameSpace); // We only want to get the block id, not the domain id, since that's going to be appended later
+
+        // Get the full Property -> Value mapping for the block state
+        final ImmutableMap<IBlockState<?>, Comparable<?>> properties = nmsState.getStateMap();
+        if (!properties.isEmpty()) {
+            builder.append('[');
+            Joiner joiner = Joiner.on(',');
+            List<String> propertyValues = new ArrayList<>();
+            // Yadadadada, go through all property entries and add each as a string for the "propertyName=value" (like "variant=oak")
+            for (Map.Entry<IBlockState<?>, Comparable<?>> entry : properties.entrySet()) {
+                // a() gets the inputted "name" for the state, the value, well, that gets the value, which is always toStringable.
+                propertyValues.add(entry.getKey().a() + "=" + entry.getValue());
+            }
+            builder.append(joiner.join(propertyValues));
+            builder.append(']');
+        }
+        // Now we can make the MinecraftKey...
+        final MinecraftKey newKey = new MinecraftKey(builder.toString());
+        BLOCK_STATE_REGISTRY.a(newKey, nmsState);
+        return newKey.toString();
+    }
+}

+ 93 - 0
bukkit/1_8_8/src/main/java/com/gmail/nossr50/bukkit/v1_8/NmsHandler.java

@@ -0,0 +1,93 @@
+package com.gmail.nossr50.bukkit.v1_8;
+
+import com.gmail.nossr50.VersionedHandler;
+import com.gmail.nossr50.mcMMO;
+import com.google.common.base.Joiner;
+import com.google.common.collect.ImmutableMap;
+import net.minecraft.server.v1_8_R3.Blocks;
+import net.minecraft.server.v1_8_R3.EntityTypes;
+import net.minecraft.server.v1_8_R3.IBlockData;
+import net.minecraft.server.v1_8_R3.IBlockState;
+import net.minecraft.server.v1_8_R3.MinecraftKey;
+import net.minecraft.server.v1_8_R3.RegistryBlocks;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.craftbukkit.v1_8_R3.entity.CraftEntity;
+import org.bukkit.craftbukkit.v1_8_R3.util.CraftMagicNumbers;
+import org.bukkit.entity.Entity;
+
+import java.util.ArrayList;
+import java.util.List;
+import java.util.Map;
+
+@SuppressWarnings({"unused", "Duplicates"}) // We use reflection to load this handler on 1.8 versions
+public class NmsHandler extends VersionedHandler {
+
+    /**
+     * Static reference to the block registry. Don't really care about the fact that
+     * it is being stored as a reference here, but for imports reasons, it's smaller
+     * line length makes it optimal to read for method usages.
+     */
+    private static final RegistryBlocks<MinecraftKey, net.minecraft.server.v1_8_R3.Block> BLOCK_REGISTRY = net.minecraft.server.v1_8_R3.Block.REGISTRY;
+    /**
+     * We can keep track of block state id's by generating them on demand, i.e., when
+     * they're being requested from Blocks, or BlockDatas.
+     */
+    private static final RegistryBlocks<MinecraftKey, IBlockData> BLOCK_STATE_REGISTRY = new RegistryBlocks<>(BLOCK_REGISTRY.c(Blocks.AIR)); // Default to AIR
+
+    NmsHandler(mcMMO plugin) {
+        super(plugin);
+    }
+
+    @Override
+    public String getIdFor(Block block) {
+        // We have to get the underlying nms block by the block, which might as well just be the type id.
+        final net.minecraft.server.v1_8_R3.Block block1 = CraftMagicNumbers.getBlock(block);
+        // The registry.c(T) will return MinecraftKey, and the toString() returns the "$mod:$name", so "minecraft:stone"
+        final MinecraftKey key = BLOCK_REGISTRY.c(block1);
+        return key.toString();
+    }
+
+    @Override
+    public String getIdFor(Entity entity) {
+        // EntityTypes maintains the maps of Class<? extends nms.Entity> to String for id's and to numerical id numbers.
+        // We of course are using the method that gets us the String id of the entity, such as "minecraft:creeper"
+        return EntityTypes.b(((CraftEntity) entity).getHandle());
+    }
+
+    @Override
+    public String getIdFor(BlockState block) {
+        // Much like #getIdFor(Block) except here we have the "state" by numerical id. So.. we have to grab it from
+        // the world.
+        final net.minecraft.server.v1_8_R3.Block nmsBlock = net.minecraft.server.v1_8_R3.Block.REGISTRY.a(block.getTypeId());
+        final MinecraftKey blockKey = net.minecraft.server.v1_8_R3.Block.REGISTRY.c(nmsBlock);
+        final IBlockData blockState = nmsBlock.fromLegacyData(block.getRawData());
+        // Now we can check if our blockstate registry actually has the block state.
+        final MinecraftKey stateKey = BLOCK_STATE_REGISTRY.c(blockState);
+        if (stateKey != null) { // If the state has been registered by the handler, then by all means.
+            return stateKey.toString();
+        }
+        // If not, well, it needs to have a key generated and registered.
+        final String nameSpace = blockKey.a();
+        StringBuilder builder = new StringBuilder();
+        builder.append(blockKey.a()); // We only want to get the block id, not the domain id, since that's going to be appended later
+
+        // Get the full Property -> Value mapping for the block state
+        final ImmutableMap<IBlockState, Comparable> properties = blockState.b();
+        if (!properties.isEmpty()) {
+            builder.append('[');
+            Joiner joiner = Joiner.on(',');
+            List<String> propertyValues = new ArrayList<>();
+            for (Map.Entry<IBlockState, Comparable> entry : properties.entrySet()) {
+                // a() gets the inputted "name" for the state, the value, well, that gets the value, which is always toStringable.
+                propertyValues.add(entry.getKey().a() + "=" + entry.getValue());
+            }
+            builder.append(joiner.join(propertyValues));
+            builder.append(']');
+        }
+        // Now we can make the MinecraftKey...
+        final MinecraftKey newKey = new MinecraftKey(builder.toString());
+        BLOCK_STATE_REGISTRY.a(newKey, blockState);
+        return newKey.toString();
+    }
+}

+ 4 - 0
bukkit/build.gradle.kts

@@ -11,8 +11,12 @@ allprojects {
         implementation(Bukkit.bstats) // Bukkit bstats
     }
 
+    // TODO dunno if this works yet... project needs to compile.
     val shadowJar by tasks.getting(ShadowJar::class) {
         relocate(Shadow.Origin.bstatsBukkit, Shadow.Target.bstatsBukkit)
+        relocate(Deps.Groups.nossr, "${Deps.Groups.nossr}.bukkit") {
+            exclude("${Deps.Groups.nossr}.core")
+        }
     }
 }
 

+ 74 - 0
bukkit/src/main/java/com/gmail/nossr50/VersionedHandler.java

@@ -0,0 +1,74 @@
+package com.gmail.nossr50;
+
+import com.sk89q.worldedit.extension.platform.NoCapablePlatformException;
+import org.bukkit.block.Block;
+import org.bukkit.block.BlockState;
+import org.bukkit.entity.Entity;
+
+public abstract class VersionedHandler {
+    private static VersionedHandler instance;
+
+    private final mcMMO plugin;
+
+    protected VersionedHandler(mcMMO plugin) {
+        this.plugin = plugin;
+    }
+
+    /**
+     * Gets the string value id of the BlockType, note that this is not the
+     * blockstate.
+     *
+     * Examples include: "minecraft:stone", "minecraft:chest", "thaumcraft:log2"
+     * BlockStates are more specific like "minecraft:log[variant=oak,axis=x]"
+     *
+     * This should be casting down and retrieving the id from the block registry maintained by vanilla.
+     *
+     * @param block The block instance (holds byte/numerical id or sometimes block state in newer versions)
+     * @return The string id of the block type
+     */
+    public abstract String getIdFor(Block block);
+
+    /**
+     * Gets the string value id of the Entity, much like blocks, this is not
+     * the full string representation of the entity, just the string id of the
+     * TYPE.
+     *
+     * Examples include: "minecraft:creeeper", "minecraft:sheep", "thaumcraft:wisp"
+     *
+     * @param entity The entity instance
+     * @return The string id of the entity's registered type.
+     */
+    public abstract String getIdFor(Entity entity);
+
+    // Technically can be TileEntity snapshot references as well.
+    public abstract String getIdFor(BlockState block);
+
+    /**
+     * Gets the {@link VersionedHandler} instance for this running platform.
+     * Note that all the handler does is perform various operations necessitated
+     * by either a lack of, or bridging an implementation of some API/core aspects
+     * that are not available through Bukkit API (like getting BlockType id's, or
+     * BlockState id's).
+     *
+     * @param plugin The mcmmo plugin
+     * @return The version handler instance
+     */
+    public VersionedHandler getInstance(mcMMO plugin) {
+        if (instance == null) {
+            final String serverPackage = mcMMO.p.getServer().getClass().getPackage().getName();
+            final String serverVersion = serverPackage.substring(serverPackage.lastIndexOf(".") + 1);
+            try {
+                final Class<?> clazz = Class.forName("com.gmail.nossr50.bukkit." + serverVersion + ".NmsHandler");
+                if (VersionedHandler.class.isAssignableFrom(clazz)) {
+                    instance = (VersionedHandler) clazz.getConstructor(mcMMO.class).newInstance(plugin);
+                }
+            } catch (Exception e) {
+                e.printStackTrace();
+                throw new NoCapablePlatformException("Could not discover a valid mcMMO VersionedHandler for version:" + serverVersion);
+            }
+        }
+        return instance;
+    }
+
+
+}

+ 1 - 1
bukkit/src/main/java/com/gmail/nossr50/listeners/EntityListener.java

@@ -1,6 +1,6 @@
 package com.gmail.nossr50.listeners;
 
-import com.gmail.nossr50.config.experience.ExperienceConfig;
+import com.gmail.nossr50.core.config.experience.ExperienceConfig;
 import com.gmail.nossr50.core.config.AdvancedConfig;
 import com.gmail.nossr50.core.config.MainConfig;
 import com.gmail.nossr50.core.config.WorldBlacklist;

+ 0 - 5
bukkit/src/nms/java/com/gmail/nossr50/InternalHandler.java

@@ -1,5 +0,0 @@
-package com.gmail.nossr50;
-
-public class InternalHandler {
-
-}

+ 7 - 0
sponge/build.gradle.kts

@@ -1,3 +1,4 @@
+import com.github.jengelman.gradle.plugins.shadow.tasks.ShadowJar
 import Config.Libs.Sponge as Sponge
 
 plugins {
@@ -18,6 +19,12 @@ allprojects {
     dependencies {
         compile(Projects.core!!)
     }
+    // TODO dunno if this works yet... project needs to compile.
+    val shadowJar by tasks.getting(ShadowJar::class) {
+        relocate(Deps.Groups.nossr, "${Deps.Groups.nossr}.sponge") {
+            exclude("${Deps.Groups.nossr}.core")
+        }
+    }
 }
 
 subprojects {