NathanWolf / BukkitPlugins

My plugins for the Bukkit Minecraft server
mine.elmakers.com
14 stars 7 forks source link

PerstistentDaoHelper #41

Closed amkeyte closed 13 years ago

amkeyte commented 13 years ago

in reference to my post about using the Persistance singleton in the data objects

If we wanted to insulate the data classes from the actual persistence plugin then perhaps a singleton class like daoHelper that can be brought in?

public class PersistenceDaoHelper{
    getServer()...
    getWorld(worldName)...
    getBlock(worldName,x,y,z)...
    getPlayer(playerName)...
    ...etc?
}

this would be instantiated in Persistence:

private PersistenceDaoHelper persistenceDaoHelper = null;

....
Persistence.onEnable(){
     persistenceDaoHelper = new  PersistenceDaoHelper(server);
.... 
}   

then in the DAO objects:

  private PersistenceDaoHelper daoHelper =   Persistence.getInstance().getDaoHelper();

 public getBlockThatHasBeenPersisted(){
         org.bukkit.Block bukkitBlock = daoHelper.getBlock(persistedWorldName, persistedX, persistedY, persistedZ)
         return bukkitBlock 
   }

this way it becomes SUPER easy to turn persistable data objects back into their org.bukkit counterparts.

in the example above, of course it's possible to create a new block and return that, but then its not THE block referenced by the game world. I'll make the class if you think this is worth a go-ahead and you want to add it to Persistence. I think it would be a great usability feature.

PS and FYI gonna go have a life. will be offline until tonight. :)

NathanWolf commented 13 years ago

:)

I use Persistence.getInstance()

The plugin (and command framework, global DAO's, etc- some other stuff..) is really the only Bukkit thing in there. The rest of the code is meant to just be a generalized persistence engine- once the plugin starts things up, it's really only in charge of handling commands from users or ops.

Where's my LocationData?? :D

NathanWolf commented 13 years ago

Ooooohh wait

I closed this too prematurely

I see the idea- a layer in between-

Actually, that's kind of the idea with PluginUtilities- that's where Bukkit-centric stuff goes, like accessing player/world data, eventually a Material system, etc.

Sitll not entirely sure if that's what you have in mind, but I think I have a better understanding of your concern now.

amkeyte commented 13 years ago

That's exactly what I have in mind. Although I would consider one of two other options, since the PluginUtilities seems to have a lot of functions not pertaining to the persistence of data, and more toward main plugin functionality.

One option is to make a DataUtilities, which would be basically like what I described above, but with a better naming convention then DaoHelper. Possibly with some common functions that facilitate data perseverance.

A second option could be to use a PersistenceData abstract base class for plugin authors to extend that would include all of these basic helper type functions as private members.

The second option would be a little more "automatic" but would prevent authors from extending another class into a DAO... I'll think on this more.

working on the LocationData btw haha

NathanWolf commented 13 years ago

Well- I wil admit there's some stuff in PluginUtilities that needs to come out, I actually started a Gameplay plugin for that reason. I didn't want Persistence to become "where I put my common stuff".

PluginUtilities is meant to be a plugin-specific instance that helps manage the global DAOs, mainly.

I've always really hated that name- I like DataUtilities a bit better, I think, but it's still too generic for me. I need to think about the name more :)

I think there will actually soon be a Persisted base class, it will be optional to use, but recommended- however, I don't think these kinds of utility functions are the place for that, though, especially since they need to be specific to a particular plugin, and DAO's can be shared.

amkeyte commented 13 years ago

Ok finally getting back to this....

I think we may be talking apples and oranges here. I will cook up some code for you to peruse and see if you like it. It will give me a chance to really work through the problem.

NathanWolf commented 13 years ago

Ok, cool! I may not fully understand what you're getting at here...

amkeyte commented 13 years ago

I have a few peices of code for you to review:

first, the DAO, showing three different methods of getting Location objects: ... //useage of getDataUtilities() private DataUtilities utilities = PersistencePlugin.getInstance().getDataUtilities(); private LocationData origin = null; ...

/**
 * @return the origin
 */
@PersistField(contained = true)
public LocationData getOrigin() {
    return origin;
}

/**
 * shows use of LocationData.toLocation(Location)
 * 
 * Returns the origin as a Location.
 * @param location
 * @return
 */
public Location originToLocation(Location location) {
    return origin.toLocation(location);
}

/**
 * shows use of LocationData.toLocation(server)
 *
 * Returns the origin as a Location
 * @param server
 * @return
 */
public Location originToLocation(Server server) {
    return origin.toLocation(server);
}
/**
 * shows usage of DataUtilities class to access bukkit objects:
 *
 * Returns the origin as a Location
 * @return
 * @throws Exception
 */
public Location originToLocation()
        throws Exception {
    if (utilities == null) {
        throw new Exception("utilities not set");
    }

    String worldName = origin.getWorldData().getName();

    return new Location(
            utilities.getWorld(worldName),
            origin.getBlockX(),
            origin.getBlockY(),
            origin.getBlockZ(),
            origin.getYaw(),
            origin.getPitch());
}
...

Notice that the the last option does not need any parameters to gain access to the instantiated bukkit server object? It is able to create a totally new location by using persisted data -- the name from a WorldData object. This is possible because the DataUtilities class (utilities in this example) provides the referencing needed.

The DataUtilities Class is shown below:

package com.elmakers.mine.bukkit.plugins.persistence;

import org.bukkit.Server;
import org.bukkit.World;
import org.bukkit.block.Block;
import org.bukkit.entity.Player;

/**
 * use this class to provide access to
 * basic bukkit objects within a DAO
 * @author amkeyte
 */
public class DataUtilities {
    private PersistencePlugin plugin = null;
    /**
     * Constructor
     * @param plugin  
     */
    public DataUtilities(PersistencePlugin instance){
        plugin = instance;
    }
    /**
     * Get the server instance
     * @return
     */
    public Server getServer(){
        return plugin.getServer();
    }
    /**
     * get a world instance by name
     * @param name
     * @return
     */
    public World getWorld(String name){
        return getServer().getWorld(name);
    }

    /**
     * get a block by location information
     * @param worldName
     * @param x
     * @param y
     * @param z
     * @return
     */
    public Block getBlock(String worldName, Integer x, Integer y, Integer z){
        return getWorld(worldName).getBlockAt(x, y, z);
    }
    /**
     * get a player instance by name
     * @param playerName
     * @return
     */
    public Player getPlayer(String playerName){
        return getServer().getPlayer(playerName);
    }
}

This class is provided by the PersistencePlugin object by adding this method:

    /**
     * create a DataUtilities instance for use by DAO objects. Allows
     * them to have access to live Bukkit objects.
     * @return
     */
    public DataUtilities getDataUtilities(){
        return new DataUtilities(this);
    }

Hopefully what this shows is that the third method makes it extremely easy and desirable to use a DAO, because it is easy to convert stored data into concrete instances, such as Worlds, Blocks, and possibly others.

Currently, we are required to pass in a reference to such objects (first two methods above, currently used).

I think the DAO should have the responsibility of being able to return the same data type as it is given before it is saved, inherently, and without requiring us to pass in a server instance.

So, hopefully the example clears up what I would like to be able to do.

--Aaron

NathanWolf commented 13 years ago

Hmmm..... let's talk about this... I need to think more... I could still be missing something, I'll give this some real brainpower when I'm awake..

But- first blush- I think I'd rather have a transient "server" in LocationData - something you can set once (or have PluginUtilities set for you, that's the idea with that class) when you first load or create the instance.

Then, you can pass that around in LocationData(LocationData copy) constructors, so you never have to really ever set the Server of a LocationData yourself.

What do you think? I think it would be a lot less code, at least... :D