Compare commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
c95f6b7c70 | ||
|
|
74ba5790f9 | ||
|
|
16cd2fd26b | ||
|
|
191efae2dd | ||
|
|
431d128ad8 | ||
|
|
573aa2ff4c | ||
|
|
94637d5980 | ||
|
|
fa5a9961a8 | ||
|
|
21d54a8a1a | ||
|
|
1f340ced78 | ||
|
|
99c16f44e6 | ||
|
|
ce213460f9 | ||
|
|
fb75ff5318 | ||
|
|
a149a7c08e | ||
|
|
fb4da81ce2 | ||
|
|
71b6155946 | ||
|
|
46821d34a2 | ||
|
|
08b92e7e9b | ||
|
|
2c9440f656 | ||
|
|
7822584cdd | ||
|
|
df936c4e04 | ||
|
|
27d18d7d01 | ||
|
|
dc8f8ceb80 | ||
|
|
9e2e778e12 | ||
|
|
ae58f4d461 | ||
|
|
3c64109090 | ||
|
|
158fab27ab | ||
|
|
9552fed2e0 | ||
|
|
e3059fc1c2 | ||
|
|
d1c84d0a8a | ||
|
|
195893a1b0 | ||
|
|
89b5275efd | ||
|
|
3bcb3ee83e | ||
|
|
341d386196 | ||
|
|
96c48d3cb3 | ||
|
|
889ec8244e | ||
|
|
fc7ef017d0 | ||
|
|
9b1bb3d9ba | ||
|
|
4d5bc8f080 | ||
|
|
6154504fee | ||
|
|
7356f21ab2 | ||
|
|
0b5904f7cc | ||
|
|
af5a4f2aa8 | ||
|
|
ccdf2c63f2 | ||
|
|
adc9613592 |
No files matched your search
@@ -109,3 +109,5 @@ Assets/Tree_Textures.meta
|
||||
Packages
|
||||
Assets/FacebookSDK/SDK/Resources.meta
|
||||
Packages
|
||||
ProjectSettings/ProjectSettings.asset
|
||||
Assets/Test
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 51038db418c84df4fb8c72ab816297b5
|
||||
guid: 328b5d62a858984408481bbfd6024557
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,233 @@
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using System.Threading.Tasks;
|
||||
using Assets.Scenes.Ride.Scripts;
|
||||
using Assets.Scripts.Apis.Models;
|
||||
using Cysharp.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class ARDownloader
|
||||
{
|
||||
private MapRoute _route;
|
||||
|
||||
private readonly string _localARDataPath;
|
||||
private readonly string _localARRoutePath;
|
||||
private readonly string _localVideoPath;
|
||||
private readonly string _serverARDataPath;
|
||||
private readonly string _serverARRoutePath;
|
||||
private readonly string _serverVideoPath;
|
||||
|
||||
private bool IsVideoNeedDownload { get; set; }
|
||||
private bool IsARDataNeedDownload { get; set; }
|
||||
private bool IsARRouteNeedDownload { get; set; }
|
||||
public bool IsDone => !IsVideoNeedDownload && !IsARDataNeedDownload && !IsARRouteNeedDownload;
|
||||
|
||||
private float _total { get; set; }
|
||||
private float _videoProgress;
|
||||
public float VideoProgress
|
||||
{
|
||||
get => _videoProgress;
|
||||
set
|
||||
{
|
||||
_videoProgress = value;
|
||||
ComputeProgress();
|
||||
}
|
||||
}
|
||||
|
||||
private float _dataProgress;
|
||||
public float DataProgress
|
||||
{
|
||||
get => _dataProgress;
|
||||
set
|
||||
{
|
||||
_dataProgress = value;
|
||||
ComputeProgress();
|
||||
}
|
||||
}
|
||||
|
||||
private float _routeProgress;
|
||||
public float RouteProgress
|
||||
{
|
||||
get => _routeProgress;
|
||||
set
|
||||
{
|
||||
_routeProgress = value;
|
||||
ComputeProgress();
|
||||
}
|
||||
}
|
||||
|
||||
private Action<float> ReportProgress { get; set; }
|
||||
|
||||
public ARDownloader(MapRoute route)
|
||||
{
|
||||
this._route = route;
|
||||
|
||||
var dataPath = $"{PFConstants.ARFolder}/{_route.Id}";
|
||||
var path = PFConstants.VideoFolder;
|
||||
Helper.CreateDirectoryIfNotExsit(dataPath);
|
||||
|
||||
_localARDataPath = $"{dataPath}/{_route.Id}.json";
|
||||
_localARRoutePath = $"{dataPath}/route-{_route.Id}.json";
|
||||
_localVideoPath = $"{path}/{_route.FileName}";
|
||||
|
||||
_serverARDataPath = _route.ARConfig;
|
||||
_serverARRoutePath = _route.VideoRoute;
|
||||
_serverVideoPath = _route.Url;
|
||||
}
|
||||
|
||||
private void ComputeProgress()
|
||||
{
|
||||
var progress = (_videoProgress + _routeProgress + _dataProgress) / _total;
|
||||
ReportProgress?.Invoke(progress);
|
||||
}
|
||||
|
||||
public async Task DownLoadDefault(Action<float> progress = null,CancellationTokenSource cancellation = default(CancellationTokenSource))
|
||||
{
|
||||
ReportProgress = progress;
|
||||
|
||||
if(IsVideoNeedDownload)
|
||||
await DownLoadVideoAsync(Progress.Create<float>(x => VideoProgress = x),cancellation);
|
||||
if(IsARRouteNeedDownload)
|
||||
await DownLoadARRouteAsync(Progress.Create<float>(x=> RouteProgress = x),cancellation);
|
||||
if(IsARDataNeedDownload)
|
||||
await DownLoadARDataAsync(Progress.Create<float>(x=> DataProgress = x),cancellation);
|
||||
}
|
||||
|
||||
private async UniTask<UnityWebRequest> DownLoadVideoAsync(IProgress<float> progress = null,CancellationTokenSource cancellation = default(CancellationTokenSource))
|
||||
{
|
||||
var result = await DownloadToFileAsync(_serverVideoPath, _localVideoPath, progress, cancellation);
|
||||
IsVideoNeedDownload = !result.isDone;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async UniTask<UnityWebRequest> DownLoadARRouteAsync(IProgress<float> progress = null,CancellationTokenSource cancellation = default(CancellationTokenSource))
|
||||
{
|
||||
var result = await DownloadToFileAsync(_serverARRoutePath, _localARRoutePath, progress, cancellation);
|
||||
IsARRouteNeedDownload = !result.isDone;
|
||||
return result;
|
||||
}
|
||||
|
||||
private async UniTask<UnityWebRequest> DownLoadARDataAsync(IProgress<float> progress = null,
|
||||
CancellationTokenSource cancellation = default(CancellationTokenSource))
|
||||
{
|
||||
var result = await DownloadToFileAsync(_serverARDataPath, _localARDataPath, progress, cancellation);
|
||||
IsARDataNeedDownload = !result.isDone;
|
||||
return result;
|
||||
}
|
||||
|
||||
public async Task<bool> CheckAllAsync()
|
||||
{
|
||||
IsARRouteNeedDownload = await CheckARRouteAsync();
|
||||
IsARDataNeedDownload = await CheckARDataAsync();
|
||||
IsVideoNeedDownload = await CheckVideoAsync();
|
||||
|
||||
if (IsVideoNeedDownload)
|
||||
_total += 1f;
|
||||
if (IsARRouteNeedDownload)
|
||||
_total += 1f;
|
||||
if (IsARDataNeedDownload)
|
||||
_total += 1f;
|
||||
|
||||
return IsVideoNeedDownload || IsARRouteNeedDownload || IsARDataNeedDownload;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return true if the video is needed to download
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<bool> CheckVideoAsync()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (!File.Exists(_localVideoPath)) return true;
|
||||
return await HeadFileAsync(_serverVideoPath, _localVideoPath);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return true if the video need to update or download
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<bool> CheckARRouteAsync()
|
||||
{
|
||||
if (!File.Exists(_localARRoutePath)) return true;
|
||||
return await HeadFileAsync(_serverARRoutePath, _localARRoutePath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// return true if the video is needed to download
|
||||
/// </summary>
|
||||
/// <returns></returns>
|
||||
private async Task<bool> CheckARDataAsync()
|
||||
{
|
||||
if (!File.Exists(_localARDataPath)) return true;
|
||||
return await HeadFileAsync(_serverARDataPath, _localARDataPath);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 下载文件到本地(持续存入磁盘减少内存占用)
|
||||
/// </summary>
|
||||
/// <param name="downloadUrl">文件连接</param>
|
||||
/// <param name="fullPath">本地文件全路径</param>
|
||||
/// <param name="progress">下载进度</param>
|
||||
/// <param name="cancellation"></param>
|
||||
private static async UniTask<UnityWebRequest> DownloadToFileAsync(string downloadUrl, string fullPath,
|
||||
IProgress<float> progress = null, CancellationTokenSource cancellation = default(CancellationTokenSource))
|
||||
{
|
||||
var dh = new DownloadHandlerFile(fullPath)
|
||||
{
|
||||
removeFileOnAbort = true
|
||||
};
|
||||
|
||||
var request = UnityWebRequest.Get(downloadUrl);
|
||||
request.downloadHandler = dh;
|
||||
request.method = UnityWebRequest.kHttpVerbGET;
|
||||
|
||||
var result = await request.SendWebRequest().ToUniTask(progress, PlayerLoopTiming.Update,
|
||||
(cancellation?.Token ?? default(CancellationToken)));
|
||||
|
||||
var etag = result.GetResponseHeader("x-oss-hash-crc64ecma");
|
||||
var path = fullPath + ".etag";
|
||||
File.WriteAllText(path, etag);
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// head request for file meta info such as etag.
|
||||
/// </summary>
|
||||
/// <param name="downloadUrl">download url</param>
|
||||
/// <param name="fullPath">local path for storage</param>
|
||||
/// <returns></returns>
|
||||
private static async Task<bool> HeadFileAsync(string downloadUrl, string fullPath,
|
||||
IProgress<float> progress = null, CancellationTokenSource cancellation = default(CancellationTokenSource))
|
||||
{
|
||||
try
|
||||
{
|
||||
var etagFile = fullPath + ".etag";
|
||||
var etag = string.Empty;
|
||||
if (File.Exists(etagFile))
|
||||
{
|
||||
etag = File.ReadAllText(etagFile);
|
||||
}
|
||||
|
||||
var request = UnityWebRequest.Head(downloadUrl);
|
||||
var result = await request.SendWebRequest().ToUniTask(progress, PlayerLoopTiming.Update, (cancellation?.Token ?? default(CancellationToken)));
|
||||
var responseTag = result.GetResponseHeader("x-oss-hash-crc64ecma");
|
||||
return !responseTag.Equals(etag);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,3 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 84a219eba2114884a2e246578ade9ab9
|
||||
timeCreated: 1684373675
|
||||
@@ -0,0 +1,214 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class ARGameObject : MonoBehaviour
|
||||
{
|
||||
public string Hash;
|
||||
public const int Layer = 1;
|
||||
public const int TestRidersLayer = 10;
|
||||
public static float MaxDistanceVisibilityModels = 80f;
|
||||
public const float VisibilityHidingTime = 0.2f;
|
||||
public const float VisibilityHidingeRange = 0.5f;
|
||||
protected VideoPointsSync videoSync { get; set; }
|
||||
protected ARRoute route { get; set; }
|
||||
public float frame;
|
||||
private float lastVisibilityLevel;
|
||||
public float distance;
|
||||
private int nextTimeDefIndex;
|
||||
protected bool useMultilapTransform;
|
||||
public Vector3 PositionOffset = Vector3.zero;
|
||||
public Vector3 RotationOffset = Vector3.zero;
|
||||
public Vector3 Scale = Vector3.one;
|
||||
|
||||
private float FrameRate = 29.97f;
|
||||
|
||||
public ARVideoTransform[] TimeTransforms { get; set; }
|
||||
|
||||
public string CustomUrl { get; set; }
|
||||
|
||||
public string ArName { get; set; }
|
||||
|
||||
public int UserId { get; set; }
|
||||
|
||||
public Vector3 CameraPositionOffset { get; set; }
|
||||
|
||||
public float Frame => !this.useMultilapTransform ? this.frame : this.frame + this.videoSync.LastVideoFrame;
|
||||
|
||||
public float VisibilityLevel { get; protected set; }
|
||||
|
||||
public float ManualVisibility { get; set; }
|
||||
|
||||
public bool IsMain { get; set; }
|
||||
|
||||
public ARRoute Route
|
||||
{
|
||||
get => this.route;
|
||||
set
|
||||
{
|
||||
if (this.route == value)
|
||||
return;
|
||||
this.route = value;
|
||||
this.SetFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public VideoPointsSync VideoSync
|
||||
{
|
||||
get => this.videoSync;
|
||||
set
|
||||
{
|
||||
if (this.videoSync == value)
|
||||
return;
|
||||
this.videoSync = value;
|
||||
this.SetFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public float DeltaDistance { get; set; }
|
||||
public float NextDistance { get; set; }
|
||||
|
||||
public float Distance
|
||||
{
|
||||
get => this.distance;
|
||||
set
|
||||
{
|
||||
if (this.distance == value)
|
||||
return;
|
||||
this.distance = value;
|
||||
this.SetFrame();
|
||||
}
|
||||
}
|
||||
|
||||
public virtual void UpdateTransform()
|
||||
{
|
||||
if (this.Route == null)
|
||||
return;
|
||||
var cameraRotation = this.GetCameraRotation(this.frame);
|
||||
var filteredCameraPosition = this.GetFilteredCameraPosition(this.frame);
|
||||
this.transform.rotation = cameraRotation * Quaternion.Euler(this.RotationOffset);
|
||||
this.transform.position = filteredCameraPosition + cameraRotation * this.PositionOffset;
|
||||
this.transform.localScale = this.Scale;
|
||||
}
|
||||
|
||||
|
||||
public void UpdateByTimeDefinitions(float currentFrame)
|
||||
{
|
||||
if (this.TimeTransforms == null || this.TimeTransforms.Length == 0)
|
||||
return;
|
||||
|
||||
if (this.nextTimeDefIndex > this.TimeTransforms.Length - 1)
|
||||
this.nextTimeDefIndex = 0;
|
||||
|
||||
if (this.nextTimeDefIndex > 0 && (double)this.TimeTransforms[this.nextTimeDefIndex - 1].Frame > (double)currentFrame)
|
||||
this.nextTimeDefIndex = 0;
|
||||
|
||||
while (this.nextTimeDefIndex < this.TimeTransforms.Length - 1 && (double)this.TimeTransforms[this.nextTimeDefIndex].Frame <= (double)currentFrame)
|
||||
++this.nextTimeDefIndex;
|
||||
|
||||
if (this.nextTimeDefIndex == 0)
|
||||
{
|
||||
this.Distance = this.TimeTransforms[0].Distance;
|
||||
this.PositionOffset = this.TimeTransforms[0].PositionOffset;
|
||||
this.Scale = this.TimeTransforms[0].Scale;
|
||||
this.RotationOffset = this.TimeTransforms[0].RotationOffset;
|
||||
}
|
||||
else
|
||||
{
|
||||
var t = Mathf.Clamp01((currentFrame - (float)this.TimeTransforms[this.nextTimeDefIndex - 1].Frame) / (float)(this.TimeTransforms[this.nextTimeDefIndex].Frame - this.TimeTransforms[this.nextTimeDefIndex - 1].Frame));
|
||||
this.Distance = Mathf.Lerp(this.TimeTransforms[this.nextTimeDefIndex - 1].Distance, this.TimeTransforms[this.nextTimeDefIndex].Distance, t);
|
||||
this.PositionOffset = Vector3.Lerp(this.TimeTransforms[this.nextTimeDefIndex - 1].PositionOffset, this.TimeTransforms[this.nextTimeDefIndex].PositionOffset, t);
|
||||
this.Scale = Vector3.Lerp(this.TimeTransforms[this.nextTimeDefIndex - 1].Scale, this.TimeTransforms[this.nextTimeDefIndex].Scale, t);
|
||||
this.RotationOffset = Vector3.Lerp(this.TimeTransforms[this.nextTimeDefIndex - 1].RotationOffset, this.TimeTransforms[this.nextTimeDefIndex].RotationOffset, t);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
public void UpdateOffsets()
|
||||
{
|
||||
if (this.Route == null || this.VideoSync == null)
|
||||
return;
|
||||
var quaternion = Quaternion.Inverse(this.GetCameraRotation(this.frame));
|
||||
var filteredCameraPosition = this.GetFilteredCameraPosition(this.frame);
|
||||
this.RotationOffset = (quaternion * this.transform.rotation).eulerAngles;
|
||||
this.PositionOffset = quaternion * (this.transform.position - filteredCameraPosition);
|
||||
this.Scale = this.transform.localScale;
|
||||
}
|
||||
|
||||
public void UpdateVisibility(
|
||||
float videoFrame,
|
||||
float visibilityRear,
|
||||
float visibilityFront,
|
||||
bool multiLap)
|
||||
{
|
||||
if (this.ManualVisibility > 0.0)
|
||||
{
|
||||
visibilityFront = this.ManualVisibility;
|
||||
visibilityRear = this.ManualVisibility;
|
||||
}
|
||||
var deltaVisibility = Time.deltaTime * 5f;
|
||||
var a = this.GetVisibilityParameter(this.frame, videoFrame, visibilityRear, visibilityFront, deltaVisibility);
|
||||
if (multiLap && (double)a <= 0.0)
|
||||
{
|
||||
var visibilityParameter = this.GetVisibilityParameter(this.frame + this.videoSync.LastVideoFrame, videoFrame, visibilityRear, visibilityFront, deltaVisibility);
|
||||
a = Mathf.Max(a, visibilityParameter);
|
||||
if ((double)a > 0.0)
|
||||
this.useMultilapTransform = true;
|
||||
}
|
||||
else
|
||||
this.useMultilapTransform = false;
|
||||
this.VisibilityLevel = a;
|
||||
this.lastVisibilityLevel = this.VisibilityLevel;
|
||||
}
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (this.Route == null || this.VideoSync == null)
|
||||
return;
|
||||
|
||||
this.UpdateTransform();
|
||||
}
|
||||
protected virtual void Awake()
|
||||
{
|
||||
|
||||
}
|
||||
protected Quaternion GetCameraRotation(float frame) => this.Route.GetTrajectoryOrientation(this.useMultilapTransform ? frame + this.videoSync.LastVideoFrame : frame);
|
||||
|
||||
protected Vector3 GetFilteredCameraPosition(float frame) => this.Route.GetFilteredCameraPosition(this.useMultilapTransform ? frame + this.videoSync.LastVideoFrame : frame) - this.CameraPositionOffset;
|
||||
|
||||
private void SetFrame()
|
||||
{
|
||||
if (this.Route == null || this.VideoSync == null)
|
||||
return;
|
||||
this.frame = this.VideoSync.GetVideoFrameAtDistance(this.Distance);
|
||||
}
|
||||
|
||||
private float GetVisibilityParameter(
|
||||
float objectFrame,
|
||||
float videoFrame,
|
||||
float visibilityRear,
|
||||
float visibilityFront,
|
||||
float deltaVisibility)
|
||||
{
|
||||
if (objectFrame < videoFrame - visibilityRear)
|
||||
return 0.0f;
|
||||
if (visibilityFront <= 0.0)
|
||||
return 1f;
|
||||
if (this.ManualVisibility == -1.0)
|
||||
return Mathf.Clamp(0.0f, this.lastVisibilityLevel - deltaVisibility, this.lastVisibilityLevel + deltaVisibility);
|
||||
float num1;
|
||||
if (objectFrame > videoFrame)
|
||||
{
|
||||
var num2 = (float)(videoFrame + visibilityFront - 0.5 * this.FrameRate);
|
||||
var num3 = videoFrame + visibilityFront;
|
||||
num1 = 1f - Mathf.Clamp01((float)((objectFrame - num2) / (num3 - num2)));
|
||||
}
|
||||
else
|
||||
{
|
||||
var num4 = videoFrame - visibilityRear;
|
||||
var num5 = (float)(videoFrame - visibilityRear + 0.5 *this.FrameRate);
|
||||
num1 = Mathf.Clamp01((float)((objectFrame - num4) / (num5 - num4)));
|
||||
}
|
||||
return Mathf.Clamp(num1, this.lastVisibilityLevel - deltaVisibility, this.lastVisibilityLevel + deltaVisibility);
|
||||
}
|
||||
}
|
||||
}
|
||||
+1
-1
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 68972f1ed725ed94bb600236ab29a6d3
|
||||
guid: dbf584e2324021741a949900752a8650
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
@@ -0,0 +1,139 @@
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public static class ARGameObjectFactory
|
||||
{
|
||||
private static bool IsValidVertex(Vector3 v) => !float.IsNaN(v.x) && !float.IsInfinity(v.x) && !float.IsNaN(v.y) && !float.IsInfinity(v.y) && !float.IsNaN(v.z) && !float.IsInfinity(v.z);
|
||||
//创建轨迹
|
||||
public static GameObject CreateTrajectory(
|
||||
ARRoute route,
|
||||
int segment,
|
||||
float lOffset,
|
||||
float rOffset,
|
||||
float margin = float.NaN)
|
||||
{
|
||||
int start;
|
||||
int end;
|
||||
route.GetSlamSegmentRange(segment, out start, out end);
|
||||
|
||||
var num1 = end - start + 1;
|
||||
var indices = new int[(num1 - 1) * 6];
|
||||
var vector3Array1 = new Vector3[num1 * 2];
|
||||
|
||||
Vector3 left, right;
|
||||
CreateVertices(start, route, lOffset, rOffset, out left, out right, margin);
|
||||
vector3Array1[0] = left;
|
||||
vector3Array1[1] = right;
|
||||
|
||||
var num2 = 2;
|
||||
var num3 = 0;
|
||||
for (var frame = start + 1; frame <= end; ++frame)
|
||||
{
|
||||
CreateVertices(frame, route, lOffset, rOffset, out left, out right, margin);
|
||||
if (IsValidVertex(left) && IsValidVertex(right))
|
||||
{
|
||||
var vector3Array2 = vector3Array1;
|
||||
var index1 = num2;
|
||||
|
||||
var num4 = index1 + 1;
|
||||
var vector3_1 = left;
|
||||
vector3Array2[index1] = vector3_1;
|
||||
var vector3Array3 = vector3Array1;
|
||||
|
||||
var index2 = num4;
|
||||
num2 = index2 + 1;
|
||||
var vector3_2 = right;
|
||||
vector3Array3[index2] = vector3_2;
|
||||
var numArray1 = indices;
|
||||
|
||||
var index3 = num3;
|
||||
var num5 = index3 + 1;
|
||||
var num6 = num2 - 3;
|
||||
numArray1[index3] = num6;
|
||||
var numArray2 = indices;
|
||||
|
||||
var index4 = num5;
|
||||
var num7 = index4 + 1;
|
||||
var num8 = num2 - 4;
|
||||
numArray2[index4] = num8;
|
||||
var numArray3 = indices;
|
||||
|
||||
var index5 = num7;
|
||||
var num9 = index5 + 1;
|
||||
var num10 = num2 - 1;
|
||||
numArray3[index5] = num10;
|
||||
var numArray4 = indices;
|
||||
|
||||
var index6 = num9;
|
||||
var num11 = index6 + 1;
|
||||
var num12 = num2 - 4;
|
||||
numArray4[index6] = num12;
|
||||
var numArray5 = indices;
|
||||
|
||||
var index7 = num11;
|
||||
var num13 = index7 + 1;
|
||||
var num14 = num2 - 2;
|
||||
numArray5[index7] = num14;
|
||||
var numArray6 = indices;
|
||||
|
||||
var index8 = num13;
|
||||
num3 = index8 + 1;
|
||||
var num15 = num2 - 1;
|
||||
numArray6[index8] = num15;
|
||||
}
|
||||
}
|
||||
|
||||
var mesh = new Mesh
|
||||
{
|
||||
vertices = vector3Array1,
|
||||
indexFormat = IndexFormat.UInt32
|
||||
};
|
||||
mesh.SetIndices(indices, MeshTopology.Triangles, 0);
|
||||
var trajectory = new GameObject(string.Format("Segment {0}", (object)segment), new System.Type[3]
|
||||
{
|
||||
typeof(MeshFilter),
|
||||
typeof(MeshRenderer),
|
||||
typeof(MeshCollider)
|
||||
});
|
||||
trajectory.GetComponent<MeshFilter>().sharedMesh = mesh;
|
||||
trajectory.GetComponent<MeshCollider>().sharedMesh = trajectory.GetComponent<MeshFilter>().sharedMesh;
|
||||
return trajectory;
|
||||
}
|
||||
|
||||
private static void CreateVertices(
|
||||
int frame,
|
||||
ARRoute route,
|
||||
float lOffset,
|
||||
float rOffset,
|
||||
out Vector3 left,
|
||||
out Vector3 right,
|
||||
float margin = float.NaN)
|
||||
{
|
||||
var trajectoryOrientationAt = route.GetTrajectoryOrientationAt(frame);
|
||||
var vector3 = route.GetCameraPositionAt(frame) - trajectoryOrientationAt * Vector3.up * route.CameraHeight;
|
||||
|
||||
if (lOffset == 0.0)
|
||||
lOffset = route.GetLeftSideOffset((float)frame);
|
||||
|
||||
if (float.IsNaN(margin))
|
||||
lOffset += route.RouteMargin;
|
||||
else
|
||||
lOffset += margin;
|
||||
|
||||
left = vector3 + trajectoryOrientationAt * Vector3.left * lOffset;
|
||||
|
||||
if (rOffset == 0.0)
|
||||
rOffset = route.GetRightSideOffset((float)frame);
|
||||
|
||||
if (float.IsNaN(margin))
|
||||
rOffset += route.RouteMargin;
|
||||
else
|
||||
rOffset += margin;
|
||||
|
||||
right = vector3 - trajectoryOrientationAt * Vector3.left * rOffset;
|
||||
left.y = right.y = vector3.y;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6ed86df267dfdd249bbec364a3c88ac9
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,23 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public enum CameraDistance
|
||||
{
|
||||
FirstPerson,
|
||||
Near,
|
||||
Middle,
|
||||
Far,
|
||||
}
|
||||
|
||||
public enum VideoPlayMode
|
||||
{
|
||||
Front,
|
||||
AutoPanorama,
|
||||
Rear,
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a289f05c09632e48b90c9f12837743a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,204 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public abstract class ARGameObjectsController : MonoBehaviour
|
||||
{
|
||||
public float MaximumVisibilityDistance = 200f;
|
||||
private readonly Vector3 CameraOriginOffset = Vector3.up * -100f;
|
||||
protected static readonly Vector3 DefaultObjectPosition = new Vector3(0.0f, 1000f, 0.0f);
|
||||
protected List<ARGameObject> arObjects = new List<ARGameObject>();
|
||||
protected Material matShadow { get; set; }
|
||||
protected Material matModelMask;
|
||||
protected AVProVideoPlayer videoPlayer { get; set; }
|
||||
protected VideoPointsSync videoSync{ get; set; }
|
||||
protected Vector3 cameraPositionOffset { get; set; }
|
||||
private GameObject panoramaObject;
|
||||
private Material panoramaMaterial;
|
||||
private Material skyboxMaterialBackup;
|
||||
protected GameObject trajectoryObject;
|
||||
private float ambientIntensity;
|
||||
private GameObject camGo;
|
||||
protected Dictionary<int, ARGameObjectsController.Segment> trajectorySegments = new Dictionary<int, ARGameObjectsController.Segment>();
|
||||
protected int lapCount = 1;
|
||||
protected double lapLength;
|
||||
|
||||
public bool AR360Version { get; private set; }
|
||||
|
||||
public Camera UnityCamera { get; protected set; }
|
||||
|
||||
public float FrameIndexDistanceCorrection { get; set; }
|
||||
|
||||
public ARRoute Route { get; private set; }
|
||||
|
||||
protected float CameraDistance { get; private set; }
|
||||
|
||||
public float TargetCameraDistance { get; private set; }
|
||||
|
||||
public Camera PanoramaCamera { get; private set; }
|
||||
|
||||
public bool PassedPanorama { get; set; }
|
||||
|
||||
public bool IsMultilap => this.lapCount > 1;
|
||||
|
||||
protected virtual void Awake()
|
||||
{
|
||||
this.ambientIntensity = RenderSettings.ambientIntensity;
|
||||
this.matShadow = Resources.Load<Material>("UI/Material/TransparentPlane");
|
||||
this.arObjects.Clear();
|
||||
this.arObjects.AddRange(FindObjectsOfType<ARGameObject>());
|
||||
SetupCamera();
|
||||
}
|
||||
|
||||
protected virtual void SetupCamera()
|
||||
{
|
||||
this.UnityCamera = Camera.main;
|
||||
}
|
||||
|
||||
public virtual void SetArRoute(ARRoute route, VideoPointsSync videoSync,AVProVideoPlayer mediaPlayer)
|
||||
{
|
||||
videoPlayer = mediaPlayer;
|
||||
this.Route = route;
|
||||
this.videoSync = videoSync;
|
||||
if (this.Route.CameraRotationsRear != null && this.Route.CameraRotationsRear.Length == this.Route.CameraRotations.Length)
|
||||
{
|
||||
this.AR360Version = true;
|
||||
ARGameObject.MaxDistanceVisibilityModels = 200f;
|
||||
this.MaximumVisibilityDistance = 500f;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.AR360Version = false;
|
||||
ARGameObject.MaxDistanceVisibilityModels = 80f;
|
||||
this.MaximumVisibilityDistance = 200f;
|
||||
}
|
||||
if (route == null)
|
||||
return;
|
||||
foreach (ARGameObject arObject in this.arObjects)
|
||||
{
|
||||
arObject.VideoSync = videoSync;
|
||||
arObject.Route = route;
|
||||
}
|
||||
|
||||
this.trajectoryObject = new GameObject("TrajectoryMesh")
|
||||
{
|
||||
transform =
|
||||
{
|
||||
parent = this.transform
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
protected virtual void UpdateGameObjects(
|
||||
float videoFrame,
|
||||
float visibilityRear,
|
||||
float visibilityFront)
|
||||
{
|
||||
foreach (var arObject in this.arObjects)
|
||||
{
|
||||
arObject.CameraPositionOffset = this.cameraPositionOffset;
|
||||
if (arObject is ARLaneGameObject arLaneObject)
|
||||
arLaneObject.FrameIndexDistanceCorrection = this.FrameIndexDistanceCorrection;
|
||||
if (arObject.TimeTransforms != null && arObject.TimeTransforms.Length > 1)
|
||||
arObject.UpdateByTimeDefinitions(videoFrame);
|
||||
arObject.UpdateVisibility(videoFrame, visibilityRear, visibilityFront, this.IsMultilap);
|
||||
var flag = this.IsObjectActive(arObject);
|
||||
arObject.gameObject.SetActive(flag);
|
||||
}
|
||||
}
|
||||
|
||||
protected virtual bool IsObjectActive(ARGameObject arObject) => (double)arObject.VisibilityLevel > 0.0 ;
|
||||
|
||||
protected virtual Material GetTrajectoryMaterial() => this.matShadow;
|
||||
|
||||
protected virtual void Update()
|
||||
{
|
||||
if (this.Route == null)
|
||||
return;
|
||||
|
||||
var num1 = this.videoPlayer.CurrentFrame - (float)this.Route.VideoFrameOffset;
|
||||
{
|
||||
this.cameraPositionOffset = this.Route.GetCameraPosition(num1) - this.CameraOriginOffset;
|
||||
UnityCamera.transform.position = this.CameraOriginOffset;
|
||||
UnityCamera.transform.rotation = this.Route.GetCameraRotation(num1);
|
||||
}
|
||||
this.CameraDistance = this.videoSync.GetDistanceForVideoFrame(num1 + this.FrameIndexDistanceCorrection);
|
||||
var num2 = Mathf.Min(float.MaxValue, this.Route.GetVisibility(num1));
|
||||
var num3 = num2;
|
||||
var visibilityRear = 200f;
|
||||
if (num3 == 0.0)
|
||||
num3 = 600f;
|
||||
if (visibilityRear == 0.0)
|
||||
visibilityRear = 600f;
|
||||
this.UpdateTrajectory(num1, num3);//更新轨迹
|
||||
this.UpdateGameObjects(num1, visibilityRear, num3);//更新骑手等位置
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新当前可见轨迹
|
||||
/// </summary>
|
||||
/// <param name="frame">帧数</param>
|
||||
/// <param name="defaultVisibility">默认可视距离</param>
|
||||
private void UpdateTrajectory(float frame, float defaultVisibility)
|
||||
{
|
||||
int start;
|
||||
int end;
|
||||
this.Route.GetVisibleSlamSegments((int)frame, out start, out end, defaultVisibility);
|
||||
var intList = new List<int>();
|
||||
foreach (var key in this.trajectorySegments.Keys)
|
||||
{
|
||||
if (key < start || key > end)
|
||||
intList.Add(key);
|
||||
}
|
||||
foreach (var key in intList)
|
||||
{
|
||||
UnityEngine.Object.Destroy(this.trajectorySegments[key].GameObject);
|
||||
this.trajectorySegments.Remove(key);
|
||||
}
|
||||
for (int index = start; index <= end; ++index)
|
||||
{
|
||||
if (!this.trajectorySegments.ContainsKey(index))
|
||||
{
|
||||
var trajectory = this.CreateTrajectory(index, 0.0f, 0.0f);
|
||||
var segment = new Segment(trajectory, trajectory.transform.position);
|
||||
this.trajectorySegments.Add(index, segment);
|
||||
}
|
||||
}
|
||||
foreach (var key in this.trajectorySegments.Keys)
|
||||
{
|
||||
var trajectorySegment = this.trajectorySegments[key];
|
||||
trajectorySegment.GameObject.transform.position = trajectorySegment.Position - this.cameraPositionOffset;
|
||||
}
|
||||
}
|
||||
|
||||
//创建轨迹
|
||||
protected virtual GameObject CreateTrajectory(
|
||||
int segment,
|
||||
float lOffset,
|
||||
float rOffset,
|
||||
float margin = float.NaN)
|
||||
{
|
||||
var trajectory = ARGameObjectFactory.CreateTrajectory(this.Route, segment, lOffset, rOffset, margin);
|
||||
trajectory.transform.parent = this.trajectoryObject.transform;
|
||||
trajectory.GetComponent<MeshRenderer>().shadowCastingMode = ShadowCastingMode.Off;
|
||||
trajectory.GetComponent<MeshRenderer>().material = this.GetTrajectoryMaterial();
|
||||
return trajectory;
|
||||
}
|
||||
|
||||
protected Vector3 GetCameraPosition(float frame) => this.Route.GetCameraPosition(frame) - this.cameraPositionOffset;
|
||||
|
||||
public class Segment
|
||||
{
|
||||
public GameObject GameObject;
|
||||
public Vector3 Position;
|
||||
|
||||
public Segment(GameObject gameObject, Vector3 position)
|
||||
{
|
||||
this.GameObject = gameObject;
|
||||
this.Position = position;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3d565e7e3c0027f41836c0210a05072c
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,76 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class ARLaneGameObject : ARGameObject
|
||||
{
|
||||
public Vector3 Lean { get; set; }//偏移量
|
||||
|
||||
public int StartPosition { get; set; }
|
||||
|
||||
public int StartRouteDistance { get; set; }
|
||||
|
||||
public bool IsAtFinish { get; set; }//是否到达终点
|
||||
|
||||
public float RouteDistance { get; set; }//线路上的距离
|
||||
|
||||
public float Lane { get; set; } //车道上的位置
|
||||
|
||||
public float BaseOffset { get; set; }//基准偏移量
|
||||
|
||||
public float DeltaLane { get; set; }//
|
||||
|
||||
public float LaneWidth { get; set; }//车道宽度
|
||||
|
||||
public float Speed { get; set; }//速度
|
||||
|
||||
public float PreSpeed { get; set; }//速度
|
||||
|
||||
public float Curvature { get; set; }//转向
|
||||
|
||||
public float LaneChangingDirection { get; set; }//方向
|
||||
|
||||
public float LaneCamera { get; set; }//车道上摄像机的位置
|
||||
|
||||
public float DistanceSort { get; set; }//距离排序
|
||||
|
||||
public float FrameIndexDistanceCorrection { get; set; }//位置纠正
|
||||
|
||||
public int TestPower { get; set; }
|
||||
|
||||
protected void Start()
|
||||
{
|
||||
this.Lane = route.Lane;//轨迹上的距离
|
||||
}
|
||||
|
||||
//重置碰撞检测参数
|
||||
public void ResetCollisionDetectionParameters()
|
||||
{
|
||||
this.StartPosition = 0;//开始位置
|
||||
this.Lane = route.Lane;//轨迹上的距离
|
||||
this.DeltaLane = 0.0f;//差距
|
||||
this.LaneWidth = 0.0f;//轨迹宽度
|
||||
this.LaneCamera = 0.0f;//轨迹上摄像头的位置
|
||||
this.DistanceSort = 0.0f;//距离上的远近
|
||||
this.Curvature = 0.0f;//角度
|
||||
this.LaneChangingDirection = 0.0f;//偏转方向
|
||||
}
|
||||
|
||||
//更新人物的位置和转向
|
||||
public override void UpdateTransform()
|
||||
{
|
||||
PositionOffset = Vector3.up * route.CameraHeight * (-1);
|
||||
var cameraRotation = this.GetCameraRotation(this.frame - this.FrameIndexDistanceCorrection);
|
||||
var normalizeCameraRotation = Quaternion.Euler(new Vector3(cameraRotation.eulerAngles.x+route.CameraRotationsOffset.x, cameraRotation.eulerAngles.y+route.CameraRotationsOffset.y, cameraRotation.eulerAngles.z+route.CameraRotationsOffset.z));
|
||||
|
||||
var filteredCameraPosition = this.GetFilteredCameraPosition(this.frame - this.FrameIndexDistanceCorrection);
|
||||
var vector3 = Vector3.left * (this.route.LeftHanded ? -1f : 1f) * (this.LaneWidth * (this.Lane + this.LaneCamera + this.route.Lane) - this.BaseOffset);
|
||||
var targetPos = filteredCameraPosition + normalizeCameraRotation * (vector3 + this.PositionOffset);
|
||||
|
||||
this.transform.position = targetPos;
|
||||
this.transform.rotation = normalizeCameraRotation * Quaternion.Euler(this.RotationOffset) * Quaternion.Euler(this.Lean);
|
||||
this.transform.localScale = this.Scale;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c83121d82f416c345a6250c354717a41
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,258 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public abstract class ARLaneGameObjectsController : ARGameObjectsController
|
||||
{
|
||||
protected const float LaneWidth = 0.7f;
|
||||
protected const float StartRegionDistance = 200f;
|
||||
private const float StartRowsGap = 1.0f;
|
||||
private const float StartRowsRandomDistance = 0.4f;
|
||||
private const float StartRowsRandomWidth = 0.15f;
|
||||
private const float MinCollisionDistance = 1.33f;
|
||||
protected readonly Dictionary<int, ARLaneGameObject> riderObjects = new Dictionary<int, ARLaneGameObject>();
|
||||
private readonly Dictionary<int, Vector2> randomizedStartOffsets = new Dictionary<int, Vector2>();
|
||||
private readonly List<ARLaneGameObject> collisionList = new List<ARLaneGameObject>();
|
||||
|
||||
public bool AllowStartOrder { get; set; } = true;
|
||||
|
||||
protected float StartRegionRouteWidth { get; private set; }
|
||||
|
||||
protected int RiderCountInStartRow { get; private set; }
|
||||
|
||||
public float OvertakingThreshold { get; set; } = 5f;
|
||||
|
||||
public bool NearViewMode { get; set; }
|
||||
|
||||
public int FollowedRiderId { get; set; }
|
||||
|
||||
public IReadOnlyDictionary<int, ARLaneGameObject> ArRiders => (IReadOnlyDictionary<int, ARLaneGameObject>)this.riderObjects;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
var frame = 100f;
|
||||
this.StartRegionRouteWidth = this.GetRouteLeftOffset(frame) + this.GetRouteRightOffset(frame);
|
||||
this.RiderCountInStartRow = Mathf.Max(1, Mathf.CeilToInt(this.StartRegionRouteWidth / LaneWidth));
|
||||
}
|
||||
|
||||
protected override void UpdateGameObjects(
|
||||
float videoFrame,
|
||||
float visibilityRear,
|
||||
float visibilityFront)
|
||||
{
|
||||
base.UpdateGameObjects(videoFrame, visibilityRear, visibilityFront);//控制3d物体显示隐藏
|
||||
if (this.Route == null || this.videoSync == null)
|
||||
return;
|
||||
this.DetectRidersCollisions(this.CameraDistance);//计算3d物体的位置和转向
|
||||
}
|
||||
//检测碰撞
|
||||
private void DetectRidersCollisions(float cameraDistance)
|
||||
{
|
||||
var num1 = cameraDistance - ARGameObject.MaxDistanceVisibilityModels;
|
||||
var num2 = cameraDistance + ARGameObject.MaxDistanceVisibilityModels;
|
||||
this.collisionList.Clear();
|
||||
foreach (var arLaneObject in this.riderObjects.Values)
|
||||
{
|
||||
if (arLaneObject.gameObject.activeSelf && !arLaneObject.IsAtFinish)
|
||||
{
|
||||
if ((double)arLaneObject.Distance >= (double)num1 && (double)arLaneObject.Distance <= (double)num2)
|
||||
{
|
||||
this.collisionList.Add(arLaneObject);
|
||||
arLaneObject.DistanceSort = arLaneObject.Distance;
|
||||
}
|
||||
}
|
||||
}
|
||||
foreach (ARLaneGameObject collision in this.collisionList)
|
||||
{
|
||||
if ((double)collision.RouteDistance < 200.0)
|
||||
{
|
||||
collision.Distance = this.GetRouteDistance(collision.StartPosition, collision.RouteDistance);
|
||||
collision.DistanceSort = collision.Distance;
|
||||
}
|
||||
}
|
||||
this.collisionList.Sort((Comparison<ARLaneGameObject>)((r1, r2) =>
|
||||
{
|
||||
int num3 = r1.Lane.CompareTo(r2.Lane);
|
||||
if (num3 == 0)
|
||||
num3 = r2.DistanceSort.CompareTo(r1.DistanceSort);
|
||||
return num3;
|
||||
}));
|
||||
var deltaTime = Time.deltaTime;
|
||||
for (int index = 0; index < this.collisionList.Count; ++index)
|
||||
{
|
||||
var collision = this.collisionList[index];
|
||||
var lane = collision.Lane;
|
||||
var num4 = this.GetLane(collision.RouteDistance, collision.DistanceSort, index);
|
||||
if ((double)collision.LaneWidth != 0.0)
|
||||
{
|
||||
float num5 = 0.02f * deltaTime * Mathf.Log(collision.Speed + 5f, 1.1f);
|
||||
num4 = Mathf.Clamp(num4, lane - num5, lane + num5 * 1.5f);
|
||||
collision.DeltaLane = (num4 - lane) / deltaTime;
|
||||
}
|
||||
collision.Lane = num4;
|
||||
}
|
||||
this.CalculateOvertakingParameters();
|
||||
foreach (ARLaneGameObject collision in this.collisionList)
|
||||
{
|
||||
collision.LaneWidth = LaneWidth;
|
||||
var num6 = this.Route.LeftHanded ? this.GetRouteLeftOffset(collision.Frame) : this.GetRouteRightOffset(collision.Frame);
|
||||
var num7 = Mathf.Lerp(this.GetStartOffset(collision.StartPosition).x, 0.0f, collision.Distance / StartRegionDistance);
|
||||
collision.BaseOffset = num6 + num7;
|
||||
}
|
||||
this.CalculateCameraAvoidance(cameraDistance);
|
||||
}
|
||||
//摄像机障碍物避免
|
||||
private void CalculateCameraAvoidance(float cameraDistance)
|
||||
{
|
||||
var deltaTime = Time.deltaTime;
|
||||
for (var index = 0; index < this.collisionList.Count; ++index)
|
||||
{
|
||||
var collision = this.collisionList[index];
|
||||
var flag1 = collision.StartPosition == this.FollowedRiderId;
|
||||
var x = Math.Abs(collision.Distance - cameraDistance);
|
||||
var x2 = 4f;
|
||||
if (this.NearViewMode && !flag1)
|
||||
x2 = 5.5f;
|
||||
if ((double)x > (double)x2)
|
||||
{
|
||||
if ((double)collision.LaneCamera > 0.0)
|
||||
collision.LaneCamera = Mathf.Max(0.0f, collision.LaneCamera - deltaTime);
|
||||
else if ((double)collision.LaneCamera < 0.0)
|
||||
collision.LaneCamera = Mathf.Min(0.0f, collision.LaneCamera + deltaTime);
|
||||
}
|
||||
else
|
||||
{
|
||||
var num1 = PFMath.Lerp(0.0f, 1f, x2, 0.0f, x);
|
||||
var num2 = collision.Lane * collision.LaneWidth - collision.BaseOffset;
|
||||
var num3 = 0.75f;
|
||||
if (this.NearViewMode && !flag1)
|
||||
{
|
||||
num2 += num3 / 2f;
|
||||
num3 *= 1.5f;
|
||||
}
|
||||
var flag2 = (double)collision.LaneCamera < 0.0 || (double)collision.LaneCamera <= 0.0 && (double)num2 < 0.0;
|
||||
var a1 = (float)(-(double)num2 - (double)num1 * (double)num3) / collision.LaneWidth;
|
||||
var a2 = (num1 * num3 - num2) / collision.LaneWidth;
|
||||
if (this.NearViewMode & flag1)
|
||||
{
|
||||
var num4 = Mathf.Max(a1 - collision.LaneCamera, -deltaTime);
|
||||
collision.LaneCamera = Mathf.Min(collision.LaneCamera + num4, -1.401298E-45f);
|
||||
}
|
||||
else
|
||||
collision.LaneCamera = !flag2 ? Mathf.Max(a2, float.Epsilon) : Mathf.Min(a1, -1.401298E-45f);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void CalculateOvertakingParameters()
|
||||
{
|
||||
var deltaTime = Time.deltaTime;
|
||||
foreach (ARLaneGameObject laneObject in this.riderObjects.Values)
|
||||
{
|
||||
var num1 = laneObject.Speed * deltaTime;
|
||||
if ((double)num1 == 0.0)
|
||||
{
|
||||
laneObject.Curvature = 0.0f;
|
||||
laneObject.LaneChangingDirection = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
var num2 = (this.Route.LeftHanded ? -1f : 1f) * laneObject.DeltaLane * laneObject.LaneWidth * deltaTime;
|
||||
if ((double)laneObject.LaneCamera != 0.0)
|
||||
num2 = 0.0f;
|
||||
var curvature = 0.0f;
|
||||
if ((double)num1 > 0.0)
|
||||
{
|
||||
var num3 = Mathf.Atan(num2 / num1);
|
||||
curvature = (float)(0.039999999105930328 * (double)PFMath.Lerp(0.0f, 3f, 20f, 1f, laneObject.Speed)) * num3;
|
||||
}
|
||||
this.UpdateRiderCurvature(laneObject, curvature, deltaTime);
|
||||
var angle = -57.29578f * Mathf.Atan(num2 / num1);
|
||||
this.UpdateLaneChangingDirection(laneObject, angle, deltaTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected void UpdateRiderCurvature(ARLaneGameObject laneObject, float curvature, float deltaTime)
|
||||
{
|
||||
var num = 6f;
|
||||
laneObject.Curvature = Mathf.Lerp(laneObject.Curvature, curvature, num * deltaTime);
|
||||
}
|
||||
|
||||
protected void UpdateLaneChangingDirection(
|
||||
ARLaneGameObject laneObject,
|
||||
float angle,
|
||||
float deltaTime)
|
||||
{
|
||||
var num = 10f * deltaTime;
|
||||
laneObject.LaneChangingDirection = Mathf.Clamp(angle, laneObject.LaneChangingDirection - num, laneObject.LaneChangingDirection + num);
|
||||
}
|
||||
|
||||
protected float GetLane(float routeDistance, float modelDistance, int count = -1)
|
||||
{
|
||||
if (count == -1)
|
||||
count = this.collisionList.Count;
|
||||
var overtakingThreshold = this.GetOvertakingThreshold(routeDistance);
|
||||
var b = 0.0f;
|
||||
for (int index = count - 1; index >= 0; --index)
|
||||
{
|
||||
var collision = this.collisionList[index];
|
||||
if ((double)collision.Lane + 1.0 >= (double)b)
|
||||
{
|
||||
var collisionParameter = ARLaneGameObjectsController.GetCollisionParameter(modelDistance, collision.DistanceSort, overtakingThreshold);
|
||||
if ((double)collisionParameter > 0.0)
|
||||
b = Mathf.Max(collision.Lane + collisionParameter, b);
|
||||
}
|
||||
else
|
||||
break;
|
||||
}
|
||||
return b;
|
||||
}
|
||||
|
||||
protected float GetOvertakingThreshold(float routeDistance)
|
||||
{
|
||||
var b = this.OvertakingThreshold;
|
||||
if (this.AllowStartOrder && (double)routeDistance < 200.0)
|
||||
b = Mathf.Lerp(1.33f, b, routeDistance / 200f);
|
||||
return b;
|
||||
}
|
||||
|
||||
private Vector2 GetStartOffset(int atIndex)
|
||||
{
|
||||
Vector2 startOffset;
|
||||
if (this.randomizedStartOffsets.TryGetValue(atIndex, out startOffset))
|
||||
return startOffset;
|
||||
startOffset = new Vector2(UnityEngine.Random.Range(-StartRowsRandomWidth, StartRowsRandomWidth), UnityEngine.Random.Range(-StartRowsRandomDistance,StartRowsRandomDistance));
|
||||
this.randomizedStartOffsets.Add(atIndex, startOffset);
|
||||
return startOffset;
|
||||
}
|
||||
|
||||
public float GetRouteDistance(int startPosition, float routeDistance)
|
||||
{
|
||||
if (!this.AllowStartOrder || (double)routeDistance >= StartRegionDistance)
|
||||
return routeDistance;
|
||||
float num = Mathf.Lerp((float) ((double) ((startPosition - 1) / this.RiderCountInStartRow) * StartRowsGap + 6.0) + this.GetStartOffset(startPosition).y, 0.0f, routeDistance / StartRegionDistance);
|
||||
return routeDistance + num;
|
||||
}
|
||||
|
||||
//计算碰撞距离
|
||||
protected static float GetCollisionParameter(
|
||||
float distSource,
|
||||
float distOther,
|
||||
float maxDistance)
|
||||
{
|
||||
var x = distSource - distOther;
|
||||
if ((double)x < 0.0)
|
||||
x = -x;
|
||||
if ((double)x < 1.0)
|
||||
return 1f;
|
||||
return (double)x > (double)maxDistance ? 0.0f : PFMath.SmoothStep(1f, 1f, maxDistance, 0.0f, x);
|
||||
}
|
||||
|
||||
private float GetRouteLeftOffset(float frame) => this.Route?.GetLeftSideOffset(frame) ?? 0.0f;
|
||||
|
||||
private float GetRouteRightOffset(float frame) => this.Route?.GetRightSideOffset(frame) ?? 0.0f;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: beab89ef5c7a65d4693d9b8b472bb0d1
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,591 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using Newtonsoft.Json;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Rendering;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class ARRoute
|
||||
{
|
||||
private const float ProjectionSmoothFrames = 30f;
|
||||
private const float DefaultNearSideOffset = 0.0f;
|
||||
private const float DefaultFarSideOffset = 4f;
|
||||
public int[] LeftSideOffsetFrames;
|
||||
public float[] LeftSideOffsets;
|
||||
public int[] RightSideOffsetFrames;
|
||||
public float[] RightSideOffsets;
|
||||
public bool RearMode;
|
||||
|
||||
public ARRoute()
|
||||
{
|
||||
}
|
||||
|
||||
public ARRoute(ARRouteData data) => this.LoadData(data);
|
||||
|
||||
public int[] Visibility { get; set; }
|
||||
|
||||
public Vector3[] CameraPositions { get; set; }
|
||||
|
||||
public Vector3[] FilteredCameraPositions { get; set; }
|
||||
|
||||
public double[] FrameDistances { get; set; }
|
||||
|
||||
public Quaternion[] CameraRotations { get; set; }
|
||||
|
||||
public Quaternion[] CameraRotationsRear { get; set; }
|
||||
|
||||
public Quaternion[] TrajectoryOrientation { get; set; }
|
||||
|
||||
public float[] TrajectoryCurvatures { get; set; }
|
||||
|
||||
public float[] LightRotationFrames { get; set; }
|
||||
|
||||
public Quaternion[] LightRotations { get; set; }
|
||||
|
||||
public float[] ShadowIntensityFrames { get; set; }
|
||||
|
||||
public float[] ShadowIntensities { get; set; }
|
||||
|
||||
public SphericalHarmonicsL2[] SphericalHarmonics { get; set; }
|
||||
|
||||
public int[] SlamSegments { get; set; }
|
||||
|
||||
public CameraProjectionParameters[] ProjectionParameters { get; set; }
|
||||
|
||||
public bool LeftHanded { get; set; }
|
||||
|
||||
public int VideoFrameOffset { get; set; }
|
||||
|
||||
public float CameraHeight { get; set; }
|
||||
|
||||
public float RiderScale { get; set; } = 1f;
|
||||
|
||||
public float RouteMargin { get; private set; } = 2f;
|
||||
|
||||
public bool HasLeftSideOffsets => this.LeftSideOffsetFrames != null && this.LeftSideOffsets != null;
|
||||
|
||||
public bool HasRightSideOffsets => this.RightSideOffsetFrames != null && this.RightSideOffsets != null;
|
||||
|
||||
public int FrameCount => this.CameraPositions.Length;
|
||||
|
||||
public double Lenght => this.FrameDistances[this.FrameCount - 1];
|
||||
|
||||
public VectorData CameraRotationsOffset { get; set; }
|
||||
|
||||
public float Lane { get; set; }
|
||||
|
||||
private float DefaultLeftSideOffset => !this.LeftHanded ? 4f : 0.0f;
|
||||
|
||||
private float DefaultRightSideOffset => !this.LeftHanded ? 0.0f : 4f;
|
||||
|
||||
|
||||
public int GetVisibilityAt(int frame)
|
||||
{
|
||||
if (this.Visibility == null || this.Visibility.Length == 0)
|
||||
return 0;
|
||||
if (frame <= 0)
|
||||
return this.Visibility[0];
|
||||
return frame >= this.Visibility.Length ? this.Visibility[this.Visibility.Length - 1] : this.Visibility[frame];
|
||||
}
|
||||
|
||||
public float GetVisibility(float frame)
|
||||
{
|
||||
if (this.Visibility == null || this.Visibility.Length == 0)
|
||||
return 0.0f;
|
||||
int index = (int)Math.Ceiling((double)frame);
|
||||
if (index <= 0)
|
||||
return (float)this.Visibility[0];
|
||||
if (index >= this.Visibility.Length)
|
||||
return (float)this.Visibility[this.Visibility.Length - 1];
|
||||
var t = frame - (float)(index - 1);
|
||||
return Mathf.Lerp((float)this.Visibility[index - 1], (float)this.Visibility[index], t);
|
||||
}
|
||||
|
||||
public Vector3 GetCameraPositionAt(int frame)
|
||||
{
|
||||
if (frame <= 0)
|
||||
return this.CameraPositions[0];
|
||||
return frame >= this.FrameCount ? this.CameraPositions[this.CameraPositions.Length - 1] : this.CameraPositions[frame];
|
||||
}
|
||||
|
||||
public Vector3 GetCameraPosition(float frame)
|
||||
{
|
||||
var index = (int)Math.Ceiling((double)frame);
|
||||
if (index <= 0)
|
||||
return this.CameraPositions[0];
|
||||
if (index >= this.FrameCount)
|
||||
return this.CameraPositions[this.CameraPositions.Length - 1];
|
||||
var t = frame - (float)(index - 1);
|
||||
return Vector3.Lerp(this.CameraPositions[index - 1], this.CameraPositions[index], t);
|
||||
}
|
||||
|
||||
public Vector3 GetFilteredCameraPositionAt(int frame)
|
||||
{
|
||||
if (frame <= 0)
|
||||
return this.FilteredCameraPositions[0];
|
||||
return frame >= this.FrameCount ? this.FilteredCameraPositions[this.FilteredCameraPositions.Length - 1] : this.FilteredCameraPositions[frame];
|
||||
}
|
||||
|
||||
public Vector3 GetFilteredCameraPosition(float frame)
|
||||
{
|
||||
var index = (int)Math.Ceiling((double)frame);
|
||||
if (index <= 0)
|
||||
return this.FilteredCameraPositions[0];
|
||||
if (index >= this.FrameCount)
|
||||
return this.FilteredCameraPositions[this.FilteredCameraPositions.Length - 1];
|
||||
var t = frame - (float)(index - 1);
|
||||
return Vector3.Lerp(this.FilteredCameraPositions[index - 1], this.FilteredCameraPositions[index], t);
|
||||
}
|
||||
|
||||
public Quaternion GetCameraRotationAt(int frame)
|
||||
{
|
||||
if (frame <= 0)
|
||||
return this.CameraRotations[0];
|
||||
return frame >= this.FrameCount ? this.CameraRotations[this.CameraRotations.Length - 1] : this.CameraRotations[frame];
|
||||
}
|
||||
|
||||
public Quaternion GetCameraRotation(float frame)
|
||||
{
|
||||
var index = (int)Math.Ceiling((double)frame);
|
||||
if (index <= 0)
|
||||
return this.CameraRotations[0];
|
||||
if (index >= this.FrameCount)
|
||||
return this.CameraRotations[this.CameraRotations.Length - 1];
|
||||
var t = frame - (float)(index - 1);
|
||||
return Quaternion.Slerp(this.CameraRotations[index - 1], this.CameraRotations[index], t);
|
||||
}
|
||||
|
||||
public Quaternion GetCameraRotationRear(float frame)
|
||||
{
|
||||
var index = (int)Math.Ceiling((double)frame);
|
||||
if (index <= 0)
|
||||
return this.CameraRotationsRear[0];
|
||||
if (index >= this.FrameCount)
|
||||
return this.CameraRotationsRear[this.CameraRotationsRear.Length - 1];
|
||||
var t = frame - (float)(index - 1);
|
||||
return Quaternion.Slerp(this.CameraRotationsRear[index - 1], this.CameraRotationsRear[index], t);
|
||||
}
|
||||
|
||||
public int GetSlamSegmentIndex(float frame)
|
||||
{
|
||||
for (var index = 1; index < this.SlamSegments.Length; ++index)
|
||||
{
|
||||
if ((double)this.SlamSegments[index] > (double)frame)
|
||||
return index - 1;
|
||||
}
|
||||
return this.SlamSegments.Length - 1;
|
||||
}
|
||||
|
||||
public void GetSlamSegmentRange(int index, out int start, out int end)
|
||||
{
|
||||
index = Mathf.Clamp(index, 0, this.SlamSegments.Length - 1);
|
||||
start = this.SlamSegments[index];
|
||||
if (index < this.SlamSegments.Length - 1)
|
||||
end = this.SlamSegments[index + 1];
|
||||
else
|
||||
end = this.FrameCount;
|
||||
}
|
||||
|
||||
public void GetVisibleSlamSegments(
|
||||
int frame,
|
||||
out int start,
|
||||
out int end,
|
||||
float defultVisibility = 0.0f)
|
||||
{
|
||||
var num = (float)this.GetVisibilityAt(frame);
|
||||
if ((double)num == 0.0)
|
||||
num = defultVisibility;
|
||||
start = this.GetSlamSegmentIndex((float)frame);
|
||||
end = this.GetSlamSegmentIndex((float)frame + num);
|
||||
}
|
||||
|
||||
public double GetFrameAtDistance(double distance)
|
||||
{
|
||||
var frameDistances = this.FrameDistances;
|
||||
var index = Array.BinarySearch<double>(frameDistances, distance);
|
||||
if (index < 0)
|
||||
index = ~index;
|
||||
if (index == 0)
|
||||
return 0.0;
|
||||
if (index == frameDistances.Length)
|
||||
return (double)(frameDistances.Length - 1);
|
||||
var num = PFMath.InverseLerp(frameDistances[index - 1], frameDistances[index], distance);
|
||||
return (double)index + num - 1.0;
|
||||
}
|
||||
|
||||
public double GetTotalDistance()
|
||||
{
|
||||
return FrameDistances[FrameDistances.Length-1];
|
||||
}
|
||||
|
||||
public double GetDistanceForFrame(double frame)
|
||||
{
|
||||
var index = (int)Math.Ceiling(frame);
|
||||
if (index <= 0)
|
||||
return this.FrameDistances[0];
|
||||
if (index >= this.FrameCount)
|
||||
return this.FrameDistances[this.FrameDistances.Length - 1];
|
||||
var t = frame - (double)(index - 1);
|
||||
return PFMath.Lerp(this.FrameDistances[index - 1], this.FrameDistances[index], t);
|
||||
}
|
||||
|
||||
public CameraProjectionParameters GetCameraProjectionParameters(
|
||||
float frame)
|
||||
{
|
||||
var index = Mathf.Clamp(this.GetSlamSegmentIndex(frame), 0, this.ProjectionParameters.Length - 1);
|
||||
var projectionParameter1 = this.ProjectionParameters[index];
|
||||
var slamSegment1 = this.SlamSegments[index];
|
||||
if (index > 0 && (double)frame < (double)slamSegment1 + 15.0)
|
||||
{
|
||||
var t = (float)(0.5 + ((double)frame - (double)slamSegment1) / 30.0);
|
||||
return CameraProjectionParameters.Lerp(this.ProjectionParameters[index - 1], projectionParameter1, t);
|
||||
}
|
||||
if (index < this.SlamSegments.Length - 1)
|
||||
{
|
||||
var slamSegment2 = this.SlamSegments[index + 1];
|
||||
if (frame > slamSegment2 - 15.0)
|
||||
{
|
||||
var t = (float)(0.5 - ((double)slamSegment2 - (double)frame) / 30.0);
|
||||
var projectionParameter2 = this.ProjectionParameters[index + 1];
|
||||
return CameraProjectionParameters.Lerp(projectionParameter1, projectionParameter2, t);
|
||||
}
|
||||
}
|
||||
return projectionParameter1;
|
||||
}
|
||||
//设置摄像机投影矩阵
|
||||
public void SetCameraProjection(float frame, Camera camera, bool fitInside = false)
|
||||
{
|
||||
var projectionParameters = this.GetCameraProjectionParameters(frame);
|
||||
if (projectionParameters.alpha == 0.0)
|
||||
return;
|
||||
var num1 = projectionParameters.cx / projectionParameters.cy;
|
||||
var num2 = (float)Screen.width / (float)Screen.height;
|
||||
var cx = projectionParameters.cx;
|
||||
var cy = projectionParameters.cy;
|
||||
if (fitInside)
|
||||
{
|
||||
if ((double)num2 > (double)num1)
|
||||
cx = cy * num2;
|
||||
if ((double)num2 < (double)num1)
|
||||
cy = cx * 1f / num2;
|
||||
}
|
||||
else
|
||||
{
|
||||
if ((double)num2 < (double)num1)
|
||||
cx = cy * num2;
|
||||
if ((double)num2 > (double)num1)
|
||||
cy = cx * 1f / num2;
|
||||
}
|
||||
camera.projectionMatrix = this.GetCameraProjectionMatrix(projectionParameters.alpha, projectionParameters.beta, cx, cy, camera.nearClipPlane, camera.farClipPlane);
|
||||
}
|
||||
|
||||
private Matrix4x4 GetCameraProjectionMatrix(
|
||||
float alpha,
|
||||
float beta,
|
||||
float cx,
|
||||
float cy,
|
||||
float nearClipPlane,
|
||||
float farClipPlane)
|
||||
{
|
||||
var projectionMatrix = new Matrix4x4();
|
||||
var z = (float)(-((double)farClipPlane + (double)nearClipPlane) / ((double)farClipPlane - (double)nearClipPlane));
|
||||
var w = (float)(-2.0 * (double)farClipPlane * (double)nearClipPlane / ((double)farClipPlane - (double)nearClipPlane));
|
||||
projectionMatrix.SetRow(0, new Vector4(alpha / cx, 0.0f, 0.0f, 0.0f));
|
||||
projectionMatrix.SetRow(1, new Vector4(0.0f, beta / cy, 0.0f, 0.0f));
|
||||
projectionMatrix.SetRow(2, new Vector4(0.0f, 0.0f, z, w));
|
||||
projectionMatrix.SetRow(3, new Vector4(0.0f, 0.0f, -1f, 0.0f));
|
||||
return projectionMatrix;
|
||||
}
|
||||
//处理摄像机3d位置
|
||||
public void CreateFilteredCameraPositions()
|
||||
{
|
||||
var length = this.CameraPositions.Length;
|
||||
var vector3Array = new Vector3[length];
|
||||
for (var index = 0; index < length; ++index)
|
||||
vector3Array[index] = this.CameraPositions[index];
|
||||
for (var index1 = 0; index1 < 3; ++index1)
|
||||
{
|
||||
for (var index2 = 1; index2 < vector3Array.Length - 1; ++index2)
|
||||
vector3Array[index2] = (vector3Array[index2 - 1] + vector3Array[index2] + vector3Array[index2 + 1]) / 3f;
|
||||
}
|
||||
this.FilteredCameraPositions = vector3Array;
|
||||
}
|
||||
//创建摄像机在3d空间的距离
|
||||
private void CreateFrameDistances()
|
||||
{
|
||||
var length = this.CameraPositions.Length;
|
||||
this.FrameDistances = new double[length];
|
||||
this.FrameDistances[0] = 0.0;
|
||||
var num = 0.0;
|
||||
for (var index = 1; index < length; ++index)
|
||||
{
|
||||
num += (double)Vector3.Distance(this.CameraPositions[index - 1], this.CameraPositions[index]);
|
||||
this.FrameDistances[index] = num;
|
||||
}
|
||||
}
|
||||
|
||||
//创建轨迹上的转向
|
||||
public void CreateTrajectoryOrientations()
|
||||
{
|
||||
var quaternionArray = new Quaternion[this.FilteredCameraPositions.Length];
|
||||
for (var index = 1; index < this.FilteredCameraPositions.Length - 1; ++index)
|
||||
quaternionArray[index] = Quaternion.LookRotation(this.FilteredCameraPositions[index + 1] - this.FilteredCameraPositions[index - 1], Vector3.up);
|
||||
quaternionArray[0] = quaternionArray[1];
|
||||
quaternionArray[this.FilteredCameraPositions.Length - 1] = quaternionArray[this.FilteredCameraPositions.Length - 2];
|
||||
this.TrajectoryOrientation = quaternionArray;
|
||||
}
|
||||
//获取轨迹上某帧的转向
|
||||
public Quaternion GetTrajectoryOrientationAt(int frame)
|
||||
{
|
||||
var index = Mathf.Clamp(frame, 0, this.FrameCount);
|
||||
if (index <= 0)
|
||||
return this.TrajectoryOrientation[0];
|
||||
return index >= this.FrameCount ? this.TrajectoryOrientation[this.TrajectoryOrientation.Length - 1] : this.TrajectoryOrientation[index];
|
||||
}
|
||||
//鬼区轨迹上模糊帧的转向
|
||||
public Quaternion GetTrajectoryOrientation(float frame)
|
||||
{
|
||||
frame = Mathf.Clamp(frame, 0.0f, (float)this.FrameCount);
|
||||
var index = (int)Math.Ceiling((double)frame);
|
||||
if (index <= 0)
|
||||
return this.TrajectoryOrientation[0];
|
||||
if (index >= this.FrameCount)
|
||||
return this.TrajectoryOrientation[this.TrajectoryOrientation.Length - 1];
|
||||
var t = frame - (float)(index - 1);
|
||||
return Quaternion.Slerp(this.TrajectoryOrientation[index - 1], this.TrajectoryOrientation[index], t);
|
||||
}
|
||||
|
||||
public float GetTrajectoryCurvature(float frame)
|
||||
{
|
||||
var index = (int)Math.Ceiling((double)frame);
|
||||
if (index <= 0)
|
||||
return this.TrajectoryCurvatures[0];
|
||||
if (index >= this.FrameCount)
|
||||
return this.TrajectoryCurvatures[this.TrajectoryCurvatures.Length - 1];
|
||||
var t = frame - (float)(index - 1);
|
||||
return Mathf.Lerp(this.TrajectoryCurvatures[index - 1], this.TrajectoryCurvatures[index], t);
|
||||
}
|
||||
|
||||
public Quaternion GetLightDirection(float distance)
|
||||
{
|
||||
if (this.LightRotations == null || this.LightRotations.Length == 0)
|
||||
return Quaternion.Euler(new Vector3(90f, 0.0f, 0.0f));
|
||||
var index1 = 0;
|
||||
for (var index2 = 0; index2 < this.LightRotationFrames.Length; ++index2)
|
||||
{
|
||||
if ((double)this.LightRotationFrames[index2] < (double)distance)
|
||||
index1 = index2;
|
||||
}
|
||||
if (index1 + 1 == this.LightRotations.Length)
|
||||
return this.LightRotations[this.LightRotations.Length - 1];
|
||||
var t = Mathf.InverseLerp(this.LightRotationFrames[index1], this.LightRotationFrames[index1 + 1], distance);
|
||||
return Quaternion.Slerp(this.LightRotations[index1], this.LightRotations[index1 + 1], t);
|
||||
}
|
||||
|
||||
public float GetShadowIntensity(float distance)
|
||||
{
|
||||
if (this.ShadowIntensities == null || this.ShadowIntensities.Length == 0)
|
||||
return 1f;
|
||||
var index1 = 0;
|
||||
for (var index2 = 0; index2 < this.ShadowIntensityFrames.Length; ++index2)
|
||||
{
|
||||
if ((double)this.ShadowIntensityFrames[index2] < (double)distance)
|
||||
index1 = index2;
|
||||
}
|
||||
if (index1 + 1 == this.ShadowIntensities.Length)
|
||||
return this.ShadowIntensities[this.ShadowIntensities.Length - 1];
|
||||
|
||||
var t = Mathf.InverseLerp(this.ShadowIntensityFrames[index1], this.ShadowIntensityFrames[index1 + 1], distance);
|
||||
return Mathf.Lerp(this.ShadowIntensities[index1], this.ShadowIntensities[index1 + 1], t);
|
||||
}
|
||||
|
||||
public float GetLeftSideOffset(float frame)
|
||||
{
|
||||
if (!this.HasLeftSideOffsets)
|
||||
return this.DefaultLeftSideOffset;
|
||||
var index = Array.BinarySearch<int>(this.LeftSideOffsetFrames, (int)Math.Ceiling((double)frame));
|
||||
if (index < 0)
|
||||
index = ~index;
|
||||
if (index == 0)
|
||||
return this.LeftSideOffsets[0];
|
||||
if (index == this.LeftSideOffsetFrames.Length)
|
||||
return this.LeftSideOffsets[this.LeftSideOffsetFrames.Length - 1];
|
||||
var t = Mathf.InverseLerp((float)this.LeftSideOffsetFrames[index - 1], (float)this.LeftSideOffsetFrames[index], frame);
|
||||
return Mathf.Lerp(this.LeftSideOffsets[index - 1], this.LeftSideOffsets[index], t);
|
||||
}
|
||||
|
||||
public float GetRightSideOffset(float frame)
|
||||
{
|
||||
if (!this.HasRightSideOffsets)
|
||||
return this.DefaultRightSideOffset;
|
||||
var index = Array.BinarySearch<int>(this.RightSideOffsetFrames, (int)Math.Ceiling((double)frame));
|
||||
if (index < 0)
|
||||
index = ~index;
|
||||
if (index == 0)
|
||||
return this.RightSideOffsets[0];
|
||||
return this.RightSideOffsets[0];
|
||||
if (index == this.RightSideOffsetFrames.Length)
|
||||
return this.RightSideOffsets[this.RightSideOffsetFrames.Length - 1];
|
||||
float t = Mathf.InverseLerp((float)this.RightSideOffsetFrames[index - 1], (float)this.RightSideOffsetFrames[index], frame);
|
||||
return Mathf.Lerp(this.RightSideOffsets[index - 1], this.RightSideOffsets[index], t);
|
||||
}
|
||||
|
||||
public void LoadData(ARRouteData data)
|
||||
{
|
||||
this.Visibility = data.Visibility;
|
||||
this.VideoFrameOffset = data.VideoFrameOffset;
|
||||
this.LeftHanded = data.LeftHanded;
|
||||
this.SlamSegments = data.SlamSegments;
|
||||
this.CameraHeight = data.CameraHeight;
|
||||
this.RiderScale = (double)data.RiderScale != 0.0 ? data.RiderScale : 1f;
|
||||
this.CameraPositions = ((IEnumerable<VectorData>)data.CameraPositions).Select<VectorData, Vector3>((Func<VectorData, Vector3>)(x => x.ToUnityVector())).ToArray<Vector3>();
|
||||
this.ProjectionParameters = data.CameraProjectionParameters;
|
||||
this.CameraRotations = ((IEnumerable<VectorData>)data.CameraRotations).Select<VectorData, Quaternion>((Func<VectorData, Quaternion>)(x => Quaternion.Euler(x.ToUnityVector()))).ToArray<Quaternion>();
|
||||
var cameraRotationsRear = data.CameraRotationsRear;
|
||||
this.CameraRotationsRear = cameraRotationsRear != null ? ((IEnumerable<VectorData>)cameraRotationsRear).Select<VectorData, Quaternion>((Func<VectorData, Quaternion>)(x => Quaternion.Euler(x.ToUnityVector()))).ToArray<Quaternion>() : (Quaternion[])null;
|
||||
this.LeftSideOffsetFrames = data.LeftSideOffsetFrames;
|
||||
this.LeftSideOffsets = data.LeftSideOffsets;
|
||||
this.RightSideOffsetFrames = data.RightSideOffsetFrames;
|
||||
this.RightSideOffsets = data.RightSideOffsets;
|
||||
this.CameraRotationsOffset = data.CameraRotationsOffset;
|
||||
this.Lane = data.Lane;
|
||||
if (data.LightRotationFrames == null || data.LightRotationFrames.Length == 0)
|
||||
{
|
||||
this.LightRotationFrames = new float[0];
|
||||
this.LightRotations = new Quaternion[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.LightRotations = ((IEnumerable<VectorData>)data.LightRotations).Select<VectorData, Quaternion>((Func<VectorData, Quaternion>)(x => Quaternion.Euler(x.ToUnityVector()))).ToArray<Quaternion>();
|
||||
this.LightRotationFrames = data.LightRotationFrames;
|
||||
}
|
||||
if (data.ShadowIntensityFrames == null || data.ShadowIntensityFrames.Length == 0)
|
||||
{
|
||||
this.ShadowIntensityFrames = new float[0];
|
||||
this.ShadowIntensities = new float[0];
|
||||
}
|
||||
else
|
||||
{
|
||||
this.ShadowIntensities = data.ShadowIntensities;
|
||||
this.ShadowIntensityFrames = data.ShadowIntensityFrames;
|
||||
}
|
||||
this.SphericalHarmonics = this.LoadSphericalHarmonics(data.SphericalHarmonics);
|
||||
this.CreateFilteredCameraPositions();
|
||||
this.CreateFrameDistances();
|
||||
this.CreateTrajectoryOrientations();
|
||||
this.CreateTrajectoryCurvatures();
|
||||
}
|
||||
|
||||
public ARRouteData ToARRouteData()
|
||||
{
|
||||
var arRouteData = new ARRouteData();
|
||||
arRouteData.Visibility = this.Visibility;
|
||||
arRouteData.VideoFrameOffset = this.VideoFrameOffset;
|
||||
arRouteData.LeftHanded = this.LeftHanded;
|
||||
arRouteData.SlamSegments = this.SlamSegments;
|
||||
arRouteData.CameraHeight = this.CameraHeight;
|
||||
arRouteData.RiderScale = (double)this.RiderScale != 0.0 ? this.RiderScale : 1f;
|
||||
arRouteData.CameraPositions = ((IEnumerable<Vector3>)this.CameraPositions).Select<Vector3, VectorData>((Func<Vector3, VectorData>)(x => new VectorData(x))).ToArray<VectorData>();
|
||||
arRouteData.CameraProjectionParameters = this.ProjectionParameters;
|
||||
arRouteData.CameraRotations = ((IEnumerable<Quaternion>)this.CameraRotations).Select<Quaternion, VectorData>((Func<Quaternion, VectorData>)(x => new VectorData(x.eulerAngles))).ToArray<VectorData>();
|
||||
arRouteData.LeftSideOffsetFrames = this.LeftSideOffsetFrames;
|
||||
arRouteData.LeftSideOffsets = this.LeftSideOffsets;
|
||||
arRouteData.RightSideOffsetFrames = this.RightSideOffsetFrames;
|
||||
arRouteData.RightSideOffsets = this.RightSideOffsets;
|
||||
if (this.LightRotationFrames == null || this.LightRotationFrames.Length == 0)
|
||||
{
|
||||
arRouteData.LightRotationFrames = new float[0];
|
||||
arRouteData.LightRotations = ((IEnumerable<Quaternion>)new Quaternion[0]).Select<Quaternion, VectorData>((Func<Quaternion, VectorData>)(x => new VectorData(x.eulerAngles))).ToArray<VectorData>();
|
||||
}
|
||||
else
|
||||
{
|
||||
arRouteData.LightRotations = ((IEnumerable<Quaternion>)this.LightRotations).Select<Quaternion, VectorData>((Func<Quaternion, VectorData>)(x => new VectorData(x.eulerAngles))).ToArray<VectorData>();
|
||||
arRouteData.LightRotationFrames = this.LightRotationFrames;
|
||||
}
|
||||
if (this.ShadowIntensityFrames == null || this.ShadowIntensityFrames.Length == 0)
|
||||
{
|
||||
arRouteData.ShadowIntensityFrames = new float[1];
|
||||
arRouteData.ShadowIntensities = new float[1] { 1f };
|
||||
}
|
||||
else
|
||||
{
|
||||
arRouteData.ShadowIntensities = this.ShadowIntensities;
|
||||
arRouteData.ShadowIntensityFrames = this.ShadowIntensityFrames;
|
||||
}
|
||||
arRouteData.SphericalHarmonics = this.StoreSphericalHarmonics(this.SphericalHarmonics);
|
||||
return arRouteData;
|
||||
}
|
||||
|
||||
private SphericalHarmonicsL2[] LoadSphericalHarmonics(float[] coefficients)
|
||||
{
|
||||
if (coefficients == null || coefficients.Length == 0)
|
||||
return (SphericalHarmonicsL2[])null;
|
||||
if (coefficients.Length % 27 != 0)
|
||||
throw new ArgumentException("An array of SH coefficients must be divisible by 27.");
|
||||
var num = 0;
|
||||
var sphericalHarmonicsL2Array = new SphericalHarmonicsL2[coefficients.Length / 27];
|
||||
for (var index = 0; index < coefficients.Length / 27; ++index)
|
||||
{
|
||||
for (var rgb = 0; rgb < 3; ++rgb)
|
||||
{
|
||||
for (var coefficient = 0; coefficient < 9; ++coefficient)
|
||||
sphericalHarmonicsL2Array[index][rgb, coefficient] = coefficients[num++];
|
||||
}
|
||||
}
|
||||
return sphericalHarmonicsL2Array;
|
||||
}
|
||||
|
||||
private float[] StoreSphericalHarmonics(SphericalHarmonicsL2[] sphericalHarmonics)
|
||||
{
|
||||
if (sphericalHarmonics == null || sphericalHarmonics.Length == 0)
|
||||
return (float[])null;
|
||||
var num = 0;
|
||||
var numArray = new float[sphericalHarmonics.Length * 27];
|
||||
for (var index = 0; index < sphericalHarmonics.Length; ++index)
|
||||
{
|
||||
for (var rgb = 0; rgb < 3; ++rgb)
|
||||
{
|
||||
for (var coefficient = 0; coefficient < 9; ++coefficient)
|
||||
numArray[num++] = sphericalHarmonics[index][rgb, coefficient];
|
||||
}
|
||||
}
|
||||
return numArray;
|
||||
}
|
||||
|
||||
private void CreateTrajectoryCurvatures()
|
||||
{
|
||||
var cameraPositions = this.CameraPositions;
|
||||
var frameDistances = this.FrameDistances;
|
||||
var length = cameraPositions.Length;
|
||||
var numArray = new float[length];
|
||||
for (var index = 0; index < length; ++index)
|
||||
{
|
||||
var aP1 = cameraPositions[index];
|
||||
var num = frameDistances[index];
|
||||
var filteredCameraPosition1 = this.GetFilteredCameraPosition((float)this.GetFrameAtDistance(num - 10.0));
|
||||
var filteredCameraPosition2 = this.GetFilteredCameraPosition((float)this.GetFrameAtDistance(num + 10.0));
|
||||
Vector3 center;
|
||||
if (!GeometryUtil.CircleCenter(filteredCameraPosition1, aP1, filteredCameraPosition2, out center))
|
||||
{
|
||||
numArray[index] = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
var magnitude = (center - filteredCameraPosition1).magnitude;
|
||||
var normalized = Vector3.Cross(aP1 - filteredCameraPosition1, Vector3.up).normalized;
|
||||
if (((double)center.x - (double)filteredCameraPosition1.x) * (double)normalized.x + ((double)center.y - (double)filteredCameraPosition1.y) * (double)normalized.y + ((double)center.z - (double)filteredCameraPosition1.z) * (double)normalized.z < 0.0)
|
||||
magnitude *= -1f;
|
||||
numArray[index] = 1f / magnitude;
|
||||
}
|
||||
}
|
||||
for (var index1 = 0; index1 < 2; ++index1)
|
||||
{
|
||||
for (var index2 = 1; index2 < numArray.Length - 1; ++index2)
|
||||
numArray[index2] = (float)(((double)numArray[index2 - 1] + (double)numArray[index2] + (double)numArray[index2 + 1]) / 3.0);
|
||||
}
|
||||
this.TrajectoryCurvatures = numArray;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 0a1e61467f8f84048b899dc7815c65ba
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,308 @@
|
||||
using Newtonsoft.Json;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.IO.Compression;
|
||||
using System.Runtime.Serialization;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
[Serializable]
|
||||
public class RouteDetailData
|
||||
{
|
||||
public RouteInfoData RouteInfo;
|
||||
public List<RouteGeometryPointData> Geometry;
|
||||
public List<RouteVideoPointData> VideoPoints;
|
||||
public List<RouteDetailSplitData> Splits;
|
||||
public long Record;
|
||||
public long UserRecord;
|
||||
public static RouteDetailData LoadFromFile(string path)
|
||||
{
|
||||
var jsonSerializer = new JsonSerializer();
|
||||
jsonSerializer.Converters.Add((JsonConverter)new VectorDataConverter());
|
||||
using (var fileStream = File.Open(path, FileMode.Open))
|
||||
{
|
||||
using (var reader1 = new StreamReader(fileStream))
|
||||
{
|
||||
using (var reader2 = new JsonTextReader((TextReader)reader1))
|
||||
return jsonSerializer.Deserialize<RouteDetailData>((JsonReader)reader2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class RouteDetailSplitData
|
||||
{
|
||||
private bool lapFinish;
|
||||
private int lapFinishIndex;
|
||||
public double Distance;
|
||||
public string Name;
|
||||
|
||||
public bool IsLapFinish => this.lapFinish;
|
||||
|
||||
public int LapFinishIndex => !this.IsLapFinish ? -1 : this.lapFinishIndex;
|
||||
|
||||
public void SetLapFinish(bool lapFinish, int lapFinishIndex)
|
||||
{
|
||||
this.lapFinish = lapFinish;
|
||||
this.lapFinishIndex = lapFinishIndex;
|
||||
}
|
||||
|
||||
public override bool Equals(object obj)
|
||||
{
|
||||
if (obj == null || !this.GetType().Equals(obj.GetType()))
|
||||
return false;
|
||||
var routeDetailSplitData = obj as RouteDetailSplitData;
|
||||
return this.Distance == routeDetailSplitData.Distance && string.Equals(this.Name, routeDetailSplitData.Name);
|
||||
}
|
||||
|
||||
public override int GetHashCode()
|
||||
{
|
||||
var hashCode = 23 * 31 + this.Distance.GetHashCode();
|
||||
if (this.Name != null)
|
||||
hashCode = hashCode * 31 + this.Name.GetHashCode();
|
||||
return hashCode;
|
||||
}
|
||||
}
|
||||
|
||||
public class RouteVideoPointData
|
||||
{
|
||||
public double Distance;
|
||||
public double VideoTime;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class RouteInfoData
|
||||
{
|
||||
private double lapLength;
|
||||
private double lapUpclimb;
|
||||
public string Name;
|
||||
public string CountryCode;
|
||||
public string VideoScreen;
|
||||
public string Profile;
|
||||
public int Version;
|
||||
public int Rating;
|
||||
public int RatingCount;
|
||||
public double Length;
|
||||
public int Upclimb;
|
||||
public double MaxSlope;
|
||||
public double AvgSlope;
|
||||
public bool IsFavourite;
|
||||
public string ARFileUrl;
|
||||
public List<RouteVideoData> Videos;
|
||||
public bool SuitableForRunning;
|
||||
public bool SuitableForCycling;
|
||||
public bool IsMultiLap;
|
||||
public int LiveSegmentsCount;
|
||||
|
||||
public bool HasVideo => this.Videos != null && this.Videos.Count > 0;
|
||||
|
||||
public bool IsAr => !string.IsNullOrEmpty(this.ARFileUrl);
|
||||
|
||||
public double LapLength => this.lapLength != 0.0 ? this.lapLength : this.Length;
|
||||
|
||||
public double LapUpclimb => this.lapUpclimb != 0.0 ? this.lapUpclimb : (double)this.Upclimb;
|
||||
|
||||
public void SetLapLength(double lapLength) => this.lapLength = lapLength;
|
||||
|
||||
public void SetLapUpclimb(double lapUpclimb) => this.lapUpclimb = lapUpclimb;
|
||||
}
|
||||
|
||||
public class RouteVideoData
|
||||
{
|
||||
public const int MobileQuality = 540;
|
||||
public const int DesktopQuality = 720;
|
||||
public const int HdQuality = 1080;
|
||||
public const int QhdQuality = 1440;
|
||||
public bool IsOFlow;
|
||||
public int Quality;
|
||||
public string Url;
|
||||
public long Size;
|
||||
|
||||
public static int[] AllQualitites() => new int[4]
|
||||
{
|
||||
540,
|
||||
720,
|
||||
1080,
|
||||
1440
|
||||
};
|
||||
|
||||
public static int[] StreamingQualities() => new int[3]
|
||||
{
|
||||
540,
|
||||
720,
|
||||
1080
|
||||
};
|
||||
}
|
||||
|
||||
public class RouteGeometryPointData
|
||||
{
|
||||
public double Latitude;
|
||||
public double Longitude;
|
||||
public double Distance;
|
||||
public double Altitude;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ARData
|
||||
{
|
||||
public ARRouteData Route;
|
||||
public ARObjectData[] Objects;
|
||||
public ARPanoramaData[] Panoramas;
|
||||
public ARPanoramaData[] Panoramas20;
|
||||
public byte[] SaveToByteData() => EncoderUtils.ToGzipBytes(JsonConvert.SerializeObject((object)this));
|
||||
|
||||
public static ARData LoadFromByteData(byte[] data) => JsonUtility.FromJson<ARData>(EncoderUtils.UncompressGzipToString(data));
|
||||
|
||||
public static ARData LoadFromFile(string path)
|
||||
{
|
||||
var jsonSerializer = new JsonSerializer();
|
||||
jsonSerializer.Converters.Add((JsonConverter)new VectorDataConverter());
|
||||
using (var fileStream = File.Open(path, FileMode.Open))
|
||||
{
|
||||
using (var reader1 = new StreamReader((Stream)fileStream))
|
||||
{
|
||||
using (var reader2 = new JsonTextReader((TextReader)reader1))
|
||||
return jsonSerializer.Deserialize<ARData>((JsonReader)reader2);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public class VectorDataConverter : JsonConverter
|
||||
{
|
||||
public override bool CanConvert(Type objectType) => objectType == typeof(VectorData);
|
||||
|
||||
public override object ReadJson(
|
||||
JsonReader reader,
|
||||
Type objectType,
|
||||
object existingValue,
|
||||
JsonSerializer serializer)
|
||||
{
|
||||
var vectorData = new VectorData();
|
||||
reader.Read();
|
||||
vectorData.x = (float)reader.ReadAsDouble().Value;
|
||||
reader.Read();
|
||||
vectorData.y = (float)reader.ReadAsDouble().Value;
|
||||
reader.Read();
|
||||
vectorData.z = (float)reader.ReadAsDouble().Value;
|
||||
reader.Read();
|
||||
return (object)vectorData;
|
||||
}
|
||||
|
||||
public override void WriteJson(JsonWriter writer, object value, JsonSerializer serializer) => throw new NotImplementedException();
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ARObjectData
|
||||
{
|
||||
[OptionalField]
|
||||
public string Hash;
|
||||
public int ObjectTypeId;
|
||||
public float Distance;
|
||||
public VectorData PositionOffset;
|
||||
public VectorData RotationOffset;
|
||||
public VectorData Scale;
|
||||
public float ManualVisibility;
|
||||
public ARObjectTimeTransformData[] TimeData;
|
||||
public string CustomUrl;
|
||||
public string ArName;
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class ARPanoramaData
|
||||
{
|
||||
public string name;
|
||||
public string url;
|
||||
public float frame;
|
||||
public int visibilityRear;
|
||||
public int visibilityFront;
|
||||
public float[] matrix;
|
||||
}
|
||||
[Serializable]
|
||||
public class ARObjectTimeTransformData
|
||||
{
|
||||
public int Frame;
|
||||
public float Distance;
|
||||
public VectorData PositionOffset;
|
||||
public VectorData RotationOffset;
|
||||
public VectorData Scale;
|
||||
}
|
||||
[Serializable]
|
||||
public class ARRouteData
|
||||
{
|
||||
public int[] Visibility;
|
||||
public VectorData[] CameraPositions;
|
||||
public VectorData[] CameraRotations;
|
||||
public VectorData[] CameraRotationsRear;
|
||||
public float[] LightRotationFrames;
|
||||
public VectorData[] LightRotations;
|
||||
public float[] ShadowIntensityFrames;
|
||||
public float[] ShadowIntensities;
|
||||
public float[] SphericalHarmonics;
|
||||
public int[] SlamSegments;
|
||||
public CameraProjectionParameters[] CameraProjectionParameters;
|
||||
public bool LeftHanded;
|
||||
public int VideoFrameOffset;
|
||||
public int VideoFrameOffsetMac = -1;
|
||||
public float CameraHeight;
|
||||
public float RiderScale = 1f;
|
||||
public int[] LeftSideOffsetFrames;
|
||||
public float[] LeftSideOffsets;
|
||||
public int[] RightSideOffsetFrames;
|
||||
public float[] RightSideOffsets;
|
||||
public VectorData CameraRotationsOffset;
|
||||
public float Lane;
|
||||
}
|
||||
public class VectorData
|
||||
{
|
||||
public float x;
|
||||
public float y;
|
||||
public float z;
|
||||
|
||||
public Vector3 ToUnityVector() => new Vector3(this.x, this.y, this.z);
|
||||
|
||||
public VectorData()
|
||||
{
|
||||
}
|
||||
|
||||
public VectorData(Vector3 unityVector)
|
||||
{
|
||||
this.x = unityVector.x;
|
||||
this.y = unityVector.y;
|
||||
this.z = unityVector.z;
|
||||
}
|
||||
}
|
||||
|
||||
[Serializable]
|
||||
public class CameraProjectionParameters
|
||||
{
|
||||
public float alpha;
|
||||
public float beta;
|
||||
public float cx;
|
||||
public float cy;
|
||||
|
||||
public CameraProjectionParameters Clone() => new CameraProjectionParameters()
|
||||
{
|
||||
alpha = this.alpha,
|
||||
beta = this.beta,
|
||||
cx = this.cx,
|
||||
cy = this.cy
|
||||
};
|
||||
|
||||
public static CameraProjectionParameters Lerp(
|
||||
CameraProjectionParameters a,
|
||||
CameraProjectionParameters b,
|
||||
float t)
|
||||
{
|
||||
return new CameraProjectionParameters()
|
||||
{
|
||||
alpha = Mathf.Lerp(a.alpha, b.alpha, t),
|
||||
beta = Mathf.Lerp(a.beta, b.beta, t),
|
||||
cx = Mathf.Lerp(a.cx, b.cx, t),
|
||||
cy = Mathf.Lerp(a.cy, b.cy, t)
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: f4aaeffc1df7bde4880cda54a3cfaf61
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,777 @@
|
||||
using System;
|
||||
using System.Linq;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using RenderHeads.Media.AVProVideo;
|
||||
using Assets.Scripts.Scenes.VideoRide;
|
||||
using Assets.Scenes.Ride.Scripts.Model.RiderModels;
|
||||
using UnityEngine.Assertions;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class ARTrainingController : ARLaneGameObjectsController
|
||||
{
|
||||
public MediaPlayer mediaPlayer;
|
||||
private ARData aRData;
|
||||
private RouteDetailData detail;
|
||||
private VideoPointsSync videoPointsSync;
|
||||
private readonly List<ARLaneGameObject> collisionList = new List<ARLaneGameObject>();
|
||||
ARVideoPlayerControl VideoPlayerControl;
|
||||
ARLaneGameObject[] rides { get; set; }
|
||||
public ARLaneGameObject mainRiderObject { get; set; }
|
||||
public Light arLight;
|
||||
private Light arBackLight { get; set; }
|
||||
public CameraDistance RiderCameraDistance { get; set; }
|
||||
public VideoPlayMode VideoControlMode { get; private set; }
|
||||
private float autoCameraSwitchTimeCounter = 80f;
|
||||
float timers = 0f;
|
||||
private VideoGameManager manager;
|
||||
public int VisibleModels { get; private set; }
|
||||
private int visibleModelsLimit = 20;
|
||||
public int VisibleRiderTitlesLimit => this.VisibleModelsLimit + 10;
|
||||
public int VisibleModelsLimit
|
||||
{
|
||||
get => this.visibleModelsLimit;
|
||||
set => this.visibleModelsLimit = Mathf.Clamp(value, 20, 100);
|
||||
}
|
||||
private Dictionary<int, VisibleRiderItem> visibleRiders = new Dictionary<int, VisibleRiderItem>();
|
||||
private Dictionary<int, OnlineRiderModel> riders = new Dictionary<int, OnlineRiderModel>();
|
||||
//private Dictionary<int, UIRect> riderNameViews { get; set; } //= new Dictionary<int, UIRect>();
|
||||
//private Dictionary<int, RiderValueView> riderValueViews = new Dictionary<int, RiderValueView>();
|
||||
|
||||
public GameObject BikerFemalePrefab => Resources.Load<GameObject>("UI/Prefab/AR/VidePlayer");
|
||||
|
||||
public GameObject BikerMalePrefab => Resources.Load<GameObject>("UI/Prefab/AR/VidePlayer_NV");
|
||||
|
||||
private bool paused { get; set; }
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
this.arObjects.Clear();
|
||||
manager = GetComponent<VideoGameManager>();
|
||||
}
|
||||
|
||||
public void Initialize(ARData arData, RouteDetailData routeDetailData)
|
||||
{
|
||||
//ar数据加载本地,本地没有就下载
|
||||
this.aRData = arData;
|
||||
this.detail = routeDetailData;
|
||||
|
||||
this.RiderCameraDistance = AR.CameraDistance.Middle;
|
||||
videoPointsSync = new VideoPointsSync(detail.VideoPoints.Select(c => new VideoPoint()
|
||||
{
|
||||
Distance = (float)c.Distance,
|
||||
Time = (float)c.VideoTime
|
||||
}));
|
||||
videoSync = videoPointsSync;
|
||||
this.VideoPlayerControl = new ARVideoPlayerControl
|
||||
{
|
||||
VideoSyncSource = videoSync
|
||||
};
|
||||
|
||||
this.videoPlayer = mediaPlayer.gameObject.AddComponent<AVProVideoPlayer>();
|
||||
this.videoPlayer.videoPlayer = mediaPlayer;
|
||||
|
||||
SetArRoute(new ARRoute(aRData.Route), videoSync, videoPlayer);
|
||||
|
||||
this.VideoPlayerControl.VideoFrameOffset = this.Route.VideoFrameOffset;
|
||||
this.VideoPlayerControl.Route = Route;
|
||||
this.VideoPlayerControl.SetVideoPlayer(videoPlayer);
|
||||
|
||||
rides = FindObjectsOfType<ARLaneGameObject>();
|
||||
SetUpLight();
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (videoPlayer == null ) return;
|
||||
|
||||
timers -= Time.deltaTime;
|
||||
while (timers <= 0)
|
||||
{
|
||||
UpdateRiders();
|
||||
RemoveRiders();
|
||||
timers += 0.2f;
|
||||
}
|
||||
|
||||
if (mainRiderObject == null || Route == null)
|
||||
{
|
||||
videoPlayer.Pause();
|
||||
return;
|
||||
}
|
||||
|
||||
PlayFrameDistance();
|
||||
VideoPlayerControl.UpdateVideoPlayRate(mainRiderObject.PreSpeed, mainRiderObject.Distance);
|
||||
FrameIndexDistanceCorrection = this.VideoPlayerControl.FrameIndexDistanceCorrection;
|
||||
UpdateCameraFollowDistance();
|
||||
|
||||
base.Update();
|
||||
UpdateRidersVisibility();
|
||||
UpdateRidersLean();
|
||||
UpdateBackLight();
|
||||
SetUpVideoControlMode();
|
||||
UpdateRemainingTime();
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 处理人物快倒计时
|
||||
/// </summary>
|
||||
private void UpdateRemainingTime()
|
||||
{
|
||||
if (mainRiderObject == null) return;
|
||||
var remainingDistance = Math.Round(manager.GetMapRoute().Distance * 1000f - mainRiderObject.Distance);
|
||||
manager.ShowUpRemainTime(remainingDistance);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 更新骑行者的实时数据
|
||||
/// </summary>
|
||||
private void UpdateRiders()
|
||||
{
|
||||
foreach (var dic in manager.rideObjs)
|
||||
{
|
||||
var item = dic.Value;
|
||||
if (!this.arObjects.Contains(item))
|
||||
this.arObjects.Add(item);
|
||||
if (!this.riderObjects.ContainsKey(item.UserId))
|
||||
this.riderObjects.Add(item.UserId, item);
|
||||
|
||||
item.PreSpeed = item.Speed;
|
||||
item.Speed = (float)dic.Key.OnlineSpeed;
|
||||
item.DeltaDistance = (float)(dic.Key.EndDistance - dic.Key.PreDistance);
|
||||
item.Route = Route;
|
||||
item.VideoSync = videoPointsSync;
|
||||
item.IsAtFinish = dic.Key.EndDistance >= manager.GetMapRoute().Distance*1000f;
|
||||
|
||||
if (dic.Key.UserId != manager.CurrentUserId) continue;
|
||||
mainRiderObject = item;
|
||||
//如果速度为0就停止播放视频
|
||||
if (item.DeltaDistance == 0 || item.Speed == 0)
|
||||
{
|
||||
item.DeltaDistance = 0;
|
||||
videoPlayer.Pause();
|
||||
}
|
||||
else
|
||||
{
|
||||
videoPlayer.Resume();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 移除不可见的骑行者
|
||||
/// </summary>
|
||||
private void RemoveRiders()
|
||||
{
|
||||
this.arObjects.RemoveAll(c => !manager.rideObjs.Select(m => m.Key.UserId.ToString()).Contains(c.UserId.ToString()));
|
||||
|
||||
var keys = riderObjects.Keys.ToList();
|
||||
foreach (var item in keys.Where(item => manager.rideObjs.Keys.All(c => c.UserId != item)))
|
||||
{
|
||||
riderObjects.Remove(item);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 将每秒的距离转换为每帧的距离
|
||||
/// </summary>
|
||||
private void PlayFrameDistance()
|
||||
{
|
||||
var delta = Time.deltaTime;
|
||||
foreach (var obj in this.riderObjects.Values.Where(obj => obj.DeltaDistance != 0))
|
||||
{
|
||||
obj.Distance = Mathf.Lerp(obj.Distance, obj.Distance + obj.DeltaDistance, delta);
|
||||
obj.RouteDistance = Mathf.Lerp(obj.RouteDistance, obj.RouteDistance + obj.DeltaDistance, delta);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置camera的跟随距离
|
||||
/// </summary>
|
||||
private void SetUpVideoControlMode()
|
||||
{
|
||||
if (Input.GetKeyDown(KeyCode.F))
|
||||
this.SetVideoControlMode(VideoPlayMode.Front);
|
||||
if (Input.GetKeyDown(KeyCode.P))
|
||||
this.SetVideoControlMode(VideoPlayMode.AutoPanorama);
|
||||
if (!Input.GetKeyDown(KeyCode.B))
|
||||
return;
|
||||
this.SetVideoControlMode(VideoPlayMode.Rear);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// 设置光线
|
||||
/// </summary>
|
||||
private void SetUpLight()
|
||||
{
|
||||
this.arLight.type = LightType.Directional;
|
||||
this.arLight.transform.rotation = Quaternion.Euler(90f, 0.0f, 0.0f);
|
||||
this.arLight.shadows = LightShadows.Soft;
|
||||
this.arLight.shadowStrength = 1f;
|
||||
|
||||
var gameObject2 = new GameObject("ARBackLight");
|
||||
gameObject2.layer = this.gameObject.layer;
|
||||
gameObject2.transform.SetParent(this.transform);
|
||||
this.arBackLight = gameObject2.AddComponent<Light>();
|
||||
this.arBackLight.type = LightType.Directional;
|
||||
this.arBackLight.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
|
||||
this.arBackLight.shadows = LightShadows.None;
|
||||
this.arBackLight.intensity = 0.5f;
|
||||
}
|
||||
|
||||
public void SetVideoControlMode(VideoPlayMode mode)
|
||||
{
|
||||
if (mode == this.VideoControlMode)
|
||||
return;
|
||||
if (!this.AR360Version)
|
||||
mode = VideoPlayMode.Front;
|
||||
this.VideoControlMode = mode;
|
||||
this.autoCameraSwitchTimeCounter = 80f;
|
||||
if (mode == VideoPlayMode.AutoPanorama)
|
||||
return;
|
||||
this.videoPlayer.IntendedRear = mode == VideoPlayMode.Rear;
|
||||
}
|
||||
//更新摄像机的位置
|
||||
private void UpdateCameraFollowDistance()
|
||||
{
|
||||
var cameraFollowDistance = GetCameraFollowDistance(this.RiderCameraDistance);
|
||||
this.VideoPlayerControl.CameraFollowDistance = cameraFollowDistance;
|
||||
}
|
||||
//人物是否显示
|
||||
protected override bool IsObjectActive(ARGameObject arObject)
|
||||
{
|
||||
var flag = base.IsObjectActive(arObject);
|
||||
if (arObject != this.mainRiderObject)
|
||||
return flag;
|
||||
if ((double)this.VideoPlayerControl.CameraFollowDistance > 0.0 || this.AR360Version)
|
||||
return flag;
|
||||
return flag && (double)this.VideoPlayerControl.CameraDistanceError > 5.0;
|
||||
}
|
||||
//获取摄像机的位置
|
||||
public static float GetCameraFollowDistance(CameraDistance distance)
|
||||
{
|
||||
switch (distance)
|
||||
{
|
||||
case AR.CameraDistance.FirstPerson:
|
||||
return 0.0f;
|
||||
case AR.CameraDistance.Near:
|
||||
return 1.5f;
|
||||
case AR.CameraDistance.Middle:
|
||||
return 8f;
|
||||
case AR.CameraDistance.Far:
|
||||
return 10f;
|
||||
default:
|
||||
throw new ArgumentException("Unknown rider's camera distance.");
|
||||
}
|
||||
}
|
||||
//添加骑手
|
||||
public void AddRider(OnlineRiderModel rider)
|
||||
{
|
||||
if (this.riders.ContainsKey(rider.UserId))
|
||||
return;
|
||||
this.riders.Add(rider.UserId, rider);
|
||||
}
|
||||
//移除骑手
|
||||
public void RemoveRider(int riderId)
|
||||
{
|
||||
if (!this.riders.ContainsKey(riderId))
|
||||
return;
|
||||
this.riders.Remove(riderId);
|
||||
this.DestroyRider(riderId);
|
||||
this.DestroyRiderTitle(riderId);
|
||||
}
|
||||
//创建人物
|
||||
private AbstractRenderer CreateRiderModel(OnlineRiderModel rider, float lane)
|
||||
{
|
||||
GameObject gameObject;
|
||||
PlayerRenderer riderModel;
|
||||
if (rider.Sex == 1)
|
||||
{
|
||||
gameObject = UnityEngine.Object.Instantiate<GameObject>(this.BikerMalePrefab);
|
||||
gameObject.name = "RiderMale " + rider.UserId.ToString();
|
||||
riderModel = gameObject.AddComponent<PlayerRenderer>();
|
||||
riderModel.Initialize(true, false);
|
||||
}
|
||||
else
|
||||
{
|
||||
gameObject = UnityEngine.Object.Instantiate<GameObject>(this.BikerFemalePrefab);
|
||||
gameObject.name = "RiderFemale " + rider.UserId.ToString();
|
||||
riderModel = gameObject.AddComponent<PlayerRenderer>();
|
||||
riderModel.Initialize(false, false);
|
||||
}
|
||||
gameObject.transform.parent = this.transform;
|
||||
gameObject.transform.position = ARGameObjectsController.DefaultObjectPosition;
|
||||
//gameObject.layer = 9;
|
||||
riderModel.Route = this.Route;
|
||||
riderModel.VideoSync = this.videoSync;
|
||||
//riderModel.VideoPlayer = this.videoPlayer;
|
||||
//riderModel.ColorUser = rider.UserColor;
|
||||
//riderModel.ColorSkin = rider.SkinColor;
|
||||
// ModelTexturesList modelTextures = this.GetModelTextures(rider.JerseyId);
|
||||
//riderModel.JerseyTexture = modelTextures.JerseyTexture;
|
||||
//riderModel.HelmTexture = modelTextures.HelmTexture;
|
||||
//riderModel.BikeTexture = modelTextures.BikeTexture;
|
||||
if ((double)lane != -1.0)
|
||||
riderModel.Lane = lane;
|
||||
this.riderObjects.Add(rider.UserId, (ARLaneGameObject)riderModel);
|
||||
this.arObjects.Add((ARGameObject)riderModel);
|
||||
//是否
|
||||
if (this.IsMainRider(rider))
|
||||
this.mainRiderObject = (ARLaneGameObject)riderModel;
|
||||
return (AbstractRenderer)riderModel;
|
||||
}
|
||||
|
||||
private ARLaneGameObject CreateRiderObject(OnlineRiderModel rider, float lane)
|
||||
{
|
||||
ARLaneGameObject riderObject = new GameObject("RiderObject " + rider.UserId.ToString())
|
||||
{
|
||||
transform = {
|
||||
parent = this.transform
|
||||
},
|
||||
//layer = 9
|
||||
}.AddComponent<ARLaneGameObject>();
|
||||
riderObject.Route = this.Route;
|
||||
riderObject.VideoSync = this.videoSync;
|
||||
//riderObject.VideoPlayer = this.videoPlayer;
|
||||
if ((double)lane != -1.0)
|
||||
riderObject.Lane = lane;
|
||||
this.riderObjects.Add(rider.UserId, riderObject);
|
||||
this.arObjects.Add((ARGameObject)riderObject);
|
||||
if (this.IsMainRider(rider))
|
||||
this.mainRiderObject = riderObject;
|
||||
return riderObject;
|
||||
}
|
||||
//销毁骑手
|
||||
private void DestroyRider(int riderId)
|
||||
{
|
||||
ARLaneGameObject arLaneObject;
|
||||
if (!this.riderObjects.TryGetValue(riderId, out arLaneObject))
|
||||
return;
|
||||
this.arObjects.Remove((ARGameObject)arLaneObject);
|
||||
this.riderObjects.Remove(riderId);
|
||||
if ((UnityEngine.Object)arLaneObject == (UnityEngine.Object)this.mainRiderObject)
|
||||
this.mainRiderObject = (ARLaneGameObject)null;
|
||||
UnityEngine.Object.Destroy((UnityEngine.Object)arLaneObject.gameObject);
|
||||
}
|
||||
//创建骑行人员头顶的名字
|
||||
private void CreateRiderTitle(OnlineRiderModel rider)
|
||||
{
|
||||
//RiderNameView riderNameView = UIRect.Create<RiderNameView>(this.transform, "Name " + rider.Id.ToString());
|
||||
//riderNameView.RectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
//riderNameView.gameObject.layer = 9;
|
||||
//riderNameView.NameLabel.Font = Fonts.WorkSansBlack;
|
||||
//riderNameView.SetName(rider.NameShort);
|
||||
//switch (rider)
|
||||
//{
|
||||
// case GhostRider _:
|
||||
// riderNameView.SetAvatarResourceIcon(AvatarView.IconType.Ghost);
|
||||
// riderNameView.SetAvatarBorderColor(rider.UserColor);
|
||||
// riderNameView.SetAvatarBorderWidth(2f);
|
||||
// break;
|
||||
// case StravaRider stravaRider:
|
||||
// switch (stravaRider.EffortType)
|
||||
// {
|
||||
// case EffortType.Kom:
|
||||
// riderNameView.SetAvatarResourceIcon(AvatarView.IconType.StravaKom);
|
||||
// break;
|
||||
// case EffortType.Qom:
|
||||
// riderNameView.SetAvatarResourceIcon(AvatarView.IconType.StravaQom);
|
||||
// break;
|
||||
// case EffortType.Pr:
|
||||
// riderNameView.SetAvatarResourceIcon(AvatarView.IconType.StravaPr);
|
||||
// break;
|
||||
// }
|
||||
// riderNameView.SetAvatarBorderColor(Color.clear);
|
||||
// riderNameView.SetAvatarBorderWidth(0.0f);
|
||||
// break;
|
||||
// default:
|
||||
// riderNameView.SetAvatarUrl(rider.AvatarUrl);
|
||||
// riderNameView.SetAvatarBorderColor(rider.UserColor);
|
||||
// riderNameView.SetAvatarBorderWidth(2f);
|
||||
// break;
|
||||
//}
|
||||
//riderNameView.BackgroundColor = this.GetRiderTitleBackgroundColor(rider);
|
||||
//riderNameView.SetCornerRadius(float.MaxValue);
|
||||
//riderNameView.TrimSize();
|
||||
//this.riderNameViews.Add(rider.Id, (UIRect)riderNameView);
|
||||
//if (rider is StravaRider)
|
||||
// return;
|
||||
//RiderValueView riderValueView = UIRect.Create<RiderValueView>(this.transform, "Value " + rider.Id.ToString());
|
||||
//riderValueView.RectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
//riderValueView.gameObject.layer = 9;
|
||||
//this.riderValueViews.Add(rider.Id, riderValueView);
|
||||
}
|
||||
private void CreateRiderTitleObject(OnlineRiderModel rider)
|
||||
{
|
||||
//UIRect uiRect = UIRect.Create<UIRect>(this.transform, "TitleObject " + rider.Id.ToString());
|
||||
//uiRect.Size = new Vector2(150f, 26f);
|
||||
//uiRect.RectTransform.pivot = new Vector2(0.5f, 0.5f);
|
||||
//uiRect.gameObject.layer = 9;
|
||||
//uiRect.AddComponent<Canvas>().renderMode = RenderMode.WorldSpace;
|
||||
//uiRect.AddComponent<BoxCollider>().size = (Vector3)uiRect.Size;
|
||||
//this.riderNameViews.Add(rider.Id, uiRect);
|
||||
}
|
||||
private void DestroyRiderTitle(int riderId)
|
||||
{
|
||||
//UIRect uiRect;
|
||||
//if (this.riderNameViews.TryGetValue(riderId, out uiRect))
|
||||
//{
|
||||
// this.riderNameViews.Remove(riderId);
|
||||
// UnityEngine.Object.Destroy((UnityEngine.Object)uiRect.gameObject);
|
||||
//}
|
||||
//RiderValueView riderValueView;
|
||||
//if (!this.riderValueViews.TryGetValue(riderId, out riderValueView))
|
||||
// return;
|
||||
//this.riderValueViews.Remove(riderId);
|
||||
//UnityEngine.Object.Destroy((UnityEngine.Object)riderValueView.gameObject);
|
||||
}
|
||||
private void UpdateRidersVisibility()
|
||||
{
|
||||
if (!this.videoPlayer.Initialized)
|
||||
return;
|
||||
this.UpdateVisibleRiders();
|
||||
return;
|
||||
//删除当前道路上应该消失的骑手
|
||||
foreach (int num in this.riderObjects.Keys.ToArray<int>())
|
||||
{
|
||||
if (!this.visibleRiders.ContainsKey(num))
|
||||
{
|
||||
ARLaneGameObject riderObject = this.riderObjects[num];
|
||||
if (!riderObject.IsAtFinish || (double)riderObject.VisibilityLevel <= 0.0)
|
||||
{
|
||||
this.DestroyRider(num);
|
||||
this.DestroyRiderTitle(num);
|
||||
}
|
||||
}
|
||||
}
|
||||
//新增应该显示的骑手
|
||||
foreach (VisibleRiderItem visibleRiderItem in this.visibleRiders.Values)
|
||||
{
|
||||
var rider = visibleRiderItem.Rider;
|
||||
bool showModel = visibleRiderItem.ShowModel;
|
||||
ARLaneGameObject arLaneObject;
|
||||
//二次检查
|
||||
if (this.riderObjects.TryGetValue(rider.UserId, out arLaneObject))
|
||||
{
|
||||
if (arLaneObject is AbstractRenderer)
|
||||
{
|
||||
if (!showModel)
|
||||
{
|
||||
float lane = arLaneObject.Lane;
|
||||
this.DestroyRider(rider.UserId);
|
||||
this.CreateRiderObject(rider, lane);
|
||||
}
|
||||
}
|
||||
else if (showModel)
|
||||
{
|
||||
float lane = arLaneObject.Lane;
|
||||
this.DestroyRider(rider.UserId);
|
||||
this.CreateRiderModel(rider, lane);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if (showModel)
|
||||
this.CreateRiderModel(rider, visibleRiderItem.Lane);
|
||||
else
|
||||
this.CreateRiderObject(rider, visibleRiderItem.Lane);
|
||||
this.CreateRiderTitleObject(rider);
|
||||
}
|
||||
}
|
||||
}
|
||||
private void UpdateVisibleRiders()
|
||||
{
|
||||
var visibilityModels = ARGameObject.MaxDistanceVisibilityModels;
|
||||
var visibilityDistance = this.MaximumVisibilityDistance;
|
||||
var routeDistance = this.CameraDistance;
|
||||
var flag = this.AllowStartOrder && (double)routeDistance < 200.0;
|
||||
var num1 = flag ? visibilityModels : visibilityDistance;
|
||||
var a1 = this.videoPlayer.IsRear ? visibilityDistance : 1f;
|
||||
var riderTitlesLimit = this.VisibleRiderTitlesLimit;
|
||||
var a2 = 5;
|
||||
|
||||
var num2 = Mathf.Max(a1, this.GetOvertakingThreshold(routeDistance) + 1f);
|
||||
var distance1 = routeDistance - num2;
|
||||
var distance2 = routeDistance + num1;
|
||||
float num3;
|
||||
if (flag)
|
||||
{
|
||||
num3 = this.StartRegionRouteWidth;
|
||||
}
|
||||
else
|
||||
{
|
||||
var videoFrameAtDistance1 = this.videoSync.GetVideoFrameAtDistance(distance1);
|
||||
var videoFrameAtDistance2 = this.videoSync.GetVideoFrameAtDistance(distance2);
|
||||
num3 = (float)(0.5 * ((double)(this.Route.GetLeftSideOffset(videoFrameAtDistance1) + this.Route.GetRightSideOffset(videoFrameAtDistance1)) + (double)(this.Route.GetLeftSideOffset(videoFrameAtDistance2) + this.Route.GetRightSideOffset(videoFrameAtDistance2))));
|
||||
}
|
||||
var num4 = num3 / 0.7f;
|
||||
var num5 = this.paused ? 0.0f : 0.5f;
|
||||
var maxLane = Math.Max(0.0f, num4 - num5);
|
||||
var visibleRiderItemList1 = new List<VisibleRiderItem>();
|
||||
var visibleRiderItemList2 = new List<VisibleRiderItem>();
|
||||
|
||||
var routeRiders = this.riders.Values;
|
||||
|
||||
foreach (var rider in routeRiders)
|
||||
{
|
||||
if (!rider.IsFinished)
|
||||
{
|
||||
float modelRouteDistance = this.GetRouteDistance(0, (float)rider.RouteDistance);
|
||||
float num6 = modelRouteDistance - routeDistance;
|
||||
if (this.IsMultilap)
|
||||
{
|
||||
if ((double)modelRouteDistance + this.lapLength >= (double)distance1 && (double)modelRouteDistance + this.lapLength <= (double)distance2)
|
||||
num6 = modelRouteDistance + (float)this.lapLength - routeDistance;
|
||||
else if ((double)modelRouteDistance - this.lapLength >= (double)distance1 && (double)modelRouteDistance - this.lapLength <= (double)distance2)
|
||||
num6 = modelRouteDistance - (float)this.lapLength - routeDistance;
|
||||
}
|
||||
if ((double)num6 > -(double)num2 && (double)num6 < (double)num1)
|
||||
{
|
||||
float num7 = -1f;
|
||||
ARLaneGameObject laneObject;
|
||||
if (this.riderObjects.TryGetValue(rider.UserId, out laneObject))
|
||||
{
|
||||
if ((double)laneObject.Lane > (double)num4)
|
||||
{
|
||||
if (this.IsMainRider(rider))
|
||||
{
|
||||
laneObject.Lane = num4;
|
||||
laneObject.DeltaLane = 0.0f;
|
||||
this.UpdateRiderCurvature(laneObject, 0.0f, Time.deltaTime);
|
||||
this.UpdateLaneChangingDirection(laneObject, 0.0f, Time.deltaTime);
|
||||
}
|
||||
else
|
||||
continue;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
num7 = this.GetLane((float)rider.RouteDistance, modelRouteDistance);
|
||||
if ((double)num7 > (double)maxLane)
|
||||
{
|
||||
if (this.IsMainRider(rider))
|
||||
num7 = num4;
|
||||
else
|
||||
continue;
|
||||
}
|
||||
}
|
||||
VisibleRiderItem visibleRiderItem = new VisibleRiderItem()
|
||||
{
|
||||
Rider = rider,
|
||||
DeltaDistance = num6,
|
||||
ModelDistance = modelRouteDistance,
|
||||
Lane = num7
|
||||
};
|
||||
if ((double)num6 < 0.0)
|
||||
visibleRiderItemList1.Add(visibleRiderItem);
|
||||
else
|
||||
visibleRiderItemList2.Add(visibleRiderItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
visibleRiderItemList1.Sort((Comparison<VisibleRiderItem>)((p1, p2) => p2.DeltaDistance.CompareTo(p1.DeltaDistance)));
|
||||
visibleRiderItemList2.Sort((Comparison<VisibleRiderItem>)((p1, p2) => p1.DeltaDistance.CompareTo(p2.DeltaDistance)));
|
||||
this.RemoveRidersOutside(visibleRiderItemList1, maxLane);
|
||||
this.RemoveRidersOutside(visibleRiderItemList2, maxLane);
|
||||
this.PrioritizeRider(visibleRiderItemList1, (Predicate<VisibleRiderItem>)(i => this.IsMainRider(i.Rider)));
|
||||
this.PrioritizeRider(visibleRiderItemList2, (Predicate<VisibleRiderItem>)(i => this.IsMainRider(i.Rider)));
|
||||
var visibleRiderItemList3 = new List<VisibleRiderItem>();
|
||||
if (!this.videoPlayer.IsRear)
|
||||
{
|
||||
int num8 = Mathf.Min(a2, visibleRiderItemList1.Count);
|
||||
for (int index = 0; index < num8; ++index)
|
||||
visibleRiderItemList3.Add(visibleRiderItemList1[index]);
|
||||
int num9 = Mathf.Min(riderTitlesLimit - num8, visibleRiderItemList2.Count);
|
||||
for (int index = 0; index < num9; ++index)
|
||||
visibleRiderItemList3.Add(visibleRiderItemList2[index]);
|
||||
}
|
||||
else
|
||||
{
|
||||
int num10 = Mathf.Min(a2, visibleRiderItemList2.Count);
|
||||
for (int index = 0; index < num10; ++index)
|
||||
visibleRiderItemList3.Add(visibleRiderItemList2[index]);
|
||||
int num11 = Mathf.Min(riderTitlesLimit - num10, visibleRiderItemList1.Count);
|
||||
for (int index = 0; index < num11; ++index)
|
||||
visibleRiderItemList3.Add(visibleRiderItemList1[index]);
|
||||
}
|
||||
int num12 = 0;
|
||||
this.visibleRiders.Clear();
|
||||
foreach (VisibleRiderItem visibleRiderItem in visibleRiderItemList3)
|
||||
{
|
||||
var rider = visibleRiderItem.Rider;
|
||||
float num13 = Mathf.Abs(visibleRiderItem.DeltaDistance);
|
||||
if ((double)num13 < (double)visibilityModels - 5.0)
|
||||
{
|
||||
if (num12 < this.VisibleModelsLimit)
|
||||
{
|
||||
visibleRiderItem.ShowModel = true;
|
||||
this.visibleRiders.Add(rider.UserId, visibleRiderItem);
|
||||
++num12;
|
||||
}
|
||||
}
|
||||
else if ((double)num13 < (double)visibilityDistance - 5.0 && this.visibleRiders.Count < this.VisibleRiderTitlesLimit)
|
||||
{
|
||||
visibleRiderItem.ShowModel = false;
|
||||
this.visibleRiders.Add(rider.UserId, visibleRiderItem);
|
||||
}
|
||||
}
|
||||
this.VisibleModels = num12;
|
||||
}
|
||||
|
||||
private void PrioritizeRider(
|
||||
List<VisibleRiderItem> list,
|
||||
Predicate<VisibleRiderItem> predicate)
|
||||
{
|
||||
int index = list.FindIndex(predicate);
|
||||
if (index == -1)
|
||||
return;
|
||||
var visibleRiderItem = list[index];
|
||||
list.RemoveAt(index);
|
||||
list.Insert(0, visibleRiderItem);
|
||||
}
|
||||
private void RemoveRidersOutside(
|
||||
List<VisibleRiderItem> sortedList,
|
||||
float maxLane)
|
||||
{
|
||||
VisibleRiderItem visibleRiderItem = (VisibleRiderItem)null;
|
||||
foreach (VisibleRiderItem sorted in sortedList)
|
||||
{
|
||||
//排除当前骑行的主人公和分区组长
|
||||
if ((double)sorted.Lane != -1.0 && !this.IsMainRider(sorted.Rider))
|
||||
{
|
||||
if (visibleRiderItem == null)
|
||||
{
|
||||
visibleRiderItem = sorted;
|
||||
}
|
||||
else
|
||||
{
|
||||
float routeDistance1 = (float)visibleRiderItem.Rider.RouteDistance;
|
||||
float routeDistance2 = (float)sorted.Rider.RouteDistance;
|
||||
float collisionParameter = ARLaneGameObjectsController.GetCollisionParameter(routeDistance1, routeDistance2, this.GetOvertakingThreshold(routeDistance1));
|
||||
sorted.Lane += collisionParameter;
|
||||
if ((double)sorted.Lane > (double)maxLane)
|
||||
sorted.Lane = float.MaxValue;
|
||||
else
|
||||
visibleRiderItem = sorted;
|
||||
}
|
||||
}
|
||||
}
|
||||
sortedList.RemoveAll((Predicate<VisibleRiderItem>)(i => (double)i.Lane == 3.4028234663852886E+38));
|
||||
}
|
||||
|
||||
private bool IsMainRider(OnlineRiderModel rider) => rider.IsSelf;
|
||||
|
||||
//更新骑手的偏移角度
|
||||
private void UpdateRidersLean()
|
||||
{
|
||||
foreach (ARLaneGameObject riderObject in this.riderObjects.Values)
|
||||
{
|
||||
float num1 = this.Route.GetTrajectoryCurvature(riderObject.Frame) + riderObject.Curvature;
|
||||
float z1;
|
||||
if ((double)num1 == 0.0)
|
||||
{
|
||||
z1 = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
double speed = riderObject.Speed;
|
||||
float f = 57.29578f * Mathf.Atan((float)(speed * speed * (double)num1 / 9.81));
|
||||
float num2 = (double)f >= 0.0 ? 1f : -1f;
|
||||
float num3 = Mathf.Abs(f);
|
||||
if ((double)num3 > 20.0)
|
||||
f = (float)((double)Mathf.Atan((float)(((double)num3 - 20.0) / 10.5)) * 10.5 + 20.0) * num2;
|
||||
float num4 = Mathf.Clamp(f, -35f, 35f);
|
||||
float z2 = riderObject.Lean.z;
|
||||
z1 = Mathf.Clamp(num4, z2 - 60f * Time.deltaTime, z2 + 60f * Time.deltaTime);
|
||||
}
|
||||
float y = Mathf.Clamp(riderObject.LaneChangingDirection, -6f, 6f);
|
||||
riderObject.Lean = new Vector3(0.0f, y, z1);
|
||||
}
|
||||
}
|
||||
//更新后背的光线
|
||||
private void UpdateBackLight()
|
||||
{
|
||||
this.arBackLight.transform.position = this.UnityCamera.transform.position;
|
||||
this.arBackLight.transform.rotation = this.UnityCamera.transform.rotation;
|
||||
this.arLight.transform.rotation = this.Route.GetLightDirection(this.videoPlayer.CurrentFrame);
|
||||
this.arLight.shadowStrength = this.Route.GetShadowIntensity(this.videoPlayer.CurrentFrame);
|
||||
}
|
||||
protected void LateUpdate() => this.UpdateRiderTitles();
|
||||
|
||||
private void UpdateRiderTitles()
|
||||
{
|
||||
//foreach (int key in this.riderNameViews.Keys)
|
||||
//{
|
||||
// ARLaneObject riderObject = this.riderObjects[key];
|
||||
// UIRect riderNameView = this.riderNameViews[key];
|
||||
// RiderValueView riderValueView;
|
||||
// this.riderValueViews.TryGetValue(key, out riderValueView);
|
||||
// float num1 = Vector3.Distance(riderObject.transform.position, this.UnityCamera.transform.position);
|
||||
// if (!riderObject.gameObject.activeSelf || (double)num1 > (double)this.MaximumVisibilityDistance || this.SelectedPanorama == null && (double)num1 < 3.0)
|
||||
// {
|
||||
// riderNameView.Active = false;
|
||||
// if ((UnityEngine.Object)riderValueView != (UnityEngine.Object)null)
|
||||
// riderValueView.Active = false;
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// riderNameView.Active = true;
|
||||
// if ((UnityEngine.Object)riderValueView != (UnityEngine.Object)null)
|
||||
// riderValueView.Active = (double)num1 < 30.0;
|
||||
// float nameViewAlpha = this.GetNameViewAlpha(num1);
|
||||
// if ((double)nameViewAlpha < 1.0)
|
||||
// riderNameView.Alpha = nameViewAlpha;
|
||||
// float t = this.GetValueViewAlpha(num1);
|
||||
// if ((double)t < 1.0 && (UnityEngine.Object)riderValueView != (UnityEngine.Object)null)
|
||||
// riderValueView.Alpha = t;
|
||||
// //if (this.sportProfile == SportProfile.Running)
|
||||
// //{
|
||||
// // if ((UnityEngine.Object)riderValueView != (UnityEngine.Object)null)
|
||||
// // riderValueView.Active = false;
|
||||
// // t = 0.0f;
|
||||
// //}
|
||||
// Vector3 vector3 = 5f * this.uiScale * Mathf.Max(0.1f, this.SelectedPanorama != null ? 1f : this.GetDistanceScale(num1));
|
||||
// Quaternion rotation = this.UnityCamera.transform.rotation;
|
||||
// //if (this.SelectedPanorama != null)
|
||||
// //{
|
||||
// // rotation = this.PanoramaCamera.transform.rotation;
|
||||
// //}
|
||||
// //else
|
||||
// {
|
||||
// if ((double)riderObject.Distance < (double)this.CameraDistance)
|
||||
// rotation *= Quaternion.Euler(0.0f, 180f, 0.0f);
|
||||
// if (this.videoPlayer.IsRear)
|
||||
// rotation *= Quaternion.Euler(0.0f, 180f, 0.0f);
|
||||
// }
|
||||
// float num2 = Mathf.Lerp(-0.5f * this.Route.RiderScale, 0.6f * this.Route.RiderScale, Mathf.Clamp01(VTMath.Lerp(ARObject.MaxDistanceVisibilityModels - 5f, 1f, ARObject.MaxDistanceVisibilityModels, 0.0f, num1)));
|
||||
// float num3 = 14f;
|
||||
// float num4 = Mathf.Lerp(num2 + vector3.y * (0.5f * riderNameView.Height), num2 + vector3.y * (float)((double)num3 + 0.5 * (double)riderNameView.Height + 5.0), t);
|
||||
// float num5 = -this.Route.RiderScale * riderObject.PositionOffset.y;
|
||||
// riderNameView.transform.localScale = vector3;
|
||||
// riderNameView.transform.position = riderObject.transform.position + rotation * new Vector3(0.0f, num4 + num5, 0.0f);
|
||||
// riderNameView.transform.rotation = rotation;
|
||||
// if ((UnityEngine.Object)riderValueView != (UnityEngine.Object)null)
|
||||
// {
|
||||
// float num6 = num2 + vector3.y * (0.5f * num3);
|
||||
// riderValueView.transform.localScale = vector3;
|
||||
// riderValueView.transform.position = riderObject.transform.position + rotation * new Vector3(0.0f, num6 + num5, 0.0f);
|
||||
// riderValueView.transform.rotation = rotation;
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
}
|
||||
public void Pause() => this.paused = true;
|
||||
|
||||
public void Resume() => this.paused = false;
|
||||
|
||||
private class VisibleRiderItem
|
||||
{
|
||||
public OnlineRiderModel Rider;
|
||||
public float ModelDistance;
|
||||
public float DeltaDistance;
|
||||
public bool ShowModel;
|
||||
public float Lane;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 300e4dc5d644157469bca467c586af2e
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,169 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class ARVideoPlayerControl
|
||||
{
|
||||
private const float MinVideoPlaybackSpeedChangeInterval = 0.2f;
|
||||
private const float MaxPlaybackSpeed = 1.5f;
|
||||
private const float MaxCameraDistanceError = 200f;
|
||||
private DateTime lastPlaybackSpeedChange = DateTime.MinValue;
|
||||
private float fixedTimeFrame;
|
||||
private DateTime fixedTimeSeekFinished = DateTime.MinValue;
|
||||
private int lapCount = 1;
|
||||
private double lapLength;
|
||||
|
||||
public float FixedVideoFrame => this.fixedTimeFrame;
|
||||
|
||||
//public IDistanceSource RiderDistance { get; set;
|
||||
|
||||
public AVProVideoPlayer VideoPlayer { get; private set; }
|
||||
|
||||
//public ISpeedSource RiderSpeed { get; set; }
|
||||
|
||||
public VideoPointsSync VideoSyncSource { get; set; }
|
||||
|
||||
public ARRoute Route { get; set; }
|
||||
|
||||
public int VideoFrameOffset { get; set; }
|
||||
|
||||
public float CameraFollowDistance { get; set; }
|
||||
|
||||
public bool AllowUpdate { get; set; } = true;
|
||||
|
||||
public float CameraDistanceError { get; private set; }
|
||||
|
||||
public bool IsTimeFixed { get; private set; }
|
||||
|
||||
public float FrameIndexDistanceCorrection { get; private set; }
|
||||
|
||||
public bool IsMultilap => this.lapCount > 1;
|
||||
|
||||
public void SetVideoPlayer(AVProVideoPlayer player) => this.VideoPlayer = player;
|
||||
|
||||
public void SetMultiLap(int lapCount, double lapLength)
|
||||
{
|
||||
this.lapCount = lapCount;
|
||||
this.lapLength = lapLength;
|
||||
}
|
||||
|
||||
public void FixTimeByDistance(float distance) => this.FixTimeByFrame(this.VideoSyncSource.GetVideoFrameAtDistance(distance));
|
||||
|
||||
public void FixTimeByFrame(float frame)
|
||||
{
|
||||
this.IsTimeFixed = true;
|
||||
this.fixedTimeFrame = frame;
|
||||
this.fixedTimeSeekFinished = DateTime.MinValue;
|
||||
if (this.VideoPlayer.IsPaused)
|
||||
this.VideoPlayer.Resume();
|
||||
this.VideoPlayer.SetPlaybackSpeed(0.25f);
|
||||
this.VideoPlayer.Seek((long)frame, true);
|
||||
}
|
||||
|
||||
public void UnFixTime()
|
||||
{
|
||||
//this.IsTimeFixed = false;
|
||||
//float videoFrameAtDistance = this.VideoSyncSource.GetVideoFrameAtDistance(this.RiderDistance.LapDistance);
|
||||
//float num = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance, videoFrameAtDistance);
|
||||
//float playbackSpeed = (double)num != 0.0 ? this.RiderSpeed.Speed / num : 0.0f;
|
||||
//if (this.VideoPlayer.IsPaused)
|
||||
// this.VideoPlayer.Resume();
|
||||
//this.VideoPlayer.SetPlaybackSpeed(playbackSpeed);
|
||||
//this.lastPlaybackSpeedChange = DateTime.UtcNow;
|
||||
//this.VideoPlayer.Seek((long)videoFrameAtDistance, true);
|
||||
}
|
||||
|
||||
private void SkipVideoToDistance(float distance) => this.SkipVideoToFrame((long)this.VideoSyncSource.GetVideoFrameAtDistance(distance));
|
||||
|
||||
private void SkipVideoToFrame(long frame) => this.VideoPlayer.Seek(frame);
|
||||
|
||||
private const float TimerInterval = 0.2f;
|
||||
|
||||
/// <summary>
|
||||
/// update video play rate
|
||||
/// </summary>
|
||||
/// <param name="speed">播放速度</param>
|
||||
/// <param name="routeDistance">骑行距离</param>
|
||||
public void UpdateVideoPlayRate(float speed, float routeDistance)
|
||||
{
|
||||
if (!this.AllowUpdate)
|
||||
return;
|
||||
if (this.IsTimeFixed)
|
||||
{
|
||||
if (this.VideoPlayer.IsSeeking)
|
||||
return;
|
||||
if (this.fixedTimeSeekFinished == DateTime.MinValue)
|
||||
this.fixedTimeSeekFinished = DateTime.UtcNow;
|
||||
if (DateTime.UtcNow.Subtract(this.fixedTimeSeekFinished).TotalSeconds < 0.25)
|
||||
return;
|
||||
if (this.VideoPlayer.CurrentFrame > this.fixedTimeFrame)
|
||||
this.VideoPlayer.Pause();
|
||||
|
||||
this.VideoPlayer.UpdateCurrentFrame();
|
||||
this.FrameIndexDistanceCorrection = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
var videoFrameAtDistance1 = this.VideoSyncSource.GetVideoFrameAtDistance(routeDistance);
|
||||
var val2 = routeDistance - this.CameraFollowDistance;
|
||||
|
||||
var distance = Math.Max(0.0f, val2);
|
||||
var frame = this.VideoSyncSource.GetVideoFrameAtDistance(distance) + this.VideoFrameOffset;
|
||||
if (this.Route != null && this.Route.GetVisibility(frame) > 10.0)
|
||||
frame = (float)this.Route.GetFrameAtDistance(Math.Max(0.0, this.Route.GetDistanceForFrame(videoFrameAtDistance1) - this.CameraFollowDistance)) + this.VideoFrameOffset;
|
||||
|
||||
this.VideoPlayer.UpdateCurrentFrame();
|
||||
var distanceForVideoFrame = this.VideoSyncSource.GetDistanceForVideoFrame(this.VideoPlayer.CurrentFrame - (float)this.VideoFrameOffset);
|
||||
float frameOffset;
|
||||
if (this.Route != null)
|
||||
{
|
||||
var frameAtDistance = this.Route.GetFrameAtDistance(this.Route.GetDistanceForFrame(this.VideoPlayer.CurrentFrame - this.VideoFrameOffset) + Mathf.Min(routeDistance, this.CameraFollowDistance));
|
||||
frameOffset = videoFrameAtDistance1 - (float)frameAtDistance;
|
||||
}
|
||||
else
|
||||
frameOffset = frame - (this.VideoPlayer.CurrentFrame - this.VideoFrameOffset);
|
||||
var num1 = Mathf.Clamp01(PFMath.Lerp(0.0f, 1f, 100f, 0.0f, Mathf.Abs(frameOffset)));
|
||||
this.FrameIndexDistanceCorrection = frameOffset * num1;
|
||||
this.CameraDistanceError = distance - distanceForVideoFrame;
|
||||
if (this.IsMultilap)
|
||||
{
|
||||
var num2 = distance - (distanceForVideoFrame + (float)this.lapLength);
|
||||
if (Math.Abs(num2) < Math.Abs(this.CameraDistanceError) && Math.Abs(num2) < 200.0)
|
||||
return;
|
||||
}
|
||||
if (Math.Abs(this.CameraDistanceError) > 200.0)
|
||||
{
|
||||
this.SkipVideoToDistance(distance);
|
||||
}
|
||||
else
|
||||
{
|
||||
var totalSeconds = DateTime.UtcNow.Subtract(this.lastPlaybackSpeedChange).TotalSeconds;
|
||||
if (totalSeconds >= 0.0 && totalSeconds < TimerInterval)
|
||||
return;
|
||||
var num3 = (float)totalSeconds;
|
||||
var num4 = num3 * speed;
|
||||
var offset = this.VideoSyncSource.GetDistanceForVideoFrame((this.VideoPlayer.CurrentFrame - this.VideoFrameOffset + num3 * this.VideoPlayer.PlaybackSpeed * this.VideoPlayer.FrameRate));
|
||||
var left = (double)Math.Abs(distance + num4 - offset);
|
||||
var right = (double)Math.Abs(this.CameraDistanceError);
|
||||
|
||||
if (left <= right)
|
||||
return;
|
||||
var videoFrameAtDistance2 = this.VideoSyncSource.GetVideoFrameAtDistance(routeDistance + num4);
|
||||
var num5 = this.VideoSyncSource.AverageVideoSpeed(videoFrameAtDistance1, videoFrameAtDistance2);
|
||||
var ratio = (num5 != 0.0 ? speed / num5 : 0.0f);
|
||||
var deltaRatio = (float)((frame - (this.VideoPlayer.CurrentFrame - this.VideoFrameOffset)) / 2.0) / this.VideoPlayer.FrameRate;
|
||||
var playbackSpeed = Mathf.Clamp(ratio + deltaRatio, 0.0f, 1.5f);
|
||||
|
||||
if (playbackSpeed == this.VideoPlayer.PlaybackSpeed || !this.VideoPlayer.SetPlaybackSpeed(playbackSpeed))
|
||||
return;
|
||||
this.lastPlaybackSpeedChange = DateTime.UtcNow;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 9f244e092373e2d40935fd6ec79c8af7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,13 @@
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class ARVideoTransform
|
||||
{
|
||||
public int Frame;
|
||||
public float Distance;
|
||||
public Vector3 PositionOffset;
|
||||
public Vector3 RotationOffset;
|
||||
public Vector3 Scale;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 301eba5f832d14449ac634fb05589194
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,283 @@
|
||||
using RenderHeads.Media.AVProVideo;
|
||||
using System;
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class AVProVideoPlayer : MonoBehaviour
|
||||
{
|
||||
private const float DefaultFps = 29.97f;
|
||||
public MediaPlayer videoPlayer;
|
||||
private Vector2Int videoResolution = Vector2Int.zero;
|
||||
private Vector2Int textureResolution = Vector2Int.zero;
|
||||
private int displacement;
|
||||
private bool interpolate;
|
||||
private bool useFlow;
|
||||
private bool pausedByTrainingPause = false;
|
||||
private bool pausedByPlaybackSpeed = true;
|
||||
private RenderTexture currentTexture;
|
||||
private RenderTexture previousTexture;
|
||||
private bool switchBuffer = true;
|
||||
private bool canSwitchBuffer = true;
|
||||
private int previousTextureFrameCount;
|
||||
private float previousVideoTimeMs;
|
||||
private float shift;
|
||||
private DateTime lastPlaybackSpeedChange = DateTime.MinValue;
|
||||
private float localCurrentFrame;
|
||||
private bool intendedRear;
|
||||
|
||||
private void Awake()
|
||||
{
|
||||
//this.videoPlayer = this.gameObject.AddComponent<MediaPlayer>();
|
||||
//this.videoPlayer.PlatformOptionsAndroid.videoApi = RenderHeads.Media.AVProVideo.Android.VideoApi.MediaPlayer;
|
||||
//this.videoPlayer.PlatformOptionsAndroid.preferSoftwareDecoder = true;
|
||||
//GameObject primitive = GameObject.CreatePrimitive(PrimitiveType.Quad);
|
||||
//primitive.name = "VideoMesh";
|
||||
//primitive.layer = 9;
|
||||
//UnityEngine.Object.Destroy((UnityEngine.Object)primitive.GetComponent<MeshCollider>());
|
||||
//this.VideoRenderer = (Renderer)primitive.GetComponent<MeshRenderer>();
|
||||
//primitive.transform.parent = this.transform;
|
||||
//this.VideoRenderer.material = new Material(Shader.Find("Rouvy/FrameInterpolation"));
|
||||
}
|
||||
|
||||
private void OnDisable() => this.ReleaseRenderTextures();
|
||||
|
||||
private void OnDestroy() => UnityEngine.Object.Destroy((UnityEngine.Object)this.VideoRenderer?.material);
|
||||
|
||||
public bool Initialized => true;
|
||||
|
||||
public float CurrentFrame => (double)this.localCurrentFrame >= (double)this.StreamFrameCount ? this.localCurrentFrame - (float)this.StreamFrameCount : this.localCurrentFrame;
|
||||
|
||||
public bool IntendedRear
|
||||
{
|
||||
get => this.intendedRear;
|
||||
set
|
||||
{
|
||||
if (this.intendedRear == value)
|
||||
return;
|
||||
this.intendedRear = value;
|
||||
this.Seek((long)(int)this.CurrentFrame, true);
|
||||
}
|
||||
}
|
||||
|
||||
public bool IsRear => (double)this.localCurrentFrame >= (double)this.StreamFrameCount;
|
||||
|
||||
public int StreamFrameCount { get; set; }
|
||||
|
||||
public void UpdateCurrentFrame()
|
||||
{
|
||||
this.localCurrentFrame = (float)(this.videoPlayer.Control.GetCurrentTime() * DefaultFps);
|
||||
}
|
||||
|
||||
public float FrameRate { get; private set; } = 29.97f;
|
||||
|
||||
public bool HasOpticalFlow { get; private set; }
|
||||
|
||||
public float PlaybackSpeed => this.videoPlayer.Control.GetPlaybackRate();
|
||||
|
||||
public Renderer VideoRenderer { get; private set; }
|
||||
|
||||
public bool IsPaused => this.pausedByTrainingPause;
|
||||
|
||||
public bool IsSeeking => this.videoPlayer.Control.IsSeeking();
|
||||
|
||||
private bool Interpolate
|
||||
{
|
||||
get => this.interpolate;
|
||||
set
|
||||
{
|
||||
if (this.interpolate == value)
|
||||
return;
|
||||
this.interpolate = value;
|
||||
this.SetShaderKeywords();
|
||||
}
|
||||
}
|
||||
|
||||
private bool UseFlow
|
||||
{
|
||||
get => this.useFlow;
|
||||
set
|
||||
{
|
||||
if (this.useFlow == value)
|
||||
return;
|
||||
this.useFlow = value;
|
||||
this.SetShaderKeywords();
|
||||
}
|
||||
}
|
||||
|
||||
public void OpenVideo(string videoUrl, int streamFramesCount)
|
||||
{
|
||||
this.StreamFrameCount = streamFramesCount;
|
||||
this.StopVideo();
|
||||
//this.videoPlayer.OpenVideoFromFile(MediaPlayer.FileLocation.AbsolutePathOrURL, videoUrl);
|
||||
}
|
||||
|
||||
public void Pause()
|
||||
{
|
||||
this.videoPlayer.Pause();
|
||||
this.pausedByTrainingPause = true;
|
||||
}
|
||||
|
||||
public void Resume()
|
||||
{
|
||||
if (!this.pausedByPlaybackSpeed)
|
||||
this.videoPlayer.Play();
|
||||
this.pausedByTrainingPause = false;
|
||||
}
|
||||
|
||||
public void StopVideo()
|
||||
{
|
||||
this.videoPlayer.Stop();
|
||||
this.videoPlayer.CloseMedia();
|
||||
this.ReleaseRenderTextures();
|
||||
}
|
||||
private float pauseSpeed = 0.001f;
|
||||
public bool SetPlaybackSpeed(float playbackSpeed)
|
||||
{
|
||||
if (this.IsSeeking || this.IsPaused || DateTime.UtcNow.Subtract(this.lastPlaybackSpeedChange).TotalSeconds < 1.0)
|
||||
return false;
|
||||
if ((double)playbackSpeed <= pauseSpeed && !this.pausedByPlaybackSpeed)
|
||||
{
|
||||
this.pausedByPlaybackSpeed = true;
|
||||
this.videoPlayer.Pause();
|
||||
}
|
||||
else if ((double)playbackSpeed > pauseSpeed && this.pausedByPlaybackSpeed)
|
||||
{
|
||||
this.pausedByPlaybackSpeed = false;
|
||||
if (!this.pausedByTrainingPause)
|
||||
this.videoPlayer.Play();
|
||||
}
|
||||
this.videoPlayer.PlaybackRate = playbackSpeed;
|
||||
this.lastPlaybackSpeedChange = DateTime.UtcNow;
|
||||
return true;
|
||||
}
|
||||
|
||||
public bool Seek(long frame, bool force = false)
|
||||
{
|
||||
if (this.IntendedRear)
|
||||
frame += (long)this.StreamFrameCount;
|
||||
if (!this.Initialized || this.IsSeeking && !force)
|
||||
return false;
|
||||
this.videoPlayer.Control.SeekToFrame((int)frame);
|
||||
return true;
|
||||
}
|
||||
|
||||
private void Initialize()
|
||||
{
|
||||
if (this.Initialized)
|
||||
return;
|
||||
this.VideoPrepareAction();
|
||||
}
|
||||
|
||||
private void LateUpdate()
|
||||
{
|
||||
if (!this.Initialized)
|
||||
{
|
||||
this.Initialize();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.previousVideoTimeMs = (float)this.videoPlayer.Control.GetCurrentTime();
|
||||
if (!this.pausedByTrainingPause && this.videoPlayer.Control.IsPaused() && !this.pausedByPlaybackSpeed)
|
||||
this.videoPlayer.Play();
|
||||
if (!this.pausedByTrainingPause && !this.pausedByPlaybackSpeed || this.videoPlayer.Control.IsPaused())
|
||||
return;
|
||||
this.videoPlayer.Pause();
|
||||
}
|
||||
}
|
||||
|
||||
private void CheckAndPauseByPlaybackSpeed()
|
||||
{
|
||||
if ((double)this.videoPlayer.Control.GetPlaybackRate() != 0.0 || this.pausedByPlaybackSpeed)
|
||||
return;
|
||||
this.pausedByPlaybackSpeed = true;
|
||||
this.videoPlayer.Pause();
|
||||
}
|
||||
|
||||
private void VideoPrepareAction()
|
||||
{
|
||||
this.FrameRate = 29.97f;
|
||||
this.videoPlayer.Control.SetTextureProperties(anisoLevel: 0);
|
||||
if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 1688) < 10)
|
||||
{
|
||||
this.videoResolution = new Vector2Int(1280, 720);
|
||||
this.displacement = 40;
|
||||
this.HasOpticalFlow = true;
|
||||
}
|
||||
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 2528) < 10)
|
||||
{
|
||||
this.videoResolution = new Vector2Int(1920, 1080);
|
||||
this.displacement = 64;
|
||||
this.HasOpticalFlow = true;
|
||||
}
|
||||
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 3372) < 10)
|
||||
{
|
||||
this.videoResolution = new Vector2Int(2560, 1440);
|
||||
this.displacement = 128;
|
||||
this.HasOpticalFlow = true;
|
||||
}
|
||||
else if (Math.Abs(this.videoPlayer.Info.GetVideoWidth() - 1264) < 10)
|
||||
{
|
||||
this.videoResolution = new Vector2Int(960, 540);
|
||||
this.HasOpticalFlow = true;
|
||||
this.displacement = 32;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.videoResolution = new Vector2Int(this.videoPlayer.Info.GetVideoWidth(), this.videoPlayer.Info.GetVideoHeight());
|
||||
this.HasOpticalFlow = false;
|
||||
}
|
||||
this.Interpolate = this.UseFlow = this.HasOpticalFlow;
|
||||
this.videoPlayer.Play();
|
||||
if (!this.pausedByTrainingPause)
|
||||
return;
|
||||
this.videoPlayer.Pause();
|
||||
}
|
||||
|
||||
private void ReleaseRenderTextures()
|
||||
{
|
||||
if ((UnityEngine.Object)this.currentTexture != (UnityEngine.Object)null)
|
||||
{
|
||||
this.currentTexture.Release();
|
||||
this.currentTexture = (RenderTexture)null;
|
||||
}
|
||||
if (!((UnityEngine.Object)this.previousTexture != (UnityEngine.Object)null))
|
||||
return;
|
||||
this.previousTexture.Release();
|
||||
this.previousTexture = (RenderTexture)null;
|
||||
}
|
||||
|
||||
private void SetShaderKeywords()
|
||||
{
|
||||
if (this.Interpolate)
|
||||
this.VideoRenderer.material.EnableKeyword(AVProVideoPlayer.ShaderKeyword.interpolate);
|
||||
else
|
||||
this.VideoRenderer.material.DisableKeyword(AVProVideoPlayer.ShaderKeyword.interpolate);
|
||||
if (this.UseFlow && this.videoResolution != this.textureResolution)
|
||||
this.VideoRenderer.material.EnableKeyword(AVProVideoPlayer.ShaderKeyword.useFlow);
|
||||
else
|
||||
this.VideoRenderer.material.DisableKeyword(AVProVideoPlayer.ShaderKeyword.useFlow);
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 1)]
|
||||
private struct ShaderID
|
||||
{
|
||||
public static int previousFrame = Shader.PropertyToID("_PreviousFrame");
|
||||
public static int currentFrame = Shader.PropertyToID("_CurrentFrame");
|
||||
public static int displacement = Shader.PropertyToID("_MaxDisplacement");
|
||||
public static int shift = Shader.PropertyToID("_Shift");
|
||||
public static int flip = Shader.PropertyToID("_Flip");
|
||||
public static int videoResolution = Shader.PropertyToID("_VideoResolution");
|
||||
public static int textureResolution = Shader.PropertyToID("_TextureResolution");
|
||||
public static int screenResolution = Shader.PropertyToID("_ScreenResolution");
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential, Size = 1)]
|
||||
private struct ShaderKeyword
|
||||
{
|
||||
public static string interpolate = "INTERPOLATE";
|
||||
public static string useFlow = "USE_FLOW";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5609ccb62c92e784e873a76e89abc3aa
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,58 @@
|
||||
using System.Runtime.InteropServices;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public abstract class AbstractRenderer : ARLaneGameObject
|
||||
{
|
||||
protected Animator animator;
|
||||
|
||||
protected MaterialPropertyBlock materialPropertyBlock;
|
||||
|
||||
private bool paused = true;
|
||||
|
||||
public bool Male { get; protected set; }
|
||||
|
||||
public bool Paused
|
||||
{
|
||||
get => this.paused;
|
||||
set
|
||||
{
|
||||
if (value == this.paused)
|
||||
return;
|
||||
this.paused = value;
|
||||
this.OnPause(this.paused);
|
||||
}
|
||||
}
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
this.animator = this.GetComponent<Animator>();
|
||||
this.materialPropertyBlock = new MaterialPropertyBlock();
|
||||
}
|
||||
|
||||
public void Initialize(bool male) => this.Male = male;
|
||||
|
||||
protected virtual void Start()
|
||||
{
|
||||
this.animator.avatar = null;
|
||||
}
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
base.Update();
|
||||
}
|
||||
|
||||
protected virtual void OnPause(bool paused)
|
||||
{
|
||||
}
|
||||
|
||||
protected void SetLayerRecursively(GameObject obj, int layer)
|
||||
{
|
||||
obj.layer = layer;
|
||||
foreach (Component component in obj.transform)
|
||||
this.SetLayerRecursively(component.gameObject, layer);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4f542667dd24fe84e87fcb325e8535cb
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,34 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public static class GeometryUtil
|
||||
{
|
||||
public static bool CircleCenter(Vector3 aP0, Vector3 aP1, Vector3 aP2, out Vector3 center)
|
||||
{
|
||||
var lhs = aP1 - aP0;
|
||||
var vector3 = aP2 - aP0;
|
||||
var rhs = Vector3.Cross(lhs, vector3);
|
||||
if ((double)rhs.sqrMagnitude < 9.9999998245167E-15)
|
||||
{
|
||||
center = Vector3.zero;
|
||||
return false;
|
||||
}
|
||||
rhs.Normalize();
|
||||
if ((double)rhs.sqrMagnitude < 9.9999998245167E-15)
|
||||
{
|
||||
center = Vector3.zero;
|
||||
return false;
|
||||
}
|
||||
var normalized1 = Vector3.Cross(lhs, rhs).normalized;
|
||||
var normalized2 = Vector3.Cross(vector3, rhs).normalized;
|
||||
var from = (lhs - vector3) * 0.5f;
|
||||
var num1 = Vector3.Angle(normalized1, normalized2);
|
||||
var num2 = Vector3.Angle(from, normalized1);
|
||||
var num3 = from.magnitude * Mathf.Sin(num2 * ((float)Math.PI / 180f)) / Mathf.Sin(num1 * ((float)Math.PI / 180f));
|
||||
center = (double)Vector3.Dot(lhs, aP2 - aP1) <= 0.0 ? aP0 + vector3 * 0.5f + normalized2 * num3 : aP0 + vector3 * 0.5f - normalized2 * num3;
|
||||
return !float.IsInfinity(center.x) && !float.IsNaN(center.x) && !float.IsInfinity(center.y) && !float.IsNaN(center.y) && !float.IsInfinity(center.z) && !float.IsNaN(center.z);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 192a6b01fc9e2ec44b90f5d19c277ca4
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,131 @@
|
||||
using System;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public static class PFMath
|
||||
{
|
||||
public const double Deg2Rad = 0.017453292519943295;
|
||||
public const double Rad2Deg = 57.295779513082323;
|
||||
|
||||
public static int Clamp(int value, int min, int max)
|
||||
{
|
||||
if (value < min)
|
||||
return min;
|
||||
return value <= max ? value : max;
|
||||
}
|
||||
|
||||
public static double Clamp(double value, double min, double max)
|
||||
{
|
||||
if (value < min)
|
||||
return min;
|
||||
return value <= max ? value : max;
|
||||
}
|
||||
|
||||
public static float Clamp(float value, float min, float max)
|
||||
{
|
||||
if ((double)value < (double)min)
|
||||
return min;
|
||||
return (double)value <= (double)max ? value : max;
|
||||
}
|
||||
|
||||
public static float Clamp01(float value) => PFMath.Clamp(value, 0.0f, 1f);
|
||||
|
||||
public static double Clamp01(double value) => PFMath.Clamp(value, 0.0, 1.0);
|
||||
|
||||
public static bool InBounds(double value, double min, double max) => min <= value && value <= max;
|
||||
|
||||
public static bool InBounds(int value, int min, int max) => min <= value && value <= max;
|
||||
|
||||
public static double Lerp(double x1, double y1, double x2, double y2, double x)
|
||||
{
|
||||
var t = x1 != x2 ? PFMath.InverseLerp(x1, x2, x) : 0.5;
|
||||
return PFMath.Lerp(y1, y2, t);
|
||||
}
|
||||
|
||||
public static float Lerp(float x1, float y1, float x2, float y2, float x)
|
||||
{
|
||||
var t = (double)x1 != (double)x2 ? PFMath.InverseLerp(x1, x2, x) : 0.5f;
|
||||
return PFMath.Lerp(y1, y2, t);
|
||||
}
|
||||
|
||||
public static double Lerp(double a, double b, double t) => (1.0 - t) * a + t * b;
|
||||
|
||||
public static float Lerp(float a, float b, float t) => (float)((1.0 - (double)t) * (double)a + (double)t * (double)b);
|
||||
|
||||
public static double InverseLerp(double a, double b, double value) => a != b ? (value - a) / (b - a) : 0.0;
|
||||
|
||||
public static float InverseLerp(float a, float b, float value) => (double)a != (double)b ? (float)(((double)value - (double)a) / ((double)b - (double)a)) : 0.0f;
|
||||
|
||||
public static double SmoothStep(double x) => x * x * (3.0 - 2.0 * x);
|
||||
|
||||
public static float SmoothStep(float x) => (float)((double)x * (double)x * (3.0 - 2.0 * (double)x));
|
||||
|
||||
public static double SmoothStep(double a, double b, double t) => PFMath.Lerp(a, b, PFMath.SmoothStep(t));
|
||||
|
||||
public static float SmoothStep(float a, float b, float t) => PFMath.Lerp(a, b, PFMath.SmoothStep(t));
|
||||
|
||||
public static double SmoothStep(double x1, double y1, double x2, double y2, double x)
|
||||
{
|
||||
var t = x1 != x2 ? PFMath.InverseLerp(x1, x2, x) : 0.5;
|
||||
return PFMath.SmoothStep(y1, y2, t);
|
||||
}
|
||||
|
||||
public static float SmoothStep(float x1, float y1, float x2, float y2, float x)
|
||||
{
|
||||
var t = (double)x1 != (double)x2 ? PFMath.InverseLerp(x1, x2, x) : 0.5f;
|
||||
return PFMath.SmoothStep(y1, y2, t);
|
||||
}
|
||||
|
||||
public static double InverseSmoothStep(double a, double b, double value) => PFMath.InverseSmoothStep(PFMath.InverseLerp(a, b, value));
|
||||
|
||||
public static double InverseSmoothStep(double x)
|
||||
{
|
||||
x = 1.0 - 2.0 * x;
|
||||
return 0.5 - Math.Sin(Math.Asin(x) / 3.0);
|
||||
}
|
||||
|
||||
public static double SmoothStepDerivative(double x) => 6.0 * x * (1.0 - x);
|
||||
|
||||
public static double SmoothStepDerivative(double a, double b, double t) => 6.0 * t * (b - a) * (1.0 - t);
|
||||
|
||||
public static double Round(double value, double step) => step * Math.Round(value / step);
|
||||
|
||||
public static float Round(float value, float step) => step * Mathf.Round(value / step);
|
||||
|
||||
public static double Floor(double value, double step) => step * Math.Floor(value / step);
|
||||
|
||||
public static float Floor(float value, float step) => step * Mathf.Floor(value / step);
|
||||
|
||||
public static double Ceil(double value, double step) => step * Math.Ceiling(value / step);
|
||||
|
||||
public static float Ceil(float value, float step) => step * Mathf.Ceil(value / step);
|
||||
|
||||
public static double DistancePointToLineSegment(
|
||||
Vector3d point,
|
||||
Vector3d lineStart,
|
||||
Vector3d lineEnd)
|
||||
{
|
||||
return Vector3d.Magnitude(PFMath.ProjectPointToLineSegment(point, lineStart, lineEnd) - point);
|
||||
}
|
||||
|
||||
public static Vector3d ProjectPointToLineSegment(
|
||||
Vector3d point,
|
||||
Vector3d lineStart,
|
||||
Vector3d lineEnd)
|
||||
{
|
||||
var lineParameter = PFMath.ProjectPointToLineParameter(point, lineStart, lineEnd);
|
||||
return Vector3d.LerpClamped(lineStart, lineEnd, lineParameter);
|
||||
}
|
||||
|
||||
public static double ProjectPointToLineParameter(
|
||||
Vector3d point,
|
||||
Vector3d lineStart,
|
||||
Vector3d lineEnd)
|
||||
{
|
||||
var rhs = point - lineStart;
|
||||
var vector3d = lineEnd - lineStart;
|
||||
return Vector3d.Dot(vector3d, rhs) / Vector3d.SqrMagnitude(vector3d);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: edfe6b3cfb01f654bb5045ca7a9217f8
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,179 @@
|
||||
|
||||
using System;
|
||||
using Assets.Scripts.Scenes.VideoRide;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class PlayerRenderer : AbstractRenderer
|
||||
{
|
||||
private const int PowerWindowSize = 10;
|
||||
private const float Circumference = 2.13097382f;
|
||||
private const double SpeedLimitForWheelRotation = 10.0;
|
||||
private const double MaxAngularSpeed = 1689.3684817282528;
|
||||
private const double MaxAnglePerFrame = 6.5;
|
||||
private const float AfterFinishRideInSec = 5f;
|
||||
public const float MaxLeanAngle = 35f;
|
||||
public const float MaxLeanAngleChange = 60f;
|
||||
public const float MaxTurnAngle = 6f;
|
||||
public const float MaxTurnAngleChange = 10f;
|
||||
public const float LeanAngleSoftStageLength = 15f;
|
||||
private float lastSpeed = 1f;
|
||||
private bool lastPauseState;
|
||||
private int lastDifficultyLevel;
|
||||
private float lastVisibilitylevel = -1f;
|
||||
private float afterFinishTime;
|
||||
private float afterFinishFrame;
|
||||
private float finishPassSpeed;
|
||||
private float afterFinishOffsetZ;
|
||||
private float lastDiffLevelChange = float.MinValue;
|
||||
private float[] powerWindow = new float[10];
|
||||
private float lastPowerWinWrite;
|
||||
private int lastPowerWinIndex;
|
||||
private float PowerWinSum;
|
||||
private float lastPowerPeak = float.MinValue;
|
||||
private int powerPeakSum;
|
||||
public Transform wheelFront;
|
||||
public Transform wheelRear;
|
||||
private float lookTime;
|
||||
private bool lockIdleAnimations;
|
||||
|
||||
public float Cadence { get; set; }
|
||||
|
||||
public int DifficultyLevel { get; set; }
|
||||
|
||||
public float Power { get; set; }
|
||||
|
||||
public float Weight { get; set; }
|
||||
|
||||
public float Slope { get; set; }
|
||||
|
||||
public Texture2D HelmTexture { get; set; }
|
||||
|
||||
public Texture2D BikeTexture { get; set; }
|
||||
|
||||
public bool WinAnimation { get; set; }
|
||||
|
||||
public bool TimeTrialBike { get; private set; }
|
||||
|
||||
public GameObject BasicShadowRenderer { get; set; }
|
||||
|
||||
public bool LockIdleAnimations
|
||||
{
|
||||
get => this.lockIdleAnimations;
|
||||
set
|
||||
{
|
||||
if (value == this.lockIdleAnimations)
|
||||
return;
|
||||
this.lockIdleAnimations = value;
|
||||
}
|
||||
}
|
||||
|
||||
public void Initialize(bool male, bool timeTrialBike)
|
||||
{
|
||||
this.Initialize(male);
|
||||
this.TimeTrialBike = timeTrialBike;
|
||||
}
|
||||
//人物再刚显示的时候计算当前人物的状态
|
||||
private void OnEnable()
|
||||
{
|
||||
if ((UnityEngine.Object)this.animator != (UnityEngine.Object)null)
|
||||
{
|
||||
if (lastSpeed > 1)
|
||||
{
|
||||
animator.Play("rideLoop");
|
||||
}
|
||||
else
|
||||
{
|
||||
animator.Play("idle");
|
||||
}
|
||||
}
|
||||
}
|
||||
private string LastAnimatorState { get; set; }
|
||||
|
||||
protected override void Update()
|
||||
{
|
||||
if (this.route == null)
|
||||
return;
|
||||
base.Update();
|
||||
var num = this.Speed;
|
||||
this.Paused = this.Speed == 0;
|
||||
var flag = this.Paused;
|
||||
if (this.IsAtFinish)
|
||||
{
|
||||
if ((double)this.afterFinishTime < 5.0)
|
||||
{
|
||||
this.ManualVisibility = 1000f;
|
||||
var videoSpeedAtDistance = this.videoSync.GetVideoSpeedAtDistance(this.Distance - 5f);
|
||||
if ((double)this.afterFinishFrame == 0.0 && (double)this.afterFinishOffsetZ == 0.0)
|
||||
{
|
||||
this.finishPassSpeed = (double)this.lastSpeed > 0.0 ? this.lastSpeed : 10f;
|
||||
}
|
||||
flag = false;
|
||||
this.afterFinishTime += Time.deltaTime;
|
||||
this.afterFinishTime = Math.Min(5f, this.afterFinishTime);
|
||||
num = Mathf.Lerp(this.finishPassSpeed, 0.0f, this.afterFinishTime / 5f);
|
||||
this.afterFinishFrame += num / videoSpeedAtDistance * Time.deltaTime * 29.97f;
|
||||
this.frame = Math.Min((float)(this.route.CameraPositions.Length - 1), this.videoSync.GetVideoFrameAtDistance(this.Distance) + this.afterFinishFrame);
|
||||
if ((double)this.frame == (double)(this.route.CameraPositions.Length - 1))
|
||||
this.afterFinishOffsetZ += num * Time.deltaTime;
|
||||
}
|
||||
else
|
||||
{
|
||||
this.afterFinishTime += Time.deltaTime;
|
||||
num = 0.0f;
|
||||
if ((double)this.afterFinishTime > 15.0)
|
||||
this.ManualVisibility = -1f;
|
||||
else
|
||||
this.ManualVisibility = 1000f;
|
||||
}
|
||||
this.PositionOffset.z = this.afterFinishOffsetZ;
|
||||
this.transform.localScale = Vector3.one * this.route.RiderScale;
|
||||
this.UpdateTransform();
|
||||
}
|
||||
else
|
||||
{
|
||||
this.transform.localScale = Vector3.one * this.route.RiderScale;
|
||||
if (flag)
|
||||
num = 0.0f;
|
||||
this.ManualVisibility = 0.0f;
|
||||
this.afterFinishTime = 0.0f;
|
||||
this.afterFinishFrame = 0.0f;
|
||||
this.afterFinishOffsetZ = 0.0f;
|
||||
this.PositionOffset.z = 0.0f;
|
||||
}
|
||||
if (flag != this.lastPauseState)
|
||||
{
|
||||
this.lastPauseState = flag;
|
||||
}
|
||||
if ((double)this.lastSpeed != (double)num)
|
||||
{
|
||||
this.lastSpeed = num;
|
||||
}
|
||||
if ((double)this.lastSpeed > 0.0 && this.lastDifficultyLevel != this.DifficultyLevel && !this.lastPauseState && (double)Math.Abs(Time.time - this.lastDiffLevelChange) > 2.0)
|
||||
{
|
||||
this.lastDifficultyLevel = this.DifficultyLevel;
|
||||
this.lastDiffLevelChange = Time.time;
|
||||
}
|
||||
if ((double)this.lastVisibilitylevel == (double)this.VisibilityLevel)
|
||||
return;
|
||||
|
||||
this.lastVisibilitylevel = this.VisibilityLevel;
|
||||
}
|
||||
|
||||
private void FixedUpdate()
|
||||
{
|
||||
//if (this.Paused || (double)this.Speed <= 0.0)
|
||||
if ((double)this.Speed <= 0.0)
|
||||
return;
|
||||
//ControlWheelRotation();
|
||||
}
|
||||
|
||||
private void ControlWheelRotation()
|
||||
{
|
||||
var angle = (float)PFMath.Clamp(PFMath.Lerp(0.0, 0.0, 1689.3684817282528, 6.5, 360.0 * ((double)this.Speed < 10.0 ? (double)this.Speed : 2.3463451135114624)), 0.0, 6.5);
|
||||
this.wheelFront.transform.Rotate(Vector3.right, angle);
|
||||
this.wheelRear.transform.Rotate(Vector3.right, angle);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a779f3247875ef947ab87e8093f5bb39
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,378 @@
|
||||
using Assets.AR;
|
||||
using DG.Tweening;
|
||||
using RenderHeads.Media.AVProVideo;
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public class TestPlayer : ARLaneGameObjectsController
|
||||
{
|
||||
protected Transform LightTrans { get; set; }
|
||||
public MediaPlayer mediaPlayer;
|
||||
public Transform Player;
|
||||
private ARData aRData;
|
||||
private RouteDetailData detail;
|
||||
private VideoPointsSync videoPointsSync;
|
||||
private int index = 1;
|
||||
private readonly List<ARLaneGameObject> collisionList = new List<ARLaneGameObject>();
|
||||
///private Dictionary<int, IRouteRider> riders = new Dictionary<int, IRouteRider>();
|
||||
ARVideoPlayerControl VideoPlayerControl;
|
||||
ARLaneGameObject[] rides;
|
||||
public ARLaneGameObject mainObject;
|
||||
|
||||
private Light arLight;
|
||||
private Light arBackLight;
|
||||
|
||||
public Text Fps;
|
||||
|
||||
protected override void Start()
|
||||
{
|
||||
base.Start();
|
||||
var txt = Resources.Load<TextAsset>("UI/88019").text;
|
||||
var route = Resources.Load<TextAsset>("UI/route-88019").text;
|
||||
aRData = Newtonsoft.Json.JsonConvert.DeserializeObject<ARData>(txt);
|
||||
detail = Newtonsoft.Json.JsonConvert.DeserializeObject<RouteDetailData>(route);
|
||||
|
||||
videoPointsSync = new VideoPointsSync(detail.VideoPoints.Select(c => new VideoPoint()
|
||||
{
|
||||
Distance = (float)c.Distance,
|
||||
Time = (float)c.VideoTime
|
||||
}));
|
||||
|
||||
videoSync = videoPointsSync;
|
||||
|
||||
this.VideoPlayerControl = new ARVideoPlayerControl();
|
||||
this.VideoPlayerControl.VideoSyncSource = videoSync;
|
||||
this.videoPlayer = new AVProVideoPlayer();
|
||||
this.videoPlayer.videoPlayer = mediaPlayer;
|
||||
SetArRoute(new ARRoute(aRData.Route), videoSync, videoPlayer);
|
||||
this.VideoPlayerControl.VideoFrameOffset = this.Route.VideoFrameOffset;
|
||||
this.VideoPlayerControl.Route = Route;
|
||||
this.VideoPlayerControl.SetVideoPlayer(videoPlayer);
|
||||
rides = FindObjectsOfType<ARLaneGameObject>();
|
||||
CreateBackLight();
|
||||
}
|
||||
|
||||
private void CreateBackLight()
|
||||
{
|
||||
GameObject gameObject1 = new GameObject("ARLight");
|
||||
gameObject1.layer = this.gameObject.layer;
|
||||
gameObject1.transform.SetParent(this.transform);
|
||||
this.arLight = gameObject1.AddComponent<Light>();
|
||||
this.arLight.type = LightType.Directional;
|
||||
this.arLight.transform.rotation = Quaternion.Euler(90f, 0.0f, 0.0f);
|
||||
//if (this.BuildConfig.IsIOs || this.BuildConfig.IsTvOs)
|
||||
//{
|
||||
// this.arLight.shadows = LightShadows.Hard;
|
||||
// this.arLight.shadowStrength = 0.5f;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
this.arLight.shadows = LightShadows.Soft;
|
||||
this.arLight.shadowStrength = 1f;
|
||||
}
|
||||
this.arLight.cullingMask = 512;
|
||||
GameObject gameObject2 = new GameObject("ARBackLight");
|
||||
gameObject2.layer = this.gameObject.layer;
|
||||
gameObject2.transform.SetParent(this.transform);
|
||||
this.arBackLight = gameObject2.AddComponent<Light>();
|
||||
this.arBackLight.type = LightType.Directional;
|
||||
this.arBackLight.transform.rotation = Quaternion.Euler(0.0f, 0.0f, 0.0f);
|
||||
this.arBackLight.shadows = LightShadows.None;
|
||||
this.arBackLight.intensity = 0.5f;
|
||||
this.arBackLight.cullingMask = 512;
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
float timers = 1f;
|
||||
double weight = 70;
|
||||
double bikeWeight = 20;
|
||||
|
||||
private void Update()
|
||||
{
|
||||
timers -= Time.deltaTime;
|
||||
|
||||
while (timers < 0)
|
||||
{
|
||||
foreach (var item in rides)
|
||||
{
|
||||
if (item.StartPosition == 1)
|
||||
{
|
||||
item.TestPower = new System.Random().Next(500, 720);
|
||||
}
|
||||
item.Speed = (float)(Assets.Scenes.Ride.Scripts.Helper.CalculateSpeed(0, 0, item.TestPower, weight, bikeWeight) / 3.6d);
|
||||
item.DeltaDistance = item.Speed;
|
||||
|
||||
item.Route = Route;
|
||||
item.VideoSync = videoPointsSync;
|
||||
if (!this.riderObjects.ContainsKey(item.GetInstanceID()))
|
||||
this.riderObjects.Add(item.GetInstanceID(), item);
|
||||
}
|
||||
|
||||
timers += 1f;
|
||||
}
|
||||
this.FrameIndexDistanceCorrection = this.VideoPlayerControl.FrameIndexDistanceCorrection;
|
||||
foreach (var item in rides)
|
||||
{
|
||||
item.Distance += item.DeltaDistance * Time.deltaTime;
|
||||
item.RouteDistance += item.DeltaDistance * Time.deltaTime;
|
||||
if (item.Distance >= Route.GetTotalDistance())
|
||||
{
|
||||
item.IsAtFinish = true;
|
||||
}
|
||||
}
|
||||
this.UpdateCameraFollowDistance();
|
||||
VideoPlayerControl.UpdateVideoPlayRate(mainObject.Speed, mainObject.distance);
|
||||
Fps.text = this.mediaPlayer.Control.GetCurrentTimeFrames().ToString();
|
||||
this.FollowedRiderId = 1;
|
||||
base.Update();
|
||||
this.UpdateRidersVisibility();
|
||||
this.UpdateRidersLean();
|
||||
this.UpdateBackLight();
|
||||
if (Input.GetKeyDown(KeyCode.F))
|
||||
this.SetVideoControlMode(VideoPlayMode.Front);
|
||||
if (Input.GetKeyDown(KeyCode.P))
|
||||
this.SetVideoControlMode(VideoPlayMode.AutoPanorama);
|
||||
if (!Input.GetKeyDown(KeyCode.B))
|
||||
return;
|
||||
this.SetVideoControlMode(VideoPlayMode.Rear);
|
||||
}
|
||||
|
||||
public VideoPlayMode VideoControlMode { get; private set; }
|
||||
private float autoCameraSwitchTimeCounter = 80f;
|
||||
public void SetVideoControlMode(VideoPlayMode mode)
|
||||
{
|
||||
if (mode == this.VideoControlMode)
|
||||
return;
|
||||
if (!this.AR360Version)
|
||||
mode = VideoPlayMode.Front;
|
||||
this.VideoControlMode = mode;
|
||||
this.autoCameraSwitchTimeCounter = 80f;
|
||||
if (mode == VideoPlayMode.AutoPanorama)
|
||||
return;
|
||||
this.videoPlayer.IntendedRear = mode == VideoPlayMode.Rear;
|
||||
}
|
||||
|
||||
public CameraDistance RiderCameraDistance { get; set; }
|
||||
//更新摄像机的位置
|
||||
private void UpdateCameraFollowDistance()
|
||||
{
|
||||
this.RiderCameraDistance = AR.CameraDistance.Middle;
|
||||
this.NearViewMode = this.RiderCameraDistance == AR.CameraDistance.Near;
|
||||
var cameraFollowDistance = GetCameraFollowDistance(this.RiderCameraDistance);
|
||||
this.VideoPlayerControl.CameraFollowDistance = cameraFollowDistance;
|
||||
}
|
||||
protected override bool IsObjectActive(ARGameObject arObject)
|
||||
{
|
||||
var flag = base.IsObjectActive(arObject);
|
||||
if ((UnityEngine.Object)arObject != (UnityEngine.Object)this.mainObject)
|
||||
return flag;
|
||||
if ((double)this.VideoPlayerControl.CameraFollowDistance > 0.0 || this.AR360Version)
|
||||
return flag;
|
||||
return flag && (double)this.VideoPlayerControl.CameraDistanceError > 5.0;
|
||||
}
|
||||
//获取摄像机的位置
|
||||
public static float GetCameraFollowDistance(CameraDistance distance)
|
||||
{
|
||||
switch (distance)
|
||||
{
|
||||
case AR.CameraDistance.FirstPerson:
|
||||
return 0.0f;
|
||||
case AR.CameraDistance.Near:
|
||||
return 2.5f;
|
||||
case AR.CameraDistance.Middle:
|
||||
return 5f;
|
||||
case AR.CameraDistance.Far:
|
||||
return 10f;
|
||||
default:
|
||||
throw new ArgumentException("Unknown rider's camera distance.");
|
||||
}
|
||||
}
|
||||
private void UpdateRidersVisibility()
|
||||
{
|
||||
//if (!this.videoPlayer.Initialized)
|
||||
// return;
|
||||
//this.UpdateVisibleRiders();
|
||||
////删除当前道路上应该消失的骑手
|
||||
//foreach (int num in this.riderObjects.Keys.ToArray<int>())
|
||||
//{
|
||||
// if (!this.visibleRiders.ContainsKey(num))
|
||||
// {
|
||||
// ARLaneObject riderObject = this.riderObjects[num];
|
||||
// if (!riderObject.IsAtFinish || (double)riderObject.VisibilityLevel <= 0.0)
|
||||
// {
|
||||
// this.DestroyRider(num);
|
||||
// this.DestroyRiderTitle(num);
|
||||
// }
|
||||
// }
|
||||
//}
|
||||
////新增应该显示的骑手
|
||||
//foreach (TrainingARController.VisibleRiderItem visibleRiderItem in this.visibleRiders.Values)
|
||||
//{
|
||||
// IRouteRider rider = visibleRiderItem.Rider;
|
||||
// bool showModel = visibleRiderItem.ShowModel;
|
||||
// ARLaneObject arLaneObject;
|
||||
// //二次检查
|
||||
// if (this.riderObjects.TryGetValue(rider.Id, out arLaneObject))
|
||||
// {
|
||||
// if (arLaneObject is BaseRenderer)
|
||||
// {
|
||||
// if (!showModel)
|
||||
// {
|
||||
// float lane = arLaneObject.Lane;
|
||||
// this.DestroyRider(rider.Id);
|
||||
// this.CreateRiderObject(rider, lane);
|
||||
// }
|
||||
// }
|
||||
// else if (showModel)
|
||||
// {
|
||||
// float lane = arLaneObject.Lane;
|
||||
// this.DestroyRider(rider.Id);
|
||||
// this.CreateRiderModel(rider, lane);
|
||||
// }
|
||||
// }
|
||||
// else
|
||||
// {
|
||||
// if (showModel)
|
||||
// this.CreateRiderModel(rider, visibleRiderItem.Lane);
|
||||
// else
|
||||
// this.CreateRiderObject(rider, visibleRiderItem.Lane);
|
||||
// this.CreateRiderTitleObject(rider);
|
||||
// }
|
||||
//}
|
||||
}
|
||||
//更新骑手的偏移角度
|
||||
private void UpdateRidersLean()
|
||||
{
|
||||
foreach (ARLaneGameObject riderObject in this.riderObjects.Values)
|
||||
{
|
||||
float num1 = this.Route.GetTrajectoryCurvature(riderObject.Frame) + riderObject.Curvature;
|
||||
float z1;
|
||||
if ((double)num1 == 0.0)
|
||||
{
|
||||
z1 = 0.0f;
|
||||
}
|
||||
else
|
||||
{
|
||||
double speed = riderObject.Speed;
|
||||
float f = 57.29578f * Mathf.Atan((float)(speed * speed * (double)num1 / 9.81));
|
||||
float num2 = (double)f >= 0.0 ? 1f : -1f;
|
||||
float num3 = Mathf.Abs(f);
|
||||
if ((double)num3 > 20.0)
|
||||
f = (float)((double)Mathf.Atan((float)(((double)num3 - 20.0) / 10.5)) * 10.5 + 20.0) * num2;
|
||||
float num4 = Mathf.Clamp(f, -35f, 35f);
|
||||
float z2 = riderObject.Lean.z;
|
||||
z1 = Mathf.Clamp(num4, z2 - 60f * Time.deltaTime, z2 + 60f * Time.deltaTime);
|
||||
}
|
||||
float y = Mathf.Clamp(riderObject.LaneChangingDirection, -6f, 6f);
|
||||
riderObject.Lean = new Vector3(0.0f, y, z1);
|
||||
}
|
||||
}
|
||||
|
||||
//更新后背的光线
|
||||
private void UpdateBackLight()
|
||||
{
|
||||
//if (this.SelectedPanorama != null)
|
||||
//{
|
||||
// this.arBackLight.transform.position = this.PanoramaCamera.transform.position;
|
||||
// this.arBackLight.transform.rotation = this.PanoramaCamera.transform.rotation;
|
||||
//}
|
||||
//else
|
||||
{
|
||||
this.arBackLight.transform.position = this.UnityCamera.transform.position;
|
||||
this.arBackLight.transform.rotation = this.UnityCamera.transform.rotation;
|
||||
}
|
||||
this.arLight.transform.rotation = this.Route.GetLightDirection(this.videoPlayer.CurrentFrame);
|
||||
this.arLight.shadowStrength = this.Route.GetShadowIntensity(this.videoPlayer.CurrentFrame);
|
||||
}
|
||||
#endif
|
||||
//人物状态
|
||||
private string ConfigPath = Application.streamingAssetsPath + "/newdirection.txt";
|
||||
public const int HERO_UP = 0;
|
||||
public const int HERO_RIGHT = 1;
|
||||
public const int HERO_DOWN = 2;
|
||||
public const int HERO_LEFT = 3;
|
||||
public const int UP = 4;
|
||||
public const int DOWN = 5;
|
||||
private Vector3 rotation = Vector3.zero;
|
||||
private void keyBordControl()
|
||||
{
|
||||
#region 人物方向控制
|
||||
var zdelta = 0.05f;
|
||||
var delta = 0.2f;
|
||||
if (Input.GetKey(KeyCode.W))
|
||||
{
|
||||
//mediaPlayer.Play();
|
||||
//mediaPlayer.PlaybackRate = 1f;
|
||||
var z = transform.position.z + zdelta;
|
||||
//transform.DOMoveZ(z, 0);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.A))
|
||||
{
|
||||
mediaPlayer.PlaybackRate = 1f;
|
||||
mediaPlayer.Play();
|
||||
var z = transform.position.x - zdelta;
|
||||
//transform.DOMoveX(z, 0);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.D))
|
||||
{
|
||||
mediaPlayer.PlaybackRate = 1f;
|
||||
mediaPlayer.Play();
|
||||
var z = transform.position.x + zdelta;
|
||||
//transform.DOMoveX(z, 0);
|
||||
}
|
||||
if (Input.GetKey(KeyCode.S))
|
||||
{
|
||||
mediaPlayer.PlaybackRate = 1f;
|
||||
mediaPlayer.Play();
|
||||
var z = transform.position.z - zdelta;
|
||||
//transform.DOMoveZ(z, 0);
|
||||
}
|
||||
|
||||
//控制人物方向
|
||||
if (Input.GetKey(KeyCode.Q))
|
||||
{
|
||||
rotation.y -= delta;
|
||||
transform.DORotate(rotation, 0);
|
||||
Camera.main.transform.DORotate(rotation, 0);
|
||||
}
|
||||
if (Input.GetKey(KeyCode.E))
|
||||
{
|
||||
rotation.y += delta;
|
||||
transform.DORotate(rotation, 0);
|
||||
Camera.main.transform.DORotate(rotation, 0);
|
||||
}
|
||||
//控制人物左右倾斜
|
||||
if (Input.GetKey(KeyCode.J))
|
||||
{
|
||||
rotation.z += zdelta;
|
||||
transform.DORotate(rotation, 0);
|
||||
}
|
||||
if (Input.GetKey(KeyCode.K))
|
||||
{
|
||||
rotation.z -= zdelta;
|
||||
transform.DORotate(rotation, 0);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.UpArrow))
|
||||
{
|
||||
var z = transform.position.y + zdelta;
|
||||
transform.DOMoveY(z, 0);
|
||||
}
|
||||
|
||||
if (Input.GetKey(KeyCode.DownArrow))
|
||||
{
|
||||
var z = transform.position.y - zdelta;
|
||||
transform.DOMoveY(z, 0);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 523f7d25735c76b4ea28ecc390829ed7
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,154 @@
|
||||
using System;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
public struct Vector3d : IEquatable<Vector3d>
|
||||
{
|
||||
private static readonly Vector3d ZeroVector = new Vector3d(0.0, 0.0, 0.0);
|
||||
private static readonly Vector3d OneVector = new Vector3d(1.0, 1.0, 1.0);
|
||||
public double x;
|
||||
public double y;
|
||||
public double z;
|
||||
|
||||
public Vector3d(double x, double y, double z)
|
||||
{
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.z = z;
|
||||
}
|
||||
|
||||
public Vector3d(double[] c)
|
||||
{
|
||||
this.x = c[0];
|
||||
this.y = c[1];
|
||||
this.z = c[2];
|
||||
}
|
||||
|
||||
public static Vector3d Zero => Vector3d.ZeroVector;
|
||||
|
||||
public static Vector3d One => Vector3d.OneVector;
|
||||
|
||||
public Vector3d Normalized => Vector3d.Normalize(this);
|
||||
|
||||
public double this[int index]
|
||||
{
|
||||
get
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
return this.x;
|
||||
case 1:
|
||||
return this.y;
|
||||
case 2:
|
||||
return this.z;
|
||||
default:
|
||||
throw new IndexOutOfRangeException("Invalid Vector3d index!");
|
||||
}
|
||||
}
|
||||
set
|
||||
{
|
||||
switch (index)
|
||||
{
|
||||
case 0:
|
||||
this.x = value;
|
||||
break;
|
||||
case 1:
|
||||
this.y = value;
|
||||
break;
|
||||
case 2:
|
||||
this.z = value;
|
||||
break;
|
||||
default:
|
||||
throw new IndexOutOfRangeException("Invalid Vector3d index!");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public void Set(double newX, double newY, double newZ)
|
||||
{
|
||||
this.x = newX;
|
||||
this.y = newY;
|
||||
this.z = newZ;
|
||||
}
|
||||
|
||||
public static double Magnitude(Vector3d v) => Math.Sqrt(v.x * v.x + v.y * v.y + v.z * v.z);
|
||||
|
||||
public static double SqrMagnitude(Vector3d v) => v.x * v.x + v.y * v.y + v.z * v.z;
|
||||
|
||||
public static Vector3d Lerp(Vector3d a, Vector3d b, double t) => new Vector3d((1.0 - t) * a.x + t * b.x, (1.0 - t) * a.y + t * b.y, (1.0 - t) * a.z + t * b.z);
|
||||
|
||||
public static Vector3d LerpClamped(Vector3d a, Vector3d b, double t)
|
||||
{
|
||||
t = PFMath.Clamp01(t);
|
||||
return Vector3d.Lerp(a, b, t);
|
||||
}
|
||||
|
||||
public static Vector3d Scale(Vector3d a, Vector3d b) => new Vector3d(a.x * b.x, a.y * b.y, a.z * b.z);
|
||||
|
||||
public void Scale(Vector3d scale)
|
||||
{
|
||||
this.x *= scale.x;
|
||||
this.y *= scale.y;
|
||||
this.z *= scale.z;
|
||||
}
|
||||
|
||||
public static Vector3d Cross(Vector3d lhs, Vector3d rhs) => new Vector3d(lhs.y * rhs.z - lhs.z * rhs.y, lhs.z * rhs.x - lhs.x * rhs.z, lhs.x * rhs.y - lhs.y * rhs.x);
|
||||
|
||||
public override int GetHashCode() => this.x.GetHashCode() ^ this.y.GetHashCode() << 2 ^ this.z.GetHashCode() >> 2;
|
||||
|
||||
public override bool Equals(object other) => other is Vector3d other1 && this.Equals(other1);
|
||||
|
||||
public bool Equals(Vector3d other) => this == other;
|
||||
|
||||
public static Vector3d Normalize(Vector3d value)
|
||||
{
|
||||
double num = Vector3d.Magnitude(value);
|
||||
return num > 0.0 ? value / num : Vector3d.Zero;
|
||||
}
|
||||
|
||||
public void Normalize()
|
||||
{
|
||||
double num = Vector3d.Magnitude(this);
|
||||
if (num > 0.0)
|
||||
this = this / num;
|
||||
else
|
||||
this = Vector3d.Zero;
|
||||
}
|
||||
|
||||
public static double Dot(Vector3d lhs, Vector3d rhs) => lhs.x * rhs.x + lhs.y * rhs.y + lhs.z * rhs.z;
|
||||
|
||||
public static double Distance(Vector3d a, Vector3d b)
|
||||
{
|
||||
double num1 = a.x - b.x;
|
||||
double num2 = a.y - b.y;
|
||||
double num3 = a.z - b.z;
|
||||
return Math.Sqrt(num1 * num1 + num2 * num2 + num3 * num3);
|
||||
}
|
||||
|
||||
public static Vector3d operator +(Vector3d a, Vector3d b) => new Vector3d(a.x + b.x, a.y + b.y, a.z + b.z);
|
||||
|
||||
public static Vector3d operator -(Vector3d a, Vector3d b) => new Vector3d(a.x - b.x, a.y - b.y, a.z - b.z);
|
||||
|
||||
public static Vector3d operator -(Vector3d a) => new Vector3d(-a.x, -a.y, -a.z);
|
||||
|
||||
public static Vector3d operator *(Vector3d a, double d) => new Vector3d(a.x * d, a.y * d, a.z * d);
|
||||
|
||||
public static Vector3d operator *(double d, Vector3d a) => new Vector3d(a.x * d, a.y * d, a.z * d);
|
||||
|
||||
public static Vector3d operator /(Vector3d a, double d) => new Vector3d(a.x / d, a.y / d, a.z / d);
|
||||
|
||||
public static bool operator ==(Vector3d lhs, Vector3d rhs) => lhs.x == rhs.x && lhs.y == rhs.y && lhs.z == rhs.z;
|
||||
|
||||
public static bool operator !=(Vector3d lhs, Vector3d rhs) => !(lhs == rhs);
|
||||
|
||||
public override string ToString() => this.ToString((string)null);
|
||||
|
||||
public string ToString(string format)
|
||||
{
|
||||
if (string.IsNullOrEmpty(format))
|
||||
format = "F2";
|
||||
return "(" + this.x.ToString(format) + ", " + this.y.ToString(format) + ", " + this.z.ToString(format) + ")";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 8454158d7f8e40a47b7134e3fcb68882
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,92 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Assets.AR
|
||||
{
|
||||
|
||||
public class VideoPoint
|
||||
{
|
||||
public float Distance { get; set; }
|
||||
|
||||
public float Time { get; set; }
|
||||
}
|
||||
public class VideoPointsSync
|
||||
{
|
||||
private const float DefaultFps = 29.97f;
|
||||
protected float[] videoDistances;
|
||||
protected float[] videoTimes;
|
||||
protected float fps;
|
||||
|
||||
public int Count => this.videoDistances.Length;
|
||||
|
||||
public float LastVideoFrame => this.videoTimes[this.videoTimes.Length - 1] * this.fps;
|
||||
|
||||
public VideoPointsSync(IEnumerable<VideoPoint> videoPoints, float fps = 29.97f)
|
||||
{
|
||||
List<VideoPoint> list = videoPoints.ToList<VideoPoint>();
|
||||
list.Sort((Comparison<VideoPoint>)((x, y) => x.Distance.CompareTo(y.Distance)));
|
||||
VideoPoint videoPoint1 = list[0];
|
||||
for (int index = 1; index < list.Count; ++index)
|
||||
{
|
||||
VideoPoint videoPoint2 = list[index];
|
||||
if ((double)videoPoint2.Distance == (double)videoPoint1.Distance)
|
||||
{
|
||||
list.RemoveAt(index);
|
||||
--index;
|
||||
}
|
||||
else
|
||||
videoPoint1 = videoPoint2;
|
||||
}
|
||||
this.videoDistances = list.Select<VideoPoint, float>((Func<VideoPoint, float>)(x => x.Distance)).ToArray<float>();
|
||||
this.videoTimes = list.Select<VideoPoint, float>((Func<VideoPoint, float>)(x => x.Time)).ToArray<float>();
|
||||
this.fps = fps;
|
||||
}
|
||||
|
||||
public float GetVideoSpeedAtDistance(float distance)
|
||||
{
|
||||
int index = this.IndexOfVideoPointForDistance(distance);
|
||||
return index == 0 || index == this.Count ? 0.0f : (float)(((double)this.videoDistances[index] - (double)this.videoDistances[index - 1]) / ((double)this.videoTimes[index] - (double)this.videoTimes[index - 1]));
|
||||
}
|
||||
|
||||
public int IndexOfVideoPointForDistance(float distance)
|
||||
{
|
||||
int num = Array.BinarySearch<float>(this.videoDistances, distance);
|
||||
return num < 0 ? ~num : num;
|
||||
}
|
||||
|
||||
public int IndexOfVideoPointForTime(float time)
|
||||
{
|
||||
int num = Array.BinarySearch<float>(this.videoTimes, time);
|
||||
return num < 0 ? ~num : num;
|
||||
}
|
||||
|
||||
public float GetVideoFrameAtDistance(float distance)
|
||||
{
|
||||
int index = this.IndexOfVideoPointForDistance(distance);
|
||||
if (index == 0)
|
||||
return this.videoTimes[0] * this.fps;
|
||||
if (index == this.Count)
|
||||
return this.videoTimes[this.Count - 1] * this.fps;
|
||||
float t = Mathf.InverseLerp(this.videoDistances[index - 1], this.videoDistances[index], distance);
|
||||
return Mathf.Lerp(this.videoTimes[index - 1], this.videoTimes[index], t) * this.fps;
|
||||
}
|
||||
|
||||
public float GetDistanceForVideoFrame(float frame)
|
||||
{
|
||||
float time = frame / this.fps;
|
||||
int index = this.IndexOfVideoPointForTime(time);
|
||||
if (index == 0)
|
||||
return this.videoDistances[0];
|
||||
if (index == this.Count)
|
||||
return this.videoDistances[this.Count - 1];
|
||||
float t = Mathf.InverseLerp(this.videoTimes[index - 1], this.videoTimes[index], time);
|
||||
return Mathf.Lerp(this.videoDistances[index - 1], this.videoDistances[index], t);
|
||||
}
|
||||
|
||||
public float AverageVideoSpeed(float startFrame, float endFrame) => (double)startFrame == (double)endFrame ? this.GetVideoSpeedAtDistance(this.GetDistanceForVideoFrame(startFrame)) : (float)(((double)this.GetDistanceForVideoFrame(endFrame) - (double)this.GetDistanceForVideoFrame(startFrame)) * ((double)this.fps / ((double)endFrame - (double)startFrame)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fe1742dfacafb6e429b9388feba5699a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -3,6 +3,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using Assets.Scenes.Ride.Scripts;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
using UnityEngine.UI;
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: fd0502d9992fe874cb27602a4f08387f
|
||||
guid: c399d5298b73e4e4383e9974ee8ec290
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
@@ -0,0 +1,18 @@
|
||||
|
||||
namespace Assets.Core
|
||||
{
|
||||
public class DownloadInfo
|
||||
{
|
||||
public string DisplayName { get; set; }
|
||||
public string FileName { get; set; }
|
||||
public string Url { get; set; }
|
||||
public float Process { get; set; }
|
||||
public DownloadInfo(string FileName, string DisplayName, float Process,string url = "")
|
||||
{
|
||||
this.FileName = FileName;
|
||||
this.DisplayName = DisplayName;
|
||||
this.Process = Process;
|
||||
this.Url = url;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 34041572f14194b4aa5cdbd0318cf85a
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Assets.Core
|
||||
{
|
||||
public interface IRider
|
||||
{
|
||||
int UserId { get;}
|
||||
double StartDistance { get; set; }
|
||||
double OnlineSpeed { get; set; }
|
||||
double PreDistance { get; set; }
|
||||
double EndDistance { get; set; }
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5af0790cf9471fd4badab6e8bef4755f
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,7 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 77ec36f4b267a044ba7dcf316d9969c6
|
||||
guid: 728ddb37c92a36e45a166a4f403334eb
|
||||
folderAsset: yes
|
||||
timeCreated: 1478463916
|
||||
timeCreated: 1456430305
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a61959f9f2c6ba45be48f6cbe72abe7
|
||||
guid: df23ccf9e7363654e984640681ae86cd
|
||||
folderAsset: yes
|
||||
timeCreated: 1478463916
|
||||
timeCreated: 1456430305
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a8be24b3ee232d24ab71d392c9b495bc
|
||||
guid: 6c710f8c964a32a4bb73f15b7e8bf7db
|
||||
folderAsset: yes
|
||||
timeCreated: 1478463916
|
||||
timeCreated: 1525536557
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
@@ -0,0 +1,74 @@
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
/*
|
||||
* Copyright (c) 2018-2021 Beebyte Limited. All rights reserved.
|
||||
*/
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEditor.Compilation;
|
||||
|
||||
namespace Beebyte.Obfuscator.Assembly
|
||||
{
|
||||
public class AssemblyReferenceLocator
|
||||
{
|
||||
public static IEnumerable<string> GetAssemblyReferenceDirectories()
|
||||
{
|
||||
HashSet<string> directories = new HashSet<string>();
|
||||
|
||||
foreach (UnityEditor.Compilation.Assembly assembly in CompilationPipeline.GetAssemblies())
|
||||
{
|
||||
directories.UnionWith(GetAssemblyReferenceDirectories(assembly));
|
||||
}
|
||||
directories.Add("./Library/PlayerScriptAssemblies".Replace('/', Path.DirectorySeparatorChar));
|
||||
directories.UnionWith(GetUnityEditorLibDirectories());
|
||||
return directories;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetUnityEditorLibDirectories()
|
||||
{
|
||||
HashSet<string> libDirectories = new HashSet<string>();
|
||||
Stack<string> stack = new Stack<string>();
|
||||
var monoPath = EditorApplication.applicationContentsPath +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"MonoBleedingEdge" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"lib" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"mono";
|
||||
stack.Push(monoPath);
|
||||
|
||||
while (stack.Count > 0)
|
||||
{
|
||||
string dir = stack.Pop();
|
||||
if (Directory.GetFiles(dir, "*.dll").Length > 0)
|
||||
{
|
||||
libDirectories.Add(dir);
|
||||
}
|
||||
foreach (var childDirectory in Directory.GetDirectories(dir))
|
||||
{
|
||||
stack.Push(childDirectory);
|
||||
}
|
||||
}
|
||||
return libDirectories;
|
||||
}
|
||||
|
||||
private static IEnumerable<string> GetAssemblyReferenceDirectories(UnityEditor.Compilation.Assembly assembly)
|
||||
{
|
||||
HashSet<string> directories = new HashSet<string>();
|
||||
|
||||
if (assembly == null) return directories;
|
||||
|
||||
if (assembly.compiledAssemblyReferences == null || assembly.compiledAssemblyReferences.Length <= 0)
|
||||
{
|
||||
return directories;
|
||||
}
|
||||
|
||||
foreach (string assemblyRef in assembly.compiledAssemblyReferences)
|
||||
{
|
||||
directories.Add(Path.GetDirectoryName(assemblyRef));
|
||||
}
|
||||
return directories;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c209dcdf03e74ef2a8a2499bbbc6ac47
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,209 @@
|
||||
/*
|
||||
* Copyright (c) 2018-2020 Beebyte Limited. All rights reserved.
|
||||
*/
|
||||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Text.RegularExpressions;
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
using UnityEditor.Compilation;
|
||||
#endif
|
||||
using UnityEngine;
|
||||
|
||||
namespace Beebyte.Obfuscator.Assembly
|
||||
{
|
||||
public class AssemblySelector
|
||||
{
|
||||
private readonly HashSet<string> _compiledAssemblyPaths = new HashSet<string>();
|
||||
private readonly HashSet<string> _assemblyPaths = new HashSet<string>();
|
||||
|
||||
public AssemblySelector(Options options)
|
||||
{
|
||||
if (options == null) throw new ArgumentException("options must not be null", "options");
|
||||
if (options.compiledAssemblies == null)
|
||||
throw new ArgumentException(
|
||||
"options.compiledAssemblies must not be null", "options");
|
||||
if (options.assemblies == null)
|
||||
throw new ArgumentException(
|
||||
"options.assemblies must not be null", "options");
|
||||
if (Application.dataPath == null) throw new ArgumentException("Application.dataPath must not be null");
|
||||
|
||||
foreach (string assemblyName in options.compiledAssemblies)
|
||||
{
|
||||
string location = FindDllLocation(assemblyName);
|
||||
if (location != null)
|
||||
{
|
||||
_compiledAssemblyPaths.Add(location);
|
||||
}
|
||||
}
|
||||
|
||||
foreach (string assemblyName in options.assemblies)
|
||||
{
|
||||
string location = FindDllLocation(assemblyName);
|
||||
if (location != null)
|
||||
{
|
||||
_assemblyPaths.Add(location);
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
if (!options.includeCompilationPipelineAssemblies) return;
|
||||
|
||||
string projectDir = Path.GetDirectoryName(Application.dataPath);
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
#if UNITY_2019_3_OR_NEWER
|
||||
foreach (UnityEditor.Compilation.Assembly assembly in CompilationPipeline.GetAssemblies(AssembliesType
|
||||
.PlayerWithoutTestAssemblies))
|
||||
#else
|
||||
foreach (UnityEditor.Compilation.Assembly assembly in CompilationPipeline.GetAssemblies(AssembliesType.Player))
|
||||
#endif
|
||||
{
|
||||
#else
|
||||
foreach (UnityEditor.Compilation.Assembly assembly in CompilationPipeline.GetAssemblies())
|
||||
{
|
||||
if ((assembly.flags & AssemblyFlags.EditorAssembly) != 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
#endif
|
||||
if (assembly.name.Contains("-firstpass"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assembly.sourceFiles.Length == 0)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (assembly.sourceFiles[0].StartsWith("Packages"))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
string scriptDllLocation = Path.Combine(projectDir, assembly.outputPath).Replace('\\', '/');
|
||||
#if !UNITY_2019_2_OR_NEWER || UNITY_2019_2_0 || UNITY_2019_2_1 || UNITY_2019_2_2 || UNITY_2019_2_3 || UNITY_2019_2_4 || UNITY_2019_2_5 || UNITY_2019_2_6 || UNITY_2019_2_7
|
||||
string dllLocation = scriptDllLocation;
|
||||
#else
|
||||
string dllLocation = ConvertToPlayerAssemblyLocationIfPresent(scriptDllLocation);
|
||||
#endif
|
||||
|
||||
// If the assembly is for a different build target platform, oddly it will still be in the compilation
|
||||
// pipeline, however the file won't actually exist.
|
||||
if (File.Exists(dllLocation))
|
||||
{
|
||||
_assemblyPaths.Add(dllLocation);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
public ICollection<string> GetCompiledAssemblyPaths()
|
||||
{
|
||||
return _compiledAssemblyPaths;
|
||||
}
|
||||
|
||||
public ICollection<string> GetAssemblyPaths()
|
||||
{
|
||||
return _assemblyPaths;
|
||||
}
|
||||
|
||||
private static string FindDllLocation(string suffix)
|
||||
{
|
||||
if (string.IsNullOrEmpty(suffix))
|
||||
{
|
||||
throw new ArgumentException(
|
||||
"Empty or null DLL names are forbidden (check Obfuscator Options assemblies / compiled assemblies list)");
|
||||
}
|
||||
|
||||
string compiledAssemblyLocation = GetCompiledAssemblyLocation(suffix);
|
||||
|
||||
#if !UNITY_2019_2_OR_NEWER || UNITY_2019_2_0 || UNITY_2019_2_1 || UNITY_2019_2_2 || UNITY_2019_2_3 || UNITY_2019_2_4 || UNITY_2019_2_5 || UNITY_2019_2_6 || UNITY_2019_2_7
|
||||
return compiledAssemblyLocation;
|
||||
#else
|
||||
return ConvertToPlayerAssemblyLocationIfPresent(compiledAssemblyLocation);
|
||||
#endif
|
||||
}
|
||||
|
||||
private static string GetCompiledAssemblyLocation(string suffix)
|
||||
{
|
||||
if (IsAPath(suffix))
|
||||
{
|
||||
var path = GetFileOnKnownPath(suffix);
|
||||
if (path != null)
|
||||
{
|
||||
return path;
|
||||
}
|
||||
}
|
||||
|
||||
foreach (System.Reflection.Assembly assembly in AppDomain.CurrentDomain.GetAssemblies())
|
||||
{
|
||||
try
|
||||
{
|
||||
if (assembly.Location.Equals(string.Empty))
|
||||
{
|
||||
DisplayFailedAssemblyParseWarning(assembly);
|
||||
}
|
||||
else if (assembly.Location.EndsWith(suffix))
|
||||
{
|
||||
return assembly.Location.Replace('\\', '/');
|
||||
}
|
||||
}
|
||||
catch (NotSupportedException)
|
||||
{
|
||||
DisplayFailedAssemblyParseWarning(assembly);
|
||||
}
|
||||
}
|
||||
|
||||
Debug.LogWarning(
|
||||
suffix + " was not found (check Obfuscator Options assemblies / compiled assemblies list)");
|
||||
return null;
|
||||
}
|
||||
|
||||
private static bool IsAPath(string s)
|
||||
{
|
||||
return s.Contains("/") || s.Contains("\\");
|
||||
}
|
||||
|
||||
private static string GetFileOnKnownPath(string path)
|
||||
{
|
||||
var fromAssetFolder = Application.dataPath + Path.DirectorySeparatorChar.ToString() + path;
|
||||
if (File.Exists(fromAssetFolder))
|
||||
{
|
||||
return fromAssetFolder;
|
||||
}
|
||||
|
||||
if (File.Exists(path))
|
||||
{
|
||||
return path;
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
private static string ConvertToPlayerAssemblyLocationIfPresent(string location)
|
||||
{
|
||||
if (location == null)
|
||||
{
|
||||
return null;
|
||||
}
|
||||
|
||||
string beeScriptAssemblyLocation =
|
||||
Regex.Replace(location, "/ScriptAssemblies/", "/Bee/PlayerScriptAssemblies/");
|
||||
string playerScriptAssemblyLocation =
|
||||
Regex.Replace(location, "/ScriptAssemblies/", "/PlayerScriptAssemblies/");
|
||||
return File.Exists(beeScriptAssemblyLocation) ? beeScriptAssemblyLocation :
|
||||
File.Exists(playerScriptAssemblyLocation) ? playerScriptAssemblyLocation : location;
|
||||
}
|
||||
|
||||
private static void DisplayFailedAssemblyParseWarning(System.Reflection.Assembly assembly)
|
||||
{
|
||||
Debug.LogWarning("Could not parse dynamically created assembly (string.Empty location) " +
|
||||
assembly.FullName +
|
||||
". If you extend classes from within this assembly that in turn extend from " +
|
||||
"MonoBehaviour you will need to manually annotate these classes with [Skip]");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: d048d941eb0d44c1b2321e1feaa06fc0
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,87 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2019 Beebyte Limited. All rights reserved.
|
||||
*/
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Threading;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
public class FileBackup
|
||||
{
|
||||
/**
|
||||
* Returns a map consisting of keys of the original file and a proposed target location.
|
||||
*/
|
||||
public static IDictionary<string, string> GetBackupMap(IEnumerable<string> locations)
|
||||
{
|
||||
IDictionary<string, string> pathMap = new Dictionary<string, string>();
|
||||
|
||||
foreach (string location in locations)
|
||||
{
|
||||
string backupLocation = location + ".bb_obf_backup.pre";
|
||||
pathMap.Add(location, backupLocation);
|
||||
}
|
||||
|
||||
return pathMap;
|
||||
}
|
||||
|
||||
/**
|
||||
* Backs up files specified in the keys of the map to their corresponding values.
|
||||
*/
|
||||
public static void Backup(IDictionary<string, string> backupMap)
|
||||
{
|
||||
foreach (KeyValuePair<string,string> keyValuePair in backupMap)
|
||||
{
|
||||
//This throws an exception if the backup already exists - we want this to happen
|
||||
File.Copy(keyValuePair.Key, keyValuePair.Value);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
*
|
||||
*/
|
||||
public static void Restore(IDictionary<string, string> pathMap)
|
||||
{
|
||||
foreach (KeyValuePair<string, string> entry in pathMap)
|
||||
{
|
||||
string target = entry.Key;
|
||||
string backup = entry.Value;
|
||||
|
||||
try
|
||||
{
|
||||
if (!File.Exists(backup)) continue;
|
||||
|
||||
DeleteFileWhenPermitted(target);
|
||||
File.Move(backup, target);
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("Could not restore original DLL to " + target + "\n" + e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void DeleteFileWhenPermitted(string target)
|
||||
{
|
||||
int attempts = 60;
|
||||
while (attempts > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
if (File.Exists(target)) File.Delete(target);
|
||||
if (attempts < 60) Debug.LogWarning("Successfully accessed " + target);
|
||||
return;
|
||||
}
|
||||
catch (Exception)
|
||||
{
|
||||
Debug.LogWarning("Failed to access " + target + " - Retrying...");
|
||||
Thread.Sleep(500);
|
||||
if (--attempts <= 0) throw;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 394a919afd2ae05469de950ccb62fad7
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,67 @@
|
||||
/*
|
||||
* Copyright (c) 2020 Beebyte Limited. All rights reserved.
|
||||
*/
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
public class GlobalGameManagersPath
|
||||
{
|
||||
internal static string GetPathToGlobalGameManagersAsset(BuildTarget buildTarget, string buildPath)
|
||||
{
|
||||
if ((int) buildTarget == 2)
|
||||
{
|
||||
return GetPathForMac(buildPath);
|
||||
}
|
||||
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
if (EditorUserBuildSettings.GetPlatformSettings("Standalone", "CreateSolution").Equals("true"))
|
||||
{
|
||||
return GetPathForVSProjectWindowsAndLinuxStandalone(buildPath);
|
||||
}
|
||||
#endif
|
||||
return GetPathForWindowsAndLinuxStandalone(buildPath);
|
||||
}
|
||||
|
||||
private static string GetPathForMac(string buildPath)
|
||||
{
|
||||
return Path.GetDirectoryName(buildPath) +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
Path.GetFileNameWithoutExtension(buildPath) +
|
||||
".app" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"Contents" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"Resources" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"Data" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"globalgamemanagers.assets";
|
||||
}
|
||||
|
||||
private static string GetPathForWindowsAndLinuxStandalone(string buildPath)
|
||||
{
|
||||
return Path.GetDirectoryName(buildPath) +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
Path.GetFileNameWithoutExtension(buildPath) +
|
||||
"_Data" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"globalgamemanagers.assets";
|
||||
}
|
||||
|
||||
private static string GetPathForVSProjectWindowsAndLinuxStandalone(string buildPath)
|
||||
{
|
||||
return Path.GetDirectoryName(buildPath) +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"build" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"bin" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
Path.GetFileNameWithoutExtension(buildPath) +
|
||||
"_Data" +
|
||||
Path.DirectorySeparatorChar.ToString() +
|
||||
"globalgamemanagers.assets";
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 3e3ecf6bcbce4c84e9acc4cb4d8a0481
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 711b9ff7066f3ec459cd07638a83395a
|
||||
folderAsset: yes
|
||||
timeCreated: 1456430305
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 5a6eeb7814c8aa443b8b82084170b6d4
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4a22658590e81f24e8559971b6d77a57
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 2f8c8a3fc07f10749a23a773b93b97b6
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,33 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 17a4ace9e0958b2488d4433197bc79f9
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 02d2e270ae961de4fb322613eb4815e3
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,162 @@
|
||||
using UnityEngine;
|
||||
using Beebyte.Obfuscator;
|
||||
|
||||
public class ObfuscatorExample : MonoBehaviour
|
||||
{
|
||||
public Color publicObfuscatedField = Color.red; // <- Obfuscated
|
||||
private Color privateObfuscatedField = Color.blue; // <- Obfuscated
|
||||
|
||||
private string normalLiteral = "Typical string";
|
||||
|
||||
//Enable string obfuscation for the following:
|
||||
private string hiddenLiteral = "^Cannot see me^"; // The client will resolve this string as "Cannot see me", but a code inspector will show it as a byte array containing jibberish
|
||||
|
||||
[Rename("RenamedPublicField")]
|
||||
public Color OldPublicField = Color.black; // <- Renamed to RenamedPublicField
|
||||
|
||||
[Skip]
|
||||
private Color visibleColor = Color.blue; // <- This is left as visibleColor
|
||||
[SkipRename]
|
||||
private Color anotherVisibleColor = Color.blue; // <- This is left as anotherVisibleColor
|
||||
|
||||
void Start() // <- Key MonoBehaviour methods like Start are left untouched
|
||||
{
|
||||
Debug.Log("Started Example");
|
||||
|
||||
Debug.Log(normalLiteral);
|
||||
Debug.Log(hiddenLiteral);
|
||||
Debug.Log(visibleColor);
|
||||
Debug.Log(anotherVisibleColor);
|
||||
}
|
||||
|
||||
public void ObfuscatedMethod(Color c) // <- Obfuscated method name and parameter
|
||||
{
|
||||
this.privateObfuscatedField = c;
|
||||
}
|
||||
|
||||
public Color ObfuscatedMethod() // <- Obfuscated
|
||||
{
|
||||
return this.privateObfuscatedField;
|
||||
}
|
||||
|
||||
[SkipRename]
|
||||
public Color SkipRenameMethod(Color obfuscatedParameter) // <- Method name is left as SkipRenameMethod, parameter is obfuscated
|
||||
{
|
||||
return obfuscatedParameter;
|
||||
}
|
||||
|
||||
[System.Reflection.Obfuscation(ApplyToMembers=false)] // This is equivalent to [SkipRename]
|
||||
public Color EquivalentMethod(Color obfuscatedParameter) // <- Method name is left as EquivalentMethod, parameter is obfuscated
|
||||
{
|
||||
return obfuscatedParameter;
|
||||
}
|
||||
|
||||
[Skip]
|
||||
public Color SkipMethod(Color visibleParameter) // <- Nothing in this method gets obfuscated, including the parameter
|
||||
{
|
||||
return visibleParameter;
|
||||
}
|
||||
|
||||
[Rename("MyVisibleRename")]
|
||||
public Color OldName(Color obfuscatedParameter) // <- Method name is changed to MyVisibleRename, parameter is obfuscated
|
||||
{
|
||||
return obfuscatedParameter;
|
||||
}
|
||||
|
||||
[SkipRename]
|
||||
public void OnButtonClick() // <- Button clicks assigned through the inspector should ALWAYS use the SkipRename flag, otherwise they will silently fail
|
||||
{
|
||||
/*
|
||||
* Enable string obfuscation for the following.
|
||||
* It worth noting here that obfuscated string literals are best declared as class static variables for performance reasons,
|
||||
* however the following examples will still work.
|
||||
*/
|
||||
Debug.Log("^Button was clicked1^"); // <- This gets obfuscated, and will print: Button was clicked1
|
||||
|
||||
Debug.Log("Button " + "^was^" + "clicked2"); // This won't work and will print: Button ^was^ clicked2
|
||||
|
||||
string was = "^was^";
|
||||
Debug.Log("Button " + was + "clicked3"); // This works, and prints: Button was clicked3
|
||||
|
||||
Debug.Log("Button was clicked4");
|
||||
}
|
||||
|
||||
[SkipRename]
|
||||
public void OnAnimationEvent() // Animation events assigned through the inspector should be excluded from obfuscation
|
||||
{
|
||||
}
|
||||
|
||||
public void ObfuscatedButtonMethod() // Button click methods can be obfuscated if they are assigned programatically, e.g. button.onClick.AddListener(ObfuscatedButtonMethod);
|
||||
{
|
||||
}
|
||||
|
||||
[ObfuscateLiterals] //New in version 1.17.0
|
||||
private void LiterallyLotsOfLiterals()
|
||||
{
|
||||
string we = "We";
|
||||
Debug.Log("Here " + we + "have three obfuscated literals. No markers needed!");
|
||||
}
|
||||
|
||||
private System.Collections.IEnumerator MyAmazingMethod() // <-- With default options Coroutine methods are obfuscated too!
|
||||
{
|
||||
//...
|
||||
yield return null;
|
||||
}
|
||||
|
||||
private void SomeMethodCallingACoroutine()
|
||||
{
|
||||
StartCoroutine("MyAmazingMethod"); // <-- With default options "MyAmazingMethod" here will be automatically
|
||||
// substituted for the new obfuscated name assigned to MyAmazingMethod()
|
||||
}
|
||||
|
||||
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
#else
|
||||
#pragma warning disable 618
|
||||
[RPC]
|
||||
[ReplaceLiteralsWithName]
|
||||
[Rename("9xy")]
|
||||
void MyRPCMethod(string message) //This method is renamed to 9xy and all references of the exact string "MyRPCMethod" are replaced with "9xy"
|
||||
{
|
||||
}
|
||||
|
||||
void NetworkingCode()
|
||||
{
|
||||
NetworkView nView = null;
|
||||
|
||||
//Because MyRPCMethod was annotated with the [ReplaceLiteralsWithName] attribute, the "MyRPCMethod" string here will be replaced with "9xy"
|
||||
nView.RPC("MyRPCMethod", RPCMode.AllBuffered, "Hello World");
|
||||
|
||||
UnityEngine.Debug.Log("Today I took my MyRPCMethod for a walk"); //This string is not changed.
|
||||
}
|
||||
|
||||
[RPC]
|
||||
void AnotherRPCMethod() //by default, RPC annotated methods are not renamed
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* For 3rd party RPC annotations to be recognised, add the attribute's canonical classname to the "Alternate RPC Annotations" array in Options
|
||||
* e.g. Third.Party.SomeOtherRPC
|
||||
*
|
||||
[SomeOtherRPC]
|
||||
void NonUnityRPCMethod()
|
||||
{
|
||||
}
|
||||
*/
|
||||
#pragma warning restore 618
|
||||
#endif
|
||||
}
|
||||
|
||||
namespace MyNamespace
|
||||
{
|
||||
[Rename("MovedNamespace.ObfuscatedName")] //Rename can change the namespace too!
|
||||
public class MyClass
|
||||
{
|
||||
}
|
||||
|
||||
[Rename("NewName")] //When the namespace isn't specified on a class, it will either leave it in the same namespace or move it to the default namespace if Strip Namespaces is enabled
|
||||
public class MyOtherClass
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: a90e2dac090cc6844aedc1fa9c457ac5
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,59 @@
|
||||
/*
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
public class ObfuscatorMenuExample
|
||||
{
|
||||
private static Options _options = null;
|
||||
|
||||
private static IList<string> GetDllPaths()
|
||||
{
|
||||
var dlls = new List<string> {@"C:\path\to\External.dll"};
|
||||
|
||||
foreach (string dll in dlls.Where(dll => !File.Exists(dll)))
|
||||
{
|
||||
throw new Exception("Could not find " + dll);
|
||||
}
|
||||
return dlls;
|
||||
}
|
||||
|
||||
[MenuItem("Tools/Obfuscate External DLL")]
|
||||
private static void ObfuscateExternalDll()
|
||||
{
|
||||
Debug.Log("Obfuscating");
|
||||
|
||||
var dllPaths = GetDllPaths();
|
||||
|
||||
//Options are read in the same way as normal Obfuscation, i.e. from the ObfuscatorOptions.asset
|
||||
if (_options == null) _options = OptionsManager.LoadOptions();
|
||||
|
||||
bool oldSkipRenameOfAllPublicMonobehaviourFields = _options.skipRenameOfAllPublicMonobehaviourFields;
|
||||
try
|
||||
{
|
||||
//Preserving monobehaviour public field names is an common step for obfuscating external DLLs that
|
||||
//allow MonoBehaviours to be dragged into the scene's hierarchy.
|
||||
_options.skipRenameOfAllPublicMonobehaviourFields = true;
|
||||
|
||||
//Consider setting this hidden value to false to allow classes like EditorWindow to be obfuscated.
|
||||
//ScriptableObjects would normally be treated as Serializable to avoid breaking loading/saving,
|
||||
//but for Editor windows this might not be necessary.
|
||||
//options.treatScriptableObjectsAsSerializable = false;
|
||||
|
||||
Obfuscator.SetExtraAssemblyDirectories(_options.extraAssemblyDirectories);
|
||||
Obfuscator.Obfuscate(dllPaths, _options, EditorUserBuildSettings.activeBuildTarget);
|
||||
}
|
||||
finally
|
||||
{
|
||||
_options.skipRenameOfAllPublicMonobehaviourFields = oldSkipRenameOfAllPublicMonobehaviourFields;
|
||||
EditorUtility.ClearProgressBar();
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
*/
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 91c4b3f6a3ac7854cb305ce1f2707fa2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,315 @@
|
||||
%YAML 1.1
|
||||
%TAG !u! tag:unity3d.com,2011:
|
||||
--- !u!114 &11400000
|
||||
MonoBehaviour:
|
||||
m_ObjectHideFlags: 0
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_GameObject: {fileID: 0}
|
||||
m_Enabled: 1
|
||||
m_EditorHideFlags: 0
|
||||
m_Script: {fileID: 1864490332, guid: 66bd02e2746234647a685703c57241ec, type: 3}
|
||||
m_Name: ObfuscatorOptions
|
||||
m_EditorClassIdentifier:
|
||||
classes: 1
|
||||
methods: 1
|
||||
parameters: 1
|
||||
fields: 0
|
||||
properties: 1
|
||||
events: 1
|
||||
skipRenameOfAllPublicMonobehaviourMethods: 1
|
||||
skipRenameOfAllPublicMonobehaviourFields: 1
|
||||
searchForUnityReflectionMethods: 1
|
||||
obfuscateLiterals: 1
|
||||
stripLiteralEscapeCharacters: 1
|
||||
obfuscateMarkerInDecimal: 94
|
||||
RSAKeyLength: 1024
|
||||
addFakeCode: 1
|
||||
minFalseMethodsPerClass: 10
|
||||
maxFalseMethodsPerClass: 150
|
||||
unicodeStartInDecimal: 65
|
||||
numberOfCharacters: 2
|
||||
createNameTranslationFile: 0
|
||||
nameTranslationFile: nameTranslation.txt
|
||||
usePreviousObfuscation: 0
|
||||
previousNameTranslationFile: nameTranslation.txt
|
||||
obfuscateAndReplaceLiteralsForRPCMethods: 0
|
||||
addObfuscatorMarker: 1
|
||||
skipNamespaces:
|
||||
- Google
|
||||
- GooglePlayGames
|
||||
- Net.Json
|
||||
- HutongGames.PlayMaker
|
||||
- ChartboostSDK
|
||||
- BestHTTP
|
||||
- InControl
|
||||
- PlayFab
|
||||
- GoogleMobileAds
|
||||
- ExitGames
|
||||
- Com.Google
|
||||
- Zenject
|
||||
- UniRx
|
||||
- DG.Tweening
|
||||
- LeanplumSDK
|
||||
- Org.BouncyCastle
|
||||
- Bolt
|
||||
- BoltInternal
|
||||
- UdpKit
|
||||
- LapinerTools
|
||||
- VRInteraction
|
||||
- Photon
|
||||
- TMPro
|
||||
- QFSW
|
||||
- Sirenix
|
||||
- ANT_WrappedLib
|
||||
- ANT_NET
|
||||
- AVProVideo
|
||||
unityMethods:
|
||||
- Awake
|
||||
- FixedUpdate
|
||||
- LateUpdate
|
||||
- OnAnimatorIK
|
||||
- OnAnimatorMove
|
||||
- OnApplicationFocus
|
||||
- OnApplicationPause
|
||||
- OnApplicationQuit
|
||||
- OnAudioFilterRead
|
||||
- OnBecameInvisible
|
||||
- OnBecameVisible
|
||||
- OnCollisionEnter
|
||||
- OnCollisionEnter2D
|
||||
- OnCollisionExit
|
||||
- OnCollisionExit2D
|
||||
- OnCollisionStay
|
||||
- OnCollisionStay2D
|
||||
- OnConnectedToServer
|
||||
- OnControllerColliderHit
|
||||
- OnDestroy
|
||||
- OnDisable
|
||||
- OnDisconnectedFromServer
|
||||
- OnDrawGizmos
|
||||
- OnDrawGizmosSelected
|
||||
- OnEnable
|
||||
- OnFailedToConnect
|
||||
- OnFailedToConnectToMasterServer
|
||||
- OnGUI
|
||||
- OnJointBreak
|
||||
- OnLevelWasLoaded
|
||||
- OnMasterServerEvent
|
||||
- OnMouseDown
|
||||
- OnMouseDrag
|
||||
- OnMouseEnter
|
||||
- OnMouseExit
|
||||
- OnMouseOver
|
||||
- OnMouseUp
|
||||
- OnMouseUpAsButton
|
||||
- OnNetworkInstantiate
|
||||
- OnParticleCollision
|
||||
- OnPlayerConnected
|
||||
- OnPlayerDisconnected
|
||||
- OnPostRender
|
||||
- OnPreCull
|
||||
- OnPreRender
|
||||
- OnRenderImage
|
||||
- OnRenderObject
|
||||
- OnSerializeNetworkView
|
||||
- OnServerInitialized
|
||||
- OnTransformChildrenChanged
|
||||
- OnTransformParentChanged
|
||||
- OnTriggerEnter
|
||||
- OnTriggerEnter2D
|
||||
- OnTriggerExit
|
||||
- OnTriggerExit2D
|
||||
- OnTriggerStay
|
||||
- OnTriggerStay2D
|
||||
- OnValidate
|
||||
- OnWillRenderObject
|
||||
- Reset
|
||||
- Start
|
||||
- Update
|
||||
- OnConnectedToPhoton
|
||||
- OnLeftRoom
|
||||
- OnMasterClientSwitched
|
||||
- OnPhotonCreateRoomFailed
|
||||
- OnPhotonJoinRoomFailed
|
||||
- OnCreatedRoom
|
||||
- OnJoinedLobby
|
||||
- OnLeftLobby
|
||||
- OnDisconnectedFromPhoton
|
||||
- OnConnectionFail
|
||||
- OnFailedToConnectToPhoton
|
||||
- OnReceivedRoomListUpdate
|
||||
- OnJoinedRoom
|
||||
- OnPhotonPlayerConnected
|
||||
- OnPhotonPlayerDisconnected
|
||||
- OnPhotonRandomJoinFailed
|
||||
- OnConnectedToMaster
|
||||
- OnPhotonSerializeView
|
||||
- OnPhotonInstantiate
|
||||
- OnPhotonMaxCccuReached
|
||||
- OnPhotonCustomRoomPropertiesChanged
|
||||
- OnPhotonPlayerPropertiesChanged
|
||||
- OnUpdatedFriendList
|
||||
- OnCustomAuthenticationFailed
|
||||
- OnCustomAuthenticationResponse
|
||||
- OnWebRpcResponse
|
||||
- OnOwnershipRequest
|
||||
- OnLobbyStatisticsUpdate
|
||||
- OnJointBreak2D
|
||||
- OnParticleSystemStopped
|
||||
- OnParticleTrigger
|
||||
- OnParticleUpdateJobScheduled
|
||||
skipClasses:
|
||||
- MonoPInvokeCallbackAttribute
|
||||
- CloudRegionCode
|
||||
- PhotonNetworkingMessage
|
||||
- PhotonLogLevel
|
||||
- PhotonTargets
|
||||
- CloudRegionFlag
|
||||
- ConnectionState
|
||||
- EncryptionMode
|
||||
- EncryptionDataParameters
|
||||
- ClientState
|
||||
- ClientState/JoinType
|
||||
- DisconnectCause
|
||||
- ServerConnection
|
||||
- MatchmakingMode
|
||||
- JoinMode
|
||||
- ReceiverGroup
|
||||
- EventCaching
|
||||
- PropertyTypeFlag
|
||||
- LobbyType
|
||||
- AuthModeOption
|
||||
- CustomAuthenticationType
|
||||
- PickupCharacterState
|
||||
- CharacterState
|
||||
- OnSerializeTransform
|
||||
- ViewSynchronization
|
||||
- OnSerializeRigidBody
|
||||
- OwnershipOption
|
||||
- JoinType
|
||||
- OpJoinRandomRoomParams
|
||||
- BoltAOI
|
||||
- BoltPOI
|
||||
- BoltDebugStart
|
||||
- BoltDebugStartSettings
|
||||
- BoltExecutionOrderAttribute
|
||||
- BoltNetworkUtils
|
||||
- BoltRuntimeConfigs
|
||||
alternateRPCAnnotations:
|
||||
- PunRPC
|
||||
- Photon.Pun.PunRPC
|
||||
includePublicClasses: 1
|
||||
includePublicMethods: 1
|
||||
includePublicFields: 1
|
||||
includePublicProperties: 1
|
||||
includePublicEvents: 1
|
||||
includeProtectedClasses: 1
|
||||
includeProtectedMethods: 1
|
||||
includeProtectedFields: 1
|
||||
includeProtectedProperties: 1
|
||||
includeProtectedEvents: 1
|
||||
enabled: 1
|
||||
onlyObfuscatedSpecifiedNamespaces: 1
|
||||
skipNamespacesRecursively: 1
|
||||
obfuscateSpecifiedNamespacesRecursively: 1
|
||||
obfuscateNamespaces:
|
||||
- Assets.AR
|
||||
- Assets.Scripts.Devices.Ant
|
||||
- Assets.Scripts.Devices.Ant.Interfaces
|
||||
- Assets.Scripts.Devices.Ant.LegacyPages
|
||||
- Assets.Scripts.Devices.Ant.Messages
|
||||
- Assets.Scripts.Devices.Ant.Pages.CalibrationPages
|
||||
- Assets.Scripts.Devices.Ant.Pages
|
||||
replaceLiteralsOnSkippedClasses: 1
|
||||
obfuscateUnityReflectionMethods: 1
|
||||
inheritBeebyteAttributes: 0
|
||||
treatScriptableObjectsAsSerializable: 1
|
||||
deriveNamesFromCryptoHash: 1
|
||||
sha1seed: OlnfRzHVH1wscaKJWrQI4cLi
|
||||
numberOfDifferentCharactersAsPowerOfTwo: 4
|
||||
numberOfHashBitsToUse: 6
|
||||
allowCopyingOfAllAttributesInFakeCode: 0
|
||||
allowCopyingOfBeebyteAttributesInFakeCode: 1
|
||||
simplifiedNameTranslationForCryptoHash: 0
|
||||
reverseNameTranslationOrderPerLine: 1
|
||||
namePaddingDelimiter: 0
|
||||
preservePrefixes:
|
||||
- OnMessage_
|
||||
- OnValue_
|
||||
- OnAttempt_
|
||||
- CanStart_
|
||||
- CanStop_
|
||||
- OnStart_
|
||||
- OnStop_
|
||||
- OnFailStart_
|
||||
- OnFailStop_
|
||||
skipEnums: 1
|
||||
maxInstructionsForCloning: 2000
|
||||
preserveNamespaces: 0
|
||||
obfuscateMonoBehaviourClassNames: 1
|
||||
replaceLiterals:
|
||||
- OnHover
|
||||
- OnSelect
|
||||
- OnInput
|
||||
- OnScroll
|
||||
- OnKey
|
||||
- OnPress
|
||||
- OnDrag
|
||||
- OnClick
|
||||
- OnDoubleClick
|
||||
- OnDrop
|
||||
- OnTooltip
|
||||
presetPathClasses: []
|
||||
presetPaths: []
|
||||
includeParametersOnPublicMethods: 1
|
||||
includeParametersOnProtectedMethods: 1
|
||||
abstractMonoBehaviours:
|
||||
- Photon.MonoBehaviour
|
||||
- Photon.PunBehaviour
|
||||
- SupportLogging
|
||||
useSimplifiedObfuscateLiterals: 0
|
||||
translateFakeMethods: 0
|
||||
attributesContainingLiteralsToBeReplaced: []
|
||||
obfuscateBeebyteTypes: 0
|
||||
exposeTranslations: 0
|
||||
equivalentAttributesForDoNotFake: []
|
||||
equivalentAttributesForObfuscateLiterals: []
|
||||
equivalentAttributesForReplaceLiteralsWithName: []
|
||||
equivalentAttributesForSkip:
|
||||
- Unity.Burst.BurstCompileAttribute
|
||||
equivalentAttributesForSkipRename:
|
||||
- Newtonsoft.Json.JsonPropertyAttribute
|
||||
includeCompilationPipelineAssemblies: 0
|
||||
assemblies:
|
||||
- Assembly-CSharp.dll
|
||||
compiledAssemblies: []
|
||||
extraAssemblyDirectories: []
|
||||
referencedAssemblies: []
|
||||
onlyObfuscateLiteralsInObfuscatedMethods: 0
|
||||
obfuscateLiteralsInAllMethods: 0
|
||||
noPublicFakeMethods: 0
|
||||
progressBar: 1
|
||||
obfuscateReleaseOnly: 0
|
||||
attributesToRemoveIfObfuscatedMember:
|
||||
- UnityEngine.AddComponentMenu
|
||||
- UnityEngine.ContextMenu
|
||||
- UnityEngine.ContextMenuItem
|
||||
- UnityEngine.CreateAssetMenu
|
||||
- UnityEngine.Header
|
||||
- UnityEngine.HelpURL
|
||||
- UnityEngine.Tooltip
|
||||
appendGenericTick: 0
|
||||
equivalentAttributesForRename: []
|
||||
doNotConvertConstantLiteralsToStatics: 0
|
||||
useRandomisedNameGenerator: 0
|
||||
forcedRandomSeed: 0
|
||||
allowShortShaSalt: 0
|
||||
printShaSaltInNameTranslationFile: 0
|
||||
randomiseShaSaltOnBuild: 1
|
||||
equivalentAttributesForSuppressLog: []
|
||||
obfuscateAnonymousTypes: 0
|
||||
obfuscateAnonymousYieldingEnumeratorTypes: 1
|
||||
allowCompilerGeneratedFieldsOnSerializedTypesToBeObfuscated: 0
|
||||
literalObfuscationBlockLength: 64
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 94453fde78581304aacd98d1b98bc8ad
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 11400000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,821 @@
|
||||
Obfuscator v3.9.9 Copyright (c) 2015-2022 Beebyte Limited. All Rights Reserved
|
||||
|
||||
Please see the Obfuscator.pdf document for more detailed guidance.
|
||||
|
||||
Usage
|
||||
=====
|
||||
|
||||
The obfuscator is designed to work out of the box. When you build your project it automatically replaces the Assembly-CSharp.dll with an obfuscated version. If you use assembly definitions then these too will be obfuscated by default.
|
||||
|
||||
The default settings provide a good level of obfuscation, but it's worth looking at Options to enable or disable extra features (such as string literal obfuscation).
|
||||
|
||||
See https://www.youtube.com/watch?v=a5ypXst4OaM for a video example.
|
||||
|
||||
|
||||
Options
|
||||
=======
|
||||
|
||||
From within Unity, select the ObfuscatorOptions asset in the Assets/Editor/Beebyte/Obfuscator directory.
|
||||
|
||||
From the Inspector window, you can now see the Obfuscation options available along with descriptions where relevant. The default settings provide a solid configuration that obfuscates the majority of your code, but here you have general control over what is obfuscated.
|
||||
|
||||
|
||||
Code Attributes
|
||||
===============
|
||||
|
||||
Methods often need to be left unobfuscated so that they can be referenced from an external plugin via reflection, or for some other reason. Or maybe you just want a field called "password" to appear as "versionId" when viewed by a decompiler.
|
||||
|
||||
You can achieve this by adding Attributes to your code. Have a look at Assets/Editor/Beebyte/Obfuscator/ObfuscatorExample.cs to see how this is done.
|
||||
|
||||
The standard System.Reflection.Obfuscation attribute is supported.
|
||||
|
||||
The following Beebyte specific attributes are supported:
|
||||
|
||||
[SkipRename] - The obfuscator will not rename this class/method/field, but will continue to obfuscate its contents (if relevant).
|
||||
[Skip] - The obfuscator will not rename this class/method/field, nor will it obfuscate its contents.
|
||||
[Rename("MyRenameExample")] - The obfuscator will rename this class/method/field to the specified name. Class renames can accept a namespace rename, i.e. [Rename("MyNamespace.MyClass")]
|
||||
[ReplaceLiteralsWithName] - If the target is obfuscated, then any literals with the exact original name will be converted to use the new obfuscated name. e.g. if method MyMethod is renamed to AAABBB, then any string literals of exactly "MyMethod" anywhere in your code will be adjusted to be "AAABBB" instead.
|
||||
[ObfuscateLiterals] - Any string literals found within this method will be instructed to be obfuscated. This is a partial replacement to the clunky way of surrounding strings with '^' characters.
|
||||
[DoNotFake] - Fake code will not be generated for this class/method.
|
||||
[SuppressLog("MessageCode")] - Prevents specific Obfuscator messages from being printed
|
||||
|
||||
|
||||
Troubleshooting F.A.Q
|
||||
=====================
|
||||
|
||||
Q. After obfuscating, my 3rd party plugin has stopped working! It has scripts that aren't in the Plugins folder.
|
||||
|
||||
A. The simplest way to fix this is to look at the plugin's script to see what namespace they use. Then, towards the bottom of the inspector window in ObfuscatorOptions.asset there is an array called "Skip Namespaces". Add the plugin's namespace to this array and the obfuscator will ignore any matching namespaces. Occassionally a plugin will forget to use namespaces for its scripts, in which case you have three choices: Either move them into a Plugins folder, or annotate each class with [Beebyte.Obfuscator.Skip], or add each class name to the "Skip Classes" array.
|
||||
|
||||
|
||||
Q. After obfuscating, my 3rd party plugin has stopped working! It only has scripts in the Plugins folder.
|
||||
|
||||
A. The obfuscator won't have touched files that live in the Plugins folder (unless you explicitly asked it to in Options), however it's likely that the plugin at some point required you to create a specifically named class and/or method. You'll need to add a [SkipRename] attribute to the class and/or method you created in your code.
|
||||
|
||||
|
||||
Q. Button clicks don't work anymore!
|
||||
|
||||
A. Check your Options and see if you enabled the "Include public mono methods". If you did, then make sure you've added a [SkipRename] attribute to the button click method.
|
||||
For a more obfuscated approach you could assign button clicks programatically. For example, here the ButtonMethod can be obfuscated:
|
||||
|
||||
public Button button;
|
||||
|
||||
public void Start()
|
||||
{
|
||||
button.onClick.AddListener(ButtonMethod);
|
||||
}
|
||||
|
||||
|
||||
Q. Animation events don't work anymore!
|
||||
|
||||
A. See "Button clicks don't work anymore!". If a method is being typed into the inspector, you should exclude it from Obfuscation.
|
||||
|
||||
|
||||
Q. How do I get string literal encryption to work, my secret field is still showing as plaintext in a decompiler?
|
||||
|
||||
A. You need to take the following steps:
|
||||
- Enable "Obfuscate Literals" in the ObfuscatorOptions asset.
|
||||
- Either leave the default Unicode to 94 (the ^ character), or change it as required.
|
||||
- In your code, surround the string with the chosen character, e.g. "secretpass" becomes "^secretpass^";
|
||||
|
||||
Alternatively, if the string is within a method you have another option:
|
||||
- Enable "Obfuscate Literals" in the ObfuscatorOptions asset.
|
||||
- Decorate the method with [ObfuscateLiterals] (using Beebyte.Obfuscator;)
|
||||
|
||||
|
||||
Q. It's not working for a certain platform.
|
||||
|
||||
A. Regardless of the platform, send me an email (support@beebyte.co.uk) with the error and I'll see what I can do, but remember that it's only officially tested for Standalone/Android/iOS/WebGL platforms.
|
||||
|
||||
|
||||
Q. How can we run obfuscation later in the build process?
|
||||
|
||||
A. You can control this in the Assets/Editor/Beebyte/Obfuscator/Postbuild.cs script. The PostProcessScene attribute on the Obfuscate method has an index number that you can freely change to enable other scripts to be called first.
|
||||
|
||||
|
||||
Q. Can I obfuscate externally created DLLs?
|
||||
|
||||
A. You can. To do this open Assets/Editor/Beebyte/Obfuscator/ObfuscatorMenuExample.cs. Uncomment this file and change the DLL filepath to point to your DLL. Now use the newly created menu option.
|
||||
|
||||
|
||||
Q. How do I obfuscate local variables?
|
||||
|
||||
A. Local variable names are not stored anywhere, so there is nothing to obfuscate. A decompiler tries to guess a local variable's name based on the name of its class, or the method that instantiated it.
|
||||
|
||||
|
||||
Q. I'm getting ArgumentException: The Assembly UnityEditor is referenced by obfuscator ('Assets/ThirdParty/Beebyte/Obfuscator/Plugins/obfuscator.dll'). But the dll is not allowed to be included or could not be found.
|
||||
|
||||
A. It's important to keep the directory structure of the obfuscator package. Specifically, the correct location should have an "Editor" folder somewhere on its path. Unity treats files within Editor folders differently. Assets/Editor/Beebyte will ensure that the obfuscator can correctly run and that the obfuscator tool itself won't be included in your production builds.
|
||||
|
||||
|
||||
Q. I'm getting an AssemblyResolutionException:Failed to resolve assembly: 'System.Collections, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a' when building for Windows Phone.
|
||||
|
||||
A. In the example given in the question, somewhere on your system would be a System.Collections.dll file of version 4.0.0.0. To fix the error, locate this file then add its location to the extraAssemblyDirectories array within Options.
|
||||
|
||||
|
||||
Q. Is is possible to obfuscate certain public MonoBehaviour methods even when I've told it not to obfuscate them by default?
|
||||
|
||||
A. Yes, you override this by using the attribute [System.Reflection.Obfuscation(Exclude=false)] on the method.
|
||||
|
||||
|
||||
Q. What can I do to make it more secure?
|
||||
|
||||
A. Try enabling obfuscation of public MonoBehaviour methods and obfuscation of MonoBehaviour class names. Enable string obfuscation and add [ObfuscateLiterals] to sensitive methods containing strings you'd prefer people not to see in a decompiler. Refactor your code to use smaller methods. Try using a different unicode starting character - instead of 65 (A) you could use 770 (Vertical text) - just be aware that makes stack traces harder to read.
|
||||
|
||||
|
||||
Q. Something's still not working, how can I get in touch with you?
|
||||
|
||||
A. Please email support@beebyte.co.uk giving as much information about the problem as possible.
|
||||
|
||||
|
||||
|
||||
Notable 3rd Party Plugins (Beebyte is not affiliated with these products or companies)
|
||||
======================================================================================
|
||||
|
||||
See Obfuscator.pdf for more information.
|
||||
|
||||
|
||||
Update History
|
||||
==============
|
||||
|
||||
3.9.9 - 2nd October 2022
|
||||
|
||||
* Fixed a runtime crash when reflection is used to access a 'fake code' generated method of an overridden base class when compiled to IL2CPP backend
|
||||
|
||||
3.9.8 - 31st May 2022
|
||||
|
||||
* Fixed an IDE crash when building development versions on 2021.2 or above
|
||||
|
||||
3.9.7 - 25th May 2022
|
||||
|
||||
* Fixed an IDE crash when using the Scripts Only Build option
|
||||
|
||||
3.9.6 - 19th May 2022
|
||||
|
||||
* Fixed a CRITICAL obfuscation bug introduced in Unity 2022.1
|
||||
* Fixed an IDE crash the second time a build is made in 2022.1
|
||||
|
||||
3.9.5 - 18th May 2022
|
||||
|
||||
* Fixed a CRITICAL obfuscation bug introduced in Unity 2022.1
|
||||
* Fixed an IDE crash the second time a build is made in 2022.1
|
||||
|
||||
3.9.4 - 7th April 2022
|
||||
|
||||
* Reduced the obfuscated DLL size when using String literal obfuscation
|
||||
|
||||
3.9.3 - 5th April 2022
|
||||
|
||||
* Fixed an issue introduced in 3.9.2. where a class defined within 'Skip Classes' in options may not have its methods skipped
|
||||
|
||||
3.9.2 - 6th January 2022
|
||||
|
||||
* Fixed method obfuscation within anonymous types
|
||||
|
||||
3.9.1 - 28th December 2021
|
||||
|
||||
* Fixed an InvalidCastException on build when using Burst
|
||||
|
||||
3.9.0 - 9th October 2021
|
||||
|
||||
* Reimplementation of string literal obfuscation resulting in faster build and run times
|
||||
|
||||
3.8.2 - 26th April 2021
|
||||
|
||||
* Fixed a FieldAccessException under rare conditions
|
||||
|
||||
3.8.1 - 15th April 2021
|
||||
|
||||
* Fixed a Unity 2018 issue when scripts call the CompatibilityBuildPipeline
|
||||
|
||||
3.8.0 - 14th April 2021
|
||||
|
||||
* [ObfuscateLiterals] can now be applied at the class level for it to apply to the methods and fields within it
|
||||
* Fixed a Unity 2017.3 compatibility issue
|
||||
|
||||
3.7.3 - 30th March 2021
|
||||
|
||||
* Fixed the hidden option 'inheritBeebyteAttributes'
|
||||
|
||||
3.7.2 - 29th March 2021
|
||||
|
||||
* Prevented some AssemblyResolutionExceptions
|
||||
|
||||
3.7.1 - 22nd March 2021
|
||||
|
||||
* Fixed an IL2CPP NullReferenceException build error with simultaneous assembly obfuscation
|
||||
|
||||
3.7.0 - 20th March 2021
|
||||
|
||||
* "Extra Assembly Directories" has been replaced by "Referenced Assemblies" that can take either directories or files
|
||||
* Fixed a build error around method parameters being a nested obfuscated enum type belonging to another simultaneously obfuscated assembly
|
||||
* Fixed an error around incorrect DLL versions being used for some checks
|
||||
* Prevented some AssemblyResolutionExceptions
|
||||
|
||||
3.6.7 - 16th March 2021
|
||||
|
||||
* Fixed an IL2CPP NullReferenceException build error
|
||||
|
||||
3.6.6 - 15th March 2021
|
||||
|
||||
* Added debug around an object reference exception error
|
||||
|
||||
3.6.5 - 10th March 2021
|
||||
|
||||
* Fixed an IL2CPP build exception when generating fake code
|
||||
|
||||
3.6.4 - 1st March 2021
|
||||
|
||||
* Prevented an Obfuscation build exception
|
||||
|
||||
3.6.3 - 15th February 2021
|
||||
|
||||
* Fixed an obfuscation issue with constructor parameters
|
||||
* Allow [ObfuscateLiterals] to be applied to constructors
|
||||
|
||||
3.6.2 - 17th December 2020
|
||||
|
||||
* Fixed obfuscation using optional "Scriptable Build Pipeline" package 1.13.1 and higher when run on Unity versions 2019.2.7 or older
|
||||
|
||||
3.6.1 - 19th November 2020
|
||||
|
||||
* Fixed an exception when obfuscation of MonoBehaviour class names and 'Create Visual Studio Solution' are both enabled
|
||||
|
||||
3.6.0 - 22nd October 2020
|
||||
|
||||
* Added hidden option to allow obfuscation of compiler generated fields on Serializable classes
|
||||
|
||||
3.5.4 - 23rd September 2020
|
||||
|
||||
* Undisclosed fix
|
||||
|
||||
3.5.3 - 29th August 2020
|
||||
|
||||
* Fixed an issue renaming MonoBehaviour classes when using Generic MonoBehaviour types
|
||||
* Coroutine anonymous types are now obfuscated by default
|
||||
|
||||
3.5.2 - 27th August 2020
|
||||
|
||||
* Events on ScriptableObjects are now obfuscated
|
||||
|
||||
3.5.1 - 26th August 2020
|
||||
|
||||
* Fixed renaming MonoBehaviour classes for MacOS builds (for non Xcode projects)
|
||||
* Renaming MonoBehaviour classes is no longer applied when creating Xcode project target builds
|
||||
|
||||
3.5.0 - 20th August 2020
|
||||
|
||||
* The option to rename MonoBehaviour classes for standalone builds only (Windows, Linux, MacOS) has been extended to include 2018.2 onwards
|
||||
* Obfuscation of explicit interface implementation method names
|
||||
* Fixed a "Sequence contains no matching element" error that occurs when building to IL2CPP when explicitly forcing obfuscation of an enum
|
||||
|
||||
3.4.0 - 27th July 2020
|
||||
|
||||
* Added option to rename MonoBehaviour classes for Unity 2020 (this is still an experimental feature!)
|
||||
* Disable option to rename MonoBehaviour classes for the WebGL build target
|
||||
* Paths to DLLs are now accepted within the Assemblies and Compiled Assemblies section of options meaning it's not only custom scripts that can now handle external DLLs
|
||||
* Updated documentation on guidance for compatibility with well known assets. Odin users in particular are encouraged to look at this if using AOT generation to prevent code stripping
|
||||
|
||||
3.3.1 - 23rd July 2020
|
||||
|
||||
* Fixed an issue with PlayFab's ExecuteCloudScriptRequest not being correctly sent
|
||||
* Anonymous types are now skipped by default. Set a hidden option of options.obfuscateAnonymousTypes = true to override this if required
|
||||
* Fixed an issue with [SuppressLog] not being applied to generated fake code
|
||||
|
||||
3.3.0 - 17th July 2020
|
||||
|
||||
* Added option to rename MonoBehaviour classes for Unity 2019.3 and 2019.4
|
||||
|
||||
3.2.1 - 17th June 2020
|
||||
|
||||
* Unity reflection methods (such as SendMessage) are now properly detected when the 2nd and 3rd arguments of the reflection calls are complex
|
||||
* A warning message is now logged should the Obfuscator fail to find the string reference for a Unity reflection method
|
||||
* A new attribute [SuppressLog] exists that can prevent certain warning messages from being printed
|
||||
|
||||
3.2.0 - 15th June 2020
|
||||
|
||||
* Faster obfuscation build times for very large projects
|
||||
|
||||
3.1.2 - 9th June 2020
|
||||
|
||||
* Fixed an issue with Inner/Nested classes and skip namespaces
|
||||
|
||||
3.1.1 - 25th May 2020
|
||||
|
||||
* Fixed a System.ArgumentNullException on build when obfuscating a string const assigned to be null
|
||||
|
||||
3.1.0 - 3rd May 2020
|
||||
|
||||
* A build exception is now thrown if the length of the salt used for name translation is too short
|
||||
* Added a button click that will regenerate the salt
|
||||
* New option to randomise salt each build
|
||||
* A new option to include the hash salt must now be enabled for it to appear in the name translation file
|
||||
* String literals containing only null characters are no longer obfuscated
|
||||
* Added 'Photon' to the list of namespaces to skip when using fresh settings
|
||||
|
||||
3.0.1 - 10th March 2020
|
||||
|
||||
* Potentially fixed the 'Copying assembly from '' to '' failed after builds.
|
||||
|
||||
3.0.0 - 10th March 2020
|
||||
|
||||
* Namespaces whose name start with a skipped namespace no longer assume they should be skipped when skipping recursively (i.e. 'ABC' is no longer skipped when only 'AB' is specified, however AB.X would be skipped).
|
||||
* Namespaces whose name start with an explicitly obfuscated namespace no longer assume to be obfuscated when obfuscating recursively.
|
||||
* Classes that are the base class to a Serializable class are now also treated as Serializable.
|
||||
* Improvements to string literal obfuscation.
|
||||
* Updated the default options to include the following 'Unity Methods': OnJointBreak2D, OnParticleSystemStopped, OnParticleTrigger, OnParticleUpdateJobScheduled
|
||||
|
||||
2.8.1 - 8th January 2020
|
||||
|
||||
* Visual Studio no longer reports a FormatException warning when obfuscating.
|
||||
* Fixed a UI issue with ObfuscatorOptions when 'Use RSA' is unselected.
|
||||
|
||||
2.8.0 - 18th November 2019
|
||||
|
||||
* Compatibility with the Unity Test Framework for Unity 2019.3 onwards.
|
||||
|
||||
2.7.6 - 5th November 2019
|
||||
|
||||
* Fixed a pipeline issue affecting Unity 2018.1
|
||||
|
||||
2.7.5 - 30th October 2019
|
||||
|
||||
* Fixed a CRITICAL obfuscation bug introduced with Unity 2019.2.8 and newer on pipeline builds when enabling the option to obfuscate all assembly definitions.
|
||||
|
||||
2.7.4 - 20th October 2019
|
||||
|
||||
* Fixed a CRITICAL obfuscation bug introduced with Unity 2019.2.8 and newer on pipeline builds. It is vital to install this version if using the latest versions of Unity.
|
||||
|
||||
2.7.3 - 12th October 2019
|
||||
|
||||
* Added a Unity incompatibility warning due to a critical bug introduced by recent changes to the Unity build pipeline
|
||||
|
||||
2.7.2 - 24th September 2019
|
||||
|
||||
* Fixed an issue with calls to StopCoroutine
|
||||
|
||||
2.7.1 - 5th September 2019
|
||||
|
||||
* Nested classes declared to be skipped via the "Skip Classes" section of options are now correctly skipped when their parents are obfuscated
|
||||
|
||||
2.7.0 - 1st September 2019
|
||||
|
||||
* Prevented an issue that could lead to the Obfuscator not being run. As a result the build pipeline scripts have been restructured and are more robust
|
||||
* Removed a warning message about duplicate method names that was only relevant to a legacy option that is no longer available
|
||||
|
||||
2.6.0 - 3rd July 2019
|
||||
|
||||
* Alternative attribute names can now be specified for the [Rename] attribute
|
||||
|
||||
2.5.4 - 30th June 2019
|
||||
|
||||
* Fixed a minor issue with nameTranslation.txt
|
||||
* Added 'LapinerTools' to the default list of namespaces to skip
|
||||
|
||||
2.5.3 - 4th June 2019
|
||||
|
||||
* Updated the default options to be compatible with Photon Bolt (skipped some namespaces and classes)
|
||||
|
||||
2.5.2 - 18th May 2019
|
||||
|
||||
* Fixed a namespace incompatiblity issue caused by using an obfuscated assembly within another project that uses Bolt 2.0
|
||||
|
||||
2.5.1 - 25th April 2019
|
||||
|
||||
* Fixed an IL2CPP build bug when referencing a generic type in another assembly definition as a parameter to a custom attribute.
|
||||
|
||||
2.5.0 - 19th April 2019
|
||||
|
||||
* Added an option to remove specified custom attributes, defaulting to Unity attributes used to interact with the Unity IDE. If you are obfuscating assets for sale on the Unity Asset Store then please check that menus and Inspector windows still work as intended. If they don't then either remove elements from the new options list or [SkipRename] the methods that are called from the IDE.
|
||||
|
||||
2.4.2 - 18th March 2019
|
||||
|
||||
* Fixed an error with string obfuscation.
|
||||
|
||||
2.4.1 - 17th March 2019
|
||||
|
||||
* Fixed a NET 4.x issue (IL2CPP build error) with string obfuscation for some methods (dependant on size).
|
||||
|
||||
2.4.0 - 16th March 2019
|
||||
|
||||
* Added a toggle to obfuscate development builds (default is true)
|
||||
* Fixed an exception when referencing a nested class type across multiple assembly definitions
|
||||
|
||||
2.3.5 - 28th February 2019
|
||||
|
||||
* Added Photon.Pun.PunRPC to the list of alternative RPC annotations (PUN2).
|
||||
|
||||
2.3.4 - 17th February 2019
|
||||
|
||||
* Fixed a CheckedResolve exception on build.
|
||||
|
||||
2.3.3 - 30th January 2019
|
||||
|
||||
* Fixed a rare case where an animation would fail to play.
|
||||
|
||||
2.3.2 - 5th December 2018
|
||||
|
||||
* Adjusted the AssemblySelector.cs to cater for player-only native assemblies as well as future proof it against new base Unity packages being added.
|
||||
|
||||
2.3.1 - 27th November 2018
|
||||
|
||||
* Fixed an IL2CPP issue brought about from 2.3.0
|
||||
|
||||
2.3.0 - 25th November 2018
|
||||
|
||||
* Slightly improved obfuscation.
|
||||
* Fixed a runtime exception that could occur after obfuscating multiple assemblies.
|
||||
|
||||
2.2.0 - 13th November 2018
|
||||
|
||||
* Optimisation - added option (Misc) to set the progress bar detail which can affect obfuscation time for large projects. By default this is now set to a summary view.
|
||||
|
||||
2.1.0 - 8th November 2018
|
||||
|
||||
* Added option to allow/disallow 'public' fake code methods from being created.
|
||||
|
||||
2.0.11 - 3rd November 2018
|
||||
|
||||
* Fixed issues with complex custom attributes.
|
||||
|
||||
2.0.10 - 29th October 2018
|
||||
|
||||
* Fixed an error about duplicate types in Beebyte.Cecil (ECS related bug).
|
||||
|
||||
2.0.9 - 20th October 2018
|
||||
|
||||
* Fixed a TypeLoadException for generic instance methods referencing obfuscated types from another assembly.
|
||||
* Fixed a TypeLoadException for custom attributes that had parameters of arrays of type definitions.
|
||||
|
||||
2.0.8 - 14th October 2018
|
||||
|
||||
* Fixed a runtime MissingMethodException that could happen after obfuscating multiple assemblies.
|
||||
|
||||
2.0.7 - 9th October 2018
|
||||
|
||||
* Fixed a TypeLoadException when using named arguments in custom attributes across assembly definitions.
|
||||
|
||||
2.0.6 - 28th September 2018
|
||||
|
||||
* Fixed a "Mono.Cecil.ResolutionException: Failed to resolve FKENQJFIROA" exception that could happen when obfuscating multiple assembly definitions.
|
||||
|
||||
2.0.5 - 27th August 2018
|
||||
|
||||
* Added Com.Google to the list of skipped namespaces, for Google Play Games compatibility.
|
||||
* Added a warning about renaming MonoBehaviour classes in 2018.2, until a fix/workaround can be found.
|
||||
|
||||
2.0.4 - 28th May 2018
|
||||
|
||||
* Updated default settings for Photon Networking (PUN) to allow WebGL builds to log in, and to allow stronger obfuscation rules to be enabled.
|
||||
|
||||
2.0.3 - 23rd May 2018
|
||||
|
||||
* Fixed a bug where the Options Inspector window would not save the 'enabled' or 'Obfuscate all assembly definition' checkboxes.
|
||||
* Relaxed the default options to only obfuscate Assembly-CSharp.dll instead of all assembly definitions. It is recommended to enable it when you're ready to increase obfuscation strength.
|
||||
|
||||
2.0.2 - 20th May 2018
|
||||
|
||||
* [UWP] Implemented a workaround for a UnityException on build for the UWP build target.
|
||||
|
||||
2.0.1 - 13th May 2018
|
||||
|
||||
* Fixed "dll was not found" errors for certain assembly definition files.
|
||||
|
||||
2.0.0 - 7th May 2018
|
||||
|
||||
* New Documentation added in PDF format.
|
||||
* Assembly Definitions introduced in 2017.3 can now be automated into the build process.
|
||||
* New options added to automatically obfuscate all assembly definitions.
|
||||
* 'permanentDLLs' in Config.cs is now defined in the inspector options file under the heading 'compiledAssemblies' (synchronising with Unity's name in the CompilationPipeline).
|
||||
* 'temporaryDLLs' in Config.cs is now defined in the inspector options file under the heading 'assemblies' (synchronising with Unity's name in the CompilationPipeline).
|
||||
* extraAssemblyDirectories in Config.cs is now defined in the inspector options file.
|
||||
* Priority of nested "[System.Reflection.Obfuscation]/[Skip]/[SkipRename]/Skip Namespaces" etc is no longer undefined behaviour - instead priority is awarded to the deepest level.
|
||||
* Classes annotated with [System.Reflection.Obfuscation(ApplyToMembers=true)] (or [Skip]) will now also skip any nested classes.
|
||||
* New option to skip literal obfuscation on methods that have been skipped.
|
||||
* New option to apply literal obfuscation on all methods by default.
|
||||
* Public nested classes and nested enums are no longer obfuscated if the public checkbox is disabled for class obfuscation.
|
||||
* Fixed a "Fatal error in Unity CIL Linker" that could occur when running with 'development' enabled build targets.
|
||||
* Obfuscating MonoBehaviour class names is no longer considered an experimental feature.
|
||||
|
||||
1.26.0 - 23rd September 2017
|
||||
|
||||
* New options to give other attributes the same effect as Beebyte specific attributes. i.e. you can configure [JsonProperty] to have the additional effect of [SkipRename].
|
||||
|
||||
1.25.2 - 16th September 2017
|
||||
|
||||
* Added ChartboostSDK to the list of Skipped Namespaces in the default options to fix a problem with delegates not being called.
|
||||
|
||||
1.25.1 - 7th September 2017
|
||||
|
||||
* Fixed a bug with methods that have the [RuntimeInitializeOnLoadMethod] attribute.
|
||||
|
||||
1.25.0 - 24th August 2017
|
||||
|
||||
* Reduced the memory footprint within the Editor following obfuscation.
|
||||
* Extensive refactoring and more tests.
|
||||
|
||||
1.24.12 - 2nd August 2017
|
||||
|
||||
* Fixed issues with Attributes that take an inner class as a parameter.
|
||||
|
||||
1.24.11 - 27th July 2017
|
||||
|
||||
* Fixed issues with Attributes that take a class as a parameter.
|
||||
|
||||
1.24.10 - 16th July 2017
|
||||
|
||||
* Fixed a bug where an enum in a parameter as a default value from a second assembly would cause a failed resolution exception on a CheckedResolve.
|
||||
|
||||
1.24.9 - 13th July 2017
|
||||
|
||||
* Fixed a bug breaking inheritence checks when generic types were nested within other generic types.
|
||||
|
||||
1.24.8 - 22nd June 2017
|
||||
|
||||
* Added some exclusion for messages sent to UnityEditor classes.
|
||||
* Fixed an Object reference exception that could sometimes occur when obfuscating literals.
|
||||
|
||||
1.24.7 - 17th June 2017
|
||||
|
||||
* Small bug fixes.
|
||||
|
||||
1.24.6 - 1st May 2017
|
||||
|
||||
* Some Unity reflection calls are now found when using chained and complex arguments.
|
||||
* Compatibility fixes when linking with newer .NET versions.
|
||||
|
||||
1.24.5 - 26th April 2017
|
||||
|
||||
* Fixed some errors that occurred when building with the old legacy procedural naming policy.
|
||||
* The stacktrace for any Obfuscator errors is visible once again.
|
||||
|
||||
1.24.4 - 13th April 2017
|
||||
|
||||
* Fixed a rare ArgumentException that could happen if two fields in the same class share the same name.
|
||||
* Improved the build process.
|
||||
|
||||
1.24.3 - 8th April 2017
|
||||
|
||||
* Optimisation when obfuscating MonoBehaviour class names.
|
||||
* Hidden option to obfuscate Beebyte attributes. This can help resolve imported types being defined multiple times (external DLLs).
|
||||
|
||||
1.24.2 - 17th March 2017
|
||||
|
||||
* Fixed a rare TypeLoadException.
|
||||
* Fixed a "redefinition of parameter" error in IL2CPP when a delegate's parameter names are inferred from default declaration i.e. delegate { .. } instead of an explicit delegate(bool a, bool b) { .. }.
|
||||
|
||||
1.24.1 - 12th February 2017
|
||||
|
||||
* Fixed a bug where a coroutine invoked by name from a different class would fail to execute if the coroutine is not annotated with [SkipRename] or [ReplaceLiteralsWithName]. This also fixes coroutines launched from within coroutines.
|
||||
|
||||
1.24.0 - 27th January 2017
|
||||
|
||||
* Multiple DLLs can be simultaneously obfuscated by declaring them within Config.cs. Endpoints in the referenced DLL are updated in the calling DLL. This new feature is experimental and has no interface.
|
||||
* Fixed a TypeLoadException that happened when a class extending an external class implements a custom interface that declares one of the external methods and where the implementing class doesn't override it.
|
||||
* Optimisation.
|
||||
|
||||
1.23.9 - 13th November 2016
|
||||
|
||||
* Optimisation - Method obfuscation is now really quick compared to previous lengthy times seen with some projects that focused heavily on reflection (mostly NGUI).
|
||||
* Extra information added to the progress bar for method obfusation.
|
||||
* Forcing obfuscation on serialized fields with [System.Reflection.Obfuscation(Exclude=false)] was sometimes being ignored.
|
||||
|
||||
1.23.8 - 3rd November 2016
|
||||
|
||||
* Fixed an ArgumentException that could happen when obfuscating literals using the simplified non-RSA algorithm.
|
||||
|
||||
1.23.7 - 31st October 2016
|
||||
|
||||
* Added hidden option to provide canonical names of attributes to be searched for strings that add to the array of method names to be treated as [ReplaceLiteralsWithName].
|
||||
* Custom attributes now have their string arguments searched for when considering [ReplaceLiteralsWithName].
|
||||
* Added option to include fake code method names to the nameTranslation file.
|
||||
* Added new Attribute to exclude fake code being created from particular methods or classes.
|
||||
|
||||
1.23.6 - 14th September 2016
|
||||
|
||||
* Fixed a compile NullReferenceException under certain conditions when cryptographic hashes are disabled.
|
||||
|
||||
1.23.5 - 4th September 2016
|
||||
|
||||
* Fixed IL2CPP compile error that, for some methods, would occur when using both string obfuscation and fake code generation.
|
||||
* The "Use RSA" setting is no longer transient.
|
||||
|
||||
1.23.4 - 25th August 2016
|
||||
|
||||
* Fixed IL2CPP compile error that could sometimes happen when fake code generation is enabled.
|
||||
* Fixed a NullReferenceException with RSA string obfuscation that could consistently appear under certain conditions.
|
||||
|
||||
1.23.3 - 12th August 2016
|
||||
|
||||
* Fixed a "NotSupportedException: The invoked member is not supported in a dynamic module." exception when using dynamically created libraries.
|
||||
|
||||
1.23.2 - 9th August 2016
|
||||
|
||||
* Fixed an IL2CPP compile error when fake code tries to clone extern methods.
|
||||
|
||||
1.23.1 - 8th August 2016
|
||||
|
||||
* Improvements to Fake Code generation.
|
||||
|
||||
1.23.0 - 27th July 2016
|
||||
|
||||
* Added new hidden options includeParametersOnPublicMethods and includeParametersOnProtectedMethods, set to true by default. Useful if you're giving an API to someone.
|
||||
* Improved scanning for Unity reflection methods.
|
||||
* Updated ObfuscatorMenuExample.cs
|
||||
* Added Photon defaults for when Obfuscating MonoBehaviour class names are enabled.
|
||||
|
||||
1.22.1 - 25th July 2016
|
||||
|
||||
* Obfuscating MonoBehaviour class names occassionally didn't get reverted due to a Unity editor delegate being reset. A more stable approach is now taken where a temporary translation file is produced, then read back in at the earliest opportunity.
|
||||
|
||||
1.22.0.1 - 25th July 2016
|
||||
|
||||
* Fixed an issue with 1.22.0 for Unity 5.2+ that expected ObfuscatorOptions to be in a fixed location. It can once again live in a non-standard location.
|
||||
|
||||
1.22.0 - 19th July 2016
|
||||
|
||||
* Option to strip namespaces.
|
||||
* Experimental option to obfuscate MonoBehaviour class names.
|
||||
* Option to supply strings of method names that should have [ReplaceLiteralsWithName] applied.
|
||||
* Added defaults for UFPS (Preserve Prefixes) and NGUI (Replace Literals).
|
||||
* ObfuscatorOptions now installs in a temporary location and will ask to overwrite or keep existing settings when next run.
|
||||
|
||||
1.21.2 - 16th June 2016
|
||||
|
||||
* Fixed missing scripts errors in WebPlayer builds that occured when using Fake Code generation on methods that declare default arguments.
|
||||
|
||||
1.21.1 - 15th June 2016
|
||||
|
||||
* Fixed extremely long obfuscation times when using fake code generation on huge methods. There is a new option to limit the size of methods to be faked. This should bring obfuscation times back down to seconds from potentially hours.
|
||||
|
||||
1.21.0 - 15th June 2016
|
||||
|
||||
* Added default settings for Photon networking compatibility.
|
||||
|
||||
1.20.0 - 15th June 2016
|
||||
|
||||
* Added a progress bar.
|
||||
|
||||
1.19.0 - 10th June 2016
|
||||
|
||||
* Enum constants can now be skipped by default.
|
||||
|
||||
1.18.4 - 2nd June 2016
|
||||
|
||||
* Fixed a bug where iOS builds could fail to compile in xcode if using the default String Literal Obfuscation method.
|
||||
|
||||
1.18.3 - 1st June 2016
|
||||
|
||||
* Using [System.Reflection.Obfuscation(Exclude=false)] on a class will now cause it to be obfuscated even if its namespace is explicity skipped in Options.
|
||||
|
||||
1.18.2 - 30th May 2016
|
||||
|
||||
* Fixed a bug with string literal obfuscation where a string of length greater than 1/8th the chosen RSA key length would appear garbled.
|
||||
|
||||
1.18.1 - 23rd May 2016
|
||||
|
||||
* Changed the default Unicode start character to 65 (A) to work around an error with structs in iOS builds for certain unpatched versions of Unity.
|
||||
* Changed defaults to use hash name generation instead of order based.
|
||||
|
||||
1.18.0 - 18th May 2016
|
||||
|
||||
* New "Preserve Prefixes" section that can keep part of a name, i.e. OnMessage_Victory() -> OnMessage_yzqor(). This is mostly for the reflection used by the UFPS plugin.
|
||||
* New option to reverse the line order of the nameTranslation.txt. This is now the default.
|
||||
* New option to surround every obfuscated name with a specified delimiter.
|
||||
* Parameter obfuscation is now included in the nameTranslation.txt.
|
||||
* New hidden option to include a simplified HASHES section in the nameTranslation.txt.
|
||||
|
||||
1.17.1 - 6th May 2016
|
||||
|
||||
* Fixed an ArgumentOutOfRangeException that could occur when the minimum number of fake methods is set to a large value.
|
||||
|
||||
1.17.0 - 5th May 2016
|
||||
|
||||
* Optimisation.
|
||||
* Option to derive obfuscated names from a cryptographically generated hash. This means names will be consistent throughout a project's lifecycle, removing the need to maintain up to date nameTranslation.txt files.
|
||||
* New attribute [ObfuscateLiterals] for methods that instructs all string literals within it to be obfuscated, without requiring delimiters within the literals.
|
||||
* New option to toggle whether attributes should be cloned for fake methods.
|
||||
|
||||
1.16.2 - 1st April 2016
|
||||
|
||||
* ScriptableObject classes are now treated as Serializable by default (i.e. fields and properties are not renamed). This can be overriden by setting options.treatScriptableObjectsAsSerializable to false, or on a case-by-case basis by making use of [System.Reflection.Obfuscation] on each field, or [System.Reflection.Obfuscation(Exclude = false, ApplyToMembers = true)] on the class.
|
||||
* Fixed a TypeLoadException for methods such as public abstract T Method() where a deriving class creates a method replacing the generic placeholder, i.e. public override int Method().
|
||||
* Added hidden option for classes to inherit Beebyte attributes Skip and SkipRename that are on an ancestor class. To use, set options.inheritBeebyteAttributes = true prior to obfuscation.
|
||||
|
||||
1.16.1 - 23rd March 2016
|
||||
|
||||
* Fixed an issue with 1.16.0 where internal methods would not obfuscate.
|
||||
|
||||
1.16.0 - 10th March 2016
|
||||
|
||||
* New option to obfuscate Unity reflection methods instead of simply skipping them.
|
||||
* Methods replacing string literals that share the same name now also share the same obfuscated name, so that replaced literals correctly point to their intended method.
|
||||
* Faster obfuscation time for methods.
|
||||
* Fixed a TypeLoadException.
|
||||
* The name translation file now has a consistent order.
|
||||
|
||||
1.15.0 - 25th February 2016
|
||||
|
||||
* Added option to include skipped classes and namespaces when searching for string literal replacement via [ReplaceLiteralsWithName] or through the RPC option.
|
||||
* Fixed a bug where classes within skipped namespaces could sometimes have their references broken if they link to obfuscated classes.
|
||||
|
||||
1.14.0 - 25th February 2016
|
||||
|
||||
* Added option to search SkipNamespaces recursively (this was the default behaviour)
|
||||
* Added option to restrict obfuscation to user-specified Namespaces.
|
||||
|
||||
1.13.1 - 24th February 2016
|
||||
|
||||
* Fixed a NullReferenceException that could sometimes (very rarely but consistent) occur during the write process.
|
||||
* Removed the dependance of the version of Mono.Cecil shipped with Unity by creating a custom library. This is necessary to avoid "The imported type `...` is defined multiple times" errors.
|
||||
|
||||
1.13.0 - 23rd February 2016
|
||||
|
||||
* Added a master "enabled" option to easily turn obfuscation on/off through scripts or the GUI.
|
||||
* Add Fake Code is now available for WebPlayer builds.
|
||||
* Fixed a "UnityException: Failed assemblies stripper" exception that occurs when selecting both fake code and player preference stripping levels.
|
||||
* Improvements to Fake Code generation.
|
||||
* Obfuscation times can now be printed with a call to Obfuscator.SetPrintChronology(..).
|
||||
* Building a project with no C# scripts will no longer cause an error to occur.
|
||||
|
||||
1.12.0 - 12th February 2016
|
||||
|
||||
* Added finer control to exclude public or protected classes, methods, properties, fields, events from being renamed. This might be useful to keep a DLLs public API unchanged, for it to then be used in another project.
|
||||
* Fixed a bug in the Options inspector that could revert some changes after an option's array's size is altered.
|
||||
|
||||
1.11.0 - 3rd February 2016
|
||||
|
||||
* Added an option to specify annotations that should be treated in the same way as [RPC], to cater for third party RPC solutions.
|
||||
|
||||
1.10.0 - 28th January 2016
|
||||
|
||||
* Previous obfuscation mappings can now be reused.
|
||||
* Unity Networking compatibility (old & new).
|
||||
* [RPC] annotated methods are no longer renamed unless an explicit [Rename("newName")] attribute is added, or if an option is enabled.
|
||||
* A new [ReplaceLiteralsWithName] attribute exists that can be applied to classes, methods, properties, fields, and events. It should be used with caution since it searches every string literal in the entire assembly replacing any instance of the old name with the obfuscated name. This is useful for certain situations such as replacing the parameters in nView.RPC("MyRPCMethod",..) method calls. It may also be useful for reflection, but note that only exact strings are replaced.
|
||||
|
||||
1.9.0 - 23rd January 2016
|
||||
|
||||
* Added a new option "Skip Classes" that is equivalent to adding [Skip] to a class. It's a good long-term solution for 3rd party assets that place files outside of a Plugin directory in the default namespace.
|
||||
* Added a way to resolve any future AssemblyResolutionExceptions via the Postscript.cs file without requiring a bespoke fix from Beebyte.
|
||||
* Fixed a bug in Postscript.cs for Unity 4.7
|
||||
* Added a workaround for an unusual Unity bug where the strings within the Options asset would sometimes be turned into hexadecimals, most noticable when swapping build targets often.
|
||||
|
||||
1.8.4 - 7th January 2016
|
||||
|
||||
* Fixed an AssemblyResolutionException for UnityEngine that could sometimes occur.
|
||||
|
||||
1.8.3 - 6th January 2016
|
||||
|
||||
* Obfuscation attributes can now be applied to Properties.
|
||||
|
||||
1.8.2 - 6th January 2016
|
||||
|
||||
* Serializable classes now retain their name, field names, and property names without requiring an explicit [Skip].
|
||||
* Fixed issues using generics that extend from MonoBehaviour.
|
||||
* Fixed an issue where two identically named methods in a type could cause obfuscation to fail if one is a generic, i.e. A() , A<T>().
|
||||
* Fixed an issue where fake code generation could sometimes result in a failed obfuscation when generic classes are involved.
|
||||
|
||||
1.8.1 - 1st January 2016
|
||||
|
||||
* Fixed various issues using generics.
|
||||
* Fixed an AssemblyResolutionException for UnityEngine.UI when using interfaces from that assembly.
|
||||
|
||||
1.8.0 - 29th December 2015
|
||||
|
||||
* Properties can now be obfuscated.
|
||||
|
||||
1.7.3 - 29th December 2015
|
||||
|
||||
* Undocumented fix.
|
||||
|
||||
1.7.2 - 28th December 2015
|
||||
|
||||
* Fixed a TypeLoadException error.
|
||||
* Fixed an issue with inheritence.
|
||||
* Undocumented fix.
|
||||
|
||||
1.7.1 - 27th December 2015
|
||||
|
||||
* Fixed a TypeLoadException error.
|
||||
* Fixed a "Script behaviour has a different serialization layout when loading." error.
|
||||
* Private Fields marked with the [SerializeField] attribute are now preserved by default.
|
||||
* Classes extending from Unity classes that have MonoBehaviour as an ancestor were not being treated as such (i.e. UIBehaviour).
|
||||
|
||||
1.7.0.1 - 14th December 2015
|
||||
|
||||
* Unity 5.3 compatibility.
|
||||
|
||||
1.7.0 - 11th December 2015
|
||||
|
||||
* Improved the "Works first time" experience by searching for reflection methods referenced by certain Unity methods such as StartCoroutine. New option added to disable this feature.
|
||||
* WebPlayer support (string literal obfuscation, public field obfuscation, fake code are disabled for WebPlayer builds).
|
||||
* Added an option to strip string literal obfuscation markers from strings when choosing not to use string literal obfuscation.
|
||||
* ObfuscatorMenuExample.cs added showing how you can Obfuscate other dlls from within Unity.
|
||||
* Added protection against accidently obfuscating the same dll multiple times.
|
||||
* Added an advanced option to skip rename of public MonoBehaviour fields.
|
||||
|
||||
1.6.1 - 16th November 2015
|
||||
|
||||
* First public release
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: ff2dce0e10fe14e4db5cb44f88208d4c
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,137 @@
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
public class OptionsManager
|
||||
{
|
||||
public const string ImportAssetName = "ObfuscatorOptionsImport";
|
||||
public const string OptionsAssetName = "ObfuscatorOptions";
|
||||
|
||||
public const string DefaultImportPath = @"Assets/Editor/Beebyte/Obfuscator/ObfuscatorOptionsImport.asset";
|
||||
public const string DefaultOptionsPath = @"Assets/Editor/Beebyte/Obfuscator/ObfuscatorOptions.asset";
|
||||
|
||||
public static Options LoadOptions()
|
||||
{
|
||||
if (HasInstallFiles()) Install();
|
||||
|
||||
Options o = LoadAsset(OptionsAssetName);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
Obfuscator.FixHexBug(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
Debug.LogError("Failed to load " + OptionsAssetName + " asset at " + DefaultOptionsPath);
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Can return null, i.e. on first package install.
|
||||
*/
|
||||
public static Options LoadOptionsIgnoringInstallFiles()
|
||||
{
|
||||
Options o = LoadAsset(OptionsAssetName);
|
||||
if (o == null) return null;
|
||||
|
||||
Obfuscator.FixHexBug(o);
|
||||
return o;
|
||||
}
|
||||
|
||||
private static bool HasInstallFiles()
|
||||
{
|
||||
return LoadAsset(ImportAssetName) != null;
|
||||
}
|
||||
|
||||
private static Options LoadAsset(string name)
|
||||
{
|
||||
string path = GetAssetPath(name);
|
||||
|
||||
return LoadAssetAtPath(path);
|
||||
}
|
||||
|
||||
private static void Install()
|
||||
{
|
||||
Options importOptions = LoadAsset(ImportAssetName);
|
||||
if (importOptions == null)
|
||||
{
|
||||
Debug.LogError("Could not find " + ImportAssetName + ".asset - aborting installation.");
|
||||
return;
|
||||
}
|
||||
|
||||
string importPath = GetAssetPath(ImportAssetName);
|
||||
string newOptionsPath = GetInstallPathFromImport(importPath);
|
||||
|
||||
Options o = LoadAssetAtPath(newOptionsPath);
|
||||
|
||||
if (o != null)
|
||||
{
|
||||
bool overwrite = EditorUtility.DisplayDialog("Obfuscator Installation", "ObfuscatorOptions already exists, would you like to replace it with new default options?", "Use new defaults", "Keep existing settings");
|
||||
if (overwrite) AssetDatabase.MoveAssetToTrash(newOptionsPath);
|
||||
else
|
||||
{
|
||||
AssetDatabase.MoveAssetToTrash(importPath);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
//Copy & Delete instead of Move, otherwise future installs think that ObfuscatorOptions is actually ObfuscatorOptionsImport
|
||||
AssetDatabase.CopyAsset(importPath, newOptionsPath);
|
||||
AssetDatabase.DeleteAsset(importPath);
|
||||
AssetDatabase.Refresh();
|
||||
}
|
||||
|
||||
private static string GetDefaultPath(string assetName)
|
||||
{
|
||||
if (ImportAssetName.Equals(assetName)) return DefaultImportPath;
|
||||
if (OptionsAssetName.Equals(assetName)) return DefaultOptionsPath;
|
||||
return null;
|
||||
}
|
||||
|
||||
#if UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2 || UNITY_4_3 || UNITY_4_5 || UNITY_4_6 || UNITY_4_7 || UNITY_4_8 || UNITY_4_9 || UNITY_5_0 || UNITY_5_1
|
||||
private static string GetAssetPath(string name)
|
||||
{
|
||||
return GetDefaultPath(name);
|
||||
}
|
||||
|
||||
private static Options LoadAssetAtPath(string path)
|
||||
{
|
||||
return (Options)Resources.LoadAssetAtPath(path, typeof(Options));
|
||||
}
|
||||
#else
|
||||
private static string GetAssetPath(string name)
|
||||
{
|
||||
string[] optionGuids = AssetDatabase.FindAssets(name);
|
||||
|
||||
IList<string> optionPaths = new List<string>();
|
||||
|
||||
foreach (string guid in optionGuids)
|
||||
{
|
||||
string optionPath = AssetDatabase.GUIDToAssetPath(guid);
|
||||
if (optionPath.EndsWith(name + ".asset"))
|
||||
{
|
||||
optionPaths.Add(optionPath);
|
||||
}
|
||||
}
|
||||
|
||||
if (optionPaths.Count == 0) return null;
|
||||
if (optionPaths.Count == 1) return optionPaths[0];
|
||||
|
||||
Debug.LogError("Multiple " + name + " assets found! Aborting");
|
||||
return null;
|
||||
}
|
||||
|
||||
private static Options LoadAssetAtPath(string path)
|
||||
{
|
||||
return AssetDatabase.LoadAssetAtPath<Options>(path);
|
||||
}
|
||||
#endif
|
||||
|
||||
private static string GetInstallPathFromImport(string importPath)
|
||||
{
|
||||
return importPath.Replace(ImportAssetName + ".asset", OptionsAssetName + ".asset");
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: e09e48f79ca11e348bc98b1cf8e479ae
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,149 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2019 Beebyte Limited. All rights reserved.
|
||||
*/
|
||||
#if !BEEBYTE_OBFUSCATOR_DISABLE
|
||||
|
||||
using System;
|
||||
using System.IO;
|
||||
using System.Net;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityEditor.Callbacks;
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
using UnityEditor.Build;
|
||||
#endif
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
using UnityEditor.Build.Reporting;
|
||||
#endif
|
||||
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
/**
|
||||
* Hooks into the Unity build pipeline and delegates to perform obfuscation / restoration if requested.
|
||||
*/
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
public class PipelineHook : IPreprocessBuildWithReport, IPostBuildPlayerScriptDLLs, IFilterBuildAssemblies
|
||||
#elif UNITY_2018_1_OR_NEWER
|
||||
public class PipelineHook : IPreprocessBuildWithReport, IPostprocessBuildWithReport
|
||||
#elif UNITY_5_6_OR_NEWER
|
||||
public class PipelineHook : IPreprocessBuild, IPostprocessBuild
|
||||
#else
|
||||
public class PipelineHook
|
||||
#endif
|
||||
{
|
||||
private static Project _project = new Project();
|
||||
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
public int callbackOrder
|
||||
{
|
||||
get { return 1; }
|
||||
}
|
||||
#endif
|
||||
|
||||
[PostProcessBuild(2)]
|
||||
public static void PostProcessBuild(BuildTarget target, string pathToBuildProject)
|
||||
{
|
||||
_project.ObfuscateAssets(target, pathToBuildProject);
|
||||
}
|
||||
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
public void OnPostBuildPlayerScriptDLLs(BuildReport report)
|
||||
#elif UNITY_2018_1_OR_NEWER
|
||||
public void OnPostprocessBuild(BuildReport report)
|
||||
#elif UNITY_5_6_OR_NEWER
|
||||
public void OnPostprocessBuild(BuildTarget target, string path)
|
||||
#else
|
||||
[PostProcessBuild(1)]
|
||||
private static void PostBuildHook(BuildTarget buildTarget, string pathToBuildProject)
|
||||
#endif
|
||||
{
|
||||
if (_project.HasMonoBehaviourAssetsThatNeedReverting()) RestoreUtils.RestoreMonobehaviourSourceFiles();
|
||||
RestoreUtils.RestoreOriginalDlls();
|
||||
|
||||
try
|
||||
{
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
if ((report.summary.options & BuildOptions.BuildScriptsOnly) != 0 &&
|
||||
(report.summary.options & BuildOptions.Development) != 0 && // BuildScriptsOnly is only applied in development builds
|
||||
_project.ShouldObfuscate())
|
||||
{
|
||||
Debug.LogError("Obfuscation is not supported for the \"Scripts Only Build\" option");
|
||||
return;
|
||||
}
|
||||
#endif
|
||||
if (_project.IsSuccess()) return;
|
||||
|
||||
if (_project.HasCSharpScripts())
|
||||
{
|
||||
Debug.LogError("Failed to obfuscate");
|
||||
#if UNITY_5_6_OR_NEWER
|
||||
throw new BuildFailedException("Failed to obfuscate");
|
||||
#else
|
||||
throw new OperationCanceledException("Failed to obfuscate");
|
||||
#endif
|
||||
}
|
||||
|
||||
Debug.LogWarning("No obfuscation required because no C# scripts were found");
|
||||
}
|
||||
finally
|
||||
{
|
||||
Clear();
|
||||
}
|
||||
}
|
||||
|
||||
#if UNITY_2018_1_OR_NEWER
|
||||
public void OnPreprocessBuild(BuildReport report)
|
||||
{
|
||||
_project = new Project();
|
||||
}
|
||||
#elif UNITY_5_6_OR_NEWER
|
||||
public void OnPreprocessBuild(BuildTarget target, string path)
|
||||
{
|
||||
_project = new Project();
|
||||
}
|
||||
#endif
|
||||
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
public string[] OnFilterAssemblies(BuildOptions buildOptions, string[] assemblies)
|
||||
{
|
||||
_project.ObfuscateIfNeeded();
|
||||
return assemblies;
|
||||
}
|
||||
#else
|
||||
[PostProcessScene(1)]
|
||||
public static void Obfuscate()
|
||||
{
|
||||
_project.ObfuscateIfNeeded();
|
||||
}
|
||||
#endif
|
||||
|
||||
public static void ClearProjectViaUpdate()
|
||||
{
|
||||
Clear();
|
||||
EditorApplication.update -= ClearProjectViaUpdate;
|
||||
}
|
||||
|
||||
private static void Clear()
|
||||
{
|
||||
_project = new Project();
|
||||
}
|
||||
}
|
||||
|
||||
[InitializeOnLoad]
|
||||
public static class RestorationStatic
|
||||
{
|
||||
/*
|
||||
* Often Unity's EditorApplication.update delegate is reset. Because it's so important to restore
|
||||
* renamed MonoBehaviour assets we assign here where it will be called after scripts are compiled.
|
||||
*/
|
||||
static RestorationStatic()
|
||||
{
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
#else
|
||||
EditorApplication.update += RestoreUtils.RestoreMonobehaviourSourceFiles;
|
||||
#endif
|
||||
EditorApplication.update += RestoreUtils.RestoreOriginalDlls;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 36b15db65a6bcba42aa20d57ec36dc0e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,9 @@
|
||||
fileFormatVersion: 2
|
||||
guid: c1c2517caf2151c4db5cd7f23599215d
|
||||
folderAsset: yes
|
||||
timeCreated: 1456430305
|
||||
licenseType: Store
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -0,0 +1,38 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 66bd02e2746234647a685703c57241ec
|
||||
labels:
|
||||
- Security
|
||||
- Obfuscation
|
||||
- Obfuscator
|
||||
- Beebyte
|
||||
PluginImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
iconMap: {}
|
||||
executionOrder: {}
|
||||
defineConstraints: []
|
||||
isPreloaded: 0
|
||||
isOverridable: 0
|
||||
isExplicitlyReferenced: 0
|
||||
validateReferences: 1
|
||||
platformData:
|
||||
- first:
|
||||
Any:
|
||||
second:
|
||||
enabled: 0
|
||||
settings: {}
|
||||
- first:
|
||||
Editor: Editor
|
||||
second:
|
||||
enabled: 1
|
||||
settings:
|
||||
DefaultValueInitialized: true
|
||||
- first:
|
||||
Windows Store Apps: WindowsStoreApps
|
||||
second:
|
||||
enabled: 0
|
||||
settings:
|
||||
CPU: AnyCPU
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,11 @@
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
/**
|
||||
* Empty class to ensure old versions of this class are wiped out on upgrades.
|
||||
*
|
||||
* @See PipelineHook.cs for the build pipeline entry points
|
||||
*/
|
||||
public class Postbuild
|
||||
{
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 09a26d25512353049a7b7e8474c3895e
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,162 @@
|
||||
/*
|
||||
* Copyright (c) 2015-2020 Beebyte Limited. All rights reserved.
|
||||
*/
|
||||
#if !BEEBYTE_OBFUSCATOR_DISABLE
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
using System.Linq;
|
||||
using Beebyte.Obfuscator.Assembly;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
/**
|
||||
* Handles obfuscation calls for a Unity project and controls restoration of backed up files.
|
||||
*/
|
||||
public class Project
|
||||
{
|
||||
private Options _options;
|
||||
|
||||
private bool _monoBehaviourAssetsNeedReverting = false;
|
||||
private bool _hasError;
|
||||
private bool _hasObfuscated;
|
||||
private bool _noCSharpScripts;
|
||||
|
||||
public bool ShouldObfuscate()
|
||||
{
|
||||
if (_options == null) _options = OptionsManager.LoadOptions();
|
||||
return _options.enabled && (_options.obfuscateReleaseOnly == false || Debug.isDebugBuild == false);
|
||||
}
|
||||
|
||||
public bool IsSuccess()
|
||||
{
|
||||
return _hasObfuscated || !ShouldObfuscate();
|
||||
}
|
||||
|
||||
public bool HasCSharpScripts()
|
||||
{
|
||||
return !_noCSharpScripts;
|
||||
}
|
||||
|
||||
public bool HasMonoBehaviourAssetsThatNeedReverting()
|
||||
{
|
||||
return _monoBehaviourAssetsNeedReverting;
|
||||
}
|
||||
|
||||
public void ObfuscateIfNeeded()
|
||||
{
|
||||
#if UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2
|
||||
if (!EditorApplication.isPlayingOrWillChangePlaymode && !_hasObfuscated && _hasError == false)
|
||||
#else
|
||||
if (!EditorApplication.isPlayingOrWillChangePlaymode && !_hasObfuscated && _hasError == false && BuildPipeline.isBuildingPlayer)
|
||||
#endif
|
||||
{
|
||||
#if !UNITY_5_6_OR_NEWER
|
||||
EditorApplication.update += PipelineHook.ClearProjectViaUpdate;
|
||||
#endif
|
||||
try
|
||||
{
|
||||
EditorApplication.LockReloadAssemblies();
|
||||
ObfuscateWhileLocked();
|
||||
}
|
||||
catch (Exception e)
|
||||
{
|
||||
Debug.LogError("Obfuscation Failed: " + e);
|
||||
_hasError = true;
|
||||
throw new OperationCanceledException("Obfuscation failed", e);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorApplication.UnlockReloadAssemblies();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private void ObfuscateWhileLocked()
|
||||
{
|
||||
if (_options == null) _options = OptionsManager.LoadOptions();
|
||||
|
||||
if (ShouldObfuscate() == false) return;
|
||||
|
||||
AssemblySelector selector = new AssemblySelector(_options);
|
||||
|
||||
ICollection<string> compiledDlls = selector.GetCompiledAssemblyPaths();
|
||||
|
||||
if (compiledDlls.Count > 0)
|
||||
{
|
||||
EditorApplication.update += RestoreUtils.RestoreOriginalDlls;
|
||||
}
|
||||
|
||||
IDictionary<string, string> backupMap = FileBackup.GetBackupMap(compiledDlls);
|
||||
FileBackup.Backup(backupMap);
|
||||
|
||||
ICollection<string> dlls = selector.GetAssemblyPaths();
|
||||
|
||||
if (dlls.Count == 0 && compiledDlls.Count == 0)
|
||||
{
|
||||
_noCSharpScripts = true;
|
||||
return;
|
||||
}
|
||||
|
||||
#if UNITY_2017_3_OR_NEWER
|
||||
Obfuscator.AppendReferenceAssemblies(AssemblyReferenceLocator.GetAssemblyReferenceDirectories().ToArray());
|
||||
#endif
|
||||
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
Obfuscator.ObfuscateMonoBehavioursByAssetDatabase(false);
|
||||
var obfuscateMonoBehaviourNames = _options.obfuscateMonoBehaviourClassNames;
|
||||
try
|
||||
{
|
||||
if (IsXCodeProject() && _options.obfuscateMonoBehaviourClassNames)
|
||||
{
|
||||
Debug.LogWarning("MonoBehaviour class names will not be obfuscated when creating Xcode projects");
|
||||
_options.obfuscateMonoBehaviourClassNames = false;
|
||||
}
|
||||
#endif
|
||||
|
||||
Obfuscator.Obfuscate(dlls, compiledDlls, _options, EditorUserBuildSettings.activeBuildTarget);
|
||||
|
||||
#if !UNITY_2018_2_OR_NEWER
|
||||
if (_options.obfuscateMonoBehaviourClassNames)
|
||||
{
|
||||
/*
|
||||
* RestoreAssets must be registered via the update delegate because [PostProcessBuild] is not guaranteed to be called
|
||||
*/
|
||||
EditorApplication.update += RestoreUtils.RestoreMonobehaviourSourceFiles;
|
||||
_monoBehaviourAssetsNeedReverting = true;
|
||||
}
|
||||
#else
|
||||
}
|
||||
finally
|
||||
{
|
||||
_options.obfuscateMonoBehaviourClassNames = obfuscateMonoBehaviourNames;
|
||||
}
|
||||
#endif
|
||||
_hasObfuscated = true;
|
||||
}
|
||||
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
private bool IsXCodeProject()
|
||||
{
|
||||
return EditorUserBuildSettings.activeBuildTarget == BuildTarget.StandaloneOSX &&
|
||||
EditorUserBuildSettings.GetPlatformSettings("OSXUniversal", "CreateXcodeProject").Equals("true");
|
||||
}
|
||||
#endif
|
||||
|
||||
public void ObfuscateAssets(BuildTarget buildTarget, string pathToBuildProject)
|
||||
{
|
||||
#if UNITY_2018_2_OR_NEWER
|
||||
if (IsXCodeProject()) return;
|
||||
if (_options == null) _options = OptionsManager.LoadOptions();
|
||||
if (_options.obfuscateMonoBehaviourClassNames && File.Exists("_AssetTranslations"))
|
||||
{
|
||||
string pathToGlobalGameManagersAsset = GlobalGameManagersPath.GetPathToGlobalGameManagersAsset(buildTarget, pathToBuildProject);
|
||||
Obfuscator.RenameScriptableAssets("_AssetTranslations", pathToGlobalGameManagersAsset);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 004ba706b30308f49ad9214f313587c2
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,60 @@
|
||||
using System.Collections.Generic;
|
||||
using Beebyte.Obfuscator.Assembly;
|
||||
using UnityEditor;
|
||||
|
||||
namespace Beebyte.Obfuscator
|
||||
{
|
||||
public class RestoreUtils
|
||||
{
|
||||
/**
|
||||
* When assemblies are declared in the 'Compiled Assemblies' list within Obfuscator options then before any
|
||||
* obfuscation they are temporarily backed up then operated on. This method is then called after obfuscation
|
||||
* to restore the original assembly and remove the backup.
|
||||
*/
|
||||
public static void RestoreOriginalDlls()
|
||||
{
|
||||
try
|
||||
{
|
||||
Options options = OptionsManager.LoadOptionsIgnoringInstallFiles();
|
||||
if (options == null || options.compiledAssemblies.Length == 0)
|
||||
{
|
||||
return;
|
||||
}
|
||||
ICollection<string> compiledAssemblyPaths = new AssemblySelector(options).GetCompiledAssemblyPaths();
|
||||
IDictionary<string, string> backupMap = FileBackup.GetBackupMap(compiledAssemblyPaths);
|
||||
//DLLs declared within 'Compiled Assemblies' will be restored from this method.
|
||||
FileBackup.Restore(backupMap);
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorApplication.update -= RestoreOriginalDlls;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This method restores obfuscated MonoBehaviour cs files to their original names.
|
||||
*/
|
||||
public static void RestoreMonobehaviourSourceFiles()
|
||||
{
|
||||
#if UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2
|
||||
#else
|
||||
if (BuildPipeline.isBuildingPlayer == false)
|
||||
{
|
||||
#endif
|
||||
try
|
||||
{
|
||||
EditorApplication.LockReloadAssemblies();
|
||||
Obfuscator.RevertAssetObfuscation();
|
||||
}
|
||||
finally
|
||||
{
|
||||
EditorApplication.update -= RestoreMonobehaviourSourceFiles;
|
||||
EditorApplication.UnlockReloadAssemblies();
|
||||
}
|
||||
#if UNITY_3_1 || UNITY_3_2 || UNITY_3_3 || UNITY_3_4 || UNITY_3_5 || UNITY_4_0 || UNITY_4_1 || UNITY_4_2
|
||||
#else
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,10 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 181fc9a6bda9f944d92bab048f7b24d9
|
||||
MonoImporter:
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,25 @@
|
||||
This asset is governed by the Asset Store EULA; however, the following components are governed by the licenses indicated below:
|
||||
|
||||
A. Mono Cecil - jbevain/cecil (relates to the following files: Beebyte.Cecil.dll, Beebyte.Cecil.Mdb.dll, Beebyte.Cecil.Pdb.dll, Beebyte.Cecil.Rocks.dll)
|
||||
MIT
|
||||
Copyright (c) 2008 - 2015 Jb Evain
|
||||
Copyright (c) 2008 - 2011 Novell, Inc.
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining
|
||||
a copy of this software and associated documentation files (the
|
||||
"Software"), to deal in the Software without restriction, including
|
||||
without limitation the rights to use, copy, modify, merge, publish,
|
||||
distribute, sublicense, and/or sell copies of the Software, and to
|
||||
permit persons to whom the Software is furnished to do so, subject to
|
||||
the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be
|
||||
included in all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
||||
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
||||
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
||||
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
||||
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
||||
@@ -0,0 +1,6 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 555e23ec41b0cea4599481f593be7b4a
|
||||
TextScriptImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -0,0 +1,20 @@
|
||||
using Assets.Scripts.Scenes.VideoRide;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using UnityEngine;
|
||||
|
||||
public class FollowerCamera : MonoBehaviour
|
||||
{
|
||||
VideoGameManager manager;
|
||||
// Start is called before the first frame update
|
||||
void Start()
|
||||
{
|
||||
manager = FindObjectOfType<VideoGameManager>();
|
||||
}
|
||||
|
||||
// Update is called once per frame
|
||||
void Update()
|
||||
{
|
||||
//manager.frame1
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4c4f03ef077d44245aff46f448c3519d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@@ -1,5 +1,5 @@
|
||||
fileFormatVersion: 2
|
||||
guid: add4628056b6bb6459d837d797b5f4ea
|
||||
guid: 39e9f40939fde574ca2a293c619e95e9
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
+6
-6
@@ -7,10 +7,10 @@ Material:
|
||||
m_CorrespondingSourceObject: {fileID: 0}
|
||||
m_PrefabInstance: {fileID: 0}
|
||||
m_PrefabAsset: {fileID: 0}
|
||||
m_Name: Female_Cloth_tex
|
||||
m_Name: VideoMaterial
|
||||
m_Shader: {fileID: 46, guid: 0000000000000000f000000000000000, type: 0}
|
||||
m_ShaderKeywords:
|
||||
m_LightmapFlags: 5
|
||||
m_ShaderKeywords: _GLOSSYREFLECTIONS_OFF _SPECULARHIGHLIGHTS_OFF
|
||||
m_LightmapFlags: 4
|
||||
m_EnableInstancingVariants: 0
|
||||
m_DoubleSidedGI: 0
|
||||
m_CustomRenderQueue: -1
|
||||
@@ -61,14 +61,14 @@ Material:
|
||||
- _DetailNormalMapScale: 1
|
||||
- _DstBlend: 0
|
||||
- _GlossMapScale: 1
|
||||
- _Glossiness: 0.5
|
||||
- _GlossyReflections: 1
|
||||
- _Glossiness: 0
|
||||
- _GlossyReflections: 0
|
||||
- _Metallic: 0
|
||||
- _Mode: 0
|
||||
- _OcclusionStrength: 1
|
||||
- _Parallax: 0.02
|
||||
- _SmoothnessTextureChannel: 0
|
||||
- _SpecularHighlights: 1
|
||||
- _SpecularHighlights: 0
|
||||
- _SrcBlend: 1
|
||||
- _UVSec: 0
|
||||
- _ZWrite: 1
|
||||
@@ -0,0 +1,8 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7a7d739233991f94b80481005b079d7d
|
||||
NativeFormatImporter:
|
||||
externalObjects: {}
|
||||
mainObjectFileID: 2100000
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
@@ -1,241 +0,0 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 7f198bca75ec03e459af141ad6563992
|
||||
timeCreated: 1478463935
|
||||
licenseType: Store
|
||||
ModelImporter:
|
||||
serializedVersion: 19
|
||||
fileIDToRecycleName:
|
||||
100000: Back_Wheel
|
||||
100002: Bike
|
||||
100004: bk_handle
|
||||
100006: bk_susp_child
|
||||
100008: bk_susp_pare
|
||||
100010: bk_suspention
|
||||
100012: bk_wheel
|
||||
100014: bk_wheel0
|
||||
100016: body1
|
||||
100018: Chest_J
|
||||
100020: Cycle_body
|
||||
100022: Cyclist_Lady
|
||||
100024: Cyclist_Lady___cycle:Body_geo
|
||||
100026: Cyclist_Lady___cycle:Eye_geo
|
||||
100028: Cyclist_Lady___cycle:Gloves_geo
|
||||
100030: Cyclist_Lady___cycle:Goggles_geo
|
||||
100032: Cyclist_Lady___cycle:Hair_geo
|
||||
100034: Cyclist_Lady___cycle:Hand_geo
|
||||
100036: Cyclist_Lady___cycle:Hemet_geo
|
||||
100038: Cyclist_Lady___cycle:Shoe_geo
|
||||
100040: Cyclist_Lady_Character
|
||||
100042: Front_Wheel
|
||||
100044: FT_wheel_Ball
|
||||
100046: ft_wheel_suspention
|
||||
100048: handle
|
||||
100050: joint2
|
||||
100052: joint3
|
||||
100054: //RootNode
|
||||
100056: L_Ankle_J
|
||||
100058: L_Arm_J
|
||||
100060: L_Ball_J
|
||||
100062: L_Clavicle_J
|
||||
100064: L_Elbow_J
|
||||
100066: L_Hip_J
|
||||
100068: L_Index_01_J
|
||||
100070: L_Index_02_J
|
||||
100072: L_Index_03_J
|
||||
100074: L_Knee_J
|
||||
100076: L_Middle_01_J
|
||||
100078: L_Middle_02_J
|
||||
100080: L_Middle_03_J
|
||||
100082: L_ProWrist_J
|
||||
100084: L_Thumb_01_J
|
||||
100086: L_Thumb_02_J
|
||||
100088: L_Toe_J
|
||||
100090: L_Wrist_J
|
||||
100092: Neck_J
|
||||
100094: pedal_J
|
||||
100096: Peddle
|
||||
100098: Pelvis_J
|
||||
100100: R_Ankle_J
|
||||
100102: R_Arm_J
|
||||
100104: R_Ball_J
|
||||
100106: R_Clavicle_J
|
||||
100108: R_Elbow_J
|
||||
100110: R_Hip_J
|
||||
100112: R_Index_01_J
|
||||
100114: R_Index_02_J
|
||||
100116: R_Index_03_J
|
||||
100118: R_Knee_J
|
||||
100120: R_Middle_01_J
|
||||
100122: R_Middle_02_J
|
||||
100124: R_Middle_03_J
|
||||
100126: R_ProWrist_J
|
||||
100128: R_Thumb_01_J
|
||||
100130: R_Thumb_02_J
|
||||
100132: R_Toe_J
|
||||
100134: R_Wrist_J
|
||||
100136: Root_J
|
||||
100138: Root_J 1
|
||||
100140: Spline_01_J
|
||||
100142: Spline_02_J
|
||||
400000: Back_Wheel
|
||||
400002: Bike
|
||||
400004: bk_handle
|
||||
400006: bk_susp_child
|
||||
400008: bk_susp_pare
|
||||
400010: bk_suspention
|
||||
400012: bk_wheel
|
||||
400014: bk_wheel0
|
||||
400016: body1
|
||||
400018: Chest_J
|
||||
400020: Cycle_body
|
||||
400022: Cyclist_Lady
|
||||
400024: Cyclist_Lady___cycle:Body_geo
|
||||
400026: Cyclist_Lady___cycle:Eye_geo
|
||||
400028: Cyclist_Lady___cycle:Gloves_geo
|
||||
400030: Cyclist_Lady___cycle:Goggles_geo
|
||||
400032: Cyclist_Lady___cycle:Hair_geo
|
||||
400034: Cyclist_Lady___cycle:Hand_geo
|
||||
400036: Cyclist_Lady___cycle:Hemet_geo
|
||||
400038: Cyclist_Lady___cycle:Shoe_geo
|
||||
400040: Cyclist_Lady_Character
|
||||
400042: Front_Wheel
|
||||
400044: FT_wheel_Ball
|
||||
400046: ft_wheel_suspention
|
||||
400048: handle
|
||||
400050: joint2
|
||||
400052: joint3
|
||||
400054: //RootNode
|
||||
400056: L_Ankle_J
|
||||
400058: L_Arm_J
|
||||
400060: L_Ball_J
|
||||
400062: L_Clavicle_J
|
||||
400064: L_Elbow_J
|
||||
400066: L_Hip_J
|
||||
400068: L_Index_01_J
|
||||
400070: L_Index_02_J
|
||||
400072: L_Index_03_J
|
||||
400074: L_Knee_J
|
||||
400076: L_Middle_01_J
|
||||
400078: L_Middle_02_J
|
||||
400080: L_Middle_03_J
|
||||
400082: L_ProWrist_J
|
||||
400084: L_Thumb_01_J
|
||||
400086: L_Thumb_02_J
|
||||
400088: L_Toe_J
|
||||
400090: L_Wrist_J
|
||||
400092: Neck_J
|
||||
400094: pedal_J
|
||||
400096: Peddle
|
||||
400098: Pelvis_J
|
||||
400100: R_Ankle_J
|
||||
400102: R_Arm_J
|
||||
400104: R_Ball_J
|
||||
400106: R_Clavicle_J
|
||||
400108: R_Elbow_J
|
||||
400110: R_Hip_J
|
||||
400112: R_Index_01_J
|
||||
400114: R_Index_02_J
|
||||
400116: R_Index_03_J
|
||||
400118: R_Knee_J
|
||||
400120: R_Middle_01_J
|
||||
400122: R_Middle_02_J
|
||||
400124: R_Middle_03_J
|
||||
400126: R_ProWrist_J
|
||||
400128: R_Thumb_01_J
|
||||
400130: R_Thumb_02_J
|
||||
400132: R_Toe_J
|
||||
400134: R_Wrist_J
|
||||
400136: Root_J
|
||||
400138: Root_J 1
|
||||
400140: Spline_01_J
|
||||
400142: Spline_02_J
|
||||
4300000: Cyclist_Lady___cycle:Body_geo
|
||||
4300002: Cyclist_Lady___cycle:Hair_geo
|
||||
4300004: Cyclist_Lady___cycle:Goggles_geo
|
||||
4300006: Cyclist_Lady___cycle:Eye_geo
|
||||
4300008: Cyclist_Lady___cycle:Hemet_geo
|
||||
4300010: Cyclist_Lady___cycle:Gloves_geo
|
||||
4300012: Cyclist_Lady___cycle:Shoe_geo
|
||||
4300014: Cyclist_Lady___cycle:Hand_geo
|
||||
4300016: Front_Wheel
|
||||
4300018: Back_Wheel
|
||||
4300020: Peddle
|
||||
4300022: Cycle_body
|
||||
7400000: Take 001
|
||||
9500000: //RootNode
|
||||
13700000: Back_Wheel
|
||||
13700002: Cycle_body
|
||||
13700004: Cyclist_Lady___cycle:Body_geo
|
||||
13700006: Cyclist_Lady___cycle:Eye_geo
|
||||
13700008: Cyclist_Lady___cycle:Gloves_geo
|
||||
13700010: Cyclist_Lady___cycle:Goggles_geo
|
||||
13700012: Cyclist_Lady___cycle:Hair_geo
|
||||
13700014: Cyclist_Lady___cycle:Hand_geo
|
||||
13700016: Cyclist_Lady___cycle:Hemet_geo
|
||||
13700018: Cyclist_Lady___cycle:Shoe_geo
|
||||
13700020: Front_Wheel
|
||||
13700022: Peddle
|
||||
materials:
|
||||
importMaterials: 1
|
||||
materialName: 0
|
||||
materialSearch: 1
|
||||
animations:
|
||||
legacyGenerateAnimations: 4
|
||||
bakeSimulation: 0
|
||||
resampleRotations: 1
|
||||
optimizeGameObjects: 0
|
||||
motionNodeName:
|
||||
animationImportErrors:
|
||||
animationImportWarnings:
|
||||
animationRetargetingWarnings:
|
||||
animationDoRetargetingWarnings: 0
|
||||
animationCompression: 1
|
||||
animationRotationError: 0.5
|
||||
animationPositionError: 0.5
|
||||
animationScaleError: 0.5
|
||||
animationWrapMode: 0
|
||||
extraExposedTransformPaths: []
|
||||
clipAnimations: []
|
||||
isReadable: 1
|
||||
meshes:
|
||||
lODScreenPercentages: []
|
||||
globalScale: 100
|
||||
meshCompression: 0
|
||||
addColliders: 0
|
||||
importBlendShapes: 1
|
||||
swapUVChannels: 0
|
||||
generateSecondaryUV: 0
|
||||
useFileUnits: 1
|
||||
optimizeMeshForGPU: 1
|
||||
keepQuads: 0
|
||||
weldVertices: 1
|
||||
secondaryUVAngleDistortion: 8
|
||||
secondaryUVAreaDistortion: 15.000001
|
||||
secondaryUVHardAngle: 88
|
||||
secondaryUVPackMargin: 4
|
||||
useFileScale: 1
|
||||
tangentSpace:
|
||||
normalSmoothAngle: 60
|
||||
normalImportMode: 0
|
||||
tangentImportMode: 3
|
||||
importAnimation: 1
|
||||
copyAvatar: 0
|
||||
humanDescription:
|
||||
human: []
|
||||
skeleton: []
|
||||
armTwist: 0.5
|
||||
foreArmTwist: 0.5
|
||||
upperLegTwist: 0.5
|
||||
legTwist: 0.5
|
||||
armStretch: 0.05
|
||||
legStretch: 0.05
|
||||
feetSpacing: 0
|
||||
rootMotionBoneName:
|
||||
hasTranslationDoF: 0
|
||||
lastHumanDescriptionAvatarSource: {instanceID: 0}
|
||||
animationType: 2
|
||||
humanoidOversampling: 1
|
||||
additionalBone: 0
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Loaded 100 of 1872 files, more files were not shown because too many files have changed in this diff.
Show more
Reference in new issue
Block a user