Compare commits
3 Commits
cfc7189b15
...
5a5b58a37d
| Author | SHA1 | Date | |
|---|---|---|---|
| 5a5b58a37d | |||
| 6b6ce7473d | |||
| 140146f1e3 |
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: th1-base
|
||||
description: TH1 project baseline engineering guide for Unity client changes: assembly boundaries, HybridCLR hotfix rules, YooAsset/AssetBundle resource rules, MemoryPack/AOT serialization safety, build packaging flow, and routing to domain skills. Use before broad TH1 Unity code/resource/build changes, especially when touching Scripts, asmdefs, HybridCLR, hotfix DLLs, StreamingAssets, BundleResources, Resources.Load replacement, YooAsset, MemoryPack, generated config, build panels, or package verification.
|
||||
description: TH1 project baseline engineering guide for Unity client changes: assembly boundaries, HybridCLR hotfix rules, YooAsset/AssetBundle resource rules, BundleResources DataAssets -> Export packaging sync, MemoryPack/AOT serialization safety, unified PC/iOS build packaging flow, and routing to domain skills. Use before broad TH1 Unity code/resource/build changes, especially when touching Scripts, asmdefs, HybridCLR, hotfix DLLs, StreamingAssets, BundleResources, Resources.Load replacement, YooAsset, MemoryPack, generated config, build panels, or package verification.
|
||||
---
|
||||
|
||||
# TH1 Base Engineering
|
||||
@ -107,6 +107,7 @@ Rules:
|
||||
Resources are moving to AB-first loading:
|
||||
|
||||
- Use `Assets/BundleResources` as the packaged resource root.
|
||||
- TH1's default YooAsset collector should collect the whole `Assets/BundleResources` root and use `TH1AddressByBundleResourcesPath`, so an asset like `Assets/BundleResources/Export/VersionConfig.asset` is addressed as `Export/VersionConfig.asset`.
|
||||
- Prefer stable logical addresses. Do not make gameplay code depend on platform-specific bundle paths.
|
||||
- Replace `Resources.Load` through `TH1Resource.ResourceLoader`/resource cache wrappers, not scattered direct YooAsset calls.
|
||||
- Editor may run simulate mode; PC/iOS packages should run actual built-in AB package logic.
|
||||
@ -120,18 +121,26 @@ Resources are moving to AB-first loading:
|
||||
|
||||
## Build And Packaging Flow
|
||||
|
||||
For migration-era PC IL2CPP smoke builds, use the project one-click flow where possible:
|
||||
For PC/iOS packages, prefer `Tools/TH1/一体化出包工具` / `TH1UnifiedBuildWindow` where possible.
|
||||
|
||||
Current one-click flow should be visible and stage-based:
|
||||
|
||||
1. Configure target platform/build settings.
|
||||
2. Configure HybridCLR.
|
||||
3. Run HybridCLR `GenerateAll`.
|
||||
4. Build hotfix DLL and copy hotfix/AOT metadata to `StreamingAssets`.
|
||||
5. Build YooAsset built-in `DefaultPackage`.
|
||||
6. Build Windows IL2CPP player.
|
||||
7. Launch player and scan the log for startup red errors.
|
||||
2. Apply selected `VersionConfig` to `Assets/BundleResources/DataAssets/VersionConfig.asset`, `PlayerSettings.bundleVersion`, scripting defines, package type, and OPS obfuscation target.
|
||||
3. Run multilingual export/import when packaging unless the user explicitly disables it. This copies/transforms `Assets/BundleResources/DataAssets/*` into `Assets/BundleResources/Export/*`, updates `Multilingual.asset`, and generates `MatchLevelData/ExportLevelData.bytes`.
|
||||
4. Configure HybridCLR.
|
||||
5. Configure YooAsset collector.
|
||||
6. Run HybridCLR `GenerateAll`.
|
||||
7. Build hotfix DLL and copy hotfix/AOT metadata to `StreamingAssets`.
|
||||
8. Build YooAsset built-in `DefaultPackage`.
|
||||
9. Check migration/build blockers.
|
||||
10. Build the PC or iOS player.
|
||||
|
||||
The window must show each phase and stop on the first phase failure. Do not rely only on a final Unity popup when the flow spans version config, multilingual export, HybridCLR, AB, and player build.
|
||||
|
||||
Manual Unity packaging gotchas:
|
||||
|
||||
- If runtime version/localization/config looks stale, compare `Assets/BundleResources/DataAssets/*` against `Assets/BundleResources/Export/*`; the game usually reads `Export/...`, not raw `DataAssets/...`.
|
||||
- After scene list changes, use full `Build`/`Clean Build`; do not use `Build Scripts Only`.
|
||||
- If the one-click build panel reports success while AOT metadata is missing, trust the artifact check, not the old status text. Required AOT metadata must exist under `Assets/StreamingAssets/HybridCLR/AOTAssemblies`.
|
||||
- If you only need a runnable PC package, keep `Create Visual Studio Solution` off unless explicitly debugging the generated solution.
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: th1-ios-migration
|
||||
description: "TH1 project-specific iOS migration guide for same-mainline dual-platform support: HybridCLR hot update foundation, iOS/IL2CPP compile isolation, Steamworks/Steam SDK platform abstraction without Steam regressions, touch input adaptation, YooAsset AssetBundle/resource migration, iOS build settings, and verification that existing online Steam builds and gameplay behavior remain unaffected. Use whenever Codex works on TH1 iOS packaging, mobile porting, HybridCLR, YooAsset AB/resource loading, removing direct Steamworks references for iOS, platform services, touch controls, or build pipeline changes that must preserve the current Steam version."
|
||||
description: "TH1 project-specific iOS migration guide for same-mainline dual-platform support: HybridCLR hot update foundation, iOS/IL2CPP compile isolation, Steamworks/Steam SDK platform abstraction without Steam regressions, touch input adaptation, YooAsset AssetBundle/resource migration, BundleResources DataAssets -> Export packaging sync, iOS build settings, unified PC/iOS build window flow, and verification that existing online Steam builds and gameplay behavior remain unaffected. Use whenever Codex works on TH1 iOS packaging, mobile porting, HybridCLR, YooAsset AB/resource loading, removing direct Steamworks references for iOS, platform services, touch controls, or build pipeline changes that must preserve the current Steam version."
|
||||
---
|
||||
|
||||
# TH1 iOS Migration
|
||||
@ -173,6 +173,14 @@ Goal: move toward AB/resource hot update without destabilizing the Steam build.
|
||||
|
||||
Use the existing YooAsset package and `AssetBundleCollectorSetting.asset` unless there is a clear reason not to.
|
||||
|
||||
Current TH1 built-in resource shape:
|
||||
|
||||
- Packaged resource root is `Assets/BundleResources`.
|
||||
- `TH1YooAssetBuildTools.ConfigureDefaultPackageCollector()` should collect the whole root for the default package.
|
||||
- `TH1AddressByBundleResourcesPath` strips `Assets/BundleResources/`, so `Assets/BundleResources/Export/Multilingual.asset` becomes address `Export/Multilingual.asset`.
|
||||
- `TH1Resource.ResourceLoader.Load<T>("Export/VersionConfig")` and similar calls normalize addresses and try extension candidates. Do not change runtime callers to platform-specific paths when the collector/address rule is the real issue.
|
||||
- Runtime config/localization/table data usually reads `Export/...`; raw `DataAssets/...` is the authoring source copied/transformed by the multilingual export/import flow.
|
||||
|
||||
Recommended sequence:
|
||||
|
||||
1. Finish a real `ResourceManager` wrapper around YooAsset package initialization.
|
||||
@ -185,7 +193,9 @@ Recommended sequence:
|
||||
Resource rules:
|
||||
|
||||
- Keep stable logical addresses. Do not make gameplay code depend on platform-specific paths.
|
||||
- Do not modify export-flow outputs such as `Unity/Assets/Resources/Export/*`, `Tools/Multilingual.xlsx`, or `Tools/MultilingualTxt.txt` unless the user asked for export/import changes.
|
||||
- Do not modify export-flow outputs such as `Unity/Assets/BundleResources/Export/*`, `Tools/Multilingual.xlsx`, or `Tools/MultilingualTxt.txt` unless the user asked for export/import changes.
|
||||
- In the current migration, export-flow outputs live under `Assets/BundleResources/Export/*`. If a package shows the wrong version, stale text, or stale table config, first check whether `DataAssets -> Export` was refreshed before AB build.
|
||||
- Before a release/debug package, run or explicitly skip with confirmation the multilingual export/import flow (`Tools/一键导出导回` or the checkbox in `TH1UnifiedBuildWindow`). It refreshes `Export/*`, `Multilingual.asset`, Excel/TXT intermediate files, and `MatchLevelData/ExportLevelData.bytes`.
|
||||
- Use iOS-specific texture/audio compression settings and bundle output. Do not reuse PC texture assumptions blindly.
|
||||
- Treat generated config/DataAsset loading as compatibility-sensitive; preserve existing table and localization behavior.
|
||||
- For Unity 2021+ / Unity 2022 with YooAsset 2.1.1, prefer SBP (`ScriptableBuildPipeline`) for built-in package builds. YooAsset's BBP path uses Unity's old `BuildPipeline.BuildAssetBundles` call and can trigger the internal assertion `m_InstanceIDToAssetBundleIndex.count(id) > 0`.
|
||||
@ -209,6 +219,20 @@ Maintain one main branch with separate build profiles:
|
||||
- iOS build: iOS, IL2CPP, mobile platform services, no Steamworks compile dependency, touch enabled, iOS bundles.
|
||||
- Hot update build: platform-specific HybridCLR DLL/AOT metadata and YooAsset manifests.
|
||||
|
||||
Prefer `Tools/TH1/一体化出包工具` for manual PC/iOS packaging. The one-click path should be staged and stop on first failure:
|
||||
|
||||
1. Apply version/platform/package defines and OPS obfuscation target.
|
||||
2. Optional but recommended multilingual export/import (`DataAssets -> Export`).
|
||||
3. Configure HybridCLR.
|
||||
4. Configure YooAsset collector.
|
||||
5. HybridCLR `GenerateAll`.
|
||||
6. Build hotfix DLL/AOT metadata.
|
||||
7. Build YooAsset built-in AB.
|
||||
8. Check build blockers.
|
||||
9. Build Player.
|
||||
|
||||
The confirmation dialog should show the selected version and whether the multilingual export/import step is enabled.
|
||||
|
||||
Release branches may exist for stabilization only:
|
||||
|
||||
- `release/steam-*` and `release/ios-*` may freeze and cherry-pick fixes.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
interface:
|
||||
display_name: "TH1 iOS Migration"
|
||||
short_description: "HybridCLR, iOS isolation, touch, YooAsset"
|
||||
default_prompt: "Use $th1-ios-migration when making TH1 iOS migration changes that must keep the Steam build and existing gameplay behavior intact."
|
||||
short_description: "HybridCLR、iOS隔离、YooAsset与统一出包"
|
||||
default_prompt: "Use $th1-ios-migration when making TH1 iOS migration or PC/iOS packaging changes that must keep the Steam build and existing gameplay behavior intact."
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
---
|
||||
name: th1-multilingual
|
||||
description: TH1 project-specific multilingual/localization guide for Unity editor export/import, Multilingual.asset, Multilingual.xlsx, MultilingualTxt.txt, special-term syntax, ordered embedded references, duplicate ID prevention, active text scanning, Excel round-tripping, and translation data debugging. Use whenever Codex works on TH1 多语言导表/导回, localization Excel issues, duplicated rows/IDs, special-term parsing, ordered marker bugs, MultilingualEditorWindow, MultilingualData, or any bug that may create new localization IDs unexpectedly.
|
||||
description: TH1 project-specific multilingual/localization guide for Unity editor export/import, BundleResources DataAssets -> Export runtime asset sync, Multilingual.asset, Multilingual.xlsx, MultilingualTxt.txt, special-term syntax, ordered embedded references, duplicate ID prevention, active text scanning, Excel round-tripping, and translation data debugging. Use whenever Codex works on TH1 多语言导表/导回, localization Excel issues, duplicated rows/IDs, special-term parsing, ordered marker bugs, MultilingualEditorWindow, MultilingualData, package/export stale version or text issues, or any bug that may create new localization IDs unexpectedly.
|
||||
---
|
||||
|
||||
# TH1 Multilingual
|
||||
@ -26,7 +26,9 @@ Translation length is part of the project quality bar. Keep target-language text
|
||||
- `Tools/ExportStringToExcel.py`
|
||||
- `Tools/Multilingual.xlsx`
|
||||
- `Tools/MultilingualTxt.txt`
|
||||
- `Unity/Assets/Resources/Export/Multilingual.asset`
|
||||
- `Unity/Assets/BundleResources/Export/Multilingual.asset`
|
||||
- `Unity/Assets/BundleResources/DataAssets/*`
|
||||
- `Unity/Assets/BundleResources/Export/*`
|
||||
|
||||
For the full data-flow contract, read `references/pipeline.md`.
|
||||
For duplicate IDs, bad markers, and validation commands, read `references/diagnostics.md`.
|
||||
@ -62,6 +64,14 @@ Asset internal form:
|
||||
7. Only allocate `_idIndex` when the canonical string is genuinely new.
|
||||
8. Write Excel-visible text through `GetMultilingualStrEditor()`, which expands internal IDs back to readable terms.
|
||||
|
||||
In the current BundleResources/YooAsset flow, export is also the authoring-to-runtime sync step:
|
||||
|
||||
- `Assets/BundleResources/DataAssets/*` is the authoring source for many ScriptableObject configs.
|
||||
- `AssetExportToExcelInternal()` instantiates each DataAsset, traverses/transforms multilingual strings, and writes the runtime copy to `Assets/BundleResources/Export/{name}.asset`.
|
||||
- Runtime table/config/localization code usually loads `Export/...` through `TH1Resource.ResourceLoader`, not raw `DataAssets/...`.
|
||||
- `ExportMatchLevelData()` writes `Assets/BundleResources/MatchLevelData/ExportLevelData.bytes`; runtime match config uses this outside editor play mode.
|
||||
- Before PC/iOS packaging, run `Tools/一键导出导回` or enable the `TH1UnifiedBuildWindow` checkbox for multilingual export/import before YooAsset AB build. If this is skipped, the built player can show a new title/bundle version while CrashSight/config/localization still report stale `Export` data.
|
||||
|
||||
## Import Workflow
|
||||
|
||||
1. Convert Excel to `MultilingualTxt.txt` through `Tools/PrintExcelString.py`.
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
interface:
|
||||
display_name: "TH1 Multilingual"
|
||||
short_description: "TH1 Unity 多语言导表导回特殊词和重复ID排查"
|
||||
default_prompt: "Use TH1 multilingual rules to inspect, fix, or explain localization export/import issues."
|
||||
short_description: "TH1 多语言导表导回、DataAssets到Export同步、重复ID排查"
|
||||
default_prompt: "Use TH1 multilingual rules to inspect, fix, or explain localization export/import and DataAssets-to-Export sync issues."
|
||||
|
||||
@ -38,7 +38,7 @@ import sys, io
|
||||
from pathlib import Path
|
||||
sys.stdout = io.TextIOWrapper(sys.stdout.buffer, encoding='utf-8', errors='replace')
|
||||
ids = {'17228', '19977'}
|
||||
text = Path('Unity/Assets/Resources/Export/Multilingual.asset').read_text(encoding='utf-8')
|
||||
text = Path('Unity/Assets/BundleResources/Export/Multilingual.asset').read_text(encoding='utf-8')
|
||||
lines = text.splitlines()
|
||||
for idx, line in enumerate(lines):
|
||||
if line.strip() in [f'- ID: {i}' for i in ids]:
|
||||
@ -59,13 +59,13 @@ Interpretation:
|
||||
Search an ID in exported assets to see who currently references it:
|
||||
|
||||
```powershell
|
||||
rg -n "Desc: 19977|ActionName: 19977|TechDesc: 19977| 19977" Unity/Assets/Resources/Export -S
|
||||
rg -n "Desc: 19977|ActionName: 19977|TechDesc: 19977| 19977" Unity/Assets/BundleResources/Export -S
|
||||
```
|
||||
|
||||
For field-level reference context:
|
||||
|
||||
```powershell
|
||||
rg -n "19977" Unity/Assets/Resources/Export/ActionDataAssets.asset -C 20
|
||||
rg -n "19977" Unity/Assets/BundleResources/Export/ActionDataAssets.asset -C 20
|
||||
```
|
||||
|
||||
If a new duplicate ID is already written into a DataAssets export, rerunning export after fixing canonicalization should normally reassign the source field back to the preserved ID.
|
||||
|
||||
@ -14,8 +14,12 @@
|
||||
- Embedded string resolve/unresolve.
|
||||
- Language fallback.
|
||||
- `MultilingualItem`.
|
||||
- `Unity/Assets/Resources/Export/Multilingual.asset`
|
||||
- `Unity/Assets/BundleResources/Export/Multilingual.asset`
|
||||
- Canonical ScriptableObject data.
|
||||
- `Unity/Assets/BundleResources/DataAssets/*`
|
||||
- Authoring ScriptableObject configs scanned during export.
|
||||
- `Unity/Assets/BundleResources/Export/*`
|
||||
- Runtime ScriptableObject copies produced by export.
|
||||
- `Tools/MultilingualTxt.txt`
|
||||
- Intermediate delimiter file.
|
||||
- `Tools/Multilingual.xlsx`
|
||||
@ -85,8 +89,8 @@ The same row can therefore have different representations at different phases. A
|
||||
- Deduplicate by canonical raw `item.ZH`.
|
||||
2. Initialize `_zhStrDict` from canonical `item.ZH`.
|
||||
3. Scan active `TextMeshProUGUI` from scene `UICanvas`.
|
||||
4. Scan prefabs under `Assets/Resources/Prefab/`.
|
||||
5. Scan ScriptableObjects under `Assets/Resources/DataAssets/`.
|
||||
4. Scan prefabs under `Assets/BundleResources/Prefab/`.
|
||||
5. Scan ScriptableObjects under `Assets/BundleResources/DataAssets/`.
|
||||
6. For each source string:
|
||||
- Trim and normalize newlines.
|
||||
- Optionally `TransformString`.
|
||||
@ -98,6 +102,17 @@ The same row can therefore have different representations at different phases. A
|
||||
8. Write `MultilingualTxt.txt` with `GetMultilingualStrEditor`, which expands IDs for Excel.
|
||||
9. Run `ExportStringToExcel.py`.
|
||||
|
||||
## BundleResources / Packaging Notes
|
||||
|
||||
The multilingual export flow also refreshes runtime config assets for AB builds:
|
||||
|
||||
- `DataAssets/*` is authoring data.
|
||||
- `SaveExportAsset(name, newAsset)` writes transformed runtime assets to `Assets/BundleResources/Export/{name}.asset`.
|
||||
- `ConfigManager`, `Table`, `MultilingualManager`, achievements, AI config, and similar runtime paths generally load `Export/...` through `TH1Resource.ResourceLoader`.
|
||||
- `ExportMatchLevelData()` writes `Assets/BundleResources/MatchLevelData/ExportLevelData.bytes`; runtime match config uses `MatchLevelData/ExportLevelData` outside editor play mode.
|
||||
- `TH1YooAssetBuildTools` collects the whole `Assets/BundleResources` root, and `TH1AddressByBundleResourcesPath` strips that prefix. `Assets/BundleResources/Export/VersionConfig.asset` is therefore addressed as `Export/VersionConfig.asset`.
|
||||
- Before building PC/iOS AB/player packages, run `Tools/一键导出导回` or the `TH1UnifiedBuildWindow` multilingual export/import checkbox. Otherwise a player can contain stale `Export` assets even when `DataAssets` and `PlayerSettings.bundleVersion` were changed.
|
||||
|
||||
## Import Phases
|
||||
|
||||
1. Run `PrintExcelString.py`.
|
||||
|
||||
@ -15,7 +15,6 @@ using Logic.Audio;
|
||||
using Logic.CrashSight;
|
||||
using Logic.Skill;
|
||||
using RuntimeData;
|
||||
using Steamworks;
|
||||
using TH1_Core.Events;
|
||||
using TH1_Core.Managers;
|
||||
using TH1_Logic.Core;
|
||||
|
||||
@ -92,28 +92,15 @@ namespace Logic.Editor
|
||||
[MenuItem("Tools/一键导出导回")]
|
||||
public static void OneClickExportAndImport()
|
||||
{
|
||||
EditorUtility.DisplayProgressBar("一键导出导回", "正在导出到 Excel...", 0.3f);
|
||||
|
||||
try
|
||||
{
|
||||
var window = new MultilingualEditorWindow();
|
||||
window.InitializeAsset();
|
||||
|
||||
// 步骤1: 执行导出
|
||||
window.AssetExportToExcelInternal();
|
||||
Debug.Log("[一键导出导回] 导出 Excel 成功");
|
||||
|
||||
EditorUtility.DisplayProgressBar("一键导出导回", "正在从 Excel 导回...", 0.7f);
|
||||
|
||||
// 步骤2: 执行导回
|
||||
window.ExcelExportToAssetInternal();
|
||||
Debug.Log("[一键导出导回] Excel 导回成功");
|
||||
|
||||
RunOneClickExportAndImportForBuild((message, progress) =>
|
||||
EditorUtility.DisplayProgressBar("一键导出导回", message, progress));
|
||||
EditorUtility.DisplayDialog("成功", "一键导出导回完成!", "确定");
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
Debug.LogError($"[一键导出导回] 失败: {ex.Message}");
|
||||
Debug.LogError($"[一键导出导回] 失败: {ex}");
|
||||
EditorUtility.DisplayDialog("错误", $"操作失败: {ex.Message}", "确定");
|
||||
}
|
||||
finally
|
||||
@ -122,6 +109,24 @@ namespace Logic.Editor
|
||||
}
|
||||
}
|
||||
|
||||
public static void RunOneClickExportAndImportForBuild(System.Action<string, float> progress = null)
|
||||
{
|
||||
var window = new MultilingualEditorWindow();
|
||||
|
||||
progress?.Invoke("正在初始化多语言资源...", 0.05f);
|
||||
window.InitializeAsset();
|
||||
|
||||
progress?.Invoke("正在导出 DataAssets/UI/Prefab 到 Export 并生成 Excel...", 0.35f);
|
||||
window.AssetExportToExcelInternal();
|
||||
Debug.Log("[一键导出导回] 导出 Excel 成功");
|
||||
|
||||
progress?.Invoke("正在从 Excel 导回 Multilingual.asset...", 0.75f);
|
||||
window.ExcelExportToAssetInternal();
|
||||
Debug.Log("[一键导出导回] Excel 导回成功");
|
||||
|
||||
progress?.Invoke("多语言导出导回完成。", 1f);
|
||||
}
|
||||
|
||||
private void InitializeAsset()
|
||||
{
|
||||
var path = "Assets/BundleResources/Export/Multilingual.asset";
|
||||
|
||||
1041
Unity/Assets/Scripts/TH1_Logic/Editor/TH1UnifiedBuildWindow.cs
Normal file
1041
Unity/Assets/Scripts/TH1_Logic/Editor/TH1UnifiedBuildWindow.cs
Normal file
File diff suppressed because it is too large
Load Diff
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 4b7ee1d9bbf743e898610ee7468260ff
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -34,6 +34,12 @@ namespace TH1_Logic.Net
|
||||
|
||||
// 获取在线好友列表
|
||||
public Dictionary<ulong, MemberInfo> GetOnlineFriendsDict();
|
||||
|
||||
// 获取可展示房间列表
|
||||
public List<LobbyListInfo> GetLobbyListInfos();
|
||||
|
||||
// 刷新房间列表缓存
|
||||
public void RefreshLobbyListInfo();
|
||||
|
||||
// 是否初始化完毕
|
||||
public bool IsInitialized();
|
||||
@ -43,6 +49,9 @@ namespace TH1_Logic.Net
|
||||
|
||||
// 举报房间
|
||||
public bool ReportLobby(LobbyListInfo lobbyInfo);
|
||||
|
||||
// 处理收到的房间举报消息
|
||||
public void OnReceivedLobbyReport(LobbyReportMessage message);
|
||||
|
||||
// 踢出成员
|
||||
public void KickMember(ulong memberId);
|
||||
@ -68,6 +77,9 @@ namespace TH1_Logic.Net
|
||||
// 获取房间所有成员信息
|
||||
public MemberInfo GetMemberInfo(ulong steamID);
|
||||
|
||||
// 获取平台展示名
|
||||
public string GetSelfDisplayName();
|
||||
|
||||
// 获取成员数量
|
||||
public int GetMemberCount();
|
||||
|
||||
@ -101,14 +113,24 @@ namespace TH1_Logic.Net
|
||||
// 发送P2P消息
|
||||
public bool SendMessageToPeer(ulong member, byte[] data, bool reliable = true);
|
||||
|
||||
// 不要求已建立房间内 P2P 连接的直发消息,用于邀请/举报等房间外消息
|
||||
public bool SendMessageToPeerWithoutConnection(ulong member, byte[] data, bool reliable = true);
|
||||
|
||||
// 广播P2P消息
|
||||
public bool BroadcastMessage(byte[] data, bool reliable = true);
|
||||
|
||||
// 检查和某成员的 P2P 连接是否已建立
|
||||
public bool IsPeerConnected(ulong memberId);
|
||||
|
||||
// 获取当前房间ID用于分享
|
||||
public ulong GetShareableLobbyId();
|
||||
|
||||
// 获取自己是否为隐私状态
|
||||
public bool IsSelfStatusInvisibleOrOffline();
|
||||
|
||||
// 平台房间名工具
|
||||
public string GetDefaultRoomName(string ownerName);
|
||||
public string FilterRoomName(string roomName);
|
||||
}
|
||||
|
||||
|
||||
@ -193,7 +215,16 @@ namespace TH1_Logic.Net
|
||||
|
||||
public Dictionary<ulong, MemberInfo> GetOnlineFriendsDict()
|
||||
{
|
||||
return null;
|
||||
return new Dictionary<ulong, MemberInfo>();
|
||||
}
|
||||
|
||||
public List<LobbyListInfo> GetLobbyListInfos()
|
||||
{
|
||||
return new List<LobbyListInfo>();
|
||||
}
|
||||
|
||||
public void RefreshLobbyListInfo()
|
||||
{
|
||||
}
|
||||
|
||||
public void CreateLobby(int maxMembers = 4,bool isPublic = true, string password = "", string roomName = "")
|
||||
@ -266,6 +297,16 @@ namespace TH1_Logic.Net
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SendMessageToPeerWithoutConnection(ulong member, byte[] data, bool reliable = true)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool IsPeerConnected(ulong memberId)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public ulong GetShareableLobbyId()
|
||||
{
|
||||
return 0;
|
||||
@ -275,5 +316,24 @@ namespace TH1_Logic.Net
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public void OnReceivedLobbyReport(LobbyReportMessage message)
|
||||
{
|
||||
}
|
||||
|
||||
public string GetSelfDisplayName()
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
|
||||
public string GetDefaultRoomName(string ownerName)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(ownerName) ? "Default" : ownerName;
|
||||
}
|
||||
|
||||
public string FilterRoomName(string roomName)
|
||||
{
|
||||
return roomName ?? string.Empty;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -6,7 +6,7 @@
|
||||
*/
|
||||
|
||||
|
||||
using TH1_Logic.Steam;
|
||||
using System;
|
||||
|
||||
namespace TH1_Logic.Net
|
||||
{
|
||||
@ -18,12 +18,23 @@ namespace TH1_Logic.Net
|
||||
|
||||
public void Init()
|
||||
{
|
||||
#if UNITY_EDITOR || STEAM_CHANNEL
|
||||
Lobby = new SteamLobbyManager();
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
Lobby = CreateSteamLobby() ?? new LobbyBase();
|
||||
#else
|
||||
Lobby = new LobbyBase();
|
||||
#endif
|
||||
Lobby.Init();
|
||||
}
|
||||
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
private static ILobby CreateSteamLobby()
|
||||
{
|
||||
var lobbyType = Type.GetType("TH1_Logic.Steam.SteamLobbyManager")
|
||||
?? Type.GetType("TH1_Logic.Steam.SteamLobbyManager, TH1.Hotfix")
|
||||
?? Type.GetType("TH1_Logic.Steam.SteamLobbyManager, TH1.Steam.Runtime");
|
||||
if (lobbyType == null) return null;
|
||||
return Activator.CreateInstance(lobbyType) as ILobby;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -3,7 +3,9 @@ using System.Threading.Tasks;
|
||||
using Logic.CrashSight;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
using Steamworks;
|
||||
#endif
|
||||
using TH1_Logic.Collect;
|
||||
using TH1_Logic.Config;
|
||||
using TH1_Logic.Core;
|
||||
@ -245,6 +247,7 @@ namespace TH1_Logic.Oss
|
||||
private static bool TryGetSteamId(out string steamId)
|
||||
{
|
||||
steamId = "";
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
try
|
||||
{
|
||||
if (!SteamUser.BLoggedOn()) return false;
|
||||
@ -259,11 +262,15 @@ namespace TH1_Logic.Oss
|
||||
{
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
private static bool TryGetAuthTicket(out string authTicket)
|
||||
{
|
||||
authTicket = null;
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
try
|
||||
{
|
||||
var ticket = new byte[1024];
|
||||
@ -283,6 +290,9 @@ namespace TH1_Logic.Oss
|
||||
LogSystem.LogWarning($"Steam auth ticket unavailable: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2,7 +2,9 @@ using System;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using Logic.CrashSight;
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
using Steamworks;
|
||||
#endif
|
||||
using TH1_Logic.Config;
|
||||
using UnityEngine;
|
||||
using UnityEngine.Networking;
|
||||
@ -144,6 +146,7 @@ namespace TH1_Logic.Oss
|
||||
|
||||
private static string GetSteamAppId()
|
||||
{
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
try
|
||||
{
|
||||
var appId = SteamUtils.GetAppID().m_AppId;
|
||||
@ -153,6 +156,9 @@ namespace TH1_Logic.Oss
|
||||
{
|
||||
return string.Empty;
|
||||
}
|
||||
#else
|
||||
return string.Empty;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -762,8 +762,7 @@ namespace TH1_Logic.Steam
|
||||
return;
|
||||
}
|
||||
|
||||
if (LobbyManager.Instance.Lobby is SteamLobbyManager steamLobby)
|
||||
steamLobby.OnReceivedLobbyReport(message);
|
||||
LobbyManager.Instance.Lobby?.OnReceivedLobbyReport(message);
|
||||
}
|
||||
|
||||
private void OnReceivedInviteVersionMismatch(InviteVersionMismatchMessage message)
|
||||
|
||||
@ -12,7 +12,6 @@ using Logic.AI;
|
||||
using Logic.CrashSight;
|
||||
using MemoryPack;
|
||||
using RuntimeData;
|
||||
using Steamworks;
|
||||
using TH1_Logic.Chat;
|
||||
using TH1_Logic.Config;
|
||||
using TH1_Logic.Core;
|
||||
@ -57,9 +56,6 @@ namespace TH1_Logic.Steam
|
||||
{
|
||||
if (lobbyInfo == null || lobbyInfo.OwnerId == 0 || lobbyInfo.LobbyId == 0) return false;
|
||||
|
||||
var targetId = new CSteamID(lobbyInfo.OwnerId);
|
||||
if (!targetId.IsValid()) return false;
|
||||
|
||||
var data = new InviteVersionMismatchMessage
|
||||
{
|
||||
LobbyId = lobbyInfo.LobbyId,
|
||||
@ -68,8 +64,8 @@ namespace TH1_Logic.Steam
|
||||
LobbyVersion = lobbyInfo.Version,
|
||||
};
|
||||
|
||||
byte[] messageBytes = NetworkPayloadCodec.Encode(TH1Serialization.Serialize<BaseMessage>(data));
|
||||
if (SimpleP2P.Instance.SendToWithOutConnect(targetId, messageBytes)) return true;
|
||||
byte[] messageBytes = SerializeForNetwork(data);
|
||||
if (LobbyManager.Instance.Lobby.SendMessageToPeerWithoutConnection(lobbyInfo.OwnerId, messageBytes)) return true;
|
||||
|
||||
LogSystem.LogError($"InviteVersionMismatchMessage: 发送给房主失败 owner={lobbyInfo.OwnerId}, lobby={lobbyInfo.LobbyId}");
|
||||
return false;
|
||||
@ -313,8 +309,7 @@ namespace TH1_Logic.Steam
|
||||
{
|
||||
if (memberId == selfId) continue;
|
||||
|
||||
var target = new CSteamID(memberId);
|
||||
if (!SimpleP2P.Instance.IsConnectedTo(target))
|
||||
if (!LobbyManager.Instance.Lobby.IsPeerConnected(memberId))
|
||||
{
|
||||
LogSystem.LogInfo($"UpdateLobbyData deferred until P2P connected: memberId={memberId}");
|
||||
continue;
|
||||
@ -330,7 +325,7 @@ namespace TH1_Logic.Steam
|
||||
if (LobbyManager.Instance.Lobby.IsLobbyOwner()) return false;
|
||||
if (!LobbyManager.Instance.Lobby.IsInLobby()) return false;
|
||||
var hostId = LobbyManager.Instance.Lobby.GetLobbyOwnerId();
|
||||
if (hostId == 0 || !SimpleP2P.Instance.IsConnectedTo(new CSteamID(hostId)))
|
||||
if (hostId == 0 || !LobbyManager.Instance.Lobby.IsPeerConnected(hostId))
|
||||
{
|
||||
NetworkPlayerTipManager.Instance.Request(NetworkPlayerTipType.LobbyDataRequestFailed);
|
||||
return false;
|
||||
|
||||
21
Unity/Assets/Scripts/TH1_Logic/Steam/LobbyListInfo.cs
Normal file
21
Unity/Assets/Scripts/TH1_Logic/Steam/LobbyListInfo.cs
Normal file
@ -0,0 +1,21 @@
|
||||
using MemoryPack;
|
||||
|
||||
namespace TH1_Logic.Steam
|
||||
{
|
||||
// 房间信息结构。保持命名空间和字段不变,避免影响已有网络消息和 UI 引用。
|
||||
[MemoryPackable]
|
||||
public partial class LobbyListInfo
|
||||
{
|
||||
public ulong LobbyId;
|
||||
public ulong OwnerId;
|
||||
|
||||
public string OwnerName;
|
||||
public string RoomName;
|
||||
public string Version;
|
||||
public int CurrentPlayers;
|
||||
public int MaxPlayers;
|
||||
public int GameState;
|
||||
public bool HasPassword;
|
||||
public int ReportCount;
|
||||
}
|
||||
}
|
||||
11
Unity/Assets/Scripts/TH1_Logic/Steam/LobbyListInfo.cs.meta
Normal file
11
Unity/Assets/Scripts/TH1_Logic/Steam/LobbyListInfo.cs.meta
Normal file
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 93f23d875f97403ba1d4cf2afdc2f8c3
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -1,4 +1,5 @@
|
||||
using System;
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
using System.Collections.Generic;
|
||||
using System.Runtime.InteropServices;
|
||||
using Logic.CrashSight;
|
||||
@ -1738,3 +1739,4 @@ namespace TH1_Logic.Steam
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -5,7 +5,7 @@
|
||||
* @Modify:
|
||||
*/
|
||||
|
||||
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
using TH1_Logic.Core;
|
||||
using TH1_Logic.Net;
|
||||
using UnityEngine;
|
||||
@ -138,4 +138,5 @@ namespace TH1_Logic.Steam
|
||||
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -1,4 +1,4 @@
|
||||
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
@ -108,6 +108,7 @@ namespace TH1_Logic.Steam
|
||||
// 房间列表
|
||||
private List<LobbyListInfo> _lobbyListInfos;
|
||||
public List<LobbyListInfo> LobbyListInfos => _lobbyListInfos;
|
||||
public List<LobbyListInfo> GetLobbyListInfos() => _lobbyListInfos;
|
||||
private readonly HashSet<ulong> _lobbyReporters = new HashSet<ulong>();
|
||||
|
||||
// 事件委托
|
||||
@ -1274,6 +1275,21 @@ namespace TH1_Logic.Steam
|
||||
if (string.IsNullOrEmpty(filteredRoomName)) return "Default";
|
||||
return BannedWordFilter.Filter(filteredRoomName, BannedTextContext.Name);
|
||||
}
|
||||
|
||||
string ILobby.GetDefaultRoomName(string ownerName)
|
||||
{
|
||||
return GetDefaultRoomName(ownerName);
|
||||
}
|
||||
|
||||
string ILobby.FilterRoomName(string roomName)
|
||||
{
|
||||
return FilterRoomName(roomName);
|
||||
}
|
||||
|
||||
public string GetSelfDisplayName()
|
||||
{
|
||||
return SelfName;
|
||||
}
|
||||
|
||||
public bool IsInitialized()
|
||||
{
|
||||
@ -1797,6 +1813,23 @@ namespace TH1_Logic.Steam
|
||||
return SimpleP2P.Instance.SendTo(cSteamId, data, reliable);
|
||||
}
|
||||
|
||||
public bool SendMessageToPeerWithoutConnection(ulong member, byte[] data, bool reliable = true)
|
||||
{
|
||||
if (data == null || data.Length == 0)
|
||||
return ReportP2PSendPrecheckFailed(member, "Trying to send null or empty data");
|
||||
var targetId = new CSteamID(member);
|
||||
if (!targetId.IsValid())
|
||||
return ReportP2PSendPrecheckFailed(member, $"Invalid target member: {member}");
|
||||
return SimpleP2P.Instance.SendToWithOutConnect(targetId, data, reliable);
|
||||
}
|
||||
|
||||
public bool IsPeerConnected(ulong memberId)
|
||||
{
|
||||
if (memberId == 0) return false;
|
||||
var targetId = new CSteamID(memberId);
|
||||
return targetId.IsValid() && SimpleP2P.Instance.IsConnectedTo(targetId);
|
||||
}
|
||||
|
||||
// 广播P2P消息
|
||||
public bool BroadcastMessage(byte[] data, bool reliable = true)
|
||||
{
|
||||
@ -2129,22 +2162,5 @@ namespace TH1_Logic.Steam
|
||||
LogSystem.LogInfo("SteamLobbyManager cleaned up");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// 房间信息结构
|
||||
[MemoryPackable]
|
||||
public partial class LobbyListInfo
|
||||
{
|
||||
public ulong LobbyId;
|
||||
public ulong OwnerId;
|
||||
|
||||
public string OwnerName;
|
||||
public string RoomName;
|
||||
public string Version;
|
||||
public int CurrentPlayers;
|
||||
public int MaxPlayers;
|
||||
public int GameState;
|
||||
public bool HasPassword;
|
||||
public int ReportCount;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
@ -0,0 +1,145 @@
|
||||
#if !(STEAM_CHANNEL || STEAMWORKS_NET)
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using Steamworks;
|
||||
using TH1_Logic.Chat;
|
||||
using TH1_Logic.Net;
|
||||
|
||||
namespace TH1_Logic.Steam
|
||||
{
|
||||
public class SteamLobbyManager : LobbyBase
|
||||
{
|
||||
public const string LobbyPasswordWrongError = "LobbyPasswordWrong";
|
||||
|
||||
public bool IsSteamInitialized => false;
|
||||
public bool IsloggedIn => false;
|
||||
public bool IsLobbyInitialized => false;
|
||||
public string SelfName => GetSelfDisplayName();
|
||||
public CSteamID SelfID => CSteamID.Nil;
|
||||
public List<LobbyListInfo> LobbyListInfos => GetLobbyListInfos();
|
||||
|
||||
public event Action<CSteamID> OnLobbyCreatedEvent;
|
||||
public event Action<CSteamID> OnLobbyEnteredEvent;
|
||||
public event Action<List<CSteamID>> OnLobbyLeftEvent;
|
||||
public event Action<CSteamID, CSteamID> OnHostChangedEvent;
|
||||
public event Action<List<CSteamID>> OnMembersChangedEvent;
|
||||
public event Action<string> OnLobbyErrorEvent;
|
||||
public event Action<CSteamID> OnMemberJoinedEvent;
|
||||
public event Action<CSteamID> OnMemberLeftEvent;
|
||||
|
||||
public new static string GetDefaultRoomName(string selfName)
|
||||
{
|
||||
return string.IsNullOrWhiteSpace(selfName) ? "Default" : $"{selfName} Room";
|
||||
}
|
||||
|
||||
public static string FilterRoomName(string input, int maxLength = 20)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(input)) return "Default";
|
||||
var result = input.Trim();
|
||||
if (result.Length > maxLength) result = result.Substring(0, maxLength);
|
||||
return BannedWordFilter.Filter(result, BannedTextContext.Name);
|
||||
}
|
||||
|
||||
public string GetRoomName()
|
||||
{
|
||||
return "Default";
|
||||
}
|
||||
|
||||
public bool SetRoomName(string roomName)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool CanCreateLobbyNow(out string reason)
|
||||
{
|
||||
reason = "Steam is unavailable on this platform.";
|
||||
return false;
|
||||
}
|
||||
|
||||
public void SearchPublicLobbies()
|
||||
{
|
||||
}
|
||||
|
||||
public List<(CSteamID id, string name)> GetOnlineFriends()
|
||||
{
|
||||
return new List<(CSteamID, string)>();
|
||||
}
|
||||
|
||||
public CSteamID GetCSteamID(ulong memberId)
|
||||
{
|
||||
return CSteamID.Nil;
|
||||
}
|
||||
|
||||
public EPersonaState GetSelfPersonaState()
|
||||
{
|
||||
return EPersonaState.k_EPersonaStateOffline;
|
||||
}
|
||||
|
||||
public void RaiseNoSteamError()
|
||||
{
|
||||
OnLobbyErrorEvent?.Invoke("Steam is unavailable on this platform.");
|
||||
}
|
||||
|
||||
public void SuppressEventWarnings()
|
||||
{
|
||||
_ = OnLobbyCreatedEvent;
|
||||
_ = OnLobbyEnteredEvent;
|
||||
_ = OnLobbyLeftEvent;
|
||||
_ = OnHostChangedEvent;
|
||||
_ = OnMembersChangedEvent;
|
||||
_ = OnMemberJoinedEvent;
|
||||
_ = OnMemberLeftEvent;
|
||||
}
|
||||
}
|
||||
|
||||
public class SimpleP2P
|
||||
{
|
||||
public static SimpleP2P Instance { get; } = new SimpleP2P();
|
||||
|
||||
public bool IsInitialized => false;
|
||||
public event Action<CSteamID> OnPeerConnectedEvent;
|
||||
public event Action<CSteamID> OnPeerDisconnectedEvent;
|
||||
public event Action<CSteamID, byte[]> OnMessageReceivedEvent;
|
||||
public event Action<CSteamID, string> OnMessageSendFailedEvent;
|
||||
public event Action<string> OnConnectionErrorEvent;
|
||||
|
||||
public void Initialize() { }
|
||||
public void Update() { }
|
||||
public void PollMessages() { }
|
||||
public void Cleanup() { }
|
||||
public void DisconnectAll() { }
|
||||
public void DisconnectFromPeer(CSteamID steamID) { }
|
||||
public void MarkExpectedDisconnect(CSteamID steamID) { }
|
||||
public int GetConnectionCount() => 0;
|
||||
public bool ConnectToPeer(CSteamID steamID) => false;
|
||||
public bool IsConnectedTo(CSteamID steamID) => false;
|
||||
public IEnumerable<CSteamID> GetConnectedPeers() => Array.Empty<CSteamID>();
|
||||
public bool HasRecentConnectionFailure(float seconds, out string reason)
|
||||
{
|
||||
reason = string.Empty;
|
||||
return false;
|
||||
}
|
||||
|
||||
public bool SendTo(CSteamID target, byte[] data, bool reliable = true, bool ordered = true) => false;
|
||||
public bool SendToWithOutConnect(CSteamID target, byte[] data, bool reliable = true, bool ordered = true) => false;
|
||||
|
||||
public bool CanQueueMessages(IReadOnlyList<CSteamID> targets, int dataLength, out CSteamID failedTarget, out string reason)
|
||||
{
|
||||
failedTarget = CSteamID.Nil;
|
||||
reason = string.Empty;
|
||||
return targets == null || targets.Count == 0;
|
||||
}
|
||||
|
||||
public void LogDetailedConnectionInfo(CSteamID steamID) { }
|
||||
|
||||
public void SuppressEventWarnings()
|
||||
{
|
||||
_ = OnPeerConnectedEvent;
|
||||
_ = OnPeerDisconnectedEvent;
|
||||
_ = OnMessageReceivedEvent;
|
||||
_ = OnMessageSendFailedEvent;
|
||||
_ = OnConnectionErrorEvent;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: 6d9854f7e4ff4700b11fc15f41159a9b
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
291
Unity/Assets/Scripts/TH1_Logic/Steam/SteamworksNonSteamStubs.cs
Normal file
291
Unity/Assets/Scripts/TH1_Logic/Steam/SteamworksNonSteamStubs.cs
Normal file
@ -0,0 +1,291 @@
|
||||
#if !(STEAM_CHANNEL || STEAMWORKS_NET)
|
||||
using System;
|
||||
|
||||
namespace Steamworks
|
||||
{
|
||||
public struct CSteamID : IEquatable<CSteamID>
|
||||
{
|
||||
public static readonly CSteamID Nil = new CSteamID(0);
|
||||
public ulong m_SteamID;
|
||||
|
||||
public CSteamID(ulong value)
|
||||
{
|
||||
m_SteamID = value;
|
||||
}
|
||||
|
||||
public bool IsValid() => m_SteamID != 0;
|
||||
public uint GetAccountID() => (uint)(m_SteamID & 0xffffffff);
|
||||
public bool Equals(CSteamID other) => m_SteamID == other.m_SteamID;
|
||||
public override bool Equals(object obj) => obj is CSteamID other && Equals(other);
|
||||
public override int GetHashCode() => m_SteamID.GetHashCode();
|
||||
public override string ToString() => m_SteamID.ToString();
|
||||
public static bool operator ==(CSteamID left, CSteamID right) => left.Equals(right);
|
||||
public static bool operator !=(CSteamID left, CSteamID right) => !left.Equals(right);
|
||||
}
|
||||
|
||||
public struct PublishedFileId_t : IEquatable<PublishedFileId_t>
|
||||
{
|
||||
public ulong m_PublishedFileId;
|
||||
|
||||
public PublishedFileId_t(ulong value)
|
||||
{
|
||||
m_PublishedFileId = value;
|
||||
}
|
||||
|
||||
public bool Equals(PublishedFileId_t other) => m_PublishedFileId == other.m_PublishedFileId;
|
||||
public override bool Equals(object obj) => obj is PublishedFileId_t other && Equals(other);
|
||||
public override int GetHashCode() => m_PublishedFileId.GetHashCode();
|
||||
public override string ToString() => m_PublishedFileId.ToString();
|
||||
public static bool operator ==(PublishedFileId_t left, PublishedFileId_t right) => left.Equals(right);
|
||||
public static bool operator !=(PublishedFileId_t left, PublishedFileId_t right) => !left.Equals(right);
|
||||
}
|
||||
|
||||
public struct AppId_t
|
||||
{
|
||||
public uint m_AppId;
|
||||
|
||||
public AppId_t(uint value)
|
||||
{
|
||||
m_AppId = value;
|
||||
}
|
||||
}
|
||||
|
||||
public struct SteamAPICall_t
|
||||
{
|
||||
public ulong m_SteamAPICall;
|
||||
}
|
||||
|
||||
public struct UGCQueryHandle_t
|
||||
{
|
||||
public ulong m_UGCQueryHandle;
|
||||
}
|
||||
|
||||
public struct UGCUpdateHandle_t
|
||||
{
|
||||
public ulong m_UGCUpdateHandle;
|
||||
}
|
||||
|
||||
public struct SteamNetworkingIdentity
|
||||
{
|
||||
public CSteamID SteamID;
|
||||
|
||||
public void SetSteamID(CSteamID steamId)
|
||||
{
|
||||
SteamID = steamId;
|
||||
}
|
||||
}
|
||||
|
||||
public enum EResult
|
||||
{
|
||||
k_EResultOK = 1,
|
||||
k_EResultFail = 2,
|
||||
k_EResultNoConnection = 3,
|
||||
k_EResultInvalidPassword = 5,
|
||||
k_EResultLimitExceeded = 25,
|
||||
k_EResultIgnored = 43,
|
||||
k_EResultAccessDenied = 15
|
||||
}
|
||||
|
||||
public enum EPersonaState
|
||||
{
|
||||
k_EPersonaStateOffline = 0,
|
||||
k_EPersonaStateOnline = 1,
|
||||
k_EPersonaStateBusy = 2,
|
||||
k_EPersonaStateAway = 3,
|
||||
k_EPersonaStateSnooze = 4,
|
||||
k_EPersonaStateInvisible = 7
|
||||
}
|
||||
|
||||
public enum ETextFilteringContext
|
||||
{
|
||||
k_ETextFilteringContextUnknown = 0,
|
||||
k_ETextFilteringContextGameContent = 1,
|
||||
k_ETextFilteringContextChat = 2,
|
||||
k_ETextFilteringContextName = 3
|
||||
}
|
||||
|
||||
[Flags]
|
||||
public enum EItemState
|
||||
{
|
||||
k_EItemStateNone = 0,
|
||||
k_EItemStateSubscribed = 1,
|
||||
k_EItemStateInstalled = 4
|
||||
}
|
||||
|
||||
public enum EItemUpdateStatus
|
||||
{
|
||||
k_EItemUpdateStatusInvalid = 0
|
||||
}
|
||||
|
||||
public enum EWorkshopFileType
|
||||
{
|
||||
k_EWorkshopFileTypeCommunity = 0
|
||||
}
|
||||
|
||||
public enum ERemoteStoragePublishedFileVisibility
|
||||
{
|
||||
k_ERemoteStoragePublishedFileVisibilityPublic = 0
|
||||
}
|
||||
|
||||
public enum EUGCQuery
|
||||
{
|
||||
k_EUGCQuery_RankedByPublicationDate = 0
|
||||
}
|
||||
|
||||
public enum EUGCMatchingUGCType
|
||||
{
|
||||
k_EUGCMatchingUGCType_Items = 0,
|
||||
k_EUGCMatchingUGCType_Items_ReadyToUse = 1
|
||||
}
|
||||
|
||||
public enum EUserUGCList
|
||||
{
|
||||
k_EUserUGCList_Published = 0
|
||||
}
|
||||
|
||||
public enum EUserUGCListSortOrder
|
||||
{
|
||||
k_EUserUGCListSortOrder_CreationOrderDesc = 0
|
||||
}
|
||||
|
||||
public struct SteamUGCDetails_t
|
||||
{
|
||||
public PublishedFileId_t m_nPublishedFileId;
|
||||
public string m_rgchTitle;
|
||||
public string m_rgchDescription;
|
||||
public string m_rgchTags;
|
||||
public uint m_unVotesUp;
|
||||
public uint m_unVotesDown;
|
||||
public int m_nFileSize;
|
||||
public uint m_rtimeCreated;
|
||||
public uint m_rtimeUpdated;
|
||||
public ulong m_ulSteamIDOwner;
|
||||
}
|
||||
|
||||
public struct SteamUGCQueryCompleted_t
|
||||
{
|
||||
public UGCQueryHandle_t m_handle;
|
||||
public EResult m_eResult;
|
||||
public uint m_unNumResultsReturned;
|
||||
public uint m_unTotalMatchingResults;
|
||||
}
|
||||
|
||||
public struct CreateItemResult_t
|
||||
{
|
||||
public EResult m_eResult;
|
||||
public PublishedFileId_t m_nPublishedFileId;
|
||||
public bool m_bUserNeedsToAcceptWorkshopLegalAgreement;
|
||||
}
|
||||
|
||||
public struct SubmitItemUpdateResult_t
|
||||
{
|
||||
public EResult m_eResult;
|
||||
public bool m_bUserNeedsToAcceptWorkshopLegalAgreement;
|
||||
}
|
||||
|
||||
public struct RemoteStorageSubscribePublishedFileResult_t
|
||||
{
|
||||
public EResult m_eResult;
|
||||
public PublishedFileId_t m_nPublishedFileId;
|
||||
}
|
||||
|
||||
public struct RemoteStorageUnsubscribePublishedFileResult_t
|
||||
{
|
||||
public EResult m_eResult;
|
||||
public PublishedFileId_t m_nPublishedFileId;
|
||||
}
|
||||
|
||||
public sealed class CallResult<T>
|
||||
{
|
||||
public static CallResult<T> Create(Action<T, bool> callback) => new CallResult<T>();
|
||||
public void Set(SteamAPICall_t apiCall) { }
|
||||
public void Set(SteamAPICall_t apiCall, Action<T, bool> callback) { }
|
||||
}
|
||||
|
||||
public static class CallbackDispatcher
|
||||
{
|
||||
public static bool IsInitialized => false;
|
||||
}
|
||||
|
||||
public static class SteamAPI
|
||||
{
|
||||
public static bool IsSteamRunning() => false;
|
||||
public static void RunCallbacks() { }
|
||||
}
|
||||
|
||||
public static class SteamUtils
|
||||
{
|
||||
public static AppId_t GetAppID() => new AppId_t(0);
|
||||
public static bool InitFilterText(uint filterOptions = 0) => false;
|
||||
|
||||
public static int FilterText(ETextFilteringContext context, CSteamID sourceSteamId, string input, out string filtered, uint filteredSize)
|
||||
{
|
||||
filtered = input;
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SteamUser
|
||||
{
|
||||
public static bool BLoggedOn() => false;
|
||||
public static CSteamID GetSteamID() => CSteamID.Nil;
|
||||
|
||||
public static uint GetAuthSessionTicket(byte[] ticket, int maxTicket, out uint ticketSize, ref SteamNetworkingIdentity identity)
|
||||
{
|
||||
ticketSize = 0;
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
public static class SteamFriends
|
||||
{
|
||||
public static string GetPersonaName() => string.Empty;
|
||||
public static bool RequestUserInformation(CSteamID steamId, bool requireNameOnly) => false;
|
||||
public static string GetFriendPersonaName(CSteamID steamId) => string.Empty;
|
||||
}
|
||||
|
||||
public static class SteamUGC
|
||||
{
|
||||
public static UGCQueryHandle_t CreateQueryAllUGCRequest(EUGCQuery queryType, EUGCMatchingUGCType matchingType, AppId_t creatorAppId, AppId_t consumerAppId, uint page) => default;
|
||||
public static UGCQueryHandle_t CreateQueryUserUGCRequest(uint accountId, EUserUGCList listType, EUGCMatchingUGCType matchingType, EUserUGCListSortOrder sortOrder, AppId_t creatorAppId, AppId_t consumerAppId, uint page) => default;
|
||||
public static bool SetReturnLongDescription(UGCQueryHandle_t handle, bool value) => false;
|
||||
public static bool SetReturnTotalOnly(UGCQueryHandle_t handle, bool value) => false;
|
||||
public static SteamAPICall_t SendQueryUGCRequest(UGCQueryHandle_t handle) => default;
|
||||
public static bool ReleaseQueryUGCRequest(UGCQueryHandle_t handle) => true;
|
||||
public static bool GetQueryUGCResult(UGCQueryHandle_t handle, uint index, out SteamUGCDetails_t details)
|
||||
{
|
||||
details = default;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static uint GetItemState(PublishedFileId_t fileId) => 0;
|
||||
public static bool GetItemInstallInfo(PublishedFileId_t fileId, out ulong sizeOnDisk, out string folder, uint folderSize, out uint timestamp)
|
||||
{
|
||||
sizeOnDisk = 0;
|
||||
folder = string.Empty;
|
||||
timestamp = 0;
|
||||
return false;
|
||||
}
|
||||
|
||||
public static uint GetNumSubscribedItems() => 0;
|
||||
public static uint GetSubscribedItems(PublishedFileId_t[] publishedFileIds, uint maxEntries) => 0;
|
||||
public static SteamAPICall_t SubscribeItem(PublishedFileId_t fileId) => default;
|
||||
public static SteamAPICall_t UnsubscribeItem(PublishedFileId_t fileId) => default;
|
||||
public static SteamAPICall_t CreateItem(AppId_t consumerAppId, EWorkshopFileType fileType) => default;
|
||||
public static UGCUpdateHandle_t StartItemUpdate(AppId_t consumerAppId, PublishedFileId_t fileId) => default;
|
||||
public static bool SetItemTitle(UGCUpdateHandle_t handle, string title) => false;
|
||||
public static bool SetItemDescription(UGCUpdateHandle_t handle, string description) => false;
|
||||
public static bool SetItemContent(UGCUpdateHandle_t handle, string contentFolder) => false;
|
||||
public static bool SetItemPreview(UGCUpdateHandle_t handle, string previewFile) => false;
|
||||
public static bool SetItemVisibility(UGCUpdateHandle_t handle, ERemoteStoragePublishedFileVisibility visibility) => false;
|
||||
public static bool SetItemTags(UGCUpdateHandle_t handle, System.Collections.Generic.IList<string> tags) => false;
|
||||
public static SteamAPICall_t SubmitItemUpdate(UGCUpdateHandle_t handle, string changeNote) => default;
|
||||
public static EItemUpdateStatus GetItemUpdateProgress(UGCUpdateHandle_t handle, out ulong bytesProcessed, out ulong bytesTotal)
|
||||
{
|
||||
bytesProcessed = 0;
|
||||
bytesTotal = 0;
|
||||
return EItemUpdateStatus.k_EItemUpdateStatusInvalid;
|
||||
}
|
||||
}
|
||||
}
|
||||
#endif
|
||||
@ -0,0 +1,11 @@
|
||||
fileFormatVersion: 2
|
||||
guid: da2c27e88ef14b3d9b65f2b1222f1f5d
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
icon: {instanceID: 0}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
@ -2,7 +2,9 @@ using TH1_Core.Events;
|
||||
using Logic.CrashSight;
|
||||
using TH1_Logic.Config;
|
||||
using TH1_Logic.Oss;
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
using Steamworks;
|
||||
#endif
|
||||
using TH1_UI.Controller.Base;
|
||||
using TH1_UI.View.Global;
|
||||
|
||||
@ -117,6 +119,7 @@ namespace TH1_UI.Controller.Global
|
||||
private static bool TryGetSteamId(out string steamId)
|
||||
{
|
||||
steamId = "";
|
||||
#if STEAM_CHANNEL || STEAMWORKS_NET
|
||||
try
|
||||
{
|
||||
if (!SteamUser.BLoggedOn())
|
||||
@ -134,6 +137,9 @@ namespace TH1_UI.Controller.Global
|
||||
LogSystem.LogWarning($"PlayerBugReport SteamID unavailable: {ex.Message}");
|
||||
return false;
|
||||
}
|
||||
#else
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user