DCS/ruiyiweiUX/Assets/Scripts/Services/DataPersistenceService.cs

765 lines
28 KiB
C#
Raw Normal View History

2026-06-09 13:59:11 +08:00
using System;
using System.Collections.Generic;
using System.IO;
using System.Globalization;
using System.Text;
using UnityEngine;
using LitJson;
using GeneralTools;
/// <summary>
/// 数据持久化服务实现
/// 使用JSON格式存储应用数据INI格式存储系统配置
/// </summary>
public class DataPersistenceService : IDataPersistenceService
{
private readonly string _settingsPath;
private readonly string _userPrefsPath;
private readonly string _appConfigPath;
private readonly string _configIniPath;
private readonly string _streamingConfigIniPath;
public DataPersistenceService()
{
// 设置存储路径
var dataPath = Application.persistentDataPath;
_settingsPath = Path.Combine(dataPath, "settings.json");
_userPrefsPath = Path.Combine(dataPath, "UserPrefs");
_appConfigPath = Path.Combine(dataPath, "appconfig.json");
_configIniPath = Path.Combine(dataPath, "config.ini");
_streamingConfigIniPath = Path.Combine(Application.streamingAssetsPath, "config.ini");
// 确保目录存在
EnsureDirectoryExists(_userPrefsPath);
TryCopyIniToPersistent();
}
public bool SaveSettings(SystemSettings settings)
{
bool jsonSaved = false;
bool iniSaved = false;
try
{
var json = JsonMapper.ToJson(settings);
jsonSaved = WriteTextAtomically(_settingsPath, json);
}
catch (Exception ex)
{
Debug.LogError($"保存JSON设置失败: {ex.Message}");
}
iniSaved = SaveToIniFile(settings);
if (jsonSaved || iniSaved)
{
Debug.Log($"设置已保存 - JSON: {jsonSaved}, INI: {iniSaved}");
return true;
}
Debug.LogError("保存设置失败JSON和INI都未成功写入");
return false;
}
public SystemSettings LoadSettings()
{
if (TryLoadJsonSettings(out var settings, out var jsonSourcePath))
{
ApplyNewestIniOverrides(settings, jsonSourcePath);
return settings;
}
if (TryLoadIniSettings(_configIniPath, "持久化INI配置", out settings))
{
return settings;
}
if (TryLoadIniSettings(_configIniPath + ".bak", "持久化INI备份配置", out settings))
{
return settings;
}
if (File.Exists(_streamingConfigIniPath))
{
settings = LoadFromIniFile(_streamingConfigIniPath);
Debug.Log($"从默认INI配置加载设置成功: {_streamingConfigIniPath}");
return settings;
}
Debug.Log("使用默认设置");
return new SystemSettings();
}
public bool SaveUserPreferences(string userId, UserPreferences preferences)
{
try
{
var filePath = Path.Combine(_userPrefsPath, $"{userId}_prefs.json");
var json = JsonMapper.ToJson(preferences);
File.WriteAllText(filePath, json);
Debug.Log($"用户偏好已保存: {userId}");
return true;
}
catch (Exception ex)
{
Debug.LogError($"保存用户偏好失败: {ex.Message}");
return false;
}
}
public UserPreferences LoadUserPreferences(string userId)
{
try
{
var filePath = Path.Combine(_userPrefsPath, $"{userId}_prefs.json");
if (File.Exists(filePath))
{
var json = File.ReadAllText(filePath);
return JsonMapper.ToObject<UserPreferences>(json);
}
}
catch (Exception ex)
{
Debug.LogError($"加载用户偏好失败: {ex.Message}");
}
return new UserPreferences { userId = userId };
}
public bool SaveAppConfig(AppConfig config)
{
try
{
var json = JsonMapper.ToJson(config);
File.WriteAllText(_appConfigPath, json);
return true;
}
catch (Exception ex)
{
Debug.LogError($"保存应用配置失败: {ex.Message}");
return false;
}
}
public AppConfig LoadAppConfig()
{
try
{
if (File.Exists(_appConfigPath))
{
var json = File.ReadAllText(_appConfigPath);
return JsonMapper.ToObject<AppConfig>(json);
}
}
catch (Exception ex)
{
Debug.LogError($"加载应用配置失败: {ex.Message}");
}
return new AppConfig();
}
public bool ExportData(string filePath, ExportDataType dataType)
{
try
{
var exportData = new
{
ExportTime = DateTime.Now,
DataType = dataType.ToString(),
Data = GetExportData(dataType)
};
var json = JsonMapper.ToJson(exportData);
File.WriteAllText(filePath, json);
Debug.Log($"数据导出成功: {filePath}");
return true;
}
catch (Exception ex)
{
Debug.LogError($"导出数据失败: {ex.Message}");
return false;
}
}
public void ClearAllData()
{
try
{
if (File.Exists(_settingsPath))
File.Delete(_settingsPath);
if (File.Exists(_appConfigPath))
File.Delete(_appConfigPath);
if (Directory.Exists(_userPrefsPath))
Directory.Delete(_userPrefsPath, true);
Debug.Log("所有持久化数据已清除");
}
catch (Exception ex)
{
Debug.LogError($"清除数据失败: {ex.Message}");
}
}
private bool SaveToIniFile(SystemSettings settings)
{
try
{
var sb = new StringBuilder();
AppendIniSection(sb, "Display",
("brightness", settings.brightness.ToString("F1", CultureInfo.InvariantCulture)));
AppendIniSection(sb, "Audio",
("volume", settings.volume.ToString(CultureInfo.InvariantCulture)),
("muteDurationMinutes", settings.muteDurationMinutes.ToString(CultureInfo.InvariantCulture)));
AppendIniSection(sb, "SerialPort",
("serialPortName", settings.serialPortName ?? string.Empty),
("serialBaudRate", settings.serialBaudRate.ToString(CultureInfo.InvariantCulture)),
("enableSerialCommunication", settings.enableSerialCommunication.ToString()));
AppendIniSection(sb, "BFI",
("bfiLowThreshold", settings.bfiLowThreshold.ToString("F1", CultureInfo.InvariantCulture)),
("bfiHighThreshold", settings.bfiHighThreshold.ToString("F1", CultureInfo.InvariantCulture)),
("bfiAlarmPriority", settings.bfiAlarmPriority.ToString(CultureInfo.InvariantCulture)),
("enableBFIAlarm", settings.enableBFIAlarm.ToString()));
AppendIniSection(sb, "Time",
("useCustomSystemTime", settings.useCustomSystemTime.ToString()),
("customTimeOffsetTicks", settings.customTimeOffsetTicks.ToString(CultureInfo.InvariantCulture)),
("systemTime", settings.systemTime == DateTime.MinValue ? string.Empty : settings.systemTime.ToString("o", CultureInfo.InvariantCulture)));
AppendIniSection(sb, "Network",
("mode", settings.network.Mode.ToString()),
("ipv4", settings.network.IPv4 ?? string.Empty),
("mask", settings.network.Mask ?? string.Empty),
("gateway", settings.network.Gateway ?? string.Empty),
("dns1", settings.network.Dns1 ?? string.Empty),
("dns2", settings.network.Dns2 ?? string.Empty));
AppendIniSection(sb, "System",
("autoBackup", settings.autoBackup.ToString()),
("dataRetentionDays", settings.dataRetentionDays.ToString(CultureInfo.InvariantCulture)));
bool saved = WriteTextAtomically(_configIniPath, sb.ToString());
if (saved)
{
IniFile.ClearCache(_configIniPath);
}
return saved;
}
catch (Exception ex)
{
Debug.LogError($"保存到INI文件失败: {ex.Message}");
return false;
}
}
private SystemSettings LoadFromIniFile(string iniPath)
{
var settings = new SystemSettings();
try
{
IniFile.ClearCache(iniPath);
// 显示设置,使用公开的方法
var brightness = IniFile.ReadIniData("Display", "brightness", "50", iniPath);
if (float.TryParse(brightness, NumberStyles.Float, CultureInfo.InvariantCulture, out float b))
settings.brightness = b;
// 音频设置
var volume = IniFile.ReadIniData("Audio", "volume", "50", iniPath);
if (int.TryParse(volume, NumberStyles.Integer, CultureInfo.InvariantCulture, out int v))
settings.volume = v;
var muteDuration = IniFile.ReadIniData("Audio", "muteDurationMinutes", "3", iniPath);
if (int.TryParse(muteDuration, NumberStyles.Integer, CultureInfo.InvariantCulture, out int md))
settings.muteDurationMinutes = md;
var serialPortName = IniFile.ReadIniData("SerialPort", "serialPortName", settings.serialPortName, iniPath);
if (!string.IsNullOrWhiteSpace(serialPortName))
settings.serialPortName = serialPortName;
var serialBaudRate = IniFile.ReadIniData("SerialPort", "serialBaudRate", settings.serialBaudRate.ToString(), iniPath);
if (int.TryParse(serialBaudRate, NumberStyles.Integer, CultureInfo.InvariantCulture, out int sbr))
settings.serialBaudRate = sbr;
var enableSerial = IniFile.ReadIniData("SerialPort", "enableSerialCommunication", settings.enableSerialCommunication.ToString(), iniPath);
if (bool.TryParse(enableSerial, out bool esc))
settings.enableSerialCommunication = esc;
var bfiLowThreshold = IniFile.ReadIniData("BFI", "bfiLowThreshold", settings.bfiLowThreshold.ToString(CultureInfo.InvariantCulture), iniPath);
if (float.TryParse(bfiLowThreshold, NumberStyles.Float, CultureInfo.InvariantCulture, out float bfiLow))
settings.bfiLowThreshold = bfiLow;
var bfiHighThreshold = IniFile.ReadIniData("BFI", "bfiHighThreshold", settings.bfiHighThreshold.ToString(CultureInfo.InvariantCulture), iniPath);
if (float.TryParse(bfiHighThreshold, NumberStyles.Float, CultureInfo.InvariantCulture, out float bfiHigh))
settings.bfiHighThreshold = bfiHigh;
var bfiAlarmPriority = IniFile.ReadIniData("BFI", "bfiAlarmPriority", settings.bfiAlarmPriority.ToString(), iniPath);
if (int.TryParse(bfiAlarmPriority, NumberStyles.Integer, CultureInfo.InvariantCulture, out int priority))
settings.bfiAlarmPriority = priority;
var enableBfiAlarm = IniFile.ReadIniData("BFI", "enableBFIAlarm", settings.enableBFIAlarm.ToString(), iniPath);
if (bool.TryParse(enableBfiAlarm, out bool enableAlarm))
settings.enableBFIAlarm = enableAlarm;
var useCustomSystemTime = IniFile.ReadIniData("Time", "useCustomSystemTime", settings.useCustomSystemTime.ToString(), iniPath);
if (bool.TryParse(useCustomSystemTime, out bool customTime))
settings.useCustomSystemTime = customTime;
var customTimeOffsetTicks = IniFile.ReadIniData("Time", "customTimeOffsetTicks", settings.customTimeOffsetTicks.ToString(), iniPath);
if (long.TryParse(customTimeOffsetTicks, NumberStyles.Integer, CultureInfo.InvariantCulture, out long offsetTicks))
settings.customTimeOffsetTicks = offsetTicks;
var systemTime = IniFile.ReadIniData("Time", "systemTime", "", iniPath);
if (!string.IsNullOrWhiteSpace(systemTime) &&
DateTime.TryParse(systemTime, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime parsedTime))
{
settings.systemTime = parsedTime;
}
// 网络设置
var networkMode = IniFile.ReadIniData("Network", "mode", "Dhcp", iniPath);
if (Enum.TryParse<NetworkMode>(networkMode, out NetworkMode nm))
settings.network.Mode = nm;
settings.network.IPv4 = IniFile.ReadIniData("Network", "ipv4", "", iniPath);
settings.network.Mask = IniFile.ReadIniData("Network", "mask", "", iniPath);
settings.network.Gateway = IniFile.ReadIniData("Network", "gateway", "", iniPath);
settings.network.Dns1 = IniFile.ReadIniData("Network", "dns1", "", iniPath);
settings.network.Dns2 = IniFile.ReadIniData("Network", "dns2", "", iniPath);
// 系统设置
var autoBackup = IniFile.ReadIniData("System", "autoBackup", "true", iniPath);
if (bool.TryParse(autoBackup, out bool ab))
settings.autoBackup = ab;
var dataRetention = IniFile.ReadIniData("System", "dataRetentionDays", "30", iniPath);
if (int.TryParse(dataRetention, NumberStyles.Integer, CultureInfo.InvariantCulture, out int dr))
settings.dataRetentionDays = dr;
}
catch (Exception ex)
{
Debug.LogError($"从INI文件加载设置失败 ({iniPath}): {ex.Message}");
}
return settings;
}
private static void AppendIniSection(StringBuilder builder, string sectionName, params (string Key, string Value)[] values)
{
builder.Append('[').Append(sectionName).AppendLine("]");
foreach (var pair in values)
{
builder.Append(pair.Key).Append('=').AppendLine(pair.Value ?? string.Empty);
}
builder.AppendLine();
}
private void ApplyIniOverrides(SystemSettings settings, string iniPath)
{
if (settings == null || string.IsNullOrWhiteSpace(iniPath) || !File.Exists(iniPath))
{
return;
}
IniFile.ClearCache(iniPath);
const string missing = "__DCX_SETTING_MISSING__";
string brightness = IniFile.ReadIniData("Display", "brightness", missing, iniPath);
if (brightness != missing && float.TryParse(brightness, NumberStyles.Float, CultureInfo.InvariantCulture, out float b))
settings.brightness = b;
string volume = IniFile.ReadIniData("Audio", "volume", missing, iniPath);
if (volume != missing && int.TryParse(volume, out int v))
settings.volume = v;
string muteDuration = IniFile.ReadIniData("Audio", "muteDurationMinutes", missing, iniPath);
if (muteDuration != missing && int.TryParse(muteDuration, out int md))
settings.muteDurationMinutes = md;
string serialPortName = IniFile.ReadIniData("SerialPort", "serialPortName", missing, iniPath);
if (serialPortName != missing && !string.IsNullOrWhiteSpace(serialPortName))
settings.serialPortName = serialPortName;
string serialBaudRate = IniFile.ReadIniData("SerialPort", "serialBaudRate", missing, iniPath);
if (serialBaudRate != missing && int.TryParse(serialBaudRate, out int sbr))
settings.serialBaudRate = sbr;
string enableSerial = IniFile.ReadIniData("SerialPort", "enableSerialCommunication", missing, iniPath);
if (enableSerial != missing && bool.TryParse(enableSerial, out bool esc))
settings.enableSerialCommunication = esc;
string bfiLowThreshold = IniFile.ReadIniData("BFI", "bfiLowThreshold", missing, iniPath);
if (bfiLowThreshold != missing && float.TryParse(bfiLowThreshold, NumberStyles.Float, CultureInfo.InvariantCulture, out float bfiLow))
settings.bfiLowThreshold = bfiLow;
string bfiHighThreshold = IniFile.ReadIniData("BFI", "bfiHighThreshold", missing, iniPath);
if (bfiHighThreshold != missing && float.TryParse(bfiHighThreshold, NumberStyles.Float, CultureInfo.InvariantCulture, out float bfiHigh))
settings.bfiHighThreshold = bfiHigh;
string bfiAlarmPriority = IniFile.ReadIniData("BFI", "bfiAlarmPriority", missing, iniPath);
if (bfiAlarmPriority != missing && int.TryParse(bfiAlarmPriority, out int priority))
settings.bfiAlarmPriority = priority;
string enableBfiAlarm = IniFile.ReadIniData("BFI", "enableBFIAlarm", missing, iniPath);
if (enableBfiAlarm != missing && bool.TryParse(enableBfiAlarm, out bool enableAlarm))
settings.enableBFIAlarm = enableAlarm;
string useCustomSystemTime = IniFile.ReadIniData("Time", "useCustomSystemTime", missing, iniPath);
if (useCustomSystemTime != missing && bool.TryParse(useCustomSystemTime, out bool customTime))
settings.useCustomSystemTime = customTime;
string customTimeOffsetTicks = IniFile.ReadIniData("Time", "customTimeOffsetTicks", missing, iniPath);
if (customTimeOffsetTicks != missing && long.TryParse(customTimeOffsetTicks, out long offsetTicks))
settings.customTimeOffsetTicks = offsetTicks;
string systemTime = IniFile.ReadIniData("Time", "systemTime", missing, iniPath);
if (systemTime != missing && !string.IsNullOrWhiteSpace(systemTime) &&
DateTime.TryParse(systemTime, CultureInfo.InvariantCulture, DateTimeStyles.RoundtripKind, out DateTime parsedTime))
{
settings.systemTime = parsedTime;
}
string networkMode = IniFile.ReadIniData("Network", "mode", missing, iniPath);
if (networkMode != missing && Enum.TryParse<NetworkMode>(networkMode, out NetworkMode nm))
settings.network.Mode = nm;
string ipv4 = IniFile.ReadIniData("Network", "ipv4", missing, iniPath);
if (ipv4 != missing)
settings.network.IPv4 = ipv4;
string mask = IniFile.ReadIniData("Network", "mask", missing, iniPath);
if (mask != missing)
settings.network.Mask = mask;
string gateway = IniFile.ReadIniData("Network", "gateway", missing, iniPath);
if (gateway != missing)
settings.network.Gateway = gateway;
string dns1 = IniFile.ReadIniData("Network", "dns1", missing, iniPath);
if (dns1 != missing)
settings.network.Dns1 = dns1;
string dns2 = IniFile.ReadIniData("Network", "dns2", missing, iniPath);
if (dns2 != missing)
settings.network.Dns2 = dns2;
string autoBackup = IniFile.ReadIniData("System", "autoBackup", missing, iniPath);
if (autoBackup != missing && bool.TryParse(autoBackup, out bool ab))
settings.autoBackup = ab;
string dataRetention = IniFile.ReadIniData("System", "dataRetentionDays", missing, iniPath);
if (dataRetention != missing && int.TryParse(dataRetention, out int dr))
settings.dataRetentionDays = dr;
}
private bool WriteTextAtomically(string filePath, string content)
{
var tempPath = string.IsNullOrWhiteSpace(filePath) ? null : filePath + ".tmp";
try
{
var directory = Path.GetDirectoryName(filePath);
if (!string.IsNullOrWhiteSpace(directory))
{
Directory.CreateDirectory(directory);
}
var backupPath = filePath + ".bak";
byte[] bytes = new UTF8Encoding(false).GetBytes(content ?? string.Empty);
DeleteFileIfExists(tempPath);
WriteBytesAndFlush(tempPath, bytes);
if (File.Exists(filePath))
{
try
{
CopyFileSynced(filePath, backupPath);
}
catch (Exception ex)
{
Debug.LogWarning($"备份旧配置文件失败,将继续写入新配置: {filePath}, {ex.Message}");
}
DeleteFileIfExists(filePath);
}
File.Move(tempPath, filePath);
var fileInfo = new FileInfo(filePath);
if (!fileInfo.Exists || fileInfo.Length != bytes.Length)
{
throw new IOException($"写入校验失败,期望 {bytes.Length} 字节,实际 {(fileInfo.Exists ? fileInfo.Length : 0)} 字节");
}
return true;
}
catch (Exception ex)
{
Debug.LogError($"原子写入失败: {filePath}, {ex.Message}");
return false;
}
finally
{
if (!string.IsNullOrWhiteSpace(tempPath))
{
DeleteFileIfExists(tempPath);
}
}
}
private void TryCopyIniToPersistent()
{
try
{
if (File.Exists(_configIniPath) || File.Exists(_settingsPath))
{
return;
}
if (File.Exists(_streamingConfigIniPath))
{
File.Copy(_streamingConfigIniPath, _configIniPath, true);
}
}
catch (Exception ex)
{
Debug.LogWarning($"复制默认INI到持久化目录失败: {ex.Message}");
}
}
private bool TryLoadJsonSettings(out SystemSettings settings, out string sourcePath)
{
settings = null;
sourcePath = null;
string[] candidates =
{
_settingsPath,
_settingsPath + ".bak",
_settingsPath + ".tmp"
};
foreach (string candidate in GetExistingPathsNewestFirst(candidates))
{
if (TryLoadJsonSettings(candidate, out settings))
{
sourcePath = candidate;
return true;
}
}
return false;
}
private IEnumerable<string> GetExistingPathsNewestFirst(IEnumerable<string> paths)
{
var existingPaths = new List<string>();
foreach (string path in paths)
{
if (!string.IsNullOrWhiteSpace(path) && File.Exists(path))
{
existingPaths.Add(path);
}
}
existingPaths.Sort((left, right) => GetLastWriteTimeUtcSafe(right).CompareTo(GetLastWriteTimeUtcSafe(left)));
return existingPaths;
}
private bool TryLoadJsonSettings(string path, out SystemSettings settings)
{
settings = null;
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
{
return false;
}
try
{
var json = File.ReadAllText(path, Encoding.UTF8);
if (string.IsNullOrWhiteSpace(json))
{
throw new InvalidDataException("文件为空");
}
settings = JsonMapper.ToObject<SystemSettings>(json);
if (settings == null)
{
throw new InvalidDataException("反序列化结果为空");
}
Debug.Log($"从JSON配置加载设置成功: {path}");
return true;
}
catch (Exception ex)
{
Debug.LogWarning($"从JSON配置加载设置失败: {path}, {ex.Message}");
settings = null;
return false;
}
}
private void ApplyNewestIniOverrides(SystemSettings settings, string jsonSourcePath)
{
string iniPath = GetNewestExistingPath(_configIniPath, _configIniPath + ".bak");
if (iniPath == null)
{
return;
}
if (GetLastWriteTimeUtcSafe(iniPath) >= GetLastWriteTimeUtcSafe(jsonSourcePath))
{
ApplyIniOverrides(settings, iniPath);
Debug.Log($"已合并INI覆盖项: {iniPath}");
}
}
private bool TryLoadIniSettings(string path, string sourceName, out SystemSettings settings)
{
settings = null;
if (string.IsNullOrWhiteSpace(path) || !File.Exists(path))
{
return false;
}
settings = LoadFromIniFile(path);
Debug.Log($"从{sourceName}加载设置成功: {path}");
return settings != null;
}
private string GetNewestExistingPath(string firstPath, string secondPath)
{
bool firstExists = !string.IsNullOrWhiteSpace(firstPath) && File.Exists(firstPath);
bool secondExists = !string.IsNullOrWhiteSpace(secondPath) && File.Exists(secondPath);
if (firstExists && secondExists)
{
return GetLastWriteTimeUtcSafe(secondPath) > GetLastWriteTimeUtcSafe(firstPath) ? secondPath : firstPath;
}
if (firstExists)
{
return firstPath;
}
return secondExists ? secondPath : null;
}
private DateTime GetLastWriteTimeUtcSafe(string path)
{
try
{
return !string.IsNullOrWhiteSpace(path) && File.Exists(path)
? File.GetLastWriteTimeUtc(path)
: DateTime.MinValue;
}
catch
{
return DateTime.MinValue;
}
}
private void WriteBytesAndFlush(string filePath, byte[] bytes)
{
using (var stream = new FileStream(filePath, FileMode.Create, FileAccess.Write, FileShare.Read, 4096))
{
stream.Write(bytes, 0, bytes.Length);
FlushFileStream(stream);
}
}
private void CopyFileSynced(string sourcePath, string targetPath)
{
if (string.IsNullOrWhiteSpace(sourcePath) || !File.Exists(sourcePath))
{
return;
}
byte[] bytes = File.ReadAllBytes(sourcePath);
WriteBytesAndFlush(targetPath, bytes);
}
private void FlushFileStream(FileStream stream)
{
try
{
stream.Flush(true);
}
catch
{
stream.Flush();
}
}
private void DeleteFileIfExists(string path)
{
try
{
if (!string.IsNullOrWhiteSpace(path) && File.Exists(path))
{
File.Delete(path);
}
}
catch (Exception ex)
{
Debug.LogWarning($"删除文件失败: {path}, {ex.Message}");
}
}
private object GetExportData(ExportDataType dataType)
{
switch (dataType)
{
case ExportDataType.Settings:
return LoadSettings();
case ExportDataType.UserData:
// 导出所有用户数据
return "用户数据导出功能待实现";
case ExportDataType.AlarmRecords:
// 导出报警记录
var records = DCSAlarmManager.Instance?.GetAlarmRecords(1000);
return records != null ? records : "无报警记录";
case ExportDataType.PatientInfo:
// 导出病人信息
var patient = ServiceLocator.Get<IPatientInfoService>()?.GetCurrentPatient();
return patient != null ? patient : "无病人信息";
case ExportDataType.SystemLogs:
return "系统日志导出功能待实现";
case ExportDataType.All:
return new
{
Settings = LoadSettings(),
AppConfig = LoadAppConfig(),
SystemInfo = new
{
UnityVersion = Application.unityVersion,
Platform = Application.platform.ToString(),
SystemTime = DateTime.Now
}
};
default:
return null;
}
}
private void EnsureDirectoryExists(string path)
{
if (!Directory.Exists(path))
{
Directory.CreateDirectory(path);
}
}
}