提交Unity 联机Pro

This commit is contained in:
PC-20230316NUNE\Administrator
2024-08-17 14:27:18 +08:00
parent f00193b000
commit 894100ae37
7448 changed files with 854473 additions and 0 deletions

View File

@@ -0,0 +1,143 @@
using System;
using System.Text;
namespace BestHTTP.Logger
{
/// <summary>
/// A basic logger implementation to be able to log intelligently additional informations about the plugin's internal mechanism.
/// </summary>
public class DefaultLogger : BestHTTP.Logger.ILogger
{
public Loglevels Level { get; set; }
public ILogOutput Output
{
get { return this._output; }
set
{
if (this._output != value)
{
if (this._output != null)
this._output.Dispose();
this._output = value;
}
}
}
private ILogOutput _output;
public string FormatVerbose { get; set; }
public string FormatInfo { get; set; }
public string FormatWarn { get; set; }
public string FormatErr { get; set; }
public string FormatEx { get; set; }
public DefaultLogger()
{
FormatVerbose = "[{0}] D [{1}]: {2}";
FormatInfo = "[{0}] I [{1}]: {2}";
FormatWarn = "[{0}] W [{1}]: {2}";
FormatErr = "[{0}] Err [{1}]: {2}";
FormatEx = "[{0}] Ex [{1}]: {2} - Message: {3} StackTrace: {4}";
Level = UnityEngine.Debug.isDebugBuild ? Loglevels.Warning : Loglevels.Error;
this.Output = new UnityOutput();
}
public void Verbose(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null)
{
if (Level <= Loglevels.All)
{
try
{
this.Output.Write(Loglevels.All, string.Format(FormatVerbose, GetFormattedTime(), division, msg));
}
catch
{ }
}
}
public void Information(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null)
{
if (Level <= Loglevels.Information)
{
try
{
this.Output.Write(Loglevels.Information, string.Format(FormatInfo, GetFormattedTime(), division, msg));
}
catch
{ }
}
}
public void Warning(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null)
{
if (Level <= Loglevels.Warning)
{
try
{
this.Output.Write(Loglevels.Warning, string.Format(FormatWarn, GetFormattedTime(), division, msg));
}
catch
{ }
}
}
public void Error(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null)
{
if (Level <= Loglevels.Error)
{
try
{
this.Output.Write(Loglevels.Error, string.Format(FormatErr, GetFormattedTime(), division, msg));
}
catch
{ }
}
}
public void Exception(string division, string msg, Exception ex, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null)
{
if (Level <= Loglevels.Exception)
{
try
{
string exceptionMessage = string.Empty;
if (ex == null)
exceptionMessage = "null";
else
{
StringBuilder sb = new StringBuilder();
Exception exception = ex;
int counter = 1;
while (exception != null)
{
sb.AppendFormat("{0}: {1} {2}", counter++.ToString(), exception.Message, exception.StackTrace);
exception = exception.InnerException;
if (exception != null)
sb.AppendLine();
}
exceptionMessage = sb.ToString();
}
this.Output.Write(Loglevels.Exception, string.Format(FormatEx,
GetFormattedTime(),
division,
msg,
exceptionMessage,
ex != null ? ex.StackTrace : "null"));
}
catch
{ }
}
}
private string GetFormattedTime()
{
return DateTime.Now.Ticks.ToString();
}
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: f0c6097670314f141ad42c8060f64ecb
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,51 @@
using System;
using BestHTTP.Extensions;
using BestHTTP.PlatformSupport.Memory;
namespace BestHTTP.Logger
{
public sealed class FileOutput : ILogOutput
{
private System.IO.Stream fileStream;
public FileOutput(string fileName)
{
this.fileStream = HTTPManager.IOService.CreateFileStream(fileName, PlatformSupport.FileSystem.FileStreamModes.Create);
}
public void Write(Loglevels level, string logEntry)
{
if (this.fileStream != null && !string.IsNullOrEmpty(logEntry))
{
int count = System.Text.Encoding.UTF8.GetByteCount(logEntry);
var buffer = BufferPool.Get(count, true);
try
{
System.Text.Encoding.UTF8.GetBytes(logEntry, 0, logEntry.Length, buffer, 0);
this.fileStream.Write(buffer, 0, count);
this.fileStream.WriteLine();
}
finally
{
BufferPool.Release(buffer);
}
this.fileStream.Flush();
}
}
public void Dispose()
{
if (this.fileStream != null)
{
this.fileStream.Close();
this.fileStream = null;
}
GC.SuppressFinalize(this);
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: f7d6b077b7753e44e943b5f433b3158d
timeCreated: 1591097750
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,65 @@
using System;
namespace BestHTTP.Logger
{
/// <summary>
/// Available logging levels.
/// </summary>
public enum Loglevels : int
{
/// <summary>
/// All message will be logged.
/// </summary>
All,
/// <summary>
/// Only Informations and above will be logged.
/// </summary>
Information,
/// <summary>
/// Only Warnings and above will be logged.
/// </summary>
Warning,
/// <summary>
/// Only Errors and above will be logged.
/// </summary>
Error,
/// <summary>
/// Only Exceptions will be logged.
/// </summary>
Exception,
/// <summary>
/// No logging will occur.
/// </summary>
None
}
public interface ILogOutput : IDisposable
{
void Write(Loglevels level, string logEntry);
}
public interface ILogger
{
/// <summary>
/// The minimum severity to log
/// </summary>
Loglevels Level { get; set; }
ILogOutput Output { get; set; }
void Verbose(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null);
void Information(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null);
void Warning(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null);
void Error(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null);
void Exception(string division, string msg, Exception ex, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null);
}
}

View File

@@ -0,0 +1,10 @@
fileFormatVersion: 2
guid: 41bbbfdb18d1d6f479d52229e8e4e827
MonoImporter:
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,173 @@
using System;
using System.Collections.Generic;
using System.Text;
namespace BestHTTP.Logger
{
public sealed class LoggingContext
{
private enum LoggingContextFieldType
{
Long,
Bool,
String,
AnotherContext
}
private struct LoggingContextField
{
public string key;
public long longValue;
public bool boolValue;
public string stringValue;
public LoggingContext loggingContextValue;
public LoggingContextFieldType fieldType;
}
private List<LoggingContextField> fields = null;
private static System.Random random = new System.Random();
private LoggingContext() { }
public LoggingContext(object boundto)
{
var name = boundto.GetType().Name;
Add("TypeName", name);
long hash = 0;
lock (random)
hash = ((long)boundto.GetHashCode() << 32 | (long)name.GetHashCode()) ^ ((long)this.GetHashCode() << 16) | (long)(random.Next(int.MaxValue) << 32) | (long)random.Next(int.MaxValue);
Add("Hash", hash);
}
public void Add(string key, long value)
{
Add(new LoggingContextField { fieldType = LoggingContextFieldType.Long, key = key, longValue = value });
}
public void Add(string key, bool value)
{
Add(new LoggingContextField { fieldType = LoggingContextFieldType.Bool, key = key, boolValue = value });
}
public void Add(string key, string value)
{
Add(new LoggingContextField { fieldType = LoggingContextFieldType.String, key = key, stringValue = value });
}
public void Add(string key, LoggingContext value)
{
Add(new LoggingContextField { fieldType = LoggingContextFieldType.AnotherContext, key = key, loggingContextValue = value });
}
private void Add(LoggingContextField field)
{
if (this.fields == null)
this.fields = new List<LoggingContextField>();
Remove(field.key);
this.fields.Add(field);
}
public void Remove(string key)
{
this.fields.RemoveAll(field => field.key == key);
}
public LoggingContext Clone()
{
LoggingContext newContext = new LoggingContext();
if (this.fields != null && this.fields.Count > 0)
{
newContext.fields = new List<LoggingContextField>(this.fields.Count);
for (int i = 0; i < this.fields.Count; ++i)
{
var field = this.fields[i];
switch (field.fieldType)
{
case LoggingContextFieldType.Long:
case LoggingContextFieldType.Bool:
case LoggingContextFieldType.String:
newContext.fields.Add(field);
break;
case LoggingContextFieldType.AnotherContext:
newContext.Add(field.key, field.loggingContextValue.Clone());
break;
}
}
}
return newContext;
}
public void ToJson(System.Text.StringBuilder sb)
{
if (this.fields == null || this.fields.Count == 0)
{
sb.Append("null");
return;
}
sb.Append("{");
for (int i = 0; i < this.fields.Count; ++i)
{
var field = this.fields[i];
if (field.fieldType != LoggingContextFieldType.AnotherContext)
{
if (i > 0)
sb.Append(", ");
sb.AppendFormat("\"{0}\": ", field.key);
}
switch (field.fieldType)
{
case LoggingContextFieldType.Long:
sb.Append(field.longValue);
break;
case LoggingContextFieldType.Bool:
sb.Append(field.boolValue ? "true" : "false");
break;
case LoggingContextFieldType.String:
sb.AppendFormat("\"{0}\"", Escape(field.stringValue));
break;
}
}
sb.Append("}");
for (int i = 0; i < this.fields.Count; ++i)
{
var field = this.fields[i];
switch (field.fieldType)
{
case LoggingContextFieldType.AnotherContext:
sb.Append(", ");
field.loggingContextValue.ToJson(sb);
break;
}
}
}
public static string Escape(string original)
{
return PlatformSupport.Text.StringBuilderPool.ReleaseAndGrab(PlatformSupport.Text.StringBuilderPool.Get(1)
.Append(original)
.Replace("\\", "\\\\")
.Replace("\"", "\\\"")
.Replace("/", "\\/")
.Replace("\b", "\\b")
.Replace("\f", "\\f")
.Replace("\n", "\\n")
.Replace("\r", "\\r")
.Replace("\t", "\\t"));
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: b2c848a07a285a7428a454b190e7c3a6
timeCreated: 1591097750
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,318 @@
using System;
using System.Collections.Concurrent;
using System.Text;
using BestHTTP.PlatformSupport.Threading;
namespace BestHTTP.Logger
{
public sealed class ThreadedLogger : BestHTTP.Logger.ILogger, IDisposable
{
public Loglevels Level { get; set; }
public ILogOutput Output { get { return this._output; }
set
{
if (this._output != value)
{
if (this._output != null)
this._output.Dispose();
this._output = value;
}
}
}
private ILogOutput _output;
public int InitialStringBufferCapacity = 256;
#if !UNITY_WEBGL || UNITY_EDITOR
public TimeSpan ExitThreadAfterInactivity = TimeSpan.FromMinutes(1);
private ConcurrentQueue<LogJob> jobs = new ConcurrentQueue<LogJob>();
private System.Threading.AutoResetEvent newJobEvent = new System.Threading.AutoResetEvent(false);
private volatile int threadCreated;
private volatile bool isDisposed;
#endif
private StringBuilder sb = new StringBuilder(0);
public ThreadedLogger()
{
this.Level = UnityEngine.Debug.isDebugBuild ? Loglevels.Warning : Loglevels.Error;
this.Output = new UnityOutput();
}
public void Verbose(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null) {
AddJob(Loglevels.All, division, msg, null, context1, context2, context3);
}
public void Information(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null) {
AddJob(Loglevels.Information, division, msg, null, context1, context2, context3);
}
public void Warning(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null) {
AddJob(Loglevels.Warning, division, msg, null, context1, context2, context3);
}
public void Error(string division, string msg, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null) {
AddJob(Loglevels.Error, division, msg, null, context1, context2, context3);
}
public void Exception(string division, string msg, Exception ex, LoggingContext context1 = null, LoggingContext context2 = null, LoggingContext context3 = null) {
AddJob(Loglevels.Exception, division, msg, ex, context1, context2, context3);
}
private void AddJob(Loglevels level, string div, string msg, Exception ex, LoggingContext context1, LoggingContext context2, LoggingContext context3)
{
if (this.Level > level)
return;
sb.EnsureCapacity(InitialStringBufferCapacity);
#if !UNITY_WEBGL || UNITY_EDITOR
if (this.isDisposed)
return;
#endif
var job = new LogJob
{
level = level,
division = div,
msg = msg,
ex = ex,
time = DateTime.Now,
threadId = System.Threading.Thread.CurrentThread.ManagedThreadId,
stackTrace = System.Environment.StackTrace,
context1 = context1 != null ? context1.Clone() : null,
context2 = context2 != null ? context2.Clone() : null,
context3 = context3 != null ? context3.Clone() : null
};
#if !UNITY_WEBGL || UNITY_EDITOR
// Start the consumer thread before enqueuing to get up and running sooner
if (System.Threading.Interlocked.CompareExchange(ref this.threadCreated, 1, 0) == 0)
BestHTTP.PlatformSupport.Threading.ThreadedRunner.RunLongLiving(ThreadFunc);
this.jobs.Enqueue(job);
try
{
this.newJobEvent.Set();
}
catch
{
try
{
this.Output.Write(job.level, job.ToJson(sb));
}
catch
{ }
return;
}
// newJobEvent might timed out between the previous threadCreated check and newJobEvent.Set() calls closing the thread.
// So, here we check threadCreated again and create a new thread if needed.
if (System.Threading.Interlocked.CompareExchange(ref this.threadCreated, 1, 0) == 0)
BestHTTP.PlatformSupport.Threading.ThreadedRunner.RunLongLiving(ThreadFunc);
#else
this.Output.Write(job.level, job.ToJson(sb));
#endif
}
#if !UNITY_WEBGL || UNITY_EDITOR
private void ThreadFunc()
{
ThreadedRunner.SetThreadName("BestHTTP.Logger");
try
{
do
{
// Waiting for a new log-job timed out
if (!this.newJobEvent.WaitOne(this.ExitThreadAfterInactivity))
{
// clear StringBuilder's inner cache and exit the thread
sb.Length = 0;
sb.Capacity = 0;
System.Threading.Interlocked.Exchange(ref this.threadCreated, 0);
return;
}
LogJob job;
while (this.jobs.TryDequeue(out job))
{
try
{
this.Output.Write(job.level, job.ToJson(sb));
}
catch
{ }
}
} while (!HTTPManager.IsQuitting);
System.Threading.Interlocked.Exchange(ref this.threadCreated, 0);
// When HTTPManager.IsQuitting is true, there is still logging that will create a new thread after the last one quit
// and always writing a new entry about the exiting thread would be too much overhead.
// It would also hard to know what's the last log entry because some are generated on another thread non-deterministically.
//var lastLog = new LogJob
//{
// level = Loglevels.All,
// division = "ThreadedLogger",
// msg = "Log Processing Thread Quitting!",
// time = DateTime.Now,
// threadId = System.Threading.Thread.CurrentThread.ManagedThreadId,
//};
//
//this.Output.WriteVerbose(lastLog.ToJson(sb));
}
catch
{
System.Threading.Interlocked.Exchange(ref this.threadCreated, 0);
}
}
#endif
public void Dispose()
{
#if !UNITY_WEBGL || UNITY_EDITOR
this.isDisposed = true;
if (this.newJobEvent != null)
{
this.newJobEvent.Close();
this.newJobEvent = null;
}
#endif
if (this.Output != null)
{
this.Output.Dispose();
this.Output = new UnityOutput();
}
GC.SuppressFinalize(this);
}
}
[BestHTTP.PlatformSupport.IL2CPP.Il2CppEagerStaticClassConstructionAttribute]
struct LogJob
{
private static string[] LevelStrings = new string[] { "Verbose", "Information", "Warning", "Error", "Exception" };
public Loglevels level;
public string division;
public string msg;
public Exception ex;
public DateTime time;
public int threadId;
public string stackTrace;
public LoggingContext context1;
public LoggingContext context2;
public LoggingContext context3;
private static string WrapInColor(string str, string color)
{
#if UNITY_EDITOR
return string.Format("<b><color={1}>{0}</color></b>", str, color);
#else
return str;
#endif
}
public string ToJson(StringBuilder sb)
{
sb.Length = 0;
sb.AppendFormat("{{\"tid\":{0},\"div\":\"{1}\",\"msg\":\"{2}\"",
WrapInColor(this.threadId.ToString(), "yellow"),
WrapInColor(this.division, "yellow"),
WrapInColor(LoggingContext.Escape(this.msg), "yellow"));
if (ex != null)
{
sb.Append(",\"ex\": [");
Exception exception = this.ex;
while (exception != null)
{
sb.Append("{\"msg\": \"");
sb.Append(LoggingContext.Escape(exception.Message));
sb.Append("\", \"stack\": \"");
sb.Append(LoggingContext.Escape(exception.StackTrace));
sb.Append("\"}");
exception = exception.InnerException;
if (exception != null)
sb.Append(",");
}
sb.Append("]");
}
if (this.stackTrace != null)
{
sb.Append(",\"stack\":\"");
ProcessStackTrace(sb);
sb.Append("\"");
}
else
sb.Append(",\"stack\":\"\"");
if (this.context1 != null || this.context2 != null || this.context3 != null)
{
sb.Append(",\"ctxs\":[");
if (this.context1 != null)
this.context1.ToJson(sb);
if (this.context2 != null)
{
if (this.context1 != null)
sb.Append(",");
this.context2.ToJson(sb);
}
if (this.context3 != null)
{
if (this.context1 != null || this.context2 != null)
sb.Append(",");
this.context3.ToJson(sb);
}
sb.Append("]");
}
else
sb.Append(",\"ctxs\":[]");
sb.AppendFormat(",\"t\":{0},\"ll\":\"{1}\",",
this.time.Ticks.ToString(),
LevelStrings[(int)this.level]);
sb.Append("\"bh\":1}");
return sb.ToString();
}
private void ProcessStackTrace(StringBuilder sb)
{
if (string.IsNullOrEmpty(this.stackTrace))
return;
var lines = this.stackTrace.Split('\n');
// skip top 4 lines that would show the logger.
for (int i = 3; i < lines.Length; ++i)
sb.Append(LoggingContext.Escape(lines[i].Replace("BestHTTP.", "")));
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: 4209c767f5d900e4e87b9ae93cacad35
timeCreated: 1588765781
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,32 @@
using System;
namespace BestHTTP.Logger
{
public sealed class UnityOutput : ILogOutput
{
public void Write(Loglevels level, string logEntry)
{
switch (level)
{
case Loglevels.All:
case Loglevels.Information:
UnityEngine.Debug.Log(logEntry);
break;
case Loglevels.Warning:
UnityEngine.Debug.LogWarning(logEntry);
break;
case Loglevels.Error:
case Loglevels.Exception:
UnityEngine.Debug.LogError(logEntry);
break;
}
}
public void Dispose()
{
GC.SuppressFinalize(this);
}
}
}

View File

@@ -0,0 +1,13 @@
fileFormatVersion: 2
guid: cc3465944e901424f8b8b181e5c95e30
timeCreated: 1591097750
licenseType: Store
MonoImporter:
externalObjects: {}
serializedVersion: 2
defaultReferences: []
executionOrder: 0
icon: {instanceID: 0}
userData:
assetBundleName:
assetBundleVariant: