Solved Saving player data

Discussion in 'Plugin Development' started by poo2thegeek, Apr 4, 2013.

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

    poo2thegeek

    For a plugin I'm writing, I wish to save a Serializable object called "Alliance". But the problem with this is that it contains Lists of the objects "Player" and "Chunk", and so when I try to save it using the following code:

    Code:
        public void saveBlue(Alliance blue) throws Exception{
            log.info("Starting to save blue...");
            File filePath =plugin.getDataFolder();
            if(!filePath.exists()){
                log.info("File path does not exist, creating it...");
                filePath.mkdirs();
                filePath.createNewFile();
            }log.info("Got file path, attempting to get file...");
            File file = new File(plugin.getDataFolder() + "/blue.data");
            if(!file.exists()){
                log.info("File doesnt exist, creating it...");
                file.createNewFile();
                log.info("created it!");
            }
       
            log.info("Starting output stream...");
            FileOutputStream blueSave = new FileOutputStream(file);
            // Write object with ObjectOutputStream
            ObjectOutputStream blueSaveOut = new ObjectOutputStream (blueSave);
            log.info("Created output stream");
            log.info("Attempting to write object...");
            // Write object out to disk
            blueSaveOut.writeObject (blue);
            log.info("Finished saving blue!");
        }
    as soon as a player joined that object, I get the error "java.io.NotSerilaizableException" because of "org.bukkit.craftbukkit.v1_5_R2.entity.CraftPlayer"

    From what I know, this basicly means that the object "Player" is not serializable. So what I want to know is, how can I save this object? Here is the entire alliance object:
    Code:
    public class Alliance implements Serializable{
        OwnedLand home;
        List<OwnedLand> ownedLand;
        List<Player> players;
        String name;
     
        public String getName(){
            return name;
        }
     
        public Alliance(String name){
            this.name=name;
            ownedLand = new ArrayList<OwnedLand>();
            players = new ArrayList<Player>();
        }
        public OwnedLand getOwnedLand(Chunk chunk){
            for(int i=0; i<ownedLand.size();i++){
                if(ownedLand.get(i).getChunk()==chunk){
                    return ownedLand.get(i);
                }
            }
       
            return null;
        }
        public void addPlayer(Player player){
            players.add(player);
        }
        public List<OwnedLand> getAllOwnedLand(){
            return ownedLand;
        }
        public Chunk getHome(){
            return home.getChunk();
        }
     
        public List<Player> getPlayers(){
            return players;
        }
     
        public void claimLand(Chunk chunk){
            ownedLand.add(new OwnedLand(chunk, this, 1));
        }
     
        public void removeLand(Chunk chunk){
            for(int i=0; i<ownedLand.size();i++){
                if(ownedLand.get(i).getChunk()==chunk){
                    ownedLand.remove(i);
                }
            }
        }
     
    }
    
    I've heard that I can use SLQ databases, but I've never used them before and don't know how they work (so if I have to use them a link to a tutorial would be nice). So I would much rather use vanilla java/bukkit if I could.

    Thanks alot!

    EDIT:
    Just a question, could I do this by making a class called "Aplayer" make that extend player and implement serializable, and just save my object as that instead? Its still the same as the player object- but now savable?
     
  2. Offline

    NoLiver92

    this is the link for a tutorial in mysql

    You cannot save an array to .dat files its not serialized (had problem on my plugin). The way i solved it was to make yml files for each save. in your case you could make a diffrent yml file for each alliance rather then a .dat file.

    a database could be easier to do but if the link to the database is broken, your plugin will break
     
  3. Offline

    zajacmp3

    Or maybe easier... You can write it in any format you wish.
    I will just point that your object is defined by these values:
    Code:
        OwnedLand home;
        List<OwnedLand> ownedLand;
        List<Player> players;
        String name;
    You can just write them to file line by line, and in reading this file recreate an object.

    @EDIT:

    I do suggest using a writer by the way. Problem with all this is that there are a lot more data strings to be written to file with other stuff like Player or OwnedLand.

    And that is why I would not really want to do this at all.
     
  4. Offline

    poo2thegeek

    But how would I save a value for these things in a .yml file?
    I would have to save an entire list of player objects (probably many players large), I would have to save a list of OwnedLand objects (a class I made that is made up of an Alliance, Chunk, and integer).
    Also, with my sql, can I save an entire object? Or is it just for saving small things?

    Thanks

    zajacmp3
    Sorry, I dont quite understand, whats a writer? And why would you not want to do this at all?

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

    zajacmp3

    My method is quite simple and slow in this case. Writer is like a writer used to writing text to files

    my example used today - that's why it poped up in my mind.
    Code:
        public void writeStatistics() throws IOException{
            FileWriter fw = new FileWriter("plugins/stat.dat");
            BufferedWriter out = new BufferedWriter(fw);
            for(int t = 0 ; t < dbp.size() ; t++){
                out.write(dbp.get(t)+" "+dbdm.get(t)+" "+dbdp.get(t)+" "+dbk.get(t)+(char)13);
            }        
            out.close();
            fw.close();
        }
    And why I would not want to do this at all? Cause I am lazy and this writing every parameter down in a file and its long and boring. And in your case not the best solution probably but easiest and without lots of thinking. Also you would have to make an method that would read all these things in correct order and afterwards recreate other objects like Player OwnedLand etc. and after a lot of operations you would finally get you object - Alliance. It is not the best method.

     
  6. Offline

    poo2thegeek

    yeah, That method would work, but as you say- its very long winded and inefficient. Im sure there must be some way of doing it, mainly because the plugin "factions" saves things like the players power- and it must save it somewhere, though im not sure where.
     
  7. Offline

    NoLiver92

    heres the code to create seperate yml files:

    Declare this:
    Code:
    private File PlayerDataFile;
        private FileConfiguration PlayerDataConfig;
    Then paste this in your event:
    Code:
    PlayerDataFile = new File("plugins/myplugin/Players/"+playername+".yml");
            PlayerDataConfig = new YamlConfiguration();
    this was to save a yml for every player, but replace playername whatever string variable on which you want the file to be named.

    this is how to create sections but only if the file did not exist:
    Code:
    if(!PlayerDataFile.exists())
            {
                try
                {
                    PlayerDataConfig.save(PlayerDataFile);
                    PlayerDataConfig.createSection("Nick Name");
                    PlayerDataConfig.createSection("Level");
                    PlayerDataConfig.createSection("IP");
                    PlayerDataConfig.createSection("Jointime");
                    Playe//add more or less to fit your needs
                    PlayerDataConfig.save(PlayerDataFile);
                }
                catch (IOException e)
                {
    }
    }
    to set values to the file:
    Code:
    PlayerDataConfig.set("Nick Name", playername);
    to get values from the yml, do something like this:
    Code:
    PlayerDataConfig.getString("Nick Name")
    the get string will have many options depending on what you want.

    You can use this like any config file which means you can save nearly everything that you would want to save easily and quickly. E.G. you can save an itemstack as an itemstack rather then splitting it up.

    This is based on what i have used and have working. If you would like me to explain more i will.
     
  8. Offline

    WolfGangSen

    Just a note.
    Its recommended that you don't store "Player" objects.
    Its generally much easier and less buggy to store their names and retrieve the player object when absolutely necessary.

    it's rather unproblematic as the name is unique.

    By store I don't mean in your save file. I mean in your lists arrays etc.
     
  9. Offline

    poo2thegeek

    WolfGangSen
    Thanks lol. I litteraly just relized this and I am starting to re-write my plugin to use the name instead. I assume I can do this with any objects like "Chunk" (just save the integers needed to make it). And this will work as long as any variables in the object are serilaizable?
     
  10. Offline

    WolfGangSen

    just store the co-ordinate integers for the chunk

    make your own serializable class if you need to

    ChunkCor or something that just stores xyz of the chunk.

    I think that chunks have y co-ords seeing as they were changed to be 16 x 16 x 16 cubes and stacked up and down

    someone tell me if I'm wrong plz.
     
  11. Offline

    NoLiver92

    poo2thegeek. You should be able to as most objects like location for example can be broken into world, x, y and z then put back into the location. BUT you have to make sure you save the basic data needed to recreate the object, otherwise this would cause an error which can be hard to spot
     
  12. Offline

    poo2thegeek

Thread Status:
Not open for further replies.

Share This Page