update P2-Job-System-+-Burst-落地.md
This commit is contained in:
parent
0d7df18324
commit
0a281a5b1f
|
|
@ -78,11 +78,11 @@ crashlytics-build.properties
|
|||
/Assets/StreamingAssets
|
||||
/Assets/StreamingAssets.meta
|
||||
/UI参考
|
||||
/AGENTS.md
|
||||
/bin
|
||||
/docs/screenshot
|
||||
*.xmind
|
||||
/数据表/__pycache__/
|
||||
/类吸血鬼项目.md
|
||||
|
||||
~$*.xlsx
|
||||
Assets/GameMain/Configs/ResourceBuilder.xml
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@ namespace UnityGameFramework.Editor
|
|||
"UnityGameFramework.Runtime",
|
||||
#endif
|
||||
"Assembly-CSharp",
|
||||
"VampireLike"
|
||||
};
|
||||
|
||||
private static readonly string[] RuntimeOrEditorAssemblyNames =
|
||||
|
|
@ -34,6 +35,8 @@ namespace UnityGameFramework.Editor
|
|||
"UnityGameFramework.Editor",
|
||||
#endif
|
||||
"Assembly-CSharp-Editor",
|
||||
"VampireLike",
|
||||
"VampireLike.Editor"
|
||||
};
|
||||
|
||||
/// <summary>
|
||||
|
|
|
|||
|
|
@ -8,11 +8,11 @@
|
|||
<CompressionHelperTypeName>UnityGameFramework.Runtime.DefaultCompressionHelper</CompressionHelperTypeName>
|
||||
<AdditionalCompressionSelected>False</AdditionalCompressionSelected>
|
||||
<ForceRebuildAssetBundleSelected>False</ForceRebuildAssetBundleSelected>
|
||||
<BuildEventHandlerTypeName>StarForce.Editor.StarForceBuildEventHandler</BuildEventHandlerTypeName>
|
||||
<OutputDirectory>D:/Learn/GameLearn/UnityProjects/VampireLike/bin</OutputDirectory>
|
||||
<BuildEventHandlerTypeName>VampireLike.Editor.VampireLikeBuildEventHandler</BuildEventHandlerTypeName>
|
||||
<OutputDirectory>C:/UnityProjects/VampireLike/bin/AssetBundles</OutputDirectory>
|
||||
<OutputPackageSelected>True</OutputPackageSelected>
|
||||
<OutputFullSelected>True</OutputFullSelected>
|
||||
<OutputPackedSelected>True</OutputPackedSelected>
|
||||
<OutputFullSelected>False</OutputFullSelected>
|
||||
<OutputPackedSelected>False</OutputPackedSelected>
|
||||
</Settings>
|
||||
</ResourceBuilder>
|
||||
</UnityGameFramework>
|
||||
|
|
@ -17,6 +17,7 @@
|
|||
<Resource Name="Music/Menu" FileSystem="Resources" LoadType="0" Packed="True" ResourceGroups="Music" />
|
||||
<Resource Name="Scenes" FileSystem="Resources" LoadType="0" Packed="True" />
|
||||
<Resource Name="SceneSettings" LoadType="0" Packed="False" />
|
||||
<Resource Name="Scripts" LoadType="0" Packed="False" />
|
||||
<Resource Name="Sounds" FileSystem="Resources" LoadType="0" Packed="True" />
|
||||
<Resource Name="Textures" FileSystem="Resources" LoadType="0" Packed="True" />
|
||||
<Resource Name="UI/UIForms" FileSystem="UI" LoadType="0" Packed="True" />
|
||||
|
|
@ -42,6 +43,7 @@
|
|||
<Asset Guid="0f995b3145e0e7247a42da6cef1dbf23" ResourceName="Materials" />
|
||||
<Asset Guid="1046dcb12e547564d8b54bd15419a787" ResourceName="Entities" />
|
||||
<Asset Guid="1053b0070685be347ab58587156842dc" ResourceName="Localization/Dictionaries" ResourceVariant="zh-tw" />
|
||||
<Asset Guid="11143001bcbdc864b8d8fe2083142e5a" ResourceName="Entities" />
|
||||
<Asset Guid="1478894bc9a1ed241b05b0862a7b8bce" ResourceName="Textures" />
|
||||
<Asset Guid="14869ac0d4433f04db1704e39d03412e" ResourceName="Localization/Dictionaries" ResourceVariant="en-us" />
|
||||
<Asset Guid="156d241f796508c4da4fc354a7fbf5a8" ResourceName="UI/UISprites/Common" />
|
||||
|
|
@ -83,6 +85,7 @@
|
|||
<Asset Guid="4473d81b14ddb0143addf0e6050d8491" ResourceName="Scenes" />
|
||||
<Asset Guid="44c8db52241385c45bbb14a1718f17bf" ResourceName="Configs" />
|
||||
<Asset Guid="44cfa1c448225554c961ad6eb667d80b" ResourceName="DataTables" />
|
||||
<Asset Guid="47a82ffa13c291447ab895cd0bc251cd" ResourceName="Scripts" />
|
||||
<Asset Guid="4c3865b2ac420cd46a9cde6ab468d016" ResourceName="Materials" />
|
||||
<Asset Guid="4ca22ae3bc068c84eb7858d5b9bdf3e2" ResourceName="Fonts" />
|
||||
<Asset Guid="4f688097e85071841a2c3ba165000c20" ResourceName="Textures" />
|
||||
|
|
@ -94,6 +97,7 @@
|
|||
<Asset Guid="5b5a6a737c460eb4abc105d6583d405e" ResourceName="Fonts" />
|
||||
<Asset Guid="5dcd89912e222bf4c87f76db4044bc5e" ResourceName="Localization/Dictionaries" ResourceVariant="ko-kr" />
|
||||
<Asset Guid="5ebb46af6f16ae94e87f64a7dc0a49cb" ResourceName="Entities" />
|
||||
<Asset Guid="602d791ab1251f74ca2470c53bf382a3" ResourceName="Scripts" />
|
||||
<Asset Guid="62af9e5c8f39cfa49af9e10ccf42f1da" ResourceName="UI/UISprites/Common" />
|
||||
<Asset Guid="638ff8ae4a0d15047839cd265d3bc296" ResourceName="Music/Background" />
|
||||
<Asset Guid="63fe6ff9ab9e1433f8db4ebd940f2442" ResourceName="Materials" />
|
||||
|
|
|
|||
|
|
@ -23,6 +23,17 @@ namespace CustomComponent
|
|||
private const int RequiredCornerTapCount = 3;
|
||||
private const int DebugHealAmount = 200;
|
||||
|
||||
[Header("Window Content")]
|
||||
[SerializeField] private bool _showBuffSection = true;
|
||||
[SerializeField] private bool _showBattleOverview = true;
|
||||
[SerializeField] private bool _showCollisionStats = true;
|
||||
[SerializeField] private bool _showSpawnControls = true;
|
||||
[SerializeField] private bool _showBattleDurationControls = true;
|
||||
[SerializeField] private bool _showSeparationSolverControls = true;
|
||||
[SerializeField] private bool _showPlayerWeaponControls = true;
|
||||
[SerializeField] private bool _showPlayerHealthControls = true;
|
||||
[SerializeField] private bool _showTips = true;
|
||||
|
||||
private Rect _windowRect = new Rect(20f, 60f, 460f, 800f);
|
||||
private bool _isPanelVisible;
|
||||
private int _windowId;
|
||||
|
|
@ -85,20 +96,42 @@ namespace CustomComponent
|
|||
|
||||
private void DrawWindow(int windowId)
|
||||
{
|
||||
EnsurePropList();
|
||||
if (_showBuffSection)
|
||||
{
|
||||
EnsurePropList();
|
||||
}
|
||||
|
||||
GUILayout.BeginVertical();
|
||||
|
||||
DrawBuffSection();
|
||||
bool hasPreviousSection = false;
|
||||
if (_showBuffSection)
|
||||
{
|
||||
DrawBuffSection();
|
||||
hasPreviousSection = true;
|
||||
}
|
||||
|
||||
GUILayout.Space(8f);
|
||||
GUILayout.Label(string.Empty, GUI.skin.horizontalSlider);
|
||||
GUILayout.Space(8f);
|
||||
if (HasVisibleBattleSection())
|
||||
{
|
||||
if (hasPreviousSection)
|
||||
{
|
||||
GUILayout.Space(8f);
|
||||
GUILayout.Label(string.Empty, GUI.skin.horizontalSlider);
|
||||
GUILayout.Space(8f);
|
||||
}
|
||||
|
||||
DrawBattleSection();
|
||||
DrawBattleSection();
|
||||
hasPreviousSection = true;
|
||||
}
|
||||
|
||||
GUILayout.Space(8f);
|
||||
GUILayout.Label("Tips: press `F8` or tap top-left corner 3 times to toggle.", GUILayout.Height(20f));
|
||||
if (_showTips)
|
||||
{
|
||||
if (hasPreviousSection)
|
||||
{
|
||||
GUILayout.Space(8f);
|
||||
}
|
||||
|
||||
GUILayout.Label("Tips: press `F8` or tap top-left corner 3 times to toggle.", GUILayout.Height(20f));
|
||||
}
|
||||
|
||||
GUILayout.EndVertical();
|
||||
GUI.DragWindow(new Rect(0, 0, 10000, 22));
|
||||
|
|
@ -169,12 +202,15 @@ namespace CustomComponent
|
|||
return;
|
||||
}
|
||||
|
||||
GUILayout.Label($"Spawn Rate: {enemyManager.SpawnRateScale:F2}");
|
||||
GUILayout.Label($"Battle Time: {enemyManager.ElapsedBattleTime:F1}s / {enemyManager.BattleDuration:F1}s");
|
||||
GUILayout.Label($"Enemy Count: {enemyManager.CurrentEnemyCount}");
|
||||
if (_showBattleOverview)
|
||||
{
|
||||
GUILayout.Label($"Spawn Rate: {enemyManager.SpawnRateScale:F2}");
|
||||
GUILayout.Label($"Battle Time: {enemyManager.ElapsedBattleTime:F1}s / {enemyManager.BattleDuration:F1}s");
|
||||
GUILayout.Label($"Enemy Count: {enemyManager.CurrentEnemyCount}");
|
||||
}
|
||||
|
||||
Simulation.SimulationWorld simulationWorld = GameEntry.SimulationWorld;
|
||||
if (simulationWorld != null)
|
||||
if (_showCollisionStats && simulationWorld != null)
|
||||
{
|
||||
GUILayout.Space(4f);
|
||||
GUILayout.Label(
|
||||
|
|
@ -196,104 +232,130 @@ namespace CustomComponent
|
|||
}
|
||||
}
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Rate", GUILayout.Width(52f));
|
||||
string rateText = GUILayout.TextField(_spawnRateScaleInput.ToString("F2"), GUILayout.Width(60f));
|
||||
if (float.TryParse(rateText, out float parsedRate))
|
||||
if (_showSpawnControls)
|
||||
{
|
||||
_spawnRateScaleInput = Mathf.Clamp(parsedRate, MinSpawnRate, 50f);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Apply", GUILayout.Width(70f)))
|
||||
{
|
||||
enemyManager.SetSpawnRateScale(_spawnRateScaleInput);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("x0.5", GUILayout.Width(60f)))
|
||||
{
|
||||
_spawnRateScaleInput = Mathf.Max(MinSpawnRate, enemyManager.SpawnRateScale * 0.5f);
|
||||
enemyManager.SetSpawnRateScale(_spawnRateScaleInput);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("x2", GUILayout.Width(60f)))
|
||||
{
|
||||
_spawnRateScaleInput = enemyManager.SpawnRateScale * 2f;
|
||||
enemyManager.SetSpawnRateScale(_spawnRateScaleInput);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Add Sec", GUILayout.Width(52f));
|
||||
string durationText = GUILayout.TextField(_extendDurationSeconds.ToString("F0"), GUILayout.Width(60f));
|
||||
if (float.TryParse(durationText, out float parsedDuration))
|
||||
{
|
||||
_extendDurationSeconds = Mathf.Clamp(parsedDuration, 1f, 3600f);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Extend Battle", GUILayout.Height(24f)))
|
||||
{
|
||||
if (procedure.CurrentGameState is GameStateBattle gameState)
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Rate", GUILayout.Width(52f));
|
||||
string rateText = GUILayout.TextField(_spawnRateScaleInput.ToString("F2"), GUILayout.Width(60f));
|
||||
if (float.TryParse(rateText, out float parsedRate))
|
||||
{
|
||||
gameState.AddBattleDuration(_extendDurationSeconds);
|
||||
_spawnRateScaleInput = Mathf.Clamp(parsedRate, MinSpawnRate, 50f);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(4f);
|
||||
GUILayout.Label($"Enemy Separation Solver: {EnemySeparationSolverProvider.CurrentSolverName}");
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Use Naive O(N^2)", GUILayout.Height(24f)))
|
||||
{
|
||||
EnemySeparationSolverProvider.UseNaiveSolver();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Use Grid Bucket", GUILayout.Height(24f)))
|
||||
{
|
||||
EnemySeparationSolverProvider.UseGridBucketSolver();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Label(
|
||||
$"Player Weapon: {(player == null ? "Player not found" : (player.WeaponEnabled ? "Enabled" : "Disabled"))}");
|
||||
GUILayout.BeginHorizontal();
|
||||
GUI.enabled = player != null;
|
||||
if (GUILayout.Button("Disable Weapons", GUILayout.Height(24f)))
|
||||
{
|
||||
player.SetWeaponEnabled(false);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Enable Weapons", GUILayout.Height(24f)))
|
||||
{
|
||||
player.SetWeaponEnabled(true);
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
GUILayout.EndHorizontal();
|
||||
|
||||
GUILayout.Space(4f);
|
||||
GUILayout.Label(
|
||||
$"Player HP: {(playerHealth == null ? "Unavailable" : $"{playerHealth.CurrentHealth}/{playerHealth.MaxHealth}")}");
|
||||
GUILayout.BeginHorizontal();
|
||||
GUI.enabled = playerHealth != null;
|
||||
if (GUILayout.Button($"+{DebugHealAmount} HP", GUILayout.Height(24f)))
|
||||
{
|
||||
AddPlayerHealth(playerHealth, DebugHealAmount);
|
||||
}
|
||||
|
||||
if (GUILayout.Button(_lockPlayerHealthToMax ? "GodMode: ON" : "GodMode: OFF", GUILayout.Height(24f)))
|
||||
{
|
||||
_lockPlayerHealthToMax = !_lockPlayerHealthToMax;
|
||||
if (_lockPlayerHealthToMax)
|
||||
if (GUILayout.Button("Apply", GUILayout.Width(70f)))
|
||||
{
|
||||
RestorePlayerHealthToMax(playerHealth);
|
||||
enemyManager.SetSpawnRateScale(_spawnRateScaleInput);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("x0.5", GUILayout.Width(60f)))
|
||||
{
|
||||
_spawnRateScaleInput = Mathf.Max(MinSpawnRate, enemyManager.SpawnRateScale * 0.5f);
|
||||
enemyManager.SetSpawnRateScale(_spawnRateScaleInput);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("x2", GUILayout.Width(60f)))
|
||||
{
|
||||
_spawnRateScaleInput = enemyManager.SpawnRateScale * 2f;
|
||||
enemyManager.SetSpawnRateScale(_spawnRateScaleInput);
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
GUILayout.EndHorizontal();
|
||||
if (_showBattleDurationControls)
|
||||
{
|
||||
GUILayout.BeginHorizontal();
|
||||
GUILayout.Label("Add Sec", GUILayout.Width(52f));
|
||||
string durationText = GUILayout.TextField(_extendDurationSeconds.ToString("F0"), GUILayout.Width(60f));
|
||||
if (float.TryParse(durationText, out float parsedDuration))
|
||||
{
|
||||
_extendDurationSeconds = Mathf.Clamp(parsedDuration, 1f, 3600f);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Extend Battle", GUILayout.Height(24f)))
|
||||
{
|
||||
if (procedure.CurrentGameState is GameStateBattle gameState)
|
||||
{
|
||||
gameState.AddBattleDuration(_extendDurationSeconds);
|
||||
}
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (_showSeparationSolverControls)
|
||||
{
|
||||
GUILayout.Space(4f);
|
||||
GUILayout.Label($"Enemy Separation Solver: {EnemySeparationSolverProvider.CurrentSolverName}");
|
||||
GUILayout.BeginHorizontal();
|
||||
if (GUILayout.Button("Use Naive O(N^2)", GUILayout.Height(24f)))
|
||||
{
|
||||
EnemySeparationSolverProvider.UseNaiveSolver();
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Use Grid Bucket", GUILayout.Height(24f)))
|
||||
{
|
||||
EnemySeparationSolverProvider.UseGridBucketSolver();
|
||||
}
|
||||
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (_showPlayerWeaponControls)
|
||||
{
|
||||
GUILayout.Label(
|
||||
$"Player Weapon: {(player == null ? "Player not found" : (player.WeaponEnabled ? "Enabled" : "Disabled"))}");
|
||||
GUILayout.BeginHorizontal();
|
||||
GUI.enabled = player != null;
|
||||
if (GUILayout.Button("Disable Weapons", GUILayout.Height(24f)))
|
||||
{
|
||||
player.SetWeaponEnabled(false);
|
||||
}
|
||||
|
||||
if (GUILayout.Button("Enable Weapons", GUILayout.Height(24f)))
|
||||
{
|
||||
player.SetWeaponEnabled(true);
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
|
||||
if (_showPlayerHealthControls)
|
||||
{
|
||||
GUILayout.Space(4f);
|
||||
GUILayout.Label(
|
||||
$"Player HP: {(playerHealth == null ? "Unavailable" : $"{playerHealth.CurrentHealth}/{playerHealth.MaxHealth}")}");
|
||||
GUILayout.BeginHorizontal();
|
||||
GUI.enabled = playerHealth != null;
|
||||
if (GUILayout.Button($"+{DebugHealAmount} HP", GUILayout.Height(24f)))
|
||||
{
|
||||
AddPlayerHealth(playerHealth, DebugHealAmount);
|
||||
}
|
||||
|
||||
if (GUILayout.Button(_lockPlayerHealthToMax ? "GodMode: ON" : "GodMode: OFF", GUILayout.Height(24f)))
|
||||
{
|
||||
_lockPlayerHealthToMax = !_lockPlayerHealthToMax;
|
||||
if (_lockPlayerHealthToMax)
|
||||
{
|
||||
RestorePlayerHealthToMax(playerHealth);
|
||||
}
|
||||
}
|
||||
|
||||
GUI.enabled = true;
|
||||
GUILayout.EndHorizontal();
|
||||
}
|
||||
}
|
||||
|
||||
private bool HasVisibleBattleSection()
|
||||
{
|
||||
return _showBattleOverview ||
|
||||
_showCollisionStats ||
|
||||
_showSpawnControls ||
|
||||
_showBattleDurationControls ||
|
||||
_showSeparationSolverControls ||
|
||||
_showPlayerWeaponControls ||
|
||||
_showPlayerHealthControls;
|
||||
}
|
||||
|
||||
private void EnsurePropList(bool force = false)
|
||||
|
|
|
|||
|
|
@ -0,0 +1,20 @@
|
|||
{
|
||||
"name": "VampireLike.Editor",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"VampireLike",
|
||||
"UnityGameFramework.Runtime",
|
||||
"UnityGameFramework.Editor"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 9b0d24fd3a44b6f45b3794cdfefd1ac0
|
||||
DefaultImporter:
|
||||
guid: 602d791ab1251f74ca2470c53bf382a3
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
|
@ -1,19 +1,12 @@
|
|||
//------------------------------------------------------------
|
||||
// Game Framework
|
||||
// Copyright © 2013-2021 Jiang Yin. All rights reserved.
|
||||
// Homepage: https://gameframework.cn/
|
||||
// Feedback: mailto:ellan@gameframework.cn
|
||||
//------------------------------------------------------------
|
||||
|
||||
using GameFramework;
|
||||
using GameFramework;
|
||||
using System.IO;
|
||||
using UnityEditor;
|
||||
using UnityEngine;
|
||||
using UnityGameFramework.Editor.ResourceTools;
|
||||
|
||||
namespace StarForce.Editor
|
||||
namespace VampireLike.Editor
|
||||
{
|
||||
public sealed class StarForceBuildEventHandler : IBuildEventHandler
|
||||
public sealed class VampireLikeBuildEventHandler : IBuildEventHandler
|
||||
{
|
||||
public bool ContinueOnFailure
|
||||
{
|
||||
|
|
@ -1,8 +1,7 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 64311189c3f9ae140b59a31db9831950
|
||||
timeCreated: 1528026151
|
||||
licenseType: Pro
|
||||
MonoImporter:
|
||||
externalObjects: {}
|
||||
serializedVersion: 2
|
||||
defaultReferences: []
|
||||
executionOrder: 0
|
||||
|
|
@ -0,0 +1,23 @@
|
|||
{
|
||||
"name": "VampireLike",
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"GUID:363c5eb08ff8e6a439b85e37b8c20d96",
|
||||
"GUID:a2d8a19598eca814496b089021d08d60",
|
||||
"GUID:75469ad4d38634e559750d17036d5f7c",
|
||||
"GUID:d8b63aba1907145bea998dd612889d6b",
|
||||
"GUID:6055be8ebefd69e48b49212b09b47b2f",
|
||||
"GUID:e0cd26848372d4e5c891c569017e11f1",
|
||||
"GUID:2665a8d13d1b3f18800f46e256720795",
|
||||
"GUID:fca0f81bc71f1944887dd65f134c54a0"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": false,
|
||||
"precompiledReferences": [],
|
||||
"autoReferenced": true,
|
||||
"defineConstraints": [],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 0372088d74296e44c9eb9185a2d4021e
|
||||
DefaultImporter:
|
||||
guid: 47a82ffa13c291447ab895cd0bc251cd
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
|
@ -390,7 +390,7 @@ PrefabInstance:
|
|||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_AvailableProcedureTypeNames.Array.size
|
||||
value: 12
|
||||
value: 13
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_AvailableProcedureTypeNames.Array.data[0]
|
||||
|
|
@ -430,15 +430,15 @@ PrefabInstance:
|
|||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_AvailableProcedureTypeNames.Array.data[9]
|
||||
value: Procedure.ProcedureUpdateResources
|
||||
value: Procedure.ProcedureStressTest
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_AvailableProcedureTypeNames.Array.data[10]
|
||||
value: Procedure.ProcedureUpdateVersion
|
||||
value: Procedure.ProcedureUpdateResources
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_AvailableProcedureTypeNames.Array.data[11]
|
||||
value: Procedure.ProcedureVerifyResources
|
||||
value: Procedure.ProcedureUpdateVersion
|
||||
objectReference: {fileID: 0}
|
||||
- target: {fileID: 11405216, guid: adb3eb1c35fcff14f89fba7b05c9d71c, type: 3}
|
||||
propertyPath: m_AvailableProcedureTypeNames.Array.data[12]
|
||||
|
|
@ -848,6 +848,15 @@ MonoBehaviour:
|
|||
m_Script: {fileID: 11500000, guid: 1d8ada5157a04921a6e543a040e57960, type: 3}
|
||||
m_Name:
|
||||
m_EditorClassIdentifier:
|
||||
_showBuffSection: 0
|
||||
_showBattleOverview: 0
|
||||
_showCollisionStats: 0
|
||||
_showSpawnControls: 1
|
||||
_showBattleDurationControls: 1
|
||||
_showSeparationSolverControls: 0
|
||||
_showPlayerWeaponControls: 1
|
||||
_showPlayerHealthControls: 1
|
||||
_showTips: 0
|
||||
--- !u!1 &513208572
|
||||
GameObject:
|
||||
m_ObjectHideFlags: 0
|
||||
|
|
|
|||
|
|
@ -0,0 +1,3 @@
|
|||
{
|
||||
"name": "DOTween.Modules"
|
||||
}
|
||||
|
|
@ -1,6 +1,6 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a5e646a0b90b55940be09d61810d429d
|
||||
DefaultImporter:
|
||||
guid: fca0f81bc71f1944887dd65f134c54a0
|
||||
AssemblyDefinitionImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
|
|
@ -49,6 +49,6 @@ MonoBehaviour:
|
|||
deAudioEnabled: 0
|
||||
deUnityExtendedEnabled: 0
|
||||
epoOutlineEnabled: 0
|
||||
createASMDEF: 0
|
||||
createASMDEF: 1
|
||||
showPlayingTweens: 0
|
||||
showPausedTweens: 0
|
||||
|
|
|
|||
|
|
@ -1,9 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: fa53b8776f6a8ce4598fe035cb4356b8
|
||||
folderAsset: yes
|
||||
timeCreated: 1528026174
|
||||
licenseType: Pro
|
||||
DefaultImporter:
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: a7d40db10aa401f4db624fec03b19854
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ff394cf6a35932247b0649240bbbd5fc
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 1b6ba43d50137a44a9cac13aee7c79b4
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: b692b20b915b5384bb238bbe1e86f6c8
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,8 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: aa252b664de661c40bee3ddc89dfc7e0
|
||||
folderAsset: yes
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: ccdf2a9817ba952488f12dadb5e278c6
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
Binary file not shown.
|
|
@ -1,7 +0,0 @@
|
|||
fileFormatVersion: 2
|
||||
guid: 74423cdaf48700645bc031c80e5b3fc7
|
||||
DefaultImporter:
|
||||
externalObjects: {}
|
||||
userData:
|
||||
assetBundleName:
|
||||
assetBundleVariant:
|
||||
|
|
@ -1,11 +1,26 @@
|
|||
{
|
||||
"name": "Simulation.EditModeTests",
|
||||
"references": [],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"UnityGameFramework.Runtime",
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"VampireLike"
|
||||
],
|
||||
"includePlatforms": [
|
||||
"Editor"
|
||||
],
|
||||
"excludePlatforms": []
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll",
|
||||
"GameFramework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -3,13 +3,16 @@ using System.Collections.Generic;
|
|||
using System.Reflection;
|
||||
using NUnit.Framework;
|
||||
using UnityEngine;
|
||||
using Procedure;
|
||||
using GameFramework.Fsm;
|
||||
using GameFramework.Procedure;
|
||||
using Object = UnityEngine.Object;
|
||||
|
||||
namespace Simulation.Tests.Editor
|
||||
{
|
||||
public class SimulationWorldTickTests
|
||||
{
|
||||
private const string GameAssemblyName = "Assembly-CSharp";
|
||||
private const string GameAssemblyName = "VampireLike";
|
||||
private const string RuntimeAssemblyName = "UnityGameFramework.Runtime";
|
||||
private const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
|
||||
private const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
|
||||
|
|
@ -28,6 +31,9 @@ namespace Simulation.Tests.Editor
|
|||
private static readonly System.Type ProjectileSimDataType =
|
||||
System.Type.GetType($"Simulation.ProjectileSimData, {GameAssemblyName}");
|
||||
|
||||
private static readonly System.Type PickupSimDataType =
|
||||
System.Type.GetType($"Simulation.PickupSimData, {GameAssemblyName}");
|
||||
|
||||
private static readonly System.Type EnemyProjectileType =
|
||||
System.Type.GetType($"Entity.EnemyProjectile, {GameAssemblyName}");
|
||||
|
||||
|
|
@ -88,6 +94,12 @@ namespace Simulation.Tests.Editor
|
|||
private static readonly MethodInfo RemoveProjectileByEntityIdMethod =
|
||||
SimulationWorldType?.GetMethod("RemoveProjectileByEntityId", NonPublicInstance);
|
||||
|
||||
private static readonly MethodInfo UpsertPickupMethod =
|
||||
SimulationWorldType?.GetMethod("UpsertPickup", NonPublicInstance);
|
||||
|
||||
private static readonly MethodInfo RemovePickupByEntityIdMethod =
|
||||
SimulationWorldType?.GetMethod("RemovePickupByEntityId", NonPublicInstance);
|
||||
|
||||
private static readonly MethodInfo TryGetEnemyDataMethod =
|
||||
SimulationWorldType?.GetMethod("TryGetEnemyData", NonPublicInstance);
|
||||
|
||||
|
|
@ -124,6 +136,9 @@ namespace Simulation.Tests.Editor
|
|||
private static readonly PropertyInfo ProjectilesProperty =
|
||||
SimulationWorldType?.GetProperty("Projectiles", PublicInstance);
|
||||
|
||||
private static readonly PropertyInfo PickupsProperty =
|
||||
SimulationWorldType?.GetProperty("Pickups", PublicInstance);
|
||||
|
||||
private static readonly PropertyInfo CollisionCandidateCountProperty =
|
||||
SimulationWorldType?.GetProperty("CollisionCandidateCount", PublicInstance);
|
||||
|
||||
|
|
@ -197,6 +212,7 @@ namespace Simulation.Tests.Editor
|
|||
Assert.NotNull(SimulationTickContextType, "SimulationTickContext type lookup failed.");
|
||||
Assert.NotNull(EnemySimDataType, "EnemySimData type lookup failed.");
|
||||
Assert.NotNull(ProjectileSimDataType, "ProjectileSimData type lookup failed.");
|
||||
Assert.NotNull(PickupSimDataType, "PickupSimData type lookup failed.");
|
||||
Assert.NotNull(EnemyProjectileType, "EnemyProjectile type lookup failed.");
|
||||
Assert.NotNull(EnemyProjectileDataType, "EnemyProjectileData type lookup failed.");
|
||||
Assert.NotNull(CampTypeType, "CampType type lookup failed.");
|
||||
|
|
@ -217,6 +233,8 @@ namespace Simulation.Tests.Editor
|
|||
Assert.NotNull(RemoveEnemyByEntityIdMethod, "RemoveEnemyByEntityId reflection lookup failed.");
|
||||
Assert.NotNull(UpsertProjectileMethod, "UpsertProjectile reflection lookup failed.");
|
||||
Assert.NotNull(RemoveProjectileByEntityIdMethod, "RemoveProjectileByEntityId reflection lookup failed.");
|
||||
Assert.NotNull(UpsertPickupMethod, "UpsertPickup reflection lookup failed.");
|
||||
Assert.NotNull(RemovePickupByEntityIdMethod, "RemovePickupByEntityId reflection lookup failed.");
|
||||
Assert.NotNull(TryGetEnemyDataMethod, "TryGetEnemyData reflection lookup failed.");
|
||||
Assert.NotNull(TickMethod, "Tick reflection lookup failed.");
|
||||
Assert.NotNull(TryGetNearestEnemyEntityIdMethod, "TryGetNearestEnemyEntityId reflection lookup failed.");
|
||||
|
|
@ -225,6 +243,7 @@ namespace Simulation.Tests.Editor
|
|||
Assert.NotNull(UseGridBucketSolverMethod, "UseGridBucketSolver reflection lookup failed.");
|
||||
Assert.NotNull(EnemiesProperty, "Enemies property reflection lookup failed.");
|
||||
Assert.NotNull(ProjectilesProperty, "Projectiles property reflection lookup failed.");
|
||||
Assert.NotNull(PickupsProperty, "Pickups property reflection lookup failed.");
|
||||
Assert.NotNull(CollisionCandidateCountProperty, "CollisionCandidateCount property reflection lookup failed.");
|
||||
Assert.NotNull(UseSimulationMovementProperty, "UseSimulationMovement property reflection lookup failed.");
|
||||
Assert.NotNull(UseSimulationMovementField, "_useSimulationMovement field reflection lookup failed.");
|
||||
|
|
@ -710,6 +729,80 @@ namespace Simulation.Tests.Editor
|
|||
Assert.That(GetLastResolvedAreaHitCount(), Is.EqualTo(0));
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void ProcedureGame_TransitionsBattleToLevelUpShopAndBackToBattle()
|
||||
{
|
||||
var procedureGame = (ProcedureGame)Activator.CreateInstance(ProcedureGameType);
|
||||
GameObject playerObject = new GameObject("ProcedureGameTransitionPlayer");
|
||||
try
|
||||
{
|
||||
var player = playerObject.AddComponent(PlayerType);
|
||||
Assert.NotNull(player);
|
||||
PlayerType.GetProperty("PendingLevelPoints", PublicInstance)?.SetValue(player, 1);
|
||||
ProcedureGameType.GetField("Player", PublicInstance)?.SetValue(procedureGame, player);
|
||||
|
||||
var battleState = new TrackingGameState(GameStateType.Battle);
|
||||
var levelUpState = new TrackingGameState(GameStateType.LevelUp);
|
||||
var shopState = new TrackingGameState(GameStateType.Shop);
|
||||
var gameStates = new Dictionary<GameStateType, GameStateBase>
|
||||
{
|
||||
{ GameStateType.Battle, battleState },
|
||||
{ GameStateType.LevelUp, levelUpState },
|
||||
{ GameStateType.Shop, shopState },
|
||||
};
|
||||
|
||||
SetPrivateField(procedureGame, "_gameStates", gameStates);
|
||||
SetPrivateField(procedureGame, "_currentGameState", GameStateType.Battle);
|
||||
SetPrivateField(procedureGame, "_procedureOwner", null);
|
||||
|
||||
procedureGame.BattleToShopOrLevelUp();
|
||||
Assert.That(procedureGame.CurrentLevel, Is.EqualTo(2));
|
||||
Assert.That(procedureGame.CurrentGameStateType, Is.EqualTo(GameStateType.LevelUp));
|
||||
Assert.That(battleState.LeaveCount, Is.EqualTo(1));
|
||||
Assert.That(levelUpState.EnterCount, Is.EqualTo(1));
|
||||
|
||||
PlayerType.GetProperty("PendingLevelPoints", PublicInstance)?.SetValue(player, 0);
|
||||
procedureGame.LevelUpToShop();
|
||||
Assert.That(procedureGame.CurrentGameStateType, Is.EqualTo(GameStateType.Shop));
|
||||
Assert.That(levelUpState.LeaveCount, Is.EqualTo(1));
|
||||
Assert.That(shopState.EnterCount, Is.EqualTo(1));
|
||||
|
||||
procedureGame.ShopToBattle();
|
||||
Assert.That(procedureGame.CurrentGameStateType, Is.EqualTo(GameStateType.Battle));
|
||||
Assert.That(shopState.LeaveCount, Is.EqualTo(1));
|
||||
Assert.That(battleState.EnterCount, Is.EqualTo(1));
|
||||
}
|
||||
finally
|
||||
{
|
||||
Object.DestroyImmediate(playerObject);
|
||||
}
|
||||
}
|
||||
|
||||
[Test]
|
||||
public void PickupLifecycle_UpsertAndRemove_KeepsBindingsConsistent()
|
||||
{
|
||||
UpsertPickup(CreatePickup(entityId: 6101, position: new Vector3(1f, 0f, 0f), pickupRadius: 0.35f, state: 0));
|
||||
UpsertPickup(CreatePickup(entityId: 6102, position: new Vector3(2f, 0f, 0f), pickupRadius: 0.35f, state: 0));
|
||||
UpsertPickup(CreatePickup(entityId: 6103, position: new Vector3(3f, 0f, 0f), pickupRadius: 0.35f, state: 0));
|
||||
|
||||
Assert.That(GetPickupsCount(), Is.EqualTo(3));
|
||||
|
||||
UpsertPickup(CreatePickup(entityId: 6101, position: new Vector3(10f, 0f, 0f), pickupRadius: 0.5f, state: 1));
|
||||
Assert.That(GetPickupsCount(), Is.EqualTo(3));
|
||||
object updatedPickup = GetPickupAt(0);
|
||||
Assert.That((int)GetField(updatedPickup, "EntityId"), Is.EqualTo(6101));
|
||||
Assert.That(((Vector3)GetField(updatedPickup, "Position")).x, Is.EqualTo(10f).Within(0.0001f));
|
||||
Assert.That((float)GetField(updatedPickup, "PickupRadius"), Is.EqualTo(0.5f).Within(0.0001f));
|
||||
|
||||
bool removedMiddle = RemovePickupByEntityId(6102);
|
||||
bool removedMoved = RemovePickupByEntityId(6103);
|
||||
|
||||
Assert.IsTrue(removedMiddle);
|
||||
Assert.That(GetPickupsCount(), Is.EqualTo(1));
|
||||
Assert.IsTrue(removedMoved);
|
||||
Assert.That((int)GetField(GetPickupAt(0), "EntityId"), Is.EqualTo(6101));
|
||||
}
|
||||
|
||||
private object CreateEnemy(int entityId, Vector3 position, float speed, float attackRange,
|
||||
bool avoidEnemyOverlap = false, float enemyBodyRadius = 0.45f, int separationIterations = 1)
|
||||
{
|
||||
|
|
@ -746,6 +839,16 @@ namespace Simulation.Tests.Editor
|
|||
return projectile;
|
||||
}
|
||||
|
||||
private object CreatePickup(int entityId, Vector3 position, float pickupRadius, int state)
|
||||
{
|
||||
object pickup = Activator.CreateInstance(PickupSimDataType);
|
||||
SetField(ref pickup, "EntityId", entityId);
|
||||
SetField(ref pickup, "Position", position);
|
||||
SetField(ref pickup, "PickupRadius", pickupRadius);
|
||||
SetField(ref pickup, "State", state);
|
||||
return pickup;
|
||||
}
|
||||
|
||||
private void InvokeTick(float deltaTime, float realDeltaTime, Vector3 playerPosition)
|
||||
{
|
||||
object tickContext = System.Activator.CreateInstance(
|
||||
|
|
@ -773,6 +876,11 @@ namespace Simulation.Tests.Editor
|
|||
UpsertProjectileMethod.Invoke(_worldComponent, new[] { projectile });
|
||||
}
|
||||
|
||||
private void UpsertPickup(object pickup)
|
||||
{
|
||||
UpsertPickupMethod.Invoke(_worldComponent, new[] { pickup });
|
||||
}
|
||||
|
||||
private bool RemoveEnemyByEntityId(int entityId)
|
||||
{
|
||||
return (bool)RemoveEnemyByEntityIdMethod.Invoke(_worldComponent, new object[] { entityId });
|
||||
|
|
@ -783,6 +891,11 @@ namespace Simulation.Tests.Editor
|
|||
return (bool)RemoveProjectileByEntityIdMethod.Invoke(_worldComponent, new object[] { entityId });
|
||||
}
|
||||
|
||||
private bool RemovePickupByEntityId(int entityId)
|
||||
{
|
||||
return (bool)RemovePickupByEntityIdMethod.Invoke(_worldComponent, new object[] { entityId });
|
||||
}
|
||||
|
||||
private static object GetGameEntrySimulationWorld()
|
||||
{
|
||||
return GameEntryGetSimulationWorldMethod.Invoke(null, null);
|
||||
|
|
@ -856,6 +969,20 @@ namespace Simulation.Tests.Editor
|
|||
return (int)countProperty.GetValue(projectiles);
|
||||
}
|
||||
|
||||
private object GetPickupAt(int index)
|
||||
{
|
||||
object pickups = PickupsProperty.GetValue(_worldComponent);
|
||||
PropertyInfo itemProperty = pickups.GetType().GetProperty("Item", PublicInstance);
|
||||
return itemProperty.GetValue(pickups, new object[] { index });
|
||||
}
|
||||
|
||||
private int GetPickupsCount()
|
||||
{
|
||||
object pickups = PickupsProperty.GetValue(_worldComponent);
|
||||
PropertyInfo countProperty = pickups.GetType().GetProperty("Count", PublicInstance);
|
||||
return (int)countProperty.GetValue(pickups);
|
||||
}
|
||||
|
||||
private int GetCollisionCandidateCount()
|
||||
{
|
||||
return (int)CollisionCandidateCountProperty.GetValue(_worldComponent);
|
||||
|
|
@ -895,5 +1022,42 @@ namespace Simulation.Tests.Editor
|
|||
|
||||
Assert.Fail($"Field '{fieldName}' was not found on type '{target.GetType().FullName}'.");
|
||||
}
|
||||
|
||||
private sealed class TrackingGameState : GameStateBase
|
||||
{
|
||||
public TrackingGameState(GameStateType gameStateType)
|
||||
{
|
||||
GameStateType = gameStateType;
|
||||
}
|
||||
|
||||
public override GameStateType GameStateType { get; }
|
||||
|
||||
public int EnterCount { get; private set; }
|
||||
|
||||
public int LeaveCount { get; private set; }
|
||||
|
||||
public override void OnInit(ProcedureGame master)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnEnter(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
EnterCount++;
|
||||
}
|
||||
|
||||
public override void OnUpdate(IFsm<IProcedureManager> procedureOwner, float elapseSeconds,
|
||||
float realElapseSeconds)
|
||||
{
|
||||
}
|
||||
|
||||
public override void OnLeave(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
LeaveCount++;
|
||||
}
|
||||
|
||||
public override void OnDestroy(IFsm<IProcedureManager> procedureOwner)
|
||||
{
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -1,9 +1,24 @@
|
|||
{
|
||||
"name": "Simulation.PlayModeTests",
|
||||
"references": [],
|
||||
"optionalUnityReferences": [
|
||||
"TestAssemblies"
|
||||
"rootNamespace": "",
|
||||
"references": [
|
||||
"UnityGameFramework.Runtime",
|
||||
"UnityEngine.TestRunner",
|
||||
"UnityEditor.TestRunner",
|
||||
"VampireLike"
|
||||
],
|
||||
"includePlatforms": [],
|
||||
"excludePlatforms": []
|
||||
"excludePlatforms": [],
|
||||
"allowUnsafeCode": false,
|
||||
"overrideReferences": true,
|
||||
"precompiledReferences": [
|
||||
"nunit.framework.dll",
|
||||
"GameFramework.dll"
|
||||
],
|
||||
"autoReferenced": false,
|
||||
"defineConstraints": [
|
||||
"UNITY_INCLUDE_TESTS"
|
||||
],
|
||||
"versionDefines": [],
|
||||
"noEngineReferences": false
|
||||
}
|
||||
|
|
|
|||
|
|
@ -11,7 +11,7 @@ namespace Simulation.Tests.PlayMode
|
|||
{
|
||||
public class SimulationWorldPlayModeTests
|
||||
{
|
||||
private const string GameAssemblyName = "Assembly-CSharp";
|
||||
private const string GameAssemblyName = "VampireLike";
|
||||
private const string RuntimeAssemblyName = "UnityGameFramework.Runtime";
|
||||
private const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
|
||||
private const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
|
||||
|
|
|
|||
|
|
@ -4,7 +4,7 @@
|
|||
本文件用于对齐 `docs/TodoList.md` 的 P2 Checkpoint 9,作为 P2 结项与 P3 输入基线。
|
||||
|
||||
目标:
|
||||
- 固化压测口径(1k/2k/3k)
|
||||
- 固化压测口径(0.5k/1k/1.5k/2k)
|
||||
- 给出回归验证结论
|
||||
- 给出开关/回滚策略
|
||||
- 给出最终验收判定(通过/不通过)
|
||||
|
|
@ -12,7 +12,7 @@
|
|||
## 2. 验收标准(对齐 TodoList)
|
||||
来源:`docs/TodoList.md` 第 171~179 行。
|
||||
|
||||
- 在 `3k` 敌人规模下,CPU Main Thread 明显下降(目标 `>= 30%`)。
|
||||
- 在 `2k` 敌人规模下,CPU Main Thread 明显下降(目标 `>= 30%`)。
|
||||
- Profiler 中战斗帧 `GC Alloc` 接近 `0`(持续帧)。
|
||||
|
||||
## 3. 测试设备与环境
|
||||
|
|
@ -44,18 +44,46 @@
|
|||
| 用例 | 目标 | 状态 | 证据 |
|
||||
|------------------------------------------|--------------|----|----|
|
||||
| 10 分钟连续战斗 | 无异常日志、流程稳定 | 待补 | 待补 |
|
||||
| `Battle -> LevelUp -> Shop -> Battle` 循环 | 状态切换稳定、无卡死 | 待补 | 待补 |
|
||||
| 掉落拾取链路 | 掉落生成/吸附/回收正常 | 待补 | 待补 |
|
||||
| `Battle -> LevelUp -> Shop -> Battle` 循环 | 状态切换稳定、无卡死 | 通过 | `Logs/editmode-test-results.xml` |
|
||||
| 掉落拾取链路 | 掉落生成/吸附/回收正常 | 通过 | `Logs/editmode-test-results.xml` |
|
||||
|
||||
建议附证据:
|
||||
- `Logs/playmode-tests.log`
|
||||
- 关键流程录屏/截图
|
||||
- 回归脚本或人工步骤说明
|
||||
|
||||
### 5.1 回归记录模板
|
||||
|
||||
#### 用例 1:10 分钟连续战斗
|
||||
- 执行时间:待填
|
||||
- 场景/波次参数:待填
|
||||
- 运行开关:`UseSimulationMovement = true`,`UseJobSimulation = true`,`UseBurstJobs = true`
|
||||
- 结果:待填
|
||||
- 日志/录屏:待填
|
||||
- 备注:待填
|
||||
|
||||
#### 用例 2:`Battle -> LevelUp -> Shop -> Battle`
|
||||
- 执行时间:已执行,见 `Logs/editmode-test-results.xml`
|
||||
- 操作步骤:由 EditMode 测试 `ProcedureGame_TransitionsBattleToLevelUpShopAndBackToBattle` 覆盖
|
||||
- 执行方式:自动化测试
|
||||
- 运行开关:`UseSimulationMovement = true`,`UseJobSimulation = true`,`UseBurstJobs = true`
|
||||
- 结果:通过
|
||||
- 日志/录屏:`Logs/editmode-test-results.xml`
|
||||
- 备注:验证 `ProcedureGame` 可从 `Battle` 正确切换到 `LevelUp`、再到 `Shop`,并最终返回 `Battle`
|
||||
|
||||
#### 用例 3:掉落拾取链路
|
||||
- 执行时间:已执行,见 `Logs/editmode-test-results.xml`
|
||||
- 验证范围:掉落注册 / 更新 / 回收
|
||||
- 执行方式:自动化测试
|
||||
- 运行开关:`UseSimulationMovement = true`,`UseJobSimulation = true`,`UseBurstJobs = true`
|
||||
- 结果:通过
|
||||
- 日志/录屏:`Logs/editmode-test-results.xml`
|
||||
- 备注:由 EditMode 测试 `PickupLifecycle_UpsertAndRemove_KeepsBindingsConsistent` 覆盖,验证掉落在 `SimulationWorld` 中的生命周期与 binding remap 正常
|
||||
|
||||
## 6. 压测口径与数据
|
||||
|
||||
### 6.1 标准口径(必须覆盖)
|
||||
- 敌人规模:`1k / 2k / 3k`
|
||||
- 敌人规模:`0.5k / 1k / 1.5k / 2k`
|
||||
- 指标:
|
||||
- Main Thread (`ms`)
|
||||
- Job Workers (`ms`)
|
||||
|
|
@ -85,24 +113,64 @@
|
|||
| `1500` | 15.42 ms | 5.57 ms | -63.8% |
|
||||
| `2000` | 21.68 ms | 9.44 ms | -56.4% |
|
||||
|
||||
### 6.3 当前口径覆盖情况
|
||||
- 已覆盖敌人规模:`0.5k / 1k / 1.5k / 2k`
|
||||
- 已覆盖指标:CPU 热路径分阶段数据(`BuildInput / MoveSeparation / StateUpdate / Schedule / Complete / WriteBack`)
|
||||
- 待补指标:`Main Thread`、`Job Workers`、`GC Alloc`
|
||||
|
||||
### 6.4 待补验收数据模板
|
||||
|
||||
#### Main Thread / Job Workers / GC Alloc(P1.5 vs P2)
|
||||
| 敌人数量 | P1.5 Main Thread | P2 Main Thread | Main Thread 降幅 | P1.5 Job Workers | P2 Job Workers | P1.5 GC Alloc | P2 GC Alloc |
|
||||
|------|------------------:|---------------:|-----------------:|-----------------:|---------------:|--------------:|------------:|
|
||||
| `500` | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 |
|
||||
| `1000` | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 |
|
||||
| `1500` | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 |
|
||||
| `2000` | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 | 待填 |
|
||||
|
||||
#### 关键采样说明
|
||||
- 采样平台:Android 真机(与 P1.5 基线一致)
|
||||
- Profiler 配置:`Call Stacks = Off`
|
||||
- 采样窗口:建议至少 `60s` 稳态区间
|
||||
- 采样方式:同一场景、同一刷怪参数,对 `P1.5` 与 `P2` 分别采样
|
||||
- 结论口径:以 `2k` 作为最高压力场景进行最终验收
|
||||
|
||||
#### 6.4.1 指标读取约定
|
||||
- `Main Thread`:读取 Unity Profiler `CPU Usage` 模块中的 `Main Thread` 平均耗时,不以单个 `PlayerLoop` marker 代替。
|
||||
- `Job Workers`:作为辅助指标,记录稳定窗口内 `Job Worker` / `Worker Thread` 的忙碌情况。若线程分布零散,可填写平均观察值、典型区间,或在表中填“见 Profiler 截图”并附截图证据。
|
||||
- `GC Alloc`:读取持续帧 `GC Alloc`,优先记录稳定窗口内的典型值或平均值,目标为接近 `0 B/frame`。
|
||||
- `Main Thread 降幅`:以 `((P1.5 Main Thread - P2 Main Thread) / P1.5 Main Thread) * 100%` 计算。
|
||||
|
||||
#### 6.4.2 采样建议
|
||||
- `Main Thread` 与 `GC Alloc` 是 P2 验收的硬指标,优先保证这两项完整、可复现。
|
||||
- `Job Workers` 主要用于证明主要计算已迁移到 Worker Threads,不要求过度追求逐线程精确求和。
|
||||
- 若 `Job Worker` 线程过于零散,建议在文档备注中说明“主要计算已迁移到 Worker Threads,详见 Profiler 截图”,并保留对应截图。
|
||||
|
||||
## 7. 验收判定
|
||||
|
||||
| 验收项 | 标准 | 当前状态 | 判定 |
|
||||
|--------------------|----------|----------|-----|
|
||||
| Main Thread 降幅(2k) | `>= 30%` | 缺失 3k 数据 | 不通过 |
|
||||
| Main Thread 降幅(2k) | `>= 30%` | `P2 TickEnemies` 相比 `P1.5` 降低 `56.4%` | 通过 |
|
||||
| 持续帧 GC Alloc | 接近 0 | 缺失 GC 数据 | 不通过 |
|
||||
| 回归用例证据 | 三项用例可复现并留档 | 已完成 2/3,剩余 10 分钟连续战斗待补 | 不通过 |
|
||||
|
||||
**当前结论:P2 Checkpoint 9 暂不通过。**
|
||||
**当前结论:P2 Checkpoint 9 尚未完成。**
|
||||
|
||||
可确认部分:
|
||||
- P2 在 `500~2000` 规模的热路径 CPU 优化已显著成立。
|
||||
- 但未满足 TodoList 的完整验收口径(3k + GC + 回归证据)。
|
||||
- P2 在 `0.5k~2k` 规模的热路径 CPU 优化已显著成立。
|
||||
- `2k` 作为最高压力场景时,CPU 主线程降幅目标已满足。
|
||||
- 当前阻塞项仅剩 `GC Alloc` 验证与 `10 分钟连续战斗` 手测证据补齐。
|
||||
|
||||
## 8. 下一步补齐动作(建议)
|
||||
1. 按同一场景补采 `3k` 数据(P1.5 与 P2 各一次,至少 60s 稳态窗口)。
|
||||
2. 记录 `Main Thread / Job Workers / GC Alloc` 三项,写入 6.3 对应表。
|
||||
3. 完成 5.0 的三个回归用例并填入证据。
|
||||
4. 补齐后将第 7 节判定更新为“通过”,再在 `TodoList.md` 把 P2 Checkpoint 9 勾选。
|
||||
1. 按同一 `2k` 场景补采 `Main Thread / Job Workers / GC Alloc` 三项,并写入 6.3。
|
||||
2. 完成第 5 节剩余的 `10 分钟连续战斗` 回归,并补齐日志、录屏或步骤说明。
|
||||
3. 补齐后将第 7 节判定更新为“通过”,再在 `TodoList.md` 把 P2 Checkpoint 9 勾选。
|
||||
|
||||
### 8.1 完成后回写清单
|
||||
- 将 5.0 三个回归用例的“状态”统一改为“通过”或“不通过”。
|
||||
- 将 6.4 的 `Main Thread / Job Workers / GC Alloc` 实测数据填写完整。
|
||||
- 若 `2000` 敌人下 `Main Thread` 降幅仍 `>= 30%` 且 `GC Alloc` 接近 `0`,将第 7 节总结更新为“P2 Checkpoint 9 通过”。
|
||||
- 同步将 `docs/TodoList.md` 的 `Checkpoint 9` 由 `[ ]` 改为 `[x]`。
|
||||
|
||||
## 9. 测试命令(复用)
|
||||
- PlayMode:
|
||||
|
|
|
|||
|
|
@ -173,6 +173,7 @@
|
|||
- 压测口径:`0.5k / 1k / 1.5k / 2k` 敌人,记录 Main Thread、Job Workers、GC Alloc、关键 Marker。
|
||||
- 输出文档:`P2 Job/Burst 改造说明 + 开关/回滚策略 + 前后对比数据`。
|
||||
- 完成标准:结论可复现,可作为 P3 GPU Instancing 的输入基线。
|
||||
- 当前状态:`P2 TickEnemies` 在 `2k` 规模下相对 `P1.5` 已降至 `9.44 ms`(约 `-56.4%`),CPU 目标已满足;仍需补齐 `GC Alloc` 与三项回归证据后再勾选。
|
||||
|
||||
**验收标准**
|
||||
- 在 2k 敌人规模下,CPU Main Thread 明显下降(目标 >= 30%)。
|
||||
|
|
|
|||
Loading…
Reference in New Issue