#Save & Load stuff

1 messages ยท Page 1 of 1 (latest)

restive depot
#

.

#

@summer mortar

summer mortar
#

yep

restive depot
#

Save & Load stuff

summer mortar
#

its easier to track a convo in a thread

restive depot
#

Yeah

summer mortar
#

ok lets see if you actually need to save and load...

#

These chests, they are spawned by a command always?

restive depot
#

Well, the plugin saves locations of blocks as a sort of lootable blocks. If the server ever crashes, reloads, or something else happens, it will otherwise lose all those locations, and the user would have to make them all over

restive depot
summer mortar
#

what object type?

restive depot
#

Uhh I mean it's like a class

summer mortar
#

in game they are represented by?

restive depot
#

how do I explain this lol

summer mortar
#

is there a block you spawn in game to display them?

restive depot
#

You use /sc add [PARTICLE] [cooldown] [items] whilst looking at a block to save that exact block location (coordinate) as a lootable block. So you dont do anything with the block, but just its location. When a player right clicks that block, the particles disappear, the player gets a random item from items, and the cooldown starts. Once the cooldown has finished, the particles reappear and the "block" (location) is lootable again

#

Of course you can also /sc remove the blocks, and /sc list them all

#

There are probably a 100 easier ways of making this plugin, but this has already taken me like 40 hours and I really dont want to spend more time on it lol.

summer mortar
#

what spigot version are you building against?

restive depot
#

1.17.1

#

if thats what you mean

summer mortar
#

yep

#

ok as there is no actual in game object to represent these, other than particles, they are quite detached from the game world so saving to file is ok, however you could consider using PDC instead

#

as you have most of it done, lets continue with saving to yaml

#

your ChestObject needs to implement as so java public class ChestObject implements ConfigurationSerializable {

#

it will tell you it's missing methods so let it add them

restive depot
#

ohh I see

summer mortar
#

you need to create a method public static ChestObject deserialize (Map< String, Object> object)

#

in that method you will be reading a Map passed in to create a new ChestObject

restive depot
#

and that new chestobject only gets created for the save and load functions right?

summer mortar
#

the deserialize method will be used by the config when it loads

restive depot
#

so it gets run automatically?

summer mortar
#

yes

restive depot
#

Ah alright

#

theres another thing AI didn't know

restive depot
summer mortar
#

it will yes

#

one sec

#

ok

#

ok inside the deserialize method you need to read data from teh map and convert it to the data your constructor needs to make a new ChestObject

#

so Location, particle, int a List of ItemStacks

restive depot
#
    public static ChestObject deserialize(Map<String, Object> args) {
        boolean isLooted = (boolean) args.get("isLooted");
        Location location = (Location) args.get("location");
        Particle particle = Particle.valueOf((String) args.get("particle"));
        int cooldown = (int) args.get("cooldown");
        List<ItemStack> items = (List<ItemStack>) args.get("items");```?
summer mortar
#

they will be in the same order we save them so we can just iterate the map

#

the last one for the List may not work, but you can try it

restive depot
#

Why not?

summer mortar
#

casting to lists and the internal object is often a pain

#

now the last line of that method would be return new ChestObject(isLooted, location, particle, cooldown, items);

#

ok, what other methods did your IDE make you create in that class?

#

probably a serialize

restive depot
#

Yeah

#

So far I got java public Map<String, Object> serialize() { Map<String, Object> result = new LinkedHashMap<>(); result.put("isLooted", isLooted); result.put("location", location); result.put("particle", particle.toString()); result.put("cooldown", cooldown); result.put("items", items); return result; }

summer mortar
#

ok in that need to dump all our data for this ChestObject

#

yep

#

did it create any other methods?

restive depot
#

No, but I read that I had to add java public ChestObject() { } to the code for the serialization/deserialization to work

#

But Im not sure why

summer mortar
#

a blank constructor

restive depot
#

yeah....

summer mortar
#

it doesn;t need that

#

but for now keep it

#

ok in yoru plugins main class

restive depot
#

It says that this is required for the YAML deserialization to work.

summer mortar
#

at the very top of your onEnable add java ConfigurationSerialization.registerClass(ChestObject.class);

restive depot
#

Ah alright

#

And that does...?

summer mortar
#

that lets Bukkit know about your object so it knows how to deserialize it

#

now test it

restive depot
#

Do you know why this might happen?

#

The error doesnt tell me much

#

I guess that particle name isnt correct, which brings me to what was mentioned earlier: Auto-correct (auto-fill-in, whatever you want to call it). Can you explain to me how something like that would work? @summer mortar

summer mortar
#

yes tab complete

#

your command class, instead of extending CommandExcutor you use TabExecutor

summer mortar
#

not quite

#

it will make you create a new method for tab complete

#

in that method you return a List of acceptable entries depending on the length of args

restive depot
#

Alright so it created public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) { return null; }

summer mortar
#

yep, if you want it to offer particles when args length is 2

#

if (args.length == 2) return Particles.values();

#

actually you need to add that to a List

#

as Particles.values() returnes an array

restive depot
#

Hmm alright

restive depot
#

I mean, I know what it is

#

but, it's not an existing thing is it

summer mortar
#

so return Arrays.asList(Particle.values());

restive depot
#

Shouldnt it be Particles.values().toString()?

summer mortar
#

ah you'll probably have to stream to get teh names

restive depot
#

stream?

summer mortar
#
if (args.length == 2) return Stream.of(Particle.values())
    .map(Particle::name)
    .collect(Collectors.toList());```
restive depot
#

And what does the stream.of mean

summer mortar
#

it processes them one by one

restive depot
#

Ah alright

summer mortar
#

map takes the entry name

restive depot
#

and where should I create enumNames?

summer mortar
#

then the last puts the results in a List

#

fixed

restive depot
#

Ah alright, awesome. Let me test it

#

or is this not done

#

Shouldnt onCommand be removed? @summer mortar

summer mortar
#

no, thats still used

#

your class does two things now, onCommand processes the command when it's fully entered and the player presses enter. TabComplete just offers up suggestions.

restive depot
#

Now Im getting an error from my main.java

    private void registerCommands(ParticleHandler particleHandler) {
        Objects.requireNonNull(getCommand("sc")).setExecutor(new AddParticleCommand(particleHandler));
    }``` 'setExecutor(org.bukkit.command.CommandExecutor)' in 'org.bukkit.command.PluginCommand' cannot be applied to '(me.JustinS_2006.particles.AddParticleCommand)'
summer mortar
#

you did change CommandExecutor to TabExecutor ?

#

not TabCompleter

restive depot
#

o

#

There we go, all fixed now lol

#

It works! It's amazing haha. Thanks so much for the help! ๐Ÿ™‚

summer mortar
#

you can improve teh tab suggestion

restive depot
#

oh, how?

summer mortar
#
if (args.length == 2) return Stream.of(Particle.values())
    .map(Particle::name)
    .filter(str -> str.trim().contains(args(1).toUpperCase()))
    .collect(Collectors.toList());```
#

would probably work

restive depot
#

What's the difference

summer mortar
#

that shoudl allow you to start typing the name and it will shorten the list

restive depot
#

ooh cool

summer mortar
#

it added the filter line

restive depot
#

Ahh I see

summer mortar
#

may have to uppercase. sec

#

fixed code

#

as all enum names are uppercase

restive depot
#

oh alright

#

Ill use fixed code

summer mortar
#

oh sec

#

ok now I've fixed it ๐Ÿ™‚

restive depot
#

๐Ÿ‘Œ

#

This is amazing haha

#

The plugin's finally working lol

summer mortar
#

nice

#

all working?

restive depot
#

well

#

I see that it requires data, but is there a way I can make sure particles that "require data" arent allowed?

#

because it kinda breaks everything

#

even if I reload

summer mortar
#

possibly

restive depot
#

Cant I use a try and except

#

wait no

summer mortar
#

you could try adding before the .map line in tabcompletejava .filter(Particle::getDataType != BlockData.class)

#

if that works to exclude teh crack entry

#

we can do a simple validity check in teh onCommand to exclude bad selections

restive depot
#

Ill give it a try

restive depot
#

Method reference expression is not expected here

summer mortar
#

tryjava .filter(enum - > Particle::getDataType != BlockData.class)

summer mortar
#

nope, one sec

#

.filter(entry -> entry.getDataType() != BlockData.class)

#

that should work

#

had to open my ide to syntax check ๐Ÿ™‚

restive depot
#

My electricity and wifi just died and it fucked up discord and mc on my laptop so 1 sec

restive depot
# summer mortar `.filter(entry -> entry.getDataType() != BlockData.class)`

It doesnt tabcomplete blockcrack anymore, but it does tab complete the legacy particles. JustinS_2006 issued server command: /sc add LEGACY_BLOCK_CRACK 5 sand [16:55:49] [Server thread/WARN]: [ScrapCollection] Task #14 for ScrapCollection v1.0 generated an exception java.lang.IllegalArgumentException: Particle LEGACY_BLOCK_CRACK requires data, null provided at com.google.common.base.Preconditions.checkArgument(Preconditions.java:191) ~[server.jar:3284a-Spigot-3892929-0ab8487]

#

which also result in chaos and destruction

summer mortar
#

simple to exclude LEGACY_

restive depot
#

yeah?

summer mortar
#
        Stream.of(Particle.values())
        .filter(entry -> entry.getDataType() != BlockData.class)
        .map(Particle::name)
        .filter(str -> str.trim().contains(args(1).toUpperCase()) && !str.startsWith("LEGACY_"))
        .collect(Collectors.toList());```
restive depot
#

Now it doesn't recommend anything anymore :/

summer mortar
#

once this is all workgin as you want it we can tidy up and simplify it

#

doh

#

fixed code

restive depot
#

oh wait it was my bad

#

I didn't return it

#

๐Ÿคฆโ€โ™‚๏ธ

restive depot
# summer mortar fixed code

Exception when JustinS_2006 attempted to tab complete sc
org.bukkit.command.CommandException: Unhandled exception during tab completion for command '/sc ' in plugin ScrapCollection v1.0
at org.bukkit.command.PluginCommand.tabComplete(PluginCommand.java:150) ~[server.jar:3284a-Spigot-3892929-0ab8487]
at org.bukkit.command.Command.tabComplete(Command.java:93) ~[server.jar:3284a-Spigot-3892929-0ab8487]
at org.bukkit.command.SimpleCommandMap.tabComplete(SimpleCommandMap.java:231) ~[server.jar:3284a-Spigot-3892929-0ab8487] ....

#

:/

summer mortar
#

I'll need the whole exception

restive depot
#

Caused by: java.lang.ArrayIndexOutOfBoundsException: Index 1 out of bounds for length 1
at me.JustinS_2006.particles.AddParticleCommand.lambda$onTabComplete$1(AddParticleCommand.java:103) ~[?:?]
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:178) ~[?:?]
at java.util.stream.ReferencePipeline$3$1.accept(ReferencePipeline.java:197) ~[?:?]
at java.util.stream.ReferencePipeline$2$1.accept(ReferencePipeline.java:179) ~[?:?]
at java.util.Spliterators$ArraySpliterator.forEachRemaining(Spliterators.java:992) ~[?:?]
at java.util.stream.AbstractPipeline.copyInto(AbstractPipeline.java:509) ~[?:?]
at java.util.stream.AbstractPipeline.wrapAndCopyInto(AbstractPipeline.java:499) ~[?:?]
at java.util.stream.ReduceOps$ReduceOp.evaluateSequential(ReduceOps.java:921) ~[?:?]
at java.util.stream.AbstractPipeline.evaluate(AbstractPipeline.java:234) ~[?:?]
at java.util.stream.ReferencePipeline.collect(ReferencePipeline.java:682) ~[?:?]
at me.JustinS_2006.particles.AddParticleCommand.onTabComplete(AddParticleCommand.java:104) ~[?:?]
at org.bukkit.command.PluginCommand.tabComplete(PluginCommand.java:141) ~[server.jar:3284a-Spigot-3892929-0ab8487]

summer mortar
#

um you deleted the if (args.length == 2)

restive depot
#

๐Ÿค”

#

oh

#

right

#

...

restive depot
summer mortar
#

ok now we don;t need to do all the streaming every time a key is pressed we can move some stuff to variables

#

ok, at the top of the class add a fieldjava List<String> validParticles = Stream.of(Particle.values()) .filter(entry -> entry.getDataType() == Void.class) .map(Particle::name) .filter(str -> !str.startsWith("LEGACY_")) .collect(Collectors.toList());

#

then where you were doing this replace withjava if (args.length == 2) return StringUtil.copyPartialMatches(args[1].toUpperCase(), validParticles, new ArrayList<String>(validParticles.size()));

#

in your onCommand you can then check they selected a valid particle and set a default if they didn't

restive depot
#

My electricity and wifi died again, sorry for the sudden disappearance

#

I gtg for dinner now but Ill be back in 20min

restive depot
#

nvm

restive depot
# summer mortar then where you were doing this replace with```java if (args.length == 2) return ...

So like this?```java
List<String> validParticles = Stream.of(Particle.values())
.filter(entry -> entry.getDataType() == Void.class)
.map(Particle::name)
.filter(str -> !str.startsWith("LEGACY_"))
.collect(Collectors.toList());

public List<String> onTabComplete(CommandSender sender, Command command, String alias, String[] args) {

    if (args.length == 2) return StringUtil.copyPartialMatches(args[1].toUpperCase(), validParticles, new ArrayList<String>(validParticles.size()));
    return null;
}```
#

Btw feel free to ping me when replying. That way I can respond asap

summer mortar
#

you can use either StringUtil as it's packaged with Spigot or use teh Stream method.

#
return validParticles.stream()
                .filter(str -> str.contains(args[1].toUpperCase()))
                .collect(Collectors.toList());```or```java
return StringUtil.copyPartialMatches(args[1].toUpperCase(), validParticles, new ArrayList<String>(validParticles.size()));```
restive depot
#

And what's the difference

summer mortar
#

StringUtils is cleaner but either works just as well as the other

#

all you have left is validate your input in onCommand

#
Particle particle = (validParticles.contains(args[2].toUppercase()) ? Particle.valueOf(args[2].toUppercase()) : Particle.ASH;```
#

That will ensure they always select a valid particle or it will set ASH

#

or whichever you want

restive depot
summer mortar
#

.toUpperCase() definately correct

restive depot
#

yeah...

#

thats what I thought

#

oh I see

summer mortar
#

you need to move that line down to where it actually picks the particle

restive depot
#

You typed toUpperc<---ase

#

Fixed that part

restive depot
#

Not sure if I still need that first line though

#

I dont think so

#

but I think it should be args[1] not args[2]

summer mortar
#

yep just replace yoru line with mine

restive depot
#

๐Ÿ‘

#

Alright, done that

summer mortar
#

looks like it should also be args[1] not 2

restive depot
#

yeah just mentioned that

summer mortar
#

ah I see

restive depot
# summer mortar ah I see

Btw is this plugin easy to turn into a player-based plugin. So basically, everyone can right click the same block, and every player has their own cooldown? Because now if someone right clicks the block, the particles also disappear for me.

summer mortar
#

you could but it would not be so easy as you'd have to use packets to display the particles

restive depot
#

Ah alright, well let's not do that then

#

Ill make sure there are enough scrap locations

restive depot
# summer mortar you could but it would not be so easy as you'd have to use packets to display th...

I let someone else try the plugin and they got this error when I use /sc add ...

[12:53:34 WARN]: java.io.IOException: No such file or directory
[12:53:34 WARN]:        at java.base/java.io.UnixFileSystem.createFileExclusively(Native Method)
[12:53:34 WARN]:        at java.base/java.io.File.createNewFile(File.java:1043)
[12:53:34 WARN]:        at ScrapCollection-1.0-SNAPSHOT.jar//me.JustinS_2006.particles.ParticleHandler.saveChestData(ParticleHandler.java:121)
[12:53:34 WARN]:        at ScrapCollection-1.0-SNAPSHOT.jar//me.JustinS_2006.particles.ParticleHandler.AddLoc(ParticleHandler.java:38)
[12:53:34 WARN]:        at ScrapCollection-1.0-SNAPSHOT.jar//me.JustinS_2006.particles.AddParticleCommand.onCommand(AddParticleCommand.java:66)``` It has to do with the path of the data file right?
summer mortar
#

yep

#

probably

#

did you call mkdirs()?

restive depot
#

uhhh

restive depot
summer mortar
#

before you attempt to create a file. It will ensure teh directory exists

restive depot
#

Ah alrigh

summer mortar
#

File#mkdirs()

#

be sure it's mkdirs not mkdir

restive depot
#

It appears Im not calling it ๐Ÿค”

#

I thought I was

restive depot
#

So like this?

summer mortar
#

yep

restive depot
#

๐Ÿ‘

#

Still not working in his server :/
This time there is a folder and file.
Error:

java.lang.NullPointerException: Cannot invoke "org.bukkit.Location.add(double, double, double)" because "location" is null
        at me.JustinS_2006.particles.ParticleHandler$1.run(ParticleHandler.java:88) ~[ScrapCollection-1.0-SNAPSHOT.jar:?]...```
the chest_data file:```
chests:
- ==: me.JustinS_2006.particles.ChestObject
  isLooted: false
  location:
    ==: org.bukkit.Location
    world: galaxy
    x: -1743.0
    y: 107.0
    z: -2937.0
    pitch: 0.0
    yaw: 0.0
  particle: SCRAPE
  cooldown: 1
  items:
  - ==: org.bukkit.inventory.ItemStack
    v: 2730
    type: SAND```
#

How can the location be null @summer mortar ?
I mean, I obviously added a particle to a location

summer mortar
#

I'd need to see your loading code

#

show me the deserialize method in your ChestObject

#

@restive depot

restive depot
#
    public static ChestObject deserialize(Map<String, Object> args) {
        // Get all the variables from the Map, and return them as a ChstObject
        boolean isLooted = (boolean) args.get("isLooted");
        Location location = (Location) args.get("location");
        Particle particle = Particle.valueOf((String) args.get("particle"));
        int cooldown = (int) args.get("cooldown");
        List<ItemStack> items = (List<ItemStack>) args.get("items");
        return new ChestObject(isLooted, location, particle, cooldown, items);
    }

    public Map<String, Object> serialize() {
        Map<String, Object> result = new LinkedHashMap<>();
        result.put("isLooted", isLooted);
        result.put("location", location);
        result.put("particle", particle.toString());
        result.put("cooldown", cooldown);
        result.put("items", items);
        return result;
    }```
#

I think the issue is Location location = entry.getKey();
/sc list also gives an error, and its the only line of code it has in common with the other method that fails

summer mortar
#

at what point does it fail, after a load?

#

check yoru log for errors during the load

restive depot
#

I added the "THE LOCATION IS NUll" thingy, and it got triggeredjava public void spawnParticlesEverySecond() { BukkitRunnable runnable = new BukkitRunnable() { public void run() { for (Map.Entry<Location, ChestObject> entry : chests.entrySet()) { if (!entry.getValue().isLooted()) { Particle particle = entry.getValue().getParticle(); Location location = entry.getKey(); if(location == null){ Bukkit.broadcastMessage("LOCATION IS NULL !!!! >:("); return; } location.add(0.5, 1.2, 0.5); location.getWorld().spawnParticle(particle, location, 7, 0.15, 0.25, 0.15); location.subtract(0.5, 1.2, 0.5); } } } };

restive depot
#

No other errors.

summer mortar
#

use entry.getvalue().getLocation()

#

if that is ok your key is bad

restive depot
summer mortar
#

if that works, show me your loading code

restive depot
#

Loading code?

summer mortar
#

when you read it from the yaml

restive depot
#

after restarting

#

So I basically start the server > /sc add... > restart > broadcastmessage appears

summer mortar
restive depot
#

Remember that this error only occurs in his server. Not when I host my local server

summer mortar
#

you never load anything from your yaml

#

after your register your class you should be loading your data

restive depot
#

Then why is it working?

summer mortar
#

no idea

#

where is yoru save and load methods?

restive depot
summer mortar
#

ohb, line 13 take the ParticleHandler off the front

#

you are defining a local variable and not using the field

#

line 13 should just be particleHandler = new ParticleHandler(this);

restive depot
#

ohh of course

summer mortar
#

you still need to load yoru data somewhere

#

so show me your loading/saving code

restive depot
# summer mortar so show me your loading/saving code

In particleHandler:

    private void loadChestData() {
        try {
            File dataFolder = plugin.getDataFolder();
            if (!dataFolder.exists()) {
                dataFolder.mkdirs();
            }
            File dataFile = new File(dataFolder, CHEST_DATA_FILE);
            if (!dataFile.exists()) {
                return;
            }
            YamlConfiguration config = YamlConfiguration.loadConfiguration(dataFile);
            List<ChestObject> chestList = (List<ChestObject>) config.getList("chests");
            if (chestList == null) {
                return;
            }
            for (ChestObject chest : chestList) {
                chests.put(chest.getLocation(), chest);
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    private void saveChestData() {
        try {
            File dataFile = new File(plugin.getDataFolder(), CHEST_DATA_FILE);
            if (!dataFile.exists()) {
                dataFile.createNewFile();
            }
            YamlConfiguration config = YamlConfiguration.loadConfiguration(dataFile);
            List<ChestObject> chestList = new ArrayList<>(chests.values());
            config.set("chests", chestList);
            config.save(dataFile);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }```
summer mortar
#

can you do it in a paste so it's easier to read

#

nm

#

opk your save code is not correct

restive depot
#

nm = nvm?

restive depot
summer mortar
#

yep

restive depot
#

why is it not correct

summer mortar
#

you call load on it when all you want to do is save

restive depot
#

how?

summer mortar
#

YamlConfiguration config = YamlConfiguration.loadConfiguration(dataFile);

#

you need to create an empty one

restive depot
#

hmm

#

But I set it anyways

#

so what's the difference

summer mortar
#

you do but you shoudl not load in a save method

restive depot
#

oh alright

summer mortar
#

so YamlConfiguration config = new YamlConfiguration();

#

if it lets you do that

#

it should as it's public

restive depot
#

Alright

#

Ill test this

summer mortar
#

sec

#

when do you call your load method?

restive depot
#

public ParticleHandler(Plugin plugin) {
this.plugin = plugin;
loadChestData();
}

#

In the particlehandler

summer mortar
#

ok on instancing

restive depot
#

thats good?

summer mortar
#

yep should be fine

#

So long as the chests field in ParticleHandler is the same one used in your event listener

restive depot
#

still doesn't work

#

the "LOCATION IS NULL" triggered

#

here's the chest_data:

chests:
- ==: me.JustinS_2006.particles.ChestObject
  isLooted: false
  location:
    ==: org.bukkit.Location
    world: galaxy
    x: -1744.0
    y: 107.0
    z: -2923.0
    pitch: 0.0
    yaw: 0.0
  particle: SCRAPE
  cooldown: 5
  items:
  - ==: org.bukkit.inventory.ItemStack
    v: 2730
    type: SAND```
#

@summer mortar idk what to do anymore

#

none of the "fixes" are fixing it

summer mortar
#

sec

#

ok I see why

#

your deserialize method is wrong

restive depot
#

like... are all of my methods wrong

summer mortar
#

no

restive depot
#

surprising lol

restive depot
summer mortar
#

I think the config is using the constructor to create a new ChestObject but the deserialize is not filling in the fields

#

it is returning a new object

#

one sec

#

ok the deserialize method needs to return itself rather than a new instance

#

paste your chestObject class

#

@restive depot

summer mortar
#

um

#

I added an overdide and removed the empty constructor as it's not needed

restive depot
#

But how would that fix location from being null

summer mortar
#

it probably used reflection to find a constructor and used it, so it created an empty object

#

had no fields set

restive depot
#

hmm

#

alright

#

Ill give it a test

#

this better work now ๐Ÿ˜ญ

summer mortar
#

um

#

needs debug code then

#

add some debug to the deserialization code

restive depot
#

The debug code is the part that says the location is null, right?

summer mortar
#

yes

restive depot
summer mortar
#

the location

restive depot
summer mortar
#

debug location in deserialization method

restive depot
#

k. Should I just check if it's null everywhere where it's used?

#

in the deserialization method

summer mortar
#

just needs one debug in there

#

if that never says null we have to look elsewhere

restive depot
#

k

summer mortar
#

doh I see where the error is

#

it is in the deserialize method I think it's takign the class fields to construct the new object

#

um nope

#

debug it

restive depot
#

trigger

#

so...

#

it gets changed somewhere else

summer mortar
#

one sec then

#

ok add this constructor```java
@SuppressWarnings("unchecked")
public ChestObject(Map<String, Object> args) {

    // Get all the variables from the Map, and return them as a ChestObject
    isLooted = (boolean) args.get("isLooted");
    location = (Location) args.get("location");
    particle = Particle.valueOf((String) args.get("particle"));
    cooldown = (int) args.get("cooldown");
    items = (List<ItemStack>) args.get("items");
}```
restive depot
#

Alright

restive depot
summer mortar
#

yes

restive depot
#

k

restive depot
summer mortar
#

the same as the deserialize did but to the local object

restive depot
#

k

restive depot
#

That location there is null

#

and is causing everything to break

summer mortar
#

no, that is just reading the already loaded map

restive depot
#

maybe it's being read wrong there? Or maybe not

summer mortar
#

so somewhere empty/null objects have been put in the map

restive depot
#

k

restive depot
summer mortar
#

add debug to the loading code

#

where you put the ChestObject in the map

restive depot
summer mortar
#

yep

restive depot
#

Whilst Im waiting for the host to check the console, how come the plugin worked perfectly in my 1.17.1 localhosted server, but not in his 1.17.1 spigot server?

summer mortar
#

no clue, makes no sense

restive depot
#

I mean, if it does, the error makes no sense

summer mortar
#

nope, path is from spigot so

restive depot
#

weird shit

restive depot
summer mortar
#

add an api-version: 1.17 to your plugin.yml

restive depot
# summer mortar add an `api-version: 1.17` to your plugin.yml

He also got this error, though Im not sure how he got it [17:39:34 ERROR]: Could not load 'plugins/ScrapCollection-1.0-SNAPSHOT.jar' in folder 'plugins' org.bukkit.plugin.InvalidPluginException: java.lang.UnsupportedClassVersionError: me/JustinS_2006/particles/main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 60.0 at org.bukkit.plugin.java.JavaPluginLoader.loadPlugin(JavaPluginLoader.java:157) ~[patched_1.17.1.jar:git-Paper-408] at org.bukkit.plugin.SimplePluginManager.loadPlugin(SimplePluginManager.java:414) ~[patched_1.17.1.jar:git-Paper-408] at org.bukkit.plugin.SimplePluginManager.loadPlugins(SimplePluginManager.java:322) ~[patched_1.17.1.jar:git-Paper-408] at org.bukkit.craftbukkit.v1_17_R1.CraftServer.loadPlugins(CraftServer.java:419) ~[patched_1.17.1.jar:git-Paper-408] at net.minecraft.server.dedicated.DedicatedServer.initServer(DedicatedServer.java:287) ~[patched_1.17.1.jar:git-Paper-408] at net.minecraft.server.MinecraftServer.runServer(MinecraftServer.java:1220) ~[patched_1.17.1.jar:git-Paper-408] at net.minecraft.server.MinecraftServer.lambda$spin$0(MinecraftServer.java:319) ~[patched_1.17.1.jar:git-Paper-408] at java.lang.Thread.run(Thread.java:831) ~[?:?] Caused by: java.lang.UnsupportedClassVersionError: me/JustinS_2006/particles/main has been compiled by a more recent version of the Java Runtime (class file version 61.0), this version of the Java Runtime only recognizes class file versions up to 60.0 .... ... 7 more my guess is that the server version isnt 1.17

restive depot
summer mortar
#

wrong java version on the server

restive depot
#

yeah, thats what I guess. Awaiting his response

restive depot
#

I'm 101% sure it has to do on his side. Just started another quick server using server.pro, 1.17.1 spigot and it works just fine

#

So it must be on his side

restive depot
#

I also changed my plugin to java 16 as their server also turned to java 16

restive depot
#

@summer mortar I found the issue. It's that the world is not recognised as world, because it's generated through a plugin (because you cant have more than 1 world in minecraft, you use a plugin such as multiverse). Do you know a workaround?

summer mortar
#

yes, the multicraft plugin has to load before yours

#

so he needs it on his server too

#

and the world must be created

restive depot
restive depot
#

It's also a randomized order (I think?)

summer mortar
#

yes unless you add a depend to your plugin.yml

#

depend: [ MultiverseCore]

#

I think

restive depot
#

Ohh so that's what depends are for?

summer mortar
#

may just be Multiverse, you'll need to look it up

restive depot
#

I saw them but thought they were just kinda like libraries