Clarifying of player

Discussion in 'Spigot Plugin Development' started by seyfahni, Jun 3, 2015.

  1. I've just read in the Spigot API Javadoc and found some interesting contrariness:
    The org.bukkit.entity.Player interface "represents a player, connected or not", as the API states but you can't get access to a player-object using the OfflinePlayer method getPlayer() or the static method Bukkit.getPlayer(String name).

    Is the interface Player only available for online players? And what happens if a player leaves, while I'm working with its Player-Object? If the interface also supports offline players, why can I not get a Player-Object with an OfflinePlayer?

    I'm a bit confused about this, because until now I thought that the Player interface is an OnlinePlayer. Has anyone an idea, how the Player and the OfflinePlayer are supposed to work?
     
  2. Afaik, the only way to get a player object (via the normal api) is when the player is online. In that sense you can mostly think of it as an online player class.

    However, If you still have a strong reference to a player object when that player logs out, the object can not be cleared from memory, so it persists, but the isOnline() method will return false.

    For this reason it's not recommended to store player objects as it can easily create memory leaks. The safest way to store a player is to save their uuid and retrieve the player object from the sever using that uuid when needed.
     
    • Informative Informative x 1
  3. Storing player objects in memory isn't a good idea, however you can store a HashMap of <String, String> that has <Name, UUID> which allows you to easily get players that are offline and then load them into memory using some classes you can find on the forums.

    On my server, I store all players that join the server in a SQL table. That way I can load them whenever I need them.
     
  4. I created this post to make people think about this contrariness in the API Javadoc, not to ask for help or tips how to use the Player interface. And until now, I never stored a Player-Object permanently and also I used a database with a users-table that stored the name, the UUID and a local player-id for easier use in our plugin.
    Can you give reasons for this? Justify it with code or a statement in the Javadoc? I worked with the same strategy and now I was very confused and before posting, I really searched for a statement like "represents an online player" in the Javadoc.

    So what does "returns: a player object if one was found, null otherwise" form the getPlayerExact(String name) and the getPlayer(UUID id) mean? Does it also return a Player-Object, if they are offline? There is no statement like "This method may not return objects for offline players." as it is in the getPlayer(String name) method.

    As far as I think almost everyone uses the Player interface for online players and the OfflinePlayer interface for (obviously) the offline players. But if the Player interface like it is said in the Javadoc may be used for offline players too, there could be many possibilities. Or it would throw an Exception when calling methods like openInventory()?
     
  5. There's nothing wrong with storing Player references, as long as you clean them up when the Player leaves.
    Found == online, basically. So it returns null for users which aren't online.As far as I think almost everyone uses the Player interface for online players and the OfflinePlayer interface for (obviously) the offline players. But if the Player interface like it is said in the Javadoc may be used for offline players too, there could be many possibilities. Or it would throw an Exception when calling methods like openInventory()?[/QUOTE]It's likely that it will not do anything. Afaik in most (if not all) methods it first checks if there is a live connection, and returns if otherwise.

    UUIDs and Strings (names) generate memory leaks just as fast. Thus the following does not quite hold (as there is no safest way)
     
  6. How does storing UUIDs and Strings generate memory leaks...

    In my 2+ years of programming in this community, I've never had memory leaks from storing UUID references... This allows for

    Code (Text):

    //where playerObj.getUUID() is a reference to the UUID of the player.
    Player p = Bukkit.getPlayer(playerObj.getUUID());
     
    versus the following (which causes memory leaks/logical errors)
    Code (Text):

    //where playerObj.getPlayer() is a reference to the type Player.
    Player p = Bukkit.getPlayer(playerObj.getPlayer())
     
    In reference to OP:
    You should store the UUID (since that's the unique identifier of a player) in another object and retrieve a Player via UUID.
     
    #6 Hyphenical, Jun 4, 2015
    Last edited: Jun 4, 2015
  7. Just because you can't see them does not mean they don't exist ;). If you have an UUID in your Map (because you never clean up the entries), and the player never joins again, it's there until you disable the plugin (which should reset the Map, Player and UUID alike).

    Memory leaks occur until the point that you manage your memory properly :p. There's nothing wrong with storing Players if you do manage your memory properly.

    (Counter note for the 2+ years experience: 6-7 years experience with various languages, including mother-of-all languages C, which cleans up not a single pointer)
     
  8. The conversation is about what to store as @iArthur states, and @seyfahni asks whats the justifications for storing UUID/String vs Player.

    As for referencing my development experience in THIS community, it's not a knock on your skills, its simply an allusion that I've not had issues storing UUID (in contrast to Player) -- so let's not have a pissing contest.
     
  9. Hence I give a counter argument as to why using Player keys is fine. It's also faster.
    (you were the one who started with '2+ years of experience though'...)
     
  10. Player keys can be outdated though -- you should always remove those references when a player leaves, similarly you should remove the UUID references. However, storing Strings or UUIDs are smaller in terms of bytes and therefore aren't as difficult to look up.

    Also how do you think that storing a 'player' reference is faster? Just because you can put it in a hash map? Then what's the key for the mapping?

    Again, I brought up the 2+ years of experience as an allusion to the problem (UUID vs Player). If I wanted to have a pissing contest about it, I would just show you the B.A.

    - back to the original author:
    - Yes you would get a null pointer as an offline player will not have an inventory.
     
  11. I'd assume, because the player object is already there and you don't have to call an extra method?
     
  12. But the object is volatile, so why would you store a volatile object?
    Say for example one of your PlayerQuitEvents ends up throwing a null pointer because of some OTHER code. The player is no longer purged from your container, and now your Player reference is a dead reference.
     
  13. Then check your reference before using it
     
  14. Sigh, the misinformation on this thread is baffling...

    TL;DR @DarkSeraphim is completely right.

    Anyway lets talk about how stupid some of you sound. First off, you do realize nearly everything in java works with references? When a player key changes somewhere, it changes everywhere.

    The amount of data used to store a Player is already on your damned server, storing a player's name or their uuid turned into a string is just stupid. You're actively using extra data for no reason what so ever.

    And you don't think storing and looking up a player is faster? Then you really don't know what the hell you're talking about. References are looked up with their place in the memory, if its the same place, its the same object. Do you know how strings are compared? They literally compare every letter by every letter...

    Please stop spewing retarded advice
    on these forums.
     
    • Like Like x 1
    • Agree Agree x 1
  15. Heard of WeakKeys?
     
  16. Since you guys are misinterpreting what I mean when I say we should store UUID/Player, let's take a look at an example.

    Let's say we have the following class:
    Code (Text):

    // this class can hold stats and further plugin specific info
    public class BasePlayer {
        //which field serves as a better key to call grab a player?
        private UUID uuid;
        private Player player;

        public UUID getUuid() {
            returnuuid;
        }

        public Player getPlayer() {
            returnplayer;
        }
    }
     
    Which is better:
    - Player p = Bukkit.getPlayer(BasePlayer.getUuid());
    or just
    - Player p = BasePlayer.getPlayer();

    (ignore private in this case)

    This example is what I'm getting at.
     
  17. There's always try-finally.
    direct Player field is faster.
     
    • Agree Agree x 1
  18. Obviously BasePlayer#player ._.
     
  19. This post.

    "UUID's will be required whenever you store information about a player for long term. For example, if you wanted to store the number of times a player has logged into the server, you should use UUID because the next time the player logs in, it could be a different user name."

    This is the same for Player vs UUID.
    You should use UUID because the next time the player logs in, it IS a different Player (object).
     
  20. If you're caching and not removing your cache after the player logs out, you're doing it wrong...

    Sigh...