Reddit-Mud / RMUD

A MUD written in C# using the fantastique literary genre, started by redditors.
MIT License
25 stars 8 forks source link

@Blecki Can you walk me through how GetOrCreateInstance works? #97

Closed ConstableBrew closed 10 years ago

ConstableBrew commented 10 years ago

For the life of me, I can't figure out how Mud.GetOrCreateInstance() works its magic.

Blecki commented 10 years ago

Sure can, though I expect you'll be disappointed by the lack of magic.

public static MudObject GetOrCreateInstance(String Path, String InstanceName, Action<String> ReportErrors = null)
        {
//Okay, so the function is 'GetOrCreateInstance', but it's not terribly clear what's expected to happen. 
//We gave it the path to an object, and the name of an instance of that object.
//The expectation is that an instance of that object will be returned. 
//If it doesn't have one with that name, it will make a new one.

            Path = Path.Replace('\\', '/');  // All we're doing here is sanitizing the path so it works consistently across windows and linux.
            var baseObject = GetObject(Path, ReportErrors); // We try and get the base object.

            //We can't make an instance of nothing; this means that the base object has an error of some kind.
            if (baseObject == null) return null; 

            //Create the new instance of the same class as the base type.
                        //Nothing special - just some reflection to create a new instance of the C# class.
            var assembly = baseObject.GetType().Assembly;
            var newMudObject = Activator.CreateInstance(baseObject.GetType()) as MudObject;

            //It should not be possible for newMudObject to be null.
                        //It actually is possible if the type to be instanced lacks a default constructor. 
            if (newMudObject != null)
            {
                newMudObject.Path = Path; //The new object's path doesn't change.

                //The 'Get' part of GetOrCreate is some database magic - if this instance exists in the database,
                //automatically hook up to it. If not, the database should create a new entry for it.
                newMudObject.Instance = InstanceName; // 'magic'.

                                // All that's left is to initialize the object we created.
                newMudObject.Initialize(); 
                newMudObject.State = ObjectState.Alive;
                newMudObject.HandleMarkedUpdate();
                return newMudObject;
            }
            else
            {
                throw new InvalidProgramException();
            }
        }

No magic. It just creates an object of the right type and sets the Path and Instance properties. Now, here is the magic...

Inside it's Initialize function, an object with persistent features calls 'this.GetDTO()'.

public DTO GetDTO()
        {
            //Use the name 'Path@Instance' to fetch data from the dynamic database.
            // If Instance is null or empty, the resulting name is 'Path@'. This is the
            // name non-instanced objects can use to store data in the dynamic
            // database.
            return Mud.LoadDTO(Path + "@" + Instance);
        }

So the path and instance properties that GetOrCreateInstance set are combined to get the name of the persisted data.

At this point, we still haven't actually created anything persistent. Mud.LoadDTO finally kinda does that...

var filename = DynamicPath + Path + ".txt";
            if (!System.IO.File.Exists(filename)) return null;
            var file = System.IO.File.OpenText(filename);

...by returning null if the persisted instance asked for doesn't exist already. Then the persistent object could create it's own DTO and save it.

There is one terrible flaw in this system: Calling GetOrCreateInstance twice with the same instance name won't get the same instance. It will get two instances with identical names, competing for the same persistent resource.

ConstableBrew commented 10 years ago

I appreciate the walk through. I thought that multiple instances were being created, but your comment about magic had me firmly believing I was missing something! I didn't have the time to do some debugging to see it all happen and validate my thoughts.

Blecki commented 10 years ago

Already obsolete! New version doesn't have that flaw I pointed out. Check it out in the latest commit to the db branch.