Adding methods to Player

Discussion in 'Plugin Development' started by ShadowDisruptor, Jun 28, 2015.

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

    ShadowDisruptor

    I am trying to add methods to Players that allow you to set and get their balances. From what I found, you need to extend Player and add methods, then cast a player to your new class, but that gave me a ClassCastException. I don't necessarily need my method fixed, just a method to add methods into the Player object. Here is how I tried:
    Code:
    public interface BalPlayer extends Player {
        void setBalance(int balance);
        int getBalance();
    }
    
    Code:
    public abstract class BytePlayerMethods implements BalPlayer {
        private int balance = 0;
    
        public void setBalance(int balance) {
            this.balance = balance;
        }
    
        public int getBalance() {
            return this.balance;
        }
    }
    
    
     
  2. Offline

    tytwining

    1) If there is an error, please include that
    2) Why can't you just make a method to get/set the balance of a player in a config
     
  3. Offline

    ShadowDisruptor

    There will be a lot more methods than just the balance ones, they're just the beginning. If I could add them to the Player object, it would make life a million times easier. I don't think the error is necessarily important, I think I'm doing everything wrong. If you think it is, I'll start up the server again and get it.
     
  4. Offline

    tytwining

    I think it'd be just easier to make a separate class with a ton of methods.
     
  5. Implementing/extends Player does absolutely nothing.. The Player is an interface that is used for the bukkit API. Every online player is assigned a CraftPlayer instance, which implements Player. If you were to create a custom Player instance, it would take forever to edit every single part. Just create some methods or a utility class where you handle all the stuff.
     
    Konato_K likes this.
  6. Offline

    ArmyArmy

    Just make a CustomPlayer class, where you have all the variables needed.
    Example:
    Code:
    import java.util.ArrayList;
    import java.util.Iterator;
    import java.util.List;
    
    import org.bukkit.entity.Player;
    
    public class CustomPlayer {
       private static List<CustomPlayer> registry = new ArrayList<CustomPlayer>();
      
       private Player player;
       private int balance;
      
       public CustomPlayer(Player player, int balance){
         this.player = player;
         this.balance = balance;
       }
    
       public Player getPlayer() {
         return player;
       }
    
       public void setPlayer(Player player) {
         this.player = player;
       }
    
       public int getBalance() {
         return balance;
       }
    
       public void setBalance(int balance) {
         this.balance = balance;
       }
      
       public static void registerPlayer(CustomPlayer customplayer){
         registry.add(customplayer);
       }
      
       public static void unregisterPlayer(CustomPlayer customplayer){
         registry.remove(customplayer);
       }
      
       @SuppressWarnings("rawtypes")
       public static CustomPlayer getPlayer(Player player){
         Iterator iterator = registry.iterator();
         while(iterator.hasNext()){
           CustomPlayer customplayer = (CustomPlayer)iterator.next();
           if(customplayer.getPlayer() == player)
             return customplayer;
         }
         return null;
       }
    }
    
    And when the player joins the game you just register him.
     
    Last edited: Jun 29, 2015
    beyondo and WesJD like this.
  7. @ArmyArmy
    A bit off-topic, but I see you spoonfeeding a lot. That is discouraged on here because people will learn nothing from it.
     
  8. Offline

    Funergy

    @megamichiel @ArmyArmy You know you would need to create everytime a new instance of the CustomPlayer class to actually get the player from the register list with all the values.

    Here is what I mean.

    I registered the player but I want to get the player from another class.
    So I would have to create a new instance since you have your list set private.
    (I dont even see why you would set your list to static since you dont even have a static method using that list.)

    but lets go further, then I should create the new instance
    new CustomPlayer(player,<the players balance but you dont even have his balance because you cant get to the registery list>);

    So I guess your 'spoon feed' doesnt really make sense.
    Why have a list there then? Why not create an extra PlayerManager where you create the list with every custom player classes.
    And why not store UUID's in place of the player itself?
    I'm just thinking logically.

    -Funergy
     
    Last edited: Jun 29, 2015
  9. Offline

    ArmyArmy

    @Funergy Whoops, my bad, those are suposed to be static methods. Going to fix it.
     
    Funergy likes this.
  10. Offline

    ShadowDisruptor

    I know how to make custom objects, this is not what I'm asking. I'm asking if its possible to add methods.
     
  11. Offline

    Ruptur

    @ShadowDisruptor
    Unless you have a custom build of bukkit you cannot add custom methods to Player class.
    This is because CraftPlayer.class implements Player.class not anything else.
    If you want to add methods then the best thing to do is to create custom objects (suggested above)
     
  12. Offline

    Funergy

    @ShadowDisruptor Yes, it is possible to add it to CraftPlayer. I have made this too. I was creating a pet plugin. and I was extending a pig. But ofcourse if you add methods or change some important lines. The pig will NEVER spawn in your world. So this is what I did.

    Code:
    /**
    * Created by Funergy on 19/02/15.
    */
    public class PigPet extends EntityPig{
        public Player player;
        public PigPet(World world) {
            super(world);
        }
        public void setAsPet(Player p){
            this.player = p;
            try {
                Field bField = PathfinderGoalSelector.class.getDeclaredField("b");
                bField.setAccessible(true);
                Field cField = PathfinderGoalSelector.class.getDeclaredField("c");
                cField.setAccessible(true);
                bField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
                bField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
                cField.set(goalSelector, new UnsafeList<PathfinderGoalSelector>());
                cField.set(targetSelector, new UnsafeList<PathfinderGoalSelector>());
    
            } catch (Exception exc) {
                exc.printStackTrace();
            }
            this.goalSelector.a(0, new PathfinderGoalFloat(this));
            this.goalSelector.a(1, new PathfinderGoalWalkToTile(this,2D,this.player));
        }
    If you have this and you spawn it you can firstly use the method and if you want the bukkit entity then it is entity.getBukkitEntity()
     
    Last edited: Jul 2, 2015
  13. Offline

    Konato_K

    @ArmyArmy That's a wrapper, the question is why on earth will you use a List and it's slow iteration to get a player when you can use a Map?
     
  14. Offline

    ArmyArmy

    @Konato_K Does it even matter? I supose he's not going to have like 500 people online on server, so the difference won't even matter.
     
  15. Offline

    Konato_K

    @ArmyArmy It would depend in the amount of players and the times he needs to call this method, scalability is signal of good code, just because you don't have 500 players in a server it doesn't mean all servers don't.
     
    Funergy likes this.
  16. Offline

    Funergy

    @Konato_K @ArmyArmy And ofcourse with the slow iterations and the user may call the methods a lot you will get a Concurrent modification error.
     
  17. Offline

    ArmyArmy

    @Funergy If I'm not mistaken, you won't get Concurrent modification exception when using Iterator.
     
  18. Offline

    1Rogue

    This is inheritence 101, a PigPet is an EntityPig, but an EntityPig might not be a PigPet, so if you cast an "EntityPig" to "PigPet" you will get a CCE in almost all cases.
     
  19. Offline

    Konato_K

    @ArmyArmy This is not truth, you can get a ConcurrentModificationException when iterators if an element is removed in another place, however, the iterator itself is allowed to remove items.
     
  20. Offline

    Funergy

    @1Rogue I have done it and it worked.
    Why cast a PigPet to EntityPig why not do pigPet.getBukkitEntity()

    Code:
    Player p = (Player) sender;
                World mcWorld = ((CraftWorld) p.getWorld()).getHandle();
                PigPet sp = new PigPet(mcWorld);
                sp.setLocation(p.getLocation().getX(), p.getLocation().getY(),
                        p.getLocation().getZ(), p.getLocation().getYaw(), p.getLocation().getPitch());
                ((CraftLivingEntity) sp.getBukkitEntity())
                        .setRemoveWhenFarAway(false);
                mcWorld.addEntity(sp, CreatureSpawnEvent.SpawnReason.CUSTOM);
                sp.setAsPet(p);
                sp.getBukkitEntity().setPassenger(p);
     
  21. Offline

    1Rogue

    Just because it compiles doesn't mean it works.
     
    _Filip and KingFaris11 like this.
  22. Offline

    WesJD

    @ArmyArmy Sort of late here, but just use a singleton for storing your player instances.
     
  23. Offline

    Funergy

    @1Rogue ... I tried it on my test server and it works perfectly fine. I always test my code before I share it... I'm not dumb. I have 3 years of bukkit programming experience
     
  24. Offline

    1Rogue

    Okay, I've been doing java since 2003.

    If you have an object that is initialized as an "EntityPig", and try to downcast it to a subclass, it will throw a CCE.

    Here's a very simple example demonstrating exactly this:

    Code:java
    1. public class Example {
    2.  
    3. public static final void main(String... args) {
    4. Parent p = new Parent();
    5. Child c = (Child) p;
    6. }
    7.  
    8. private static class Parent {};
    9.  
    10. private static class Child extends Parent {};
    11.  
    12. }


    Feel free to run that, and see for yourself. You will run into exactly the same issue casting the parent (EntityPig) class to a child subclass (PigPet)
     
    KingFaris11 likes this.
  25. Offline

    Funergy

    @1Rogue I see what you are saying. But the problem is it worked on my 1.8 spigot server. And I know if you are casting it it will throw a CCE. But I'm not even casting it to EntityPig I'm getting the bukkit entity and that works fine, as you can see on my examples in my post. So lets stop discussing this stupid thing.
     
  26. Offline

    1Rogue

    but that's exactly what you said...

    Java isn't magic, you don't magically bypass standards that have been there almost 20 years.
     
    bobacadodl, KingFaris11 and _Filip like this.
  27. Offline

    _Filip

    very ez u first make a subclass of craft player let's name it "BettaPlaya" and add all methods u want in it
    Then u get an instance of Unsafe, let's name it "unsafe"
    Store the value of the long returned by unsafe.getLong(new BettaPlaya(), 8L) ( if on a 64 bit machine ofc :p) name the var "klassVal"
    Get the Player instance and name it "normalPlayer" then do unsafe.putLong(normalPlayer, 8L, klassVal)
    Now the normalPlayer obj will have the same state as before but different behaviour.

    The problem is that if you are going to use the code in a testing/for fun/experimental environment its perfect and let's you examine and learn how java works "behind the scenes" but there's a reason the class is called "unsafe"
    Basically, you can't safely add methods to a class during runtime and especially by casting to a completely irrelevant subclass.
     
    KingFaris11 likes this.
  28. I feel like this conversation has gone way off topic. The question was if it was possible to add methods to player. But the response is simply only when you modify the server jar. I see people talking about extending the Pig, but that is nothing compared to modifying CraftPlayer/EntityPlayer. The only way possible without modifying the jar is creating a custom class that handles everything, and that can easily be done without help from others, if he does need help he should google it since it has nothing to do with bukkit.
     
  29. Offline

    Funergy

    oh lol
    EDIT: I changed that line now. lol
     
Thread Status:
Not open for further replies.

Share This Page