getBedSpawnLocation returns null due to not being actual bed location

Discussion in 'Plugin Development' started by MixerBlaze, Dec 14, 2020.

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

    MixerBlaze

    Hello! This is my first post here.

    I've currently working on a plugin that acts as a substitute to some popular programs like Multiverse. Right now, I'm saving every player's data (inventories, spawn points, health, potions etc.) to a config folder, and when the player goes to the world, it reads the config and restores the player's original state.

    The problem that I'm encountering is with #setBedSpawnLocation and #getBedSpawnLocation. It was always returning null even when the config had a legitimate "bed" location.

    After numerous days of debugging, I finally gave in to frustration and started messing around, eventually placing a ton of beds in a square shape. I then set my spawn in the middle, left that world, came back, and voila, my spawn location was in the general area. I then found that you always spawned to the left of the head of the bed, if possible, and if not, on top of the bed directly.

    So my question is, is there any non-hacky solution to get the actual location of a bed spawn? I can't just use interact events to intercept set spawn times directly, because that's not particularly future proof and spawn anchors do exist. It's also not possible to just check for a bed within a general vicinity.

    Can anyone point me in the right direction?

    Thanks in advance.
     
  2. Offline

    Kars

    I don't understand your problem. You want to figure out a player's bed location when getBedSpawnLocation returns null? When that function returns null it might mean that the bed location is invalid.

    Why can you not use interact events? Why is it not future proof and why can you not check for a bed within the vicinity?
     
  3. Offline

    MixerBlaze

    I'm sorry if I didn't explain this clearly enough. What I mean is that getBedSpawnLocation never returns the actual bed's location, and rather some block near the bed where you would spawn. That's why it will return null because when you try to set their bed to that location, there's not always an actual bed there. So basically I'm wondering if there's any surefire way to do what getBedSpawnLocation should be doing. Which is to get the actual location of the bed, if the bed is still there.

    About the future proof/interact events/vicinity I was just mentioning some hacky alternatives and basically saying that they're flawed. Probably shouldn't have added that part.

    Thanks for responding.
     
  4. Offline

    CraftCreeper6

    @MixerBlaze
    If the value of getBedSpawnLocation is 1 block away or on top of the bed, why does it matter? What difference will it make in a plugin like Multiverse?

    If it really matters then just store the location of the bed when it is used, make sure to overwrite the location if the player uses a different bed, and make sure you check if the bed has been destroyed and remove the location. And obviously the locations should be player specific.
     
  5. Offline

    MixerBlaze

    Multiverse is how I like to explain things because there's no other way then to describe it as a "world switch plugin." But like I said, I save all data inside of a config folder including spawn points. Checking when they sleep in it won't work because you can set a spawn point without sleeping in a bed.

    If I have to rephrase the question again, how do I get the actual location of a bed that the player's spawn is anchored to?
     
  6. Offline

    CraftCreeper6

    @MixerBlaze
    By anchored to, I assume you're referring to
    If that's the case then just check the block in each lateral direction and see if it's a bed, if none are, check below, and if still no bed, it's not longer a bed spawn point.

    I'm still unsure why you don't just use PlayerBedEnterEvent. You can use getBed() to get the bed and get it's location and just store that value, then teleport them there afterwards.

    Unless I'm seriously misunderstanding the question at hand here, that seems like a perfectly legitimate solution.
     
    Kars likes this.
  7. Offline

    MixerBlaze

    It's a survival server, so you can click a bed and it will set your spawn point. That means that you don't have to sleep in a bed in order to set your spawn.

    Checking every lateral direction is also very strange as you're trying to set their bed spawn and you don't know if maybe there are two beds next to each other and the one you're looking for has been broken or something. Another reason why you'd need their exact bed point is in the case of respawn anchors (which act like beds I think), which have their own metadata and will determine whether or not it's a valid spawn point.
     
  8. Offline

    CraftCreeper6

    @MixerBlaze
    PlayerBedEnterEvent
    "This event is fired when the player is almost about to enter the bed."

    I do believe that even right clicking will call this event. Use EventPriority.HIGHEST to make sure it fires before any other plugins cancel it.
     
    Last edited: Dec 15, 2020
  9. Offline

    MixerBlaze

    How would I use it for respawn anchors then? Dang do I hate respawn anchors. What I'm basically asking is if there's some kind of universal way to check if they set their spawn point and then give back that spawn point after a certain period of time.
     
  10. Offline

    Kars

    @MixerBlaze you can use PlayerBedEnterEvent.getBed.getLocation to get the location of the bed.
     
  11. Offline

    MixerBlaze

    @Kars Again, that would make sense for beds, but how about respawn anchors? Also, I found this nice little page that basically says what I'm trying to achieve is almost impossible without some very specific hard-coding. https://hub.spigotmc.org/jira/browse/SPIGOT-6081
     
  12. Offline

    CraftCreeper6

    @MixerBlaze
    Then PlayerInteractEvent. Check if the respawn anchor contains glowstone before respawning them, though.
     
  13. Offline

    Kars

    Just catch the events that are used to set your spawn and catch the block associated with them.
     
  14. Offline

    MixerBlaze

    @Kars
    @CraftCreeper6
    Here's what I ended up doing.

    Code:
        public void setSpawn(PlayerInteractEvent event) { // set respawn code
            Player player = event.getPlayer();
            if(event.getAction()==Action.RIGHT_CLICK_BLOCK)//if they right clicked a block
                if (event.getPlayer().getWorld().getName().toLowerCase().contains("smp")) {
                    if (event.getClickedBlock() != null) {
                        if (event.getClickedBlock().getType() == Material.RESPAWN_ANCHOR) {
                            if (!event.getClickedBlock().getBlockData().getAsString().contains("charges=0")) {
                                this.getConfig().set("spawns." + event.getPlayer().getUniqueId(), event.getClickedBlock().getLocation());
                                this.saveConfig();
                                player.sendMessage(ChatColor.AQUA + "Respawn point set");
                           
                            }
                        }
                        if (event.getClickedBlock().getType().toString().contains("_BED")) {
    
                            Block head = event.getClickedBlock();
                            if (head.getBlockData().getAsString().contains("part=foot")) {
    
                                String data = event.getClickedBlock().getBlockData().getAsString();
                                String dir = data.substring(data.indexOf("facing=") + 7, data.indexOf("facing=") + 8);
                                switch (dir) {
                                case "n":
                                    head = head.getLocation().add(0, 0, -1).getBlock();
                                    break;
                                case "s":
                                    head = head.getLocation().add(0, 0, 1).getBlock();
                                    break;
                                case "e":
                                    head = head.getLocation().add(1, 0, 0).getBlock();
                                    break;
                                case "w":
                                    head = head.getLocation().add(-1, 0, 0).getBlock();
                                    break;
                                }
                            }
    
    
                            this.getConfig().set("spawns." + event.getPlayer().getUniqueId(), head.getLocation());
                            event.getPlayer().setBedSpawnLocation(head.getLocation());
                            this.saveConfig();
                            player.sendMessage(ChatColor.AQUA + "DEBUG: Config respawn point set");
    
    
                        }
    
                    }
                }
        }
    As you can see it's definitely a workaround and not ideal. This code is also not useable yet as Respawn Anchors only work when you click on the top of them.

    I have an idea, and that's to catch whenever the default respawn set words "Respawn point set" are sent to the player from the server to further make this more accurate. Any ideas?

    By the way, I ask that you excuse my horrendous nested ifs. I'm still developing my habits.
     
  15. Offline

    CraftCreeper6

    @MixerBlaze
    I say keep it as it is. It's much more reliable than monitoring the chat, plus, you'll still have to keep track of the last block the player clicked even if you do monitor the chat. IMO, not worth the trouble, and any plugin may change what it says in chat.
     
Thread Status:
Not open for further replies.

Share This Page