Time Rewizer

Published by mark on

Time Rewizer (Plugin)

The Idea of this project came out of another project i was working on. Click Here to view it. This plugin allows for easy and lightweight rewinding of objects or variables. this plugin is really useful for people who want to have easy and quick results.

Features

Animation rewinding
Position and rotation rewinding
Internal script variable rewinding
Easy Api
Highly customizalble, and easy to build on top
Baking of animations
Baking of position and rotations
Baking internal script variables
Custom Serializer

Included Plugins:
GenericEditor

Use cases

Reasons why you would use this plugin are for optimization, core mechanic, easy replaying of physics.

Screenshots

Trailer video

Techinical Information

Used Patterns

  1. Factory( Builder & Abstract Factory & Factory Method)
  2. Dependency Injection
  3. Singleton
  4. Prototype
  5. Decorator
  6. Observer
  7. Memento
  8. Chain Responsibility

Personal Thoughts

This project has been a very nice learning experience for me. In this project I’ve learned many new patterns and ways to write code. Both in an data oriented manner and some new ways in OOP. this project I’ve worked on in my free time mostly, this project really came in as an ambition to make something difficult and fun. I will continue to work on the project from time to time, and expand on some parts of the project to make them standout.

Links

Gource progression video

Small video of my repository activity while making this plugin, this is a part of it, not the full.

Sample Code

This piece of sample code is the code responsible for opening editor windows capable of interacting with cache objects from the plugin.

    using System;
using System.Collections.Generic;
using UnityEditor;
using UnityEngine;

namespace MarkOostveen.TimeRewizer.Editor.Baking
{
    public static partial class EditorRewizeSystemUtility
    {
        /// 
        ///     Starts window of given type.
        ///     please give all listed types below to setup editor window for baking
        ///     T0: Type of window being outputted
        ///     T1: Baker type used
        ///     T2: Type of Cache Object used
        ///     T3: Setting type being used
        ///     T4: Properties type Used by baker
        ///     T5: Properties type being used to save data by Cache object
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static (ScriptableBake bake, T0 Window) InitializeEditorWindow
        (string scriptableSettingsName, T1 bakertarget, string type, PropertyConversion conversionMethod, Action ClearCallBack,
            Func> loadOverwrite = null, Action startupAction = null)
            where T0 : EditorWindow, IBakeWindow //output window
            where T1 : MonoBehaviour, IBaker //baker
            where T2 : ScriptableObject, ICache //CacheType
            where T3 : ScriptableObject, ISetting //setting type
            where T4 : IProperties, ICloneable //baker properties
            where T5 : IProperties //cache properties
        {
            EditorRewizerDebug.Log("Finding cache ");
            //Get Corresponding cache
            T2 cache = GetCache(bakertarget.gameObject, type);
            EditorRewizerDebug.Log("Loading Asset Data");

            //Loading Asset Data
            if (loadOverwrite != null)
            {
                loadOverwrite.Invoke(cache, bakertarget);
            }
            else
            {
                bakertarget.Snapshots = new List();
                for (int i = 0; i < cache.Snapshots.Count; i++)
                    bakertarget.Snapshots.Add((T4)conversionMethod.Execute(cache.Snapshots[i]).Clone());
            }

            EditorRewizerDebug.Log("Creating Save Function");

            //Saving Asset
            void BakertargetSave(string objectname)
            {
                T2 saveCache = GetCacheobj(objectname, type);

                saveCache.Snapshots.Clear();

                for (int i = 0; i < bakertarget.Snapshots.Count; i++)
                    saveCache.Snapshots.Add(conversionMethod.ReversedExecute((T4)bakertarget.Snapshots[i].Clone()));

                SaveDirtyObject(saveCache);
            }

            bakertarget.Save = BakertargetSave;
            EditorRewizerDebug.Log("Linking bake object");

            //inject scriptable object into baker
            bakertarget.BaseBaker = new BaseBaker();
            bakertarget.BaseBaker.Initialize(bakertarget);

            EditorRewizerDebug.Log("Starting Window of Type " + typeof(T0));

            return (GetBake(bakertarget.gameObject.name),
                StartWindow(scriptableSettingsName, bakertarget, startupAction, ClearCallBack));
        }

        /// 
        ///     Get the singleton window of window type
        /// 
        /// 
        /// 
        public static T SingletonWindow() where T : EditorWindow
        {
            EditorRewizerDebug.Log("Getting Window of type: " + typeof(T));

            T[] windows = Resources.FindObjectsOfTypeAll();

            return windows.Length > 0 ? windows[0] : null;
        }

        /// 
        ///     T is output window
        ///     T1 is input for attached baker script
        ///     T2 is settings that need to be used for this window
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static T StartWindow(string scriptableSettingsName, T1 attachedscript, Action startupAction, Action ClearBakeCallBack)
            where T : EditorWindow, IBakeWindow
            where T1 : MonoBehaviour, IBaker
            where T2 : ScriptableObject, ISetting
        {
            EditorRewizerDebug.Log("Obtaining Window Settings of type " + typeof(T2));

            T2 scriptableobjectinstance = GetSetting(scriptableSettingsName);

            if (scriptableobjectinstance == null)
            {
                EditorRewizerDebug.Log("Can't find settings of: " + typeof(T2) + " creating a new one...");
                scriptableobjectinstance = CreateScriptableSettings(scriptableSettingsName);
            }

            T window = SingletonWindow();

            if (window == null)
            {
                EditorRewizerDebug.Log("No Window Active of type " + typeof(T) + ", instantiating a new one.");
                window = EditorWindow.GetWindow(true, scriptableSettingsName);
            }

            EditorRewizerDebug.Log("Initializing Window of type " + typeof(T));

            window.titleContent = new GUIContent(scriptableSettingsName);
            window.Initialize(attachedscript);
            if (window is IRecorder)
                ((IRecorder)window).Recording = scriptableobjectinstance.Recording;

            window.Clear = ClearBakeCallBack;
            window.WindowStartup(startupAction);
            window.Show();

            return window;
        }

        /// 
        ///     T: SnapshotType
        ///     T1: Recorder type and type of window
        ///     T2: Baker Type
        ///     T3 ComponentType
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        /// 
        public static void StartStopRecording(T1 window, GameObject attachedobj)
            where T : ISnapShot
            where T1 : IRecorder, IBakeWindow
            where T2 : MonoBehaviour, IBaker
            where T3 : MonoBehaviour, IRecordAble
        {
            if (window.Recording && Application.isPlaying)
            {
                EditorRewizerDebug.Log("Initialized Recording on " + attachedobj.name, attachedobj.transform);
                //subscribe
                T3 rewinding = attachedobj.GetComponent();
                rewinding.OnTracked += window.Record;
            }
            else if (!Application.isPlaying)
            {
                //desubscribe
                T3 rewinding = attachedobj.GetComponent();
                rewinding.OnTracked -= window.Record;
            }
        }

        /// 
        ///     Check recording checkmark of a settings object
        /// 
        /// 
        /// 
        /// 
        public static bool CheckRecordingState(string settingsscriptableobjectname)
            where T0 : ScriptableObject, ISetting
        {
            T0 settings = GetSetting(settingsscriptableobjectname);

            return settings.Recording;
        }

        /// 
        ///     Returns if settings script indicates it needs to be started on launch
        /// 
        /// 
        /// 
        /// 
        public static bool CheckActiveState(string settingsscriptableobjectname)
            where T0 : ScriptableObject, ISetting
        {
            T0 settings = GetSetting(settingsscriptableobjectname);

            return settings.Active;
        }
    }
}
  
Categories: HighlightPlugins