Solved How to check/clear arrow color?

Discussion in 'Spigot Plugin Development' started by WellyPL, Feb 11, 2020.

  1. Hello, I am wondering what is the proper way of getting the arrow's color or removing it.

    I want to check whether an arrow is colored and if it is, remove the color upon hitting the ground so that the particles aren't visible.

    I tried doing it this way:
    Code (Java):
        protected void handleArrowHitEventCleaning(ProjectileHitEvent event)
        {
            if(event.getEntity() instanceof AbstractArrow)
            {
                AbstractArrow arr = (AbstractArrow)(event.getEntity());
                if(arr instanceof Arrow)
                {
                    Arrow arrow = (Arrow)arr;
                    Color c = arrow.getColor();
                    if(c!=null)
                        arrow.setColor(null);
                }
            }
        }
    However, the getColor() method returns the following exception when an arrow isn't colored:
    Code (Text):
    [18:31:13] [Server thread/ERROR]: Could not pass event ProjectileHitEvent to Battlefeast v1.0
    org.bukkit.event.EventException: null
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:320) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at org.bukkit.plugin.RegisteredListener.callEvent(RegisteredListener.java:70) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at org.bukkit.plugin.SimplePluginManager.fireEvent(SimplePluginManager.java:529) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at org.bukkit.plugin.SimplePluginManager.callEvent(SimplePluginManager.java:514) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at org.bukkit.craftbukkit.v1_15_R1.event.CraftEventFactory.callProjectileHitEvent(CraftEventFactory.java:1158) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.EntityArrow.a(EntityArrow.java:276) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.EntityArrow.tick(EntityArrow.java:191) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.EntityTippedArrow.tick(EntityTippedArrow.java:92) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.WorldServer.entityJoinedWorld(WorldServer.java:626) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.World.a(World.java:718) [spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.WorldServer.doTick(WorldServer.java:395) [spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.MinecraftServer.b(MinecraftServer.java:1082) [spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.DedicatedServer.b(DedicatedServer.java:399) [spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.MinecraftServer.a(MinecraftServer.java:984) [spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at net.minecraft.server.v1_15_R1.MinecraftServer.run(MinecraftServer.java:824) [spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at java.lang.Thread.run(Unknown Source) [?:1.8.0_231]
    Caused by: java.lang.IllegalArgumentException: Extrenuous data in: -1
        at org.apache.commons.lang.Validate.isTrue(Validate.java:93) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at org.bukkit.Color.fromRGB(Color.java:147) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at org.bukkit.craftbukkit.v1_15_R1.entity.CraftTippedArrow.getColor(CraftTippedArrow.java:124) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        at me.WellyPL.Battlefeast.Items.Abstract.ArrowShootingItem.handleArrowHitEventCleaning(ArrowShootingItem.java:26) ~[?:?]
        at me.WellyPL.Battlefeast.Items.SubMachineGun.onArrowHit(SubMachineGun.java:229) ~[?:?]
        at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[?:1.8.0_231]
        at sun.reflect.NativeMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_231]
        at sun.reflect.DelegatingMethodAccessorImpl.invoke(Unknown Source) ~[?:1.8.0_231]
        at java.lang.reflect.Method.invoke(Unknown Source) ~[?:1.8.0_231]
        at org.bukkit.plugin.java.JavaPluginLoader$1.execute(JavaPluginLoader.java:316) ~[spigot-1.15.2.jar:git-Spigot-800b93f-8160e29]
        ... 15 more

    Moreover, as the argument of setColor() is @NotNull, naturally setColor(null) is wrong.

    What is the proper way to achieve the result I want then?

    Edit: The arrow is colored by setColor() method, not by adding effects to it
     
    #1 WellyPL, Feb 11, 2020
    Last edited: Feb 12, 2020
    • Agree Agree x 1
  2. Unfortunately, clearing the effects leaves an arrow with light blue particles. Any ideas?
    I'd like to add that the color was given by setColor() method.

    And what about checking whether an arrow is colored?
     
    #5 WellyPL, Feb 12, 2020
    Last edited: Feb 12, 2020
  3. Digging into the server code, it looks like there isn't really a way to clear the arrow color, only to set it. The color is stored inside the Entity's DataWatcher object, so it would need to be cleared from there. If you are okay using a little bit of NMS, you can set the Entity's DataWatcher to
    Code (Java):
    DataWatcher.a(EntityTippedArrow.class, DataWatcherRegistry.b)
    and set the hasColor field to false.

    Code (Java):
        private static final DataWatcherObject<Integer> COLOR;


        static {
            COLOR = DataWatcher.a(EntityTippedArrow.class, DataWatcherRegistry.b);
        }

        private void b(int i) {
            int j = this.getColor();
            if (j != -1 && i > 0) {
                double d0 = (double)(j >> 16 & 255) / 255.0D;
                double d1 = (double)(j >> 8 & 255) / 255.0D;
                double d2 = (double)(j >> 0 & 255) / 255.0D;

                for(int k = 0; k < i; ++k) {
                    this.world.addParticle(Particles.ENTITY_EFFECT, this.d(0.5D), this.cv(), this.g(0.5D), d0, d1, d2);
                }
            }

        }

        public void setColor(int i) {
            this.hasColor = true;
            this.datawatcher.set(COLOR, i);
        }

    The other option is to use less NMS and simply get the CraftTippedArrow run getHandle().setColor(null) (Maybe that'll work. Haha.. if using Arrow.setColor(null) doesn't work, I'm skeptical about this solution). The EntityTippedArrow checks for a value of -1 for the color. If it's -1, it doesn't spawn particles. So you could try that too. This might be the preferred method actually.

    Code (Java):
        public void setColor(Color color) {
            this.getHandle().setColor(color.asRGB());
        }

    And as a last ditch effort, you could always copy the vector of the arrow, the shooter, and any other relevant information. Then you could remove the current arrow and spawn a new one.
     
    • Like Like x 1
    • Agree Agree x 1
  4. How do you dig the code of the server?
     
  5. IntelliJ has a built in decompiler that allows you to open up dependencies as if they were just a folder in your file tree. You can poke around and see the code in the different classes. I specifically was looking at the server jar itself instead of the usual API jar.
     
  6. Thanks, Travja!
    I replaced this part of code
    Code (Java):
                if(arr instanceof Arrow)
                {
                    Arrow arrow = (Arrow)arr;
                    Color c = arrow.getColor();
                    if(c!=null)
                        arrow.setColor(null);
                }
    With this
    Code (Text):
             
                if(arr instanceof CraftTippedArrow)
                    ((CraftTippedArrow)arr).getHandle().setColor(-1);
     
    And so far it's working great! Thank you!

    Also, if one wanted to check whether an arrow is colored, this code will work, I checked it:
    Code (Text):
    if(((CraftTippedArrow)arr).getHandle().getColor()!=-1)
    {
       //...
    }
     
    • Like Like x 1
    • Winner Winner x 1
  7. Please mark this as solved so others know you're no longer looking for help.
     
    • Agree Agree x 1