1.17.1 Store BlockStates

Discussion in 'Spigot Plugin Development' started by GrandEnder, Jun 16, 2021.

  1. Hello all!

    I have a plugin in which I give players the ability to blow up large swathes of terrain (just turning it all to air and the occasional fallingblock), and that terrain proceeds to regenerate over the course of several minutes. I do this by simply saving all that terrain as a list of blockstates, creating a bukkitrunnable, and running through that list over the course of thirty minutes or an hour and .updating all those blockstates by force.

    However, what if the server saves and crashes in the interim? I am a coder, and must plan for all eventualities! Even this. And I would be truly shamed if a player's chest full of diamond blocks vanished because of my poor coding!

    If the server saved and crashed while my plugin was still restoring blocks, the server would reload to the point of the save, where the terrain is still destroyed, but it wouldn't continue running the bukkitrunnable!

    Therefore, I need some way to store these BlockStates in a .yml file or something of that sort, and then re-acquire them on server start up to clean up everything if there are any pending repairs to be made.

    Currently, I've been trying to use gson to convert BlockStates into strings that I can store, but I'm having some difficulty.

    Code (Text):
    Gson gson = new GsonBuilder().setPrettyPrinting().create();
    String s = gson.toJson(blockstate.get(1));
    player.sendMessage(s);
    Doesn't even work, for example! Throws an error (assume that blockstate there is a List<BlockState>). Any tips or tricks, you folks?
     
    #1 GrandEnder, Jun 16, 2021
    Last edited: Jun 16, 2021
    • Like Like x 1
  2. toJson() requires a writer to be passed as second argument and the method does not return anything (it is of type void). Your IDE should be screaming at you ;-)

    One example of saving would be:
    Code (Java):
    private void saveObject(@NotNull Object object, @NotNull File file) {
            try (FileWriter writer = new FileWriter(file)) {
                if (!file.exists())
                    if (!file.createNewFile())
                        throw new RuntimeException("Failed to create file at " + file.getPath());

                this.gson.toJson(object, writer);
            } catch (IOException e) {
                throw new RuntimeException("Failed to save " + object.getClass().getSimpleName() + " to " + file.getPath());
            }
        }
    with reading being:
    Code (Text):
    private <U> @NotNull U readObject(@NotNull File file, Class<U> clazz) {
            if (!file.exists()) throw new IllegalArgumentException("File at " + file.getPath() + " does not exist");
            U result;
            try (Reader reader = Files.newBufferedReader(file.toPath())) {
                result = this.gson.fromJson(reader, clazz);
                return result;
            } catch (IOException e) {
                throw new RuntimeException("Failed to read " + clazz.getSimpleName() + " at " + file.getPath());
            }
        }
    Note that you will need to register some TypeAdapters to the gsonbuilder before running build to serialize some of the default bukkit classes.
     
  3. Hey, I made the experience that bukkit objects arent made to be make to json. Just simple ones like locations.

    You need to write a own typeadapter for those classes.
    I would recommend you that you're detecting server stops and reloads and try set the blocks directly. For crashes I would say, you can't do anything against that. A other method could be that you save the blocks via the worldedit api and create a schematic from that, so you would save even entities like paintings and such stuff.
     
  4. I like the worldedit idea a lot, but I’m not too familiar with using the API (just the plugin). Any documentation on it anywhere?
     
    • Like Like x 1
  5. Great that you ask. You find the world edit documentation here
     
  6. Tau

    Tau

    Considering the high bandwidth of this I wouldn't save it as json let alone through GSON
    It is terribly slow.

    If you want something unreasonably fast look at my Item implementation in KaBoom
    https://gitlab.com/TauCu/kaboom/-/blob/master/src/main/java/me/taucu/kaboom/util/ItemSerial.java

    So long as you can get your data in some primitive form of array (such as byte[]) it will wrap it into one huge blob and can unwrap it later.