TH1/Unity/Assets/Scripts/TH1_Logic/Editor/SteamEditorWindow.cs

694 lines
31 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

/*
* @Author: 白哉
* @Description: 回放编辑器
* @Date: 2025年04月22日 星期二 15:04:14
* @Modify:
*/
using System;
using System.Text;
using Logic.CrashSight;
using Logic.Multilingual;
using Steamworks;
using TH1_Logic.Core;
using TH1_Logic.Net;
using TH1_Logic.Oss;
using TH1_Logic.Steam;
using UnityEditor;
using UnityEngine;
namespace Logic.Editor
{
public class SteamEditorWindow : EditorWindow
{
// 滑条
private Vector2 _barPosition;
// 背景
private GUIStyle _redBoxStyle;
private GUIStyle _whiteBoxStyle;
[MenuItem("Tools/Steam 编辑器")]
private static void ShowWindow()
{
var window = CreateWindow<SteamEditorWindow>();
window.titleContent = new GUIContent("Steam 编辑器");
window.Show();
}
private void OnGUI()
{
if (_redBoxStyle == null)
{
_redBoxStyle = InspectorUtils.GetHelpBoxStyle();
InspectorUtils.AddBorder(_redBoxStyle, new Color(0.5f, 0.4f, 0.4f, 0.6f));
}
if (_whiteBoxStyle == null)
{
_whiteBoxStyle = InspectorUtils.GetHelpBoxStyle();
InspectorUtils.AddBorder(_whiteBoxStyle, new Color(1f, 1f, 1f, 0.2f));
}
var lobby = LobbyManager.Instance.Lobby as SteamLobbyManager;
if (lobby == null) return;
GUI.skin.button.wordWrap = true;
_barPosition = EditorGUILayout.BeginScrollView(_barPosition);
EditorGUILayout.BeginVertical(_whiteBoxStyle);
InspectorUtils.InspectorTextWidthRich("Steam 测试状态");
InspectorUtils.InspectorTextWidthRich($"Steam初始化: {(lobby.IsSteamInitialized ? "" : "")}");
InspectorUtils.InspectorTextWidthRich($"用户登录: {(lobby.IsloggedIn ? "" : "")}");
InspectorUtils.InspectorTextWidthRich($"Lobby 初始化: {(lobby.IsLobbyInitialized ? "" : "")}");
InspectorUtils.InspectorTextWidthRich($"P2P 初始化: {(SimpleP2P.Instance.IsInitialized ? "" : "")}");
InspectorUtils.InspectorTextWidthRich($"是否全部初始化完毕: {(lobby.IsInitialized() ? "" : "")}");
InspectorUtils.InspectorTextWidthRich($"用户: {lobby.SelfName}");
InspectorUtils.InspectorTextWidthRich($"ID: {lobby.SelfID}");
InspectorUtils.InspectorTextWidthRich("房间状态");
InspectorUtils.InspectorTextWidthRich($"当前状态: {lobby.GetCurState()}");
InspectorUtils.InspectorTextWidthRich($"在房间中: {(lobby.IsInLobby() ? "" : "")}");
InspectorUtils.InspectorTextWidthRich($"是房主: {(lobby.IsLobbyOwner() ? "" : "")}");
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
if (lobby.IsInitialized() && lobby.IsInLobby())
{
EditorGUILayout.BeginVertical(_whiteBoxStyle);
InspectorUtils.InspectorTextWidthRich($"房间ID: {lobby.GetShareableLobbyId()}");
InspectorUtils.InspectorTextWidthRich($"成员数: {lobby.GetMemberCount()}/{lobby.GetMemberLimit()}");
InspectorUtils.InspectorTextWidthRich($"P2P连接数: {SimpleP2P.Instance.GetConnectionCount()}");
if (lobby.IsLobbyOwner())
{
foreach (var kv in lobby.GetAllMemberInfo())
{
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich($"{kv.Value.Name}");
if (InspectorUtils.InspectorButtonWithTextWidth("踢出"))
{
lobby.KickMember(kv.Key);
}
EditorGUILayout.EndHorizontal();
}
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
if (lobby.IsInitialized())
{
EditorGUILayout.BeginVertical(_whiteBoxStyle);
InspectorUtils.InspectorTextWidthRich($"测试按钮");
EditorGUILayout.BeginHorizontal();
// 房间操作按钮
if (!lobby.IsInLobby())
{
if (InspectorUtils.InspectorButtonWithTextWidth("创建房间"))
{
lobby.CreateLobby();
}
}
else
{
if (InspectorUtils.InspectorButtonWithTextWidth("离开房间")) lobby.LeaveLobby();
if (InspectorUtils.InspectorButtonWithTextWidth("测试")) GameNetSender.Instance.BroadcastString("testtesttest");
if (lobby.IsLobbyOwner())
{
if (InspectorUtils.InspectorButtonWithTextWidth("设置房间公开")) lobby.SetLobbyPublic();
if (InspectorUtils.InspectorButtonWithTextWidth("设置房间私密")) lobby.SetLobbyFriendsOnly();
}
}
EditorGUILayout.EndHorizontal();
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
if (lobby.IsInLobby())
{
// 好友操作
EditorGUILayout.BeginVertical(_whiteBoxStyle);
InspectorUtils.InspectorTextWidthRich($"好友列表");
var friends = lobby.GetOnlineFriendsDict();
foreach (var kv in friends)
{
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich($"{kv.Value.Name}");
if (InspectorUtils.InspectorButtonWithTextWidth("邀请"))
{
lobby.InviteFriend(kv.Key);
}
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
EditorGUILayout.BeginVertical(_whiteBoxStyle);
InspectorUtils.InspectorTextWidthRich($"测试改阵营");
var selfMemberId = LobbyManager.Instance.Lobby.GetSelfMemberId();
var civ = Main.Instance.MapConfig.GetMemberCiv(selfMemberId);
if (civ != null)
{
EditorGUILayout.BeginHorizontal();
if (InspectorUtils.InspectorButtonWithTextWidth("改1")) civ.CivId = 1;
if (InspectorUtils.InspectorButtonWithTextWidth("改2")) civ.CivId = 2;
if (InspectorUtils.InspectorButtonWithTextWidth("改3")) civ.CivId = 3;
if (InspectorUtils.InspectorButtonWithTextWidth("改4")) civ.CivId = 4;
EditorGUILayout.EndHorizontal();
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
EditorGUILayout.BeginVertical(_whiteBoxStyle);
EditorGUILayout.BeginHorizontal();
InspectorUtils.InspectorTextWidthRich($"服务器上的房间信息");
if (InspectorUtils.InspectorButtonWithTextWidth("搜索")) lobby.SearchPublicLobbies();
EditorGUILayout.EndHorizontal();
foreach (var lobbyInfo in lobby.LobbyListInfos)
{
EditorGUILayout.BeginVertical(_redBoxStyle);
InspectorUtils.InspectorTextWidthRich($"LobbyId : {lobbyInfo.LobbyId}");
InspectorUtils.InspectorTextWidthRich($"OwnerId : {lobbyInfo.OwnerId}");
InspectorUtils.InspectorTextWidthRich($"OwnerName : {lobbyInfo.OwnerName}");
InspectorUtils.InspectorTextWidthRich($"RoomName : {lobbyInfo.RoomName}");
InspectorUtils.InspectorTextWidthRich($"Version : {lobbyInfo.Version}");
InspectorUtils.InspectorTextWidthRich($"CurrentPlayers : {lobbyInfo.CurrentPlayers}");
InspectorUtils.InspectorTextWidthRich($"MaxPlayers : {lobbyInfo.MaxPlayers}");
InspectorUtils.InspectorTextWidthRich($"GameState : {lobbyInfo.GameState}");
if (InspectorUtils.InspectorButtonWithTextWidth("加入此房间"))
LobbyManager.Instance.Lobby.JoinLobbyById(lobbyInfo.LobbyId);
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
}
EditorGUILayout.EndVertical();
EditorGUILayout.Space();
EditorGUILayout.EndScrollView();
}
}
public class SteamUploadFlowTestEditorWindow : EditorWindow
{
private const string FunctionUrl = "https://get-sts-token-qltjykaafr.cn-shanghai.fcapp.run";
private Vector2 _scrollPosition;
private GUIStyle _whiteBoxStyle;
private GUIStyle _sectionHeaderStyle;
private StsTokenService _stsService;
private OssUploadService _uploadService;
private bool _isRunning;
private string _version = "";
private string _normalPayload = "{\"test\":\"ossdata\"}";
private string _bugDescription = "测试 Bug 汇报";
private string _multilingualId = "1";
private string _multilingualSelectedText = "测试多语言选中文本";
private string _multilingualDescription = "测试多语言问题自述";
private MultilingualType _multilingualLanguage = MultilingualType.EN;
private string _questionnaireId = "upload-flow-test";
private string _questionnaireSingleChoiceId = "test-choice-a";
private string _questionnaireOpenText = "测试问卷开放题回答";
private string _status = "就绪";
private string _lastObjectKey = "";
[MenuItem("Tools/Steam 上传流程测试器")]
private static void ShowWindow()
{
var window = GetWindow<SteamUploadFlowTestEditorWindow>();
window.titleContent = new GUIContent("Steam 上传流程测试器");
window.minSize = new Vector2(560, 520);
window.Show();
}
private void OnEnable()
{
_stsService = new StsTokenService(FunctionUrl);
_uploadService = new OssUploadService();
if (string.IsNullOrEmpty(_version))
_version = PlayerBugReportService.GetCurrentVersion();
_multilingualLanguage = PlayerMultilingualReportService.GetCurrentLanguage();
}
private void OnGUI()
{
InitStyles();
_scrollPosition = EditorGUILayout.BeginScrollView(_scrollPosition);
DrawSteamState();
EditorGUILayout.Space(8);
DrawCommonInputs();
EditorGUILayout.Space(8);
DrawTestButtons();
EditorGUILayout.Space(8);
DrawStatus();
EditorGUILayout.EndScrollView();
}
private void InitStyles()
{
if (_whiteBoxStyle == null)
{
_whiteBoxStyle = InspectorUtils.GetHelpBoxStyle();
InspectorUtils.AddBorder(_whiteBoxStyle, new Color(1f, 1f, 1f, 0.2f));
}
if (_sectionHeaderStyle == null)
{
_sectionHeaderStyle = new GUIStyle(EditorStyles.boldLabel)
{
fontSize = 13,
padding = new RectOffset(2, 0, 4, 4)
};
}
}
private void DrawSteamState()
{
EditorGUILayout.LabelField("Steam 状态", _sectionHeaderStyle);
EditorGUILayout.BeginVertical(_whiteBoxStyle);
var lobby = LobbyManager.Instance.Lobby as SteamLobbyManager;
EditorGUILayout.LabelField("Play Mode", Application.isPlaying ? "运行中" : "未运行");
EditorGUILayout.LabelField("Steam AppID", GetSteamAppIdForDisplay());
if (lobby != null)
{
EditorGUILayout.LabelField("Steam 初始化", lobby.IsSteamInitialized ? "是" : "否");
EditorGUILayout.LabelField("用户登录", lobby.IsloggedIn ? "是" : "否");
EditorGUILayout.LabelField("Lobby 初始化", lobby.IsLobbyInitialized ? "是" : "否");
EditorGUILayout.LabelField("用户", lobby.SelfName);
EditorGUILayout.LabelField("SteamID", lobby.SelfID.ToString());
}
else
{
EditorGUILayout.HelpBox("未找到 SteamLobbyManager。请进入 Play Mode 后再测试。", MessageType.Warning);
}
EditorGUILayout.EndVertical();
}
private void DrawCommonInputs()
{
EditorGUILayout.LabelField("测试参数", _sectionHeaderStyle);
EditorGUILayout.BeginVertical(_whiteBoxStyle);
_version = EditorGUILayout.TextField("版本号", _version);
EditorGUILayout.LabelField("普通 OSS 测试内容");
_normalPayload = EditorGUILayout.TextArea(_normalPayload, GUILayout.MinHeight(45));
EditorGUILayout.LabelField("Bug 汇报自述");
_bugDescription = EditorGUILayout.TextArea(_bugDescription, GUILayout.MinHeight(55));
_multilingualLanguage = (MultilingualType)EditorGUILayout.EnumPopup("多语言语种", _multilingualLanguage);
_multilingualId = EditorGUILayout.TextField("多语言 ID", _multilingualId);
EditorGUILayout.LabelField("多语言选中文本");
_multilingualSelectedText = EditorGUILayout.TextArea(_multilingualSelectedText, GUILayout.MinHeight(55));
EditorGUILayout.LabelField("多语言玩家自述");
_multilingualDescription = EditorGUILayout.TextArea(_multilingualDescription, GUILayout.MinHeight(55));
_questionnaireId = EditorGUILayout.TextField("问卷 ID", _questionnaireId);
_questionnaireSingleChoiceId = EditorGUILayout.TextField("问卷单选选项 ID", _questionnaireSingleChoiceId);
EditorGUILayout.LabelField("问卷开放题回答");
_questionnaireOpenText = EditorGUILayout.TextArea(_questionnaireOpenText, GUILayout.MinHeight(45));
EditorGUILayout.EndVertical();
}
private void DrawTestButtons()
{
EditorGUILayout.LabelField("上传流程", _sectionHeaderStyle);
EditorGUILayout.BeginVertical(_whiteBoxStyle);
using (new EditorGUI.DisabledScope(_isRunning || !Application.isPlaying))
{
if (GUILayout.Button("1. Steam 身份预校验 action=steamauth", GUILayout.Height(28)))
TestSteamWarmup();
if (GUILayout.Button("2. 普通 OSS 上传 type=ossdata", GUILayout.Height(28)))
TestOssDataUpload();
if (GUILayout.Button("3. Bug 汇报上传 type=bugreport", GUILayout.Height(28)))
TestBugReportUpload();
if (GUILayout.Button("4. 多语言汇报上传 type=multilingualreport", GUILayout.Height(28)))
TestMultilingualReportUpload();
if (GUILayout.Button("5. 问卷上传 type=questionnaire", GUILayout.Height(28)))
TestQuestionnaireUpload();
if (GUILayout.Button("顺序测试 1-5", GUILayout.Height(32)))
TestAll();
}
if (!Application.isPlaying)
EditorGUILayout.HelpBox("这个测试器需要 Play Mode 中的 Steam 登录态和 AuthTicket。", MessageType.Info);
EditorGUILayout.EndVertical();
}
private void DrawStatus()
{
EditorGUILayout.LabelField("结果", _sectionHeaderStyle);
EditorGUILayout.BeginVertical(_whiteBoxStyle);
EditorGUILayout.HelpBox(_status, MessageType.Info);
if (!string.IsNullOrEmpty(_lastObjectKey))
EditorGUILayout.SelectableLabel(_lastObjectKey, EditorStyles.textField, GUILayout.Height(22));
EditorGUILayout.EndVertical();
}
private async void TestSteamWarmup()
{
await RunTest("Steam 身份预校验", async () =>
{
var steamId = GetSteamId();
var authTicket = GetAuthTicket();
var response = await _stsService.WarmupSteamAuthAsync(steamId, authTicket, _version);
_lastObjectKey = "";
return $"Steam 预校验成功: cached={response.cached}, expiresIn={response.expiresIn}s, steamId={response.steamId}";
});
}
private async void TestOssDataUpload()
{
await RunTest("普通 OSS 上传", async () =>
{
var steamId = GetSteamId();
var authTicket = GetAuthTicket();
var credentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "ossdata", _version);
var bytes = Encoding.UTF8.GetBytes(string.IsNullOrEmpty(_normalPayload)
? "{\"test\":\"ossdata\"}"
: _normalPayload);
var success = await _uploadService.UploadFileAsync(credentials, bytes, "application/json");
_lastObjectKey = credentials.objectKey;
return success
? $"普通 OSS 上传成功: {credentials.objectKey}"
: $"普通 OSS 上传失败: {credentials.objectKey}";
});
}
private async void TestBugReportUpload()
{
await RunTest("Bug 汇报上传", async () =>
{
var steamId = GetSteamId();
var package = PlayerBugReportService.BuildPackage(steamId, _bugDescription, _version,
false, false, false);
var result = await OssManager.Instance.UploadPlayerBugReportAsync(steamId, package.Data,
package.Manifest.version);
_lastObjectKey = result.objectKey ?? "";
return result.success
? $"Bug 汇报上传成功: {result.objectKey}"
: $"Bug 汇报上传失败: {result.objectKey}";
});
}
private async void TestMultilingualReportUpload()
{
await RunTest("多语言汇报上传", async () =>
{
if (!uint.TryParse(_multilingualId.Trim(), out var id) || id == 0)
throw new Exception("多语言 ID 必须是大于 0 的整数");
if (string.IsNullOrWhiteSpace(_multilingualSelectedText))
throw new Exception("多语言选中文本不能为空");
if (string.IsNullOrWhiteSpace(_multilingualDescription))
throw new Exception("多语言玩家自述不能为空");
var steamId = GetSteamId();
var package = PlayerMultilingualReportService.BuildPackage(steamId, id, _multilingualSelectedText,
_multilingualDescription, _version, _multilingualLanguage);
var result = await OssManager.Instance.UploadPlayerMultilingualReportAsync(steamId, package.Data,
package.Manifest.version);
_lastObjectKey = result.objectKey ?? "";
return result.success
? $"多语言汇报上传成功: {result.objectKey}"
: $"多语言汇报上传失败: {result.objectKey}";
});
}
private async void TestQuestionnaireUpload()
{
await RunTest("问卷上传", async () =>
{
var steamId = GetSteamId();
var authTicket = GetAuthTicket();
var questionnaireBytes = BuildQuestionnairePayloadBytes(steamId);
var credentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "questionnaire",
_version);
if (!IsQuestionnaireObjectKey(credentials?.objectKey))
throw new Exception($"服务端返回了非问卷 objectKey: {credentials?.objectKey}");
var success = await _uploadService.UploadFileAsync(credentials, questionnaireBytes,
"application/json", MaxQuestionnaireUploadBytes);
_lastObjectKey = credentials.objectKey ?? "";
return success
? $"问卷上传成功: {credentials.objectKey}"
: $"问卷上传失败: {credentials.objectKey}";
});
}
private async void TestAll()
{
await RunTest("顺序测试 1-5", async () =>
{
var steamId = GetSteamId();
var authTicket = GetAuthTicket();
var warmup = await _stsService.WarmupSteamAuthAsync(steamId, authTicket, _version);
var credentials = await _stsService.RequestStsTokenAsync(steamId, authTicket, "ossdata", _version);
var normalBytes = Encoding.UTF8.GetBytes(string.IsNullOrEmpty(_normalPayload)
? "{\"test\":\"ossdata\"}"
: _normalPayload);
var normalOk = await _uploadService.UploadFileAsync(credentials, normalBytes, "application/json");
var bugPackage = PlayerBugReportService.BuildPackage(steamId, _bugDescription, _version,
false, false, false);
var bugOk = await OssManager.Instance.UploadPlayerBugReportAsync(steamId, bugPackage.Data,
bugPackage.Manifest.version);
if (!uint.TryParse(_multilingualId.Trim(), out var id) || id == 0)
throw new Exception("多语言 ID 必须是大于 0 的整数");
var multilingualPackage = PlayerMultilingualReportService.BuildPackage(steamId, id,
_multilingualSelectedText, _multilingualDescription, _version, _multilingualLanguage);
var multilingualOk = await OssManager.Instance.UploadPlayerMultilingualReportAsync(steamId,
multilingualPackage.Data, multilingualPackage.Manifest.version);
var questionnaireBytes = BuildQuestionnairePayloadBytes(steamId);
var questionnaireCredentials = await _stsService.RequestStsTokenAsync(steamId, authTicket,
"questionnaire", _version);
if (!IsQuestionnaireObjectKey(questionnaireCredentials?.objectKey))
throw new Exception($"服务端返回了非问卷 objectKey: {questionnaireCredentials?.objectKey}");
var questionnaireOk = await _uploadService.UploadFileAsync(questionnaireCredentials,
questionnaireBytes, "application/json", MaxQuestionnaireUploadBytes);
_lastObjectKey = questionnaireCredentials.objectKey ?? "";
return $"顺序测试完成: steamauth cached={warmup.cached}; ossdata={(normalOk ? "" : "")} {credentials.objectKey}; bugreport={(bugOk.success ? "" : "")} {bugOk.objectKey}; multilingualreport={(multilingualOk.success ? "" : "")} {multilingualOk.objectKey}; questionnaire={(questionnaireOk ? "" : "")} {questionnaireCredentials.objectKey}";
});
}
private async System.Threading.Tasks.Task RunTest(string title,
Func<System.Threading.Tasks.Task<string>> action)
{
_isRunning = true;
_status = $"{title} 运行中...";
Repaint();
try
{
var result = await action();
_status = result;
Debug.Log($"[SteamUploadFlowTest] {result}");
}
catch (Exception ex)
{
_status = $"{title} 失败: {ex.Message}";
Debug.LogError($"[SteamUploadFlowTest] {title} failed: {ex}");
}
finally
{
_isRunning = false;
Repaint();
}
}
private static string GetSteamId()
{
try
{
if (SteamUser.BLoggedOn())
{
var id = SteamUser.GetSteamID().m_SteamID;
if (id != 0) return id.ToString();
}
}
catch
{
// ignored
}
var lobbyId = LobbyManager.Instance.Lobby.GetSelfMemberId();
if (lobbyId != 0) return lobbyId.ToString();
throw new Exception("未获取到 SteamID请确认 Steam 已初始化并登录");
}
private static string GetAuthTicket()
{
var ticket = new byte[1024];
var identity = new SteamNetworkingIdentity();
SteamUser.GetAuthSessionTicket(ticket, 1024, out var ticketSize, ref identity);
if (ticketSize == 0)
throw new Exception("Steam auth ticket is empty");
return BitConverter.ToString(ticket, 0, (int)ticketSize).Replace("-", "").ToLower();
}
private static string GetSteamAppIdForDisplay()
{
try
{
var appId = SteamUtils.GetAppID().m_AppId;
return appId == 0 ? "(未获取到)" : appId.ToString();
}
catch
{
return "(Steam 未初始化)";
}
}
private const int MaxQuestionnaireUploadBytes = 512 * 1024;
private static bool IsQuestionnaireObjectKey(string objectKey)
{
return !string.IsNullOrEmpty(objectKey)
&& objectKey.StartsWith("questionnaire/", StringComparison.Ordinal)
&& objectKey.EndsWith(".json", StringComparison.OrdinalIgnoreCase);
}
[Serializable]
private class QuestionnaireTestPayload
{
public string schema = "th1.questionnaire-answer.v1";
public string responseId;
public string questionnaireId;
public long submittedAtUnix;
public string submittedAtUtc;
public string createdAtUtc;
public string createdAtLocal;
public string timezone;
public string steamId;
public string version;
public string unityVersion;
public string platform;
public string crashSightDeviceId;
public string deviceModel;
public string deviceName;
public string operatingSystem;
public string processorType;
public int processorCount;
public int systemMemorySizeMb;
public string graphicsDeviceName;
public int graphicsMemorySizeMb;
public QuestionnaireTestAnswerSheet answerSheet;
}
[Serializable]
private class QuestionnaireTestAnswerSheet
{
public string QuestionnaireId;
public long SubmittedAtUnix;
public string SubmittedAtUtc;
public string LastUploadObjectKey = "";
public string LastUploadedAtUtc = "";
public string LastUploadError = "";
public QuestionnaireTestAnswer[] Answers;
}
[Serializable]
private class QuestionnaireTestAnswer
{
public string QuestionId;
public int QuestionType;
public string[] SelectedOptionIds;
public string OpenText;
}
private byte[] BuildQuestionnairePayloadBytes(string steamId)
{
var now = DateTimeOffset.UtcNow;
var questionnaireId = string.IsNullOrWhiteSpace(_questionnaireId)
? "upload-flow-test"
: _questionnaireId.Trim();
var selectedOptionId = string.IsNullOrWhiteSpace(_questionnaireSingleChoiceId)
? "test-choice-a"
: _questionnaireSingleChoiceId.Trim();
var openText = string.IsNullOrWhiteSpace(_questionnaireOpenText)
? "测试问卷开放题回答"
: _questionnaireOpenText.Trim();
var submittedAtUtc = now.UtcDateTime.ToString("O");
var answerSheet = new QuestionnaireTestAnswerSheet
{
QuestionnaireId = questionnaireId,
SubmittedAtUnix = now.ToUnixTimeSeconds(),
SubmittedAtUtc = submittedAtUtc,
Answers = new[]
{
new QuestionnaireTestAnswer
{
QuestionId = "upload-flow-single-choice",
QuestionType = 1,
SelectedOptionIds = new[] { selectedOptionId },
OpenText = ""
},
new QuestionnaireTestAnswer
{
QuestionId = "upload-flow-open",
QuestionType = 0,
SelectedOptionIds = Array.Empty<string>(),
OpenText = openText
}
}
};
var payload = new QuestionnaireTestPayload
{
responseId = Guid.NewGuid().ToString("N"),
questionnaireId = questionnaireId,
submittedAtUnix = answerSheet.SubmittedAtUnix,
submittedAtUtc = submittedAtUtc,
createdAtUtc = DateTime.UtcNow.ToString("O"),
createdAtLocal = DateTime.Now.ToString("O"),
timezone = GetLocalTimezone(),
steamId = steamId ?? "",
version = string.IsNullOrWhiteSpace(_version) ? PlayerBugReportService.GetCurrentVersion() : _version.Trim(),
unityVersion = Application.unityVersion,
platform = Application.platform.ToString(),
crashSightDeviceId = CrashSightManager.GetCrashSightDeviceId(),
deviceModel = SystemInfo.deviceModel,
deviceName = SystemInfo.deviceName,
operatingSystem = SystemInfo.operatingSystem,
processorType = SystemInfo.processorType,
processorCount = SystemInfo.processorCount,
systemMemorySizeMb = SystemInfo.systemMemorySize,
graphicsDeviceName = SystemInfo.graphicsDeviceName,
graphicsMemorySizeMb = SystemInfo.graphicsMemorySize,
answerSheet = answerSheet
};
var bytes = new UTF8Encoding(false).GetBytes(JsonUtility.ToJson(payload, true));
if (bytes.Length > MaxQuestionnaireUploadBytes)
throw new Exception($"问卷测试 payload 大小 {bytes.Length} 超过 {MaxQuestionnaireUploadBytes} 字节限制");
return bytes;
}
private static string GetLocalTimezone()
{
try
{
var offset = DateTimeOffset.Now.Offset;
var sign = offset < TimeSpan.Zero ? "-" : "+";
return $"{TimeZoneInfo.Local.Id} (UTC{sign}{offset.Duration():hh\\:mm})";
}
catch
{
return DateTimeOffset.Now.Offset.ToString();
}
}
}
}