Need help working with 'native' code

Discussion in 'Plugin Development' started by bergerkiller, Aug 9, 2011.

Thread Status:
Not open for further replies.
  1. Offline

    bergerkiller

    I tried fixing my Minecart collision issue in the onCollision event, this was a complete failure no matter what I tried. Could someone guide me of how I can replace the standard Entity with my custom Entity?

    Currently fixing this part for only the carts in my group:
    Code:
                    for(int l1 = 0; l1 < list.size(); l1++)
                    {
                        Entity entity = (Entity)list.get(l1);
                        if(entity != passenger && entity.d_() && (entity instanceof EntityMinecart))
                            entity.collide(this);
                    }
    This is called in the native EntityMinecart code, and as you see, the entity collide is called with the current instance. This means I need to replace the Entity collide routine with my own. Now, since Minecarts implement/extends the Entity, I can override the same method for minecarts:
    Code:
    package com.bergerkiller.bukkit.tc;
    
    import org.bukkit.entity.Minecart;
    
    import net.minecraft.server.Entity;
    import net.minecraft.server.World;
    import net.minecraft.server.EntityMinecart;
    
    public class MinecartFixer extends EntityMinecart {
    
        public MinecartFixer(World world) {
            super(world);
            // TODO Auto-generated constructor stub
        }
    
        @Override
        public void collide(Entity arg0) {
            if (arg0 instanceof EntityMinecart) {
                if (!MinecartGroup.isMember((Minecart) arg0)) { //can it cast an Entity(Minecart) to bukkit.Minecart?
                    super.collide(arg0);
                }
            } else {
                super.collide(arg0);
            }
        }
    
    }
    
    I have a few major questions:
    - How can I replace (Bukkit) Minecart entities with my custom Minecart fixer?
    - Is this direct casting from minecraft.EntityMinecart to bukkit.entity.Minecart possible?
    /- If not, how then?
    - Is what I am trying to do even possible?

    I am using CraftBukkit in combination with Bukkit.

    EDIT

    Ugh this is just great. Craftbukkit hides WorldServer from plain view, making it impossible to even construct the class...really? Then at least add the collide function to override...come on. :(
     
  2. Offline

    nisovin

    You can't cast that Entity directly to Minecart, but you should be able to do arg0.getBukkitEntity() and cast that to Minecart. However, I don't think it would be easy to replace minecart entities with your new version.
     
  3. Offline

    bergerkiller

    Yup I noticed. Craftbukkit encapsulates net.minecraft, nothing 'peeks through' the code. Again, I end up dead in my tracks. (pun intended) :(
     
  4. Offline

    Shamebot

    You can get the worldserver with
    Code:java
    1. ((CraftWorld)world).getHandle()

    To swap an entity with yours, synchronize all fields, delete the old one and add yours with
    nms.World.addEntity(entity);
     
  5. Offline

    bergerkiller

    You're a lifesaver. :p

    I feel that I am so (damn) close to getting this to work! Only one problem, I can't add the entity! I get the following error:
    At line:
    Code:
    s.addEntity(f);
    I am currently using this:
    Code:
    package com.bergerkiller.bukkit.tc;
    
    import org.bukkit.Location;
    import org.bukkit.Material;
    import org.bukkit.craftbukkit.CraftWorld;
    import org.bukkit.craftbukkit.entity.CraftMinecart;
    import org.bukkit.entity.Minecart;
    import org.bukkit.entity.PoweredMinecart;
    import org.bukkit.entity.StorageMinecart;
    
    import net.minecraft.server.Entity;
    import net.minecraft.server.World;
    import net.minecraft.server.WorldServer;
    import net.minecraft.server.EntityMinecart;
    
    public class MinecartFixer extends EntityMinecart {
    
        public MinecartFixer(World world, double d0, double d1, double d2, int i) {
            super(world, d0, d1, d2, i);
            // TODO Auto-generated constructor stub
        }
        public MinecartFixer(World world) {
            super(world);
            // TODO Auto-generated constructor stub
        }
    
        public static Minecart replace(Minecart m) {
            int type = Material.MINECART.getId();
            if (m instanceof PoweredMinecart) type = Material.POWERED_MINECART.getId();
            if (m instanceof StorageMinecart) type = Material.STORAGE_MINECART.getId();
    
            WorldServer s = ((CraftWorld) m.getWorld()).getHandle();
            Location l = m.getLocation();
            MinecartFixer f = new MinecartFixer(s, l.getX(), l.getY(), l.getZ(), type);
            f.motX = m.getVelocity().getX();
            f.motY = m.getVelocity().getY();
            f.motZ = m.getVelocity().getZ();
            //remove the old one
            m.remove();
            s.addEntity(f);
            return (Minecart) f.getBukkitEntity();
        }
    
        @Override
        public void collide(Entity arg0) {
            if (arg0 instanceof EntityMinecart) {
                if (!MinecartGroup.isMember((Minecart) arg0.getBukkitEntity())) { //can it cast an Entity(Minecart) to bukkit.Minecart?
                    super.collide(arg0);
                }
            } else {
                super.collide(arg0);
            }
        }
    
    }
    
    You know of a way to get this to work? Perhaps I need to do a forced cast, only afraid it would undo my changes to the class...
     
  6. Offline

    Crash

    Just so you know any spawned custom minecarts won't save when the server shuts down.
     
  7. Offline

    bergerkiller

    That's no problem, neither is the linking of the carts. I only have some issues getting Minecraft to recognize my custom class...

    Note: Minecart disappears and leaves a 'ghost' Minecart at the spot, other minecarts to seem to react to the invisible spot.
     
  8. Offline

    Shamebot

    They will probably be normal minecarts.
    There are probably 2 methods for loading/saving he could override to implement his own persistence. Or he just saves them from the HashMap he has.
     
  9. Offline

    bergerkiller

    Again, saving is no problem, the groups are not stored for simplicities sake. All I need to know is how to add an extended class version to Minecraft. I can't see why Minecraft is being whiny about it, since all previous functions and constructors are there....
     
  10. Offline

    Shamebot

    Yeah, you posted that will I typed.
    So it doesn't work?
     
  11. Offline

    Crash

    That's interesting because I tried it myself and it worked fine. (Although not doing it the way you did)

    Code:
    class CustomMinecart extends net.minecraft.server.EntityMinecart {
        
        public CustomMinecart(World world){
            
            super(world);
            
        }
        
        @Override
        public void collide(Entity e){
            
            //...
            
        }
        
    }
    
    class PListener extends PlayerListener {
        
        @Override
        public void onPlayerInteract(PlayerInteractEvent event){
            
            if(event.getAction() == Action.RIGHT_CLICK_BLOCK){
                
                Block b = event.getClickedBlock();
                
                ItemStack item = event.getItem();
                
                if(item == null)
                    return;
                
                if(item.getType() != Material.MINECART)
                    return;
                
                if(b.getType() == Material.RAILS || b.getType() == Material.POWERED_RAIL || b.getType() == Material.DETECTOR_RAIL){
                    
                    World world = ((CraftWorld)b.getWorld()).getHandle();
                    
                    CustomMinecart minecart = new CustomMinecart(world);
                    minecart.setLocation(b.getX() + 0.5, b.getY(), b.getZ() + 0.5, 0, 0);
                    world.addEntity(minecart);
                    if(item.getAmount() == 1)
                        event.getPlayer().setItemInHand(null);
                    else
                        item.setAmount(item.getAmount() - 1);
                    event.setCancelled(true);
                    
                }
                
            }
            
        }
        
    }
     
  12. YOUR BACK! xD
     
  13. Offline

    bergerkiller

    I can't see a problem either, and now it just freezes. Sigh. Obviously I am doing something wrong here. :p
    I did see I was using WorldServer instead of World. I changed that now.

    EDIT

    Ow I see what is going on. It is *kinda* linking till infinity due to some wrong placement of the replace call. Time to move it around a bit.
    EDIIIT

    OOOOOOOW shit. [creeper]
    Ok that was the most explosive spawn bug I've ever seen. Minecarts linked aaand hell broke loose. Hundreds upon Hundreds of Minecarts getting spawned. I'll have to seriously look at this. I'll try to do it differently for now, hopefully itll work out. Thanks for the help so far. :)

    EDIT

    Awesome! I cancelled all collision events and can now literally walk through minecarts. :)

    EDIT2

    It cancelled all events...except the one between other minecarts. At least I know this is possible, if it requires a total physics rewrite I don't care anymore. :D

    I DID IT!!! ;)

    You have no idea what happened. I had to look through all code, and this is what was happening:
    Downside: if Craftbukkit/notch adds updates to this function I will have to update my plugin, too. But ow well. :)

    Code:
                List list = this.world.getEntities(this, this.boundingBox.a(d0, d1, d2));
                
                //TO IGNORE COLLISIONS!
                list.clear();
    
                for (int i = 0; i < list.size(); ++i) {
                    d1 = ((AxisAlignedBB) list.get(i)).b(this.boundingBox, d1);
                }
    
                this.boundingBox.d(0.0D, d1, 0.0D);
                if (!this.bg && d6 != d1) {
                    d2 = 0.0D;
                    d1 = 0.0D;
                    d0 = 0.0D;
                }
    
                boolean flag1 = this.onGround || d6 != d1 && d6 < 0.0D;
    
                int j;
    
                for (j = 0; j < list.size(); ++j) {
                    d0 = ((AxisAlignedBB) list.get(j)).a(this.boundingBox, d0);
                }
    I see I could also change the bounding box to 0/negative size, this would probably be more persistent. I'll look into that too.

    It is all working perfectly. I only have the idea my routine is a bit heavy. Any way to make it less long/looping?
    Code:
                List list = this.world.getEntities(this, this.boundingBox.a(d0, d1, d2));
    
                //=========================TrainCarts Changes Start==============================
                int ri = 0;
                while (ri < list.size()) {
                    AxisAlignedBB a = (AxisAlignedBB) list.get(ri);
                    boolean next = true;
                    for (Entity ee : (List<Entity>) this.world.entityList) {
                        if (ee instanceof EntityMinecart && ee.boundingBox.equals(a)) {
                            next = false;
                            list.remove(ri);
                            break;
                        }
                    }
                    if (next) ri++;
                }
                //=========================TrainCarts Changes End==============================
    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 18, 2016
    Shamebot likes this.
  14. Offline

    Shamebot

    I think you are just interested in the entities around your minecart, aren't you?
    So you could either use org.bukkit.Chunk's getEntities() or use the nms.Chunk.entitySlices array of lists.
    The chunk is vertically divided in 8 parts, each part has a list in the array, slice 0 is at the bottom, slice 7 at the top.
    (at least that's what I tink from looking at the code)
    You may also want to get the entities of the chunks around, when the minecart is at a chunkborder.
     
  15. Offline

    bergerkiller

    That would require me to loop through nine chunks and all entities in them. I guess I'll stay with the global list, since this is simply a variable I can access.

    EDIT

    And you were right, it didn't save. How can I make sure my custom class gets saved as the underlying type?
     
  16. Offline

    Afforess

    Can't. As a self-proclaimed expert in replacing bukkit classes, I suggest you do 2 things. onEnable in your plugin, loop through all the minecarts and replace them. Then listen to onVehicleSpawn (or whatever the event name is) to pick up new vehicles.

    HOWEVER,

    Plugins may spawn minecarts in game, and I'm not certain this will always trigger such an event. You may want to make sure you can handle things if you get a stray notch-cart in the works.

    A SECOND WORD OF WARNING:

    After your plugin is disabled (/reload), your minecarts will likely still be lying around. HOWEVER, new instances of your plugin use a new classloader, so while instanceof MinecraftFix might return true on an entityminecart, casting will throw an exception stating that your class can not be cast. You need to check that the actual classes match, like ((CraftMinecart)minecart).getHandle().getClass().equals(MinecartFix.class) before casting. Classloader's are so much fun. ;)
     
  17. Offline

    bergerkiller

    Yeps I currently store replaced minecarts in a HashSet. The cleanup routine cleans this set up as well. On disable I remove all previously replaced carts and place the default one. And thanks for the casting example, I could use it to prevent (unneeded) replacing of carts. :)
     
  18. Offline

    MoeMix

    bergerkiller What method in EntityMinecartAbstract handles minecart gravity? I have also created a custom minecart that I can move around but it doesn't follow gravity at all. I was hoping you would know the method so I can just add it to my custom minecart class and override it.
    [​IMG]
     
  19. Offline

    Garris0n

    The thread is 3 years old and bergerkiller barely posts here anymore...
    Make your own post and people will answer it.
     
  20. Offline

    MoeMix

    I have. But I was hoping bergerkiller (a pro with minecarts) could help me out. I was unaware about his inactivity.
     
  21. Offline

    bergerkiller

    MoeMix
    Reviving a 3-year old thread...oh well. I indeed don't come here anymore but check, maybe, every 2-3 weeks to see if anything important is happening. I've got a little time right now, so I'll help ya out.

    There is a single line in the onTick function (no idea what the obfuscated name is right now, it keeps changing. BKCommonLib has translation classes (Entity Controller) for that stuff) where the following is done:
    This causes the downwards velocity to become 0.04 faster every tick. Like acceleration. The final speed is limited by 'Max Speed' which is 0.4 AFAIK. Then there are also 'resistance' values which slow the minecart down in all directions.

    Physics. A
    Physics. B
    Physics. C
     
Thread Status:
Not open for further replies.

Share This Page