implement Player?

Discussion in 'Plugin Development' started by keelar, Dec 8, 2011.

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

    keelar

    How would I go about implementing Player that way I can add some custom Player methods? Obviously I know how to implement it, but it gets nothing but errors when I try to use the class that implements it. Any help would be appreciated.

    In case anyone was wondering the error says: java.lang.ClassCastException: org.bukkit.craftbukkit.entity.CraftPlayer cannot be cast to me.keelar.CLPlayer

    And this is where I get the error:
    Code:
    CLPlayer player = (CLPlayer) sender;
     
  2. Offline

    mindless728

    you may want to include CraftBukkit and not Bukkit as a dependency for your project, then your custom class should probably extend CraftPlayer (org.bukkit.craftbukkit.entity.CraftPlayer) instead, this way you don't have to rewrite every function in Player
     
  3. Offline

    coldandtired

    Try extending Player instead of implementing it.
     
  4. Offline

    keelar

    Neither worked :( Still get the ClassCastException.
     
  5. Offline

    matter123

    because you cant cast craftplayer to your coustun player think about it
    public class object{
    //more stuff
    }
    public class Car extends object {
    //car related stuff such as drive
    }
    object o=new object();
    Car c=(Car)o;
    who would that ever work?
     
  6. Offline

    bergerkiller

    @keelar just so you know; THIS is not possible:
    Code:
    Player player = event.getPlayer();
    CustomPlayer myplayer = (CustomPlayer) player;
    Neither Player nor CraftPlayer extend or implement 'CustomPlayer', so there is no way for Java to convert it. Your only option is to replace the player in total; which is exactly what Spout does already. And believe me, even replacing a Minecart entity is a huge hassle. I recommend adding those methods in a separate class instead.

    Your other option is to directly change the 'CraftPlayer' class entity in CraftBukkit. For this the server needs the special CraftBukkit build you have to maintain yourself. Solving that using CraftBukkit is simple:
    Code:
    public class CraftPlayer implements Player extends CustomPlayer {
        //craftbukkit code here
    }
     
  7. Offline

    keelar

    Okay, well thanks for letting me know.
     
  8. Offline

    Evenprime

    What you probably want to do is cast it to CraftPlayer by doing:

    Code:
    CraftPlayer player = (CraftPlayer) sender;
    
    This may not always work as there is no guarantee that everything that implements "Player" is indeed a "CraftPlayer" object (usually it is though). "CraftPlayer" already provides some more methods that you can use to manipulate the player. If you need even more direct access, do:

    Code:
    CraftPlayer player = (CraftPlayer) sender;
    EntityPlayer entityPlayer = player.getHandle();
    
    "EntityPlayer" is the actual minecraft object that represents the player. Using that directly will lead to:

    * Your code breaking on the next Minecraft update (very likely)
    * You causing data corruption or other strange problems (maybe)

    So only do that if there is absolutely no way to do what you want by just using "Player".

    ----

    All those are things that defeat the purpose of Bukkit being an API for generic interaction with Minecraft servers. What you could do instead is to wrap the "Player" object into your own object, if all you want is to have some convenience methods for working with "Player".

    Code:
    public class FancyPlayer {
    
      private Player player;
    
      public FancyPlayer(Player player) {
        this.player = player;
      }
    
      public Player getPlayer() {
        return player;
      }
    
      // Now define your fancy convenience methods
      public void somethingCool( ... ) {
        player.something(...);
        player.somethingElse(...);
        player.somethingAgain(...);
      }
    
      public void somethingFunny( ... ) {
        // you get the idea
      }
    
      // and so on
    }
    
    In your event listeners you'd then only do:

    Code:
    FancyPlayer fancyPlayer = new FancyPlayer(player);
    
    fancyPlayer.somethingCool(...);
    fancyPlayer.somethingFunny(...);
    
    // and when you need to access methods of the encapsulated Player object, you'd access it like this
    fancyPlayer.getPlayer().someStandardPlayerMethod(...);
    
    That's a pretty neat and clean way of "improving" Player with additional methods.
     
    leon3001 likes this.
  9. Offline

    matter123

    its perfectly possible
    1) do what spout does and use reflection to replace
    2)have custom player implement player and take a craft player in the args and delegate the methods

    2 is much more widely supported
     
  10. Offline

    Evenprime

    The problem with 1) is that only one plugin can do that. If somebody besides Spout tried to do that, it would no longer work.

    Doing 2) seems to me like an overkill. Unless someone plans to give his custom player object back to Bukkit such that Bukkit has to work on it (which would pretty much lead to situation 1) again, it is more reasonable to write a simple wrapper and access the wrapped "Player" when necessary directly.
     
  11. Offline

    matter123

    after looking at yours, 2 and yours are pretty much the same except that you can make bukkit calls directly on fancyplayer and use it where Player is expected.
    also 2 allows you to change some methods
     
  12. Offline

    keelar

    I want to be able to give all players a unique integer like how each player has a unique getTicksLived() method. I want to be able to temporarily store integers(until the server restarts) for each player without having to use a config. What would be an easy way to do this?
     
  13. Offline

    halley

    All entities already have a unique ID, but that ID is retired when the entity dies (the player is unloaded) and is probably not the same when the same player returns on next log-in.

    If you want to invent a GUID for each player, go for it. Store it in a separate place.

    All of the Spout-like or reflection tricks to supplant an instance are pretty dangerous (likely to have bugs on its own, likely to have bugs in conflict with other plugins, and likely to have more bugs as Bukkit refactors itself over time). Reflection is useful for debugging. Reflection sometimes makes it possible, but not advisable, to modify things that you didn't write. (If Minecraft set up a security model on their class loader, this would be less possible, but also incur overhead.)

    The basic principle should be: if Minecraft invokes new Player(), then Minecraft should be able to rely on that reference to that class; and if Bukkit/BukkitCraft invokes new CraftPlayer(), then Bukkit/BukkitCraft should likewise be able to rely on it.

    Instead, just maintain yourself some kind of companion class that you keep things like special identifiers and special methods. "Loose coupling" is an important concept in software design. Sheltering and being responsible for your own data are big part of loose coupling.
     
  14. Offline

    keelar

    Temp config it is then! lol
     
  15. Offline

    bergerkiller

    @matter123 Mind the 'THIS', it points to the lines below. Of course it is possible to use custom Player implementations, but as mentioned before:
    - Will hard-break with Spout
    - Requires you to replace the Player every time the player teleports, joins, etc.
    - It is a HUGE pain to replace the Player wherever it is referenced. It is references from the server to every single event possible, and hooking an event right before the Player changes is a tricky situation.

    With minecarts this is pretty simple: if you need a MinecartMember you simply destroy the previous minecart and spawn your own implementation. But with players you have a lot of attached data:
    - Inventory
    - Pointers to netserverhandler
    - Cross-ways pointers, such as world <> player and server <> player
    - Have to make sure the player doesn't notice it (packet issues - invisible players - physics issues)
    The only true way is if you do what Spout does: pretty much hook into every class and modify.

    And, adding to that, it decreases the resistance of your plugin. TrainCarts breaks on pretty much every MC/Bukkit build because all field names change all the time, although I don't think it's that bad with a Player, which is of Bukkit.
     
  16. Offline

    matter123

    thats why i suggested using option 2 which wraps around a craft player and delegates calls but also gives you a chance to step in
     
  17. Offline

    Evenprime

    If you just want a unique ID to identify players, why not simply use the player's name? It doesn't get more unique than that, as Minecraft ensures that a player always has the same name, between server restarts and even on other servers.
     
Thread Status:
Not open for further replies.

Share This Page