TechzoneMC / SonarPet

A fork of EchoPet, updated to 1.11
https://ci.techcable.net/job/SonarPet/
GNU General Public License v3.0
19 stars 16 forks source link

Use the C pre-processor to maintain NMS sources #54

Closed Techcable closed 8 years ago

Techcable commented 8 years ago

It'd change an unmaintainable mess of duplicated code into a series of template files like this:

#include "nms.h"

import net.minecraft.server.NMS_VERSION.*;

public class NMSImpl implements INMS {

// Only needed on 1.9 or newer since spawn egg data was in item data before
#if NMS_VERSION >= 1_9_R1
    @Override
    public SpawnEggItemData createSpawnEggData(byte rawData, ItemMeta meta) {
        EntityType entityType = NMSSpawnEggItemData.getSpawnEggEntityTypeIfPresent(meta).orElse(EntityType.fromId(rawData));
        if (entityType == null) entityType = SpawnEggItemData.DEFAULT_TYPE; // 'Fix' broken configs
        return new NMSSpawnEggItemData(rawData, meta, entityType);
    }

    @Override
    public SpawnEggItemData createSpawnEggData(EntityType entityType, ItemMeta meta) {
        Preconditions.checkNotNull(entityType, "Null entity type");
        Preconditions.checkNotNull(meta, "Null item meta");
        return new NMSSpawnEggItemData(new SpawnEgg(entityType).getData(), meta, entityType); // Pretend we use metadata to make the code happy
    }

    // Only needed on 1.9 :/
    @Override
    public void mount(org.bukkit.entity.Entity bukkitRider, org.bukkit.entity.Entity bukkitVehicle) {
        Entity rider = NMS.getHandle(Objects.requireNonNull(bukkitRider, "Null rider"));
        if (bukkitVehicle == null) {
            Entity vehicle = rider.getVehicle(); // This is how you *really* get the vehicle :/
            if (rider instanceof EntityInsentientPet) {
                ((EntityInsentientPet) rider).reallyStopRiding(); // normally we block dismounting, but now we really do want to dismount
            } else {
                rider.stopRiding();
            }
            if (vehicle != null) {
                Packet packet = new PacketPlayOutMount(vehicle);
                for (EntityHuman human : rider.world.players) {
                    ((EntityPlayer) human).playerConnection.sendPacket(packet);
                }
            }
        } else {
            Preconditions.checkArgument(bukkitRider.getWorld().equals(bukkitVehicle.getWorld()), "Rider is in world %s, while vehicle is in world %s", bukkitRider.getWorld().getName(), bukkitVehicle.getWorld().getName());
            Entity vehicle = NMS.getHandle(bukkitVehicle);
            NMS.startRiding(rider, vehicle, true);
            Packet packet = new PacketPlayOutMount(vehicle);
            for (EntityHuman human : rider.world.players) {
                ((EntityPlayer) human).playerConnection.sendPacket(packet);
            }
        }
    }
#endif

    @Override
    public EntityInsentientPet spawn(IPet pet, Player owner) {
        Location l = owner.getLocation();
        PetPreSpawnEvent spawnEvent = new PetPreSpawnEvent(pet, l);
        EchoPet.getPlugin().getServer().getPluginManager().callEvent(spawnEvent);
        if (spawnEvent.isCancelled()) {
            owner.sendMessage(EchoPet.getPrefix() + ChatColor.YELLOW + "Pet spawn was cancelled externally.");
            EchoPet.getManager().removePet(pet, true);
            return null;
        }
        l = spawnEvent.getSpawnLocation();
        World mcWorld = ((CraftWorld) l.getWorld()).getHandle();
        EntityInsentientPet entityPet = (EntityInsentientPet) pet.getPetType().getNewEntityPetInstance(mcWorld, pet);

        entityPet.getEntity().spawnIn(mcWorld);
        // Modern bukkit API has setCollidablle API
        #if NMS_VERSION >= "v1_9_R2"
            entityPet.getBukkitEntity().setCollidable(false);
        #elseif NMS_VERSION == "v1_9_R1"
            // the version of craftbukkit we compile against doesn't have this method, but the version of bukkit does :/
            ((Creature) entityPet.getBukkitEntity()).setCollidable(false);
        #endif
        entityPet.setLocation(new Location(mcWorld.getWorld(), l.getX(), l.getY(), l.getZ(), l.getYaw(), l.getPitch()));
        if (!l.getChunk().isLoaded()) {
            l.getChunk().load();
        }
        if (!mcWorld.addEntity(entityPet.getEntity(), CreatureSpawnEvent.SpawnReason.CUSTOM)) {
            owner.sendMessage(EchoPet.getPrefix() + ChatColor.YELLOW + "Failed to spawn pet entity.");
            EchoPet.getManager().removePet(pet, true);
        } else {
            Particle.MAGIC_RUNES.show(l);
        }
        return entityPet;
    }
}

This single file would contain the code for all supported version in a simple maintanble manner with no code duplication. This would give a lot better support for 1.8.8, and would make updating to new versions much easier.

dmulloy2 commented 8 years ago

I'm interested to see how this works out, it could be a good alternative to using reflection with ProtocolLib