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.
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.
Yup I noticed. Craftbukkit encapsulates net.minecraft, nothing 'peeks through' the code. Again, I end up dead in my tracks. (pun intended)
You can get the worldserver with Code:java ((CraftWorld)world).getHandle() To swap an entity with yours, synchronize all fields, delete the old one and add yours with nms.World.addEntity(entity);
You're a lifesaver. 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...
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.
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.
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....
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); } } } }
I can't see a problem either, and now it just freezes. Sigh. Obviously I am doing something wrong here. 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. 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.
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==============================
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.
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?
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.
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.