[RPC] public void RecordAction(string pActionType, string pParametersString)
    {
        string[]        pParameters = pParametersString.Split(',');
        Type            t           = Type.GetType(pActionType);
        RecordingChange c           = (RecordingChange)t.GetConstructors()[0].Invoke(pParameters);

        uRecordingChanges.Add(c);
    }
    /**
     * Jump the current playback to pTime
     */
    public void Jump(float pTime)
    {
        Reset();

        // Then split it into a separate list per object
        Dictionary <string, List <RecordingChange> > partitionedChanges = new Dictionary <string, List <RecordingChange> >();

        foreach (RecordingChange rc in mPlayingPlayer.uRecordingChanges.Where(rc => rc.uTime < pTime))
        {
            mPlayedChanges.Add(rc);
            if (!partitionedChanges.ContainsKey(rc.uID))
            {
                partitionedChanges[rc.uID] = new List <RecordingChange>();
            }
            partitionedChanges[rc.uID].Add(rc);
        }

        foreach (KeyValuePair <string, List <RecordingChange> > kvp in partitionedChanges)
        {
            List <RecordingChange> changes = kvp.Value;

            IEnumerable <RecordingChange> runnableChanges = PerformPropJumpActions(changes);
            if (runnableChanges == null)
            {
                runnableChanges = PerformDialogueJumpActions(changes);
            }

            // now get the last size/zorder/position change and apply it
            Type[] changesToApply = new Type[] { typeof(SizeChange), typeof(ZOrderChange), typeof(PositionChange), typeof(DialogueTextChange), typeof(DialogueTextScaleChange) };

            if (runnableChanges != null)
            {
                foreach (Type t in changesToApply)
                {
                    RecordingChange lastChange = runnableChanges.Where(rc => rc.GetType() == t).OrderByDescending(rc => rc.uTime).FirstOrDefault();
                    if (lastChange != null)
                    {
                        lastChange.run(mPlayingScreen);
                    }
                }
            }
        }

        mTime = pTime;
    }
    IEnumerable <RecordingChange> PerformDialogueJumpActions(List <RecordingChange> changes)
    {
        // Now loop through each one, and find the latest "Create" action, and latest "destroy" action
        RecordingChange lastCreate  = changes.Where(rc => rc.GetType() == typeof(DialogueInstantiationChange)).OrderByDescending(rc => rc.uTime).FirstOrDefault();
        RecordingChange lastDestroy = changes.Where(rc => rc.GetType() == typeof(DestroyChange)).OrderByDescending(rc => rc.uTime).FirstOrDefault();

        // if there is no create - or the destroy is after the create, then we don't do anything
        if (lastCreate == null)
        {
            return(null);
        }

        if (lastDestroy != null && lastDestroy.uTime >= lastCreate.uTime)
        {
            return(null);
        }

        // Run the last create
        lastCreate.run(mPlayingScreen);

        // re-filter the changes to remove any which occured before the creation
        return(changes.Where(rc => rc.uTime >= lastCreate.uTime));
    }