ui基本完毕,修了一大把的bug
This commit is contained in:
@@ -1,8 +1,10 @@
|
||||
using System;
|
||||
using System.Collections.Concurrent;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
using System.IO;
|
||||
using System.Text;
|
||||
using System.Threading;
|
||||
using UnityEngine;
|
||||
|
||||
public static class GameplaySkillLogger
|
||||
@@ -18,6 +20,24 @@ public static class GameplaySkillLogger
|
||||
|
||||
private const float RapidDuplicateSkillThresholdSeconds = 0.05f;
|
||||
|
||||
// Off-thread writer: judge/skill events push formatted lines into this queue and a
|
||||
// single background thread writes them to disk in FIFO order. This keeps the
|
||||
// synchronous file I/O off the gameplay hot path (first-note hitch) while producing
|
||||
// byte-identical output: the queue preserves enqueue order (enqueues happen under
|
||||
// s_fileLock), and the writer thread is the sole owner of the file so a session
|
||||
// truncate (header) can never interleave with an append.
|
||||
private struct LogMessage
|
||||
{
|
||||
public bool Truncate; // true => WriteAllText (new session header); false => AppendAllText
|
||||
public string Text;
|
||||
}
|
||||
|
||||
private static readonly ConcurrentQueue<LogMessage> s_pendingLines = new ConcurrentQueue<LogMessage>();
|
||||
private static readonly AutoResetEvent s_writeSignal = new AutoResetEvent(false);
|
||||
private static Thread s_writerThread;
|
||||
private static volatile bool s_writerRunning;
|
||||
private static readonly object s_writerStartLock = new object();
|
||||
|
||||
public static string LogFilePath
|
||||
{
|
||||
get { return EnsureLogFilePath(); }
|
||||
@@ -256,14 +276,9 @@ public static class GameplaySkillLogger
|
||||
"# Format: [elapsedSec] [CATEGORY] key=value | key=value" + Environment.NewLine +
|
||||
Environment.NewLine;
|
||||
|
||||
try
|
||||
{
|
||||
File.WriteAllText(path, header, s_utf8NoBom);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning("[GameplaySkillLogger] Failed to create session log: " + ex.Message);
|
||||
}
|
||||
EnsureWriterThread();
|
||||
s_pendingLines.Enqueue(new LogMessage { Truncate = true, Text = header });
|
||||
s_writeSignal.Set();
|
||||
}
|
||||
|
||||
private static float AppendEventLineLocked(string category, string payload)
|
||||
@@ -286,18 +301,70 @@ public static class GameplaySkillLogger
|
||||
.Append("] ")
|
||||
.AppendLine(payload);
|
||||
|
||||
try
|
||||
{
|
||||
File.AppendAllText(EnsureLogFilePath(), builder.ToString(), s_utf8NoBom);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning("[GameplaySkillLogger] Failed to append log: " + ex.Message);
|
||||
}
|
||||
EnsureWriterThread();
|
||||
s_pendingLines.Enqueue(new LogMessage { Truncate = false, Text = builder.ToString() });
|
||||
s_writeSignal.Set();
|
||||
|
||||
return elapsed;
|
||||
}
|
||||
|
||||
private static void EnsureWriterThread()
|
||||
{
|
||||
if (s_writerRunning)
|
||||
return;
|
||||
|
||||
lock (s_writerStartLock)
|
||||
{
|
||||
if (s_writerRunning)
|
||||
return;
|
||||
|
||||
s_writerRunning = true;
|
||||
s_writerThread = new Thread(WriterLoop)
|
||||
{
|
||||
Name = "GameplaySkillLoggerWriter",
|
||||
IsBackground = true
|
||||
};
|
||||
s_writerThread.Start();
|
||||
}
|
||||
}
|
||||
|
||||
private static void WriterLoop()
|
||||
{
|
||||
while (s_writerRunning)
|
||||
{
|
||||
s_writeSignal.WaitOne(200);
|
||||
DrainPendingLines();
|
||||
}
|
||||
|
||||
// Final drain so nothing queued right before shutdown is lost.
|
||||
DrainPendingLines();
|
||||
}
|
||||
|
||||
private static void DrainPendingLines()
|
||||
{
|
||||
while (s_pendingLines.TryDequeue(out LogMessage message))
|
||||
{
|
||||
// Read the cached path directly: it is always resolved on the main thread
|
||||
// (BeginSessionInternal -> EnsureLogFilePath) before the writer thread starts,
|
||||
// so we must never call Application.dataPath from this background thread.
|
||||
string path = s_logFilePath;
|
||||
if (string.IsNullOrEmpty(path))
|
||||
continue;
|
||||
|
||||
try
|
||||
{
|
||||
if (message.Truncate)
|
||||
File.WriteAllText(path, message.Text, s_utf8NoBom);
|
||||
else
|
||||
File.AppendAllText(path, message.Text, s_utf8NoBom);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogWarning("[GameplaySkillLogger] Failed to write log: " + ex.Message);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private static void EnsureSessionLocked()
|
||||
{
|
||||
if (!s_sessionActive)
|
||||
|
||||
Reference in New Issue
Block a user