Files
bansonic_beta_main/Assets/scripts/settings/readDeviceInfo.cs
T

460 lines
14 KiB
C#

using UnityEngine;
using UnityEngine.UI;
using System.IO;
using System.Text.RegularExpressions;
using System;
using System.Collections.Generic;
using System.Text;
using System.Runtime.InteropServices;
public class readDeviceInfo : MonoBehaviour
{
private const string LabelColorHex = "#2457c6";
private const string ValueColorHex = "#6b8acd";
private const float ColumnPaddingPixels = 32f;
private const int MinimumGapSpaces = 2;
public Button reread_button;
public Button export_button;
public Text deviceInfo_text;
void Start()
{
if (reread_button != null)
{
reread_button.onClick.AddListener(read_deviceInfo);
}
if (export_button != null)
{
export_button.onClick.AddListener(ExportToFile);
}
if (deviceInfo_text != null)
{
ConfigureDeviceInfoText();
}
read_deviceInfo();
}
void OnDestroy()
{
if (reread_button != null)
reread_button.onClick.RemoveListener(read_deviceInfo);
if (export_button != null)
export_button.onClick.RemoveListener(ExportToFile);
}
void Update()
{
}
private void read_deviceInfo()
{
ConfigureDeviceInfoText();
var entries = new System.Collections.Generic.List<KeyValuePair<string, string>>();
void AddEntry(string title, object value)
{
string str;
if (value == null) str = "";
else if (value is bool b) str = b ? "是" : "否";
else str = value.ToString();
entries.Add(new KeyValuePair<string, string>(title ?? string.Empty, str ?? string.Empty));
}
AddEntry("平台", Application.platform.ToString());
AddEntry("数据目录", Application.dataPath);
AddEntry("persistent 数据路径", Application.persistentDataPath);
AddEntry("操作系统", SystemInfo.operatingSystem);
AddEntry("设备名称", SystemInfo.deviceName);
AddEntry("设备型号", SystemInfo.deviceModel);
AddEntry("设备唯一ID", SystemInfo.deviceUniqueIdentifier);
AddEntry("CPU", SystemInfo.processorType);
AddEntry("CPU核心数", SystemInfo.processorCount);
AddEntry("系统内存 (MB)", SystemInfo.systemMemorySize);
AddEntry("图形设备名称", SystemInfo.graphicsDeviceName);
AddEntry("图形设备供应商", SystemInfo.graphicsDeviceVendor);
AddEntry("DirectX", SystemInfo.graphicsDeviceType.ToString());
AddEntry("显存 (MB)", SystemInfo.graphicsMemorySize);
AddEntry("屏幕分辨率", $"{Screen.currentResolution.width} x {Screen.currentResolution.height} @ {Screen.currentResolution.refreshRateRatio.value:0.##}Hz");
AddEntry("屏幕DPI", Screen.dpi);
AddEntry("显示模式", Screen.fullScreenMode.ToString());
try
{
AddEntry("Battery Level", $"{SystemInfo.batteryLevel * 100:F0}%");
}
catch
{
AddEntry("Battery Status", "Not Supported");
}
AddEntry("主程序版本", "v1.1h02e");
AddEntry("内置小游戏版本", "v1.301");
AddEntry("游戏代码版本", "code::testingVersion1062");
AddEntry("登录渠道", "Steam Client");
AddEntry(".NET Framework", "8.0 +");
AddEntry("Max Texture Size", SystemInfo.maxTextureSize);
AddEntry("启用后台运行", Application.runInBackground);
AddEntry("启用多线程渲染", SystemInfo.graphicsMultiThreaded);
string output = BuildTwoColumnOutput(entries);
if (deviceInfo_text != null)
{
deviceInfo_text.text = output;
}
}
void ExportToFile()
{
if (deviceInfo_text == null)
{
return;
}
string path = ShowSaveFileDialog();
if (string.IsNullOrEmpty(path))
{
return;
}
try
{
string raw = deviceInfo_text.text;
string cleaned = Regex.Replace(raw, "<.*?>", string.Empty);
File.WriteAllText(path, cleaned);
}
catch (System.Exception)
{
}
}
private string BuildTwoColumnOutput(System.Collections.Generic.IReadOnlyList<KeyValuePair<string, string>> entries)
{
if (entries == null || entries.Count == 0)
{
return string.Empty;
}
float maxLabelWidth = 0f;
for (int i = 0; i < entries.Count; i++)
{
maxLabelWidth = Mathf.Max(maxLabelWidth, MeasurePlainTextWidth(entries[i].Key));
}
float availableWidth = GetAvailableTextWidth();
float targetLabelWidth = maxLabelWidth + ColumnPaddingPixels;
if (availableWidth > 0f)
{
targetLabelWidth = Mathf.Min(targetLabelWidth, availableWidth * 0.38f);
}
float spaceWidth = Mathf.Max(1f, MeasurePlainTextWidth(" "));
int continuationIndentSpaces = Mathf.Max(MinimumGapSpaces, Mathf.CeilToInt(targetLabelWidth / spaceWidth) + MinimumGapSpaces);
string continuationIndent = new string(' ', continuationIndentSpaces);
StringBuilder sb = new StringBuilder();
for (int i = 0; i < entries.Count; i++)
{
string label = entries[i].Key ?? string.Empty;
string value = entries[i].Value ?? string.Empty;
int gapSpaces = Mathf.Max(
MinimumGapSpaces,
Mathf.CeilToInt((targetLabelWidth - MeasurePlainTextWidth(label)) / spaceWidth) + MinimumGapSpaces);
string padding = new string(' ', gapSpaces);
float firstLineValueWidth = availableWidth > 0f
? Mathf.Max(32f, availableWidth - MeasurePlainTextWidth(label) - MeasurePlainTextWidth(padding))
: 0f;
float continuationValueWidth = availableWidth > 0f
? Mathf.Max(32f, availableWidth - MeasurePlainTextWidth(continuationIndent))
: 0f;
List<string> wrappedLines = WrapValueLines(value, firstLineValueWidth, continuationValueWidth);
sb.Append("<color=").Append(LabelColorHex).Append("><b>")
.Append(EscapeRichText(label))
.Append("</b></color>")
.Append(padding)
.Append("<color=").Append(ValueColorHex).Append(">")
.Append(EscapeRichText(wrappedLines[0]))
.Append("</color>");
for (int lineIndex = 1; lineIndex < wrappedLines.Count; lineIndex++)
{
sb.AppendLine();
sb.Append(continuationIndent)
.Append("<color=").Append(ValueColorHex).Append(">")
.Append(EscapeRichText(wrappedLines[lineIndex]))
.Append("</color>");
}
if (i < entries.Count - 1)
{
sb.AppendLine();
}
}
return sb.ToString();
}
private void ConfigureDeviceInfoText()
{
if (deviceInfo_text == null)
{
return;
}
deviceInfo_text.supportRichText = true;
deviceInfo_text.alignment = TextAnchor.UpperLeft;
deviceInfo_text.horizontalOverflow = HorizontalWrapMode.Wrap;
deviceInfo_text.verticalOverflow = VerticalWrapMode.Overflow;
deviceInfo_text.resizeTextForBestFit = false;
}
private float GetAvailableTextWidth()
{
if (deviceInfo_text == null)
{
return 0f;
}
RectTransform rectTransform = deviceInfo_text.rectTransform;
if (rectTransform == null)
{
return 0f;
}
float width = rectTransform.rect.width;
return width > 0f ? width : 0f;
}
private float MeasurePlainTextWidth(string text)
{
if (deviceInfo_text == null || string.IsNullOrEmpty(text))
{
return 0f;
}
TextGenerationSettings settings = deviceInfo_text.GetGenerationSettings(Vector2.zero);
settings.richText = false;
settings.generateOutOfBounds = true;
TextGenerator generator = new TextGenerator();
return generator.GetPreferredWidth(text, settings) / deviceInfo_text.pixelsPerUnit;
}
private List<string> WrapValueLines(string value, float firstLineWidth, float continuationLineWidth)
{
string normalized = NormalizeLineBreaks(value);
if (string.IsNullOrEmpty(normalized))
{
return new List<string> { string.Empty };
}
string[] rawLines = normalized.Split('\n');
List<string> wrapped = new List<string>();
for (int i = 0; i < rawLines.Length; i++)
{
string rawLine = rawLines[i];
List<string> lineParts = WrapSingleLine(rawLine, wrapped.Count == 0 ? firstLineWidth : continuationLineWidth);
if (lineParts.Count == 0)
{
lineParts.Add(string.Empty);
}
wrapped.Add(lineParts[0]);
for (int j = 1; j < lineParts.Count; j++)
{
wrapped.Add(lineParts[j]);
}
}
return wrapped.Count > 0 ? wrapped : new List<string> { string.Empty };
}
private List<string> WrapSingleLine(string text, float maxWidth)
{
List<string> lines = new List<string>();
if (string.IsNullOrEmpty(text) || maxWidth <= 0f)
{
lines.Add(text ?? string.Empty);
return lines;
}
string remaining = text;
while (!string.IsNullOrEmpty(remaining))
{
if (MeasurePlainTextWidth(remaining) <= maxWidth)
{
lines.Add(remaining);
break;
}
int splitIndex = FindSplitIndex(remaining, maxWidth);
if (splitIndex <= 0 || splitIndex >= remaining.Length)
{
lines.Add(remaining);
break;
}
string current = remaining.Substring(0, splitIndex).TrimEnd();
if (current.Length == 0)
{
current = remaining.Substring(0, Mathf.Min(1, remaining.Length));
splitIndex = current.Length;
}
lines.Add(current);
remaining = remaining.Substring(splitIndex).TrimStart();
}
return lines;
}
private int FindSplitIndex(string text, float maxWidth)
{
int lastBreakableIndex = -1;
int fallbackIndex = -1;
for (int i = 1; i <= text.Length; i++)
{
string candidate = text.Substring(0, i);
if (MeasurePlainTextWidth(candidate) <= maxWidth)
{
fallbackIndex = i;
if (IsBreakableCharacter(text[i - 1]))
{
lastBreakableIndex = i;
}
continue;
}
break;
}
if (lastBreakableIndex > 0)
{
return lastBreakableIndex;
}
return fallbackIndex;
}
private static bool IsBreakableCharacter(char c)
{
return char.IsWhiteSpace(c) || c == '/' || c == '\\' || c == '_' || c == '-' || c == '.' || c == ':' || c == ')' || c == ']';
}
private static string NormalizeLineBreaks(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}
return input.Replace("\r\n", "\n").Replace('\r', '\n');
}
private static string EscapeRichText(string input)
{
if (string.IsNullOrEmpty(input))
{
return string.Empty;
}
return input.Replace("&", "&amp;")
.Replace("<", "&lt;")
.Replace(">", "&gt;");
}
string ShowSaveFileDialog()
{
#if UNITY_EDITOR
string desktop = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
string path = UnityEditor.EditorUtility.SaveFilePanel("保存设备信息", desktop, "device_info", "txt");
return string.IsNullOrEmpty(path) ? null : path;
#elif UNITY_STANDALONE_WIN
try
{
// Use native Windows SaveFile dialog via comdlg32 GetSaveFileName
OpenFileName ofn = new OpenFileName();
ofn.structSize = Marshal.SizeOf(ofn);
ofn.filter = "Text files (*.txt)\0*.txt\0All files (*.*)\0*.*\0";
ofn.file = new string('\0', 260);
ofn.maxFile = ofn.file.Length;
ofn.fileTitle = new string('\0', 260);
ofn.maxFileTitle = ofn.fileTitle.Length;
ofn.initialDir = Environment.GetFolderPath(Environment.SpecialFolder.Desktop);
ofn.title = "保存设备信息";
ofn.defExt = "txt";
ofn.flags = OpenFileNameFlags.OFN_OVERWRITEPROMPT;
if (GetSaveFileName(ofn))
{
// Trim any trailing nulls
return ofn.file.TrimEnd('\0');
}
}
catch (Exception)
{
}
return null;
#else
string defaultPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.Desktop), "device_info.txt");
return defaultPath;
#endif
}
#if UNITY_STANDALONE_WIN
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Auto)]
private class OpenFileName
{
public int structSize = 0;
public IntPtr dlgOwner = IntPtr.Zero;
public IntPtr instance = IntPtr.Zero;
public string filter = null;
public string customFilter = null;
public int maxCustFilter = 0;
public int filterIndex = 0;
public string file = null;
public int maxFile = 0;
public string fileTitle = null;
public int maxFileTitle = 0;
public string initialDir = null;
public string title = null;
public int flags = 0;
public short fileOffset = 0;
public short fileExtension = 0;
public string defExt = null;
public IntPtr custData = IntPtr.Zero;
public IntPtr hook = IntPtr.Zero;
public string templateName = null;
public IntPtr reservedPtr = IntPtr.Zero;
public int reservedInt = 0;
public int flagsEx = 0;
}
private static class OpenFileNameFlags
{
public const int OFN_OVERWRITEPROMPT = 0x00000002;
}
[DllImport("comdlg32.dll", CharSet = CharSet.Auto, SetLastError = true)]
private static extern bool GetSaveFileName([In, Out] OpenFileName ofn);
#endif
}