Solved Storing entities in a list and getting entities by UUID

Discussion in 'Plugin Development' started by JRL1004, Dec 9, 2013.

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

    JRL1004

    I don't have my IDE up and it takes age to load so I can't supply the exact code yet but the gist of my first question is this: I have a HashSet<UUID> call entities where I am storying any entities I need. Here is an example (not the actually method so ignore any mistakes in it):
    Code:java
    1. public HashSet<UUID> entities = new HashSet<UUID>;
    2. @EventHandler
    3. public void onMove(EntityMoveEvent e) {
    4. if(!(e.getEntity() instanceof LivingEntity)) return;
    5. UUID mobID = e.getEntity().getUniqueId();
    6. if(!entities.contains(mobID)) enities.add(mobID);
    7. return;
    8. }

    I was wondering if there is a more efficient way to store the entities and if storing an entities UUID could somehow cause a memory leak (I'm a tad paranoid about those).

    My second question is this: How could I get an entity that is stored in a list if I only have it's UUID? I don't want to store then Entity itself because I feel it will cause leaks similar to storing a player (E.g. if the mob's chunk is meant to be unloaded or the mob is killed).

    Also, for those wondering, I am storing the mobs for use later on (duh), my idea is that when a command is issued, a random one of these mobs will be teleported to the player who issued the command.
     
  2. Offline

    NathanWolf

    I think a HashSet is your best bet for you to store them. You don't need to call contains() first before adding add(), HashSet will guarantee uniqueness for you.

    A UUID is an int, so you don't have to worry *too* much about running out of memory- but if you get the opportunity to clear this list every once in a while that would not be a bad thing. Because otherwise it might grow forever.

    Unfortunately I'm not aware of a way to get an entity by UUID, I think you have to loop through all the entities in the world and look for the one you want. Unless someone has set up a clever way of caching them on spawn and removing them on despawn that doesn't leak memory, but I haven't seen it :)

    Oh, I just realized you're doing this on move.. yeah there's got to be a better way, like entity spawn.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
  3. Offline

    JRL1004

    NathanWolf The onMove is just an example, the actually method uses PlayerInteractEntityEvent (or whichever one is called when a player right-clicks a mob, I can't remember and my laptop is slow to load Eclipse (I've been booting it for the past 5 minutes)).
     
  4. Offline

    The_Doctor_123

    JRL1004
    I think he means that if he stores a UUID reference, it may prevent the GC from throwing away the Entity. My guess is that it's a copy, however, it does not say that. Try testing to see if a memory leak occurs.
     
  5. Offline

    JRL1004

    The_Doctor_123 How would I got about catching if a leak occurs? I know how to avoid them but not how to catch if they are occurring.
     
  6. Offline

    The_Doctor_123

    JRL1004
    You can't really catch them, besides looking at your memory usage and seeing if it's abnormal. Even if you could detect them, what would do? It would require a code modification to fix.
     
  7. Offline

    JRL1004

    The_Doctor_123 Well, my computer is crap and memory usage never goes below 90% - 95% so everything looks normal (usage wise). I'll just assume is does and hope a kind soul on the forums can give me a better way of doing this while I tinker about with the code and try to improve upon what exists.

    EDIT: Do you have any ideas about how to get the stored mob?
     
  8. Offline

    The_Doctor_123

    JRL1004
    I meant checking the JVM's usage inside the code itself. Quite honestly, though, I don't think it's going to cause a memory leak. If you'd like to take a precaution, copy the UUID.
     
  9. Offline

    NathanWolf

    We may be talking about two different things- I meant that a "UUID" for an Entity is literally an int:

    http://jd.bukkit.org/rb/apidocs/org/bukkit/entity/Entity.html#getEntityId()

    So you definitely don't have to worry about the GC not collecting entities if that's all your storing. (I assumed your code up there was psuedo-code from your comments - if there is some actual UUID class then I may be wrong here)

    And what I meant by cleaning the list was, bukkit will generate new entity id's constantly so your list will grow forever if you don't do something to clean it up every once in a while. A list of ints growing won't consume massive memory, but it's just something to be aware of.
     
  10. Offline

    JRL1004

    NathanWolf I made the a method for getting the mob by UUID but it's fairly server-intense. Here is the method:
    Code:java
    1. public Entity getMob(UUID id) {
    2. for(World w : getServer().getWorlds())
    3. {
    4. for(Entity e : w.getEntities())
    5. {
    6. if(!e.getUniqueId().equals(id)) continue;
    7. return e;
    8. }
    9. }
    10. return null;
    11. }

    It cycles through all the server's world and each mob in each world. Can you think of any better ways of doing this? I thought of using a HashMap<UUID, World> and just checking that world but notice that it would fail if the mod changed worlds (say it went through a nether portal).
     
  11. Offline

    NathanWolf

    Huh, I was totally confused by the UUID thing. I've never used them in Bukkit before- what makes that "persistent" versus just the entity's id? I thought entity ids were persistent across reloads, but maybe not? Anyway, I'm just curious about this part since this is new to me.

    In either case, unfortunately I think searching is the only way.

    The only other option I can think of would be to try and track entities yourself- as in catch when they spawn and despawn, and keep a map of UUID to Entity. But you would have to make sure you remove them when they despawn or you'd be causing some leaking. I'm honestly not sure whether this is possible or a good idea, I'm hoping someone with more experience in mob spawning can help out.. I'm mostly a block guy :)
     
  12. Offline

    The_Doctor_123

    NathanWolf
    I don't think they're persistent upon restarts.
     
    NathanWolf likes this.
  13. Offline

    JRL1004

    NathanWolf Because I how I have it set up, the UUIDs are lost on reload/restart but I don't want to go through making a config for it (or even using the getConfig()) because mobs are removed on restart (I believe) and that would require me to find a way for the plugin to know if the server is shutting down or restarting.
     
  14. Offline

    The_Doctor_123

    JRL1004
    There's a way to prevent mobs from despawning when chunks are unloaded.
     
    NathanWolf likes this.
  15. Offline

    NathanWolf

    Wow, good to know- sorry about my confusion there, and thanks for the info.

    So I guess since there's no reliable Entity or Creature despawn event, you can't really track them on your own (without potentially leaking them).

    I guess you could try tracking them on spawn, and then periodically go through your list and purge entities that are no longer isValid()?

    Definitely sounds tricky and messy.. sorry I'm not more help!

    EDIT: Heh, or what The_Doctor said - sometimes there's a tremendously easier way. Sounds like you'd still have to track them, though, if you want to do anything other than prevent them from despawing?
     
  16. Offline

    JRL1004

    The_Doctor_123 NathanWolf Couldn't preventing every mob that is on the list from despawning lead to an overabundance of creatures roaming about? Even if I clear out any mobs on the list that are not valid, eventually all the mobs that are not permitted to despawn will pile up. I'm hoping to store them but to prevent despawns would make the server seem more like a sort of minecraft wildlife preserve. Also, How would I go about making it so players can damage the mobs but the mobs can't die (without giving all the mob resistance 5 or something)? I know how to do it with EntityDamageEvent but I don't want to make and register a new class if it's not needed (as yes I would have to register it since I put each eventlistener in it's own class).

    My issue seems to be reasonably solved so I'll make this thread as so, however addition help is still nice to have and up to anyone who wants to decide whether or not to provide it.

    EDIT by Moderator: merged posts, please use the edit button instead of double posting.
     
    Last edited by a moderator: Jun 5, 2016
Thread Status:
Not open for further replies.

Share This Page