private void buildAudioTracks(ProgressBar progress, PlayableDirector director, TimelineAsset timeline)
        {
            var audioData    = GetComponentsInChildren <RecordedAudio>(includeInactive: true);
            var sourceToData = audioData.Query().ToDictionary(a => a.target, a => a);

            progress.Begin(sourceToData.Count, "", "Building Audio Track: ", () => {
                foreach (var pair in sourceToData)
                {
                    var track = timeline.CreateTrack <AudioTrack>(null, pair.Value.name);
                    director.SetGenericBinding(track.outputs.Query().First().sourceObject, pair.Key);

                    progress.Begin(pair.Value.data.Count, "", "", () => {
                        foreach (var clipData in pair.Value.data)
                        {
                            progress.Step(clipData.clip.name);

                            var clip       = track.CreateClip(clipData.clip);
                            clip.start     = clipData.startTime;
                            clip.timeScale = clipData.pitch;
                            clip.duration  = clipData.clip.length;
                        }
                    });
                }
            });
        }
Пример #2
0
        public static void SimpleTest()
        {
            var progressBar = new ProgressBar("Simple Test");

            progressBar.Begin(5, "[5]");
            for (int i = 0; i < 5; i++)
            {
                progressBar.Begin(4, "[4]");
                for (int j = 0; j < 4; j++)
                {
                    progressBar.Begin(3, "[3]");
                    for (int k = 0; k < 3; k++)
                    {
                        System.Threading.Thread.Sleep(100);
                        if (progressBar.Update(1) == true)
                        {
                            break;
                        }
                    }
                    progressBar.End();

                    progressBar.Update(1);
                }
                progressBar.End();

                progressBar.Update(1);
            }
            progressBar.End();
        }
Пример #3
0
        private AnimationClip generateCompressedClip(ProgressBar progress)
        {
            var clip = new AnimationClip();

            var bindingMap = new Dictionary <EditorCurveBinding, AnimationCurve>();
            var recordings = GetComponentsInChildren <RecordedData>(includeInactive: true);

            progress.Begin(2, "", "", () => {
                progress.Begin(recordings.Length, "", "Compressing: ", () => {
                    for (int i = 0; i < recordings.Length; i++)
                    {
                        progress.Begin(2, "", "", () => {
                            var recordingData = recordings[i];

                            progress.Step(recordingData.name);

                            var toCompress = new Dictionary <EditorCurveBinding, AnimationCurve>();

                            progress.Begin(recordingData.data.Count, "", "", () => {
                                foreach (var bindingData in recordingData.data)
                                {
                                    progress.Step(recordingData.name + " : " + bindingData.propertyName);

                                    Type type = recordingData.GetComponents <Component>().
                                                Query().
                                                Select(c => c.GetType()).
                                                Concat(typeof(GameObject)).
                                                FirstOrDefault(t => t.Name == bindingData.typeName);

                                    if (type == null)
                                    {
                                        //If could not find the type, the component must have been deleted
                                        continue;
                                    }

                                    var binding         = EditorCurveBinding.FloatCurve(bindingData.path, type, bindingData.propertyName);
                                    toCompress[binding] = bindingData.curve;
                                }
                            });

                            doCompression(progress, recordingData, toCompress, bindingMap);
                        });
                    }
                });

                progress.Begin(bindingMap.Count, "", "Assigning Curves: ", () => {
                    foreach (var binding in bindingMap)
                    {
                        progress.Step(binding.Key.propertyName);
                        AnimationUtility.SetEditorCurve(clip, binding.Key, binding.Value);
                    }
                });
            });

            return(clip);
        }
        private void buildMethodRecordingTracks(ProgressBar progress, PlayableDirector director, TimelineAsset timeline)
        {
            var recordings = GetComponentsInChildren <MethodRecording>();

            if (recordings.Length > 0)
            {
                progress.Begin(recordings.Length, "", "Building Method Tracks: ", () => {
                    foreach (var recording in recordings)
                    {
                        progress.Step(recording.gameObject.name);

                        try {
                            var track = timeline.CreateTrack <MethodRecordingTrack>(null, recording.gameObject.name);
                            director.SetGenericBinding(track.outputs.Query().First().sourceObject, recording);

                            var clip = track.CreateClip <MethodRecordingClip>();


                            clip.duration = recording.GetDuration();
                        } catch (Exception e) {
                            Debug.LogException(e);
                        }
                    }
                });
            }
        }
Пример #5
0
        /// <summary>
        /// Инициализация поля
        /// </summary>
        /// <param name="zoom">Зум поля</param>
        /// <param name="progress">Прогресс инициализации</param>
        /// <param name="input">Управление игроком</param>
        /// <param name="debug">Отладка</param>
        public void Init(ZoomControl zoom, ProgressBar progress, IPlayerInput input, IGameDebug debug)
        {
            // Подпишемся на изменения зума
            _zoom = zoom;

            _input = input;

            // Инициализируем случайные значения положения игрока на поле и его рейтинг
            _currentCellPosition     = SettingsAccess.GetRandomFieldPosition();
            _currentCellItemPosition = SettingsAccess.GetRandomCellPosition(_currentCellPosition);
            _playerRating            = NoiseTool.GetRandomPlayerRating();

            // Инициализируем коллекцию ячеек
            _cells = new CellCollection(_playerRating);

            // Инициализируем механизм поиска первых <see cref="SettingsAccess.MaxAdvancedVisiblePlanet"/> планет, ближайших по рейтингу к рейтингу игрока
            _sortedCellsVisitor = gameObject.AddComponent <SortedCellsVisitor>().Init(_cells, _playerRating, debug);
            _sortedCellsVisitor.OnProcessEnd += OnSearchTopRatingsEnd;

            string generationString;

            if (SystemInfo.supportsComputeShaders)
            {
                // Если поддерживаются Computed Shader
                _generator = gameObject.AddComponent <ComputedShaderNoiseGenerator>()
                             .SetDebug(debug);

                generationString = "GENERATE COMPUTED SHADER";
            }
            else
            {
#if (UNITY_ANDROID)
                // По идее, должен поддерживаться большинством платформ, добавлять директивы препроцессора по мере тестирования
                _generator = gameObject.AddComponent <CustomRenderTextureNoiseGenerator>()
                             .SetDebug(debug);

                generationString = "GENERATE RENDER TEXTURE";
#else
                // Для всех остальных платформ.
                _generator = gameObject.AddComponent <CpuNoiseGenerator>()
                             .SetDebug(debug);

                generationString = "GENERATE CPU";
#endif
            }

            _generator.OnProcessEnd += OnGenerationEnd;

            // Добавим первое задание на генерацию всего поля
            _generator.AppendRect(SettingsAccess.GetFieldRectPx(_currentCellPosition));

            // Отобразим прогресс
            progress.Begin(() => _generator.GetProgress(), generationString, OnEndInit);
        }
Пример #6
0
    public IEnumerator AttackCoroutine()
    {
        progressBar.Begin(attackTime);

        ChangeState(State.attack);

        yield return(new WaitForSeconds(attackTime));

        foreach (HitboxAttackManager hitbox in hitboxes)
        {
            hitbox.OnAttackTriggerReceived();
        }

        ChangeState(State.stagger);
        yield return(new WaitForSeconds(attackCooldown));

        ChangeState(State.idle);
    }
Пример #7
0
        protected void finishRecording(ProgressBar progress)
        {
            string targetFolderPath = targetFolder.Path;

            if (targetFolderPath == null)
            {
                if (gameObject.scene.IsValid() && !string.IsNullOrEmpty(gameObject.scene.path))
                {
                    string sceneFolder = Path.GetDirectoryName(gameObject.scene.path);
                    targetFolderPath = Path.Combine(sceneFolder, "Recordings");
                }
                else
                {
                    targetFolderPath = Path.Combine("Assets", "Recordings");
                }
            }

            int    folderSuffix = 1;
            string finalSubFolder;

            do
            {
                finalSubFolder = Path.Combine(targetFolderPath, recordingName + " " + folderSuffix.ToString().PadLeft(2, '0'));
                folderSuffix++;
            } while (Directory.Exists(finalSubFolder));

            string dataDirectory = Path.Combine(finalSubFolder, "_Data");

            Directory.CreateDirectory(dataDirectory);
            Directory.CreateDirectory(finalSubFolder);
            AssetDatabase.Refresh();

            progress.Begin(6, "Saving Recording", "", () => {
                if (!_isRecording)
                {
                    return;
                }
                _isRecording = false;

                //Turn on auto-pushing for all auto-proxy components
                foreach (var autoProxy in GetComponentsInChildren <AutoValueProxy>())
                {
                    autoProxy.autoPushingEnabled = true;
                }

                progress.Begin(3, "", "Reverting Scene State", () => {
                    //For all of our transform data, revert to the first piece recorded
                    progress.Begin(_transformData.Count, "", "", () => {
                        foreach (var pair in _transformData)
                        {
                            progress.Step();
                            var transform = pair.Key;
                            var data      = pair.Value;

                            if (transform == null || data.Count == 0)
                            {
                                continue;
                            }

                            data[0].ApplyTo(transform);
                        }
                    });

                    //For all recorded curves, revert to start of curve
                    progress.Begin(_curves.Count, "", "", () => {
                        AnimationClip tempClip = new AnimationClip();
                        foreach (var data in _curves)
                        {
                            progress.Step();
                            AnimationUtility.SetEditorCurve(tempClip, data.binding, data.curve);
                        }
                        tempClip.SampleAnimation(gameObject, 0);
                    });

                    //For all non-transform components, revert to original serialized values
                    progress.Begin(_initialComponentData.Count, "", "", () => {
                        foreach (var pair in _initialComponentData)
                        {
                            progress.Step();
                            var component = pair.Key;
                            var sobj      = pair.Value;

                            if (component == null || component is Transform)
                            {
                                continue;
                            }


                            //We don't want to revert method recordings!
                            if (component is MethodRecording ||
                                component is RecordedAudio)
                            {
                                continue;
                            }

                            var flags = sobj.FindProperty("m_ObjectHideFlags");
                            if (flags == null)
                            {
                                Debug.LogError("Could not find hide flags for " + component);
                                continue;
                            }

                            //We have to dirty the serialized object somehow
                            //apparently there is no api to do this
                            //all objects have hide flags so we just touch them and revert them
                            int originalFlags = flags.intValue;
                            flags.intValue    = ~originalFlags;
                            flags.intValue    = originalFlags;

                            try {
                                //Applies previous state of entire component
                                sobj.ApplyModifiedProperties();
                            } catch (Exception e) {
                                Debug.LogError("Exception when trying to apply properties to " + component);
                                Debug.LogException(e);
                            }
                        }
                    });
                });

                progress.Begin(1, "", "Patching Materials: ", () => {
                    GetComponentsInChildren(true, _recorders);
                    foreach (var recorder in _recorders)
                    {
                        DestroyImmediate(recorder);
                    }

                    //Patch up renderer references to materials
                    var allMaterials = Resources.FindObjectsOfTypeAll <Material>().
                                       Query().
                                       Where(AssetDatabase.IsMainAsset).
                                       ToList();

                    var renderers = GetComponentsInChildren <Renderer>(includeInactive: true);

                    progress.Begin(renderers.Length, "", "", () => {
                        foreach (var renderer in renderers)
                        {
                            progress.Step(renderer.name);

                            var materials = renderer.sharedMaterials;
                            for (int i = 0; i < materials.Length; i++)
                            {
                                var material = materials[i];
                                if (material == null)
                                {
                                    continue;
                                }

                                if (!AssetDatabase.IsMainAsset(material))
                                {
                                    var matchingMaterial = allMaterials.Query().FirstOrDefault(m => material.name.Contains(m.name) &&
                                                                                               material.shader == m.shader);

                                    if (matchingMaterial != null)
                                    {
                                        materials[i] = matchingMaterial;
                                    }
                                }
                            }
                            renderer.sharedMaterials = materials;
                        }
                    });
                });

                progress.Begin(_behaviourActivity.Count, "", "Converting Activity Data: ", () => {
                    foreach (var pair in _behaviourActivity)
                    {
                        var targetBehaviour = pair.Key;
                        var activityData    = pair.Value;

                        if (targetBehaviour == null)
                        {
                            continue;
                        }

                        progress.Step(targetBehaviour.name);

                        string path         = AnimationUtility.CalculateTransformPath(targetBehaviour.transform, transform);
                        Type type           = targetBehaviour.GetType();
                        string propertyName = "m_Enabled";

                        AnimationCurve curve = new AnimationCurve();
                        foreach (var dataPoint in activityData)
                        {
                            int index = curve.AddKey(dataPoint.time, dataPoint.enabled ? 1 : 0);
                            AnimationUtility.SetKeyLeftTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                            AnimationUtility.SetKeyRightTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                        }

                        if (curve.IsConstant())
                        {
                            continue;
                        }

                        var binding = EditorCurveBinding.FloatCurve(path, type, propertyName);

                        if (_curves.Query().Any(c => c.binding == binding))
                        {
                            Debug.LogError("Binding already existed?");
                            Debug.LogError(binding.path + " : " + binding.propertyName);
                            continue;
                        }

                        _curves.Add(new CurveData()
                        {
                            binding = binding,
                            curve   = curve
                        });
                    }
                });

                progress.Begin(_transformData.Count, "", "Converting Transform Data: ", () => {
                    foreach (var pair in _transformData)
                    {
                        var targetTransform = pair.Key;
                        var targetData      = pair.Value;

                        progress.Step(targetTransform.name);

                        string path = AnimationUtility.CalculateTransformPath(targetTransform, transform);

                        bool isActivityConstant = true;
                        bool isPositionConstant = true;
                        bool isRotationConstant = true;
                        bool isScaleConstant    = true;

                        {
                            bool startEnabled        = targetData[0].enabled;
                            Vector3 startPosition    = targetData[0].localPosition;
                            Quaternion startRotation = targetData[0].localRotation;
                            Vector3 startScale       = targetData[0].localScale;
                            for (int i = 1; i < targetData.Count; i++)
                            {
                                isActivityConstant &= targetData[i].enabled == startEnabled;
                                isPositionConstant &= targetData[i].localPosition == startPosition;
                                isRotationConstant &= targetData[i].localRotation == startRotation;
                                isScaleConstant    &= targetData[i].localScale == startScale;
                            }
                        }

                        for (int i = 0; i < TransformData.CURVE_COUNT; i++)
                        {
                            string propertyName = TransformData.GetName(i);
                            Type type           = typeof(Transform);

                            AnimationCurve curve = new AnimationCurve();
                            var dataType         = TransformData.GetDataType(i);

                            switch (dataType)
                            {
                            case TransformDataType.Position:
                                if (isPositionConstant)
                                {
                                    continue;
                                }
                                break;

                            case TransformDataType.Rotation:
                                if (isRotationConstant)
                                {
                                    continue;
                                }
                                break;

                            case TransformDataType.Scale:
                                if (isScaleConstant)
                                {
                                    continue;
                                }
                                break;

                            case TransformDataType.Activity:
                                if (isActivityConstant)
                                {
                                    continue;
                                }
                                type = typeof(GameObject);
                                break;
                            }

                            for (int j = 0; j < targetData.Count; j++)
                            {
                                int index = curve.AddKey(targetData[j].time, targetData[j].GetFloat(i));
                                if (dataType == TransformDataType.Activity)
                                {
                                    AnimationUtility.SetKeyLeftTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                                    AnimationUtility.SetKeyRightTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                                }
                            }

                            var binding = EditorCurveBinding.FloatCurve(path, type, propertyName);

                            if (_curves.Query().Any(c => c.binding == binding))
                            {
                                Debug.LogError("Duplicate object was created??");
                                Debug.LogError("Named " + targetTransform.name + " : " + binding.path + " : " + binding.propertyName);
                            }
                            else
                            {
                                _curves.Add(new CurveData()
                                {
                                    binding = binding,
                                    curve   = curve
                                });
                            }
                        }
                    }
                });

                progress.Begin(_curves.Count, "", "Compressing Data: ", () => {
                    _curves.Sort((a, b) => a.binding.propertyName.CompareTo(b.binding.propertyName));
                    foreach (var data in _curves)
                    {
                        using (new ProfilerSample("A")) {
                            EditorCurveBinding binding = data.binding;
                            AnimationCurve curve       = data.curve;

                            progress.Step(binding.propertyName);

                            GameObject animationGameObject;
                            {
                                var animatedObj = AnimationUtility.GetAnimatedObject(gameObject, binding);
                                if (animatedObj is GameObject)
                                {
                                    animationGameObject = animatedObj as GameObject;
                                }
                                else
                                {
                                    animationGameObject = (animatedObj as Component).gameObject;
                                }
                            }

                            bool isMatBinding = binding.propertyName.StartsWith("material.") &&
                                                binding.type.IsSubclassOf(typeof(Renderer));

                            //But if the curve is constant, just get rid of it!
                            //Except for material curves, which we always need to keep
                            if (curve.IsConstant() && !isMatBinding)
                            {
                                //Check to make sure there are no other matching curves that are
                                //non constant.  If X and Y are constant but Z is not, we need to
                                //keep them all :(
                                if (_curves.Query().Where(p => p.binding.path == binding.path &&
                                                          p.binding.type == binding.type &&
                                                          p.binding.propertyName.TrimEnd(2) == binding.propertyName.TrimEnd(2)).
                                    All(k => k.curve.IsConstant()))
                                {
                                    continue;
                                }
                            }

                            //First do a lossless compression
                            using (new ProfilerSample("B")) {
                                curve = AnimationCurveUtil.Compress(curve, Mathf.Epsilon, checkSteps: 3);
                            }

                            Transform targetTransform = null;
                            var targetObj             = AnimationUtility.GetAnimatedObject(gameObject, binding);
                            if (targetObj is GameObject)
                            {
                                targetTransform = (targetObj as GameObject).transform;
                            }
                            else if (targetObj is Component)
                            {
                                targetTransform = (targetObj as Component).transform;
                            }
                            else
                            {
                                Debug.LogError("Target obj was of type " + targetObj.GetType().Name);
                            }
                        }
                    }
                });
            });

            progress.Begin(4, "Finalizing Assets", "", () => {
                var postProcessComponent = gameObject.AddComponent <HierarchyPostProcess>();

                GameObject myGameObject = gameObject;

                DestroyImmediate(this);

                //Create all the files for the method recording
                progress.Step("Creating Method Recording Files...");
                var methodRecordings = myGameObject.GetComponentsInChildren <MethodRecording>();
                for (int i = 0; i < methodRecordings.Length; i++)
                {
                    var methodRecording = methodRecordings[i];
                    string fullPath     = Path.Combine(finalSubFolder, "MethodRecording_" + i + ".asset");
                    methodRecording.ExitRecordingMode(fullPath);
                }

                postProcessComponent.dataFolder = new AssetFolder(dataDirectory);

                //Create the asset that holds all of the curve data
                progress.Begin(_curves.Count, "", "", () => {
                    string curveFile = Path.Combine(dataDirectory, "Curves.data");
                    using (var writer = File.CreateText(curveFile)) {
                        foreach (var data in _curves)
                        {
                            progress.Step(data.binding.propertyName);

                            var bindingData = new EditorCurveBindingData()
                            {
                                path         = data.binding.path,
                                propertyName = data.binding.propertyName,
                                typeName     = data.binding.type.Name,
                                curve        = data.curve
                            };

                            writer.WriteLine(JsonUtility.ToJson(bindingData));
                        }
                    }
                });

                //Create the asset that holds all of the leap data
                if (_leapData.Count > 0)
                {
                    progress.Begin(_leapData.Count, "", "", () => {
                        string leapFile = Path.Combine(dataDirectory, "Frames.data");

                        using (var writer = File.CreateText(leapFile)) {
                            for (int i = 0; i < _leapData.Count; i++)
                            {
                                progress.Step("Frame " + i);
                                writer.WriteLine(JsonUtility.ToJson(_leapData[i]));
                            }
                        }
                    });
                }

                progress.Step("Creating Final Prefab...");
                //Init the post process component
                postProcessComponent.recordingName = recordingName;
                postProcessComponent.assetFolder   = new AssetFolder(finalSubFolder);

                string prefabPath = Path.Combine(finalSubFolder, recordingName + " Raw.prefab");
                PrefabUtility.CreatePrefab(prefabPath.Replace('\\', '/'), myGameObject);

                AssetDatabase.Refresh();

                EditorApplication.isPlaying = false;
            });
        }
        public void BuildPlaybackPrefab(ProgressBar progress)
        {
            var timeline = ScriptableObject.CreateInstance <TimelineAsset>();

            var animationTrack = timeline.CreateTrack <AnimationTrack>(null, "Playback Animation");

            var clip = generateCompressedClip(progress);

            var playableAsset = ScriptableObject.CreateInstance <AnimationPlayableAsset>();

            playableAsset.clip      = clip;
            playableAsset.hideFlags = HideFlags.HideInInspector | HideFlags.HideInHierarchy;
            playableAsset.name      = "Recorded Animation";

            var timelineClip = animationTrack.CreateClip(clip);

            timelineClip.duration    = clip.length;
            timelineClip.asset       = playableAsset;
            timelineClip.displayName = "Recorded Animation";

            //If a clip is not recordable, it will not show up as editable in the timeline view.
            //For whatever reason unity decided that imported clips are not recordable, so we hack a
            //private variable to force them to be!  This seems to have no ill effects but if things go
            //wrong we can just revert this line
            timelineClip.GetType().GetField("m_Recordable", System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance).SetValue(timelineClip, true);

            //Try to generate a leap recording if we have leap data
            RecordingTrack recordingTrack = null;
            LeapRecording  leapRecording  = null;

            string framesPath = Path.Combine(dataFolder.Path, "Frames.data");

            if (File.Exists(framesPath))
            {
                List <Frame> frames = new List <Frame>();

                progress.Begin(1, "Loading Leap Data", "", () => {
                    progress.Step();
                    using (var reader = File.OpenText(framesPath)) {
                        while (true)
                        {
                            string line = reader.ReadLine();
                            if (string.IsNullOrEmpty(line))
                            {
                                break;
                            }

                            frames.Add(JsonUtility.FromJson <Frame>(line));
                        }
                    }
                });

                leapRecording = ScriptableObject.CreateInstance(_leapRecordingType) as LeapRecording;
                if (leapRecording != null)
                {
                    leapRecording.name = "Recorded Leap Data";
                    leapRecording.LoadFrames(frames);
                }
                else
                {
                    Debug.LogError("Unable to create Leap recording: Invalid type specification for "
                                   + "LeapRecording implementation.", this);
                }
            }

            string assetPath = Path.Combine(assetFolder.Path, recordingName + ".asset");

            AssetDatabase.CreateAsset(timeline, assetPath);
            AssetDatabase.AddObjectToAsset(playableAsset, timeline);
            AssetDatabase.AddObjectToAsset(animationTrack, timeline);
            AssetDatabase.AddObjectToAsset(clip, timeline);

            //If we do have a leap recording, create a recording track to house it
            if (leapRecording != null)
            {
                recordingTrack = timeline.CreateTrack <RecordingTrack>(null, "Leap Recording");

                var recordingClip = recordingTrack.CreateDefaultClip();
                recordingClip.duration = leapRecording.length;

                var recordingAsset = recordingClip.asset as RecordingClip;
                recordingAsset.recording = leapRecording;

                AssetDatabase.AddObjectToAsset(leapRecording, timeline);
            }

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();

            //Create the playable director and link it to the new timeline
            var director = gameObject.AddComponent <PlayableDirector>();

            director.playableAsset = timeline;

            //Create the animator
            gameObject.AddComponent <Animator>();

            //Link the animation track to the animator
            //(it likes to point to gameobject instead of the animator directly)
            director.SetGenericBinding(animationTrack.outputs.Query().First().sourceObject, gameObject);

            //Destroy existing provider
            var provider = gameObject.GetComponentInChildren <LeapProvider>();

            if (provider != null)
            {
                GameObject providerObj = provider.gameObject;
                DestroyImmediate(provider);
                //If a leap recording track exists, spawn a playable provider and link it to the track
                if (recordingTrack != null)
                {
                    var playableProvider = providerObj.AddComponent <LeapPlayableProvider>();
                    director.SetGenericBinding(recordingTrack.outputs.Query().First().sourceObject, playableProvider);
                }
            }

            buildAudioTracks(progress, director, timeline);
            buildMethodRecordingTracks(progress, director, timeline);

            progress.Begin(1, "", "Finalizing Prefab", () => {
                GameObject myGameObject = gameObject;
                DestroyImmediate(this);

                string prefabPath = Path.Combine(assetFolder.Path, recordingName + ".prefab");
                PrefabUtility.SaveAsPrefabAsset(myGameObject, prefabPath.Replace('\\', '/'));
            });
        }
        private void doCompression(ProgressBar progress,
                                   UnityEngine.Object targetObject,
                                   Dictionary <EditorCurveBinding, AnimationCurve> toCompress,
                                   Dictionary <EditorCurveBinding, AnimationCurve> bindingMap)
        {
            var propertyToMaxError = calculatePropertyErrors(targetObject);

            List <EditorCurveBinding> bindings;

            progress.Begin(6, "", targetObject.name, () => {
                //First do rotations
                bindings = toCompress.Keys.Query().ToList();
                progress.Begin(bindings.Count, "", "", () => {
                    foreach (var wBinding in bindings)
                    {
                        progress.Step();

                        if (!wBinding.propertyName.EndsWith(".w"))
                        {
                            continue;
                        }

                        string property = wBinding.propertyName.Substring(0, wBinding.propertyName.Length - 2);
                        string xProp    = property + ".x";
                        string yProp    = property + ".y";
                        string zProp    = property + ".z";

                        var xMaybe = toCompress.Keys.Query().FirstOrNone(t => t.propertyName == xProp);
                        var yMaybe = toCompress.Keys.Query().FirstOrNone(t => t.propertyName == yProp);
                        var zMaybe = toCompress.Keys.Query().FirstOrNone(t => t.propertyName == zProp);

                        Maybe.MatchAll(xMaybe, yMaybe, zMaybe, (xBinding, yBinding, zBinding) => {
                            float maxAngleError;
                            if (!propertyToMaxError.TryGetValue(property, out maxAngleError))
                            {
                                maxAngleError = rotationMaxError;
                            }

                            AnimationCurve compressedX, compressedY, compressedZ, compressedW;
                            AnimationCurveUtil.CompressRotations(toCompress[xBinding],
                                                                 toCompress[yBinding],
                                                                 toCompress[zBinding],
                                                                 toCompress[wBinding],
                                                                 out compressedX,
                                                                 out compressedY,
                                                                 out compressedZ,
                                                                 out compressedW,
                                                                 maxAngleError);

                            bindingMap[xBinding] = compressedX;
                            bindingMap[yBinding] = compressedY;
                            bindingMap[zBinding] = compressedZ;
                            bindingMap[wBinding] = compressedW;

                            toCompress.Remove(xBinding);
                            toCompress.Remove(yBinding);
                            toCompress.Remove(zBinding);
                            toCompress.Remove(wBinding);
                        });
                    }
                });

                //Next do scales
                bindings = toCompress.Keys.Query().ToList();
                progress.Begin(bindings.Count, "", "", () => {
                    foreach (var binding in bindings)
                    {
                        progress.Step();

                        if (!binding.propertyName.EndsWith(".x") &&
                            !binding.propertyName.EndsWith(".y") &&
                            !binding.propertyName.EndsWith(".z"))
                        {
                            continue;
                        }

                        if (!binding.propertyName.Contains("LocalScale"))
                        {
                            continue;
                        }

                        bindingMap[binding] = AnimationCurveUtil.CompressScale(toCompress[binding], scaleMaxError);
                        toCompress.Remove(binding);
                    }
                });

                //Next do positions
                bindings = toCompress.Keys.Query().ToList();
                progress.Begin(bindings.Count, "", "", () => {
                    foreach (var xBinding in bindings)
                    {
                        progress.Step();

                        if (!xBinding.propertyName.EndsWith(".x"))
                        {
                            continue;
                        }

                        string property = xBinding.propertyName.Substring(0, xBinding.propertyName.Length - 2);
                        string yProp    = property + ".y";
                        string zProp    = property + ".z";

                        var yMaybe = toCompress.Keys.Query().FirstOrNone(t => t.propertyName == yProp);
                        var zMaybe = toCompress.Keys.Query().FirstOrNone(t => t.propertyName == zProp);

                        Maybe.MatchAll(yMaybe, zMaybe, (yBinding, zBinding) => {
                            float maxDistanceError;
                            if (!propertyToMaxError.TryGetValue(property, out maxDistanceError))
                            {
                                maxDistanceError = positionMaxError;
                            }

                            AnimationCurve compressedX, compressedY, compressedZ;
                            AnimationCurveUtil.CompressPositions(toCompress[xBinding],
                                                                 toCompress[yBinding],
                                                                 toCompress[zBinding],
                                                                 out compressedX,
                                                                 out compressedY,
                                                                 out compressedZ,
                                                                 maxDistanceError);

                            bindingMap[xBinding] = compressedX;
                            bindingMap[yBinding] = compressedY;
                            bindingMap[zBinding] = compressedZ;

                            toCompress.Remove(xBinding);
                            toCompress.Remove(yBinding);
                            toCompress.Remove(zBinding);
                        });
                    }
                });

                //Next do colors
                bindings = toCompress.Keys.Query().ToList();
                progress.Begin(bindings.Count, "", "", () => {
                    foreach (var rBinding in bindings)
                    {
                        progress.Step();

                        if (!rBinding.propertyName.EndsWith(".r"))
                        {
                            continue;
                        }

                        string property = rBinding.propertyName.Substring(0, rBinding.propertyName.Length - 2);
                        string gProp    = property + ".g";
                        string bProp    = property + ".b";

                        var gMaybe = toCompress.Keys.Query().FirstOrNone(t => t.propertyName == gProp);
                        var bMaybe = toCompress.Keys.Query().FirstOrNone(t => t.propertyName == bProp);

                        Maybe.MatchAll(gMaybe, bMaybe, (gBinding, bBinding) => {
                            AnimationCurve compressedR, compressedG, compressedB;
                            AnimationCurveUtil.CompressColorsHSV(toCompress[rBinding],
                                                                 toCompress[gBinding],
                                                                 toCompress[bBinding],
                                                                 out compressedR,
                                                                 out compressedG,
                                                                 out compressedB,
                                                                 colorHueMaxError,
                                                                 colorSaturationMaxError,
                                                                 colorValueMaxError);

                            bindingMap[rBinding] = compressedR;
                            bindingMap[gBinding] = compressedG;
                            bindingMap[bBinding] = compressedB;
                        });
                    }
                });

                //Then do color alpha
                bindings = toCompress.Keys.Query().ToList();
                progress.Begin(bindings.Count, "", "", () => {
                    foreach (var aBinding in bindings)
                    {
                        progress.Step();

                        if (!aBinding.propertyName.EndsWith(".a"))
                        {
                            continue;
                        }

                        var compressedA = AnimationCurveUtil.Compress(toCompress[aBinding], colorAlphaMaxError);

                        toCompress.Remove(aBinding);
                        bindingMap[aBinding] = compressedA;
                    }
                });

                //Then everything else
                bindings = toCompress.Keys.Query().ToList();
                progress.Begin(bindings.Count, "", "", () => {
                    foreach (var binding in bindings)
                    {
                        progress.Step();

                        float maxError;
                        if (!propertyToMaxError.TryGetValue(binding.propertyName, out maxError))
                        {
                            maxError = genericMaxError;
                        }

                        var compressedCurve = AnimationCurveUtil.Compress(toCompress[binding], maxError);

                        toCompress.Remove(binding);
                        bindingMap[binding] = compressedCurve;
                    }
                });
            });
        }
        private AnimationClip generateCompressedClip(ProgressBar progress)
        {
            var clip = new AnimationClip();

            clip.name = "Recorded Animation";

            List <EditorCurveBindingData> curveData = new List <EditorCurveBindingData>();

            progress.Begin(1, "Opening Curve Files...", "", () => {
                progress.Step();
                using (var reader = File.OpenText(Path.Combine(dataFolder.Path, "Curves.data"))) {
                    while (true)
                    {
                        string line = reader.ReadLine();
                        if (string.IsNullOrEmpty(line))
                        {
                            break;
                        }

                        curveData.Add(JsonUtility.FromJson <EditorCurveBindingData>(line));
                    }
                }
            });

            progress.Begin(2, "", "", () => {
                var bindingMap = new Dictionary <EditorCurveBinding, AnimationCurve>();

                Dictionary <string, Type> nameToType = new Dictionary <string, Type>();
                foreach (var component in GetComponentsInChildren <Component>())
                {
                    nameToType[component.GetType().Name] = component.GetType();
                }
                nameToType[typeof(GameObject).Name] = typeof(GameObject);

                var toCompress    = new Dictionary <EditorCurveBinding, AnimationCurve>();
                var targetObjects = new HashSet <UnityEngine.Object>();

                foreach (var data in curveData)
                {
                    Type type;
                    if (!nameToType.TryGetValue(data.typeName, out type))
                    {
                        continue;
                    }

                    var binding = EditorCurveBinding.FloatCurve(data.path, type, data.propertyName);

                    var targetObj = AnimationUtility.GetAnimatedObject(gameObject, binding);
                    if (targetObj == null)
                    {
                        continue;
                    }

                    toCompress[binding] = data.curve;
                    targetObjects.Add(targetObj);
                }

                progress.Begin(targetObjects.Count, "Compressing Curves", "", () => {
                    foreach (var targetObj in targetObjects)
                    {
                        var filteredCurves = new Dictionary <EditorCurveBinding, AnimationCurve>();
                        foreach (var curve in toCompress)
                        {
                            if (AnimationUtility.GetAnimatedObject(gameObject, curve.Key) == targetObj)
                            {
                                filteredCurves[curve.Key] = curve.Value;
                            }
                        }

                        doCompression(progress, targetObj, filteredCurves, bindingMap);
                    }
                });

                progress.Begin(bindingMap.Count, "Assigning Curves", "", () => {
                    foreach (var binding in bindingMap)
                    {
                        progress.Step(binding.Key.propertyName);
                        AnimationUtility.SetEditorCurve(clip, binding.Key, binding.Value);
                    }
                });
            });
            return(clip);
        }
Пример #11
0
        public void BuildPlaybackPrefab(ProgressBar progress)
        {
            var timeline = ScriptableObject.CreateInstance <TimelineAsset>();

            var animationTrack = timeline.CreateTrack <AnimationTrack>(null, "Playback Animation");

            var clip = generateCompressedClip(progress);

            var timelineClip = animationTrack.CreateClip(clip);

            timelineClip.duration        = clip.length;
            timelineClip.asset           = clip;
            timelineClip.underlyingAsset = clip;

            //Try to generate a leap recording if we have leap data
            RecordingTrack recordingTrack = null;
            LeapRecording  leapRecording  = null;

            if (leapData.Count > 0)
            {
                leapRecording = ScriptableObject.CreateInstance(_leapRecordingType) as LeapRecording;
                if (leapRecording != null)
                {
                    leapRecording.LoadFrames(leapData);
                }
                else
                {
                    Debug.LogError("Unable to create Leap recording: Invalid type specification for "
                                   + "LeapRecording implementation.", this);
                }
            }

            string assetPath = Path.Combine(assetFolder.Path, recordingName + ".asset");

            AssetDatabase.CreateAsset(timeline, assetPath);
            AssetDatabase.AddObjectToAsset(animationTrack, timeline);
            AssetDatabase.AddObjectToAsset(clip, timeline);

            //If we do have a leap recording, create a recording track to house it
            if (leapRecording != null)
            {
                recordingTrack = timeline.CreateTrack <RecordingTrack>(null, "Leap Recording");

                var recordingClip = recordingTrack.CreateDefaultClip();
                recordingClip.duration = leapRecording.length;

                var recordingAsset = recordingClip.asset as RecordingClip;
                recordingAsset.recording = leapRecording;

                AssetDatabase.AddObjectToAsset(leapRecording, timeline);
            }

            AssetDatabase.SaveAssets();
            AssetDatabase.Refresh();

            foreach (var recording in GetComponentsInChildren <RecordedData>(includeInactive: true))
            {
                DestroyImmediate(recording);
            }

            //Create the playable director and link it to the new timeline
            var director = gameObject.AddComponent <PlayableDirector>();

            director.playableAsset = timeline;

            //Create the animator and link it to the animation track
            var animator = gameObject.AddComponent <Animator>();

            director.SetGenericBinding(animationTrack.outputs.Query().First().sourceObject, animator);

            //Destroy existing provider
            var provider = gameObject.GetComponentInChildren <LeapProvider>();

            if (provider != null)
            {
                GameObject providerObj = provider.gameObject;
                DestroyImmediate(provider);
                //If a leap recording track exists, spawn a playable provider and link it to the track
                if (recordingTrack != null)
                {
                    var playableProvider = providerObj.AddComponent <LeapPlayableProvider>();
                    director.SetGenericBinding(recordingTrack.outputs.Query().First().sourceObject, playableProvider);
                }
            }

            buildAudioTracks(progress, director, timeline);

            progress.Begin(1, "", "Finalizing Prefab", () => {
                GameObject myGameObject = gameObject;
                DestroyImmediate(this);

                string prefabPath = Path.Combine(assetFolder.Path, recordingName + ".prefab");
                PrefabUtility.CreatePrefab(prefabPath.Replace('\\', '/'), myGameObject);
            });
        }
Пример #12
0
        protected void finishRecording(ProgressBar progress)
        {
            progress.Begin(5, "Saving Recording", "", () => {
                if (!_isRecording)
                {
                    return;
                }
                _isRecording = false;

                //Turn on auto-pushing for all auto-proxy components
                foreach (var autoProxy in GetComponentsInChildren <AutoValueProxy>())
                {
                    autoProxy.autoPushingEnabled = true;
                }

                progress.Begin(1, "", "Reverting Scene State", () => {
                    foreach (var pair in _initialTransformData)
                    {
                        pair.Key.localPosition = pair.Value.localPosition;
                        pair.Key.localRotation = pair.Value.localRotation;
                        pair.Key.localScale    = pair.Value.localScale;
                        pair.Key.gameObject.SetActive(pair.Value.enabled);
                    }

                    foreach (var pair in _initialActivityData)
                    {
                        EditorUtility.SetObjectEnabled(pair.Key, pair.Value);
                    }
                });

                progress.Begin(1, "", "Patching Materials: ", () => {
                    GetComponentsInChildren(true, _recorders);
                    foreach (var recorder in _recorders)
                    {
                        DestroyImmediate(recorder);
                    }

                    //Patch up renderer references to materials
                    var allMaterials = Resources.FindObjectsOfTypeAll <Material>().
                                       Query().
                                       Where(AssetDatabase.IsMainAsset).
                                       ToList();

                    var renderers = GetComponentsInChildren <Renderer>(includeInactive: true);

                    progress.Begin(renderers.Length, "", "", () => {
                        foreach (var renderer in renderers)
                        {
                            progress.Step(renderer.name);

                            var materials = renderer.sharedMaterials;
                            for (int i = 0; i < materials.Length; i++)
                            {
                                var material = materials[i];
                                if (!AssetDatabase.IsMainAsset(material))
                                {
                                    var matchingMaterial = allMaterials.Query().FirstOrDefault(m => material.name.Contains(m.name) &&
                                                                                               material.shader == m.shader);

                                    if (matchingMaterial != null)
                                    {
                                        materials[i] = matchingMaterial;
                                    }
                                }
                            }
                            renderer.sharedMaterials = materials;
                        }
                    });
                });

                progress.Begin(_behaviourActivity.Count, "", "Converting Activity Data: ", () => {
                    foreach (var pair in _behaviourActivity)
                    {
                        var targetBehaviour = pair.Key;
                        var activityData    = pair.Value;

                        progress.Step(targetBehaviour.name);

                        string path         = AnimationUtility.CalculateTransformPath(targetBehaviour.transform, transform);
                        Type type           = targetBehaviour.GetType();
                        string propertyName = "m_Enabled";

                        AnimationCurve curve = new AnimationCurve();
                        foreach (var dataPoint in activityData)
                        {
                            int index = curve.AddKey(dataPoint.time, dataPoint.enabled ? 1 : 0);
                            AnimationUtility.SetKeyLeftTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                            AnimationUtility.SetKeyRightTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                        }

                        if (curve.IsConstant())
                        {
                            continue;
                        }

                        var binding = EditorCurveBinding.FloatCurve(path, type, propertyName);

                        if (_curves.ContainsKey(binding))
                        {
                            Debug.LogError("Binding already existed?");
                            Debug.LogError(binding.path + " : " + binding.propertyName);
                            continue;
                        }
                        _curves.Add(binding, curve);
                    }
                });

                progress.Begin(_transformData.Count, "", "Converting Transform Data: ", () => {
                    foreach (var pair in _transformData)
                    {
                        var targetTransform = pair.Key;
                        var targetData      = pair.Value;

                        progress.Step(targetTransform.name);

                        string path = AnimationUtility.CalculateTransformPath(targetTransform, transform);

                        bool isActivityConstant = true;
                        bool isPositionConstant = true;
                        bool isRotationConstant = true;
                        bool isScaleConstant    = true;

                        {
                            bool startEnabled        = targetData[0].enabled;
                            Vector3 startPosition    = targetData[0].localPosition;
                            Quaternion startRotation = targetData[0].localRotation;
                            Vector3 startScale       = targetData[0].localScale;
                            for (int i = 1; i < targetData.Count; i++)
                            {
                                isActivityConstant &= targetData[i].enabled == startEnabled;
                                isPositionConstant &= targetData[i].localPosition == startPosition;
                                isRotationConstant &= targetData[i].localRotation == startRotation;
                                isScaleConstant    &= targetData[i].localScale == startScale;
                            }
                        }

                        for (int i = 0; i < TransformData.CURVE_COUNT; i++)
                        {
                            string propertyName = TransformData.GetName(i);
                            Type type           = typeof(Transform);

                            AnimationCurve curve = new AnimationCurve();
                            var dataType         = TransformData.GetDataType(i);

                            switch (dataType)
                            {
                            case TransformDataType.Position:
                                if (isPositionConstant)
                                {
                                    continue;
                                }
                                break;

                            case TransformDataType.Rotation:
                                if (isRotationConstant)
                                {
                                    continue;
                                }
                                break;

                            case TransformDataType.Scale:
                                if (isScaleConstant)
                                {
                                    continue;
                                }
                                break;

                            case TransformDataType.Activity:
                                if (isActivityConstant)
                                {
                                    continue;
                                }
                                type = typeof(GameObject);
                                break;
                            }

                            for (int j = 0; j < targetData.Count; j++)
                            {
                                int index = curve.AddKey(targetData[j].time, targetData[j].GetFloat(i));
                                if (dataType == TransformDataType.Activity)
                                {
                                    AnimationUtility.SetKeyLeftTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                                    AnimationUtility.SetKeyRightTangentMode(curve, index, AnimationUtility.TangentMode.Constant);
                                }
                            }

                            var binding = EditorCurveBinding.FloatCurve(path, type, propertyName);

                            if (_curves.ContainsKey(binding))
                            {
                                Debug.LogError("Duplicate object was created??");
                                Debug.LogError("Named " + targetTransform.name + " : " + binding.path + " : " + binding.propertyName);
                            }
                            else
                            {
                                _curves.Add(binding, curve);
                            }
                        }
                    }
                });

                progress.Begin(_curves.Count, "", "Compressing Data: ", () => {
                    foreach (var pair in _curves)
                    {
                        EditorCurveBinding binding = pair.Key;
                        AnimationCurve curve       = pair.Value;

                        progress.Step(binding.propertyName);

                        GameObject animationGameObject;
                        {
                            var animatedObj = AnimationUtility.GetAnimatedObject(gameObject, binding);
                            if (animatedObj is GameObject)
                            {
                                animationGameObject = animatedObj as GameObject;
                            }
                            else
                            {
                                animationGameObject = (animatedObj as Component).gameObject;
                            }
                        }

                        //But if the curve is constant, just get rid of it!
                        if (curve.IsConstant())
                        {
                            //Check to make sure there are no other matching curves that are
                            //non constant.  If X and Y are constant but Z is not, we need to
                            //keep them all :(
                            if (_curves.Query().Where(p => p.Key.path == binding.path &&
                                                      p.Key.type == binding.type &&
                                                      p.Key.propertyName.TrimEnd(2) == binding.propertyName.TrimEnd(2)).
                                All(k => k.Value.IsConstant()))
                            {
                                continue;
                            }
                        }

                        //First do a lossless compression
                        curve = AnimationCurveUtil.Compress(curve, Mathf.Epsilon);

                        Transform targetTransform = null;
                        var targetObj             = AnimationUtility.GetAnimatedObject(gameObject, binding);
                        if (targetObj is GameObject)
                        {
                            targetTransform = (targetObj as GameObject).transform;
                        }
                        else if (targetObj is Component)
                        {
                            targetTransform = (targetObj as Component).transform;
                        }
                        else
                        {
                            Debug.LogError("Target obj was of type " + targetObj.GetType().Name);
                        }

                        var dataRecorder = targetTransform.GetComponent <RecordedData>();
                        if (dataRecorder == null)
                        {
                            dataRecorder = targetTransform.gameObject.AddComponent <RecordedData>();
                        }

                        dataRecorder.data.Add(new RecordedData.EditorCurveBindingData()
                        {
                            path         = binding.path,
                            propertyName = binding.propertyName,
                            typeName     = binding.type.Name,
                            curve        = curve
                        });
                    }
                });

                progress.Step("Finalizing Prefab...");

                var postProcessComponent = gameObject.AddComponent <HierarchyPostProcess>();

                GameObject myGameObject = gameObject;

                DestroyImmediate(this);

                string targetFolderPath = targetFolder.Path;
                if (targetFolderPath == null)
                {
                    if (myGameObject.scene.IsValid() && !string.IsNullOrEmpty(myGameObject.scene.path))
                    {
                        string sceneFolder = Path.GetDirectoryName(myGameObject.scene.path);
                        targetFolderPath   = Path.Combine(sceneFolder, "Recordings");
                    }
                    else
                    {
                        targetFolderPath = Path.Combine("Assets", "Recordings");
                    }
                }

                int folderSuffix = 1;
                string finalSubFolder;
                do
                {
                    finalSubFolder = Path.Combine(targetFolderPath, recordingName + " " + folderSuffix.ToString().PadLeft(2, '0'));
                    folderSuffix++;
                } while (Directory.Exists(finalSubFolder));

                Directory.CreateDirectory(finalSubFolder);
                AssetDatabase.Refresh();

                postProcessComponent.recordingName    = recordingName;
                postProcessComponent.assetFolder.Path = finalSubFolder;
                postProcessComponent.leapData         = _leapData;

                string prefabPath = Path.Combine(finalSubFolder, recordingName + " Raw.prefab");
                PrefabUtility.CreatePrefab(prefabPath.Replace('\\', '/'), myGameObject);
                AssetDatabase.Refresh();

                EditorApplication.isPlaying = false;
            });
        }