Domanda

I've been creating a prototype for a modern MUD engine. A MUD is a simple form of simulation and provide a good method in which to test a concept I'm working on. This has led me to a couple of places in my code where things, are a bit unclear, and the design is coming into question (probably due to its being flawed). I'm using model first (I may need to change this) and I've designed a top down architecture of game objects. I may be doing this completely wrong.

What I've done is create a MUDObject entity. This entity is effectively a base for all of my other logical constructs, such as characters, their items, race, etc. I've also created a set of three meta classes which are used for logical purposes as well Attributes, Events, and Flags. They are fairly straightforward, and are all inherited from MUDObject.

The MUDObject class is designed to provide default data behavior for all of the objects, this includes deletion of dead objects. The automatically clearing of floors. etc. This is also designed to facilitate this logic virtually if needed. For example, checking a room to see if an effect has ended and deleting the the effect (remove the flag).

public partial class MUDObject
{
    public virtual void Update()
    {
        if (this.LifeTime.Value.CompareTo(DateTime.Now) > 0)
        {
            using (var context = new ReduxDataContext())
            {
                context.MUDObjects.DeleteObject(this);
            }
        }            
    }

    public virtual void Pause()
    {

    }

    public virtual void Resume()
    {

    }

    public virtual void Stop()
    {

    }        
}

I've also got a class World, it is derived from MUDObject and contains the areas and room (which in turn contain the games objects) and handles the timer for the operation to run the updates. (probably going to be moved, put here as if it works would limit it to only the objects in-world at the time.)

public partial class World
{
    private Timer ticker;


    public void Start()
    {
        this.ticker = new Timer(3000.0);
        this.ticker.Elapsed += ticker_Elapsed;
        this.ticker.Start();
    }

    private void ticker_Elapsed(object sender, ElapsedEventArgs e)
    {
        this.Update();
    }

    public override void Update()
    {
        this.CurrentTime += 3;
        // update contents
        base.Update();
    }

    public override void Pause()
    {
        this.ticker.Enabled = false;
        // update contents
        base.Pause();
    }

    public override void Resume()
    {
        this.ticker.Enabled = true;
        // update contents
        this.Resume();
    }

    public override void Stop()
    {            
        this.ticker.Stop();
        // update contents
        base.Stop();
    }
}

I'm curious of two things.

  1. Is there a way to recode the context so that it has separate ObjectSets for each type derived from MUDObject?

    • i.e. context.MUDObjects.Flags or context.Flags
    • If not how can I query a child type specifically?
  2. Does the Update/Pause/Resume/Stop architecture I'm using work properly when placed into the EF entities directly? given than it's for data purposes only?

    • Will locking be an issue?
    • Does the partial class automatically commit changes when they are made?
    • Would I be better off using a flat repository and doing this in the game engine directly?
È stato utile?

Soluzione

1) Is there a way to recode the context so that it has separate ObjectSets for each type derived from MUDObject?

Yes, there is. If you decide that you want to define a base class for all your entities it is common to have an abstract base class that is not part of the entity framework model. The model only contains the derived types and the context contains DbSets of derived types (if it is a DbContext) like

public DbSet<Flag> Flags { get; set; }

If appropriate you can implement inheritance between classes, but that would be to express polymorphism, not to implement common persistence-related behaviour.

2) Does the Update/Pause/Resume/Stop architecture I'm using work properly when placed into the EF entities directly?

No. Entities are not supposed to know anything about persistence. The context is responsible for creating them, tracking their changes and updating/deleting them. I think that also answers your question about automatically committing changes: no.

Elaboration:

I think here it's good to bring up the single responsibility principle. A general pattern would be to

  • let a context populate objects from a store
  • let the object act according to their responsibilities (the simulation)
  • let a context store their state whenever necessary

I think Pause/Resume/Stop could be responsibilities of MUD objects. Update is an altogether different kind of action and responsibility.

Now I have to speculate, but take your World class. You should be able to express its responsibility in a short phrase, maybe something like "harbour other objects" or "define boundaries". I don't think it should do the timing. I think the timing should be the responsibility of some core utility which signals that a time interval has elapsed. Other objects know how to respond to that (e.g. do some state change, or, the context or repository, save changes).

Well, this is only an example of how to think about it, probably far from correct.

One other thing is that I think saving changes should be done not nearly as often as state changes of the objects that carry out the simulation. It would probably slow down the process dramatically. Maybe it should be done in longer intervals or by a user action.

Altri suggerimenti

First thing to say, if you are using EF 4.1 (as it is tagged) you should really consider going to version 5.0 (you will need to make a .NET 4.5 project for this)

With several improvements on performance, you can benefit from other features also. The code i will show you will work for 5.0 (i dont know if it will work for 4.1 version)

Now, let's go to you several questions:

Is there a way to recode the context so that it has separate ObjectSets for each type derived from MUDObject? If not how can I query a child type specifically? i.e. context.MUDObjects.Flags or context.Flags

Yes, you can. But to call is a little different, you will not have Context.Worlds you will only have the base class to be called this way, if you want to get the set of Worlds (that inherit from MUDObject, you will call:

var worlds = context.MUDObjects.OfType<World>();

Or you can do in direct way by using generics:

var worlds = context.Set<World>();

If you define you inheritance the right way, you should have an abstract class called MUDObjects and all others should iherit from that class. EF can work perfectly with this, you just need to make it right.

Does the Update/Pause/Resume/Stop architecture I'm using work properly when placed into the EF entities directly? given than it's for data purposes only?

In this case i think you should consider using a Design Pattern called Strategy Pattern, do some research, it will fit your objects.

Will locking be an issue?

Depends on how you develop the system....

Does the partial class automatically commit changes when they are made?

Did not understand that question.... Partial classes are just like regular classes, thay are just in different files, but when compiled (or event at Design-Time, because of the vshost.exe) they are in fact just one.

Would I be better off using a flat repository and doing this in the game engine directly?

Hard to answer, it all depends on the requirements of the game, deploy strategy....

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top