Prevent IllegalAccessError from showing

Discussion in 'Plugin Development' started by Sorroko, Feb 26, 2012.

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

    Sorroko

    Hello all, I am accessing the Arrow collision code from within the Projectile Hit event. The code works fine but it gives an ugly error saying it is Illegal. Is there any way to prevent this. Here is the full error:
    Code:
    16:34:36 [WARNING] Could not properly handle event BLOCK_PHYSICS:
    java.lang.IllegalAccessError: Synchronized code got accessed from another thread: me.ryan7745.CombatPlus.CombatListener$2
        at org.bukkit.event.Listener.onBlockPhysics(Listener:0)
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
        at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
        at java.lang.reflect.Method.invoke(Method.java:597)
        at org.bukkit.plugin.java.JavaPluginLoader$103.execute(JavaPluginLoader.java:1024)
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:61)
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:460)
        at net.minecraft.server.World.k(World.java:522)
        at net.minecraft.server.World.applyPhysics(World.java:507)
        at net.minecraft.server.World.update(World.java:471)
        at net.minecraft.server.World.setTypeId(World.java:443)
        at org.bukkit.craftbukkit.block.CraftBlock.setTypeId(CraftBlock.java:88)
        at org.bukkit.craftbukkit.block.CraftBlock.setType(CraftBlock.java:84)
        at me.ryan7745.CombatPlus.CombatListener$2.run(CombatListener.java:180)
        at org.bukkit.craftbukkit.scheduler.CraftWorker.run(CraftWorker.java:34)
    16:34:36 [INFO] This error is logged only once: it could have occurred multiple times by now.
    
     
  2. Offline

    billofbong

    The code would be helpful...
     
  3. Offline

    Sorroko

    Here it is, its quite alot for just setting a block on fire :/
    Code:
    @EventHandler
        public void ProjectileHit(ProjectileHitEvent event){
            Entity e = event.getEntity();
            if(e instanceof Arrow){
                final Arrow a = (Arrow) e;
                if(a.getFireTicks() > 0){
                    plugin.getServer().getScheduler().scheduleAsyncDelayedTask(plugin, new Runnable() {
     
                        @Override
                        public void run() {
                            World world = a.getWorld();
     
                            net.minecraft.server.EntityArrow entityArrow = ((CraftArrow)a).getHandle();
                         
                            Field fieldX = null;
                            Field fieldY = null;
                            Field fieldZ = null;
                            try {
                                fieldX = net.minecraft.server.EntityArrow.class.getDeclaredField("e");
                                fieldY = net.minecraft.server.EntityArrow.class.getDeclaredField("f");
                                fieldZ = net.minecraft.server.EntityArrow.class.getDeclaredField("g");
                            } catch (SecurityException e) {
                                e.printStackTrace();
                            } catch (NoSuchFieldException e) {
                                e.printStackTrace();
                            }
     
                            fieldX.setAccessible(true);
                            fieldY.setAccessible(true);
                            fieldZ.setAccessible(true);
     
                            int x = 0;
                            int y = 0;
                            int z = 0;
                            try {
                                x = fieldX.getInt(entityArrow);
                                y = fieldY.getInt(entityArrow);
                                z = fieldZ.getInt(entityArrow);
                            } catch (IllegalArgumentException e) {
                                e.printStackTrace();
                            } catch (IllegalAccessException e) {
                                e.printStackTrace();
                            }
     
                            Block block = world.getBlockAt(x, y, z);
                            Block rblock = block.getRelative(BlockFace.UP);
                            if(rblock.isEmpty() && !(rblock.isLiquid())){
                                rblock.setType(Material.FIRE);
                            }
                         
                        }
                    });
                }
            }
        }
    Note: The code has to be in a delayed task otherwise it returns -1 for coords

    Anyone?

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: May 24, 2016
  4. Make your delayed task sync and not async, problem solved.

    What you are doing right now is like the worst thing you can possibly do from a separate thread (async task): Using Reflection hooks on a class that is heavily-used by the main thread!

    I just recently explained the concurrency problem, look here: http://forums.bukkit.org/posts/979109/
    There is also no reason to use an async task, all you want is a 1 tick delay, and you get exactly that with a delayed sync task without a delay!
     
  5. Offline

    Sorroko

    Ah yes, thanks for that. Should I avoid using sync in future, on a longer delay?
     
  6. Not exactly. You should use sync tasks in almost every case. There are only very few cases when a separate/async thread would be an advantage, for example:
    • performing an operation that takes very long, like sending an HTTP requests, huge interactions with a database or enormous operations like rendering something
    • having something constantly running/waiting in the background that cannot be delayed with the scheduler (repeating task). A ServerSocket would come to my mind as an example, waiting for connecting clients.
    But you can never interact with the minecraft server / bukkit, so it needs to be avoided where possible. The only world-related bukkit method that can actually be called from another thread is world.getTypeIdAt(x, y, z).
     
Thread Status:
Not open for further replies.

Share This Page