Solved How to change private static final array

Discussion in 'Plugin Development' started by Bobcat00, Jan 25, 2015.

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

    Bobcat00

    org/bukkit/map/MapPalette.java has the following:
    Code:
    private static final Color[] colors = {
    new Color(0, 0, 0, 0), new Color(0, 0, 0, 0),
    new Color(0, 0, 0, 0), new Color(0, 0, 0, 0),
    c(89, 125, 39), c(109, 153, 48), c(127, 178, 56), c(67, 94, 29),
    ...
    c(79, 1, 0), c(96, 1, 0), c(112, 2, 0), c(59, 1, 0)
    }; 
    I want to change the values in the array with a plugin. Can I declare my own array, say bobcatscolors[], then somehow assign MapPallet.colors to point to my array (colors=bobcatscolors)? I know private says I'm not allowed to, but can I do it with reflection? If so, can someone point me in the right direction?
     
    Last edited: Jan 25, 2015
  2. Offline

    WinX64

    One way i just tried was to use reflection to get access to the array, like you mentioned. However, instead of creating my own Color array and setting it back, i simply modified the current one. As it is final, i can't assign a new array to the variable, but i can edit its items just fine.
     
    ReadySetPawn likes this.
  3. Offline

    567legodude

    @Bobcat00 I don't think that it can be changed at all since it is final.
    When something is declared as final, I think it means that it has to stay the way it was declared and can't be changed.
     
  4. Offline

    mythbusterma

    @Bobcat00

    Yes, it can be done with reflection. No, there is not a single reason ever that you should for any reason do this.

    Don't do it. Just define your own color palate and use it instead.
     
    Konato_K likes this.
  5. Offline

    Bobcat00

    Looks like removing the 'final' is possible by changing the modifiers: ~Modifier.FINAL

    An additional question: The array is part of a class:
    Code:
    public final class MapPalette 
    Does this make a difference? I think since the array is 'static', all instances of the class share the same array.
     
  6. Offline

    1Rogue

    A class marked "final" simply means that the class cannot be subclassed (extended by another class).

    Keep in mind that you need to conform to the class's own internal implementation of the array (which is usually undocumented as private and package-private members are not meant to be documented and interacted with, they're part of the class's contract and help with implementation).
     
  7. Offline

    mythbusterma

    @Bobcat00

    Why do you /NEED/ to do this? There is absolutely no reason you should be doing this. It can cause a lot of unintended consequences and is relatively pointless.

    Just define an array yourself and use it. Don't overwrite a field that is clearly not intended to be overwritten.
     
  8. Offline

    Bobcat00

    I need to do it because Grum changed the map palette and items are not displayed correctly. He caused a mismatch between otherwise-compatible servers and clients. i.e., old server + new client = wrong colors. You'd think that with a palette of only 140 colors (even the original Netscape had 216 colors), he could have afforded to add the colors he needed. But, no, he changed a palette that's been around forever. That's the part with unintended consequences.

    It's another plugin that's using the palette. So I'd have to rewrite and maintain that plugin and duplicate the entire Bukkit MapPalette class (which is certainly possible) instead of simply changing the palette itself to match Grum's modified palette.

    We're going to get 18 inches of snow tomorrow, so this gives me something to mess with while I'm at home.
     
  9. Offline

    mythbusterma

    @Bobcat00

    The problem is, Java isn't like C++, where you can just cast away const-ness and add it back as you please. While you CAN change the value, you should not, because the JVM expects the value to never change, ever. While the reflection libraries do support this kind of operation, on a lot of implementations of the JVM this can cause highly unpredictable results, which are, most importantly, inconsistent.

    Honestly, you probably just want to update your server.
     
  10. Offline

    Bobcat00

    With 35 years of software engineering experience, I realize this. But in this case, the worst that would happen is the colors would be wrong, and they're wrong already. (Thanks, Grum!)

    The problem is the plugin doesn't reference the palette directly. Nor does it reference the class containing the palette. The plugin calls other Bukkit classes which, in turn, call other Bukkit classes, which reference the palette. So I'd probably have to duplicate the entire org.bukkit.map package, which consists of 8 files. (Assuming I get it right.) Just to change the data values in a simple array.

    There is no update. I'd have to modify the Bukkit source.
     
    Last edited: Jan 26, 2015
  11. Offline

    1Rogue

    Arrays are mutable by definition, as long as you can access the array you can modify it.
     
  12. Offline

    mythbusterma

    That's exactly what I'd recommend.
     
  13. Offline

    Bobcat00

    .
     
    Last edited: Jan 28, 2015
  14. Offline

    Bobcat00

    OK, I got it to work. In case anyone is interested, this is what I ended up with. It uses a single 'set' method to change the palette by pointing it to my array.
    Code:
    public void onEnable()
    {
        boolean pluginLoaded = false;
        try {
            Field colorsField = MapPalette.class.getDeclaredField("colors");
            colorsField.setAccessible(true);
    
            Field modifiersField = Field.class.getDeclaredField("modifiers");
            modifiersField.setAccessible(true);
            modifiersField.setInt(colorsField, colorsField.getModifiers() & ~Modifier.FINAL);
    
            colorsField.set(null, newColors);
    
            pluginLoaded = true;
        } catch (NoSuchFieldException x) {
            x.printStackTrace();
        } catch (IllegalAccessException x) {
            x.printStackTrace();
        }
        if (pluginLoaded)
        {
            getLogger().info("Map palette changed successfully.");
        }
    } 
     
    Last edited: Jan 28, 2015
  15. Offline

    xTrollxDudex

    Can be done with Unsafe in one line but ok
     
  16. Offline

    Bobcat00

    I don't know what you mean. Can you explain, please?
     
  17. Offline

    Experminator

  18. Offline

    xTrollxDudex

  19. Offline

    Experminator

    @xTrollxDudex Sorry, i was confused with the annotation @SafeVarargs.
     
  20. Offline

    1Rogue

    mythbusterma likes this.
Thread Status:
Not open for further replies.

Share This Page