Teleportation Help

Discussion in 'Plugin Development' started by Dthen, Sep 26, 2011.

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

    Dthen

    I am attempting to create a plugin which teleports the player to random location on their first join. My code in my PlayerListener currently looks like this:

    Code:
    package dthen.randomspawn;
    
    
    
    import org.bukkit.event.player.PlayerLoginEvent;
    import org.bukkit.entity.HumanEntity;
    import org.bukkit.entity.Player;
    import java.io.File;
    import java.util.Random;
    
    	
    public class RandomSpawnPlayerListener
    {
    	public void onPlayerLogin(PlayerLoginEvent event)
    	{
    			File playerDat = new File("world/players/"+ event.getPlayer()+ ".dat");
    			if(!playerDat.exists())
    		{
    				
    				Random r = new Random();
    				double minRange = (-45000.0);
    				double maxRange = (45000.0);
    				double x = (minRange + (maxRange - minRange) *r.nextDouble());
    				double z = (minRange + (maxRange - minRange) *r.nextDouble());
    				Player player = event.getPlayer();
    		player.teleport(x,0.0,z);
    		}
    	}
    }
    I know this isn't correct as Eclipse is telling me it's wrong, but I'm not sure how to make it right.

    If anyone could tell me how to do this properly, that would be lovely.
    Also, if anyone could tell me the best way to make sure the player spawns on the surface & not underground, that would be excellent.

    I know I should also probably make it read the minimum & maximum distances from a config file, but I haven't looked into how to do that yet.

    Thanks in advance, Dthen.
     
  2. Get a random int between 1 and 45000.
    Code:java
    1. Random generator = new Random();
    2. int randX = generator.nextInt(45000) + 1,
    3. randZ = generator.nextInt(45000) + 1;

    For configuration files I suggest you look at my huge plugin tutorial on the wiki.
     
  3. Offline

    Dthen

    Thanks, that helps a little, Although I believe it would need to be between -45000 & 45000.

    The biggest issue I'm having is the line with "player.teleport(x,0.0,z);", though.
    Eclipse claims "The method teleport(Location) in the type Entity is not applicable for the arguments (double, double, double)".
     
  4. You need to specify a world also so :
    player.teleport(player.getWorld(), x,0.0,z);
     
  5. Offline

    Dthen

    Oh, I see!
    Considering it's onPlayerLogin, though, would they be in a world yet?

    EDIT: Eclipse now says "The method teleport(Location) in the type Entity is not applicable for the arguments (World, double, double, double)".

    Not sure what I'm doing wrong.
     
  6. Offline

    Feed_Dante

    You need something like:
    teleport(new Location(world, x, y, z))

    If you need the world try something like:
    event.getPlayer().getWorld()

    Note: Done from memory, I might be wrong (Check the API if somethings off)
     
  7. Offline

    Dthen

    Ooh, I think that may just have worked! Thank you very much.
    A couple more questions for anyone who may know the answers:
    How would I change a player's respawn point (not the world's)?
    How would I determine whether or not a location is on the surface so as to know whether or not to teleport the player there?
     
  8. You need to use on player join. Or at least you should.
     
  9. Offline

    Dthen

    Is there any way to detect if it is the first time a player is joining the server using on player join?
    If there is, I'll change it, but I was looking around & other similar threads seemed to indicate that wasn't possible.
     
  10. Offline

    desht

    Your plugin could maintain a persistent list of all players, which it reads on enable, and saves on disable (and possibly at other times too to avoid data loss). If the player in the PLAYER_JOIN event isn't in the list, it must be their first time joining, so add them to the list, and teleport them. I would recommend using a HashSet for your internal datastructure - much better performance as the list of players grows.

    By the way, do you really mean to teleport them to the Y co-ordinate 0.0? That's at bedrock level. Check out the world.getHighestBlockAt(x,z) method to get the surface level.
     
  11. Offline

    Dthen

    No, I don't mean to do that, that was just a placeholder until I worked out the best way to spawn them on the surface, which you have just provided me with. Thanks. Although that tells me that "world could not be resolved". I'm not sure how to fix that, although I think I understand the problem.

    I considered maintaining a consistent list of players, but I have to say that sounds scarily difficult.
    Is it is as difficult as it sounds?
     
  12. Offline

    desht

    The easiest way to get the world is just to use player.getWorld().

    Not really. Maintain a HashSet object somewhere (a field in your main plugin class might be simplest). Your onEnable() method will load a file on startup which can just be a simple list of player names, one per line. Each of those names get placed in your HashSet with the add() method.

    Then your onPlayerJoin() method can check the HashSet with containsKey() to see if the player has been seen before. If not, teleport him, and also add him to the HashSet (again, the add() method).

    Finally you'll need to write out the HashSet to the same file you loaded from. You can do this in the onDisable() method, but there is a risk - if the server crashes or exits abnormally, this might not happen. You can also write the HashSet whenever it's updated (from onPlayerJoin()) but on a busy server with people logging in frequently, this might lead to excessive disk usage, hurting performance. It's a bit of a balancing act.

    The other useful class here is the Bukkit Configuration class, which is useful for loading/saving data other than just configuration data. There's a section about it in Adamki11s's big tutorial.
     
  13. Offline

    Feed_Dante

    A HashMap seems like overkill when your current code:
    Code:
    File playerDat = new File("world/players/"+ event.getPlayer()+ ".dat");
    if(!playerDat.exists())
    seems to me like the best solution.

    Is there some reason you wish to avoid this method? Is there some problem with it?
     
  14. Offline

    Dthen

    Well, currently I can't use player.getWorld() to specify the world using that code, because it has to be done on login, not on join. If there is another way to specify the world, that would work as well.
     
  15. Offline

    Feed_Dante

    It all depends on when username.dat is created.

    Given the 3 'login' events:
    • onPlayerPreLogin
    • onPlayerLogin
    • onPlayerJoin
    In which event can you safely teleport a player, and at what point in the process is username.dat created? Before or after said event?

    If username.dat is created after then checking for username.dat should work just fine.

    If username.dat is created before then you'd have to check in an earlier event and, if they're new, add them to a HashMap. then durring whatever event you can teleport from, check the HashMap.
    In this way you wouldn't need to worry about saving/loading the HashMap as it's only purpose would be as a placeholder for tansfering wether or not they're a new player from an earlier event to the teleport safe event.


    Breakdown of PlayerJoinEvent, PlayerPreLoginEvent and PlayerLoginEvent:
    http://forums.bukkit.org/threads/br...ayerpreloginevent-and-playerloginevent.37992/


    EDIT:
    Teleport API: http://jd.bukkit.org/apidocs/org/bukkit/entity/Entity.html#teleport(org.bukkit.Location)

    Your teleport options are either:
    boolean teleport(Entity destination)
    or:
    boolean teleport(Location location)

    You could also try player.getLocation().setX()/setY()/setZ()
    (Location API: http://jd.bukkit.org/apidocs/org/bukkit/Location.html)

    Although if you can't use player.getWorld() (As it may be to early in the login process for them to even be in a world) I would think that player.getLocation() would give the same result. (An NPE I assume?)
     
  16. Offline

    Dthen

    According to this thread, you would be correct. Although the poster in that thread appears to have a solution. I'm not sure if I'm competent to implement that, though. :(
     
  17. Offline

    Feed_Dante

    Heh, didn't expect that lol; I'm glad I guessed right.

    Buy yes, his solution is exactly what I described; the code's even there as-well (Modified slightly):
    Code:java
    1. public static Map<Player, boolean> newPlayers = new HashMap<Player, boolean>();
    2.  
    3. public void onPlayerJoin(PlayerJoinEvent event) {
    4. Player p = event.getPlayer();
    5. if (newPlayers.contains(p)) {
    6. p.teleport(new Location(p.getWorld(), x, y, z)); //Insert new location here
    7. newPlayers.remove(p); //Remove the player to prevent a memory leak
    8. }
    9. }
    10.  
    11. public void onPlayerLogin(PlayerLoginEvent event) {
    12. File playerDat = new File("world/players/" + event.getPlayer().getName() + ".dat");
    13. if(!playerDat.exists()) {
    14. newPlayers.add(event.getPlayer());
    15. }
    16. }

    EDIT:
    Don't be afraid to try, thats a great way to learn! (At least for me.)

    Anyways, I'm off to bed; Good luck!
     
  18. Offline

    desht

    Heh, good idea. Completely forgot about the player dat files.
     
Thread Status:
Not open for further replies.

Share This Page