main
zyy2412666 2023-11-20 15:03:44 +08:00
parent bc87fabb5f
commit d39759b94d
155 changed files with 30547 additions and 0 deletions

File diff suppressed because it is too large Load Diff

Binary file not shown.

View File

@ -0,0 +1,144 @@
<?xml version="1.0"?>
<doc>
<assembly>
<name>DOTweenEditor</name>
</assembly>
<members>
<member name="T:DG.DOTweenEditor.EditorCompatibilityUtils">
<summary>
Contains compatibility methods taken from DemiEditor (for when DOTween is without it)
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorCompatibilityUtils.FindObjectOfType``1(System.Boolean)">
<summary>
Warning: some versions of this method don't have the includeInactive parameter so it won't be taken into account
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorCompatibilityUtils.FindObjectOfType(System.Type,System.Boolean)">
<summary>
Warning: some versions of this method don't have the includeInactive parameter so it won't be taken into account
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorCompatibilityUtils.FindObjectsOfType``1(System.Boolean)">
<summary>
Warning: some versions of this method don't have the includeInactive parameter so it won't be taken into account
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorCompatibilityUtils.FindObjectsOfType(System.Type,System.Boolean)">
<summary>
Warning: some versions of this method don't have the includeInactive parameter so it won't be taken into account
</summary>
</member>
<member name="M:DG.DOTweenEditor.DOTweenEditorPreview.Start(System.Action)">
<summary>
Starts the update loop of tween in the editor. Has no effect during playMode.
</summary>
<param name="onPreviewUpdated">Eventual callback to call after every update</param>
</member>
<member name="M:DG.DOTweenEditor.DOTweenEditorPreview.Stop(System.Boolean,System.Boolean)">
<summary>
Stops the update loop and clears the onPreviewUpdated callback.
</summary>
<param name="resetTweenTargets">If TRUE also resets the tweened objects to their original state.
Note that this works by calling Rewind on all tweens, so it will work correctly
only if you have a single tween type per object and it wasn't killed</param>
<param name="clearTweens">If TRUE also kills any cached tween</param>
</member>
<member name="M:DG.DOTweenEditor.DOTweenEditorPreview.PrepareTweenForPreview(DG.Tweening.Tween,System.Boolean,System.Boolean,System.Boolean)">
<summary>
Readies the tween for editor preview by setting its UpdateType to Manual plus eventual extra settings.
</summary>
<param name="t">The tween to ready</param>
<param name="clearCallbacks">If TRUE (recommended) removes all callbacks (OnComplete/Rewind/etc)</param>
<param name="preventAutoKill">If TRUE prevents the tween from being auto-killed at completion</param>
<param name="andPlay">If TRUE starts playing the tween immediately</param>
</member>
<member name="F:DG.DOTweenEditor.EditorVersion.Version">
<summary>Full major version + first minor version (ex: 2018.1f)</summary>
</member>
<member name="F:DG.DOTweenEditor.EditorVersion.MajorVersion">
<summary>Major version</summary>
</member>
<member name="F:DG.DOTweenEditor.EditorVersion.MinorVersion">
<summary>First minor version (ex: in 2018.1 it would be 1)</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.SetEditorTexture(UnityEngine.Texture2D,UnityEngine.FilterMode,System.Int32)">
<summary>
Checks that the given editor texture use the correct import settings,
and applies them if they're incorrect.
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.DOTweenSetupRequired">
<summary>
Returns TRUE if setup is required
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.AssetExists(System.String)">
<summary>
Returns TRUE if the file/directory at the given path exists.
</summary>
<param name="adbPath">Path, relative to Unity's project folder</param>
<returns></returns>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.ADBPathToFullPath(System.String)">
<summary>
Converts the given project-relative path to a full path,
with backward (\) slashes).
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.FullPathToADBPath(System.String)">
<summary>
Converts the given full path to a path usable with AssetDatabase methods
(relative to Unity's project folder, and with the correct Unity forward (/) slashes).
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.ConnectToSourceAsset``1(System.String,System.Boolean)">
<summary>
Connects to a <see cref="T:UnityEngine.ScriptableObject"/> asset.
If the asset already exists at the given path, loads it and returns it.
Otherwise, either returns NULL or automatically creates it before loading and returning it
(depending on the given parameters).
</summary>
<typeparam name="T">Asset type</typeparam>
<param name="adbFilePath">File path (relative to Unity's project folder)</param>
<param name="createIfMissing">If TRUE and the requested asset doesn't exist, forces its creation</param>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.GetAssemblyFilePath(System.Reflection.Assembly)">
<summary>
Full path for the given loaded assembly, assembly file included
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.AddGlobalDefine(System.String)">
<summary>
Adds the given global define if it's not already present
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.RemoveGlobalDefine(System.String)">
<summary>
Removes the given global define if it's present
</summary>
</member>
<member name="M:DG.DOTweenEditor.EditorUtils.HasGlobalDefine(System.String,System.Nullable{UnityEditor.BuildTargetGroup})">
<summary>
Returns TRUE if the given global define is present in all the <see cref="T:UnityEditor.BuildTargetGroup"/>
or only in the given <see cref="T:UnityEditor.BuildTargetGroup"/>, depending on passed parameters.<para/>
</summary>
<param name="id"></param>
<param name="buildTargetGroup"><see cref="T:UnityEditor.BuildTargetGroup"/>to use. Leave NULL to check in all of them.</param>
</member>
<member name="T:DG.DOTweenEditor.DOTweenDefines">
<summary>
Not used as menu item anymore, but as a utiity function
</summary>
</member>
<member name="F:DG.DOTweenEditor.UnityEditorVersion.Version">
<summary>Full major version + first minor version (ex: 2018.1f)</summary>
</member>
<member name="F:DG.DOTweenEditor.UnityEditorVersion.MajorVersion">
<summary>Major version</summary>
</member>
<member name="F:DG.DOTweenEditor.UnityEditorVersion.MinorVersion">
<summary>First minor version (ex: in 2018.1 it would be 1)</summary>
</member>
</members>
</doc>

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 319 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

View File

@ -0,0 +1,198 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
using UnityEngine;
using UnityEngine.Audio; // Required for AudioMixer
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleAudio
{
#region Shortcuts
#region Audio
/// <summary>Tweens an AudioSource's volume to the given value.
/// Also stores the AudioSource as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach (0 to 1)</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFade(this AudioSource target, float endValue, float duration)
{
if (endValue < 0) endValue = 0;
else if (endValue > 1) endValue = 1;
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.volume, x => target.volume = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an AudioSource's pitch to the given value.
/// Also stores the AudioSource as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOPitch(this AudioSource target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.pitch, x => target.pitch = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region AudioMixer
/// <summary>Tweens an AudioMixer's exposed float to the given value.
/// Also stores the AudioMixer as the tween's target so it can be used for filtered operations.
/// Note that you need to manually expose a float in an AudioMixerGroup in order to be able to tween it from an AudioMixer.</summary>
/// <param name="floatName">Name given to the exposed float to set</param>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOSetFloat(this AudioMixer target, string floatName, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(()=> {
float currVal;
target.GetFloat(floatName, out currVal);
return currVal;
}, x=> target.SetFloat(floatName, x), endValue, duration);
t.SetTarget(target);
return t;
}
#region Operation Shortcuts
/// <summary>
/// Completes all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens completed
/// (meaning the tweens that don't have infinite loops and were not already complete)
/// </summary>
/// <param name="withCallbacks">For Sequences only: if TRUE also internal Sequence callbacks will be fired,
/// otherwise they will be ignored</param>
public static int DOComplete(this AudioMixer target, bool withCallbacks = false)
{
return DOTween.Complete(target, withCallbacks);
}
/// <summary>
/// Kills all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens killed.
/// </summary>
/// <param name="complete">If TRUE completes the tween before killing it</param>
public static int DOKill(this AudioMixer target, bool complete = false)
{
return DOTween.Kill(target, complete);
}
/// <summary>
/// Flips the direction (backwards if it was going forward or viceversa) of all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens flipped.
/// </summary>
public static int DOFlip(this AudioMixer target)
{
return DOTween.Flip(target);
}
/// <summary>
/// Sends to the given position all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens involved.
/// </summary>
/// <param name="to">Time position to reach
/// (if higher than the whole tween duration the tween will simply reach its end)</param>
/// <param name="andPlay">If TRUE will play the tween after reaching the given position, otherwise it will pause it</param>
public static int DOGoto(this AudioMixer target, float to, bool andPlay = false)
{
return DOTween.Goto(target, to, andPlay);
}
/// <summary>
/// Pauses all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens paused.
/// </summary>
public static int DOPause(this AudioMixer target)
{
return DOTween.Pause(target);
}
/// <summary>
/// Plays all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlay(this AudioMixer target)
{
return DOTween.Play(target);
}
/// <summary>
/// Plays backwards all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlayBackwards(this AudioMixer target)
{
return DOTween.PlayBackwards(target);
}
/// <summary>
/// Plays forward all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens played.
/// </summary>
public static int DOPlayForward(this AudioMixer target)
{
return DOTween.PlayForward(target);
}
/// <summary>
/// Restarts all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens restarted.
/// </summary>
public static int DORestart(this AudioMixer target)
{
return DOTween.Restart(target);
}
/// <summary>
/// Rewinds all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens rewinded.
/// </summary>
public static int DORewind(this AudioMixer target)
{
return DOTween.Rewind(target);
}
/// <summary>
/// Smoothly rewinds all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens rewinded.
/// </summary>
public static int DOSmoothRewind(this AudioMixer target)
{
return DOTween.SmoothRewind(target);
}
/// <summary>
/// Toggles the paused state (plays if it was paused, pauses if it was playing) of all tweens that have this target as a reference
/// (meaning tweens that were started from this target, or that had this target added as an Id)
/// and returns the total number of tweens involved.
/// </summary>
public static int DOTogglePause(this AudioMixer target)
{
return DOTween.TogglePause(target);
}
#endregion
#endregion
#endregion
}
}
#endif

View File

@ -0,0 +1,146 @@
using UnityEngine;
#if false || EPO_DOTWEEN // MODULE_MARKER
using EPOOutline;
using DG.Tweening.Plugins.Options;
using DG.Tweening;
using DG.Tweening.Core;
namespace DG.Tweening
{
public static class DOTweenModuleEPOOutline
{
public static int DOKill(this SerializedPass target, bool complete)
{
return DOTween.Kill(target, complete);
}
public static TweenerCore<float, float, FloatOptions> DOFloat(this SerializedPass target, string propertyName, float endValue, float duration)
{
var tweener = DOTween.To(() => target.GetFloat(propertyName), x => target.SetFloat(propertyName, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOFade(this SerializedPass target, string propertyName, float endValue, float duration)
{
var tweener = DOTween.ToAlpha(() => target.GetColor(propertyName), x => target.SetColor(propertyName, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOColor(this SerializedPass target, string propertyName, Color endValue, float duration)
{
var tweener = DOTween.To(() => target.GetColor(propertyName), x => target.SetColor(propertyName, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static TweenerCore<Vector4, Vector4, VectorOptions> DOVector(this SerializedPass target, string propertyName, Vector4 endValue, float duration)
{
var tweener = DOTween.To(() => target.GetVector(propertyName), x => target.SetVector(propertyName, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static TweenerCore<float, float, FloatOptions> DOFloat(this SerializedPass target, int propertyId, float endValue, float duration)
{
var tweener = DOTween.To(() => target.GetFloat(propertyId), x => target.SetFloat(propertyId, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOFade(this SerializedPass target, int propertyId, float endValue, float duration)
{
var tweener = DOTween.ToAlpha(() => target.GetColor(propertyId), x => target.SetColor(propertyId, x), endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
public static TweenerCore<Color, Color, ColorOptions> DOColor(this SerializedPass target, int propertyId, Color endValue, float duration)
{
var tweener = DOTween.To(() => target.GetColor(propertyId), x => target.SetColor(propertyId, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static TweenerCore<Vector4, Vector4, VectorOptions> DOVector(this SerializedPass target, int propertyId, Vector4 endValue, float duration)
{
var tweener = DOTween.To(() => target.GetVector(propertyId), x => target.SetVector(propertyId, x), endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
public static int DOKill(this Outlinable.OutlineProperties target, bool complete = false)
{
return DOTween.Kill(target, complete);
}
public static int DOKill(this Outliner target, bool complete = false)
{
return DOTween.Kill(target, complete);
}
/// <summary>
/// Controls the alpha (transparency) of the outline
/// </summary>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Outlinable.OutlineProperties target, float endValue, float duration)
{
var tweener = DOTween.ToAlpha(() => target.Color, x => target.Color = x, endValue, duration);
tweener.SetOptions(true).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the color of the outline
/// </summary>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Outlinable.OutlineProperties target, Color endValue, float duration)
{
var tweener = DOTween.To(() => target.Color, x => target.Color = x, endValue, duration);
tweener.SetOptions(false).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of blur applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DOBlurShift(this Outlinable.OutlineProperties target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.BlurShift, x => target.BlurShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of blur applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DOBlurShift(this Outliner target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.BlurShift, x => target.BlurShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of dilation applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DODilateShift(this Outlinable.OutlineProperties target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.DilateShift, x => target.DilateShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
/// <summary>
/// Controls the amount of dilation applied to the outline
/// </summary>
public static TweenerCore<float, float, FloatOptions> DODilateShift(this Outliner target, float endValue, float duration, bool snapping = false)
{
var tweener = DOTween.To(() => target.DilateShift, x => target.DilateShift = x, endValue, duration);
tweener.SetOptions(snapping).SetTarget(target);
return tweener;
}
}
}
#endif

View File

@ -0,0 +1,216 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
using UnityEngine;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModulePhysics
{
#region Shortcuts
#region Rigidbody
/// <summary>Tweens a Rigidbody's position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMove(this Rigidbody target, Vector3 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's X position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveX(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue, 0, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's Y position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveY(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, endValue, 0), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's Z position to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOMoveZ(this Rigidbody target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue), duration);
t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody's rotation to the given value.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="mode">Rotation mode</param>
public static TweenerCore<Quaternion, Vector3, QuaternionOptions> DORotate(this Rigidbody target, Vector3 endValue, float duration, RotateMode mode = RotateMode.Fast)
{
TweenerCore<Quaternion, Vector3, QuaternionOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration);
t.SetTarget(target);
t.plugOptions.rotateMode = mode;
return t;
}
/// <summary>Tweens a Rigidbody's rotation so that it will look towards the given position.
/// Also stores the rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="towards">The position to look at</param><param name="duration">The duration of the tween</param>
/// <param name="axisConstraint">Eventual axis constraint for the rotation</param>
/// <param name="up">The vector that defines in which direction up is (default: Vector3.up)</param>
public static TweenerCore<Quaternion, Vector3, QuaternionOptions> DOLookAt(this Rigidbody target, Vector3 towards, float duration, AxisConstraint axisConstraint = AxisConstraint.None, Vector3? up = null)
{
TweenerCore<Quaternion, Vector3, QuaternionOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, towards, duration)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetLookAt);
t.plugOptions.axisConstraint = axisConstraint;
t.plugOptions.up = (up == null) ? Vector3.up : (Vector3)up;
return t;
}
#region Special
/// <summary>Tweens a Rigidbody's position to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJump(this Rigidbody target, Vector3 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.position, target.MovePosition, new Vector3(0, jumpPower, 0), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(() => startPosY = target.position.y);
s.Append(DOTween.To(() => target.position, target.MovePosition, new Vector3(endValue.x, 0, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(DOTween.To(() => target.position, target.MovePosition, new Vector3(0, 0, endValue.z), duration)
.SetOptions(AxisConstraint.Z, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
yTween.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector3 pos = target.position;
pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad);
target.MovePosition(pos);
});
return s;
}
/// <summary>Tweens a Rigidbody's position through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations.
/// <para>NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOPath.</para></summary>
/// <param name="path">The waypoints to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, new Path(pathType, path, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
return t;
}
/// <summary>Tweens a Rigidbody's localPosition through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody as the tween's target so it can be used for filtered operations
/// <para>NOTE: to tween a rigidbody correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOLocalPath.</para></summary>
/// <param name="path">The waypoint to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody target, Vector3[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
// Used by path editor when creating the actual tween, so it can pass a pre-compiled path
internal static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, target.MovePosition, path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
return t;
}
internal static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
#endregion
#endregion
#endregion
}
}
#endif

View File

@ -0,0 +1,193 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true // MODULE_MARKER
using System;
using DG.Tweening.Core;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
using UnityEngine;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModulePhysics2D
{
#region Shortcuts
#region Rigidbody2D Shortcuts
/// <summary>Tweens a Rigidbody2D's position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMove(this Rigidbody2D target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's X position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMoveX(this Rigidbody2D target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's Y position to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMoveY(this Rigidbody2D target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.position, target.MovePosition, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a Rigidbody2D's rotation to the given value.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DORotate(this Rigidbody2D target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.rotation, target.MoveRotation, endValue, duration);
t.SetTarget(target);
return t;
}
#region Special
/// <summary>Tweens a Rigidbody2D's position to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations.
/// <para>IMPORTANT: a rigidbody2D can't be animated in a jump arc using MovePosition, so the tween will directly set the position</para></summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJump(this Rigidbody2D target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.position, x => target.position = x, new Vector2(0, jumpPower), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(() => startPosY = target.position.y);
s.Append(DOTween.To(() => target.position, x => target.position = x, new Vector2(endValue.x, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
yTween.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector3 pos = target.position;
pos.y += DOVirtual.EasedValue(0, offsetY, yTween.ElapsedPercentage(), Ease.OutQuad);
target.MovePosition(pos);
});
return s;
}
/// <summary>Tweens a Rigidbody2D's position through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations.
/// <para>NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOPath.</para></summary>
/// <param name="path">The waypoints to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path (useless in case of Linear paths): higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
int len = path.Length;
Vector3[] path3D = new Vector3[len];
for (int i = 0; i < len; ++i) path3D[i] = path[i];
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, x => target.MovePosition(x), new Path(pathType, path3D, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
return t;
}
/// <summary>Tweens a Rigidbody2D's localPosition through the given path waypoints, using the chosen path algorithm.
/// Also stores the Rigidbody2D as the tween's target so it can be used for filtered operations
/// <para>NOTE: to tween a Rigidbody2D correctly it should be set to kinematic at least while being tweened.</para>
/// <para>BEWARE: doesn't work on Windows Phone store (waiting for Unity to fix their own bug).
/// If you plan to publish there you should use a regular transform.DOLocalPath.</para></summary>
/// <param name="path">The waypoint to go through</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="pathType">The type of path: Linear (straight path), CatmullRom (curved CatmullRom path) or CubicBezier (curved with control points)</param>
/// <param name="pathMode">The path mode: 3D, side-scroller 2D, top-down 2D</param>
/// <param name="resolution">The resolution of the path: higher resolutions make for more detailed curved paths but are more expensive.
/// Defaults to 10, but a value of 5 is usually enough if you don't have dramatic long curves between waypoints</param>
/// <param name="gizmoColor">The color of the path (shown when gizmos are active in the Play panel and the tween is running)</param>
public static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody2D target, Vector2[] path, float duration, PathType pathType = PathType.Linear,
PathMode pathMode = PathMode.Full3D, int resolution = 10, Color? gizmoColor = null
)
{
if (resolution < 1) resolution = 1;
int len = path.Length;
Vector3[] path3D = new Vector3[len];
for (int i = 0; i < len; ++i) path3D[i] = path[i];
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), new Path(pathType, path3D, resolution, gizmoColor), duration)
.SetTarget(target).SetUpdate(UpdateType.Fixed);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
// Used by path editor when creating the actual tween, so it can pass a pre-compiled path
internal static TweenerCore<Vector3, Path, PathOptions> DOPath(
this Rigidbody2D target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => target.position, x => target.MovePosition(x), path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
return t;
}
internal static TweenerCore<Vector3, Path, PathOptions> DOLocalPath(
this Rigidbody2D target, Path path, float duration, PathMode pathMode = PathMode.Full3D
)
{
Transform trans = target.transform;
TweenerCore<Vector3, Path, PathOptions> t = DOTween.To(PathPlugin.Get(), () => trans.localPosition, x => target.MovePosition(trans.parent == null ? x : trans.parent.TransformPoint(x)), path, duration)
.SetTarget(target);
t.plugOptions.isRigidbody2D = true;
t.plugOptions.mode = pathMode;
t.plugOptions.useLocalPosition = true;
return t;
}
#endregion
#endregion
#endregion
}
}
#endif

View File

@ -0,0 +1,93 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true // MODULE_MARKER
using System;
using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleSprite
{
#region Shortcuts
#region SpriteRenderer
/// <summary>Tweens a SpriteRenderer's color to the given value.
/// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this SpriteRenderer target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Material's alpha color to the given value.
/// Also stores the spriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this SpriteRenderer target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a SpriteRenderer's color using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this SpriteRenderer target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region Blendables
#region SpriteRenderer
/// <summary>Tweens a SpriteRenderer's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the SpriteRenderer as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this SpriteRenderer target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#endregion
#endregion
}
}
#endif

View File

@ -0,0 +1,662 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
#if true // MODULE_MARKER
using System;
using System.Globalization;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening.Core;
using DG.Tweening.Core.Enums;
using DG.Tweening.Plugins;
using DG.Tweening.Plugins.Options;
using Outline = UnityEngine.UI.Outline;
using Text = UnityEngine.UI.Text;
#pragma warning disable 1591
namespace DG.Tweening
{
public static class DOTweenModuleUI
{
#region Shortcuts
#region CanvasGroup
/// <summary>Tweens a CanvasGroup's alpha color to the given value.
/// Also stores the canvasGroup as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFade(this CanvasGroup target, float endValue, float duration)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.alpha, x => target.alpha = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region Graphic
/// <summary>Tweens an Graphic's color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Graphic target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Graphic's alpha color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Graphic target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region Image
/// <summary>Tweens an Image's color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Image target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's alpha color to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Image target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's fillAmount to the given value.
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach (0 to 1)</param><param name="duration">The duration of the tween</param>
public static TweenerCore<float, float, FloatOptions> DOFillAmount(this Image target, float endValue, float duration)
{
if (endValue > 1) endValue = 1;
else if (endValue < 0) endValue = 0;
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.fillAmount, x => target.fillAmount = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens an Image's colors using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this Image target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region LayoutElement
/// <summary>Tweens an LayoutElement's flexibleWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOFlexibleSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.flexibleWidth, target.flexibleHeight), x => {
target.flexibleWidth = x.x;
target.flexibleHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens an LayoutElement's minWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOMinSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.minWidth, target.minHeight), x => {
target.minWidth = x.x;
target.minHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens an LayoutElement's preferredWidth/Height to the given value.
/// Also stores the LayoutElement as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPreferredSize(this LayoutElement target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => new Vector2(target.preferredWidth, target.preferredHeight), x => {
target.preferredWidth = x.x;
target.preferredHeight = x.y;
}, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
#endregion
#region Outline
/// <summary>Tweens a Outline's effectColor to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Outline target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.effectColor, x => target.effectColor = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Outline's effectColor alpha to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Outline target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.effectColor, x => target.effectColor = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Outline's effectDistance to the given value.
/// Also stores the Outline as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOScale(this Outline target, Vector2 endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.effectDistance, x => target.effectDistance = x, endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region RectTransform
/// <summary>Tweens a RectTransform's anchoredPosition to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPos(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPosX(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorPosY(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3D(this RectTransform target, Vector3 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DX(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(endValue, 0, 0), duration);
t.SetOptions(AxisConstraint.X, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DY(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, endValue, 0), duration);
t.SetOptions(AxisConstraint.Y, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchoredPosition3D Z to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector3, Vector3, VectorOptions> DOAnchorPos3DZ(this RectTransform target, float endValue, float duration, bool snapping = false)
{
TweenerCore<Vector3, Vector3, VectorOptions> t = DOTween.To(() => target.anchoredPosition3D, x => target.anchoredPosition3D = x, new Vector3(0, 0, endValue), duration);
t.SetOptions(AxisConstraint.Z, snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchorMax to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorMax(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchorMax, x => target.anchorMax = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's anchorMin to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOAnchorMin(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.anchorMin, x => target.anchorMin = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivot(this RectTransform target, Vector2 endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot X to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivotX(this RectTransform target, float endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(endValue, 0), duration);
t.SetOptions(AxisConstraint.X).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's pivot Y to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOPivotY(this RectTransform target, float endValue, float duration)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.pivot, x => target.pivot = x, new Vector2(0, endValue), duration);
t.SetOptions(AxisConstraint.Y).SetTarget(target);
return t;
}
/// <summary>Tweens a RectTransform's sizeDelta to the given value.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOSizeDelta(this RectTransform target, Vector2 endValue, float duration, bool snapping = false)
{
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.sizeDelta, x => target.sizeDelta = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
/// <summary>Punches a RectTransform's anchoredPosition towards the given direction and then back to the starting one
/// as if it was connected to the starting position via an elastic.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="punch">The direction and strength of the punch (added to the RectTransform's current position)</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="vibrato">Indicates how much will the punch vibrate</param>
/// <param name="elasticity">Represents how much (0 to 1) the vector will go beyond the starting position when bouncing backwards.
/// 1 creates a full oscillation between the punch direction and the opposite direction,
/// while 0 oscillates only between the punch and the start position</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOPunchAnchorPos(this RectTransform target, Vector2 punch, float duration, int vibrato = 10, float elasticity = 1, bool snapping = false)
{
return DOTween.Punch(() => target.anchoredPosition, x => target.anchoredPosition = x, punch, duration, vibrato, elasticity)
.SetTarget(target).SetOptions(snapping);
}
/// <summary>Shakes a RectTransform's anchoredPosition with the given values.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
/// <param name="randomnessMode">Randomness mode</param>
public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, float strength = 100, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full)
{
return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, true, fadeOut, randomnessMode)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
/// <summary>Shakes a RectTransform's anchoredPosition with the given values.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="duration">The duration of the tween</param>
/// <param name="strength">The shake strength on each axis</param>
/// <param name="vibrato">Indicates how much will the shake vibrate</param>
/// <param name="randomness">Indicates how much the shake will be random (0 to 180 - values higher than 90 kind of suck, so beware).
/// Setting it to 0 will shake along a single direction.</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
/// <param name="fadeOut">If TRUE the shake will automatically fadeOut smoothly within the tween's duration, otherwise it will not</param>
/// <param name="randomnessMode">Randomness mode</param>
public static Tweener DOShakeAnchorPos(this RectTransform target, float duration, Vector2 strength, int vibrato = 10, float randomness = 90, bool snapping = false, bool fadeOut = true, ShakeRandomnessMode randomnessMode = ShakeRandomnessMode.Full)
{
return DOTween.Shake(() => target.anchoredPosition, x => target.anchoredPosition = x, duration, strength, vibrato, randomness, fadeOut, randomnessMode)
.SetTarget(target).SetSpecialStartupMode(SpecialStartupMode.SetShake).SetOptions(snapping);
}
#region Special
/// <summary>Tweens a RectTransform's anchoredPosition to the given value, while also applying a jump effect along the Y axis.
/// Returns a Sequence instead of a Tweener.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="jumpPower">Power of the jump (the max height of the jump is represented by this plus the final Y offset)</param>
/// <param name="numJumps">Total number of jumps</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Sequence DOJumpAnchorPos(this RectTransform target, Vector2 endValue, float jumpPower, int numJumps, float duration, bool snapping = false)
{
if (numJumps < 1) numJumps = 1;
float startPosY = 0;
float offsetY = -1;
bool offsetYSet = false;
// Separate Y Tween so we can elaborate elapsedPercentage on that insted of on the Sequence
// (in case users add a delay or other elements to the Sequence)
Sequence s = DOTween.Sequence();
Tween yTween = DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(0, jumpPower), duration / (numJumps * 2))
.SetOptions(AxisConstraint.Y, snapping).SetEase(Ease.OutQuad).SetRelative()
.SetLoops(numJumps * 2, LoopType.Yoyo)
.OnStart(()=> startPosY = target.anchoredPosition.y);
s.Append(DOTween.To(() => target.anchoredPosition, x => target.anchoredPosition = x, new Vector2(endValue.x, 0), duration)
.SetOptions(AxisConstraint.X, snapping).SetEase(Ease.Linear)
).Join(yTween)
.SetTarget(target).SetEase(DOTween.defaultEaseType);
s.OnUpdate(() => {
if (!offsetYSet) {
offsetYSet = true;
offsetY = s.isRelative ? endValue.y : endValue.y - startPosY;
}
Vector2 pos = target.anchoredPosition;
pos.y += DOVirtual.EasedValue(0, offsetY, s.ElapsedDirectionalPercentage(), Ease.OutQuad);
target.anchoredPosition = pos;
});
return s;
}
#endregion
#endregion
#region ScrollRect
/// <summary>Tweens a ScrollRect's horizontal/verticalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DONormalizedPos(this ScrollRect target, Vector2 endValue, float duration, bool snapping = false)
{
return DOTween.To(() => new Vector2(target.horizontalNormalizedPosition, target.verticalNormalizedPosition),
x => {
target.horizontalNormalizedPosition = x.x;
target.verticalNormalizedPosition = x.y;
}, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
/// <summary>Tweens a ScrollRect's horizontalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOHorizontalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false)
{
return DOTween.To(() => target.horizontalNormalizedPosition, x => target.horizontalNormalizedPosition = x, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
/// <summary>Tweens a ScrollRect's verticalNormalizedPosition to the given value.
/// Also stores the ScrollRect as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static Tweener DOVerticalNormalizedPos(this ScrollRect target, float endValue, float duration, bool snapping = false)
{
return DOTween.To(() => target.verticalNormalizedPosition, x => target.verticalNormalizedPosition = x, endValue, duration)
.SetOptions(snapping).SetTarget(target);
}
#endregion
#region Slider
/// <summary>Tweens a Slider's value to the given value.
/// Also stores the Slider as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<float, float, FloatOptions> DOValue(this Slider target, float endValue, float duration, bool snapping = false)
{
TweenerCore<float, float, FloatOptions> t = DOTween.To(() => target.value, x => target.value = x, endValue, duration);
t.SetOptions(snapping).SetTarget(target);
return t;
}
#endregion
#region Text
/// <summary>Tweens a Text's color to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOColor(this Text target, Color endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.To(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>
/// Tweens a Text's text from one integer to another, with options for thousands separators
/// </summary>
/// <param name="fromValue">The value to start from</param>
/// <param name="endValue">The end value to reach</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="addThousandsSeparator">If TRUE (default) also adds thousands separators</param>
/// <param name="culture">The <see cref="CultureInfo"/> to use (InvariantCulture if NULL)</param>
public static TweenerCore<int, int, NoOptions> DOCounter(
this Text target, int fromValue, int endValue, float duration, bool addThousandsSeparator = true, CultureInfo culture = null
){
int v = fromValue;
CultureInfo cInfo = !addThousandsSeparator ? null : culture ?? CultureInfo.InvariantCulture;
TweenerCore<int, int, NoOptions> t = DOTween.To(() => v, x => {
v = x;
target.text = addThousandsSeparator
? v.ToString("N0", cInfo)
: v.ToString();
}, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Text's alpha color to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param><param name="duration">The duration of the tween</param>
public static TweenerCore<Color, Color, ColorOptions> DOFade(this Text target, float endValue, float duration)
{
TweenerCore<Color, Color, ColorOptions> t = DOTween.ToAlpha(() => target.color, x => target.color = x, endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Text's text to the given value.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end string to tween to</param><param name="duration">The duration of the tween</param>
/// <param name="richTextEnabled">If TRUE (default), rich text will be interpreted correctly while animated,
/// otherwise all tags will be considered as normal text</param>
/// <param name="scrambleMode">The type of scramble mode to use, if any</param>
/// <param name="scrambleChars">A string containing the characters to use for scrambling.
/// Use as many characters as possible (minimum 10) because DOTween uses a fast scramble mode which gives better results with more characters.
/// Leave it to NULL (default) to use default ones</param>
public static TweenerCore<string, string, StringOptions> DOText(this Text target, string endValue, float duration, bool richTextEnabled = true, ScrambleMode scrambleMode = ScrambleMode.None, string scrambleChars = null)
{
if (endValue == null) {
if (Debugger.logPriority > 0) Debugger.LogWarning("You can't pass a NULL string to DOText: an empty string will be used instead to avoid errors");
endValue = "";
}
TweenerCore<string, string, StringOptions> t = DOTween.To(() => target.text, x => target.text = x, endValue, duration);
t.SetOptions(richTextEnabled, scrambleMode, scrambleChars)
.SetTarget(target);
return t;
}
#endregion
#region Blendables
#region Graphic
/// <summary>Tweens a Graphic's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Graphic as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Graphic target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#region Image
/// <summary>Tweens a Image's color to the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Image as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Image target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#region Text
/// <summary>Tweens a Text's color BY the given value,
/// in a way that allows other DOBlendableColor tweens to work together on the same target,
/// instead than fight each other as multiple DOColor would do.
/// Also stores the Text as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The value to tween to</param><param name="duration">The duration of the tween</param>
public static Tweener DOBlendableColor(this Text target, Color endValue, float duration)
{
endValue = endValue - target.color;
Color to = new Color(0, 0, 0, 0);
return DOTween.To(() => to, x => {
Color diff = x - to;
to = x;
target.color += diff;
}, endValue, duration)
.Blendable().SetTarget(target);
}
#endregion
#endregion
#region Shapes
/// <summary>Tweens a RectTransform's anchoredPosition so that it draws a circle around the given center.
/// Also stores the RectTransform as the tween's target so it can be used for filtered operations.<para/>
/// IMPORTANT: SetFrom(value) requires a <see cref="Vector2"/> instead of a float, where the X property represents the "from degrees value"</summary>
/// <param name="center">Circle-center/pivot around which to rotate (in UI anchoredPosition coordinates)</param>
/// <param name="endValueDegrees">The end value degrees to reach (to rotate counter-clockwise pass a negative value)</param>
/// <param name="duration">The duration of the tween</param>
/// <param name="relativeCenter">If TRUE the <see cref="center"/> coordinates will be considered as relative to the target's current anchoredPosition</param>
/// <param name="snapping">If TRUE the tween will smoothly snap all values to integers</param>
public static TweenerCore<Vector2, Vector2, CircleOptions> DOShapeCircle(
this RectTransform target, Vector2 center, float endValueDegrees, float duration, bool relativeCenter = false, bool snapping = false
)
{
TweenerCore<Vector2, Vector2, CircleOptions> t = DOTween.To(
CirclePlugin.Get(), () => target.anchoredPosition, x => target.anchoredPosition = x, center, duration
);
t.SetOptions(endValueDegrees, relativeCenter, snapping).SetTarget(target);
return t;
}
#endregion
#endregion
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
// ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
public static class Utils
{
/// <summary>
/// Converts the anchoredPosition of the first RectTransform to the second RectTransform,
/// taking into consideration offset, anchors and pivot, and returns the new anchoredPosition
/// </summary>
public static Vector2 SwitchToRectTransform(RectTransform from, RectTransform to)
{
Vector2 localPoint;
Vector2 fromPivotDerivedOffset = new Vector2(from.rect.width * 0.5f + from.rect.xMin, from.rect.height * 0.5f + from.rect.yMin);
Vector2 screenP = RectTransformUtility.WorldToScreenPoint(null, from.position);
screenP += fromPivotDerivedOffset;
RectTransformUtility.ScreenPointToLocalPointInRectangle(to, screenP, null, out localPoint);
Vector2 pivotDerivedOffset = new Vector2(to.rect.width * 0.5f + to.rect.xMin, to.rect.height * 0.5f + to.rect.yMin);
return to.anchoredPosition + localPoint - pivotDerivedOffset;
}
}
}
}
#endif

View File

@ -0,0 +1,389 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
using System;
using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Options;
//#if UNITY_2018_1_OR_NEWER && (NET_4_6 || NET_STANDARD_2_0)
//using Task = System.Threading.Tasks.Task;
//#endif
#pragma warning disable 1591
namespace DG.Tweening
{
/// <summary>
/// Shortcuts/functions that are not strictly related to specific Modules
/// but are available only on some Unity versions
/// </summary>
public static class DOTweenModuleUnityVersion
{
#region Material
/// <summary>Tweens a Material's color using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param><param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this Material target, Gradient gradient, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.color = c.color;
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
/// <summary>Tweens a Material's named color property using the given gradient
/// (NOTE 1: only uses the colors of the gradient, not the alphas - NOTE 2: creates a Sequence, not a Tweener).
/// Also stores the image as the tween's target so it can be used for filtered operations</summary>
/// <param name="gradient">The gradient to use</param>
/// <param name="property">The name of the material property to tween (like _Tint or _SpecColor)</param>
/// <param name="duration">The duration of the tween</param>
public static Sequence DOGradientColor(this Material target, Gradient gradient, string property, float duration)
{
Sequence s = DOTween.Sequence();
GradientColorKey[] colors = gradient.colorKeys;
int len = colors.Length;
for (int i = 0; i < len; ++i) {
GradientColorKey c = colors[i];
if (i == 0 && c.time <= 0) {
target.SetColor(property, c.color);
continue;
}
float colorDuration = i == len - 1
? duration - s.Duration(false) // Verifies that total duration is correct
: duration * (i == 0 ? c.time : c.time - colors[i - 1].time);
s.Append(target.DOColor(c.color, property, colorDuration).SetEase(Ease.Linear));
}
s.SetTarget(target);
return s;
}
#endregion
#region CustomYieldInstructions
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or complete.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForCompletion(true);</code>
/// </summary>
public static CustomYieldInstruction WaitForCompletion(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForCompletion(t);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or rewinded.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForRewind();</code>
/// </summary>
public static CustomYieldInstruction WaitForRewind(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForRewind(t);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForKill();</code>
/// </summary>
public static CustomYieldInstruction WaitForKill(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForKill(t);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or has gone through the given amount of loops.
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForElapsedLoops(2);</code>
/// </summary>
/// <param name="elapsedLoops">Elapsed loops to wait for</param>
public static CustomYieldInstruction WaitForElapsedLoops(this Tween t, int elapsedLoops, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForElapsedLoops(t, elapsedLoops);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed
/// or has reached the given time position (loops included, delays excluded).
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForPosition(2.5f);</code>
/// </summary>
/// <param name="position">Position (loops included, delays excluded) to wait for</param>
public static CustomYieldInstruction WaitForPosition(this Tween t, float position, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForPosition(t, position);
}
/// <summary>
/// Returns a <see cref="CustomYieldInstruction"/> that waits until the tween is killed or started
/// (meaning when the tween is set in a playing state the first time, after any eventual delay).
/// It can be used inside a coroutine as a yield.
/// <para>Example usage:</para><code>yield return myTween.WaitForStart();</code>
/// </summary>
public static CustomYieldInstruction WaitForStart(this Tween t, bool returnCustomYieldInstruction)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return null;
}
return new DOTweenCYInstruction.WaitForStart(t);
}
#endregion
#if UNITY_2018_1_OR_NEWER
#region Unity 2018.1 or Newer
#region Material
/// <summary>Tweens a Material's named texture offset property with the given ID to the given value.
/// Also stores the material as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="propertyID">The ID of the material property to tween (also called nameID in Unity's manual)</param>
/// <param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOOffset(this Material target, Vector2 endValue, int propertyID, float duration)
{
if (!target.HasProperty(propertyID)) {
if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID);
return null;
}
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.GetTextureOffset(propertyID), x => target.SetTextureOffset(propertyID, x), endValue, duration);
t.SetTarget(target);
return t;
}
/// <summary>Tweens a Material's named texture scale property with the given ID to the given value.
/// Also stores the material as the tween's target so it can be used for filtered operations</summary>
/// <param name="endValue">The end value to reach</param>
/// <param name="propertyID">The ID of the material property to tween (also called nameID in Unity's manual)</param>
/// <param name="duration">The duration of the tween</param>
public static TweenerCore<Vector2, Vector2, VectorOptions> DOTiling(this Material target, Vector2 endValue, int propertyID, float duration)
{
if (!target.HasProperty(propertyID)) {
if (Debugger.logPriority > 0) Debugger.LogMissingMaterialProperty(propertyID);
return null;
}
TweenerCore<Vector2, Vector2, VectorOptions> t = DOTween.To(() => target.GetTextureScale(propertyID), x => target.SetTextureScale(propertyID, x), endValue, duration);
t.SetTarget(target);
return t;
}
#endregion
#region .NET 4.6 or Newer
#if UNITY_2018_1_OR_NEWER && (NET_4_6 || NET_STANDARD_2_0)
#region Async Instructions
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or complete.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.WaitForCompletion();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForCompletion(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && !t.IsComplete()) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or rewinded.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForRewind();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForRewind(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && (!t.playedOnce || t.position * (t.CompletedLoops() + 1) > 0)) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForKill();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForKill(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or has gone through the given amount of loops.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForElapsedLoops();</code>
/// </summary>
/// <param name="elapsedLoops">Elapsed loops to wait for</param>
public static async System.Threading.Tasks.Task AsyncWaitForElapsedLoops(this Tween t, int elapsedLoops)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && t.CompletedLoops() < elapsedLoops) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed or started
/// (meaning when the tween is set in a playing state the first time, after any eventual delay).
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForPosition();</code>
/// </summary>
/// <param name="position">Position (loops included, delays excluded) to wait for</param>
public static async System.Threading.Tasks.Task AsyncWaitForPosition(this Tween t, float position)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && t.position * (t.CompletedLoops() + 1) < position) await System.Threading.Tasks.Task.Yield();
}
/// <summary>
/// Returns an async <see cref="System.Threading.Tasks.Task"/> that waits until the tween is killed.
/// It can be used inside an async operation.
/// <para>Example usage:</para><code>await myTween.AsyncWaitForKill();</code>
/// </summary>
public static async System.Threading.Tasks.Task AsyncWaitForStart(this Tween t)
{
if (!t.active) {
if (Debugger.logPriority > 0) Debugger.LogInvalidTween(t);
return;
}
while (t.active && !t.playedOnce) await System.Threading.Tasks.Task.Yield();
}
#endregion
#endif
#endregion
#endregion
#endif
}
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
// ███ CLASSES █████████████████████████████████████████████████████████████████████████████████████████████████████████
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
public static class DOTweenCYInstruction
{
public class WaitForCompletion : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && !t.IsComplete();
}}
readonly Tween t;
public WaitForCompletion(Tween tween)
{
t = tween;
}
}
public class WaitForRewind : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && (!t.playedOnce || t.position * (t.CompletedLoops() + 1) > 0);
}}
readonly Tween t;
public WaitForRewind(Tween tween)
{
t = tween;
}
}
public class WaitForKill : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active;
}}
readonly Tween t;
public WaitForKill(Tween tween)
{
t = tween;
}
}
public class WaitForElapsedLoops : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && t.CompletedLoops() < elapsedLoops;
}}
readonly Tween t;
readonly int elapsedLoops;
public WaitForElapsedLoops(Tween tween, int elapsedLoops)
{
t = tween;
this.elapsedLoops = elapsedLoops;
}
}
public class WaitForPosition : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && t.position * (t.CompletedLoops() + 1) < position;
}}
readonly Tween t;
readonly float position;
public WaitForPosition(Tween tween, float position)
{
t = tween;
this.position = position;
}
}
public class WaitForStart : CustomYieldInstruction
{
public override bool keepWaiting { get {
return t.active && !t.playedOnce;
}}
readonly Tween t;
public WaitForStart(Tween tween)
{
t = tween;
}
}
}
}

View File

@ -0,0 +1,167 @@
// Author: Daniele Giardini - http://www.demigiant.com
// Created: 2018/07/13
using System;
using System.Reflection;
using UnityEngine;
using DG.Tweening.Core;
using DG.Tweening.Plugins.Core.PathCore;
using DG.Tweening.Plugins.Options;
#pragma warning disable 1591
namespace DG.Tweening
{
/// <summary>
/// Utility functions that deal with available Modules.
/// Modules defines:
/// - DOTAUDIO
/// - DOTPHYSICS
/// - DOTPHYSICS2D
/// - DOTSPRITE
/// - DOTUI
/// Extra defines set and used for implementation of external assets:
/// - DOTWEEN_TMP ► TextMesh Pro
/// - DOTWEEN_TK2D ► 2D Toolkit
/// </summary>
public static class DOTweenModuleUtils
{
static bool _initialized;
#region Reflection
/// <summary>
/// Called via Reflection by DOTweenComponent on Awake
/// </summary>
#if UNITY_2018_1_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
public static void Init()
{
if (_initialized) return;
_initialized = true;
DOTweenExternalCommand.SetOrientationOnPath += Physics.SetOrientationOnPath;
#if UNITY_EDITOR
#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1
UnityEditor.EditorApplication.playmodeStateChanged += PlaymodeStateChanged;
#else
UnityEditor.EditorApplication.playModeStateChanged += PlaymodeStateChanged;
#endif
#endif
}
#if UNITY_2018_1_OR_NEWER
#pragma warning disable
[UnityEngine.Scripting.Preserve]
// Just used to preserve methods when building, never called
static void Preserver()
{
Assembly[] loadedAssemblies = AppDomain.CurrentDomain.GetAssemblies();
MethodInfo mi = typeof(MonoBehaviour).GetMethod("Stub");
}
#pragma warning restore
#endif
#endregion
#if UNITY_EDITOR
// Fires OnApplicationPause in DOTweenComponent even when Editor is paused (otherwise it's only fired at runtime)
#if UNITY_4_3 || UNITY_4_4 || UNITY_4_5 || UNITY_4_6 || UNITY_5 || UNITY_2017_1
static void PlaymodeStateChanged()
#else
static void PlaymodeStateChanged(UnityEditor.PlayModeStateChange state)
#endif
{
if (DOTween.instance == null) return;
DOTween.instance.OnApplicationPause(UnityEditor.EditorApplication.isPaused);
}
#endif
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
// ███ INTERNAL CLASSES ████████████████████████████████████████████████████████████████████████████████████████████████
// █████████████████████████████████████████████████████████████████████████████████████████████████████████████████████
public static class Physics
{
// Called via DOTweenExternalCommand callback
public static void SetOrientationOnPath(PathOptions options, Tween t, Quaternion newRot, Transform trans)
{
#if true // PHYSICS_MARKER
if (options.isRigidbody) ((Rigidbody)t.target).rotation = newRot;
else trans.rotation = newRot;
#else
trans.rotation = newRot;
#endif
}
// Returns FALSE if the DOTween's Physics2D Module is disabled, or if there's no Rigidbody2D attached
public static bool HasRigidbody2D(Component target)
{
#if true // PHYSICS2D_MARKER
return target.GetComponent<Rigidbody2D>() != null;
#else
return false;
#endif
}
#region Called via Reflection
// Called via Reflection by DOTweenPathInspector
// Returns FALSE if the DOTween's Physics Module is disabled, or if there's no rigidbody attached
#if UNITY_2018_1_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
public static bool HasRigidbody(Component target)
{
#if true // PHYSICS_MARKER
return target.GetComponent<Rigidbody>() != null;
#else
return false;
#endif
}
// Called via Reflection by DOTweenPath
#if UNITY_2018_1_OR_NEWER
[UnityEngine.Scripting.Preserve]
#endif
public static TweenerCore<Vector3, Path, PathOptions> CreateDOTweenPathTween(
MonoBehaviour target, bool tweenRigidbody, bool isLocal, Path path, float duration, PathMode pathMode
){
TweenerCore<Vector3, Path, PathOptions> t = null;
bool rBodyFoundAndTweened = false;
#if true // PHYSICS_MARKER
if (tweenRigidbody) {
Rigidbody rBody = target.GetComponent<Rigidbody>();
if (rBody != null) {
rBodyFoundAndTweened = true;
t = isLocal
? rBody.DOLocalPath(path, duration, pathMode)
: rBody.DOPath(path, duration, pathMode);
}
}
#endif
#if true // PHYSICS2D_MARKER
if (!rBodyFoundAndTweened && tweenRigidbody) {
Rigidbody2D rBody2D = target.GetComponent<Rigidbody2D>();
if (rBody2D != null) {
rBodyFoundAndTweened = true;
t = isLocal
? rBody2D.DOLocalPath(path, duration, pathMode)
: rBody2D.DOPath(path, duration, pathMode);
}
}
#endif
if (!rBodyFoundAndTweened) {
t = isLocal
? target.transform.DOLocalPath(path, duration, pathMode)
: target.transform.DOPath(path, duration, pathMode);
}
return t;
}
#endregion
}
}
}

View File

@ -0,0 +1,29 @@
DOTween and DOTween Pro are copyright (c) 2014-2018 Daniele Giardini - Demigiant
// IMPORTANT!!! /////////////////////////////////////////////
// Upgrading DOTween from versions older than 1.2.000 ///////
// (or DOTween Pro older than 1.0.000) //////////////////////
-------------------------------------------------------------
If you're upgrading your project from a version of DOTween older than 1.2.000 (or DOTween Pro older than 1.0.000) please follow these instructions carefully.
1) Import the new version in the same folder as the previous one, overwriting old files. A lot of errors will appear but don't worry
2) Close and reopen Unity (and your project). This is fundamental: skipping this step will cause a bloodbath
3) Open DOTween's Utility Panel (Tools > Demigiant > DOTween Utility Panel) if it doesn't open automatically, then press "Setup DOTween...": this will run the upgrade setup
4) From the Add/Remove Modules panel that opens, activate/deactivate Modules for Unity systems and for external assets (Pro version only)
// GET STARTED //////////////////////////////////////////////
- After importing a new DOTween update, select DOTween's Utility Panel from the "Tools/Demigiant" menu (if it doesn't open automatically) and press the "Setup DOTween..." button to activate/deactivate Modules. You can also access a Preferences Tab from there to choose default settings for DOTween.
- In your code, add "using DG.Tweening" to each class where you want to use DOTween.
- You're ready to tween. Check out the links below for full documentation and license info.
// LINKS ///////////////////////////////////////////////////////
DOTween website (documentation, examples, etc): http://dotween.demigiant.com
DOTween license: http://dotween.demigiant.com/license.php
DOTween repository (Google Code): https://code.google.com/p/dotween/
Demigiant website (documentation, examples, etc): http://www.demigiant.com
// NOTES //////////////////////////////////////////////////////
- DOTween's Utility Panel can be found under "Tools > Demigiant > DOTween Utility Panel" and also contains other useful options, plus a tab to set DOTween's preferences

View File

@ -0,0 +1,119 @@
#if UNITY_EDITOR
using System.Linq;
using UnityEditor;
using UnityEngine;
namespace Crosstales.Common.EditorTask
{
/// <summary>Base for adding and removing the given symbols to PlayerSettings compiler define symbols.</summary>
public abstract class BaseCompileDefines
{
#region Public methods
/// <summary>Adds the given symbols to the compiler defines.</summary>
/// <param name="symbols">Symbols to add to the compiler defines</param>
public static void AddSymbolsToAllTargets(params string[] symbols)
{
addSymbolsToAllTargets(symbols);
}
/// <summary>Removes the given symbols from the compiler defines.</summary>
/// <param name="symbols">Symbols to remove from the compiler defines</param>
public static void RemoveSymbolsFromAllTargets(params string[] symbols)
{
removeSymbolsFromAllTargets(symbols);
}
#endregion
#region Protected methods
protected static void addSymbolsToAllTargets(params string[] symbols)
{
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup)))
{
if (!isValidBuildTargetGroup(group)) continue;
System.Collections.Generic.List<string> defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(group).Split(';').Select(d => d.Trim()).ToList();
bool changed = false;
foreach (string symbol in symbols.Where(symbol => !defineSymbols.Contains(symbol)))
{
defineSymbols.Add(symbol);
changed = true;
}
if (changed)
{
try
{
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, string.Join(";", defineSymbols.ToArray()));
}
catch (System.Exception)
{
Debug.LogError($"Could not add compile defines for build target group: {group}");
//throw;
}
}
}
}
protected static void removeSymbolsFromAllTargets(params string[] symbols)
{
foreach (BuildTargetGroup group in System.Enum.GetValues(typeof(BuildTargetGroup)))
{
if (!isValidBuildTargetGroup(group)) continue;
System.Collections.Generic.List<string> defineSymbols = PlayerSettings.GetScriptingDefineSymbolsForGroup(group).Split(';').Select(d => d.Trim()).ToList();
bool changed = false;
foreach (string symbol in symbols.Where(symbol => defineSymbols.Contains(symbol)))
{
defineSymbols.Remove(symbol);
changed = true;
}
if (changed)
{
try
{
PlayerSettings.SetScriptingDefineSymbolsForGroup(group, string.Join(";", defineSymbols.ToArray()));
}
catch (System.Exception)
{
Debug.LogError($"Could not remove compile defines for build target group: {group}");
//throw;
}
}
}
}
#endregion
#region Private methods
private static bool isValidBuildTargetGroup(BuildTargetGroup group)
{
return group != BuildTargetGroup.Unknown && !isObsolete(group);
}
private static bool isObsolete(System.Enum value)
{
int enumInt = (int)(object)value;
if (enumInt == 4 || enumInt == 14)
return false;
System.Reflection.FieldInfo field = value.GetType().GetField(value.ToString());
System.ObsoleteAttribute[] attributes = (System.ObsoleteAttribute[])field.GetCustomAttributes(typeof(System.ObsoleteAttribute), false);
return attributes.Length > 0;
}
#endregion
}
}
#endif
// © 2018-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,62 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
namespace Crosstales.Common.EditorTask
{
/// <summary>Base-class for moving all resources to 'Editor Default Resources'.</summary>
public abstract class BaseSetupResources
{
protected static void setupResources(string source, string sourceFolder, string target, string targetFolder, string metafile)
{
bool exists = false;
try
{
if (System.IO.Directory.Exists(sourceFolder))
{
exists = true;
if (!System.IO.Directory.Exists(targetFolder))
System.IO.Directory.CreateDirectory(targetFolder);
System.IO.DirectoryInfo dirSource = new System.IO.DirectoryInfo(sourceFolder);
foreach (System.IO.FileInfo file in dirSource.GetFiles("*"))
{
if (System.IO.File.Exists(targetFolder + file.Name))
{
if (Util.BaseConstants.DEV_DEBUG)
Debug.Log($"File exists: {file}");
}
else
{
AssetDatabase.MoveAsset(source + file.Name, target + file.Name);
if (Util.BaseConstants.DEV_DEBUG)
Debug.Log($"File moved: {file}");
}
}
//dirSource.Delete(true);
dirSource.Delete();
if (System.IO.File.Exists(metafile))
System.IO.File.Delete(metafile);
}
}
catch (System.Exception ex)
{
if (Util.BaseConstants.DEV_DEBUG)
Debug.LogError($"Could not move all files: {ex}");
}
finally
{
if (exists)
EditorUtil.BaseEditorHelper.RefreshAssetDatabase();
}
}
}
}
#endif
// © 2018-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,40 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
namespace Crosstales.Common.EditorTask
{
/// <summary>Checks if a 'Happy new year'-message must be displayed.</summary>
[InitializeOnLoad]
public static class NYCheck
{
private const string KEY_NYCHECK_DATE = "CT_CFG_NYCHECK_DATE";
#region Constructor
static NYCheck()
{
string lastYear = EditorPrefs.GetString(KEY_NYCHECK_DATE);
string year = System.DateTime.Now.ToString("yyyy");
//string year = "9999"; //only for test
string month = System.DateTime.Now.ToString("MM");
//string month = "01"; //only for test
if (!year.Equals(lastYear) && month.Equals("01"))
{
Debug.LogWarning(Util.BaseHelper.CreateString("-", 400));
Debug.LogWarning($"<color=yellow>¸.•°*”˜˜”*°•.¸ ★</color> <b><color=darkblue>crosstales LLC</color></b> wishes you a <b>happy</b> and <b>successful <color=orange>{year}</color></b>! <color=yellow>★ ¸.•*¨`*•.</color><color=cyan>♫</color><color=red>❤</color><color=lime>♫</color><color=red>❤</color><color=magenta>♫</color><color=red>❤</color>");
Debug.LogWarning(Util.BaseHelper.CreateString("-", 400));
if (!year.Equals("9999"))
EditorPrefs.SetString(KEY_NYCHECK_DATE, year);
}
}
#endregion
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,44 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
namespace Crosstales.Common.EditorTask
{
/// <summary>Moves all resources to 'Editor Default Resources'.</summary>
[InitializeOnLoad]
public abstract class SetupResources : BaseSetupResources
{
#region Constructor
static SetupResources()
{
Setup();
}
#endregion
#region Public methods
public static void Setup()
{
#if !CT_DEVELOP
string path = Application.dataPath;
string assetpath = "Assets/Plugins/crosstales/Common/";
string sourceFolder = $"{path}/Plugins/crosstales/Common/Icons/";
string source = $"{assetpath}Icons/";
string targetFolder = $"{path}/Editor Default Resources/crosstales/Common/";
string target = "Assets/Editor Default Resources/crosstales/Common/";
string metafile = $"{assetpath}Icons.meta";
setupResources(source, sourceFolder, target, targetFolder, metafile);
#endif
}
#endregion
}
}
#endif
// © 2019-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,723 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using System.Linq;
namespace Crosstales.Common.EditorUtil
{
/// <summary>Base for various Editor helper functions.</summary>
public abstract class BaseEditorHelper : Util.BaseHelper
{
#region Static variables
private static readonly System.Type moduleManager = System.Type.GetType("UnityEditor.Modules.ModuleManager,UnityEditor.dll");
private static readonly System.Reflection.MethodInfo isPlatformSupportLoaded = moduleManager.GetMethod("IsPlatformSupportLoaded", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
private static readonly System.Reflection.MethodInfo getTargetStringFromBuildTarget = moduleManager.GetMethod("GetTargetStringFromBuildTarget", System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.NonPublic);
private static Texture2D logo_asset_bwf;
private static Texture2D logo_asset_dj;
private static Texture2D logo_asset_fb;
private static Texture2D logo_asset_oc;
private static Texture2D logo_asset_radio;
private static Texture2D logo_asset_rtv;
private static Texture2D logo_asset_tb;
private static Texture2D logo_asset_tpb;
private static Texture2D logo_asset_tps;
private static Texture2D logo_asset_tr;
private static Texture2D logo_ct;
private static Texture2D logo_unity;
private static Texture2D icon_save;
private static Texture2D icon_reset;
private static Texture2D icon_refresh;
private static Texture2D icon_delete;
private static Texture2D icon_folder;
private static Texture2D icon_plus;
private static Texture2D icon_minus;
private static Texture2D icon_manual;
private static Texture2D icon_api;
private static Texture2D icon_forum;
private static Texture2D icon_product;
private static Texture2D icon_check;
private static Texture2D social_Discord;
private static Texture2D social_Facebook;
private static Texture2D social_Twitter;
private static Texture2D social_Youtube;
private static Texture2D social_Linkedin;
private static Texture2D video_promo;
private static Texture2D video_tutorial;
private static Texture2D icon_videos;
private static Texture2D icon_3p_assets;
private static Texture2D asset_PlayMaker;
private static Texture2D asset_VolumetricAudio;
private static Texture2D asset_rocktomate;
#endregion
#region Static properties
public static Texture2D Logo_Asset_BWF => loadImage(ref logo_asset_bwf, "logo_asset_bwf.png");
public static Texture2D Logo_Asset_DJ => loadImage(ref logo_asset_dj, "logo_asset_dj.png");
public static Texture2D Logo_Asset_FB => loadImage(ref logo_asset_fb, "logo_asset_fb.png");
public static Texture2D Logo_Asset_OC => loadImage(ref logo_asset_oc, "logo_asset_oc.png");
public static Texture2D Logo_Asset_Radio => loadImage(ref logo_asset_radio, "logo_asset_radio.png");
public static Texture2D Logo_Asset_RTV => loadImage(ref logo_asset_rtv, "logo_asset_rtv.png");
public static Texture2D Logo_Asset_TB => loadImage(ref logo_asset_tb, "logo_asset_tb.png");
public static Texture2D Logo_Asset_TPB => loadImage(ref logo_asset_tpb, "logo_asset_tpb.png");
public static Texture2D Logo_Asset_TPS => loadImage(ref logo_asset_tps, "logo_asset_tps.png");
public static Texture2D Logo_Asset_TR => loadImage(ref logo_asset_tr, "logo_asset_tr.png");
public static Texture2D Logo_CT => loadImage(ref logo_ct, "logo_ct.png");
public static Texture2D Logo_Unity => loadImage(ref logo_unity, "logo_unity.png");
public static Texture2D Icon_Save => loadImage(ref icon_save, "icon_save.png");
public static Texture2D Icon_Reset => loadImage(ref icon_reset, "icon_reset.png");
public static Texture2D Icon_Refresh => loadImage(ref icon_refresh, "icon_refresh.png");
public static Texture2D Icon_Delete => loadImage(ref icon_delete, "icon_delete.png");
public static Texture2D Icon_Folder => loadImage(ref icon_folder, "icon_folder.png");
public static Texture2D Icon_Plus => loadImage(ref icon_plus, "icon_plus.png");
public static Texture2D Icon_Minus => loadImage(ref icon_minus, "icon_minus.png");
public static Texture2D Icon_Manual => loadImage(ref icon_manual, "icon_manual.png");
public static Texture2D Icon_API => loadImage(ref icon_api, "icon_api.png");
public static Texture2D Icon_Forum => loadImage(ref icon_forum, "icon_forum.png");
public static Texture2D Icon_Product => loadImage(ref icon_product, "icon_product.png");
public static Texture2D Icon_Check => loadImage(ref icon_check, "icon_check.png");
public static Texture2D Social_Discord => loadImage(ref social_Discord, "social_Discord.png");
public static Texture2D Social_Facebook => loadImage(ref social_Facebook, "social_Facebook.png");
public static Texture2D Social_Twitter => loadImage(ref social_Twitter, "social_Twitter.png");
public static Texture2D Social_Youtube => loadImage(ref social_Youtube, "social_Youtube.png");
public static Texture2D Social_Linkedin => loadImage(ref social_Linkedin, "social_Linkedin.png");
public static Texture2D Video_Promo => loadImage(ref video_promo, "video_promo.png");
public static Texture2D Video_Tutorial => loadImage(ref video_tutorial, "video_tutorial.png");
public static Texture2D Icon_Videos => loadImage(ref icon_videos, "icon_videos.png");
public static Texture2D Icon_3p_Assets => loadImage(ref icon_3p_assets, "icon_3p_assets.png");
public static Texture2D Asset_PlayMaker => loadImage(ref asset_PlayMaker, "asset_PlayMaker.png");
public static Texture2D Asset_VolumetricAudio => loadImage(ref asset_VolumetricAudio, "asset_VolumetricAudio.png");
public static Texture2D Asset_RockTomate => loadImage(ref asset_rocktomate, "asset_rocktomate.png");
#endregion
#region Public methods
/// <summary>Restart Unity.</summary>
/// <param name="executeMethod">Executed method after the restart (optional)</param>
public static void RestartUnity(string executeMethod = "")
{
UnityEditor.SceneManagement.EditorSceneManager.SaveCurrentModifiedScenesIfUserWantsTo();
bool success = false;
using (System.Diagnostics.Process process = new System.Diagnostics.Process())
{
try
{
process.StartInfo.CreateNoWindow = true;
process.StartInfo.UseShellExecute = false;
string scriptfile;
switch (Application.platform)
{
case RuntimePlatform.WindowsEditor:
scriptfile = $"{System.IO.Path.GetTempPath()}RestartUnity-{System.Guid.NewGuid()}.cmd";
System.IO.File.WriteAllText(scriptfile, generateWindowsRestartScript(executeMethod));
process.StartInfo.FileName = "cmd.exe";
process.StartInfo.Arguments = $"/c start \"\" \"{scriptfile}\"";
break;
case RuntimePlatform.OSXEditor:
scriptfile = $"{System.IO.Path.GetTempPath()}RestartUnity-{System.Guid.NewGuid()}.sh";
System.IO.File.WriteAllText(scriptfile, generateMacRestartScript(executeMethod));
process.StartInfo.FileName = "/bin/sh";
process.StartInfo.Arguments = $"\"{scriptfile}\" &";
break;
case RuntimePlatform.LinuxEditor:
scriptfile = $"{System.IO.Path.GetTempPath()}RestartUnity-{System.Guid.NewGuid()}.sh";
System.IO.File.WriteAllText(scriptfile, generateLinuxRestartScript(executeMethod));
process.StartInfo.FileName = "/bin/sh";
process.StartInfo.Arguments = $"\"{scriptfile}\" &";
break;
default:
Debug.LogError($"Unsupported Unity Editor: {Application.platform}");
return;
}
process.Start();
if (isWindowsEditor)
process.WaitForExit(Util.BaseConstants.PROCESS_KILL_TIME);
success = true;
}
catch (System.Exception ex)
{
string errorMessage = $"Could restart Unity: {ex}";
Debug.LogError(errorMessage);
}
}
if (success)
EditorApplication.Exit(0);
}
/// <summary>Shows a separator-UI.</summary>
/// <param name="space">Space in pixels between the component and the separator line (default: 12, optional).</param>
public static void SeparatorUI(int space = 12)
{
GUILayout.Space(space);
GUILayout.Box(string.Empty, GUILayout.ExpandWidth(true), GUILayout.Height(1));
}
/// <summary>Generates a read-only text field with a label.</summary>
public static void ReadOnlyTextField(string label, string text)
{
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.LabelField(label, GUILayout.Width(EditorGUIUtility.labelWidth - 4));
EditorGUILayout.SelectableLabel(text, EditorStyles.textField, GUILayout.Height(EditorGUIUtility.singleLineHeight));
}
EditorGUILayout.EndHorizontal();
}
/// <summary>Refreshes the asset database.</summary>
/// <param name="options">Asset import options (default: ImportAssetOptions.Default, optional).</param>
public static void RefreshAssetDatabase(ImportAssetOptions options = ImportAssetOptions.Default)
{
if (isEditorMode)
{
AssetDatabase.Refresh(options);
}
}
/// <summary>Invokes a public static method on a full qualified class.</summary>
/// <param name="className">Full qualified name of the class</param>
/// <param name="methodName">Public static method of the class to execute</param>
/// <param name="parameters">Parameters for the method (optional)</param>
public static void InvokeMethod(string className, string methodName, params object[] parameters)
{
if (string.IsNullOrEmpty(className))
{
Debug.LogWarning("'className' is null or empty; can not execute.");
return;
}
if (string.IsNullOrEmpty(methodName))
{
Debug.LogWarning("'methodName' is null or empty; can not execute.");
return;
}
foreach (System.Type type in System.AppDomain.CurrentDomain.GetAssemblies().SelectMany(assembly => assembly.GetTypes()))
{
try
{
if (type.FullName?.Equals(className) == true)
if (type.IsClass)
type.GetMethod(methodName, System.Reflection.BindingFlags.Static | System.Reflection.BindingFlags.Public).Invoke(null, parameters);
}
catch (System.Exception ex)
{
Debug.LogWarning($"Could not execute method call: {ex}");
}
}
}
/// <summary>Returns the true if the BuildTarget is installed in Unity.</summary>
/// <param name="target">BuildTarget to test</param>
/// <returns>True if the BuildTarget is installed in Unity.</returns>
public static bool isValidBuildTarget(BuildTarget target)
{
return (bool)isPlatformSupportLoaded.Invoke(null, new object[] {(string)getTargetStringFromBuildTarget.Invoke(null, new object[] {target})});
}
/*
public static IEnumerable<BuildTarget> GetAvailableBuildTargets()
{
foreach (BuildTarget target in (BuildTarget[])Enum.GetValues(typeof(BuildTarget)))
{
BuildTargetGroup group = BuildPipeline.GetBuildTargetGroup(target);
if (BuildPipeline.IsBuildTargetSupported(group, target))
{
yield return target;
}
}
}
*/
/// <summary>Returns an argument for a name from the command line.</summary>
/// <param name="name">Name for the argument</param>
/// <returns>True if the BuildTarget is installed in Unity.</returns>
public static string getCLIArgument(string name)
{
string[] args = System.Environment.GetCommandLineArgs();
for (int ii = 0; ii < args.Length; ii++)
{
if (name.CTEquals(args[ii]) && args.Length > ii + 1)
return args[ii + 1];
}
return null;
}
/// <summary>Returns the BuildTarget for a build name, like 'win64'.</summary>
/// <param name="build">Build name, like 'win64'</param>
/// <returns>The BuildTarget for a build name.</returns>
public static BuildTarget getBuildTargetForBuildName(string build)
{
if ("win32".CTEquals(build) || "win".CTEquals(build))
return BuildTarget.StandaloneWindows;
if ("win64".CTEquals(build))
return BuildTarget.StandaloneWindows64;
if (!string.IsNullOrEmpty(build) && build.CTContains("osx"))
return BuildTarget.StandaloneOSX;
#if UNITY_2019_2_OR_NEWER
if (!string.IsNullOrEmpty(build) && build.CTContains("linux"))
return BuildTarget.StandaloneLinux64;
#else
if ("linux".CTEquals(build))
return BuildTarget.StandaloneLinux;
if ("linux64".CTEquals(build))
return BuildTarget.StandaloneLinux64;
if ("linuxuniversal".CTEquals(build))
return BuildTarget.StandaloneLinuxUniversal;
#endif
if ("android".CTEquals(build))
return BuildTarget.Android;
if ("ios".CTEquals(build))
return BuildTarget.iOS;
if ("wsaplayer".CTEquals(build) || "WindowsStoreApps".CTEquals(build))
return BuildTarget.WSAPlayer;
if ("webgl".CTEquals(build))
return BuildTarget.WebGL;
if ("tvOS".CTEquals(build))
return BuildTarget.tvOS;
if ("ps4".CTEquals(build))
return BuildTarget.PS4;
if ("xboxone".CTEquals(build))
return BuildTarget.XboxOne;
if ("switch".CTEquals(build))
return BuildTarget.Switch;
Debug.LogWarning($"Build target '{build}' not found! Returning 'StandaloneWindows64'.");
return BuildTarget.StandaloneWindows64;
}
/// <summary>Returns the build name for a BuildTarget.</summary>
/// <param name="build">BuildTarget for a build name</param>
/// <returns>The build name for a BuildTarget.</returns>
public static string getBuildNameFromBuildTarget(BuildTarget build)
{
switch (build)
{
case BuildTarget.StandaloneWindows:
return "Win";
case BuildTarget.StandaloneWindows64:
return "Win64";
case BuildTarget.StandaloneOSX:
return "OSXUniversal";
#if UNITY_2019_2_OR_NEWER
case BuildTarget.StandaloneLinux64:
return "Linux64";
#else
case BuildTarget.StandaloneLinux:
return "Linux";
case BuildTarget.StandaloneLinux64:
return "Linux64";
case BuildTarget.StandaloneLinuxUniversal:
return "LinuxUniversal";
#endif
case BuildTarget.Android:
return "Android";
case BuildTarget.iOS:
return "iOS";
case BuildTarget.WSAPlayer:
return "WindowsStoreApps";
case BuildTarget.WebGL:
return "WebGL";
case BuildTarget.tvOS:
return "tvOS";
case BuildTarget.PS4:
return "PS4";
case BuildTarget.XboxOne:
return "XboxOne";
case BuildTarget.Switch:
return "Switch";
default:
Debug.LogWarning($"Build target '{build}' not found! Returning Windows standalone.");
return "Win64";
}
}
/// <summary>Returns assets for a certain type.</summary>
/// <returns>List of assets for a certain type.</returns>
public static System.Collections.Generic.List<T> FindAssetsByType<T>() where T : Object
{
string[] guids = AssetDatabase.FindAssets($"t:{typeof(T)}");
return guids.Select(AssetDatabase.GUIDToAssetPath).Select(AssetDatabase.LoadAssetAtPath<T>).Where(asset => asset != null).ToList();
}
#endregion
#region Private methods
private static string generateWindowsRestartScript(string executeMethod)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
// setup
sb.AppendLine("@echo off");
sb.AppendLine("cls");
// title
sb.Append("title Restart of ");
sb.Append(Application.productName);
sb.AppendLine(" - DO NOT CLOSE THIS WINDOW!");
// header
sb.AppendLine("echo ##############################################################################");
sb.AppendLine("echo # #");
sb.AppendLine("echo # Common 2020.4.1 - Windows #");
sb.AppendLine("echo # Copyright 2018-2020 by www.crosstales.com #");
sb.AppendLine("echo # #");
sb.AppendLine("echo # This script restarts Unity. #");
sb.AppendLine("echo # This will take some time, so please be patient and DON'T CLOSE THIS #");
sb.AppendLine("echo # WINDOW before the process is finished! #");
sb.AppendLine("echo # #");
sb.AppendLine("echo ##############################################################################");
sb.Append("echo ");
sb.AppendLine(Application.productName);
sb.AppendLine("echo.");
sb.AppendLine("echo.");
// check if Unity is closed
sb.AppendLine(":waitloop");
sb.Append("if not exist \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("Temp\\UnityLockfile\" goto waitloopend");
sb.AppendLine();
sb.AppendLine("echo.");
sb.AppendLine("echo Waiting for Unity to close...");
sb.AppendLine("timeout /t 3");
/*
#if UNITY_2018_2_OR_NEWER
sb.Append("del \"");
sb.Append(Constants.PATH);
sb.Append("Temp\\UnityLockfile\" /q");
sb.AppendLine();
#endif
*/
sb.AppendLine("goto waitloop");
sb.AppendLine(":waitloopend");
// Restart Unity
sb.AppendLine("echo.");
sb.AppendLine("echo ##############################################################################");
sb.AppendLine("echo # Restarting Unity #");
sb.AppendLine("echo ##############################################################################");
sb.Append("start \"\" \"");
sb.Append(ValidatePath(EditorApplication.applicationPath, false));
sb.Append("\" -projectPath \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH.Substring(0, Util.BaseConstants.APPLICATION_PATH.Length - 1));
sb.Append("\"");
if (!string.IsNullOrEmpty(executeMethod))
{
sb.Append(" -executeMethod ");
sb.Append(executeMethod);
}
sb.AppendLine();
sb.AppendLine("echo.");
// check if Unity is started
sb.AppendLine(":waitloop2");
sb.Append("if exist \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("Temp\\UnityLockfile\" goto waitloopend2");
sb.AppendLine();
sb.AppendLine("echo Waiting for Unity to start...");
sb.AppendLine("timeout /t 3");
sb.AppendLine("goto waitloop2");
sb.AppendLine(":waitloopend2");
sb.AppendLine("echo.");
sb.AppendLine("echo Bye!");
sb.AppendLine("timeout /t 1");
sb.AppendLine("exit");
return sb.ToString();
}
private static string generateMacRestartScript(string executeMethod)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
// setup
sb.AppendLine("#!/bin/bash");
sb.AppendLine("set +v");
sb.AppendLine("clear");
// title
sb.Append("title='Relaunch of ");
sb.Append(Application.productName);
sb.AppendLine(" - DO NOT CLOSE THIS WINDOW!'");
sb.AppendLine("echo -n -e \"\\033]0;$title\\007\"");
// header
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.AppendLine("echo \"¦ ¦\"");
sb.AppendLine("echo \"¦ Common 2020.4.1 - macOS ¦\"");
sb.AppendLine("echo \"¦ Copyright 2018-2020 by www.crosstales.com ¦\"");
sb.AppendLine("echo \"¦ ¦\"");
sb.AppendLine("echo \"¦ This script restarts Unity. ¦\"");
sb.AppendLine("echo \"¦ This will take some time, so please be patient and DON'T CLOSE THIS ¦\"");
sb.AppendLine("echo \"¦ WINDOW before the process is finished! ¦\"");
sb.AppendLine("echo \"¦ ¦\"");
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.Append("echo \"");
sb.Append(Application.productName);
sb.AppendLine("\"");
sb.AppendLine("echo");
sb.AppendLine("echo");
// check if Unity is closed
sb.Append("while [ -f \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("Temp/UnityLockfile\" ]");
sb.AppendLine();
sb.AppendLine("do");
sb.AppendLine(" echo \"Waiting for Unity to close...\"");
sb.AppendLine(" sleep 3");
/*
#if UNITY_2018_2_OR_NEWER
sb.Append(" rm \"");
sb.Append(Constants.PATH);
sb.Append("Temp/UnityLockfile\"");
sb.AppendLine();
#endif
*/
sb.AppendLine("done");
// Restart Unity
sb.AppendLine("echo");
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.AppendLine("echo \"¦ Restarting Unity ¦\"");
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.Append("open -a \"");
sb.Append(EditorApplication.applicationPath);
sb.Append("\" --args -projectPath \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("\"");
if (!string.IsNullOrEmpty(executeMethod))
{
sb.Append(" -executeMethod ");
sb.Append(executeMethod);
}
sb.AppendLine();
//check if Unity is started
sb.AppendLine("echo");
sb.Append("while [ ! -f \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("Temp/UnityLockfile\" ]");
sb.AppendLine();
sb.AppendLine("do");
sb.AppendLine(" echo \"Waiting for Unity to start...\"");
sb.AppendLine(" sleep 3");
sb.AppendLine("done");
sb.AppendLine("echo");
sb.AppendLine("echo \"Bye!\"");
sb.AppendLine("sleep 1");
sb.AppendLine("exit");
return sb.ToString();
}
private static string generateLinuxRestartScript(string executeMethod)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
// setup
sb.AppendLine("#!/bin/bash");
sb.AppendLine("set +v");
sb.AppendLine("clear");
// title
sb.Append("title='Relaunch of ");
sb.Append(Application.productName);
sb.AppendLine(" - DO NOT CLOSE THIS WINDOW!'");
sb.AppendLine("echo -n -e \"\\033]0;$title\\007\"");
// header
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.AppendLine("echo \"¦ ¦\"");
sb.AppendLine("echo \"¦ Common 2020.4.1 - Linux ¦\"");
sb.AppendLine("echo \"¦ Copyright 2018-2020 by www.crosstales.com ¦\"");
sb.AppendLine("echo \"¦ ¦\"");
sb.AppendLine("echo \"¦ This script restarts Unity. ¦\"");
sb.AppendLine("echo \"¦ This will take some time, so please be patient and DON'T CLOSE THIS ¦\"");
sb.AppendLine("echo \"¦ WINDOW before the process is finished! ¦\"");
sb.AppendLine("echo \"¦ ¦\"");
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.Append("echo \"");
sb.Append(Application.productName);
sb.AppendLine("\"");
sb.AppendLine("echo");
sb.AppendLine("echo");
// check if Unity is closed
sb.Append("while [ -f \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("Temp/UnityLockfile\" ]");
sb.AppendLine();
sb.AppendLine("do");
sb.AppendLine(" echo \"Waiting for Unity to close...\"");
sb.AppendLine(" sleep 3");
/*
#if UNITY_2018_2_OR_NEWER
sb.Append(" rm \"");
sb.Append(Constants.PATH);
sb.Append("Temp/UnityLockfile\"");
sb.AppendLine();
#endif
*/
sb.AppendLine("done");
// Restart Unity
sb.AppendLine("echo");
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.AppendLine("echo \"¦ Restarting Unity ¦\"");
sb.AppendLine("echo \"+----------------------------------------------------------------------------+\"");
sb.Append('"');
sb.Append(EditorApplication.applicationPath);
sb.Append("\" --args -projectPath \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("\"");
if (!string.IsNullOrEmpty(executeMethod))
{
sb.Append(" -executeMethod ");
sb.Append(executeMethod);
}
sb.Append(" &");
sb.AppendLine();
// check if Unity is started
sb.AppendLine("echo");
sb.Append("while [ ! -f \"");
sb.Append(Util.BaseConstants.APPLICATION_PATH);
sb.Append("Temp/UnityLockfile\" ]");
sb.AppendLine();
sb.AppendLine("do");
sb.AppendLine(" echo \"Waiting for Unity to start...\"");
sb.AppendLine(" sleep 3");
sb.AppendLine("done");
sb.AppendLine("echo");
sb.AppendLine("echo \"Bye!\"");
sb.AppendLine("sleep 1");
sb.AppendLine("exit");
return sb.ToString();
}
private static Texture2D loadImage(ref Texture2D logo, string fileName)
{
if (logo == null)
{
#if CT_DEVELOP
logo = (Texture2D)AssetDatabase.LoadAssetAtPath($"Assets/Plugins/crosstales/Common/Icons/{fileName}", typeof(Texture2D));
#else
logo = (Texture2D)EditorGUIUtility.Load($"crosstales/Common/{fileName}");
#endif
if (logo == null)
Debug.LogWarning($"Image not found: {fileName}");
}
return logo;
}
#endregion
/*
// compress the folder into a ZIP file, uses https://github.com/r2d2rigo/dotnetzip-for-unity
static void CompressDirectory(string directory, string zipFileOutputPath)
{
Debug.Log("attempting to compress " + directory + " into " + zipFileOutputPath);
// display fake percentage, I can't get zip.SaveProgress event handler to work for some reason, whatever
EditorUtility.DisplayProgressBar("COMPRESSING... please wait", zipFileOutputPath, 0.38f);
using (ZipFile zip = new ZipFile())
{
zip.ParallelDeflateThreshold = -1; // DotNetZip bugfix that corrupts DLLs / binaries http://stackoverflow.com/questions/15337186/dotnetzip-badreadexception-on-extract
zip.AddDirectory(directory);
zip.Save(zipFileOutputPath);
}
EditorUtility.ClearProgressBar();
}
*/
}
}
#endif
// © 2018-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,56 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &113888
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 5
m_Component:
- component: {fileID: 405290}
- component: {fileID: 11411614}
m_Layer: 0
m_Name: Screenshot
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &405290
Transform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 113888}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!114 &11411614
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 113888}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: cd0c53ef60a81f140a5f5c69d6e738bf, type: 3}
m_Name:
m_EditorClassIdentifier:
Prefix: CT_Screenshot
Scale: 1
KeyCode: 289
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 113888}
m_IsPrefabParent: 1

View File

@ -0,0 +1,54 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1001 &100100000
Prefab:
m_ObjectHideFlags: 1
serializedVersion: 2
m_Modification:
m_TransformParent: {fileID: 0}
m_Modifications: []
m_RemovedComponents: []
m_ParentPrefab: {fileID: 0}
m_RootGameObject: {fileID: 1000011299910152}
m_IsPrefabParent: 1
--- !u!1 &1000011299910152
GameObject:
m_ObjectHideFlags: 0
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
serializedVersion: 4
m_Component:
- 4: {fileID: 4000013802688284}
- 114: {fileID: 114000014233112364}
m_Layer: 0
m_Name: SurviveSceneSwitch
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &4000013802688284
Transform:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011299910152}
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
m_Children: []
m_Father: {fileID: 0}
m_RootOrder: 0
--- !u!114 &114000014233112364
MonoBehaviour:
m_ObjectHideFlags: 1
m_PrefabParentObject: {fileID: 0}
m_PrefabInternal: {fileID: 100100000}
m_GameObject: {fileID: 1000011299910152}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 0c785f14f1d24f30836f90d598985193, type: 3}
m_Name:
m_EditorClassIdentifier:
Survivors: []

View File

@ -0,0 +1,46 @@
# crosstales LLC - Common package 2020.4.8
## Description
This folder and its content is needed for all assets from "crosstales LLC".
Please DON'T DELETE anything or the assets won't work anymore!
## Notes:
### macOS (notarization and Mac App Store)
To get an app through the Apples signing process, do one of the following things:
1) Add the following key to the entitlement-file:
<key>com.apple.security.cs.disable-library-validation</key><true/>
2) Sign the libraries after building:
codesign --deep --force --verify --verbose --timestamp --sign "Developer ID Application : YourCompanyName (0123456789)" "YourApp.app/Contents/Plugins/libProcessStart.bundle"
If everything fails, delete "libProcessStart.bundle".
## Contact
crosstales LLC
Schanzeneggstrasse 1
CH-8002 Zürich
* [Homepage](https://www.crosstales.com/)
* [Email](mailto:assets@crosstales.com)
### Social media
* [Facebook](https://www.facebook.com/crosstales/)
* [Twitter](https://twitter.com/crosstales)
* [LinkedIN](https://www.linkedin.com/company/crosstales)
## More information
* [AssetStore](https://assetstore.unity.com/lists/crosstales-42213?aid=1011lNGT)
* [Youtube-channel](https://www.youtube.com/c/Crosstales)
`Version: 16.12.2020`

View File

@ -0,0 +1,33 @@
using UnityEngine;
namespace Crosstales.Common.Audio
{
/// <summary>FFT analyzer for an audio channel.</summary>
public class FFTAnalyzer : MonoBehaviour
{
#region Variables
///<summary>Array for the samples. More samples mean better accuracy but it also needs more performance (default: 256).</summary>
[Tooltip("Array for the samples. More samples mean better accuracy but it also needs more performance (default: 256)")]
public float[] Samples = new float[256];
///<summary>Analyzed channel (0 = right, 1 = left, default: 0).</summary>
[Tooltip("Analyzed channel (0 = right, 1 = left, default: 0).")] [Range(0, 1)] public int Channel;
///<summary>FFT-algorithm to analyze the audio (default: BlackmanHarris).</summary>
[Tooltip("FFT-algorithm to analyze the audio (default: BlackmanHarris).")] public FFTWindow FFTMode = FFTWindow.BlackmanHarris;
#endregion
#region MonoBehaviour methods
private void Update()
{
AudioListener.GetSpectrumData(Samples, Channel, FFTMode);
}
#endregion
}
}
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,81 @@
using UnityEngine;
namespace Crosstales.Common.Audio
{
/// <summary>Simple spectrum visualizer.</summary>
public class SpectrumVisualizer : MonoBehaviour
{
#region Variables
///<summary>FFT-analyzer with the spectrum data.</summary>
[Tooltip("FFT-analyzer with the spectrum data.")] public FFTAnalyzer Analyzer;
///<summary>Prefab for the frequency representation.</summary>
[Tooltip("Prefab for the frequency representation.")] public GameObject VisualPrefab;
///<summary>Width per prefab.</summary>
[Tooltip("Width per prefab.")] public float Width = 0.075f;
///<summary>Gain-power for the frequency.</summary>
[Tooltip("Gain-power for the frequency.")] public float Gain = 70f;
///<summary>Frequency band from left-to-right (default: true).</summary>
[Tooltip("Frequency band from left-to-right (default: true).")] public bool LeftToRight = true;
///<summary>Opacity of the material of the prefab (default: 1).</summary>
[Tooltip("Opacity of the material of the prefab (default: 1).")] [Range(0f, 1f)] public float Opacity = 1f;
private Transform tf;
private Transform[] visualTransforms;
private Vector3 visualPos = Vector3.zero;
private int samplesPerChannel;
#endregion
#region MonoBehaviour methods
private void Start()
{
tf = transform;
samplesPerChannel = Analyzer.Samples.Length / 2;
visualTransforms = new Transform[samplesPerChannel];
for (int ii = 0; ii < samplesPerChannel; ii++)
{
//cut the upper frequencies >11000Hz
GameObject tempCube;
if (LeftToRight)
{
Vector3 position = tf.position;
tempCube = Instantiate(VisualPrefab, new Vector3(position.x + ii * Width, position.y, position.z), Quaternion.identity);
}
else
{
Vector3 position = tf.position;
tempCube = Instantiate(VisualPrefab, new Vector3(position.x - ii * Width, position.y, position.z), Quaternion.identity);
}
tempCube.GetComponent<Renderer>().material.color = Util.BaseHelper.HSVToRGB(360f / samplesPerChannel * ii, 1f, 1f, Opacity);
visualTransforms[ii] = tempCube.GetComponent<Transform>();
visualTransforms[ii].parent = tf;
}
}
private void Update()
{
for (int ii = 0; ii < visualTransforms.Length; ii++)
{
visualPos.Set(Width, Analyzer.Samples[ii] * Gain, Width);
visualTransforms[ii].localScale = visualPos;
}
}
#endregion
}
}
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,904 @@
using UnityEngine;
using System.Linq;
namespace Crosstales
{
/// <summary>Various extension methods.</summary>
public static class ExtensionMethods
{
#region Strings
/// <summary>
/// Extension method for strings.
/// Converts a string to title case (first letter uppercase).
/// </summary>
/// <param name="str">String-instance.</param>
/// <returns>Converted string in title case.</returns>
public static string CTToTitleCase(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
#if UNITY_WSA
return toTitleCase(str);
#else
return System.Globalization.CultureInfo.CurrentCulture.TextInfo.ToTitleCase(str.ToLower());
#endif
}
#if UNITY_WSA
/// <summary>
/// Converts to title case: each word starts with an upper case.
/// </summary>
private static string toTitleCase(string str)
{
if (str.Length == 0)
return str;
System.Text.StringBuilder result = new System.Text.StringBuilder(str);
result[0] = char.ToUpper(result[0]);
for (int ii = 1; ii < result.Length; ii++)
{
if (char.IsWhiteSpace(result[ii - 1]))
result[ii] = char.ToUpper(result[ii]);
else
result[ii] = char.ToLower(result[ii]);
}
return result.ToString();
}
#endif
/// <summary>
/// Extension method for strings.
/// Reverses a string.
/// </summary>
/// <param name="str">String-instance.</param>
/// <returns>Reversed string.</returns>
public static string CTReverse(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
char[] charArray = str.ToCharArray();
System.Array.Reverse(charArray);
return new string(charArray);
}
/// <summary>
/// Extension method for strings.
/// Case insensitive 'Replace'.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="oldString">String to replace.</param>
/// <param name="newString">New replacement string.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>Replaced string.</returns>
public static string CTReplace(this string str, string oldString, string newString, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
if (oldString == null)
throw new System.ArgumentNullException(nameof(oldString));
if (newString == null)
throw new System.ArgumentNullException(nameof(newString));
int index = str.IndexOf(oldString, comp);
bool MatchFound = index >= 0;
if (MatchFound)
{
str = str.Remove(index, oldString.Length);
str = str.Insert(index, newString);
}
return str;
}
/// <summary>
/// Extension method for strings.
/// Case insensitive 'Equals'.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="toCheck">String to check.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>True if the string contains the given string.</returns>
public static bool CTEquals(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
//if (toCheck == null)
// throw new System.ArgumentNullException("toCheck");
return str.Equals(toCheck, comp);
}
/// <summary>
/// Extension method for strings.
/// Case insensitive 'Contains'.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="toCheck">String to check.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>True if the string contains the given string.</returns>
public static bool CTContains(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
//if (toCheck == null)
// throw new System.ArgumentNullException("toCheck");
return str.IndexOf(toCheck, comp) >= 0;
}
/// <summary>
/// Extension method for strings.
/// Contains any given string.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="searchTerms">Search terms separated by the given split-character.</param>
/// <param name="splitChar">Split-character (default: ' ', optional)</param>
/// <returns>True if the string contains any parts of the given string.</returns>
public static bool CTContainsAny(this string str, string searchTerms, char splitChar = ' ')
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
if (string.IsNullOrEmpty(searchTerms))
return true;
char[] split = {splitChar};
return searchTerms.Split(split, System.StringSplitOptions.RemoveEmptyEntries).Any(searchTerm => str.CTContains(searchTerm));
}
/// <summary>
/// Extension method for strings.
/// Contains all given strings.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="searchTerms">Search terms separated by the given split-character.</param>
/// <param name="splitChar">Split-character (default: ' ', optional)</param>
/// <returns>True if the string contains all parts of the given string.</returns>
public static bool CTContainsAll(this string str, string searchTerms, char splitChar = ' ')
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
if (string.IsNullOrEmpty(searchTerms))
return true;
char[] split = {splitChar};
return searchTerms.Split(split, System.StringSplitOptions.RemoveEmptyEntries).All(searchTerm => str.CTContains(searchTerm));
}
/// <summary>
/// Extension method for strings.
/// Checks if the string is numeric.
/// </summary>
/// <param name="str">String-instance.</param>
/// <returns>True if the string is numeric.</returns>
public static bool CTisNumeric(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return double.TryParse(str, out double output);
}
/// <summary>
/// Extension method for strings.
/// Checks if the string is integer.
/// </summary>
/// <param name="str">String-instance.</param>
/// <returns>True if the string is integer.</returns>
public static bool CTisInteger(this string str)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return !str.Contains(".") && long.TryParse(str, out long output);
}
/// <summary>
/// Extension method for strings.
/// Checks if the string starts with another string.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="toCheck">String to check.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>True if the string is integer.</returns>
public static bool CTStartsWith(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) || str.StartsWith(toCheck, comp);
}
/// <summary>
/// Extension method for strings.
/// Checks if the string ends with another string.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="toCheck">String to check.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>True if the string is integer.</returns>
public static bool CTEndsWith(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) || str.EndsWith(toCheck, comp);
}
/// <summary>
/// Extension method for strings.
/// Returns the index of the last occurence of a given string.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="toCheck">String for the index.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>The index of the last occurence of the given string if the string is integer.</returns>
public static int CTLastIndexOf(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) ? 0 : str.LastIndexOf(toCheck, comp);
}
/// <summary>
/// Extension method for strings.
/// Returns the index of the first occurence of a given string.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="toCheck">String for the index.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>The index of the first occurence of the given string if the string is integer.</returns>
public static int CTIndexOf(this string str, string toCheck, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) ? 0 : str.IndexOf(toCheck, comp);
}
/// <summary>
/// Extension method for strings.
/// Returns the index of the first occurence of a given string.
/// </summary>
/// <param name="str">String-instance.</param>
/// <param name="toCheck">String for the index.</param>
/// <param name="startIndex">Start index for the check.</param>
/// <param name="comp">StringComparison-method (default: StringComparison.OrdinalIgnoreCase, optional)</param>
/// <returns>The index of the first occurence of the given string if the string is integer.</returns>
public static int CTIndexOf(this string str, string toCheck, int startIndex, System.StringComparison comp = System.StringComparison.OrdinalIgnoreCase)
{
if (str == null)
throw new System.ArgumentNullException(nameof(str));
return string.IsNullOrEmpty(toCheck) ? 0 : str.IndexOf(toCheck, startIndex, comp);
}
#endregion
#region Arrays
/// <summary>
/// Extension method for Arrays.
/// Shuffles an Array.
/// </summary>
/// <param name="array">Array-instance to shuffle.</param>
/// <param name="seed">Seed for the PRNG (default: 0 (=standard), optional)</param>
public static void CTShuffle<T>(this T[] array, int seed = 0)
{
if (array == null || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Random rnd = seed == 0 ? new System.Random() : new System.Random(seed);
int n = array.Length;
while (n > 1)
{
int k = rnd.Next(n--);
T temp = array[n];
array[n] = array[k];
array[k] = temp;
}
}
/// <summary>
/// Extension method for Arrays.
/// Dumps an array to a string.
/// </summary>
/// <param name="array">Array-instance to dump.</param>
/// <param name="prefix">Prefix for every element (default: empty, optional).</param>
/// <param name="postfix">Postfix for every element (default: empty, optional).</param>
/// <returns>String with lines for all array entries.</returns>
public static string CTDump<T>(this T[] array, string prefix = "", string postfix = "")
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (T element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(prefix);
sb.Append(element);
sb.Append(postfix);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Quaternion-Arrays.
/// Dumps an array to a string.
/// </summary>
/// <param name="array">Quaternion-Array-instance to dump.</param>
/// <returns>String with lines for all array entries.</returns>
public static string CTDump(this Quaternion[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Quaternion element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Vector2-Arrays.
/// Dumps an array to a string.
/// </summary>
/// <param name="array">Vector2-Array-instance to dump.</param>
/// <returns>String with lines for all array entries.</returns>
public static string CTDump(this Vector2[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector2 element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Vector3-Arrays.
/// Dumps an array to a string.
/// </summary>
/// <param name="array">Vector3-Array-instance to dump.</param>
/// <returns>String with lines for all array entries.</returns>
public static string CTDump(this Vector3[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector3 element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Vector4-Arrays.
/// Dumps an array to a string.
/// </summary>
/// <param name="array">Vector4-Array-instance to dump.</param>
/// <returns>String with lines for all array entries.</returns>
public static string CTDump(this Vector4[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector4 element in array)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Arrays.
/// Generates a string array with all entries (via ToString).
/// </summary>
/// <param name="array">Array-instance to ToString.</param>
/// <returns>String array with all entries (via ToString).</returns>
public static string[] CTToString<T>(this T[] array)
{
if (array == null) // || array.Length <= 0)
throw new System.ArgumentNullException(nameof(array));
string[] result = new string[array.Length];
for (int ii = 0; ii < array.Length; ii++)
{
result[ii] = null == array[ii] ? "null" : array[ii].ToString();
}
return result;
}
#endregion
#region Lists
/// <summary>
/// Extension method for IList.
/// Shuffles a List.
/// </summary>
/// <param name="list">IList-instance to shuffle.</param>
/// <param name="seed">Seed for the PRNG (default: 0 (=standard), optional)</param>
public static void CTShuffle<T>(this System.Collections.Generic.IList<T> list, int seed = 0)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Random rnd = seed == 0 ? new System.Random() : new System.Random(seed);
int n = list.Count;
while (n > 1)
{
int k = rnd.Next(n--);
T temp = list[n];
list[n] = list[k];
list[k] = temp;
}
}
/// <summary>
/// Extension method for IList.
/// Dumps a list to a string.
/// </summary>
/// <param name="list">IList-instance to dump.</param>
/// <param name="prefix">Prefix for every element (default: empty, optional).</param>
/// <param name="postfix">Postfix for every element (default: empty, optional).</param>
/// <returns>String with lines for all list entries.</returns>
public static string CTDump<T>(this System.Collections.Generic.IList<T> list, string prefix = "", string postfix = "")
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (T element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(prefix);
sb.Append(element);
sb.Append(postfix);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Quaternion-IList.
/// Dumps a list to a string.
/// </summary>
/// <param name="list">Quaternion-IList-instance to dump.</param>
/// <returns>String with lines for all list entries.</returns>
public static string CTDump(this System.Collections.Generic.IList<Quaternion> list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Quaternion element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Vector2-IList.
/// Dumps a list to a string.
/// </summary>
/// <param name="list">Vector2-IList-instance to dump.</param>
/// <returns>String with lines for all list entries.</returns>
public static string CTDump(this System.Collections.Generic.IList<Vector2> list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector2 element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Vector3-IList.
/// Dumps a list to a string.
/// </summary>
/// <param name="list">Vector3-IList-instance to dump.</param>
/// <returns>String with lines for all list entries.</returns>
public static string CTDump(this System.Collections.Generic.IList<Vector3> list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector3 element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
}
return sb.ToString();
}
/// <summary>
/// Extension method for Vector4-IList.
/// Dumps a list to a string.
/// </summary>
/// <param name="list">Vector4-IList-instance to dump.</param>
/// <returns>String with lines for all list entries.</returns>
public static string CTDump(this System.Collections.Generic.IList<Vector4> list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (Vector4 element in list)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(element.x);
sb.Append(", ");
sb.Append(element.y);
sb.Append(", ");
sb.Append(element.z);
sb.Append(", ");
sb.Append(element.w);
}
return sb.ToString();
}
/// <summary>
/// Extension method for IList.
/// Generates a string list with all entries (via ToString).
/// </summary>
/// <param name="list">IList-instance to ToString.</param>
/// <returns>String list with all entries (via ToString).</returns>
public static System.Collections.Generic.List<string> CTToString<T>(this System.Collections.Generic.IList<T> list)
{
if (list == null)
throw new System.ArgumentNullException(nameof(list));
System.Collections.Generic.List<string> result = new System.Collections.Generic.List<string>(list.Count);
result.AddRange(list.Select(element => null == element ? "null" : element.ToString()));
return result;
}
#endregion
#region Dictionaries
/// <summary>
/// Extension method for IDictionary.
/// Dumps a dictionary to a string.
/// </summary>
/// <param name="dict">IDictionary-instance to dump.</param>
/// <param name="prefix">Prefix for every element (default: empty, optional).</param>
/// <param name="postfix">Postfix for every element (default: empty, optional).</param>
/// <returns>String with lines for all dictionary entries.</returns>
public static string CTDump<K, V>(this System.Collections.Generic.IDictionary<K, V> dict, string prefix = "", string postfix = "")
{
if (dict == null)
throw new System.ArgumentNullException(nameof(dict));
System.Text.StringBuilder sb = new System.Text.StringBuilder();
foreach (System.Collections.Generic.KeyValuePair<K, V> kvp in dict)
{
if (0 < sb.Length)
sb.Append(System.Environment.NewLine);
sb.Append(prefix);
sb.Append("Key = ");
sb.Append(kvp.Key);
sb.Append(", Value = ");
sb.Append(kvp.Value);
sb.Append(postfix);
}
return sb.ToString();
}
/// <summary>
/// Extension method for IDictionary.
/// Adds a dictionary to an existing one.
/// </summary>
/// <param name="dict">IDictionary-instance.</param>
/// <param name="collection">Dictionary to add.</param>
public static void CTAddRange<K, V>(this System.Collections.Generic.IDictionary<K, V> dict, System.Collections.Generic.IDictionary<K, V> collection)
{
if (dict == null)
throw new System.ArgumentNullException(nameof(dict));
if (collection == null)
throw new System.ArgumentNullException(nameof(collection));
foreach (System.Collections.Generic.KeyValuePair<K, V> item in collection)
{
if (!dict.ContainsKey(item.Key))
{
dict.Add(item.Key, item.Value);
}
else
{
// handle duplicate key issue here
Debug.LogWarning($"Duplicate key found: {item.Key}");
}
}
}
#endregion
#region Unity specific
/// <summary>
/// Extension method for Renderer.
/// Determines if the renderer is visible from a certain camera.
/// </summary>
/// <param name="renderer">Renderer to test the visibility.</param>
/// <param name="camera">Camera for the test.</param>
/// <returns>True if the renderer is visible by the given camera.</returns>
public static bool CTIsVisibleFrom(this Renderer renderer, Camera camera)
{
if (renderer == null)
throw new System.ArgumentNullException(nameof(renderer));
if (camera == null)
throw new System.ArgumentNullException(nameof(camera));
Plane[] planes = GeometryUtility.CalculateFrustumPlanes(camera);
return GeometryUtility.TestPlanesAABB(planes, renderer.bounds);
}
/// <summary>
/// Extension method for Transform.
/// Recursively searches all children of a parent transform for specific named transform
/// </summary>
/// <param name="parent">Parent of the current children.</param>
/// <param name="name">Name of the transform.</param>
/// <returns>True if the renderer is visible by the given camera.</returns>
public static Transform CTDeepSearch(Transform parent, string name)
{
if (parent == null)
throw new System.ArgumentNullException(nameof(parent));
if (name == null)
throw new System.ArgumentNullException(nameof(name));
Transform tf = parent.Find(name);
if (tf != null)
return tf;
foreach (Transform child in parent)
{
tf = CTDeepSearch(child, name);
if (tf != null)
return tf;
}
return null;
}
#endregion
#region Streams
/// <summary>
/// Extension method for Stream.
/// Reads the full content of a Stream.
/// </summary>
/// <param name="input">Stream-instance to read.</param>
/// <param name="bufferSize">Buffer size in bytes (default: 16384, optional).</param>
/// <returns>Byte-array of the Stream content.</returns>
public static byte[] CTReadFully(this System.IO.Stream input, int bufferSize = 16384)
{
if (input == null)
throw new System.ArgumentNullException(nameof(input));
byte[] buffer = new byte[bufferSize];
using (System.IO.MemoryStream ms = new System.IO.MemoryStream())
{
int read;
while ((read = input.Read(buffer, 0, buffer.Length)) > 0)
{
ms.Write(buffer, 0, read);
}
return ms.ToArray();
}
}
#endregion
/*
/// <summary>
/// Perform a deep Copy of the object.
/// </summary>
/// <typeparam name="T">The type of object being copied.</typeparam>
/// <param name="source">The object instance to copy.</param>
/// <returns>The copied object.</returns>
public static T Clone<T>(this T source)
{
if (!typeof(T).IsSerializable)
{
throw new ArgumentException("The type must be serializable.", "source");
}
// Don't serialize a null object, simply return the default for that object
if (Object.ReferenceEquals(source, null))
{
return default(T);
}
IFormatter formatter = new BinaryFormatter();
Stream stream = new MemoryStream();
using (stream)
{
formatter.Serialize(stream, source);
stream.Seek(0, SeekOrigin.Begin);
return (T)formatter.Deserialize(stream);
}
}
*/
/*
/// <summary>
/// Clone a List with elememts containing a copy constructor.
/// </summary>
/// <param name="list">List-instance to clone.</param>
/// <returns>Clones list.</returns>
public static List<T> CTClone<T>(this List<T> listToClone) where T : ICopyable
{
List<T> newList = new List<T>(listToClone.Count);
listToClone.ForEach((item) =>
{
newList.Add(new T(item));
});
return newList;
//return listToClone.Select(item => (T)item.Clone()).ToList();
}
*/
/*
public static string[] CTToUppercase(string[] array)
{
if (array == null || array.Length <= 0)
throw new ArgumentNullException("array");
string[] result = new string[array.Length];
for (int ii = 0; ii < array.Length; ii++)
{
result[ii] = array[ii].ToUpper();
}
return result;
}
public static string[] CTToLowercase(string[] array)
{
if (array == null || array.Length <= 0)
throw new ArgumentNullException("array");
string[] result = new string[array.Length];
for (int ii = 0; ii < array.Length; ii++)
{
result[ii] = array[ii].ToLower();
}
return result;
}
*/
}
}
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,17 @@
namespace Crosstales.Common.Model.Enum
{
/// <summary>All available platforms.</summary>
public enum Platform
{
Windows,
OSX,
Linux,
IOS,
Android,
WSA,
Web,
Unsupported,
MaryTTS
}
}
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,20 @@
namespace Crosstales.Common.Model.Enum
{
/// <summary>Typical audio sample rates.</summary>
public enum SampleRate
{
_8000Hz = 8000,
_11025Hz = 11025,
//_16000Hz = 16000,
_22050Hz = 22050,
//_32000Hz = 32000,
_44100Hz = 44100,
_48000Hz = 48000
//_96000Hz = 96000,
//_192000Hz = 192000,
}
}
// © 2019-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,137 @@
using UnityEngine;
namespace Crosstales.Common.Tool
{
/// <summary>
/// A simple free camera to be added to a Unity game object.
///
/// Keys:
/// wasd / arrows - movement
/// q/e - up/down (local space)
/// r/f - up/down (world space)
/// pageup/pagedown - up/down (world space)
/// hold shift - enable fast movement mode
/// right mouse - enable free look
/// mouse - free look / rotation
/// </summary>
public class FreeCam : MonoBehaviour
{
#region Variables
/// <summary>Normal speed of camera movement.</summary>
public float MovementSpeed = 10f;
/// <summary>Speed of camera movement when shift is held down.</summary>
public float FastMovementSpeed = 100f;
/// <summary>Sensitivity for free look.</summary>
public float FreeLookSensitivity = 3f;
/// <summary>Amount to zoom the camera when using the mouse wheel.</summary>
public float ZoomSensitivity = 10f;
/// <summary>Amount to zoom the camera when using the mouse wheel (fast mode).</summary>
public float FastZoomSensitivity = 50f;
private Transform tf;
private bool looking;
#endregion
#region MonoBehaviour methods
private void Start()
{
tf = transform;
}
private void Update()
{
bool fastMode = Input.GetKey(KeyCode.LeftShift) || Input.GetKey(KeyCode.RightShift);
float movementSpeed = fastMode ? FastMovementSpeed : MovementSpeed;
if (Input.GetKey(KeyCode.A) || Input.GetKey(KeyCode.LeftArrow))
tf.position += Time.deltaTime * movementSpeed * -tf.right;
if (Input.GetKey(KeyCode.D) || Input.GetKey(KeyCode.RightArrow))
tf.position += Time.deltaTime * movementSpeed * tf.right;
if (Input.GetKey(KeyCode.W) || Input.GetKey(KeyCode.UpArrow))
tf.position += Time.deltaTime * movementSpeed * tf.forward;
if (Input.GetKey(KeyCode.S) || Input.GetKey(KeyCode.DownArrow))
tf.position += Time.deltaTime * movementSpeed * -tf.forward;
if (Input.GetKey(KeyCode.Q))
tf.position += Time.deltaTime * movementSpeed * tf.up;
if (Input.GetKey(KeyCode.E))
tf.position += Time.deltaTime * movementSpeed * -tf.up;
if (Input.GetKey(KeyCode.R) || Input.GetKey(KeyCode.PageUp))
tf.position += Time.deltaTime * movementSpeed * Vector3.up;
if (Input.GetKey(KeyCode.F) || Input.GetKey(KeyCode.PageDown))
tf.position += Time.deltaTime * movementSpeed * -Vector3.up;
if (looking)
{
Vector3 localEulerAngles = tf.localEulerAngles;
float newRotationX = localEulerAngles.y + Input.GetAxis("Mouse X") * FreeLookSensitivity;
float newRotationY = localEulerAngles.x - Input.GetAxis("Mouse Y") * FreeLookSensitivity;
localEulerAngles = new Vector3(newRotationY, newRotationX, 0f);
tf.localEulerAngles = localEulerAngles;
}
float axis = Input.GetAxis("Mouse ScrollWheel");
if (Mathf.Abs(axis) > Util.BaseConstants.FLOAT_TOLERANCE)
{
float zoomSensitivity = fastMode ? FastZoomSensitivity : ZoomSensitivity;
tf.position += zoomSensitivity * axis * tf.forward;
}
if (Input.GetKeyDown(KeyCode.Mouse1))
{
StartLooking();
}
else if (Input.GetKeyUp(KeyCode.Mouse1))
{
StopLooking();
}
}
private void OnDisable()
{
StopLooking();
}
#endregion
#region Public methods
/// <summary>
/// Enable free looking.
/// </summary>
public void StartLooking()
{
looking = true;
Cursor.visible = false;
Cursor.lockState = CursorLockMode.Locked;
}
/// <summary>
/// Disable free looking.
/// </summary>
public void StopLooking()
{
looking = false;
Cursor.visible = true;
Cursor.lockState = CursorLockMode.None;
}
#endregion
}
}
// © 2019-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,49 @@
using System.Linq;
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Allows any Unity gameobject to survive a scene switch. This is especially useful to keep the music playing while loading a new scene.</summary>
[DisallowMultipleComponent]
public class SurviveSceneSwitch : Singleton<SurviveSceneSwitch>
{
#region Variables
///<summary>Objects which have to survive a scene switch.</summary>
[Tooltip("Objects which have to survive a scene switch.")] public GameObject[] Survivors; //any object, like a RadioPlayer
private const float ensureParentTime = 1.5f;
private float ensureParentTimer;
private Transform tf;
#endregion
#region MonoBehaviour methods
private void Start()
{
ensureParentTimer = ensureParentTime;
tf = transform;
}
private void Update()
{
ensureParentTimer += Time.deltaTime;
if (Survivors != null && ensureParentTimer > ensureParentTime)
{
ensureParentTimer = 0f;
foreach (GameObject _go in Survivors.Where(_go => _go != null))
{
_go.transform.SetParent(tf);
}
}
}
#endregion
}
}
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,69 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Take screen shots inside an application.</summary>
[DisallowMultipleComponent]
public class TakeScreenshot : Singleton<TakeScreenshot>
{
#region Variables
///<summary>Prefix for the generate file names.</summary>
[Tooltip("Prefix for the generate file names.")] public string Prefix = "CT_Screenshot";
///<summary>Factor by which to increase resolution (default: 1).</summary>
[Tooltip("Factor by which to increase resolution (default: 1).")] public int Scale = 1;
///<summary>Key-press to capture the screen (default: F8).</summary>
[Tooltip("Key-press to capture the screen (default: F8).")] public KeyCode KeyCode = KeyCode.F8;
///<summary>Show file location (default: true).</summary>
[Tooltip("Show file location (default: true).")] public bool ShowFileLocation = true;
private Texture2D texture;
private bool locationShown;
#endregion
#if (!UNITY_WSA && !UNITY_WEBGL) || UNITY_EDITOR
#region MonoBehaviour methods
private void Update()
{
if (Input.GetKeyDown(KeyCode))
Capture();
}
#endregion
#region Public methods
///<summary>Capture the screen.</summary>
public void Capture()
{
string file = $"{Application.persistentDataPath}/{Prefix}{System.DateTime.Now:_dd-MM-yyyy-HH-mm-ss-f}.png";
ScreenCapture.CaptureScreenshot(file, Scale);
Debug.Log($"Screenshot saved: {file}");
if (!locationShown && ShowFileLocation)
{
BaseHelper.ShowFileLocation(file);
locationShown = true;
}
}
#endregion
#else
public void Start()
{
Debug.LogWarning("'TakeScreenshot' doesn't work with the current platform!");
}
#endif
}
}
// © 2014-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,50 @@
using System.Linq;
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Enables or disable game objects on Android or iOS in the background.</summary>
public class BackgroundController : MonoBehaviour
{
#region Variables
///<summary>Selected objects to disable in the background for the controller.</summary>
[Tooltip("Selected objects to disable in the background for the controller.")] public GameObject[] Objects;
private bool isFocused;
#endregion
#region MonoBehaviour methods
#if (UNITY_ANDROID || UNITY_IOS) && !UNITY_EDITOR //|| CT_DEVELOP
private void Start()
{
isFocused = Application.isFocused;
}
private void FixedUpdate()
{
if (Application.isFocused != isFocused)
{
isFocused = Application.isFocused;
if (BaseHelper.isMobilePlatform && !TouchScreenKeyboard.visible)
{
foreach (GameObject go in Objects.Where(go => go != null))
{
go.SetActive(isFocused);
}
if (BaseConstants.DEV_DEBUG)
Debug.Log($"Application.isFocused: {isFocused}", this);
}
}
}
#endif
#endregion
}
}
// © 2018-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,186 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Base for collected constants of very general utility for the asset.</summary>
public abstract class BaseConstants
{
#region Constant variables
/// <summary>Author of the asset.</summary>
public const string ASSET_AUTHOR = "crosstales LLC";
/// <summary>URL of the asset author.</summary>
public const string ASSET_AUTHOR_URL = "https://www.crosstales.com";
/// <summary>URL of the crosstales assets in UAS.</summary>
public const string ASSET_CT_URL = "https://assetstore.unity.com/lists/crosstales-42213?aid=1011lNGT";
/// <summary>URL of the crosstales Discord-channel.</summary>
public const string ASSET_SOCIAL_DISCORD = "https://discord.gg/ZbZ2sh4";
/// <summary>URL of the crosstales Facebook-profile.</summary>
public const string ASSET_SOCIAL_FACEBOOK = "https://www.facebook.com/crosstales/";
/// <summary>URL of the crosstales Twitter-profile.</summary>
public const string ASSET_SOCIAL_TWITTER = "https://twitter.com/crosstales";
/// <summary>URL of the crosstales Youtube-profile.</summary>
public const string ASSET_SOCIAL_YOUTUBE = "https://www.youtube.com/c/Crosstales";
/// <summary>URL of the crosstales LinkedIn-profile.</summary>
public const string ASSET_SOCIAL_LINKEDIN = "https://www.linkedin.com/company/crosstales";
/// <summary>URL of the 3rd party asset "PlayMaker".</summary>
public const string ASSET_3P_PLAYMAKER = "https://assetstore.unity.com/packages/slug/368?aid=1011lNGT";
/// <summary>URL of the 3rd party asset "Volumetric Audio".</summary>
public const string ASSET_3P_VOLUMETRIC_AUDIO = "https://assetstore.unity.com/packages/slug/17125?aid=1011lNGT";
/// <summary>URL of the 3rd party asset "RockTomate".</summary>
public const string ASSET_3P_ROCKTOMATE = "https://assetstore.unity.com/packages/slug/156311?aid=1011lNGT";
/// <summary>URL of the "Badword Filter" asset.</summary>
public const string ASSET_BWF = "https://assetstore.unity.com/packages/slug/26255?aid=1011lNGT";
/// <summary>URL of the "DJ" asset.</summary>
public const string ASSET_DJ = "https://assetstore.unity.com/packages/slug/41993?aid=1011lNGT";
/// <summary>URL of the "File Browser" asset.</summary>
public const string ASSET_FB = "https://assetstore.unity.com/packages/slug/98713?aid=1011lNGT";
/// <summary>URL of the "Online Check" asset.</summary>
public const string ASSET_OC = "https://assetstore.unity.com/packages/slug/74688?aid=1011lNGT";
/// <summary>URL of the "Radio" asset.</summary>
public const string ASSET_RADIO = "https://assetstore.unity.com/packages/slug/32034?aid=1011lNGT";
/// <summary>URL of the "RT-Voice" asset.</summary>
public const string ASSET_RTV = "https://assetstore.unity.com/packages/slug/41068?aid=1011lNGT";
/// <summary>URL of the "Turbo Backup" asset.</summary>
public const string ASSET_TB = "https://assetstore.unity.com/packages/slug/98711?aid=1011lNGT";
/// <summary>URL of the "Turbo Builder" asset.</summary>
public const string ASSET_TPB = "https://assetstore.unity.com/packages/slug/98714?aid=1011lNGT";
/// <summary>URL of the "Turbo Switch" asset.</summary>
public const string ASSET_TPS = "https://assetstore.unity.com/packages/slug/60040?aid=1011lNGT";
/// <summary>URL of the "True Random" asset.</summary>
public const string ASSET_TR = "https://assetstore.unity.com/packages/slug/61617?aid=1011lNGT";
/// <summary>Factor for kilo bytes.</summary>
public const int FACTOR_KB = 1024;
/// <summary>Factor for mega bytes.</summary>
public const int FACTOR_MB = FACTOR_KB * 1024;
/// <summary>Factor for giga bytes.</summary>
public const int FACTOR_GB = FACTOR_MB * 1024;
/// <summary>Float value of 32768.</summary>
public const float FLOAT_32768 = 32768f;
/// <summary>Float tolerance.</summary>
public const float FLOAT_TOLERANCE = 0.0001f;
/// <summary>ToString for two decimal places.</summary>
public const string FORMAT_TWO_DECIMAL_PLACES = "0.00";
/// <summary>ToString for no decimal places.</summary>
public const string FORMAT_NO_DECIMAL_PLACES = "0";
/// <summary>ToString for percent.</summary>
public const string FORMAT_PERCENT = "0%";
// Default values
public const bool DEFAULT_DEBUG = false;
/// <summary>Path delimiter for Windows.</summary>
public const string PATH_DELIMITER_WINDOWS = @"\";
/// <summary>Path delimiter for Unix.</summary>
public const string PATH_DELIMITER_UNIX = "/";
#endregion
#region Changable variables
/// <summary>Development debug logging for the asset.</summary>
public static bool DEV_DEBUG = false;
// Text fragments for the asset
public static string TEXT_TOSTRING_START = " {";
public static string TEXT_TOSTRING_END = "}";
public static string TEXT_TOSTRING_DELIMITER = "', ";
public static string TEXT_TOSTRING_DELIMITER_END = "'";
// Prefixes for URLs and paths
public static string PREFIX_HTTP = "http://";
public static string PREFIX_HTTPS = "https://";
/// <summary>Kill processes after 5000 milliseconds.</summary>
public static int PROCESS_KILL_TIME = 5000;
/// <summary>Path to the cmd under Windows.</summary>
public static string CMD_WINDOWS_PATH = @"C:\Windows\system32\cmd.exe";
/// <summary>Show the BWF banner.</summary>
public static bool SHOW_BWF_BANNER = true;
/// <summary>Show the DJ banner.</summary>
public static bool SHOW_DJ_BANNER = true;
/// <summary>Show the FB banner.</summary>
public static bool SHOW_FB_BANNER = true;
/// <summary>Show the OC banner.</summary>
public static bool SHOW_OC_BANNER = true;
/// <summary>Show the Radio banner.</summary>
public static bool SHOW_RADIO_BANNER = true;
/// <summary>Show the RTV banner.</summary>
public static bool SHOW_RTV_BANNER = true;
/// <summary>Show the TB banner.</summary>
public static bool SHOW_TB_BANNER = true;
/// <summary>Show the TPB banner.</summary>
public static bool SHOW_TPB_BANNER = true;
/// <summary>Show the TPS banner.</summary>
public static bool SHOW_TPS_BANNER = true;
/// <summary>Show the TR banner.</summary>
public static bool SHOW_TR_BANNER = true;
#endregion
#region Properties
/// <summary>URL prefix for files.</summary>
public static string PREFIX_FILE
{
get
{
if ((BaseHelper.isWindowsBasedPlatform || BaseHelper.isWindowsEditor) && !BaseHelper.isMacOSEditor && !BaseHelper.isLinuxEditor)
{
return "file:///";
}
return "file://";
}
}
/// <summary>Application path.</summary>
public static string APPLICATION_PATH => BaseHelper.ValidatePath(Application.dataPath.Substring(0, Application.dataPath.LastIndexOf('/') + 1));
#endregion
}
}
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,228 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Wrapper for the PlayerPrefs.</summary>
public static class CTPlayerPrefs
{
//TODO add getter and setter: Vector2 - 4, Quaternion
/*
#if UNITY_EDITOR
private static readonly SerializableDictionary<string, string> content = new SerializableDictionary<string, string>();
private static readonly string fileName = $"{Application.persistentDataPath}/crosstales.cfg";
static CTPlayerPrefs()
{
if (System.IO.File.Exists(fileName))
content = XmlHelper.DeserializeFromFile<SerializableDictionary<string, string>>(fileName);
if (content == null)
content = new SerializableDictionary<string, string>();
}
#endif
*/
/// <summary>Exists the key?</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <returns>Value for the key.</returns>
public static bool HasKey(string key)
{
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
//#if UNITY_EDITOR
// return content.ContainsKey(key);
//#else
return PlayerPrefs.HasKey(key);
//#endif
}
/// <summary>Deletes all keys.</summary>
public static void DeleteAll()
{
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
PlayerPrefs.DeleteAll();
//#else
// content.Clear();
//#endif
}
/// <summary>Delete the key.</summary>
/// <param name="key">Key to delete in the PlayerPrefs.</param>
public static void DeleteKey(string key)
{
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
PlayerPrefs.DeleteKey(key);
//#else
// content.Remove(key);
//#endif
}
/// <summary>Saves all modifications.</summary>
public static void Save()
{
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
PlayerPrefs.Save();
/*
#else
if (content != null && content.Count > 0)
{
XmlHelper.SerializeToFile(content, fileName);
}
#endif
*/
}
#region Getter
/// <summary>Allows to get a string from a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <returns>Value for the key.</returns>
public static string GetString(string key)
{
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
return PlayerPrefs.GetString(key);
//#else
// return content[key];
//#endif
}
/// <summary>Allows to get a float from a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <returns>Value for the key.</returns>
public static float GetFloat(string key)
{
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
return PlayerPrefs.GetFloat(key);
//#else
// float.TryParse(GetString(key), out float result);
// return result;
//#endif
}
/// <summary>Allows to get an int from a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <returns>Value for the key.</returns>
public static int GetInt(string key)
{
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
return PlayerPrefs.GetInt(key);
//#else
// int.TryParse(GetString(key), out int result);
// return result;
//#endif
}
/// <summary>Allows to get a bool from a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <returns>Value for the key.</returns>
public static bool GetBool(string key)
{
return "true".CTEquals(GetString(key));
}
/// <summary>Allows to get a DateTime from a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <returns>Value for the key.</returns>
public static System.DateTime GetDate(string key)
{
System.DateTime.TryParseExact(GetString(key), "yyyyMMddHHmmsss", null, System.Globalization.DateTimeStyles.None, out System.DateTime result);
return result;
}
#endregion
#region Setter
/// <summary>Allows to set a string for a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <param name="value">Value for the PlayerPrefs.</param>
public static void SetString(string key, string value)
{
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
PlayerPrefs.SetString(key, value);
/*
#else
if (content.ContainsKey(key))
{
content[key] = value;
}
else
{
content.Add(key, value);
}
#endif
*/
}
/// <summary>Allows to set a float for a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <param name="value">Value for the PlayerPrefs.</param>
public static void SetFloat(string key, float value)
{
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
PlayerPrefs.SetFloat(key, value);
//#else
// SetString(key, value.ToString(System.Globalization.CultureInfo.InvariantCulture));
//#endif
}
/// <summary>Allows to set an int for a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <param name="value">Value for the PlayerPrefs.</param>
public static void SetInt(string key, int value)
{
//#if (UNITY_WSA || UNITY_WEBGL) && !UNITY_EDITOR
if (string.IsNullOrEmpty(key))
throw new System.ArgumentNullException(nameof(key));
PlayerPrefs.SetInt(key, value);
//#else
// SetString(key, value.ToString());
//#endif
}
/// <summary>Allows to set a bool for a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <param name="value">Value for the PlayerPrefs.</param>
public static void SetBool(string key, bool value)
{
SetString(key, value ? "true" : "false");
}
/// <summary>Allows to set a DateTime for a key.</summary>
/// <param name="key">Key for the PlayerPrefs.</param>
/// <param name="value">Value for the PlayerPrefs.</param>
public static void SetDate(string key, System.DateTime value)
{
if (value == null)
throw new System.ArgumentNullException(nameof(value));
SetString(key, value.ToString("yyyyMMddHHmmsss"));
}
#endregion
}
}
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,739 @@
#if UNITY_STANDALONE || UNITY_EDITOR
using UnityEngine;
namespace Crosstales.Common.Util
{
#region CTProcess
/// <summary>Native process class for standalone IL2CPP-builds (mimicking the missing "System.Diagnostics.Process"-class with the most important properties, methods and events).</summary>
public class CTProcess : System.IDisposable
{
#region Variables
private uint exitCode = 123456;
private CTProcessStartInfo startInfo = new CTProcessStartInfo();
#endregion
#region Properties
/// <summary>Gets the native handle of the associated process.</summary>
public System.IntPtr Handle { get; private set; }
/// <summary>Gets the unique identifier for the associated process.</summary>
public int Id { get; private set; }
/// <summary>Gets or sets the properties to pass to the Start() method of the Process.</summary>
public CTProcessStartInfo StartInfo
{
get => startInfo;
set
{
if (value != null)
startInfo = value;
}
}
/// <summary>Gets a value indicating whether the associated process has been terminated.</summary>
public bool HasExited { get; private set; }
/// <summary>Gets the value that the associated process specified when it terminated.</summary>
public uint ExitCode => exitCode;
/// <summary>Gets the time that the associated process was started.</summary>
public System.DateTime StartTime { get; private set; }
/// <summary>Gets the time that the associated process exited.</summary>
public System.DateTime ExitTime { get; private set; }
/// <summary>Gets a stream used to read the textual output of the application.</summary>
public System.IO.StreamReader StandardOutput { get; private set; }
/// <summary>Gets a stream used to read the error output of the application.</summary>
public System.IO.StreamReader StandardError { get; private set; }
/// <summary>Gets a value indicating whether the associated process has been busy.</summary>
public bool isBusy { get; private set; }
#endregion
#region Events
public event System.EventHandler Exited;
//#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN || ENABLE_IL2CPP
public event System.Diagnostics.DataReceivedEventHandler OutputDataReceived;
public event System.Diagnostics.DataReceivedEventHandler ErrorDataReceived;
//#endif
#region Event-trigger methods
private void onExited()
{
if (BaseConstants.DEV_DEBUG)
Debug.Log($"onExited: {ExitCode}");
Exited?.Invoke(this, new System.EventArgs());
}
#endregion
#endregion
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
//#if false
#region Windows
#region Variables
private System.IntPtr threadHandle = System.IntPtr.Zero;
private static readonly System.Reflection.FieldInfo[] eventFields =
typeof(System.Diagnostics.DataReceivedEventArgs).GetFields(
System.Reflection.BindingFlags.NonPublic | System.Reflection.BindingFlags.Instance |
System.Reflection.BindingFlags.DeclaredOnly);
private const uint Infinite = 0xffffffff;
// Creation flags
private const uint CREATE_NO_WINDOW = 0x08000000;
#endregion
#region Public methods
/// <summary>Starts (or reuses) the process resource that is specified by the StartInfo property of this Process component and associates it with the component.</summary>
public void Start()
{
cleanup();
isBusy = true;
HasExited = false;
if (StartInfo.UseThread)
{
new System.Threading.Thread(createProcess).Start();
System.Threading.Thread.Sleep(200);
}
else
{
createProcess();
}
}
/// <summary>Starts the process resource that is specified by the parameter containing process start information (for example, the file name of the process to start) and associates the resource with a new Process component..</summary>
public void Start(CTProcessStartInfo info)
{
if (info != null)
StartInfo = info;
Start();
}
/// <summary>Immediately stops the associated process.</summary>
public void Kill()
{
if (Handle != System.IntPtr.Zero)
{
uint _exitCode = 99999; //killed
NativeMethods.TerminateProcess(Handle, ref _exitCode);
Dispose();
}
}
public void WaitForExit(int milliseconds = 0)
{
if (milliseconds > 0)
{
NativeMethods.WaitForSingleObject(Handle, (uint)milliseconds);
}
else
{
NativeMethods.WaitForSingleObject(Handle, Infinite);
}
}
public void BeginOutputReadLine()
{
//System.Threading.Thread.Sleep(100);
new System.Threading.Thread(watchStdOut).Start();
}
public void BeginErrorReadLine()
{
//System.Threading.Thread.Sleep(100);
new System.Threading.Thread(watchStdErr).Start();
}
public void Dispose()
{
if (BaseConstants.DEV_DEBUG)
Debug.LogWarning("Dispose called!");
if (Handle != System.IntPtr.Zero)
NativeMethods.CloseHandle(Handle);
if (threadHandle != System.IntPtr.Zero)
NativeMethods.CloseHandle(threadHandle);
Handle = System.IntPtr.Zero;
threadHandle = System.IntPtr.Zero;
Id = 0;
isBusy = false;
HasExited = true;
StandardOutput?.Dispose();
StandardError?.Dispose();
}
#endregion
#region Private methods
private void createProcess()
{
StartTime = System.DateTime.Now;
string app = StartInfo.FileName;
string args = StartInfo.Arguments;
if (BaseConstants.DEV_DEBUG)
Debug.Log($"createProcess: {StartTime}");
//isBusy = true;
//HasExited = false;
NativeMethods.STARTUPINFOEX startupInfo = new NativeMethods.STARTUPINFOEX();
try
{
if ((StartInfo.RedirectStandardOutput || StartInfo.RedirectStandardError || StartInfo.UseCmdExecute) &&
!StartInfo.FileName.CTContains("cmd"))
{
app = BaseConstants.CMD_WINDOWS_PATH;
args = $"/c call \"{StartInfo.FileName}\" {StartInfo.Arguments}";
}
if (StartInfo.RedirectStandardOutput)
{
string tempStdFile = System.IO.Path.GetTempFileName();
args += $" > \"{tempStdFile}\"";
if (BaseConstants.DEV_DEBUG)
Debug.Log($"tempStdFile: {tempStdFile}");
StandardOutput = new System.IO.StreamReader(new System.IO.FileStream(tempStdFile, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite), StartInfo.StandardOutputEncoding);
}
else
{
StandardOutput =
new System.IO.StreamReader(new System.IO.MemoryStream(), StartInfo.StandardOutputEncoding);
}
if (StartInfo.RedirectStandardError)
{
string tempErrFile = System.IO.Path.GetTempFileName();
args += $" 2> \"{tempErrFile}\"";
if (BaseConstants.DEV_DEBUG)
Debug.Log($"tempErrFile: {tempErrFile}");
StandardError = new System.IO.StreamReader(new System.IO.FileStream(tempErrFile, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite), StartInfo.StandardOutputEncoding);
}
else
{
StandardError = new System.IO.StreamReader(new System.IO.MemoryStream(), StartInfo.StandardOutputEncoding);
}
NativeMethods.SECURITY_ATTRIBUTES pSec = new NativeMethods.SECURITY_ATTRIBUTES();
NativeMethods.SECURITY_ATTRIBUTES tSec = new NativeMethods.SECURITY_ATTRIBUTES();
pSec.nLength = System.Runtime.InteropServices.Marshal.SizeOf(pSec);
tSec.nLength = System.Runtime.InteropServices.Marshal.SizeOf(tSec);
if (BaseConstants.DEV_DEBUG)
Debug.Log($"application: {app}{System.Environment.NewLine}arguments: {args}");
bool retValue =
NativeMethods.CreateProcess(app, $" {args}", ref pSec, ref tSec, true,
StartInfo.CreateNoWindow ? CREATE_NO_WINDOW : 0x00000000, System.IntPtr.Zero,
StartInfo.WorkingDirectory, ref startupInfo, out NativeMethods.PROCESS_INFORMATION processInfo);
if (retValue)
{
Handle = processInfo.hProcess;
threadHandle = processInfo.hThread;
Id = processInfo.dwProcessId;
WaitForExit();
}
else
{
Debug.LogError($"Could not start process: '{StartInfo.FileName}'{System.Environment.NewLine}Arguments: '{StartInfo.Arguments}'{System.Environment.NewLine}Working dir: '{StartInfo.WorkingDirectory}'{System.Environment.NewLine}Last error: {NativeMethods.GetLastError()}");
}
}
catch (System.Exception ex)
{
Debug.LogError($"Process threw an error: {ex}");
Dispose();
}
finally
{
System.Threading.Thread.Sleep(200); //give the streams the chance to write out all events
NativeMethods.GetExitCodeProcess(Handle, ref exitCode);
ExitTime = System.DateTime.Now;
if (Handle != System.IntPtr.Zero)
NativeMethods.CloseHandle(Handle);
if (threadHandle != System.IntPtr.Zero)
NativeMethods.CloseHandle(threadHandle);
Handle = System.IntPtr.Zero;
threadHandle = System.IntPtr.Zero;
Id = 0;
if (!HasExited)
onExited();
isBusy = false;
HasExited = true;
}
}
private void cleanup()
{
Kill();
Dispose();
}
private void watchStdOut()
{
using (System.IO.StreamReader streamReader = StandardOutput)
{
while (!streamReader.EndOfStream)
{
string reply = streamReader.ReadLine();
if (BaseConstants.DEV_DEBUG)
Debug.Log($"watchStdOut: {reply}");
OutputDataReceived?.Invoke(this, createMockDataReceivedEventArgs(reply));
}
}
}
private void watchStdErr()
{
using (System.IO.StreamReader streamReader = StandardError)
{
while (!streamReader.EndOfStream)
{
string reply = streamReader.ReadLine();
if (BaseConstants.DEV_DEBUG)
Debug.Log($"watchStdErr: {reply}");
ErrorDataReceived?.Invoke(this, createMockDataReceivedEventArgs(reply));
}
}
}
private static System.Diagnostics.DataReceivedEventArgs createMockDataReceivedEventArgs(string data)
{
if (string.IsNullOrEmpty(data))
throw new System.ArgumentException("Data is null or empty.", nameof(data));
System.Diagnostics.DataReceivedEventArgs mockEventArgs =
(System.Diagnostics.DataReceivedEventArgs)System.Runtime.Serialization.FormatterServices
.GetUninitializedObject(typeof(System.Diagnostics.DataReceivedEventArgs));
if (eventFields.Length > 0)
{
eventFields[0].SetValue(mockEventArgs, data);
}
else
{
Debug.LogError("Could not create 'DataReceivedEventArgs'!");
}
return mockEventArgs;
}
#endregion
#endregion
#else
#region Unix
#region Variables
private System.Threading.Thread worker;
#endregion
#region Public methods
/// <summary>Starts (or reuses) the process resource that is specified by the StartInfo property of this Process component and associates it with the component.</summary>
public void Start()
{
isBusy = true;
HasExited = false;
if (StartInfo.UseThread)
{
worker = new System.Threading.Thread(() => createProcess());
worker.Start();
System.Threading.Thread.Sleep(200);
}
else
{
createProcess();
}
}
/// <summary>Starts the process resource that is specified by the parameter containing process start information (for example, the file name of the process to start) and associates the resource with a new Process component..</summary>
public void Start(CTProcessStartInfo info)
{
if (info != null)
StartInfo = info;
Start();
}
/// <summary>Immediately stops the associated process.</summary>
public void Kill()
{
if (worker != null && worker.IsAlive)
{
worker.Abort();
}
Dispose();
}
public void WaitForExit(int milliseconds = 0)
{
//Debug.Log("Not implemented!");
}
public void BeginOutputReadLine()
{
//Debug.Log("Not implemented!");
}
public void BeginErrorReadLine()
{
//Debug.Log("Not implemented!");
}
public void Dispose()
{
if (BaseConstants.DEV_DEBUG)
Debug.LogWarning("Dispose called!");
Id = 0;
isBusy = false;
HasExited = true;
if (StandardOutput != null)
StandardOutput.Dispose();
if (StandardError != null)
StandardError.Dispose();
}
#endregion
#region Private methods
private void createProcess()
{
StartTime = System.DateTime.Now;
string app = StartInfo.FileName;
string args = StartInfo.Arguments;
if (BaseConstants.DEV_DEBUG)
Debug.LogWarning($"createProcess: {StartTime}");
try
{
#if UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
//#if true
if (StartInfo.RedirectStandardOutput)
{
StandardOutput = new System.IO.StreamReader(new System.IO.MemoryStream(), StartInfo.StandardOutputEncoding);
}
if (StartInfo.RedirectStandardError)
{
string tempErrFile = System.IO.Path.GetTempFileName();
args += $" 2> \"{tempErrFile}\"";
if (BaseConstants.DEV_DEBUG)
Debug.Log($"tempErrFile: {tempErrFile}");
StandardError = new System.IO.StreamReader(new System.IO.FileStream(tempErrFile, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite), StartInfo.StandardOutputEncoding);
}
else
{
StandardError = new System.IO.StreamReader(new System.IO.MemoryStream(), StartInfo.StandardOutputEncoding);
}
string result = System.Runtime.InteropServices.Marshal.PtrToStringAnsi(NativeMethods.RunCommand($"{app} {args}"));
if (StartInfo.RedirectStandardOutput && !string.IsNullOrEmpty(result))
{
byte[] byteArray = StartInfo.StandardOutputEncoding.GetBytes(result);
System.IO.MemoryStream stream = new System.IO.MemoryStream(byteArray);
StandardOutput = new System.IO.StreamReader(stream);
}
exitCode = 0;
#else
if (StartInfo.RedirectStandardOutput)
{
string tempStdFile = System.IO.Path.GetTempFileName();
args += $" > \"{tempStdFile}\"";
if (BaseConstants.DEV_DEBUG)
Debug.Log($"tempStdFile: {tempStdFile}");
StandardOutput = new System.IO.StreamReader(new System.IO.FileStream(tempStdFile, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite), StartInfo.StandardOutputEncoding);
}
else
{
StandardOutput = new System.IO.StreamReader(new System.IO.MemoryStream(), StartInfo.StandardOutputEncoding);
}
if (StartInfo.RedirectStandardError)
{
string tempErrFile = System.IO.Path.GetTempFileName();
args += $" 2> \"{tempErrFile}\"";
if (BaseConstants.DEV_DEBUG)
Debug.Log($"tempErrFile: {tempErrFile}");
StandardError =
new System.IO.StreamReader(new System.IO.FileStream(tempErrFile, System.IO.FileMode.Open, System.IO.FileAccess.Read, System.IO.FileShare.ReadWrite), StartInfo.StandardOutputEncoding);
}
else
{
StandardError = new System.IO.StreamReader(new System.IO.MemoryStream(), StartInfo.StandardOutputEncoding);
}
exitCode = (uint)NativeMethods.RunCommand($"{app} {args}");
#endif
}
catch (System.Threading.ThreadAbortException)
{
//Debug.LogWarning("Process killed!");
exitCode = 123456;
}
catch (System.Exception ex)
{
Debug.LogError($"Process threw an error: {ex}");
exitCode = 99;
}
finally
{
ExitTime = System.DateTime.Now;
Id = 0;
if (!HasExited)
onExited();
isBusy = false;
HasExited = true;
}
}
#endregion
#endregion
#endif
}
#endregion
#region Native methods
/// <summary>Native methods (bridge to Windows).</summary>
internal static class NativeMethods
{
#if UNITY_STANDALONE_WIN || UNITY_EDITOR_WIN
//#if false
#region Windows
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true,
CharSet = System.Runtime.InteropServices.CharSet.Auto)]
[return: System.Runtime.InteropServices.MarshalAs(System.Runtime.InteropServices.UnmanagedType.Bool)]
internal static extern bool CreateProcess(
string lpApplicationName, string lpCommandLine, ref SECURITY_ATTRIBUTES lpProcessAttributes,
ref SECURITY_ATTRIBUTES lpThreadAttributes, bool bInheritHandles, uint dwCreationFlags,
System.IntPtr lpEnvironment, string lpCurrentDirectory,
[System.Runtime.InteropServices.In] ref STARTUPINFOEX lpStartupInfo,
out PROCESS_INFORMATION lpProcessInformation);
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
[System.Runtime.ConstrainedExecution.ReliabilityContract(
System.Runtime.ConstrainedExecution.Consistency.WillNotCorruptState,
System.Runtime.ConstrainedExecution.Cer.MayFail)]
internal static extern bool CloseHandle(System.IntPtr hObject);
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
internal static extern bool GetExitCodeProcess(System.IntPtr process, ref uint exitCode);
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
internal static extern uint WaitForSingleObject(System.IntPtr handle, uint milliseconds);
[System.Runtime.InteropServices.DllImport("Kernel32.dll", SetLastError = true)]
internal static extern bool TerminateProcess(System.IntPtr hProcess, ref uint exitCode);
[System.Runtime.InteropServices.DllImport("Kernel32.dll")]
internal static extern uint GetLastError();
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet =
System.Runtime.InteropServices.CharSet.Unicode)]
internal struct STARTUPINFOEX
{
public STARTUPINFO StartupInfo;
public System.IntPtr lpAttributeList;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential, CharSet =
System.Runtime.InteropServices.CharSet.Unicode)]
internal struct STARTUPINFO
{
public int cb;
public string lpReserved;
public string lpDesktop;
public string lpTitle;
public int dwX;
public int dwY;
public int dwXSize;
public int dwYSize;
public int dwXCountChars;
public int dwYCountChars;
public int dwFillAttribute;
public int dwFlags;
public short wShowWindow;
public short cbReserved2;
public System.IntPtr lpReserved2;
public System.IntPtr hStdInput;
public System.IntPtr hStdOutput;
public System.IntPtr hStdError;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal struct PROCESS_INFORMATION
{
public System.IntPtr hProcess;
public System.IntPtr hThread;
public int dwProcessId;
public int dwThreadId;
}
[System.Runtime.InteropServices.StructLayout(System.Runtime.InteropServices.LayoutKind.Sequential)]
internal struct SECURITY_ATTRIBUTES
{
public int nLength;
public System.IntPtr lpSecurityDescriptor;
public int bInheritHandle;
}
#endregion
#elif UNITY_STANDALONE_OSX || UNITY_EDITOR_OSX
//#elif false
#region macOS
[System.Runtime.InteropServices.DllImport("libProcessStart")]
internal static extern System.IntPtr RunCommand(string command);
#endregion
#elif UNITY_STANDALONE_LINUX || UNITY_EDITOR_LINUX
//#elif true
#region Linux
[System.Runtime.InteropServices.DllImport("libProcessStart")]
internal static extern int RunCommand(string command);
#endregion
#endif
}
#endregion
#region CTProcessStartInfo
/// <summary>Specifies a set of values that are used when you start a process (mimicking the "System.Diagnostics.ProcessStartInfo"-class with the most important properties).</summary>
public class CTProcessStartInfo
{
public CTProcessStartInfo()
{
StandardErrorEncoding = StandardOutputEncoding = System.Text.Encoding.UTF8;
UseThread = true;
}
/// <summary>Gets or sets the application to be threaded.</summary>
public bool UseThread { get; set; }
/// <summary>Gets or sets the application to be started in cmd (command prompt).</summary>
public bool UseCmdExecute { get; set; }
/// <summary>Gets or sets the application or document to start.</summary>
public string FileName { get; set; }
/// <summary>Gets or sets the set of command-line arguments to use when starting the application.</summary>
public string Arguments { get; set; }
/// <summary>Gets or sets a value indicating whether to start the process in a new window.</summary>
public bool CreateNoWindow { get; set; }
/// <summary>Gets or sets the working directory for the process to be started.</summary>
public string WorkingDirectory { get; set; }
/// <summary>Gets or sets a value that indicates whether the textual output of an application is written to the StandardOutput stream.</summary>
public bool RedirectStandardOutput { get; set; }
/// <summary>Gets or sets a value that indicates whether the error output of an application is written to the StandardError stream.</summary>
public bool RedirectStandardError { get; set; }
/// <summary>Gets or sets the preferred encoding for standard output (UTF8 per default).</summary>
public System.Text.Encoding StandardOutputEncoding { get; set; }
/// <summary>Gets or sets the preferred encoding for error output (UTF8 per default).</summary>
public System.Text.Encoding StandardErrorEncoding { get; set; }
/// <summary>Gets or sets a value indicating whether to use the operating system shell to start the process (ignored, always false).</summary>
public bool UseShellExecute { get; set; }
}
#endregion
}
#endif
// © 2019-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,70 @@
#if !UNITY_WSA || UNITY_EDITOR
namespace Crosstales.Common.Util
{
/// <summary>Specialized WebClient.</summary>
public class CTWebClient : System.Net.WebClient
{
#region Properties
/// <summary>Timeout in milliseconds</summary>
public int Timeout { get; set; }
/// <summary>Connection limit for all WebClients</summary>
public int ConnectionLimit { get; set; }
#endregion
#region Constructors
public CTWebClient() : this(5000)
{
//default
}
public CTWebClient(int timeout, int connectionLimit = 20)
{
Timeout = timeout;
ConnectionLimit = connectionLimit;
}
#endregion
#region Public methods
public System.Net.WebRequest CTGetWebRequest(string uri)
{
return GetWebRequest(new System.Uri(uri));
}
#endregion
#region Overriden methods
protected override System.Net.WebRequest GetWebRequest(System.Uri uri)
{
System.Net.WebRequest wr = base.GetWebRequest(uri);
if (wr != null && wr.GetType() == typeof(System.Net.HttpWebRequest))
{
System.Net.HttpWebRequest request = (System.Net.HttpWebRequest)base.GetWebRequest(uri);
if (request != null)
{
request.ServicePoint.ConnectionLimit = ConnectionLimit;
request.Timeout = Timeout;
return request;
}
}
return wr;
}
#endregion
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,248 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Memory cache stream.</summary>
public class MemoryCacheStream : System.IO.Stream
{
#region Variables
/// <summary>The cache as byte[]</summary>
private byte[] cache;
/// <summary>The write position within the stream.</summary>
private long writePosition;
/// <summary>The read position within the stream.</summary>
private long readPosition;
/// <summary>Stream length. Indicates where the end of the stream is.</summary>
private long length;
/// <summary>Cache size in bytes</summary>
private int size;
/// <summary>Maximum cache size in bytes</summary>
private readonly int maxSize;
#endregion
#region Constructors
/// <summary>Constructor with a specified cache size.</summary>
/// <param name="cacheSize">Cache size of the stream in bytes.</param>
/// <param name="maxCacheSize">Maximum cache size of the stream in bytes.</param>
public MemoryCacheStream(int cacheSize = 64 * BaseConstants.FACTOR_KB, int maxCacheSize = 64 * BaseConstants.FACTOR_MB)
{
length = writePosition = readPosition = 0;
size = cacheSize;
maxSize = maxCacheSize;
createCache();
//Debug.Log("MemoryCacheStream: " + cacheSize + "-" + maxCacheSize);
}
#endregion
#region Stream Overrides [Properties]
/// <summary>Gets a flag flag that indicates if the stream is readable (always true).</summary>
public override bool CanRead => true;
/// <summary>Gets a flag flag that indicates if the stream is seekable (always true).</summary>
public override bool CanSeek => true;
/// <summary>Gets a flag flag that indicates if the stream is seekable (always true).</summary>
public override bool CanWrite => true;
/// <summary>Gets or sets the current stream position.</summary>
public override long Position
{
get => readPosition;
set
{
if (value < 0L)
{
throw new System.ArgumentOutOfRangeException(nameof(value), "Non-negative number required.");
}
//writePosition = readPosition = value; //TODO only readPosition?
readPosition = value;
}
}
/// <summary>Gets the current stream length.</summary>
public override long Length => length;
#endregion
#region Stream Overrides [Methods]
public override void Flush()
{
// Memory based stream with nothing to flush; Do nothing.
}
public override long Seek(long offset, System.IO.SeekOrigin origin)
{
switch (origin)
{
case System.IO.SeekOrigin.Begin:
{
Position = (int)offset;
break;
}
case System.IO.SeekOrigin.Current:
{
long newPos = unchecked(Position + offset);
if (newPos < 0L)
throw new System.IO.IOException("An attempt was made to move the position before the beginning of the stream.");
Position = newPos;
break;
}
case System.IO.SeekOrigin.End:
{
long newPos = unchecked(length + offset);
if (newPos < 0L)
throw new System.IO.IOException("An attempt was made to move the position before the beginning of the stream.");
Position = newPos;
break;
}
default:
{
throw new System.ArgumentException("Invalid seek origin.");
}
}
return Position;
}
public override void SetLength(long value)
{
int _size = (int)value;
if (size != _size)
{
size = _size;
length = Position = 0;
createCache();
}
}
public override int Read(byte[] buffer, int offset, int count)
{
if (null == buffer)
throw new System.ArgumentNullException(nameof(buffer), "Buffer cannot be null.");
if (offset < 0)
throw new System.ArgumentOutOfRangeException(nameof(offset), "Non-negative number required.");
if (count < 0)
throw new System.ArgumentOutOfRangeException(nameof(count), "Non-negative number required.");
if (buffer.Length - offset < count)
{
throw new System.ArgumentException("Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.");
}
// Test for end of stream (or beyond end)
return readPosition >= length ? 0 : read(buffer, offset, count);
}
public override void Write(byte[] buffer, int offset, int count)
{
if (null == buffer)
throw new System.ArgumentNullException(nameof(buffer), "Buffer cannot be null.");
if (offset < 0)
throw new System.ArgumentOutOfRangeException(nameof(offset), "Non-negative number required.");
if (count < 0)
throw new System.ArgumentOutOfRangeException(nameof(count), "Non-negative number required.");
if (count > size)
throw new System.ArgumentOutOfRangeException(nameof(count), "Value is larger than the cache size.");
if (buffer.Length - offset < count)
{
throw new System.ArgumentException("Offset and length were out of bounds for the array or count is greater than the number of elements from index to the end of the source collection.");
}
if (0 == count)
{
// Nothing to do.
return;
}
write(buffer, offset, count);
}
#endregion
#region Private methods
/// <summary>Read bytes from the memory stream into the provided buffer.</summary>
private int read(byte[] buff, int offset, int count)
{
int arrayPosition = (int)(readPosition % size);
if (arrayPosition + count > size)
{
int countEnd = size - arrayPosition;
int countStart = count - countEnd;
System.Array.Copy(cache, arrayPosition, buff, offset, countEnd);
System.Array.Copy(cache, 0, buff, offset + countEnd, countStart);
}
else
{
System.Array.Copy(cache, arrayPosition, buff, offset, count);
}
readPosition += count;
return count;
}
/// <summary>Write bytes into the memory stream.</summary>
private void write(byte[] buff, int offset, int count)
{
int arrayPosition = (int)(writePosition % size);
if (arrayPosition + count > size)
{
int countEnd = size - arrayPosition;
int countStart = count - countEnd;
System.Array.Copy(buff, offset, cache, arrayPosition, countEnd);
System.Array.Copy(buff, offset + countEnd, cache, 0, countStart);
}
else
{
System.Array.Copy(buff, offset, cache, arrayPosition, count);
}
writePosition += count;
length = writePosition;
}
/// <summary>Create the cache</summary>
private void createCache()
{
if (size > maxSize)
{
cache = new byte[maxSize];
Debug.LogWarning("'size' is larger than 'maxSize'! Using 'maxSize' as cache!");
}
else
{
cache = new byte[size];
}
}
#endregion
}
}
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,79 @@
using System.Linq;
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Enables or disable game objects and scripts for a given platform.</summary>
public class PlatformController : MonoBehaviour
{
#region Variables
///<summary>Selected platforms for the controller.</summary>
[Header("Configuration")] [Tooltip("Selected platforms for the controller.")] public System.Collections.Generic.List<Model.Enum.Platform> Platforms;
///<summary>Enable or disable the 'Objects' for the selected 'Platforms' (default: true).</summary>
[Tooltip("Enable or disable the 'Objects' for the selected 'Platforms' (default: true).")] public bool Active = true;
///<summary>Selected objects for the controller.</summary>
[Header("GameObjects")] [Tooltip("Selected objects for the controller.")] public GameObject[] Objects;
///<summary>Selected scripts for the controller.</summary>
[Header("MonoBehaviour Scripts")] [Tooltip("Selected scripts for the controller.")] public MonoBehaviour[] Scripts;
protected Model.Enum.Platform currentPlatform;
#endregion
#region MonoBehaviour methods
protected virtual void Awake()
{
selectPlatform();
}
#endregion
#region Private methods
protected void selectPlatform()
{
currentPlatform = BaseHelper.CurrentPlatform;
activateGameObjects();
activateScripts();
}
protected void activateGameObjects()
{
if (Objects?.Length > 0)
{
bool active = Platforms.Contains(currentPlatform) ? Active : !Active;
foreach (GameObject go in Objects.Where(go => go != null))
{
go.SetActive(active);
}
}
}
protected void activateScripts()
{
if (Scripts?.Length > 0)
{
bool active = Platforms.Contains(currentPlatform) ? Active : !Active;
foreach (MonoBehaviour script in Scripts.Where(script => script != null))
{
script.enabled = active;
}
}
}
#endregion
}
}
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,145 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Random color changer.</summary>
public class RandomColor : MonoBehaviour
{
#region Variables
///<summary>Use intervals to change the color (default: true).</summary>
[Tooltip("Use intervals to change the color (default: true).")] public bool UseInterval = true;
///<summary>Random change interval between min (= x) and max (= y) in seconds (default: x = 5, y = 10).</summary>
[Tooltip("Random change interval between min (= x) and max (= y) in seconds (default: x = 5, y = 10).")]
public Vector2 ChangeInterval = new Vector2(5, 10);
///<summary>Random hue range between min (= x) and max (= y) (default: x = 0, y = 1).</summary>
[Tooltip("Random hue range between min (= x) and max (= y) (default: x = 0, y = 1).")] public Vector2 HueRange = new Vector2(0f, 1f);
///<summary>Random saturation range between min (= x) and max (= y) (default: x = 1, y = 1).</summary>
[Tooltip("Random saturation range between min (= x) and max (= y) (default: x = 1, y = 1).")] public Vector2 SaturationRange = new Vector2(1f, 1f);
///<summary>Random value range between min (= x) and max (= y) (default: x = 1, y = 1).</summary>
[Tooltip("Random value range between min (= x) and max (= y) (default: x = 1, y = 1).")] public Vector2 ValueRange = new Vector2(1f, 1f);
///<summary>Random alpha range between min (= x) and max (= y) (default: x = 1, y = 1).</summary>
[Tooltip("Random alpha range between min (= x) and max (= y) (default: x = 1, y = 1).")] public Vector2 AlphaRange = new Vector2(1f, 1f);
///<summary>Use gray scale colors (default: false).</summary>
[Tooltip("Use gray scale colors (default: false).")] public bool GrayScale;
///<summary>Modify the color of a material instead of the Renderer (default: not set, optional).</summary>
[Tooltip("Modify the color of a material instead of the Renderer (default: not set, optional).")]
public Material Material;
///<summary>Set the object to a random color at Start (default: false).</summary>
[Tooltip("Set the object to a random color at Start (default: false).")] public bool RandomColorAtStart;
private float elapsedTime;
private float changeTime;
private Renderer currentRenderer;
private Color32 startColor;
private Color32 endColor;
private float lerpProgress;
private static readonly int colorID = Shader.PropertyToID("_Color");
private bool existsMaterial;
#endregion
#region MonoBehaviour methods
private void Start()
{
existsMaterial = Material != null;
elapsedTime = changeTime = Random.Range(ChangeInterval.x, ChangeInterval.y);
if (RandomColorAtStart)
{
if (GrayScale)
{
float grayScale = Random.Range(HueRange.x, HueRange.y);
startColor = new Color(grayScale, grayScale, grayScale, Random.Range(AlphaRange.x, AlphaRange.y));
}
else
{
startColor = Random.ColorHSV(HueRange.x, HueRange.y, SaturationRange.x, SaturationRange.y, ValueRange.x, ValueRange.y, AlphaRange.x, AlphaRange.y);
}
if (existsMaterial)
{
Material.SetColor(colorID, startColor);
}
else
{
currentRenderer = GetComponent<Renderer>();
currentRenderer.material.color = startColor;
}
}
else
{
if (existsMaterial)
{
startColor = Material.GetColor(colorID);
}
else
{
currentRenderer = GetComponent<Renderer>();
startColor = currentRenderer.material.color;
}
}
}
private void Update()
{
if (UseInterval)
{
elapsedTime += Time.deltaTime;
if (elapsedTime > changeTime)
{
lerpProgress = elapsedTime = 0f;
if (GrayScale)
{
float grayScale = Random.Range(HueRange.x, HueRange.y);
endColor = new Color(grayScale, grayScale, grayScale, Random.Range(AlphaRange.x, AlphaRange.y));
}
else
{
endColor = Random.ColorHSV(HueRange.x, HueRange.y, SaturationRange.x, SaturationRange.y, ValueRange.x, ValueRange.y, AlphaRange.x, AlphaRange.y);
}
changeTime = Random.Range(ChangeInterval.x, ChangeInterval.y);
}
if (existsMaterial)
{
Material.SetColor(colorID, Color.Lerp(startColor, endColor, lerpProgress));
}
else
{
currentRenderer.material.color = Color.Lerp(startColor, endColor, lerpProgress);
}
if (lerpProgress < 1f)
{
lerpProgress += Time.deltaTime / (changeTime - 0.1f);
}
else
{
startColor = existsMaterial ? Material.GetColor(colorID) : currentRenderer.material.color;
}
}
}
#endregion
}
}
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,69 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Random rotation changer.</summary>
public class RandomRotator : MonoBehaviour
{
#region Variables
///<summary>Use intervals to change the rotation (default: true).</summary>
[Tooltip("Use intervals to change the rotation (default: true).")] public bool UseInterval = true;
///<summary>Random change interval between min (= x) and max (= y) in seconds (default: x = 10, y = 20).</summary>
[Tooltip("Random change interval between min (= x) and max (= y) in seconds (default: x = 10, y = 20).")]
public Vector2 ChangeInterval = new Vector2(10, 20);
///<summary>Minimum rotation speed per axis (default: 5 for all axis).</summary>
[Tooltip("Minimum rotation speed per axis (default: 5 for all axis).")] public Vector3 SpeedMin = new Vector3(5, 5, 5);
///<summary>Maximum rotation speed per axis (default: 15 for all axis).</summary>
[Tooltip("Minimum rotation speed per axis (default: 15 for all axis).")] public Vector3 SpeedMax = new Vector3(15, 15, 15);
///<summary>Set the object to a random rotation at Start (default: false).</summary>
[Tooltip("Set the object to a random rotation at Start (default: false).")] public bool RandomRotationAtStart;
private Transform tf;
private Vector3 speed;
private float elapsedTime;
private float changeTime;
#endregion
#region MonoBehaviour methods
private void Start()
{
tf = transform;
elapsedTime = changeTime = Random.Range(ChangeInterval.x, ChangeInterval.y);
if (RandomRotationAtStart)
tf.localRotation = Random.rotation;
}
private void Update()
{
if (UseInterval)
{
elapsedTime += Time.deltaTime;
if (elapsedTime > changeTime)
{
elapsedTime = 0f;
speed.x = Random.Range(Mathf.Abs(SpeedMin.x), Mathf.Abs(SpeedMax.x)) * (Random.Range(0, 2) == 0 ? 1 : -1);
speed.y = Random.Range(Mathf.Abs(SpeedMin.y), Mathf.Abs(SpeedMax.y)) * (Random.Range(0, 2) == 0 ? 1 : -1);
speed.z = Random.Range(Mathf.Abs(SpeedMin.z), Mathf.Abs(SpeedMax.z)) * (Random.Range(0, 2) == 0 ? 1 : -1);
changeTime = Random.Range(ChangeInterval.x, ChangeInterval.y);
}
tf.Rotate(speed.x * Time.deltaTime, speed.y * Time.deltaTime, speed.z * Time.deltaTime);
}
}
#endregion
}
}
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,108 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Random scale changer.</summary>
public class RandomScaler : MonoBehaviour
{
#region Variables
///<summary>Use intervals to change the scale (default: true).</summary>
[Tooltip("Use intervals to change the scale (default: true).")] public bool UseInterval = true;
///<summary>Random change interval between min (= x) and max (= y) in seconds (default: x = 10, y = 20).</summary>
[Tooltip("Random change interval between min (= x) and max (= y) in seconds (default: x = 10, y = 20).")]
public Vector2 ChangeInterval = new Vector2(10, 20);
///<summary>Minimum scale per axis (default: 0.1 for all axis).</summary>
[Tooltip("Minimum rotation speed per axis (default: 5 for all axis).")] public Vector3 ScaleMin = new Vector3(0.1f, 0.1f, 0.1f);
///<summary>Maximum scale per axis (default: 0.1 for all axis).</summary>
[Tooltip("Maximum scale per axis (default: 0.1 for all axis).")] public Vector3 ScaleMax = new Vector3(3, 3, 3);
///<summary>Uniform scaling for all axis (x-axis values will be used, default: true).</summary>
[Tooltip("Uniform scaling for all axis (x-axis values will be used, default: true).")] public bool Uniform = true;
///<summary>Set the object to a random scale at Start (default: false).</summary>
[Tooltip("Set the object to a random scale at Start (default: false).")] public bool RandomScaleAtStart;
private Transform tf;
private Vector3 startScale;
private Vector3 endScale;
private float elapsedTime;
private float changeTime;
private float lerpTime;
#endregion
#region MonoBehaviour methods
private void Start()
{
tf = transform;
elapsedTime = changeTime = Random.Range(ChangeInterval.x, ChangeInterval.y);
if (RandomScaleAtStart)
{
if (Uniform)
{
startScale.x = startScale.y = startScale.z = Random.Range(ScaleMin.x, Mathf.Abs(ScaleMax.x));
}
else
{
startScale.x = Random.Range(ScaleMin.x, Mathf.Abs(ScaleMax.x));
startScale.y = Random.Range(ScaleMin.y, Mathf.Abs(ScaleMax.y));
startScale.z = Random.Range(ScaleMin.z, Mathf.Abs(ScaleMax.z));
}
tf.localScale = startScale;
}
else
{
startScale = tf.localScale;
}
}
private void Update()
{
if (UseInterval)
{
elapsedTime += Time.deltaTime;
if (elapsedTime > changeTime)
{
lerpTime = elapsedTime = 0f;
if (Uniform)
{
endScale.x = endScale.y = endScale.z = Random.Range(ScaleMin.x, Mathf.Abs(ScaleMax.x));
}
else
{
endScale.x = Random.Range(ScaleMin.x, Mathf.Abs(ScaleMax.x));
endScale.y = Random.Range(ScaleMin.y, Mathf.Abs(ScaleMax.y));
endScale.z = Random.Range(ScaleMin.z, Mathf.Abs(ScaleMax.z));
}
changeTime = Random.Range(ChangeInterval.x, ChangeInterval.y);
}
tf.localScale = Vector3.Lerp(startScale, endScale, lerpTime);
if (lerpTime < 1f)
{
lerpTime += Time.deltaTime / (changeTime - 0.1f);
}
else
{
startScale = tf.localScale;
}
}
}
#endregion
}
}
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,330 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Base-class for all singletons.</summary>
public abstract class Singleton<T> : MonoBehaviour where T : Singleton<T>
{
#region Variables
[Tooltip("Don't destroy gameobject during scene switches (default: false)."), SerializeField] private bool dontDestroy = true;
/// <summary>Fully qualified prefab path.</summary>
public static string PrefabPath;
protected static T instance;
private static readonly object lockObj = new object();
#endregion
#region Properties
/// <summary>Returns the singleton instance of this class.</summary>
/// <returns>Singleton instance of this class.</returns>
public static T Instance
{
get
{
if (SingletonHelper.isQuitting)
{
//Debug.LogWarning($"[Singleton] Instance '{typeof(T)}' already destroyed. Returning null.");
return instance;
}
if (instance == null)
CreateInstance();
//Debug.LogWarning($"{Time.realtimeSinceStartup}-[Singleton] Instance '{typeof(T)}' GET: {instance.GetInstanceID()}");
return instance;
}
protected set
{
lock (lockObj)
{
//Debug.LogWarning($"{Time.realtimeSinceStartup}-[Singleton] Instance '{typeof(T)}' SET: {value?.GetInstanceID()}");
instance = value;
}
}
}
/// <summary>Don't destroy gameobject during scene switches.</summary>
public bool DontDestroy
{
get => dontDestroy;
set => dontDestroy = value;
}
#endregion
#region MonoBehaviour methods
protected virtual void Awake()
{
//Debug.LogWarning($"{Time.realtimeSinceStartup}-[Singleton] Instance '{typeof(T)}' AWAKE: {activeInstance.GetInstanceID()}");
Util.BaseHelper.ApplicationIsPlaying = Application.isPlaying; //needed to enforce the right mode
//isQuitting = false;
if (instance == null)
{
Instance = GetComponent<T>();
if (!Util.BaseHelper.isEditorMode && dontDestroy)
DontDestroyOnLoad(transform.root.gameObject);
}
else
{
if (!Util.BaseHelper.isEditorMode && dontDestroy && instance != this)
{
Debug.LogWarning($"Only one active instance of '{typeof(T).Name}' allowed in all scenes!{System.Environment.NewLine}This object will now be destroyed.", this);
Destroy(gameObject, 0.1f);
}
}
}
protected virtual void OnDestroy()
{
if (instance == this)
{
//SingletonHelper.isQuitting = !BaseHelper.isEditorMode;
SingletonHelper.isQuitting = true;
//Debug.LogWarning($"{Time.realtimeSinceStartup}-[Singleton] Instance '{typeof(T)}' ONDESTROY: {instance.GetInstanceID()}");
if (!dontDestroy)
Instance = null;
//DeleteInstance();
}
}
protected virtual void OnApplicationQuit()
{
SingletonHelper.isQuitting = true;
Util.BaseHelper.ApplicationIsPlaying = false;
}
#endregion
/// <summary>Creates an instance of this object.</summary>
/// <param name="searchExistingGameObject">Search for existing GameObjects of this object (default: true, optional)</param>
/// <param name="deleteExistingInstance">Delete existing instance of this object (default: false, optional)</param>
public static void CreateInstance(bool searchExistingGameObject = true, bool deleteExistingInstance = false)
{
if (deleteExistingInstance)
DeleteInstance();
if (instance == null)
{
// Search for existing instance.
if (searchExistingGameObject)
Instance = (T)FindObjectOfType(typeof(T));
// Create new instance if one doesn't already exist.
if (instance == null)
{
if (!string.IsNullOrEmpty(PrefabPath))
{
T prefab = Resources.Load<T>(PrefabPath);
if (prefab == null)
{
Debug.LogWarning("Singleton prefab missing: " + PrefabPath);
}
else
{
Instance = Instantiate(prefab);
//Debug.LogWarning($"{Time.realtimeSinceStartup}-[Singleton] Instance '{typeof(T)}' CREATE Prefab: {instance.GetInstanceID()}");
}
}
if (instance == null)
{
if (BaseHelper.isEditorMode)
{
#if UNITY_EDITOR
//instanceEditor = UnityEditor.EditorUtility.CreateGameObjectWithHideFlags($"{typeof(T).Name} (Hidden Singleton)", HideFlags.DontSaveInBuild | HideFlags.HideInHierarchy).AddComponent<T>();
Instance = new GameObject($"{typeof(T).Name} (Singleton)").AddComponent<T>();
#endif
//Debug.LogWarning($"{Time.realtimeSinceStartup}-[Singleton] Instance '{typeof(T)}' CREATE Editor: {instance.GetInstanceID()} - {BaseHelper.isEditorMode}");
}
else
{
Instance = new GameObject($"{typeof(T).Name} (Singleton)").AddComponent<T>();
//Debug.LogWarning($"{Time.realtimeSinceStartup}-[Singleton] Instance '{typeof(T)}' CREATE Play: {instance.GetInstanceID()} - {BaseHelper.isEditorMode}");
}
}
}
}
}
/// <summary>Deletes the instance of this object.</summary>
public static void DeleteInstance()
{
if (instance != null)
{
T _instance = instance;
Instance = null;
Destroy(_instance.gameObject);
}
}
}
/// <summary>Helper-class for singletons.</summary>
#if UNITY_EDITOR
[UnityEditor.InitializeOnLoad]
#endif
public class SingletonHelper
{
#if UNITY_EDITOR
private const string key = "CT_SINGLETON_ISQUITTING";
private static bool quitting;
private static bool isQuittingSet;
public static bool isQuitting
{
get
{
if (!isQuittingSet)
{
isQuittingSet = true;
quitting = UnityEditor.BuildPipeline.isBuildingPlayer || Crosstales.Common.Util.CTPlayerPrefs.GetBool(key);
}
return quitting;
}
set
{
//Debug.Log("SET isQuitting: " + value);
if (value != quitting)
{
quitting = value;
Crosstales.Common.Util.CTPlayerPrefs.SetBool(key, value);
Crosstales.Common.Util.CTPlayerPrefs.Save();
}
}
}
#else
public static bool isQuitting { get; set; }
#endif
private static bool isInitialized;
#region Constructor
static SingletonHelper()
{
//Debug.Log($"{Time.realtimeSinceStartup} - Constructor!");
initialize();
}
#endregion
[RuntimeInitializeOnLoadMethod(RuntimeInitializeLoadType.BeforeSceneLoad)]
private static void initialize()
{
if (isInitialized)
{
//Debug.Log($"{Time.realtimeSinceStartup} - already initialized!");
}
else
{
//Debug.Log($"{Time.realtimeSinceStartup} - initialize: {isQuitting}");
isInitialized = true;
UnityEngine.SceneManagement.SceneManager.sceneLoaded += onSceneLoaded;
UnityEngine.SceneManagement.SceneManager.sceneUnloaded += onSceneUnloaded;
Application.quitting += onQuitting;
//Application.wantsToQuit += onWantsToQuit;
#if UNITY_EDITOR
UnityEditor.EditorApplication.playModeStateChanged += onPlayModeStateChanged;
UnityEditor.SceneManagement.EditorSceneManager.sceneClosing += onSceneClosing;
//UnityEditor.SceneManagement.EditorSceneManager.sceneOpening += onSceneOpening;
UnityEditor.SceneManagement.EditorSceneManager.sceneOpened += onSceneOpened;
#endif
}
}
#if UNITY_EDITOR
private static void onSceneOpened(UnityEngine.SceneManagement.Scene scene, UnityEditor.SceneManagement.OpenSceneMode mode)
{
//Debug.Log($"{Time.realtimeSinceStartup} - onSceneOpened");
isQuitting = false;
}
/*
private static void onSceneOpening(string path, UnityEditor.SceneManagement.OpenSceneMode mode)
{
Debug.Log($"{Time.realtimeSinceStartup} - onSceneOpening");
isQuitting = false;
}
*/
private static void onSceneClosing(UnityEngine.SceneManagement.Scene scene, bool removingscene)
{
//Debug.Log($"{Time.realtimeSinceStartup} - onSceneClosing");
isQuitting = true;
}
private static void onPlayModeStateChanged(UnityEditor.PlayModeStateChange obj)
{
isQuitting = obj == UnityEditor.PlayModeStateChange.ExitingEditMode || obj == UnityEditor.PlayModeStateChange.ExitingPlayMode;
//Debug.LogWarning($"{Time.realtimeSinceStartup} - onPlayModeStateChanged: {obj} - {isQuitting}");
}
#endif
/*
private static bool onWantsToQuit()
{
Debug.Log($"{Time.realtimeSinceStartup} - onWantsToQuit");
isQuitting = true;
return true;
}
*/
private static void onQuitting()
{
//Debug.Log($"{Time.realtimeSinceStartup} - onQuitting");
isQuitting = true;
}
private static void onSceneLoaded(UnityEngine.SceneManagement.Scene scene, UnityEngine.SceneManagement.LoadSceneMode mode)
{
//Debug.Log($"{Time.realtimeSinceStartup} - onSceneLoaded");
isQuitting = false;
Util.BaseHelper.ApplicationIsPlaying = true;
}
private static void onSceneUnloaded(UnityEngine.SceneManagement.Scene scene)
{
//Debug.Log($"{Time.realtimeSinceStartup} - onSceneUnloaded");
isQuitting = true;
Util.BaseHelper.ApplicationIsPlaying = false;
}
}
}
// © 2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,129 @@
using UnityEngine;
namespace Crosstales.Common.Util
{
/// <summary>Helper-class for XML.</summary>
public static class XmlHelper
{
#if !UNITY_WEBGL || UNITY_EDITOR
/// <summary>Serialize an object to an XML-file.</summary>
/// <param name="obj">Object to serialize.</param>
/// <param name="filename">File name of the XML.</param>
public static void SerializeToFile<T>(T obj, string filename)
{
if (null == obj)
throw new System.ArgumentNullException(nameof(obj));
if (filename == null)
throw new System.ArgumentNullException(nameof(filename));
try
{
System.IO.File.WriteAllText(filename, SerializeToString(obj));
}
catch (System.Exception ex)
{
Debug.LogError($"Could not serialize the object to a file: {ex}");
}
}
/// <summary>Deserialize a XML-file to an object.</summary>
/// <param name="filename">XML-file of the object</param>
/// <param name="skipBOM">Skip BOM (optional, default: false)</param>
/// <returns>Object</returns>
public static T DeserializeFromFile<T>(string filename, bool skipBOM = false)
{
if (filename == null)
throw new System.ArgumentNullException(nameof(filename));
try
{
if (System.IO.File.Exists(filename))
return DeserializeFromString<T>(System.IO.File.ReadAllText(filename), skipBOM);
Debug.LogError($"File doesn't exist: {filename}");
}
catch (System.Exception ex)
{
Debug.LogError($"Could not deserialize the object from a file: {ex}");
}
return default;
}
#endif
/// <summary>Serialize an object to an XML-string.</summary>
/// <param name="obj">Object to serialize.</param>
/// <returns>Object as XML-stringValid path</returns>
public static string SerializeToString<T>(T obj)
{
if (null == obj)
throw new System.ArgumentNullException(nameof(obj));
try
{
System.IO.MemoryStream ms = new System.IO.MemoryStream();
System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(obj.GetType());
System.Xml.XmlTextWriter xmlTextWriter = new System.Xml.XmlTextWriter(ms, System.Text.Encoding.UTF8);
xs.Serialize(xmlTextWriter, obj);
ms = (System.IO.MemoryStream)xmlTextWriter.BaseStream;
return System.Text.Encoding.UTF8.GetString(ms.ToArray());
}
catch (System.Exception ex)
{
Debug.LogError($"Could not serialize the object to a string: {ex}");
}
return string.Empty;
}
/// <summary>Deserialize a XML-string to an object.</summary>
/// <param name="xmlAsString">XML of the object</param>
/// <param name="skipBOM">Skip BOM (optional, default: true)</param>
/// <returns>Object</returns>
public static T DeserializeFromString<T>(string xmlAsString, bool skipBOM = true)
{
if (string.IsNullOrEmpty(xmlAsString))
throw new System.ArgumentNullException(nameof(xmlAsString));
try
{
System.Xml.Serialization.XmlSerializer xs = new System.Xml.Serialization.XmlSerializer(typeof(T));
using (System.IO.StringReader sr = new System.IO.StringReader(xmlAsString.Trim()))
{
if (skipBOM)
sr.Read(); //skip BOM
return (T)xs.Deserialize(sr);
}
}
catch (System.Exception ex)
{
Debug.LogError($"Could not deserialize the object from a string: {ex}");
}
return default;
}
/// <summary>Deserialize a Unity XML resource (TextAsset) to an object.</summary>
/// <param name="resourceName">Name of the resource</param>
/// <param name="skipBOM">Skip BOM (optional, default: true)</param>
/// <returns>Object</returns>
public static T DeserializeFromResource<T>(string resourceName, bool skipBOM = true)
{
if (string.IsNullOrEmpty(resourceName))
throw new System.ArgumentNullException(nameof(resourceName));
// Load the resource
TextAsset xml = Resources.Load(resourceName) as TextAsset;
return xml != null ? DeserializeFromString<T>(xml.text, skipBOM) : default;
}
}
}
// © 2014-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,99 @@
# Adventure Creator
Version: 1.65.1
https://assetstore.unity.com/packages/slug/11896?aid=1011lNGT
# Amplitude
Version: 1.1.0
https://assetstore.unity.com/packages/slug/111277?aid=1011lNGT
# AWS Polly
Version: 26.01.2018
https://aws.amazon.com/polly/
https://github.com/aws/aws-sdk-net/files/1669402/AWSPollyMin.zip
# Azure (Bing Speech)
https://docs.microsoft.com/en-us/azure/cognitive-services/Speech/Home
# Cinema Director
Version: 1.4.5.2
https://assetstore.unity.com/packages/slug/19779?aid=1011lNGT
# Dialogue System
Version: current
https://assetstore.unity.com/packages/slug/11672?aid=1011lNGT
Please use the provided example from:
Assets\Dialogue System\Third Party Support\RTVoice Support.unitypackage
# Google Cloud
Version: 1.2
https://assetstore.unity.com/packages/slug/115170?aid=1011lNGT
# Klattersynth
Version: 1.0
https://assetstore.unity.com/packages/slug/95453?aid=1011lNGT
# LDC
Version: 5.0
https://assetstore.unity.com/packages/slug/5020?aid=1011lNGT
# LipSync
Version: 1.1
https://assetstore.unity.com/packages/slug/32117?aid=1011lNGT
# MaryTTS
Version: 5.2
http://mary.dfki.de/
# NPC Chat
Version: 1.76
https://assetstore.unity.com/packages/slug/9723?aid=1011lNGT
# PlayMaker
Version: 1.9.0.p10
https://assetstore.unity.com/packages/slug/368?aid=1011lNGT
# SALSA
Version: 2.1.0
https://assetstore.unity.com/packages/slug/148442?aid=1011lNGT
For the previous version, see the "SALSAv1.zip"
# SAPI Unity
Version: 03.01.2018
https://forum.unity.com/threads/text-to-speech-dll-for-windows-desktop.56038/page-4#post-3340957
# SLATE
Version: 1.8.2
https://assetstore.unity.com/packages/slug/56558?aid=1011lNGT
#Volumetric Audio
Version: 1.1.9
https://assetstore.unity.com/packages/slug/17125?aid=1011lNGT
# WebGL Speech Synthesis
Version: 1.5
https://assetstore.unity.com/packages/slug/81861?aid=1011lNGT
# Already working:
## Quest System Pro
https://assetstore.unity.com/packages/slug/63460?aid=1011lNGT

View File

@ -0,0 +1,27 @@
# RT-Voice PRO - EmotionML
Works with MaryTTS.
## Examples
<emotion dimension-set="http://www.w3.org/TR/emotion-voc/xml#pad-dimensions">
You can use the SSML prosody element to modify the the speech output of a voice. The SSML definition for the prososdy element specifies attributes for pitch, rate, volume, contour, range, and duration.
<dimension name="arousal" value="0.3"/><!-- lower-than-average arousal -->
<dimension name="pleasure" value="0.9"/><!-- very high positive valence -->
<dimension name="dominance" value="0.8"/><!-- relatively high potency -->
</emotion>
<emotion>
<category name="happiness"/>
EmotionML markup explicitly refers to one or more separate vocabularies used for representing emotion-related states.
</emotion>
<emotion category-set="http://www.w3.org/TR/emotion-voc/xml#everyday-categories">
<category name="relaxed"/>
EmotionML markup explicitly refers to one or more separate vocabularies used for representing emotion-related states.
</emotion>
## More information
* [EmotionML](https://www.w3.org/TR/emotionml/)
* [EmotionML - Emotions](https://www.w3.org/TR/emotion-voc/)

View File

@ -0,0 +1,103 @@
# RT-Voice PRO - SSML
Works with Windows, WSA (UWP), MaryTTS, eSpeak, AWS Polly, Azure and Google Cloud.
## Examples
### Changing Voices
This is the default voice. <voice name="Microsoft David Desktop">This is David.</voice> This is the default again. <voice name="Microsoft Zira Desktop">Zira here.</voice>
This is the default voice. <voice name="cmu-bdl-hsmm">This is cmu-bdl-hsmm.</voice> This is the default again. <voice name="dfki-spike-hsmm">dfki-spike-hsmm here.</voice>
### Inserting silence / pauses (not working in MaryTTS 5.2)
This is not <break strength="none" /> a pause.
This is a <break strength="x-weak" /> phrase break.
This is a <break strength="weak" /> phrase break.
This is a <break strength="medium" /> sentence break.
This is a <break strength="strong" /> paragraph break.
This is a <break strength="x-strong" /> paragraph break.
This is a <break time="3s" /> three second pause.
This is a <break time="4500ms" /> 4.5 second pause.
This is a <break /> sentence break
### Adjusting Speech Rate
I am now <prosody rate="x-slow">speaking at half speed.</prosody>
I am now <prosody rate="slow">speaking at 2/3 speed.</prosody>
I am now <prosody rate="medium">speaking at normal speed.</prosody>
I am now <prosody rate="fast">speaking 33% faster.</prosody>
I am now <prosody rate="x-fast">speaking twice as fast</prosody>
I am now <prosody rate="default">speaking at normal speed.</prosody>
I am now <prosody rate=".42">speaking at 42% of normal speed.</prosody>
I am now <prosody rate="2.8">speaking 2.8 times as fast</prosody>
I am now <prosody rate="-0.3">speaking 30% more slowly.</prosody>
I am now <prosody rate="+0.3">speaking 30% faster.</prosody>
### Adjusting Voice Pitch
<prosody pitch="x-low">This is half-pitch</prosody>
<prosody pitch="low">This is 3/4 pitch.</prosody>
<prosody pitch="medium">This is normal pitch.</prosody>
<prosody pitch="high">This is twice as high.</prosody>
<prosody pitch="x-high">This is three times as high.</prosody>
<prosody pitch="default">This is normal pitch.</prosody>
<prosody pitch="-50%">This is 50% lower.</prosody>
<prosody pitch="+50%">This is 50% higher.</prosody>
<prosody pitch="-6st">This is six semitones lower.</prosody>
<prosody pitch="+6st">This is six semitones higher.</prosody>
<prosody pitch="-25Hz">This has a pitch mean 25 Hertz lower.</prosody>
<prosody pitch="+25Hz">This has a pitch mean 25 Hertz higher.</prosody>
<prosody pitch="75Hz">This has a pitch mean of 75 Hertz.</prosody>
### Adjusting Output Volume (partially working in AWS Polly)
<prosody volume="silent">This is silent.</prosody>
<prosody volume="x-soft">This is 25% as loud.</prosody>
<prosody volume="soft">This is 50% as loud.</prosody>
<prosody volume="medium">This is the default volume.</prosody>
<prosody volume="loud">This is 50% louder.</prosody>
<prosody volume="x-loud">This is 100% louder.</prosody>
<prosody volume="default">This is the default volume.</prosody>
<prosody volume="-33%">This is 33% softer.</prosody>
<prosody volume="+33%">This is 33% louder.</prosody>
<prosody volume="33%">This is 33% louder.</prosody>
<prosody volume="33">This is 33% of normal volume.</prosody>
### Adding Emphasis to Speech (no effect in MaryTTS 5.2)
This is <emphasis level="strong">stronger</emphasis> than the rest.
This is <emphasis level="moderate">slightly stronger</emphasis> than the rest.
This is <emphasis level="none">the same as</emphasis> than the rest.
### Shaping intonation contour (seems not to work in Windows)
<prosody contour="(0%,+20%) (40%,+40%) (60%,+60%) (80%,+80%) (100%,+100%)">I am talking with rising intonation.</prosody>
<prosody contour="(0%,-20%) (40%,-40%) (60%,-60%) (80%,-80%) (100%,-100%)">I am talking with falling intonation.</prosody>
<prosody contour="(0%,+20Hz) (10%,+30%) (40%,+10Hz)">good morning</prosody>
### Say-as example (partially working in MaryTTS)
Your reservation for <say-as interpret-as="cardinal"> 2 </say-as> rooms on
the <say-as interpret-as="ordinal"> 4th </say-as> floor of the hotel on
<say-as interpret-as="date" format="mdy"> 3/21/2012 </say-as>, with early
arrival at <say-as interpret-as="time" format="hms12"> 12:35pm </say-as>
has been confirmed. Please call <say-as interpret-as="telephone" format="1">
(888) 555-1212 </say-as> with any questions.
### Control the rhythm of speech output
The rental car you reserved <break strength="medium" /> a mid-size sedan
<break strength="medium" /> will be ready for you to pick up at <break
time="500ms" /> <say-as interpret-as="hms12"> 4:00pm </say-as> today.
### Adding audio (e.g. for paralanguage, only Windows and WSA (UWP))
<audio src="https://www.crosstales.com/media/rtvoice/Miau.wav"/>is the sound of a cat.
<audio src="https://www.crosstales.com/media/rtvoice/Ouch.wav"/>I hit my thumb!
## More information
* [SSML](https://www.w3.org/TR/speech-synthesis/)
* [Reference MS](https://docs.microsoft.com/en-us/cortana/reference/ssml)

View File

@ -0,0 +1,690 @@
# RT-Voice PRO - Release notes
## 2020.4.10 - 17.12.2020
* Improved for Unity 2020.2
* Documentation updated
* Updated to Common 2020.4.8
## 2020.4.9 - 16.12.2020
* Speaker: "HandleFocus" added and better handling of focus on mobile
* Demo scenes and prefabs improved
## 2020.4.8 - 14.12.2020
* Planned final release for 2020
* Google Cloud provider improved
* Updated to Common 2020.4.7
## 2020.4.7 - 09.12.2020
* Android: Fix for Java file
* Updated to Common 2020.4.6
## 2020.4.6 - 02.12.2020
* Android: AAR replaced by Java file
* Updated to Common 2020.4.5
## 2020.4.5 - 27.11.2020
* AWS Polly improved
* Android native library improved
* Loudspeaker improved
## 2020.4.4 - 30.10.2020
* eSpeak is now fully configurable
* AWS, Azure and Google providers improved
* MaryTTS is now a custom provider
* WebGL fixed
## 2020.4.3 - 19.10.2020
* Fixes error cases in standalone providers
* Android: fixes for build problems due the manifest
* LiveSpeaker: all methods are now ending with "Live", like "SpeakLive"
* Speaker improved
* Updated to Common 2020.4.4
## 2020.4.2 - 14.09.2020
* Fix for WSA
* Speaker improved
* GlobalCache improved
## 2020.4.1 - 10.09.2020
* Code clean-up
## 2020.4.0 - 07.09.2020
* macOS: WAV instead of AIFF
* iOS: potential method conflicts removed
* WSA: DLL removed and source "RTVoiceUWPBridge" file added
* AWS Polly updated
* Big code overhaul: use "Instance" to access the methods and variables
* Import of the demo scenes streamlined
* Caching fixed
* Dropped support for versions before Unity 2018.4
* Updated to Common 2020.4.3
## 2020.3.2 - 21.07.2020
* macOS: emergency fix
## 2020.3.1 - 20.07.2020
* iOS: fix for automatically added "Speaker"
* macOS: fix for builds
## 2020.3.0 - 03.07.2020
* Unity events added to "Speaker":
* OnReady
* OnSpeakStarted
* OnSpeakCompleted
* OnProviderChanged
* OnError
* Unity events added to "AudioFileGenerator":
* OnStart
* OnComplete
* Unity events added to "Paralanguage":
* OnStart
* OnComplete
* Unity events added to "SpeechText":
* OnStart
* OnComplete
* C# delegates and Unity events added to "TextFileSpeaker":
* OnStart
* OnComplete
* GlobalCache added
* Android: support for all installed TTS engines
* Updated to Common 2020.3.0
## 2020.2.3 - 17.06.2020
* Windows: executables removed
* Demo scenes are now in "Demos.unitypackage" (please install "Assets/Plugins/crosstales/Common/UI.unitypackage" first)
* Speaker: "Reset" changed to "ResetObject"
* Demos improved
* Updated to Common 2020.2.1
## 2020.2.2 - 02.06.2020
* iOS: Pause and UnPause improved
* Further improvements for AWS, Azure and Google Cloud
## 2020.2.1 - 24.05.2020
* Speaker: works without an object in the scene
* AWS, Azure and Google Cloud updated
* Small Editor improvements
* Updated to Common 2020.2.0
## 2020.2.0 - 17.05.2020
* AWS: support for WSA
* Azure: Support for .NET Standard 2.0
* Demo scenes improved
* General code overhaul
* Compile defines can now be disabled
* Editor integration improved
* PlayMaker actions improved
* Integration for Unity 2020 improved
## 2020.1.5 - 20.04.2020
* WSA: provider largely improved
* Azure: sample rate added
* All 3rd-party integrations improved
## 2020.1.4 - 16.04.2020
* Windows: fix for long texts
* AudioFileGenerator: fixed for macOS and Linux editors
* AWS Polly: sample rate added
* Klattersynth: integration improved
* SAPI Unity: integration improved
## 2020.1.3 - 14.04.2020
* iOS: support for Pause and UnPause added
* AWS Polly: installation improved and support for neural voices added
* Code cleanup
* Updated to Common 2020.1.3
## 2020.1.2 - 26.03.2020
* Windows: resilience for buggy voices improved
* SAPI: integration improved
* Improvements for macOS and Linux editors
## 2020.1.1 - 05.03.2020
* Speaker; default of parameter "isFuzzy" changed to false in:
* VoiceForCulture
* VoicesForCulture
* VoiceForGender
* VoicesForGender
* iOS: Silence(uid) works now as expected
* SAPI Unity: Silence(uid) works now as expected
* ReminderCheck removed
* Updated to Common 2020.1.2
## 2020.1.0 - 29.01.2020
* iOS: library reworked
* macOS: IL2CPP support
* eSpeak: IL2CPP support
* asmdef added
* Demo: Poems updated for macOS&Linux
* Editor integration improved
* Support for Unity 2020
* Updated to Common 2020.1.1
## 2019.6.5 - 17.12.2019
* PlayMaker-actions improved
* Android: Manifest fixed
* Code improvements
## 2019.6.4 - 05.12.2019
* Speaker:
* "isMuted", "Mute", "UnMute" and "MuteOrUnMute" added
* "isPaused" and "PauseOrUnpause" added
* Providers fixed for special XML characters
* Azure provider largely improved
* Android: potential bug in native library fixed
* Updated to Common 2019.5.4
## 2019.6.3 - 20.11.2019
* General: fix for "VoiceForName"
* Updated to Common 2019.5.3
## 2019.6.2 - 10.11.2019
* General: Improvements for "VoiceForName"
* WSA: fix for the build pipeline
* AWS Polly: voices added and improved for 2019+
* Azure: fix for .NET4x
* Updated to Common 2019.5.2
## 2019.6.1 - 10.10.2019
* WebGL: fix for builds
## 2019.6.0 - 06.10.2019
* Biggest code overhaul since the release
* Updated to Common 2019.5.0
## 2019.5.2 - 25.09.2019
* Fix for macOS
* Google Cloud provider improved
* ReminderCheck changed
* UpdateCheck is now set to "false" per default (enable it in the configuration)
## 2019.5.1 - 23.09.2019
* Fix for macOS
* Small improvements
## 2019.5.0 - 11.09.2019
* New voice provider "Google Cloud" added! See "3rd party"-folder for the integration
* AWS Polly: Editor improved
* Azure: Editor improved
* Editor integration improved
## 2019.4.1 - 05.09.2019
* eSpeak: pause at the end of the text removed
* Wrapper: "SpeechTime"-property added
* Updated to Common 2019.4.1
## 2019.4.0 - 28.07.2019
* New voice provider "Azure (Bing Speech)" added! See "3rd party"-folder for the integration
* SALSA-integration updated to version 2.1.0
* AWS Polly: fix for IL2CPP under Android
* Updated for Unity 2017.4 and higher
* Added compatibility with assembly definitions
* Demos: fully qualified access to classes
* Updated to Common 2019.4.0
## 2019.3.1 - 27.05.2019
* Linux: problems under non-Windows platforms solved
* Rare problems with loading a corrupted configuration fixed
* Updated to Common 2019.3.2
## 2019.3.0 - 08.05.2019
* New voice provider "WebGL" added! See "3rd party"-folder for the integration
* Windows: voice selection fixed
* Pattern matching for cultures simplified. E.g. "en US", "enus", "en-us" and "en_us" is now working.
* PlayMaker actions "GetVoices" and "GetCultures" added
* Updated to Common 2019.3.1
## 2019.2.3 - 19.04.2019
* "Enforce Standalone TTS" for development in the configuration added (e.g. for mobile)
* Fixes for iOS, Android and WSA build platforms
* Better Editor handling
* Tested with Unity 2019.1.0
* Updated to Common 2019.3.0
## 2019.2.2 - 11.04.2019
* Fix: Build platforms other than Windows failed in 2019.2.1
* Updated to Common 2019.2.6
## 2019.2.1 - 05.04.2019
* Windows: Native and eSpeak voice providers are now working under IL2CPP!
* New voice provider "SAPI Unity" added! See "3rd party"-folder for the integration
* WSA: code improved and native mode added (when built as XAML without IL2CPP)
* AWS Polly: "Auto Breath" added
* Speaker: OnApplicationFocus now pauses and unpauses per default
* Speaker and Provider: "isWorkingInPlaymode" and "isIL2CPPSupported" added
* Voice: Version added
* Editor improved
* Updated to Common 2019.2.5
## 2019.2.0 - 12.03.2019
* New voice provider "Klattersynth" added! See "3rd party"-folder for the integration
* Speaker: "isOnlineService" and "hasCoRoutines" added
* Provider: "isOnlineService" and "hasCoRoutines" added
* AudioFileGenerator: callback "OnParalanguageStart" and "OnParalanguageComplete" added
* Paralanguage: callback "OnParalanguageStart" and "OnParalanguageComplete" added
* SpeechText: callback "OnSpeechTextStart" and "OnSpeechTextComplete" added
* PlayMaker actions added:
* AudioFileGenerator
* Paralanguage
* SpeechText
* TextFileSpeaker
* Updated to Common 2019.2.3
## 2019.1.3 - 11.02.2019
* eSpeak-NG support added
* eSpeak: added data path (can now be bundled with Unity)
* Warning added if build target is standalone with IL2CPP
* Code cleanup
## 2019.1.2 - 07.02.2019
* Windows:
* fix for built-in provider when voice is null
* detection of "modern Spanish" added
* Updated to Common 2019.2.1
## 2019.1.1 - 28.01.2019
* "Unity Standard Assets" removed
* UWP (WSA) provider improved
* Minor code improvements
## 2019.1.0 - 14.01.2019
* Windows: new DLL-integrated wrapper added (use "Windows Legacy" to use the old wrapper)
* Provider:
* isSpeakNativeSupported added
* isSpeakSupported added
* isPlatformSupported added
* isSSMLSupported added
* Speaker:
* isSpeakNativeSupported added
* isSpeakSupported added
* isPlatformSupported added
* isSSMLSupported added
* BusyCount and isBusy added
* Updated to Common 2019.1.0
## 2018.4.0 - 01.11.2018
* Windows: Wrapper improved to become faster
* macOS: voices correctly set
* Amplitude-demo added
* SALSA-demos improved
* Updated to Common 2018.4.0
## 2018.3.1 - 18.10.2018
* New voice provider AWS Polly added! See "3rd party"-folder for the integration
* Removed false-positives for AV-scanners under Windows (issues with the deployment on "Steam" caused by Trend Micro)
* Fixes for WSA
* Speaker:
* SpeakNative: "O"nSpeakComplete" is only called if the speech was successful
* "DeleteAudioFiles"-method added
* Memory-leak from AudioClips fixed
* Demo scenes improved
* 3rd party:
* Adventure Creator-version updated to 1.65.1
* LDC-version updated to 5.0
* SALSA-version updated to 1.5.5
* SLATE-version updated to 1.8.2
* Updated to Common 2018.3.1
## 2018.3.0 - 09.10.2018
* Android: storage-permission removed
* Speaker:
* "Pause" and "UnPause" added
* "SpeechCount" added
* "Reset"-method added
* Windows:
* fix for prepare voices
* SSML for apostrophes improved
* WWW replaced with UnityWebRequest
* Speaker: ensure name is optional (see "Config")
* Editor integration improved
* UpdateCheck: runs in a separate thread
* Minimum Unity version is now 5.6
* Common 2018.3.0 added
* Tested with Unity 2018.3
## 2018.2.0 - 24.08.2018
* Speaker:
* Custom provider added (but not officially accessible)
* "areVoicesReady" added
* "OnSpeakAudioGenerationComplete" fixed (was always called after the speech)
* "ForceSSML" added
* "isVoiceForNameAvailable" and VoiceForName have a new parameter "isExact"
* TextFileSpeaker: Next, Previous, SpeakAll and StopAll added
* Paralanguage added
* BaseCustomVoiceProvider added (for an example see "VoiceProviderExample")
* WavMaster added
* Wrapper: ForceSSML added
* iOS: Voice match by id instead of name
* Windows: SSML improved
* WebGL: compatible with "Amplitude" => lip-sync in the browser
* Large refactorings to improve all providers
* Processes and error messages improved
* Common 2018.2.0 added
* Discord channel added
* Standard version removed
## 2.9.8 - 05.06.2018
* WSA:
* SSML support added
* pitch added
* rate added
* volume added
* Speaker: added parameter "isFuzzy" to all VoicesForXY-methods
* VoiceAlias improved
* Demo scenes improved (gender added)
* Editor integration improved
* Android: gender matching added
* Windows: SSML improved
* Official support for Unity 2018.1 & 2018.2
## 2.9.7 - 04.04.2018
* Fix for MaryTTS (was always disabled in play-mode)
* New class "ChangeGender.cs" added (useful for eSpeak)
* Gender-mapping for:
* iOS (11.0)
* macOS (10.13)
* WSA (UWP)
* Speaker: "VoicesForGender" and "VoiceForGender" added
* eSpeak integration improved - now are all modifiers (m1-m6, f1-f4, croak, whisper) available!
## 2.9.6 - 25.03.2018
* Provider for Linux added (works also on Windows and macOS, see option "eSpeak" in Speaker)!
* Delegates moved to own class "Delegates.cs"
* Providers implement now the interface "IVoiceProvider.cs"
* Voice: Gender is now an enum
* VoiceAlias added
* Speaker: Streamed and Compressed added for AudioClips
## 2.9.5 - 21.02.2018
* Windows and macOS: Processes fixed (exit condition)
* Common 1.2.5 added
## 2.9.4 - 08.12.2018
* Latency of the Speak-call reduced
* Common 1.2.0 added
## 2.9.3 - 22.12.2017
* Asset moved to "Plugins"
* Windows and macOS provider improved
* AudioFileGenerator: output sample rate, bits and channels added for Windows
* VoiceProviderMary: Text type added
* UpdateCheck improved
* NYCheck added
* Code cleanup
## 2.9.2 - 04.12.2017
* "Dont Destroy" added to Speaker
* BaseVoiceProvider and VoiceProviderWindows: "SpeakNative" improved
* Silence on focus lost added
* EditorConfig improved
* Improved for Unity 2017.3
* Support for pre Unity 5.3 dropped
## 2.9.1 - 23.11.2017
* Windows and maOS provider fixed for WSA
* Locate of the assets improved
## 2.9.0 - 18.11.2017
* Compile define symbol "CT_RTV" added
* id file added
* Windows and macOS: now fully multi-threaded & better performance
* Android and WSA: GC allocs minimized
* Asset path in Editor removed, locate it automatically!
* General code improvements
## 2.8.6 - 17.10.2017
* VoiceInitalizer added
* Android: pre-caching of voices disabled
* iOS: Bridge improved
* SALSA: 2D-demo scene added
* PlayMaker: missing platforms added
* Speaker:
* isVoiceForCultureAvailable added
* isVoiceForNameAvailable added
* VoiceForCulture has now a third parameter called "fallbackCulture"
* Editor scripts better organized
* Updated for Unity 2017.3
## 2.8.5 - 18.09.2017
* Editor improved
* Windows: Wrappers fixed to work again with all SAPI5 voices
* Documentation improved
## 2.8.4 - 03.09.2017
* PlayMaker-actions improved
* Speaker: isSpeaking added
* ConfigLoader added
* Show configuration on the first launch
* Updated for Unity 2017.2
## 2.8.3 - 24.08.2017
* WSA: IL2CPP fixed
* WSA: Support for version 8.0 and 8.1 removed
* Windows: Wrappers improved
* Videos updated
## 2.8.2 - 15.08.2017
* WSA: path problems fixed
* Providers improved
* GAApi added
* General code improvements
## 2.8.1 - 24.07.2017
* MaryTTS: RAWMARYXML, EmotionML and SSML added!
* MaryTTS: Rate and pitch added
* MaryTTS: provider works now without a given voice
* MaryTTS: proper URI-encoding added
* Windows: SSML added!
* Windows: Pitch added
* AudioFileGenerator: Prefab and demo scene added
* Helper.cs: ClearTags added
* Speaker.cs: order of the arguments switched (volume <=> pitch)
* LiveSpeaker.cs: order of the arguments switched (volume <=> pitch)
* Tutorial for SSML and EmotionML added
* Poem.txt added
* Official support for Unity 2017
## 2.8.0 - 07.07.2017
* Demo scenes improved
* Android: automatically set the correct API-level
* iOS: legacy code for pre-iOS 8 removed. Now are all voices selectable.
* iOS: automatically set the correct target SDK
* iOS: speech rate fixed
* MaryTTS: HTTP-auth added
* Callbacks: EventArgs removed and replaced by parameters (like the "Wrapper" etc.)
* Speaker: Speak-parameters changed (switched the positions of "outputFile" and "pitch")
* New callback "OnVoicesReady" added
* DLL removed (only source code)
* EXEs and DLLs are now signed
* Documentation for MaryTTS-server with HTTPS added (for WebGL)
* Small fixes
## 2.7.4 - 20.06.2017
* SetupResources.cs improved
## 2.7.3 - 02.06.2017
* Internet check improved
* Update check improved
* Reminder added
* Configuration window and menu "Tools" improved:
* Videos added (incl. promo and tutorials)
* README added
* VERSIONS added
* Social-media buttons added
## 2.7.2 - 19.05.2017
* Events changed:
* OnErrorInfo
* OnSpeakCurrentWord
* OnSpeakCurrentPhoneme
* OnSpeakCurrentViseme
* Internet availability check added
* Use of "System.Guid" reduced
* TTS-Killtime changed from 5000 to 3000
* Wrapper: "Created" added
* New EXE"s for Windows
* Fix for WSA (UWP) builds
* Tested with Unity 2017
* Code-cleanup
## 2.7.1 - 10.04.2017
* Support for HTTPS added
* Editor: scroll views added
* Context-menu for hierarchy added
* Editor-components improved
* API-template improved
* Demo scenes updated
* Proxy added
## 2.7.0 - 09.03.2017
* MaryTTS implemented
* Support for WSA 8.0 and 8.1 added
* File-operations improvement
* Events are simplified - parameter "sender" was removed
* Code improvements
## 2.6.2 - 27.01.2017
* DLL fixed for IL2CPP
## 2.6.1 - 11.01.2017
* Stub for UWP (WSA) fixed
## 2.6.0 - 09.01.2017
* UWP (WSA) support added!
* Speaker events "OnSpeakNativeStart" and "OnSpeakNativeComplete" removed: use "OnSpeakStart" and "OnSpeakComplete" instead
* Android: fix for getting the voices on various devices
* Windows: special character (UTF8) support for voices
* Support for Unity 5.6 added
* TextFileSpeaker improved
* Sources are inside the "Sources.unitypackage"
* Minor code improvements
## 2.5.2 - 27.10.2016
* TextFileSpeaker added
* DontDestroyOnLoad is now configurable in the settings (currently hidden)
* The Windows-TTS-Wrapper is now configurable in the settings (currently hidden)
* The macOS-TTS-command is now configurable in the settings (currently hidden)
* Settings are managed via CTPlayerPrefs
* Default as DLL (sources are inside the "sources.zip")
* Code clean-up
## 2.5.1 - 21.09.2016
* PlayMaker actions improved
* 32bit-mode for Windows changed
* Unity 5.5-ready
## 2.5.0 - 13.09.2016
* Android support added!
* iOS support added!
* Support for 32-Bit Windows system voices
* Pitch added
* Namespaces extended
* Code improvements
## 2.4.4 - 28.02.2016
* VoiceProvider Speak() improved
* Demo for "NPC Chat" added (see folder "3rd party")
* Code improvements
## 2.4.3 - 15.07.2016
* Editor integration improved
* Rename of all events to OnXY
* Marginal code changes
## 2.4.2 - 11.07.2016
* 3rd party support (AC, UDEA and PlayMaker) improved
* New method to approximate the length of a speech: Speaker.ApproximateSpeechLength()
* Test-Drive added to the configuration window
* Callbacks are now on the Speaker-class
* Error-callback "ErrorInfoEvent" added
* Documentation improved
## 2.4.1 - 05.07.2016
* Configuration window and "Unity Preferences" added
## 2.4.0 - 30.06.2016
* SpeechText added
* LiveSpeaker improved
* Automatically adds the necessary RTVoice-prefabs to the current scene
* Update-checker added
* PlayMaker actions improved
* RTVoiceTTSWrapper.exe rebuild (is now "AnyCPU" instead of "x86") and malware report from [Metadefender](https://www.metadefender.com/) added
* VoiceProvider is now platform independent
* Demo for "Adventure Creator" added (see folder "3rd party")
* Demo for "Cinema Director" added (see folder "3rd party")
* Demo for "Dialogue System" added (see folder "3rd party")
* Demo for "LDC" added (see folder "3rd party")
* Demo for "LipSync" added (see folder "3rd party")
* Demo for "SLATE" added (see folder "3rd party")
* Demo for "THE Dialogue Engine" added (see folder "3rd party")
* Code improvements
* Documentation updated (section "Additional voices")
* Minimal Unity version is now 5.2.1
## 2.3.1 - 10.06.2016
* Code clean-up
## 2.3.0 - 31.05.2016
* Generated audio can now be stored on a desired file path (see Wrapper-class -> "OutputFile")
* Loudspeaker added: use 1-n synchronized loudspeakers for a single AudioSource origin.
* The Silence()-method works now with provided AudioSources
* Correct handling of AudioSource.Pause() and AudioSource.UnPause()
* SALSA-demo added (see folder "3rd party")
* Code improvements
## 2.2.1 - 17.05.2016
* PlayMaker actions improved
## 2.2.0 - 26.04.2016
* PlayMaker actions added
## 2.1.2 - 12.04.2016
* Demo scenes improved
* Windows provider improved
## 2.1.1 - 04.04.2016
* Multi-threading improved
* Demo scenes improved
* New callbacks added
## 2.1.0 - 24.03.2016
* Sequencer added
* Demo scenes improved (with many 3D audio examples)
* Multi-threading added
* Better Unity Editor integration
* ExecuteInEditMode removed
* Timing for callbacks improved
## 2.0.0 - 22.02.2016
* Various callbacks added
* Added visemes and phomenes on Windows
* Rate and volume control added
* Code clean-up
## 1.4.1 - 11.11.2015
* Exit-handling of processes improved
## 1.4.0 - 22.10.2015
* PRO edition created
* Obsolete-warning for Unity 5.2 and above removed
## 1.3.0 - 20.09.2015
* Windows-Wrapper improved
## 1.2.1 - 28.08.2015
* Bug on OSX fixed
## 1.2.0 - 22.08.2015
* Support for Localized Dialogs & Cutscenes (LDC) added
* Support for Dialogue System for Unity added
* Support for THE Dialogue Engine added
* Wrappers for MonoBehaviour added (like "SendMessage")
## 1.1.1 - 12.08.2015
* Minor code improvements
## 1.1.0 - 07.08.2015
* Direct Unity-support added (thanks to "Crazy Minnow Studio" for their valuable suggestions)
## 1.0.0 - 20.07.2015
* Production release

View File

@ -0,0 +1,3 @@
Please DON'T REMOVE this file!
181f4dab-261f-4746-85f8-849c2866d353

View File

@ -0,0 +1,91 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'SpeechText'-class.</summary>
[CustomEditor(typeof(Tool.AudioFileGenerator))]
[CanEditMultipleObjects]
public class AudioFileGeneratorEditor : Editor
{
#region Variables
private Tool.AudioFileGenerator script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.AudioFileGenerator)target;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
EditorHelper.SeparatorUI();
if (script.isActiveAndEnabled)
{
if (script.TextFiles != null && script.TextFiles.Length > 0)
{
if (Speaker.Instance.isTTSAvailable && EditorHelper.isRTVoiceInScene)
{
if (Util.Helper.isEditorMode)
{
GUILayout.Label("Generate Audio Files", EditorStyles.boldLabel);
GUILayout.BeginHorizontal();
{
if (Speaker.Instance.isWorkingInEditor)
{
if (GUILayout.Button(new GUIContent(" Generate", EditorHelper.Icon_Speak, "Generates the speeches from the text files.")))
script.Generate();
}
else
{
EditorGUILayout.HelpBox("Generate is not supported for current TTS-system inside the Unity Editor.", MessageType.Info);
}
}
GUILayout.EndHorizontal();
EditorHelper.SeparatorUI();
GUILayout.Label("Editor", EditorStyles.boldLabel);
if (GUILayout.Button(new GUIContent(" Refresh AssetDatabase", EditorHelper.Icon_Refresh, "Refresh the AssetDatabase from the Editor.")))
{
EditorHelper.RefreshAssetDatabase();
}
}
else
{
EditorGUILayout.HelpBox("Disabled in Play-mode!", MessageType.Info);
}
}
else
{
EditorHelper.NoVoicesUI();
}
}
else
{
EditorGUILayout.HelpBox("Please add an entry to 'Text Files'!", MessageType.Warning);
}
}
else
{
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,64 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'ChangeGender'-class.</summary>
[CustomEditor(typeof(Tool.ChangeGender))]
[CanEditMultipleObjects]
public class ChangeGenderEditor : Editor
{
#region Variables
private Tool.ChangeGender script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.ChangeGender)target;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
EditorHelper.SeparatorUI();
if (script.isActiveAndEnabled)
{
if (Speaker.Instance.isTTSAvailable && EditorHelper.isRTVoiceInScene)
{
GUILayout.Label("Action", EditorStyles.boldLabel);
if (Util.Helper.isEditorMode)
{
if (GUILayout.Button(new GUIContent(" Change Gender", EditorHelper.Icon_Refresh, "Change the gender of all voices (useful for eSpeak).")))
script.Change();
}
else
{
EditorGUILayout.HelpBox("Disabled in Play-mode!", MessageType.Info);
}
}
else
{
EditorHelper.NoVoicesUI();
}
}
else
{
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2019 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,77 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'GlobalCache'-class.</summary>
[CustomEditor(typeof(GlobalCache))]
public class GlobalCacheEditor : Editor
{
#region Variables
private GlobalCache script;
private bool showCachedClips;
#endregion
#region Editor methods
public void OnEnable()
{
script = (GlobalCache)target;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
EditorHelper.SeparatorUI();
if (script.isActiveAndEnabled)
{
GUILayout.Label("Cache Information", EditorStyles.boldLabel);
GUILayout.Space(6);
showCachedClips = EditorGUILayout.Foldout(showCachedClips, $"Cached Speeches (Clips): {Util.Helper.FormatBytesToHRF(script.CurrentClipCacheSize)}/{Util.Helper.FormatBytesToHRF(script.ClipCacheSize)} ({script.Clips.Count})");
if (showCachedClips)
{
EditorGUI.indentLevel++;
foreach (System.Collections.Generic.KeyValuePair<Crosstales.RTVoice.Model.Wrapper, AudioClip> pair in script.Clips)
{
EditorGUILayout.SelectableLabel(pair.Key.Text, GUILayout.Height(16), GUILayout.ExpandHeight(false));
}
EditorGUI.indentLevel--;
}
GUILayout.Space(6);
GUILayout.Label($"Cache Efficiency: {Util.Context.CacheEfficiency:P}");
EditorHelper.SeparatorUI();
if (GUILayout.Button(new GUIContent(" Clear", EditorHelper.Icon_Delete, "Clears the cache.")))
script.ClearCache();
}
else
{
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
public override bool RequiresConstantRepaint()
{
return true;
}
#endregion
}
}
#endif
// © 2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,52 @@
#if UNITY_EDITOR
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'Loudspeaker'-class.</summary>
[CustomEditor(typeof(Tool.Loudspeaker))]
public class LoudspeakerEditor : Editor
{
#region Variables
private Tool.Loudspeaker script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.Loudspeaker)target;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (script.isActiveAndEnabled)
{
if (script.Source != null)
{
//add stuff if needed
}
else
{
EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Please add a 'Source'!", MessageType.Warning);
}
}
else
{
EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,67 @@
#if UNITY_EDITOR
using UnityEditor;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'Paralanguage'-class.</summary>
[CustomEditor(typeof(Tool.Paralanguage))]
[CanEditMultipleObjects]
public class ParalanguageEditor : Editor
{
#region Variables
private Tool.Paralanguage script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.Paralanguage)target;
}
public void OnDisable()
{
if (Util.Helper.isEditorMode)
{
Speaker.Instance.Silence();
}
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (script.isActiveAndEnabled)
{
if (!string.IsNullOrEmpty(script.Text))
{
if (Speaker.Instance.isTTSAvailable && EditorUtil.EditorHelper.isRTVoiceInScene)
{
//add stuff if needed
}
else
{
EditorUtil.EditorHelper.NoVoicesUI();
}
}
else
{
EditorUtil.EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Please enter a 'Text'!", MessageType.Warning);
}
}
else
{
EditorUtil.EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,56 @@
#if UNITY_EDITOR
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'Sequencer'-class.</summary>
[CustomEditor(typeof(Tool.Sequencer))]
public class SequencerEditor : Editor
{
#region Variables
private Tool.Sequencer script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.Sequencer)target;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (script.isActiveAndEnabled)
{
if (script.Sequences != null && script.Sequences.Length > 0)
{
if (!Speaker.Instance.isTTSAvailable && EditorHelper.isRTVoiceInScene)
{
EditorHelper.SeparatorUI();
EditorHelper.NoVoicesUI();
}
}
else
{
EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Please add an entry to 'Sequences'!", MessageType.Warning);
}
}
else
{
EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,447 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'Speaker'-class.</summary>
[InitializeOnLoad]
[CustomEditor(typeof(Speaker))]
public class SpeakerEditor : Editor
{
#region Variables
private string text = "Hello world!";
private int voiceIndex;
private float rate = 1f;
private float pitch = 1f;
private float volume = 1f;
private Speaker script;
private bool showVoices;
private Object customProvider;
private bool customMode;
private bool eSpeakMode;
private Model.Enum.ESpeakModifiers eSpeakModifier;
private string eSpeakApp;
private string eSpeakData;
private string androidEngine;
private bool autoClearTags;
private bool caching;
//private bool windowsLegacy;
//private bool wsaNative;
private bool silenceOnDisable;
private bool silenceOnFocusLost;
private bool handleFocus;
private bool dontDestroy;
#endregion
#region Static constructor
static SpeakerEditor()
{
EditorApplication.hierarchyWindowItemOnGUI += hierarchyItemCB;
}
#endregion
#region Editor methods
public void OnEnable()
{
script = (Speaker)target;
}
public void OnDisable()
{
if (Util.Helper.isEditorMode)
script.Silence();
}
public override bool RequiresConstantRepaint()
{
return true;
}
public override void OnInspectorGUI()
{
EditorHelper.BannerOC();
if (script.enforcedStandaloneTTS)
{
EditorGUILayout.HelpBox("Standalone TTS is used for development. The TTS on the current build target may have other voices and features.", MessageType.Warning);
}
if (script.Voices?.Count == 0)
{
if (script.isPlatformSupported && !script.isWorkingInPlaymode)
{
EditorGUILayout.HelpBox("The current TTS only works in builds!", MessageType.Error);
}
else if (!script.isPlatformSupported)
{
EditorGUILayout.HelpBox("The current platform is not supported by the active voice provider. Please use MaryTTS or a custom provider (e.g. Klattersynth).", MessageType.Error);
}
else
{
if (script.hasVoicesInEditor)
EditorGUILayout.HelpBox("TTS with the current settings is not possible!", MessageType.Error);
}
}
if (Util.Helper.isIL2CPP && !script.isIL2CPPSupported)
{
GUILayout.Space(6);
EditorGUILayout.HelpBox("IL2CPP is not supported by the current voice provider. Please use Mono, MaryTTS or a custom provider (e.g. Klattersynth).", MessageType.Error);
}
serializedObject.Update();
GUILayout.Label("Custom Provider", EditorStyles.boldLabel);
customMode = EditorGUILayout.BeginToggleGroup(new GUIContent("Active", "Enables or disables the custom provider (default: false)."), script.CustomMode);
if (customMode != script.CustomMode)
{
serializedObject.FindProperty("customMode").boolValue = customMode;
serializedObject.ApplyModifiedProperties();
voiceIndex = 0;
script.ReloadProvider();
}
EditorGUI.indentLevel++;
customProvider = EditorGUILayout.ObjectField("Custom Provider", script.CustomProvider, typeof(Provider.BaseCustomVoiceProvider), true);
if (customProvider != script.CustomProvider)
{
serializedObject.FindProperty("customProvider").objectReferenceValue = customProvider;
serializedObject.ApplyModifiedProperties();
voiceIndex = 0;
script.ReloadProvider();
}
EditorGUI.indentLevel--;
EditorGUILayout.EndToggleGroup();
if (customMode)
{
if (script.CustomProvider == null)
{
EditorGUILayout.HelpBox("'Custom Provider' is null! Please add a valid provider.", MessageType.Warning);
}
else
{
if (!script.CustomProvider.isPlatformSupported)
{
EditorGUILayout.HelpBox("'Custom Provider' does not support the current platform!", MessageType.Warning);
}
}
}
GUILayout.Space(8);
GUILayout.Label("eSpeak Settings", EditorStyles.boldLabel);
eSpeakMode = EditorGUILayout.BeginToggleGroup(new GUIContent("Active", "Enable or disable eSpeak for standalone platforms (default: false)."), script.ESpeakMode);
if (eSpeakMode != script.ESpeakMode)
{
serializedObject.FindProperty("eSpeakMode").boolValue = eSpeakMode;
serializedObject.ApplyModifiedProperties();
voiceIndex = 0;
script.ReloadProvider();
}
EditorGUI.indentLevel++;
eSpeakApp = EditorGUILayout.TextField(new GUIContent("Application", "eSpeak application name/path (default: 'espeak')."), script.ESpeakApplication);
if (!eSpeakApp.Equals(script.ESpeakApplication))
{
serializedObject.FindProperty("eSpeakApplication").stringValue = eSpeakApp;
serializedObject.ApplyModifiedProperties();
//script.ReloadProvider();
}
eSpeakData = EditorGUILayout.TextField(new GUIContent("Data Path", "eSpeak application data path (default: empty)."), script.ESpeakDataPath);
if (!eSpeakData.Equals(script.ESpeakDataPath))
{
serializedObject.FindProperty("eSpeakDataPath").stringValue = eSpeakData;
serializedObject.ApplyModifiedProperties();
//script.ReloadProvider();
}
eSpeakModifier = (Model.Enum.ESpeakModifiers)EditorGUILayout.EnumPopup(new GUIContent("Modifier", "Active modifier for all eSpeak voices (default: none, m1-m6 = male, f1-f4 = female)."), script.ESpeakModifier);
if (eSpeakModifier != script.ESpeakModifier)
{
serializedObject.FindProperty("eSpeakModifier").enumValueIndex = (int)eSpeakModifier;
serializedObject.ApplyModifiedProperties();
}
EditorGUI.indentLevel--;
EditorGUILayout.EndToggleGroup();
if (eSpeakMode && !Provider.VoiceProviderLinux.isSupported)
{
EditorGUILayout.HelpBox("'eSpeak' is not supported on the current platform!", MessageType.Warning);
}
GUILayout.Space(8);
GUILayout.Label("Android Settings", EditorStyles.boldLabel);
androidEngine = EditorGUILayout.TextField(new GUIContent("Engine", "Active speech engine under Android (default: empty)."), script.AndroidEngine);
if (!androidEngine.Equals(script.AndroidEngine))
{
serializedObject.FindProperty("androidEngine").stringValue = androidEngine;
serializedObject.ApplyModifiedProperties();
//script.ReloadProvider();
}
GUILayout.Space(8);
GUILayout.Label("Advanced Settings", EditorStyles.boldLabel);
autoClearTags = EditorGUILayout.Toggle(new GUIContent("Auto Clear Tags", "Automatically clear tags from speeches depending on the capabilities of the current TTS-system (default: false)."), script.AutoClearTags);
if (autoClearTags != script.AutoClearTags)
{
serializedObject.FindProperty("autoClearTags").boolValue = autoClearTags;
serializedObject.ApplyModifiedProperties();
}
caching = EditorGUILayout.Toggle(new GUIContent("Caching", "Enable or disable the caching of generated speeches (default: true)."), script.Caching);
if (caching != script.Caching)
{
serializedObject.FindProperty("caching").boolValue = caching;
serializedObject.ApplyModifiedProperties();
}
GUILayout.Space(8);
GUILayout.Label("Behaviour Settings", EditorStyles.boldLabel);
silenceOnDisable = EditorGUILayout.Toggle(new GUIContent("Silence On Disable", "Silence any speeches if this component gets disabled (default: false)."), script.SilenceOnDisable);
if (silenceOnDisable != script.SilenceOnDisable)
{
serializedObject.FindProperty("silenceOnDisable").boolValue = silenceOnDisable;
serializedObject.ApplyModifiedProperties();
}
silenceOnFocusLost = EditorGUILayout.Toggle(new GUIContent("Silence On Focus Lost", "Silence any speeches if the application loses the focus (default: true)."), script.SilenceOnFocusLost);
if (silenceOnFocusLost != script.SilenceOnFocusLost)
{
serializedObject.FindProperty("silenceOnFocusLost").boolValue = silenceOnFocusLost;
serializedObject.ApplyModifiedProperties();
}
handleFocus = EditorGUILayout.Toggle(new GUIContent("Handle Focus", "Starts and stops the Speaker depending on the focus and running state (default: true)."), script.HandleFocus);
if (handleFocus != script.HandleFocus)
{
serializedObject.FindProperty("handleFocus").boolValue = handleFocus;
serializedObject.ApplyModifiedProperties();
}
dontDestroy = EditorGUILayout.Toggle(new GUIContent("Dont Destroy", "Don't destroy gameobject during scene switches (default: true)."), script.DontDestroy);
if (dontDestroy != script.DontDestroy)
{
serializedObject.FindProperty("dontDestroy").boolValue = dontDestroy;
serializedObject.ApplyModifiedProperties();
}
SerializedProperty onReady = serializedObject.FindProperty("OnReady");
EditorGUILayout.PropertyField(onReady);
SerializedProperty onSpeakStarted = serializedObject.FindProperty("OnSpeakStarted");
EditorGUILayout.PropertyField(onSpeakStarted);
SerializedProperty onSpeakCompleted = serializedObject.FindProperty("OnSpeakCompleted");
EditorGUILayout.PropertyField(onSpeakCompleted);
SerializedProperty onProviderChanged = serializedObject.FindProperty("OnProviderChanged");
EditorGUILayout.PropertyField(onProviderChanged);
SerializedProperty onError = serializedObject.FindProperty("OnError");
EditorGUILayout.PropertyField(onError);
EditorHelper.SeparatorUI();
if (script.isActiveAndEnabled)
{
GUILayout.Label("Data", EditorStyles.boldLabel);
showVoices = EditorGUILayout.Foldout(showVoices, "Voices (" + script.Voices.Count + ")");
if (showVoices)
{
EditorGUI.indentLevel++;
foreach (string voice in script.Voices.CTToString())
{
EditorGUILayout.SelectableLabel(voice, GUILayout.Height(16), GUILayout.ExpandHeight(false));
}
EditorGUI.indentLevel--;
}
if (GUILayout.Button(new GUIContent(" Reload", EditorHelper.Icon_Refresh, "Reload the provider.")))
{
script.ReloadProvider();
}
EditorHelper.SeparatorUI();
GUILayout.Label("Test-Drive", EditorStyles.boldLabel);
if (script.Voices.Count > 0)
{
//EditorHelper.SeparatorUI();
//GUILayout.Label("Test-Drive", EditorStyles.boldLabel);
if (Util.Helper.isEditorMode)
{
if (script.isWorkingInEditor)
{
GUI.enabled = !script.isSpeaking;
text = EditorGUILayout.TextField("Text: ", text);
voiceIndex = EditorGUILayout.Popup("Voice", voiceIndex, script.Voices.CTToString().ToArray());
rate = EditorGUILayout.Slider("Rate", rate, 0f, 3f);
if (Util.Helper.isWindowsPlatform)
{
pitch = EditorGUILayout.Slider("Pitch", pitch, 0f, 2f);
volume = EditorGUILayout.Slider("Volume", volume, 0f, 1f);
}
GUI.enabled = true;
GUILayout.Space(8);
if (script.isSpeaking)
{
if (GUILayout.Button(new GUIContent(" Silence", EditorHelper.Icon_Silence, "Silence all active speakers.")))
{
script.Silence();
}
}
else
{
if (GUILayout.Button(new GUIContent(" Speak", EditorHelper.Icon_Speak, "Speaks the text with the selected voice and settings.")))
{
//script.SpeakNative("You have selected " + script.Voices[voiceIndex].Name, script.Voices[voiceIndex], rate, pitch, volume);
script.SpeakNative(text, script.Voices[voiceIndex], rate, pitch, volume);
}
}
}
else
{
EditorGUILayout.HelpBox("Test-Drive is not supported for the current TTS-system.", MessageType.Info);
}
}
else
{
EditorGUILayout.HelpBox("Disabled in Play-mode!", MessageType.Info);
}
}
else
{
if (Util.Helper.isEditorMode)
{
if (!script.isWorkingInEditor)
{
EditorGUILayout.HelpBox("Test-Drive is not supported for the current TTS-system.", MessageType.Info);
}
}
else
{
EditorGUILayout.HelpBox("Disabled in Play-mode!", MessageType.Info);
}
}
/*
else
{
if (script.isPlatformSupported && !script.isWorkingInPlaymode)
{
EditorGUILayout.HelpBox("The current TTS only works in builds!", MessageType.Error);
}
else if (!script.isPlatformSupported)
{
EditorGUILayout.HelpBox("The current platform is not supported by the active voice provider. Please use MaryTTS or a custom provider (e.g. Klattersynth).", MessageType.Error);
}
else
{
EditorGUILayout.HelpBox("TTS with the current settings is not possible!", MessageType.Error);
}
}
*/
EditorHelper.SeparatorUI();
GUILayout.Label("Information", EditorStyles.boldLabel);
GUILayout.Label("Speech Count:\t" + script.SpeechCount);
GUILayout.Label("Total Speeches:\t" + Util.Context.NumberOfSpeeches);
#if UNITY_2019_1_OR_NEWER
GUILayout.Label("Total Files:\t" + Util.Context.NumberOfAudioFiles);
#else
GUILayout.Label("Total Audio Files:\t" + Util.Context.NumberOfAudioFiles);
#endif
/*
if (script.Caching)
{
GUILayout.Space(12);
GUILayout.Label($"Cached Speeches:\t{Util.Helper.FormatBytesToHRF(GlobalCache.Instance.CurrentClipCacheSize)}/{Util.Helper.FormatBytesToHRF(GlobalCache.Instance.ClipCacheSize)} ({GlobalCache.Instance.Clips.Count})");
GUILayout.Label($"Cache Efficiency:\t{Util.Context.CacheEfficiency:P}");
}
*/
}
else
{
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
serializedObject.ApplyModifiedProperties();
}
#endregion
#region Private methods
private static void hierarchyItemCB(int instanceID, Rect selectionRect)
{
if (EditorConfig.HIERARCHY_ICON)
{
GameObject go = EditorUtility.InstanceIDToObject(instanceID) as GameObject;
if (go != null && go.GetComponent<Speaker>())
{
Rect r = new Rect(selectionRect);
r.x = r.width - 4;
//Debug.Log("HierarchyItemCB: " + r);
GUI.Label(r, EditorHelper.Logo_Asset_Small);
}
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,114 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'SpeechText'-class.</summary>
[CustomEditor(typeof(Tool.SpeechText))]
[CanEditMultipleObjects]
public class SpeechTextEditor : Editor
{
#region Variables
private Tool.SpeechText script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.SpeechText)target;
}
public void OnDisable()
{
if (Util.Helper.isEditorMode)
{
Speaker.Instance.Silence();
}
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
EditorHelper.SeparatorUI();
if (script.isActiveAndEnabled)
{
if (!string.IsNullOrEmpty(script.Text))
{
if (script.GenerateAudioFile && !string.IsNullOrEmpty(script.FileName) || !script.GenerateAudioFile)
{
if (Speaker.Instance.isTTSAvailable && EditorHelper.isRTVoiceInScene)
{
GUILayout.Label("Test-Drive", EditorStyles.boldLabel);
if (Util.Helper.isEditorMode)
{
if (Speaker.Instance.isWorkingInEditor)
{
if (Speaker.Instance.isSpeaking)
{
if (GUILayout.Button(new GUIContent(" Silence", EditorHelper.Icon_Silence, "Silence the active speaker.")))
{
script.Silence();
}
}
else
{
if (GUILayout.Button(new GUIContent(" Speak", EditorHelper.Icon_Speak, "Speaks the text with the selected voice and settings.")))
{
script.Speak();
}
}
}
else
{
EditorGUILayout.HelpBox("Test-Drive is not supported for current TTS-system inside the Unity Editor.", MessageType.Info);
}
EditorHelper.SeparatorUI();
GUILayout.Label("Editor", EditorStyles.boldLabel);
if (GUILayout.Button(new GUIContent(" Refresh AssetDatabase", EditorHelper.Icon_Refresh, "Refresh the AssetDatabase from the Editor.")))
{
EditorHelper.RefreshAssetDatabase();
}
}
else
{
EditorGUILayout.HelpBox("Disabled in Play-mode!", MessageType.Info);
}
}
else
{
EditorHelper.NoVoicesUI();
}
}
else
{
EditorGUILayout.HelpBox("'File Name' is null or empty! Please enter a valid name (incl. path).", MessageType.Warning);
}
}
else
{
EditorGUILayout.HelpBox("Please enter a 'Text'!", MessageType.Warning);
}
}
else
{
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,123 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'TextFileSpeaker'-class.</summary>
[CustomEditor(typeof(Tool.TextFileSpeaker))]
[CanEditMultipleObjects]
public class TextFileSpeakerEditor : Editor
{
#region Variables
private Tool.TextFileSpeaker script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.TextFileSpeaker)target;
}
public void OnDisable()
{
if (Util.Helper.isEditorMode)
{
Speaker.Instance.Silence();
}
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
EditorHelper.SeparatorUI();
if (script.isActiveAndEnabled)
{
if (script.TextFiles != null && script.TextFiles.Length > 0)
{
if (script.PlayOnStart && script.PlayAllOnStart)
{
EditorGUILayout.HelpBox("Can't use 'Play On Start' and 'Play All On Start' in combination. Please decide for one approach!", MessageType.Warning);
}
else
{
if (Speaker.Instance.isTTSAvailable && EditorHelper.isRTVoiceInScene)
{
GUILayout.Label("Test-Drive", EditorStyles.boldLabel);
if (Util.Helper.isEditorMode)
{
if (Speaker.Instance.isWorkingInEditor)
{
GUILayout.BeginHorizontal();
{
/*
if (GUILayout.Button(new GUIContent(" Previous", EditorHelper.Icon_Previous, "Plays the previous radio station.")))
{
script.Previous();
}
*/
if (Speaker.Instance.isSpeaking)
{
if (GUILayout.Button(new GUIContent(" Silence", EditorHelper.Icon_Silence, "Silence the active speaker.")))
{
script.Silence();
}
}
else
{
if (GUILayout.Button(new GUIContent(" Speak", EditorHelper.Icon_Speak, "Speaks a random text file with the selected voice and settings.")))
{
script.Speak();
}
}
/*
if (GUILayout.Button(new GUIContent(" Next", EditorHelper.Icon_Next, "Speaks the next text file.")))
{
script.Next();
}
*/
}
GUILayout.EndHorizontal();
}
else
{
EditorGUILayout.HelpBox("Test-Drive is not supported for current TTS-system inside the Unity Editor.", MessageType.Info);
}
}
else
{
EditorGUILayout.HelpBox("Disabled in Play-mode!", MessageType.Info);
}
}
else
{
EditorHelper.NoVoicesUI();
}
}
}
else
{
EditorGUILayout.HelpBox("Please add an entry to 'Text Files'!", MessageType.Warning);
}
}
else
{
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,56 @@
#if UNITY_EDITOR
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorExtension
{
/// <summary>Custom editor for the 'VoiceInitalizer'-class.</summary>
[CustomEditor(typeof(Tool.VoiceInitializer))]
public class VoiceInitializerEditor : Editor
{
#region Variables
private Tool.VoiceInitializer script;
#endregion
#region Editor methods
public void OnEnable()
{
script = (Tool.VoiceInitializer)target;
}
public override void OnInspectorGUI()
{
DrawDefaultInspector();
if (script.isActiveAndEnabled)
{
if (script.AllVoices || script.VoiceNames != null && script.VoiceNames.Length > 0)
{
if (!Speaker.Instance.isTTSAvailable && EditorHelper.isRTVoiceInScene)
{
EditorHelper.SeparatorUI();
EditorHelper.NoVoicesUI();
}
}
else
{
EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Please add an entry to 'Voice Names'!", MessageType.Warning);
}
}
else
{
EditorHelper.SeparatorUI();
EditorGUILayout.HelpBox("Script is disabled!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,599 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using Crosstales.RTVoice.EditorTask;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorIntegration
{
/// <summary>Base class for editor windows.</summary>
public abstract class ConfigBase : EditorWindow
{
#region Variables
private static string updateText = UpdateCheck.TEXT_NOT_CHECKED;
private static UpdateStatus updateStatus = UpdateStatus.NOT_CHECKED;
private System.Threading.Thread worker;
private Vector2 scrollPosConfig;
private Vector2 scrollPosHelp;
private Vector2 scrollPosAboutUpdate;
private Vector2 scrollPosAboutReadme;
private Vector2 scrollPosAboutVersions;
private static string readme;
private static string versions;
private static string ssml;
private static string emotionml;
private bool enforceStandaloneTTS;
private int aboutTab;
private static readonly System.Random rnd = new System.Random();
private readonly int adRnd1 = rnd.Next(0, 8);
private const int maxChars = 16000;
#endregion
#region Protected methods
protected void showConfiguration()
{
EditorHelper.BannerOC();
GUI.skin.label.wordWrap = true;
scrollPosConfig = EditorGUILayout.BeginScrollView(scrollPosConfig, false, false);
{
GUILayout.Label("General Settings", EditorStyles.boldLabel);
//Util.Config.AUDIOFILE_PATH = EditorGUILayout.TextField(new GUIContent("Audio Path", "Path to the generated audio files (default: '" + Util.Constants.DEFAULT_AUDIOFILE_PATH + "')."), Util.Config.AUDIOFILE_PATH);
GUILayout.Label("Audio Path", EditorStyles.centeredGreyMiniLabel);
//EditorGUI.indentLevel++;
EditorGUILayout.BeginHorizontal();
{
EditorGUILayout.SelectableLabel(Util.Config.AUDIOFILE_PATH);
//GUILayout.Label(Util.Config.AUDIOFILE_PATH);
if (GUILayout.Button(new GUIContent(" Select", EditorHelper.Icon_Folder, "Select path for the audio files")))
{
string path = EditorUtility.OpenFolderPanel("Select path for the audio files", Util.Config.AUDIOFILE_PATH, string.Empty);
if (!string.IsNullOrEmpty(path))
{
Util.Config.AUDIOFILE_PATH = path + "/";
}
}
}
EditorGUILayout.EndHorizontal();
//EditorGUI.indentLevel--;
Util.Config.AUDIOFILE_AUTOMATIC_DELETE = EditorGUILayout.Toggle(new GUIContent("Audio Auto-Delete", "Enable or disable auto-delete of the generated audio files (default: " + Util.Constants.DEFAULT_AUDIOFILE_AUTOMATIC_DELETE + ")."), Util.Config.AUDIOFILE_AUTOMATIC_DELETE);
EditorConfig.PREFAB_AUTOLOAD = EditorGUILayout.Toggle(new GUIContent("Prefab Auto-Load", "Enable or disable auto-loading of the prefabs to the scene (default: " + EditorConstants.DEFAULT_PREFAB_AUTOLOAD + ")."), EditorConfig.PREFAB_AUTOLOAD);
Util.Config.DEBUG = EditorGUILayout.Toggle(new GUIContent("Debug", "Enable or disable debug logs (default: " + Util.Constants.DEFAULT_DEBUG + ")."), Util.Config.DEBUG);
EditorConfig.UPDATE_CHECK = EditorGUILayout.Toggle(new GUIContent("Update Check", "Enable or disable the update-checks for the asset (default: " + EditorConstants.DEFAULT_UPDATE_CHECK + ")"), EditorConfig.UPDATE_CHECK);
EditorConfig.COMPILE_DEFINES = EditorGUILayout.Toggle(new GUIContent("Compile Defines", "Enable or disable adding compile define 'CT_RTV' for the asset (default: " + EditorConstants.DEFAULT_COMPILE_DEFINES + ")"), EditorConfig.COMPILE_DEFINES);
EditorHelper.SeparatorUI();
GUILayout.Label("Speaker", EditorStyles.boldLabel);
EditorConfig.HIERARCHY_ICON = EditorGUILayout.Toggle(new GUIContent("Show Hierarchy Icon", "Show hierarchy icon (default: " + EditorConstants.DEFAULT_HIERARCHY_ICON + ")."), EditorConfig.HIERARCHY_ICON);
EditorHelper.SeparatorUI();
GUILayout.Label("Development Settings", EditorStyles.boldLabel);
enforceStandaloneTTS = EditorGUILayout.Toggle(new GUIContent("Enforce Standalone TTS", "Enforce standalone TTS for development (default: " + Util.Constants.DEFAULT_ENFORCE_STANDALONE_TTS + ")."), Util.Config.ENFORCE_STANDALONE_TTS);
if (enforceStandaloneTTS != Util.Config.ENFORCE_STANDALONE_TTS)
{
Util.Config.ENFORCE_STANDALONE_TTS = enforceStandaloneTTS;
Speaker.Instance.ReloadProvider();
}
/*
EditorHelper.SeparatorUI();
GUILayout.Label("Windows Settings", EditorStyles.boldLabel);
Util.Config.ENFORCE_32BIT_WINDOWS = EditorGUILayout.Toggle(new GUIContent("Enforce 32bit Voices", "Enforce 32bit versions of voices under Windows (default: " + Util.Constants.DEFAULT_ENFORCE_32BIT_WINDOWS + ")."), Util.Config.ENFORCE_32BIT_WINDOWS);
*/
}
EditorGUILayout.EndScrollView();
}
protected void showHelp()
{
EditorHelper.BannerOC();
scrollPosHelp = EditorGUILayout.BeginScrollView(scrollPosHelp, false, false);
{
GUILayout.Label("Resources", EditorStyles.boldLabel);
//GUILayout.Space(8);
GUILayout.BeginHorizontal();
{
GUILayout.BeginVertical();
{
if (GUILayout.Button(new GUIContent(" Manual", EditorHelper.Icon_Manual, "Show the manual.")))
Util.Helper.OpenURL(Util.Constants.ASSET_MANUAL_URL);
GUILayout.Space(6);
if (GUILayout.Button(new GUIContent(" Forum", EditorHelper.Icon_Forum, "Visit the forum page.")))
Util.Helper.OpenURL(Util.Constants.ASSET_FORUM_URL);
}
GUILayout.EndVertical();
GUILayout.BeginVertical();
{
if (GUILayout.Button(new GUIContent(" API", EditorHelper.Icon_API, "Show the API.")))
Util.Helper.OpenURL(Util.Constants.ASSET_API_URL);
GUILayout.Space(6);
if (GUILayout.Button(new GUIContent(" Product", EditorHelper.Icon_Product, "Visit the product page.")))
Util.Helper.OpenURL(Util.Constants.ASSET_WEB_URL);
}
GUILayout.EndVertical();
}
GUILayout.EndHorizontal();
EditorHelper.SeparatorUI();
GUILayout.Label("Videos", EditorStyles.boldLabel);
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(" Promo", EditorHelper.Video_Promo, "View the promotion video on 'Youtube'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_VIDEO_PROMO);
if (GUILayout.Button(new GUIContent(" Tutorial", EditorHelper.Video_Tutorial, "View the tutorial video on 'Youtube'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_VIDEO_TUTORIAL);
}
GUILayout.EndHorizontal();
GUILayout.Space(6);
if (GUILayout.Button(new GUIContent(" All Videos", EditorHelper.Icon_Videos, "Visit our 'Youtube'-channel for more videos.")))
Util.Helper.OpenURL(Util.Constants.ASSET_SOCIAL_YOUTUBE);
EditorHelper.SeparatorUI();
GUILayout.Label("3rd Party Assets", EditorStyles.boldLabel);
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Asset_PlayMaker, "More information about 'PlayMaker'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_PLAYMAKER);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_AdventureCreator, "More information about 'Adventure Creator'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_ADVENTURE_CREATOR);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_CinemaDirector, "More information about 'Cinema Director'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_CINEMA_DIRECTOR);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_DialogueSystem, "More information about 'Dialogue System'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_DIALOGUE_SYSTEM);
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_LDC, "More information about 'Localized Dialogs'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_LOCALIZED_DIALOGS);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_LipSync, "More information about 'LipSync'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_LIPSYNC);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_NPC_Chat, "More information about 'NPC Chat'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_NPC_CHAT);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_QuestSystem, "More information about 'Quest System'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_QUEST_SYSTEM);
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_SALSA, "More information about 'SALSA'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_SALSA);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_SLATE, "More information about 'SLATE'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_SLATE);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_Amplitude, "More information about 'Amplitude'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_AMPLITUDE);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_Klattersynth, "More information about 'Klattersynth'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_KLATTERSYNTH);
}
GUILayout.EndHorizontal();
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_WebGL, "More information about 'WebGL Speech Synthesis'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_WEBGL);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Store_Google, "More information about 'Google Cloud Text To Speech'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_GOOGLE);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Asset_VolumetricAudio, "More information about 'Volumetric Audio'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_VOLUMETRIC_AUDIO);
//CT Ads
switch (adRnd1)
{
case 0:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_BWF, "More information about 'Bad Word Filter'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_BWF);
break;
}
case 1:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_DJ, "More information about 'DJ'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_DJ);
break;
}
case 2:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_FB, "More information about 'File Browser'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_FB);
break;
}
case 3:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_Radio, "More information about 'Radio'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_RADIO);
break;
}
case 4:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_TB, "More information about 'Turbo Backup'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_TB);
break;
}
case 5:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_TPS, "More information about 'Turbo Switch'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_TPS);
break;
}
case 6:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_TPB, "More information about 'Turbo Builder'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_TPB);
break;
}
case 7:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_OC, "More information about 'Online Check'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_OC);
break;
}
default:
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset_TR, "More information about 'True Random'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_TR);
break;
}
}
}
GUILayout.EndHorizontal();
GUILayout.Space(6);
if (GUILayout.Button(new GUIContent(" All Supported Assets", EditorHelper.Icon_3p_Assets, "More information about the all supported assets.")))
Util.Helper.OpenURL(Util.Constants.ASSET_3P_URL);
}
EditorGUILayout.EndScrollView();
GUILayout.Space(6);
}
protected void showAbout()
{
EditorHelper.BannerOC();
GUILayout.Space(3);
GUILayout.Label(Util.Constants.ASSET_NAME, EditorStyles.boldLabel);
GUILayout.BeginHorizontal();
{
GUILayout.BeginVertical(GUILayout.Width(60));
{
GUILayout.Label("Version:");
GUILayout.Space(12);
GUILayout.Label("Web:");
GUILayout.Space(2);
GUILayout.Label("Email:");
}
GUILayout.EndVertical();
GUILayout.BeginVertical(GUILayout.Width(170));
{
GUILayout.Space(0);
GUILayout.Label(Util.Constants.ASSET_VERSION);
GUILayout.Space(12);
EditorGUILayout.SelectableLabel(Util.Constants.ASSET_AUTHOR_URL, GUILayout.Height(16), GUILayout.ExpandHeight(false));
GUILayout.Space(2);
EditorGUILayout.SelectableLabel(Util.Constants.ASSET_CONTACT, GUILayout.Height(16), GUILayout.ExpandHeight(false));
}
GUILayout.EndVertical();
GUILayout.BeginVertical(GUILayout.ExpandWidth(true));
{
//GUILayout.Space(0);
}
GUILayout.EndVertical();
GUILayout.BeginVertical(GUILayout.Width(64));
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Logo_Asset, "Visit asset website")))
Util.Helper.OpenURL(EditorConstants.ASSET_URL);
}
GUILayout.EndVertical();
}
GUILayout.EndHorizontal();
GUILayout.Label("© 2015-2020 by " + Util.Constants.ASSET_AUTHOR);
EditorHelper.SeparatorUI();
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(" AssetStore", EditorHelper.Logo_Unity, "Visit the 'Unity AssetStore' website.")))
Util.Helper.OpenURL(Util.Constants.ASSET_CT_URL);
if (GUILayout.Button(new GUIContent(" " + Util.Constants.ASSET_AUTHOR, EditorHelper.Logo_CT, "Visit the '" + Util.Constants.ASSET_AUTHOR + "' website.")))
Util.Helper.OpenURL(Util.Constants.ASSET_AUTHOR_URL);
}
GUILayout.EndHorizontal();
EditorHelper.SeparatorUI();
aboutTab = GUILayout.Toolbar(aboutTab, new[] {"Readme", "Versions", "SSML", "EML", "Update"});
switch (aboutTab)
{
case 4:
{
scrollPosAboutUpdate = EditorGUILayout.BeginScrollView(scrollPosAboutUpdate, false, false);
{
Color fgColor = GUI.color;
GUI.color = Color.yellow;
switch (updateStatus)
{
case UpdateStatus.NO_UPDATE:
GUI.color = Color.green;
GUILayout.Label(updateText);
break;
case UpdateStatus.UPDATE:
{
GUILayout.Label(updateText);
if (GUILayout.Button(new GUIContent(" Download", "Visit the 'Unity AssetStore' to download the latest version.")))
{
UnityEditorInternal.AssetStore.Open("content/" + EditorConstants.ASSET_ID);
}
break;
}
case UpdateStatus.UPDATE_VERSION:
{
GUILayout.Label(updateText);
if (GUILayout.Button(new GUIContent(" Upgrade", "Upgrade to the newer version in the 'Unity AssetStore'")))
Util.Helper.OpenURL(Util.Constants.ASSET_CT_URL);
break;
}
case UpdateStatus.DEPRECATED:
{
GUILayout.Label(updateText);
if (GUILayout.Button(new GUIContent(" More Information", "Visit the 'crosstales'-site for more information.")))
Util.Helper.OpenURL(Util.Constants.ASSET_AUTHOR_URL);
break;
}
default:
GUI.color = Color.cyan;
GUILayout.Label(updateText);
break;
}
GUI.color = fgColor;
}
EditorGUILayout.EndScrollView();
if (updateStatus == UpdateStatus.NOT_CHECKED || updateStatus == UpdateStatus.NO_UPDATE)
{
bool isChecking = !(worker == null || worker?.IsAlive == false);
GUI.enabled = Util.Helper.isInternetAvailable && !isChecking;
if (GUILayout.Button(new GUIContent(isChecking ? "Checking... Please wait." : " Check For Update", EditorHelper.Icon_Check, "Checks for available updates of " + Util.Constants.ASSET_NAME)))
{
worker = new System.Threading.Thread(() => UpdateCheck.UpdateCheckForEditor(out updateText, out updateStatus));
worker.Start();
}
GUI.enabled = true;
}
break;
}
case 0:
{
if (readme == null)
{
string path = Application.dataPath + EditorConfig.ASSET_PATH + "README.txt";
try
{
readme = verifyTextLength(System.IO.File.ReadAllText(path));
}
catch (System.Exception)
{
readme = "README not found: " + path;
}
}
scrollPosAboutReadme = EditorGUILayout.BeginScrollView(scrollPosAboutReadme, false, false);
{
GUILayout.Label(readme);
}
EditorGUILayout.EndScrollView();
break;
}
case 1:
{
if (versions == null)
{
string path = Application.dataPath + EditorConfig.ASSET_PATH + "Documentation/VERSIONS.txt";
try
{
versions = verifyTextLength(System.IO.File.ReadAllText(path));
}
catch (System.Exception)
{
versions = "VERSIONS not found: " + path;
}
}
scrollPosAboutVersions = EditorGUILayout.BeginScrollView(scrollPosAboutVersions, false, false);
{
GUILayout.Label(versions);
}
EditorGUILayout.EndScrollView();
break;
}
case 2:
{
if (ssml == null)
{
string path = Application.dataPath + EditorConfig.ASSET_PATH + "Documentation/SSML.txt";
try
{
ssml = verifyTextLength(System.IO.File.ReadAllText(path));
}
catch (System.Exception)
{
ssml = "SSML not found: " + path;
}
}
scrollPosAboutVersions = EditorGUILayout.BeginScrollView(scrollPosAboutVersions, false, false);
{
GUILayout.Label(ssml);
}
EditorGUILayout.EndScrollView();
break;
}
default:
{
if (emotionml == null)
{
string path = Application.dataPath + EditorConfig.ASSET_PATH + "Documentation/EMOTIONML.txt";
try
{
emotionml = verifyTextLength(System.IO.File.ReadAllText(path));
}
catch (System.Exception)
{
emotionml = "EmotionML not found: " + path;
}
}
scrollPosAboutVersions = EditorGUILayout.BeginScrollView(scrollPosAboutVersions, false, false);
{
GUILayout.Label(emotionml);
}
EditorGUILayout.EndScrollView();
break;
}
}
EditorHelper.SeparatorUI();
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Social_Discord, "Communicate with us via 'Discord'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_SOCIAL_DISCORD);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Social_Facebook, "Follow us on 'Facebook'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_SOCIAL_FACEBOOK);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Social_Twitter, "Follow us on 'Twitter'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_SOCIAL_TWITTER);
if (GUILayout.Button(new GUIContent(string.Empty, EditorHelper.Social_Linkedin, "Follow us on 'LinkedIn'.")))
Util.Helper.OpenURL(Util.Constants.ASSET_SOCIAL_LINKEDIN);
}
GUILayout.EndHorizontal();
GUILayout.Space(6);
}
private static string verifyTextLength(string text)
{
string result = text;
if (text.Length > maxChars)
{
result = text.Substring(0, maxChars) + "..." + System.Environment.NewLine + "<--- Content truncated --->";
}
return result;
}
protected static void save()
{
Util.Config.Save();
EditorConfig.Save();
if (Util.Config.DEBUG)
Debug.Log("Config data saved");
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,77 @@
#if UNITY_EDITOR && !UNITY_2019_1_OR_NEWER
using UnityEditor;
using UnityEngine;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorIntegration
{
/// <summary>Unity "Preferences" extension.</summary>
public class ConfigPreferences : ConfigBase
{
#region Variables
private static int tab;
private static int lastTab;
private static ConfigPreferences cp;
#endregion
#region Static methods
[PreferenceItem(Util.Constants.ASSET_NAME_SHORT)]
private static void PreferencesGUI()
{
if (cp == null)
{
cp = CreateInstance(typeof(ConfigPreferences)) as ConfigPreferences;
}
tab = GUILayout.Toolbar(tab, new[] {"Configuration", "Help", "About"});
if (tab != lastTab)
{
lastTab = tab;
GUI.FocusControl(null);
}
switch (tab)
{
case 0:
{
cp.showConfiguration();
EditorHelper.SeparatorUI();
if (GUILayout.Button(new GUIContent(" Reset", EditorHelper.Icon_Reset, "Resets the configuration settings for this project.")))
{
if (EditorUtility.DisplayDialog("Reset configuration?", "Reset the configuration of " + Util.Constants.ASSET_NAME + "?", "Yes", "No"))
{
Util.Config.Reset();
EditorConfig.Reset();
save();
}
}
GUILayout.Space(6);
break;
}
case 1:
cp.showHelp();
break;
default:
cp.showAbout();
break;
}
if (GUI.changed)
{
save();
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,349 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorIntegration
{
/// <summary>Editor window extension.</summary>
[InitializeOnLoad]
public class ConfigWindow : ConfigBase
{
#region Variables
private int tab;
private int lastTab;
private string text = "Test all your voices with different texts and settings.";
private int voiceIndex;
private float rate = 1f;
private float pitch = 1f;
private float volume = 1f;
private bool silenced = true;
private Vector2 scrollPosPrefabs;
private Vector2 scrollPosTD;
public delegate void StopPlayback();
public static event StopPlayback OnStopPlayback;
#endregion
#region Static constructor
static ConfigWindow()
{
EditorApplication.update += onEditorUpdate;
}
#endregion
#region EditorWindow methods
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Configuration...", false, EditorHelper.MENU_ID + 1)]
public static void ShowWindow()
{
GetWindow(typeof(ConfigWindow));
}
public static void ShowWindow(int tab)
{
ConfigWindow window = GetWindow(typeof(ConfigWindow)) as ConfigWindow;
if (window != null) window.tab = tab;
}
public void OnEnable()
{
titleContent = new GUIContent(Util.Constants.ASSET_NAME_SHORT, EditorHelper.Logo_Asset_Small);
OnStopPlayback += silence;
}
public void OnDisable()
{
//Speaker.Instance.Silence();
OnStopPlayback -= silence;
}
public void OnGUI()
{
tab = GUILayout.Toolbar(tab, new[] {"Config", "Prefabs", "TD", "Help", "About"});
if (tab != lastTab)
{
lastTab = tab;
GUI.FocusControl(null);
}
switch (tab)
{
case 0:
{
showConfiguration();
EditorHelper.SeparatorUI();
GUILayout.BeginHorizontal();
{
if (GUILayout.Button(new GUIContent(" Save", EditorHelper.Icon_Save, "Saves the configuration settings for this project.")))
{
save();
}
if (GUILayout.Button(new GUIContent(" Reset", EditorHelper.Icon_Reset, "Resets the configuration settings for this project.")))
{
if (EditorUtility.DisplayDialog("Reset configuration?", "Reset the configuration of " + Util.Constants.ASSET_NAME + "?", "Yes", "No"))
{
Util.Config.Reset();
EditorConfig.Reset();
save();
}
}
}
GUILayout.EndHorizontal();
GUILayout.Space(6);
break;
}
case 1:
showPrefabs();
break;
case 2:
showTestDrive();
break;
case 3:
showHelp();
break;
default:
showAbout();
break;
}
}
public void OnInspectorUpdate()
{
Repaint();
}
#endregion
#region Private methods
private static void onEditorUpdate()
{
if (EditorApplication.isCompiling || EditorApplication.isPlaying || BuildPipeline.isBuildingPlayer)
{
onStopPlayback();
}
}
private static void onStopPlayback()
{
OnStopPlayback?.Invoke();
}
private void silence()
{
if (!silenced)
{
Speaker.Instance.Silence();
silenced = true;
}
}
private void showPrefabs()
{
EditorHelper.BannerOC();
scrollPosPrefabs = EditorGUILayout.BeginScrollView(scrollPosPrefabs, false, false);
{
//GUILayout.Space(8);
GUILayout.Label("Available Prefabs", EditorStyles.boldLabel);
GUILayout.Space(6);
//EditorHelper.SeparatorUI (6);
GUI.enabled = !EditorHelper.isRTVoiceInScene;
GUILayout.Label(Util.Constants.RTVOICE_SCENE_OBJECT_NAME);
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds the '" + Util.Constants.RTVOICE_SCENE_OBJECT_NAME + "'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab(Util.Constants.RTVOICE_SCENE_OBJECT_NAME);
}
GUI.enabled = true;
EditorHelper.SeparatorUI();
GUI.enabled = !EditorHelper.isGlobalCacheInScene;
GUILayout.Label(Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME);
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a '" + Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME + "'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab(Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME);
}
GUI.enabled = true;
EditorHelper.SeparatorUI();
GUILayout.Label("AudioFileGenerator");
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a 'AudioFileGenerator'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab("AudioFileGenerator");
}
GUILayout.Space(6);
GUILayout.Label("Paralanguage");
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a 'Paralanguage'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab("Paralanguage");
}
GUILayout.Space(6);
GUILayout.Label("Sequencer");
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a 'Sequencer'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab("Sequencer");
}
GUILayout.Space(6);
GUILayout.Label("SpeechText");
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a 'SpeechText'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab("SpeechText");
}
GUILayout.Space(6);
GUILayout.Label("TextFileSpeaker");
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a 'TextFileSpeaker'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab("TextFileSpeaker");
}
EditorHelper.SeparatorUI();
GUILayout.Label("Loudspeaker");
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a 'Loudspeaker'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab("Loudspeaker");
}
EditorHelper.SeparatorUI();
GUILayout.Label("VoiceInitializer");
if (GUILayout.Button(new GUIContent(" Add", EditorHelper.Icon_Plus, "Adds a 'VoiceInitializer'-prefab to the scene.")))
{
EditorHelper.InstantiatePrefab("VoiceInitializer");
}
GUILayout.Space(6);
}
EditorGUILayout.EndScrollView();
}
private void showTestDrive()
{
EditorHelper.BannerOC();
GUILayout.Space(3);
GUILayout.Label("Test-Drive", EditorStyles.boldLabel);
if (Util.Helper.isEditorMode)
{
if (EditorHelper.isRTVoiceInScene)
{
if (Speaker.Instance != null && Speaker.Instance.isWorkingInEditor)
{
if (Speaker.Instance.Voices.Count > 0 && EditorHelper.isRTVoiceInScene)
{
scrollPosTD = EditorGUILayout.BeginScrollView(scrollPosTD, false, false);
{
if (Speaker.Instance.isWorkingInEditor)
{
GUI.enabled = !Speaker.Instance.isSpeaking;
text = EditorGUILayout.TextField("Text: ", text);
voiceIndex = EditorGUILayout.Popup("Voice", voiceIndex, Speaker.Instance.Voices.CTToString().ToArray());
rate = EditorGUILayout.Slider("Rate", rate, 0f, 3f);
if (Util.Helper.isWindowsPlatform)
{
pitch = EditorGUILayout.Slider("Pitch", pitch, 0f, 2f);
volume = EditorGUILayout.Slider("Volume", volume, 0f, 1f);
}
GUI.enabled = true;
}
else
{
EditorGUILayout.HelpBox("Test-Drive is not supported for the current TTS-system.", MessageType.Info);
}
}
EditorGUILayout.EndScrollView();
EditorHelper.SeparatorUI();
if (Speaker.Instance.isSpeaking)
{
if (GUILayout.Button(new GUIContent(" Silence", EditorHelper.Icon_Silence, "Silence all active speakers.")))
{
silence();
}
}
else
{
if (GUILayout.Button(new GUIContent(" Speak", EditorHelper.Icon_Speak, "Speaks the text with the selected voice and settings.")))
{
Speaker.Instance.SpeakNative(text, Speaker.Instance.Voices[voiceIndex], rate, pitch, volume);
silenced = false;
}
}
GUILayout.Space(6);
}
else
{
EditorHelper.NoVoicesUI();
}
}
else
{
EditorGUILayout.HelpBox("Test-Drive is not supported for the current TTS-system.", MessageType.Info);
}
}
else
{
EditorHelper.RTVUnavailable();
}
}
else
{
EditorGUILayout.HelpBox("Disabled in Play-mode!", MessageType.Info);
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,78 @@
#if UNITY_EDITOR
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorIntegration
{
/// <summary>Editor component for the "Hierarchy"-menu.</summary>
public static class RTVoiceGameObject
{
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/" + Util.Constants.RTVOICE_SCENE_OBJECT_NAME, false, EditorHelper.GO_ID)]
private static void AddRTVoice()
{
EditorHelper.InstantiatePrefab(Util.Constants.RTVOICE_SCENE_OBJECT_NAME);
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/" + Util.Constants.RTVOICE_SCENE_OBJECT_NAME, true)]
private static bool AddRTVoiceValidator()
{
return !EditorHelper.isRTVoiceInScene;
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/" + Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME, false, EditorHelper.GO_ID + 1)]
private static void AddGlobalCache()
{
EditorHelper.InstantiatePrefab(Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME);
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/" + Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME, true)]
private static bool AddGlobalCacheValidator()
{
return !EditorHelper.isGlobalCacheInScene;
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/AudioFileGenerator", false, EditorHelper.GO_ID + 2)]
private static void AddAudioFileGenerator()
{
EditorHelper.InstantiatePrefab("AudioFileGenerator");
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/Paralanguage", false, EditorHelper.GO_ID + 3)]
private static void AddParalanguage()
{
EditorHelper.InstantiatePrefab("Paralanguage");
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/Sequencer", false, EditorHelper.GO_ID + 4)]
private static void AddSequencer()
{
EditorHelper.InstantiatePrefab("Sequencer");
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/SpeechText", false, EditorHelper.GO_ID + 5)]
private static void AddSpeechText()
{
EditorHelper.InstantiatePrefab("SpeechText");
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/TextFileSpeaker", false, EditorHelper.GO_ID + 6)]
private static void AddTextFileSpeaker()
{
EditorHelper.InstantiatePrefab("TextFileSpeaker");
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/Loudspeaker", false, EditorHelper.GO_ID + 7)]
private static void AddLoudspeaker()
{
EditorHelper.InstantiatePrefab("Loudspeaker");
}
[MenuItem("GameObject/" + Util.Constants.ASSET_NAME + "/VoiceInitializer", false, EditorHelper.GO_ID + 8)]
private static void AddVoiceInitializer()
{
EditorHelper.InstantiatePrefab("VoiceInitializer");
}
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,152 @@
#if UNITY_EDITOR
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorIntegration
{
/// <summary>Editor component for the "Tools"-menu.</summary>
public static class RTVoiceMenu
{
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/" + Util.Constants.RTVOICE_SCENE_OBJECT_NAME, false, EditorHelper.MENU_ID + 20)]
private static void AddRTVoice()
{
EditorHelper.InstantiatePrefab(Util.Constants.RTVOICE_SCENE_OBJECT_NAME);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/" + Util.Constants.RTVOICE_SCENE_OBJECT_NAME, true)]
private static bool AddRTVoiceValidator()
{
return !EditorHelper.isRTVoiceInScene;
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/" + Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME, false, EditorHelper.MENU_ID + 40)]
private static void AddGlobalCache()
{
EditorHelper.InstantiatePrefab(Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/" + Util.Constants.GLOBALCACHE_SCENE_OBJECT_NAME, true)]
private static bool AddGlobalCacheValidator()
{
return !EditorHelper.isGlobalCacheInScene;
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/AudioFileGenerator", false, EditorHelper.MENU_ID + 60)]
private static void AddAudioFileGenerator()
{
EditorHelper.InstantiatePrefab("AudioFileGenerator");
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/Paralanguage", false, EditorHelper.MENU_ID + 70)]
private static void AddParalanguage()
{
EditorHelper.InstantiatePrefab("Paralanguage");
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/Sequencer", false, EditorHelper.MENU_ID + 80)]
private static void AddSequencer()
{
EditorHelper.InstantiatePrefab("Sequencer");
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/SpeechText", false, EditorHelper.MENU_ID + 90)]
private static void AddSpeechText()
{
EditorHelper.InstantiatePrefab("SpeechText");
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/TextFileSpeaker", false, EditorHelper.MENU_ID + 100)]
private static void AddTextFileSpeaker()
{
EditorHelper.InstantiatePrefab("TextFileSpeaker");
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/Loudspeaker", false, EditorHelper.MENU_ID + 120)]
private static void AddLoudspeaker()
{
EditorHelper.InstantiatePrefab("Loudspeaker");
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Prefabs/VoiceInitializer", false, EditorHelper.MENU_ID + 140)]
private static void AddVoiceInitializer()
{
EditorHelper.InstantiatePrefab("VoiceInitializer");
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/Manual", false, EditorHelper.MENU_ID + 600)]
private static void ShowManual()
{
Util.Helper.OpenURL(Util.Constants.ASSET_MANUAL_URL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/API", false, EditorHelper.MENU_ID + 610)]
private static void ShowAPI()
{
Util.Helper.OpenURL(Util.Constants.ASSET_API_URL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/Forum", false, EditorHelper.MENU_ID + 620)]
private static void ShowForum()
{
Util.Helper.OpenURL(Util.Constants.ASSET_FORUM_URL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/Product", false, EditorHelper.MENU_ID + 630)]
private static void ShowProduct()
{
Util.Helper.OpenURL(Util.Constants.ASSET_WEB_URL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/Videos/Promo", false, EditorHelper.MENU_ID + 650)]
private static void ShowVideoPromo()
{
Util.Helper.OpenURL(Util.Constants.ASSET_VIDEO_PROMO);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/Videos/Tutorial", false, EditorHelper.MENU_ID + 660)]
private static void ShowVideoTutorial()
{
Util.Helper.OpenURL(Util.Constants.ASSET_VIDEO_TUTORIAL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/Videos/All Videos", false, EditorHelper.MENU_ID + 680)]
private static void ShowAllVideos()
{
Util.Helper.OpenURL(Util.Constants.ASSET_SOCIAL_YOUTUBE);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/Help/3rd Party Assets", false, EditorHelper.MENU_ID + 700)]
private static void Show3rdPartyAV()
{
Util.Helper.OpenURL(Util.Constants.ASSET_3P_URL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/About/Unity AssetStore", false, EditorHelper.MENU_ID + 800)]
private static void ShowUAS()
{
Util.Helper.OpenURL(EditorConstants.ASSET_URL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/About/" + Util.Constants.ASSET_AUTHOR, false, EditorHelper.MENU_ID + 820)]
private static void ShowCT()
{
Util.Helper.OpenURL(Util.Constants.ASSET_AUTHOR_URL);
}
[MenuItem("Tools/" + Util.Constants.ASSET_NAME + "/About/Info", false, EditorHelper.MENU_ID + 840)]
private static void ShowInfo()
{
EditorUtility.DisplayDialog(Util.Constants.ASSET_NAME + " - About",
"Version: " + Util.Constants.ASSET_VERSION +
System.Environment.NewLine +
System.Environment.NewLine +
"© 2015-2020 by " + Util.Constants.ASSET_AUTHOR +
System.Environment.NewLine +
System.Environment.NewLine +
Util.Constants.ASSET_AUTHOR_URL +
System.Environment.NewLine, "Ok");
}
}
}
#endif
// © 2015-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,29 @@
#if UNITY_EDITOR
using UnityEditor;
namespace Crosstales.RTVoice.EditorTask
{
/// <summary>Loads the configuration at startup.</summary>
[InitializeOnLoad]
public static class AAAConfigLoader
{
#region Constructor
static AAAConfigLoader()
{
//UnityEngine.Debug.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
if (!Util.Config.isLoaded)
{
Util.Config.Load();
if (Util.Config.DEBUG)
UnityEngine.Debug.Log("Config data loaded");
}
}
#endregion
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,51 @@
#if UNITY_EDITOR
using UnityEditor;
using UnityEngine.SceneManagement;
using UnityEditor.SceneManagement;
namespace Crosstales.RTVoice.EditorTask
{
/// <summary>Automatically adds the necessary prefabs to the current scene.</summary>
[InitializeOnLoad]
public class AutoInitialize
{
#region Variables
private static Scene currentScene;
#endregion
#region Constructor
static AutoInitialize()
{
//UnityEngine.Debug.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
EditorApplication.hierarchyChanged += hierarchyWindowChanged;
}
#endregion
#region Private static methods
private static void hierarchyWindowChanged()
{
if (currentScene != EditorSceneManager.GetActiveScene())
{
if (EditorUtil.EditorConfig.PREFAB_AUTOLOAD)
{
if (!EditorUtil.EditorHelper.isRTVoiceInScene)
EditorUtil.EditorHelper.InstantiatePrefab(Util.Constants.RTVOICE_SCENE_OBJECT_NAME);
}
currentScene = EditorSceneManager.GetActiveScene();
}
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,26 @@
#if UNITY_EDITOR
using UnityEditor;
namespace Crosstales.RTVoice.EditorTask
{
/// <summary>Adds the given define symbols to PlayerSettings define symbols.</summary>
[InitializeOnLoad]
public class CompileDefines : Common.EditorTask.BaseCompileDefines
{
private const string symbol = "CT_RTV";
static CompileDefines()
{
if (EditorUtil.EditorConfig.COMPILE_DEFINES)
{
addSymbolsToAllTargets(symbol);
}
else
{
removeSymbolsFromAllTargets(symbol);
}
}
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,23 @@
#if UNITY_EDITOR
using UnityEditor;
using Enumerable = System.Linq.Enumerable;
namespace Crosstales.RTVoice.EditorTask
{
/// <summary>Show the configuration window on the first launch.</summary>
public class Launch : AssetPostprocessor
{
public static void OnPostprocessAllAssets(string[] importedAssets, string[] deletedAssets, string[] movedAssets, string[] movedFromAssetPaths)
{
if (Enumerable.Any(importedAssets, str => str.Contains(EditorUtil.EditorConstants.ASSET_UID.ToString())))
{
Common.EditorTask.SetupResources.Setup();
SetupResources.Setup();
EditorIntegration.ConfigWindow.ShowWindow(4);
}
}
}
}
#endif
// © 2017-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,44 @@
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
namespace Crosstales.RTVoice.EditorTask
{
/// <summary>Moves all needed resources to 'Editor Default Resources'.</summary>
[InitializeOnLoad]
public class SetupResources : Common.EditorTask.BaseSetupResources
{
#region Constructor
static SetupResources()
{
Setup();
}
#endregion
#region Public methods
public static void Setup()
{
#if !CT_DEVELOP
string path = Application.dataPath;
string assetpath = "Assets" + EditorUtil.EditorConfig.ASSET_PATH;
string sourceFolder = path + EditorUtil.EditorConfig.ASSET_PATH + "Icons/";
string source = assetpath + "Icons/";
string targetFolder = path + "/Editor Default Resources/crosstales/RTVoice/";
string target = "Assets/Editor Default Resources/crosstales/RTVoice/";
string metafile = assetpath + "Icons.meta";
setupResources(source, sourceFolder, target, targetFolder, metafile);
#endif
}
#endregion
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

View File

@ -0,0 +1,394 @@
using System.Linq;
#if UNITY_EDITOR
using UnityEngine;
using UnityEditor;
using Crosstales.RTVoice.EditorUtil;
namespace Crosstales.RTVoice.EditorTask
{
/// <summary>Checks for updates of the asset.</summary>
[InitializeOnLoad]
public static class UpdateCheck
{
#region Variables
public const string TEXT_NOT_CHECKED = "Not checked.";
public const string TEXT_NO_UPDATE = "No update available - you are using the latest version.";
private static UpdateStatus status = UpdateStatus.NOT_CHECKED;
private static readonly char[] splitChar = {';'};
#endregion
#region Constructor
static UpdateCheck()
{
//Debug.Log(System.Reflection.MethodBase.GetCurrentMethod().DeclaringType.Name);
if (EditorConfig.UPDATE_CHECK)
{
if (Util.Config.DEBUG)
Debug.Log("Updater enabled!");
string lastDate = EditorPrefs.GetString(EditorConstants.KEY_UPDATE_DATE);
string date = System.DateTime.Now.ToString("yyyyMMdd"); // every day
//string date = System.DateTime.Now.ToString("yyyyMMddHHmm"); // every minute (for tests)
if (Util.Constants.DEV_DEBUG)
Debug.Log("Last check: " + lastDate);
if (!date.Equals(lastDate))
{
if (Util.Helper.isInternetAvailable)
{
if (Util.Config.DEBUG)
Debug.Log("Checking for update...");
//new System.Threading.Thread(() => updateCheck()).Start();
updateCheck();
EditorPrefs.SetString(EditorConstants.KEY_UPDATE_DATE, date);
}
else
{
if (Util.Config.DEBUG)
Debug.Log("No Internet available!");
}
}
else
{
if (Util.Config.DEBUG)
Debug.Log("No update check needed.");
}
}
else
{
if (Util.Config.DEBUG)
Debug.Log("Updater disabled!");
}
}
#endregion
#region Static methods
public static void UpdateCheckForEditor(out string result, out UpdateStatus st)
{
string[] data = readData();
updateStatus(data);
switch (status)
{
case UpdateStatus.UPDATE:
result = updateTextForEditor(data);
break;
case UpdateStatus.UPDATE_VERSION:
result = updateVersionTextForEditor(data);
break;
case UpdateStatus.DEPRECATED:
result = deprecatedTextForEditor(data);
break;
default:
result = TEXT_NO_UPDATE;
break;
}
st = status;
}
#endregion
#region Private methods
private static void updateCheck()
{
string[] data = readData();
updateStatus(data);
switch (status)
{
case UpdateStatus.UPDATE:
{
int option = EditorUtility.DisplayDialogComplex(Util.Constants.ASSET_NAME + " - Update available",
updateText(data),
"Yes, let's do it!",
"Not right now",
"Don't check again!");
switch (option)
{
case 0:
Util.Helper.OpenURL(EditorConstants.ASSET_URL);
//UnityEditorInternal.AssetStore.Open("content/" + EditorConstants.ASSET_ID);
break;
case 1:
// do nothing!
break;
default:
EditorConfig.UPDATE_CHECK = false;
EditorConfig.Save();
break;
}
break;
}
case UpdateStatus.UPDATE_VERSION:
{
int option = EditorUtility.DisplayDialogComplex(Util.Constants.ASSET_NAME + " - Upgrade needed",
updateVersionText(data),
"Yes, let's do it!",
"Not right now",
"Don't ask again!");
switch (option)
{
case 0:
Util.Helper.OpenURL(EditorConstants.ASSET_URL);
break;
case 1:
// do nothing!
break;
default:
EditorConfig.UPDATE_CHECK = false;
EditorConfig.Save();
break;
}
break;
}
case UpdateStatus.DEPRECATED:
{
int option = EditorUtility.DisplayDialogComplex(Util.Constants.ASSET_NAME + " - Upgrade needed",
deprecatedText(data),
"Learn more",
"Not right now",
"Don't bother me again!");
switch (option)
{
case 0:
Util.Helper.OpenURL(Util.Constants.ASSET_AUTHOR_URL);
break;
case 1:
// do nothing!
break;
default:
EditorConfig.UPDATE_CHECK = false;
EditorConfig.Save();
break;
}
break;
}
default:
{
if (Util.Config.DEBUG)
Debug.Log("Asset is up-to-date.");
break;
}
}
}
private static string updateText(string[] data)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (data != null)
{
sb.Append("Your version:\t");
sb.Append(Util.Constants.ASSET_VERSION);
sb.Append(System.Environment.NewLine);
sb.Append("New version:\t");
sb.Append(data[2]);
sb.Append(System.Environment.NewLine);
sb.Append(System.Environment.NewLine);
sb.AppendLine("Please download the new version from the Unity AssetStore!");
}
return sb.ToString();
}
private static string updateVersionText(string[] data) //TODO remove in the future
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (data != null)
{
sb.Append(Util.Constants.ASSET_NAME);
sb.Append(" is deprecated in favor of an newer version!");
sb.Append(System.Environment.NewLine);
sb.Append(System.Environment.NewLine);
sb.AppendLine("Please consider an upgrade in the Unity AssetStore.");
}
return sb.ToString();
}
private static string deprecatedText(string[] data)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (data != null)
{
sb.Append(Util.Constants.ASSET_NAME);
sb.Append(" is deprecated!");
sb.Append(System.Environment.NewLine);
sb.Append(System.Environment.NewLine);
sb.AppendLine("Please check the link for more information:");
sb.AppendLine(Util.Constants.ASSET_AUTHOR_URL);
}
return sb.ToString();
}
private static string[] readData()
{
string[] data = null;
try
{
System.Net.ServicePointManager.ServerCertificateValidationCallback = Util.Helper.RemoteCertificateValidationCallback;
using (System.Net.WebClient client = new Common.Util.CTWebClient())
{
string content = client.DownloadString(Util.Constants.ASSET_UPDATE_CHECK_URL);
foreach (string line in Util.Helper.SplitStringToLines(content).Where(line => line.CTStartsWith(EditorConstants.ASSET_UID.ToString())))
{
data = line.Split(splitChar, System.StringSplitOptions.RemoveEmptyEntries);
//Debug.Log("data: " + data.CTDump());
if (data.Length >= 3)
{
//valid record?
break;
}
//Debug.LogWarning("invalid data: " + data.Length);
data = null;
}
}
}
catch (System.Exception ex)
{
Debug.LogError("Could not load update file: " + System.Environment.NewLine + ex);
}
return data;
}
private static void updateStatus(string[] data)
{
if (data != null)
{
if (int.TryParse(data[1], out int buildNumber))
{
if (buildNumber > Util.Constants.ASSET_BUILD)
{
status = UpdateStatus.UPDATE;
}
else
switch (buildNumber)
{
case -200:
status = UpdateStatus.UPDATE_VERSION;
break;
case -900:
status = UpdateStatus.DEPRECATED;
break;
default:
status = UpdateStatus.NO_UPDATE;
break;
}
}
if (Util.Config.DEBUG)
Debug.Log("buildNumber: " + buildNumber);
}
else
{
if (Util.Config.DEBUG)
Debug.LogWarning("data is null!");
}
}
private static string updateTextForEditor(string[] data)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (data != null)
{
sb.AppendLine("Update found!");
sb.Append(System.Environment.NewLine);
sb.Append("Your version:\t");
sb.Append(Util.Constants.ASSET_VERSION);
sb.Append(System.Environment.NewLine);
sb.Append("New version:\t");
sb.Append(data[2]);
sb.Append(System.Environment.NewLine);
sb.Append(System.Environment.NewLine);
sb.AppendLine("Please download the new version from the Unity AssetStore.");
}
return sb.ToString();
}
private static string updateVersionTextForEditor(string[] data) //TODO remove in the future
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (data != null)
{
sb.Append(Util.Constants.ASSET_NAME);
sb.Append(" is deprecated in favor of an newer version!");
sb.Append(System.Environment.NewLine);
sb.Append(System.Environment.NewLine);
sb.AppendLine("Please consider an upgrade in the Unity AssetStore.");
}
return sb.ToString();
}
private static string deprecatedTextForEditor(string[] data)
{
System.Text.StringBuilder sb = new System.Text.StringBuilder();
if (data != null)
{
sb.Append(Util.Constants.ASSET_NAME);
sb.Append(" is deprecated!");
sb.Append(System.Environment.NewLine);
sb.Append(System.Environment.NewLine);
sb.AppendLine("Please click below for more information.");
}
return sb.ToString();
}
#endregion
}
/// <summary>All possible update stati.</summary>
public enum UpdateStatus
{
NOT_CHECKED,
NO_UPDATE,
UPDATE,
UPDATE_VERSION,
DEPRECATED
}
}
#endif
// © 2016-2020 crosstales LLC (https://www.crosstales.com)

Some files were not shown because too many files have changed in this diff Show More