Updater 2.3- Easy, Safe, and Policy-Compliant auto-updating for your plugins [NEW!]

Discussion in 'Resources' started by Gravity, Aug 28, 2012.

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

    Gravity

    Updater - Version 2.3
    Updater is an easy-to-use but robust and fully policy-compliant plugin updating system. It provides plugin developers with the ability to both check for and download new updates straight from BukkitDev, and requires no web server setup to function.

    Download and Source:
    Updater is a single class file that you need to add to your plugin. Simply create a new class somewhere in your plugin named "Updater", and populate it with Updater's source code, which you can find by clicking the "Get Updater" link below. Then, go to the "How to use it" section to learn how adding one line of code to your plugin will implement Updater.

    Get Updater

    Features:

    • No more hassle! Never worry about configuring your Dropbox text files to the latest build's url, or forgetting to update external files again. Upload once to BukkitDev, and as soon as your file is approved clients will start downloading it, even if the approval comes at 4am and you're fast asleep.
    • Setup is as easy as copying a class and giving it your BukkitDev project slug. Updater will do the rest.
    • Ability to tag certain builds as non-update builds. For instance, on my Jenkins system every build is tagged with -DEV, so that people who are using it do not get switched to the official latest build, and can stay testing the pre-release. Simply edit the "noUpdateTag" array in the class to define what kind of builds should be left alone.
    • Don't hassle your users anymore. Server admins have enough on their hands, don't concern them with updates, because they just will /not/ update. From personal experience, I know that the only time I cared about a plugin update was when something broke. It's far too difficult to worry about a new file every day, but if you let Updater automatically install updates, your users will rejoice!
    • Be safe. EVERY file that Updater downloads has been approved by BukkitDev staff. Real humans go line-by-line through the code of each plugin that is approved on dev.bukkit.org, to verify it is free of any malicious code. Your user's shouldn't have to blindly accept your trust, you can instead show and prove to them that by using updater, you are keeping them secure.
    • Works with both .jar file and .zip file updates.
    -- Get Updater --


    How it works:

    - First, Updater connects to BukkitDev API and requests information about your project.

    - It then searches the information for the latest file, and obtains information about it like its name and version number.

    - Optionally, Updater will run a version check, comparing the newest file with the plugin's current version. NOTE: For this to work, your file titles must be named in this format: 'PluginName vVersionNumber', such as 'AntiCheat v1.0' (or simply 'v1.0', the name is not needed, but suggested). Here's a screenshot of how this should look, if done properly:
    File titles with proper version numbers (open)

    [​IMG]

    - Assuming that an update is needed, Updater will download the file from dev.bukkit.org and store it in the update folder. This is a folder defined in the bukkit.yml file where any stored jars will be switched with its currently-in-use counterpart when the system is reloaded or restarted. This means that the user does not need to worry about replacing the downloaded file with the current file; it's all done in the background.

    How to use it:

    If you are using Maven to manage your project you can use my Maven repository to get the dependency. To do this, edit your pom.xml to add the following repository:
    Code:
        <repositories>
            <repository>
                <id>gravity-repo</id>
                <url>http://repo.gravitydevelopment.net</url>
            </repository>
        </repositories>
    
    Then, add the following dependency:
    Code:
        <dependencies>
            <dependency>
                <groupId>net.gravitydevelopment.updater</groupId>
                <artifactId>updater</artifactId>
                <version>2.1</version>
            </dependency>
        </dependencies>
    
    Otherwise, you can use the traditional way and download the source code for Updater. Simply place this somewhere within your plugin's packages, and then switch over to your main class to get to work.

    As with most of my projects, I boast the fact that you only need one line of code added to your main class (the one that extends JavaPlugin) to make this work (along with my Updater class, of course), so here's what it is:

    Code:
    Updater updater = new Updater(this, id, this.getFile(), Updater.UpdateType.DEFAULT, false);
    That's it! This single line of code will literally keep the user updated for the rest of their life. Here's a breakdown of what all these values are:

    1) "this" - The plugin instance. I suggest using this in your onEnable() method, so that you can properly issue the 'this' keyword. Other methods that are called before onEnable() will not work (but anything after it, or that is called BY onEnable() does work).

    2) "id" - This is how Updater finds your project on BukkitDev. If you don't know what this is, follow the instructions on this wiki article.

    3) "this.getFile()" - The plugin's file, this is so that Updater can properly replace your plugin with the update when it is downloaded. Note that this is a protected value, and so it can only be accessed within your plugin's main class

    4) "Updater.UpdateType.DEFAULT" - This allows you to choose which type of update you would like to take place. Currently there are 3 options:
    - DEFAULT - Typically what you would want. Do an update check, and then if it's out of date download and install the latest update.
    - NO_VERSION_CHECK - In case you know you need (or want) to update, skip version checking and just download the latest file, regardless of any it's details.
    - NO_DOWNLOAD - In case you just want to do a version check. No files will be downloaded, but you still get information about the newest build on DBO, like it's version number and size.

    5) "false" - This is a value declaring whether you want Updater to announce the progress of the download, as it takes place. This is similar to what this output (to the console) will look like:
    Output (open)

    2012-08-29 16:30:56 [INFO] [AntiCheat] Enabling AntiCheat v1.3.6-DEV
    2012-08-29 16:30:57 [INFO] About to download a new update: AntiCheat v1.3.5
    2012-08-29 16:30:57 [INFO] Downloading update: 10% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 20% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 30% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 50% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 70% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 80% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 90% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Downloading update: 100% of 93738 bytes.
    2012-08-29 16:30:57 [INFO] Finished updating.

    If this option is true, and there is no update, there will be no output to the console.

    You can also see these values documented in JavaDocs here: http://gravitydevelopment.net/docs/updater/

    ------------------------------------------------------------------------------------------------------------------------------------
    NOTICE:
    As of Updater 2.0, a configuration file is created to allow server administrators to globally toggle updating for any plugin using this class. While this option does provide a convenient method for server admins to disable all Updater instances, Bukkit project submission guidelines still require that you make your plugin's Updater instance specifically toggleable with its own configuration option. This gives server administrators the opportunity to only disable the updating capabilities of one plugin in particular, should they choose to do so. You may read more about compliance with this policy here.
    ------------------------------------------------------------------------------------------------------------------------------------


    Expanding updater:

    Note: The following contains more advanced user information on controlling Updater. While Updater is very simple to use, it also gives a great deal of feedback and control to the developer if they want to use it. If you are just starting to develop plugins, it is recommended that you stop here and just use Updater as you have learned to use it so far. If you are an advanced user, you may continue on, but know that all of the following info is optional, and only necessary if you want to customize your experience.

    Now, of course you may want to know what the outcome of the process was, so you can inform the user or update some values in your plugin to reflect that it is now updated. This result can easily be obtained by using the "getResult()" call. This returns an UpdateResult that reflects what happened.​

    Code:
            Updater.UpdateResult result = updater.getResult();
            switch(result)
            {
                case SUCCESS:
                    // Success: The updater found an update, and has readied it to be loaded the next time the server restarts/reloads
                    break;
                case NO_UPDATE:
                    // No Update: The updater did not find an update, and nothing was downloaded.
                    break;
                case DISABLED:
                    // Won't Update: The updater was disabled in its configuration file.
                    break;
                case FAIL_DOWNLOAD:
                    // Download Failed: The updater found an update, but was unable to download it.
                    break;
                case FAIL_DBO:
                    // dev.bukkit.org Failed: For some reason, the updater was unable to contact DBO to download the file.
                    break;
                case FAIL_NOVERSION:
                    // No version found: When running the version check, the file on DBO did not contain the a version in the format 'vVersion' such as 'v1.0'.
                    break;
                case FAIL_BADID:
                    // Bad id: The id provided by the plugin running the updater was invalid and doesn't exist on DBO.
                    break;
                case FAIL_APIKEY:
                    // Bad API key: The user provided an invalid API key for the updater to use.
                    break;
                case UPDATE_AVAILABLE:
                  // There was an update found, but because you had the UpdateType set to NO_DOWNLOAD, it was not downloaded.
            }
    All these values, of course, are documented in easy-to-read HTML here: http://gravitydevelopment.net/docs/updater/

    You also may want to know information about the newest update. Some people prefer to have Updater run a version check ONLY (using UpdateType.NO_DOWNLOAD), then, if there is an update available, start notifying admins as they log in that there is a new version ready, with information like file size and version. An admin would then issue a command, and the developer would run Updater again but this time with UpdateType set to NO_VERSION_CHECK, thus downloading the newest build at the admin's request.

    We have a few methods available for you to use for this information. We already know that we can determine the outcome of the version check by calling getResult(), but here are some more methods you can call to get information about the newest file:

    - getLatestName() - Returns the name of the latest file you have uploaded to BukkitDev (Ex: "AntiCheat v1.5.9")
    - getLatestType() - Returns the type of the latest file you have uploaded to BukkitDev (Alpha, Beta, Release)
    - getLatestGameVersion() - Returns the compatible Game Version of the latest file you have uploaded to BukkitDev (Ex: "CB 1.6.2-R1.0")
    - getLatestFileLink() - Returns the link to the latest file you have uploaded.

    The scenario mentioned about would look something like this (pseudocode):

    Code:
    // In main class
    
    public static boolean update = false;
    public static String name = "";
    public static ReleaseType type = null;
    public static String version = "";
    public static String link = "";
    // You would want to make getter methods in your class, this is just for simplicity.
    
    public void onEnable()
    {
      Updater updater = new Updater(this, YOUR_ID_HERE, this.getFile(), Updater.UpdateType.NO_DOWNLOAD, false); // Start Updater but just do a version check
      update = updater.getResult() == Updater.UpdateResult.UPDATE_AVAILABLE; // Determine if there is an update ready for us
      name = updater.getLatestName(); // Get the latest name
      version = updater.getLatestGameVersion(); // Get the latest game version
      type = updater.getLatestType(); // Get the latest file's type
      link = updater.getLatestFileLink(); // Get the latest link
    }
    
    // In a listener class:
    
    @EventHandler
    public void onPlayerJoin(PlayerJoinEvent event)
    {
      Player player = event.getPlayer();
      if(player.hasPermission("foo.bar") && Main.update)
      {
        player.sendMessage("An update is available: " + Main.name + ", a " + Main.type + " for " + Main.version + " available at " + Main.link);
        // Will look like - An update is available: AntiCheat v1.5.9, a release for CB 1.6.2-R0.1 available at http://media.curseforge.com/XYZ
        player.sendMessage("Type /update if you would like to automatically update.");
      }
    }
    
    // And then later in a CommandExecutor class, when they type /update:
    
    Updater updater = new Updater(this, YOUR_ID_HERE, this.getFile(), Updater.UpdateType.NO_VERSION_CHECK, true); // Go straight to downloading, and announce progress to console.
    

     
    Last edited: May 6, 2016
    FisheyLP, Nathat23, Eathuis and 36 others like this.
  2. Offline

    Gravity

    On the main post. Again:
     
  3. Offline

    AnorZaken

    It's a nice piece of code, greatly saves on all the time I would need to check up on all the underlying bukkit / dbo stuff and implement it myself. Much appreciated! (And now, time to fetch the reading glasses :cool: )

    There is this one thing though that I really feel is unmotivated, namely that there is no way of asking if the worker thread is finished. So even if it is open-source = people can easily do it themselves, not all people are that good at coding (yet, hopefully they keep at it and learn more :) ), so seeing as it's really easy to implement if you know what to do I strongly feel this should be included in the "official" version.

    The reason I feel that it's strongly needed is because on very stable servers that have long up-times you will probably want to be able to let admins initiate an update check/download while the server is running.
    But as of now there are only three (four) ways to do this:
    1. The really bad way: Just do it! Main thread will lock up for possibly several seconds causing severe lag.
    2. The bad way: Initiate the update then schedule checking the update result after a predetermined amount of time has passed. This is still bad because you are just guessing at the time needed for the update to finish. There is no guarantees that it's finished and you still risk blocking the main thread.
    3. The cumbersome and wasteful way: You implement and run a separate thread just for getting the result and in your code using this thread you check if your thread has finished before trying to grab data from it. This is a lot of hassle for something so small and also uses an extra thread, which is wasteful.
    4. The right way: You make a handful of small edits to the Updater-class and implement a function that lets you ask if the Updater instance has finished it's execution.
    Thing is that people with emerging programming skills are most likely to use 1. or 2. because 3. requires a lot more know-how and 4. might be something they are hesitant to do of fear of breaking the updater code. Doing 4. is almost as easy as adding UpdateResult.THREAD_BUSY and changing the value the result field is initialized to so it isn't initialized to SUCCESS (which I found kind of odd anyway). +A few more edits: making sure the saveFile() sets result = SUCCESS when it is successful (since now it seems to lazily rely on the fact that result was initialized to this), and adding a pollResult() function that is non-blocking, i.e. doesn't wait for the thread just returns the current state of result.

    Of course I have a version ready that has this feature, but making this improvement to the intended way of using it also exposes a few other changes that, while not completely necessary, would be considered good practice or make good sense in some way:

    Being able to ask if the updater is finished inherently means that you not only want, but need to keep your updater instance around (at least until it has finished and you have taken note of this). This is if you plan on giving the user any feedback on how the update went (and you most likely do - that's good practice).
    Keeping the instance around means keeping a lot of data around that isn't needed anymore. As soon as the check/download has completed this data should be discarded. This is part of the internals of the Updater-class, the developer using it should feel safe in knowing the Updater class doesn't keep any data around if it doesn't need it anymore.

    To facilitate this I refactored the code into two inner classes: One that holds the result, and one that does all the dirty work and holds all the data needed for it to be able to do this work. So basically the Updater class itself now only holds two variables! And once the worker is done the worker instance is nullified so all unnecessary data is freed up for the GC to collect.

    I've made all these changes of course, it's not perfection, it could still be reworked a bit to reduce the complexity of the code (complexity grew a bit since I was basically coding as I went along, not planing ahead as much as I should). I also kept full backwards compatibility with the old Updater-class functions and their behavior retained, but I'm not sure backwards compatibility is a good thing with all those blocking calls, should rather be deprecated imo. So if I get around to doing a second rewrite any time soon it will have all these features and easier to read/maintain code. (It's not that bad, basically there is this one issue... but since the thought of it will keep on pestering me... I wont be able too look at the code with undiluted satisfaction... I will probably fix it within the next few days to get it of my mind!) ;)
     
  4. Offline

    Gravity

    AnorZaken - thanks for your post, that was very thoughtful and well written. I agree with you that the threading implementation could use improvement, and the changes you describe sound decent. I'd be happy to look over a pull request you submit if you plan on doing so and going over the diffs in detail. If you have any questions about compatibility or functionality feel free to PM me or hop on IRC and chat (I'm Gravity on espernet - although I'll be AFK the next few days due to travel, so PM might work better until I'm back)

    Thanks again for your input!
     
  5. Offline

    SnipsRevival

    If we switched update checkers to use the Curse API, won't some server admins be a little hesitant if the update checker directs them towards download links that aren't from BukkitDev? Not everyone is necessarily going to trust these download links as opposed to getting a link straight off your project's page on BukkitDev.
     
  6. Offline

    AnorZaken

    Gravity - I'm just glad to contribute, and thanks for your reply. I could perhaps polish up the version I mentioned in my previous post and send that as a pull request if you want. It's not that many changes and doing a diff against the current version would make perfect sense.

    However that one small issue I mentioned led to me starting a total rewrite. In short the reason was that once I removed the block-to-get-the-result shortcut from the design it became apparent that this had several implications for how you would most likely use / want to use the updater. In effect it's old behavior didn't make as much sense as it used to anymore because making it non-blocking both opened up new possibilities and highlighted some issues.

    (Edit: What I mean with the first part is that I could give you a polished version of my first edits, which is a branch, but what I'm trying to say in the second part is that I'm currently working on a fork.)

    So the idea is that with the non-blocking updater it should be easy to do some things that was not so easy before. The most prominent example would probably be: make it easy to implement commands that lets an admin/moderator check or download updates at any time they feel is convenient. For now this is usually controlled by the plugin (usually at server start), but I want to move this decision to the server admins (or rather: make it easy for the plugin maker to give this control to the server admin - if they want to). That's the goal. So what are the implications? Well giving the admin a check-command and a download-command sounds reasonable right? Well there are actually some not instantly obvious problems and changes required to make this work well...
    • Ok so you will no longer get the result immediately when you call the updater (that's the whole non-blocking thing in a nutshell), so basically you could accidentally start two downloads of the same file simultaneously. This isn't really a new problem but a problem inherited from the original code, but I think it's arguably more likely to happen with how I envision the usage pattern to change. This is thankfully easy to fix. (We can ensure that this is impossible from within the updater code with relative ease and a small memory footprint.)
    • Imagine this scenario: The admin does a check... update "some-plugin" v2.1 is found and this information is displayed to the admin. Shortly after the admin issues a download command. The plugin does a look-up, finds the info on the most recent version and downloads it. However it just so happens v2.2 was released, and is what gets downloaded. Aside from looking unprofessional it's probably not such a big deal (and very unlikely), but it actually exposes an underlying issue:
    • After the updater has done a look-up, all that information is stored so it can be read by the plugin and presented to the user. But when we want to do a download of the detected version we throw all of that information away and redo the look-up? That is a waste! Solving this problem also results in solving the above problem...
    • ...Looking for the solution to this problem we soon realize we need to split the update process from the 2 steps it consists of now: 1. look-up+version-check and 2. download, into 3 steps: look-up, version-check, download. Well this is already done internally (look-up is the function called read(), download is saveFile()), but now we need to expose this externally, in the UpdateType enum. We already have the option to skip the version-check or the download, but now we need to be able to reuse previously gathered data, aka skip the look-up step...
    • ...This causes the UpdateType enum to grow considerably, and it becomes a valid question if it might be better to simply expose 3 booleans, one for each update-step? (I'm not sure...)
    • What should the new public function signatures look like? (We can no longer do everything in the constructor.) Goal here is to make it as easy to understand and use as possible while at the same time maintaining clean internal code so it's easy for others to understand and modify the updater code. (Ease of use has higher priority though.)
    It also dawned on me that it might be beneficial to include a few static helper functions for things like notifying a player that an update exist or asking if they want to download. This could help standardize the look and style of all plugins using updater, which I believe would greatly benefit the end-user. This is just a suggestion.

    (Also playing with the thought a bit I believe it should be possible to make updater automatically notify the plugin or the player using the updater when the worker thread has finished, without running into threading issues. I'm talking about either a callback or delivering a status-report in the chat, from within the main thread.) (<- Edit: I will be doing this, the internal code complexity might increase slightly, but the ease of use for the developer will be worth it - maintaining that one-line-of-code-to-make-it-work principle from the original updater code even for things like admin commands.)

    (Developing this thought one step further it arouses the question: How much additional work would it require to enable automatic aggregation of updater results for all plugins using the updater class?)

    ...I have this nagging feeling I forgot to mention something but the post is plenty long anyway so I'll be posting it now. :rolleyes:

    (Edited a few typos...)
     
  7. Offline

    PieMan456

    Gravity
    When I use this I get an error:
    Code:
    2013-11-10 15:30:20 [SEVERE] Could not load 'plugins\ScareBat.jar' in folder 'plugins'
    org.bukkit.plugin.InvalidPluginException: java.lang.NullPointerException
        at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:182)
        at org.bukkit.plugin.SimplePluginManager.loadPlugin(SimplePluginManager.java:305)
        at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:230)
        at org.bukkit.craftbukkit.v1_6_R3.CraftServer.loadPlugins(CraftServer.java:239)
        at org.bukkit.craftbukkit.v1_6_R3.CraftServer.<init>(CraftServer.java:217)
        at net.minecraft.server.v1_6_R3.PlayerList.<init>(PlayerList.java:56)
        at net.minecraft.server.v1_6_R3.DedicatedPlayerList.<init>(SourceFile:11)
        at net.minecraft.server.v1_6_R3.DedicatedServer.init(DedicatedServer.java:107)
        at net.minecraft.server.v1_6_R3.MinecraftServer.run(MinecraftServer.java:393)
        at net.minecraft.server.v1_6_R3.ThreadServerApplication.run(SourceFile:583)
    Caused by: java.lang.NullPointerException
        at me.pieman.scarebat.Updater.<init>(Updater.java:145)
        at me.pieman.scarebat.Scarebat.<init>(Scarebat.java:20)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance0(Native Method)
        at sun.reflect.NativeConstructorAccessorImpl.newInstance(Unknown Source)
        at sun.reflect.DelegatingConstructorAccessorImpl.newInstance(Unknown Source)
        at java.lang.reflect.Constructor.newInstance(Unknown Source)
        at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:178)
        ... 9 more
     
  8. Offline

    Gravity

    That error is caused by the server not finding a folder to place plugin updates. Can you create a folder inside the plugins folder called "updates" and see if it resolves the error?
    Additionally, can you post the contents of the bukkit.yml for the server you're running this on?
     
  9. Offline

    PieMan456

    Gravity
    Wait what? Create a folder inside the plugins folder? I don't understand what you are saying.
     
  10. Offline

    Gravity

    Yeah. Bukkit uses a folder inside the plugins folder called "update" (or whatever you change it to in the bukkit.yml) to cycle in new plugin updates. Updater uses this to store jars that are downloaded, and Bukkit does the lifting in terms of removing the old files from the plugin directory and replacing them with the new ones.
     
  11. Offline

    PieMan456

    Gravity
    Ok I understand now. How would I auto generate the folder if they don't have it.
     
  12. Offline

    AnorZaken

    That's odd. Unless there is some nonsense value in the bukkit.yml the code in craftbukkit looks like this:
    Code:java
    1. public String getUpdateFolder() {
    2. return this.configuration.getString("settings.update-folder", "update");
    3. }

    i.e. it should be the folder "update" if it's not set in the config. (Which reminds me of the fact that you try-catch on creating files Gravity, but not on the mkdir, which can also throw.)

    EDIT: Ah, also it's "update" not "updates". So if creating a folder called "updates" actually solves the problem then there really is a bug somewhere else, because that's supposed to be wrong.
     
  13. Offline

    PieMan456

    AnorZaken
    Thanks for telling me how to auto-generate the foler.
    Gravity
    The folder update does not fix the problem.
     
  14. Offline

    AnorZaken

    I don't follow...? o_0 That's not what I did. I just said that it's not possible that the server doesn't know what update folder to use because it cant be undefined. If it is there is a hard coded default. That was my whole point. That code is from the bukkit server code, not something you should put in your code.
     
  15. Offline

    Gravity

    Again, I'd like the contents of the bukkit.yml so I can help diagnose the issue.
     
  16. Offline

    PieMan456

    Gravity
    Code:
    # This is the main configuration file for Bukkit.
    # As you can see, there's actually not that much to configure without any plugins.
    # For a reference for any variable inside this file, check out the bukkit wiki at
    # http://wiki.bukkit.org/Bukkit.yml
    settings:
      allow-end: true
      warn-on-overload: true
      permissions-file: permissions.yml
      update-folder: update
      ping-packet-limit: 100
      use-exact-login-location: false
      plugin-profiling: false
      connection-throttle: 4000
      query-plugins: true
      deprecated-verbose: default
      shutdown-message: Server closed
    spawn-limits:
      monsters: 70
      animals: 15
      water-animals: 5
      ambient: 15
    chunk-gc:
      period-in-ticks: 600
      load-threshold: 0
    ticks-per:
      animal-spawns: 400
      monster-spawns: 1
      autosave: 0
    auto-updater:
      enabled: true
      on-broken:
      - warn-console
      - warn-ops
      on-update:
      - warn-console
      - warn-ops
      preferred-channel: rb
      host: dl.bukkit.org
      suggest-channels: true
    database:
      username: bukkit
      isolation: SERIALIZABLE
      driver: org.sqlite.JDBC
      password: walrus
      url: jdbc:sqlite:{DIR}{NAME}.db
    
     
  17. Offline

    Gravity

    PieMan456 and you haven't changed the updater code at all from what I've provided? I can't really understand why that line would return null (unless you've provided a null plugin reference?)
     
  18. Offline

    PieMan456

    Gravity
    No I do not think I have mad a null plugin preference. Could you explain to me where I would have made that? Would I have made it in my plugin?
     
  19. Offline

    Gravity

    You would have had to pass a null value in when constructing the updater, eg. new Updater(null, ...) or using a variable that hasn't been assigned yet eg. new Updater(plugin, ...) where "plugin" hasn't been initialized yet
     
  20. Offline

    PieMan456

    Gravity
    This is what mine looks like: Updater updater = new Updater(this, 68248, this.getFile(), UpdateType.DEFAULT, true);
    I don't think I set it to null.
     
  21. Offline

    Gravity

    PieMan456 no, from that snippit it looks fine.. I'm a little baffled as to what's going on but I think you're just going to have to do some debug prints in the Updater class to see what exactly is null on line 145. I've never encountered this error and cannot reproduce it, so there's not a whole ton I can do from my end.
     
  22. Offline

    AnorZaken

    PieMan456 are you doing that in the plugins onEnable()? Or are you doing it in the class constructor or as a field initialization? I'm thinking it might happen too soon before something somewhere else (in the server code) is properly initialized.
     
  23. Offline

    PieMan456

    AnorZaken
    I am not doing it in the onEnable() it is on its own.

    Gravity
    Should I recopy the Updater class and see if that works?

    Edit:
    It didn't work :(

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jan 4, 2016
  24. Offline

    AnorZaken

    Could you be more specific please. Where is that line of code?
    (Edit: if possible try moving the assignment to the onEnable and see if that helps)
     
  25. Offline

    PieMan456

    AnorZaken
    Ok i will try it in the onEnable()

    Edit: IT WORKS!!!:):D:p

    Gravity
    How do I make it so the people that download my plugin with the Updater in it can enable the updater of disable it?

    AnorZaken
    Ok well the folder doesn't fix the problem any way so it doesn't matter.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jan 6, 2016
  26. Offline

    Gravity

    Make a configuration option that you check before starting the updater. If you need help with configuration, there's documentation on the API on our wiki. Just google "Bukkit configuration api" -- also if you refer to my link earlier there's tons of open source examples.
     
  27. Offline

    PieMan456

    Gravity
    I don't think it shows you how to check if the person who has the plugin set the config updater to true or false.
     
  28. Offline

    AnorZaken

    Gravity:
    You never asked for the pull Gravity so haven't invested time in it, however my fork called PluginUpdater is now completed (as in first working version). Grew from your original 500 lines of code to 2000 lines of code.

    First plugin to use it will be my next release (v1.2) of SoundCommands.
    Source is not included yet however - I will publish it somewhere soon (or on request).
    (I have some unfinished javadoc!)

    It is almost as easy to use as your version, but is completely non-blocking and has a host of additional optional features.
    I will not go into great length about it here, but for instance you can supply one or several CommandSenders and these will be automatically notified of how the requested update action went. Or you can supply your own Runnable instance that will be scheduled to run in the main thread once the worker thread is finished.
    ...and other advanced optional features. Everything non-blocking of course.

    I will post here again once all the javadoc is finished. A look at it would be much appreciated.
    (Then I will probably create a separate thread for it, so others can use it and has a place to ask support questions.)
     
  29. Offline

    Gravity

    AnorZaken oh, I misunderstood your last post, I thought you were going to work on a diff already. In any case, I would be happy to look at what you've changed if you publish your code (which I would do regardless -- open sourcing this stuff is important to helping others use it)
     
  30. Offline

    AnorZaken

    Well of course, I've been working on this under the assumption that it's GPLv3, now that I think about it I'm not sure I've actually looked up the license... just assumed it's open ^^

    I don't want to give a time estimate because my time estimates are usually wrong, but I will make the source available "in the not too distant future" and would love feedback on it! ;)
     
  31. Offline

    AnorZaken

    Gravity I still haven't finished all of the javadoc I mentioned (and I will continue working on the code, have plans for more features / improvements) , but if you are curious the source is included in the .jar file for AnimalsDropMeat v1.1 and BabyZombieExp v1.1 (both awaiting approval).

    Example of typical usage would look like this:
    Code:
    public void onEnable()
    {
      //...
      PluginUpdater.easyUpdate(this, getFile(), PROJECT_ID, EasyMode.Check_Only, getServer().getConsoleSender());
    }
    And:
    Code:
    public boolean onCommand(CommandSender sender, Command command, String label, String[] args)
    {
      //...
      if(args[0].equalsIgnoreCase("check"))
          PluginUpdater.easyUpdate(this, getFile(), PROJECT_ID, EasyMode.Check_Only, sender);
      else if(args[0].equalsIgnoreCase("download"))
          PluginUpdater.easyUpdate(this, getFile(), PROJECT_ID, EasyMode.Download_NoCheck, sender);
      //...
    }
    There are a few overloads available for easyUpdate(), the above being the easiest one.
    It is deceptively similar to Updater 2.0 but as I've mentioned before the code base is four times as big, a lot has happened under the hood.

    PluginUpdater.easyUpdate() will auto handle everything: sender will be notified about what is happening and, once the worker thread has finished, what the result was. The great benefit from this (aside from being extremely easy to use) is that if you let PluginUpdater handle all the messaging all plugins using the updater will have a uniform output style, increasing ease-of-use for the end user (the server admin). It can also take an optional argument that is intended for informing the user what command to use to start the download if a successful update-check was performed.

    There are more advanced and direct ways to interact with the PluginUpdater but easyUpdate() is probably what 99% of the devs are going to use 99% of the time anyway...

    So there you have a little teaser. Short posts ain't my forte. ^^
    If you're curious have a look soon (when the new versions get approved), if you're busy you can always wait for a more polished release which will come later.
     
Thread Status:
Not open for further replies.

Share This Page