Solved Strange location behavior

Discussion in 'Spigot Plugin Development' started by xlis1, May 28, 2017.

  1. Im having an issue where my location appears to be setting its self to some random fixed point when called from a runTaskLater. its hard for me to describe so ill just show you.


    Code (Text):
    if (loc.getBlock().getType().isSolid()) {
                                loc.getWorld().spawnParticle(Particle.END_ROD , loc, 15);
                                if (loc.getBlock().getType() == Material.MAGMA) {
                                    loc.getBlock().setType(Material.SEA_LANTERN);
                                    Location saveloc = loc;
                                    Bukkit.broadcastMessage(saveloc.toString());
                                    Bukkit.broadcastMessage(loc.toString());
                                    Bukkit.getScheduler().runTaskLater(getInstance(), () -> {
                                        Bukkit.broadcastMessage(saveloc.toString());
                                        saveloc.getBlock().setType(Material.MAGMA);
                                      }, 20L);
                                    loc.getWorld().spawnParticle(Particle.CRIT, loc, 15);
                                    player.setLevel(player.getLevel() + 1);
                                }
                                t = 2000;
                            }
    That's the code im using to detect when my beam has hit a solid block, if that block is a magma block set it to a sea lantern then one second later set it to a magma block again. (the bukkit.broadcastmessage's are there for debuging)


    the issue is, saveloc is some random location in the middle of nowhere, but only when referenced from the runTaskLater

    in game output

    [​IMG]

    (that is in the order of saveloc, loc, saveloc(inside the runTaskLater this time))

    can anyone explain whats going on here?



    EDIT: there are no errors in console either
     
    #1 xlis1, May 28, 2017
    Last edited: May 28, 2017
  2. When you set saveLoc = loc, you're setting the value of saveLoc to a reference to the loc object. I can't see your full code, but I see that you don't define loc. I'd have to see all your code to be sure, but its possible that the loc object changes which will change the saveLoc?

    Try setting saveLoc to a new location using the loc's world, x, y and z coordinates and see if the problem still occurs
     
  3. Change
    Code (Text):
    Location saveloc = loc;
    to
    Code (Text):
    Location saveloc = loc.clone();
    and you should be good to go.
     
    • Winner Winner x 1
  4. I was unaware of this, thank you!
     
    • Friendly Friendly x 1
  5. To explain why cloning the location works (for anyone that finds this thread from searching):

    The Location object is a mutable object, meaning it's internal values can change if you change them. Combine that with the fact the Java is a pass-by-reference language, and you get a lot of confused people that are new to the language.

    I'll break it down in some pseudo-code for clarification.

    Code (Text):

    Location loc1 = new Location(Bukkit.getWorld("world"), 0, 0, 0);
        // loc1 has coords: world 0,0,0

    Location loc2 = loc1.add(100,100,100);
        // loc1 has coords: world 100,100,100
        // loc2 has coords: world 100,100,100
        // this is because loc1 is mutable and the .add() method changed its internal values and returns itself.
        // loc2 is the exact same object as loc1, not just similar internal values.

    Location loc3 = loc2;
        // loc1 has coords: world 100,100,100
        // loc2 has coords: world 100,100,100
        // loc3 has coords: world 100,100,100
        // loc3, loc2, and loc1 are all the exact same object now. Changing one of them will show in all of them

    loc2.add(250,250,250);
        // loc1 has coords: world 350,350,350
        // loc2 has coords: world 350,350,350
        // loc3 has coords: world 350,350,350
        // this confuses a lot of new people

    Location loc4 = loc1.clone();
        // loc1 has coords: world 350,350,350
        // loc2 has coords: world 350,350,350
        // loc3 has coords: world 350,350,350
        // loc4 has coords: world 350,350,350
        // loc4 is now a new object. it is different than loc1/2/3 just with similar internal values

    Location loc5 = loc4.add(500,500,500);
        // loc1 has coords: world 350,350,350
        // loc2 has coords: world 350,350,350
        // loc3 has coords: world 350,350,350
        // loc4 has coords: world 850,850,850
        // loc5 has coords: world 850,850,850
        // changing loc4 doesnt change loc1/2/3 and loc5 is now the exact same object as loc4.

    Location loc6 = loc4.clone().add(500, 500, 500);
        // loc1 has coords: world 350,350,350
        // loc2 has coords: world 350,350,350
        // loc3 has coords: world 350,350,350
        // loc4 has coords: world 850,850,850
        // loc5 has coords: world 850,850,850
        // loc6 has coords: world 1350,1350,1350
        // loc1/2/3 are still the same object, loc4/5 are the same object, loc6 is its own object.
     
    etc etc etc.

    It's been long debated whether or not it is a good thing that Location is mutable. It has its uses, but it seems more use-cases actually prefer it not to be. Just remember to use clone() to create a new object if your use-case needs it.

    Side note: the World object inside all 6 of the above locations is the exact same object (because of Java's pass-by-reference nature). ;)
     
    • Agree Agree x 2