Skip to content

Commit 4b71443

Browse files
committed
fix: oveflow, rename
1 parent 8b030ed commit 4b71443

File tree

13 files changed

+184
-207
lines changed

13 files changed

+184
-207
lines changed

Assets/UnityBox.unity

Lines changed: 30 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -17206,41 +17206,14 @@ GameObject:
1720617206
- component: {fileID: 1679610430}
1720717207
- component: {fileID: 1679610429}
1720817208
- component: {fileID: 1679610428}
17209-
- component: {fileID: 1679610427}
17209+
- component: {fileID: 1679610432}
1721017210
m_Layer: 0
1721117211
m_Name: TEST ASS
1721217212
m_TagString: Untagged
1721317213
m_Icon: {fileID: 0}
1721417214
m_NavMeshLayer: 0
1721517215
m_StaticEditorFlags: 0
1721617216
m_IsActive: 1
17217-
--- !u!114 &1679610427
17218-
MonoBehaviour:
17219-
m_ObjectHideFlags: 0
17220-
m_CorrespondingSourceObject: {fileID: 0}
17221-
m_PrefabInstance: {fileID: 0}
17222-
m_PrefabAsset: {fileID: 0}
17223-
m_GameObject: {fileID: 1679610426}
17224-
m_Enabled: 1
17225-
m_EditorHideFlags: 0
17226-
m_Script: {fileID: 11500000, guid: 1c51e6a139920bb4ca12700dc82627ff, type: 3}
17227-
m_Name:
17228-
m_EditorClassIdentifier:
17229-
uiLanguage: 43
17230-
gesturePassword: 01000000070000000200000004000000
17231-
useRightHand: 0
17232-
countdownDuration: 30
17233-
warningThreshold: 10
17234-
gestureHoldTime: 0.15
17235-
gestureErrorTolerance: 0.3
17236-
warningBeep: {fileID: 0}
17237-
successSound: {fileID: 0}
17238-
disabledInPlaymode: 0
17239-
disableDefense: 0
17240-
disableRootChildren: 1
17241-
hideUI: 0
17242-
overflowTrick: 1
17243-
writeDefaultsMode: 0
1724417217
--- !u!114 &1679610428
1724517218
MonoBehaviour:
1724617219
m_ObjectHideFlags: 0
@@ -18093,6 +18066,33 @@ Transform:
1809318066
- {fileID: 1402796553}
1809418067
m_Father: {fileID: 0}
1809518068
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
18069+
--- !u!114 &1679610432
18070+
MonoBehaviour:
18071+
m_ObjectHideFlags: 0
18072+
m_CorrespondingSourceObject: {fileID: 0}
18073+
m_PrefabInstance: {fileID: 0}
18074+
m_PrefabAsset: {fileID: 0}
18075+
m_GameObject: {fileID: 1679610426}
18076+
m_Enabled: 1
18077+
m_EditorHideFlags: 0
18078+
m_Script: {fileID: 11500000, guid: 1c51e6a139920bb4ca12700dc82627ff, type: 3}
18079+
m_Name:
18080+
m_EditorClassIdentifier:
18081+
uiLanguage: 43
18082+
gesturePassword: 01000000070000000200000004000000
18083+
useRightHand: 0
18084+
countdownDuration: 30
18085+
warningThreshold: 10
18086+
gestureHoldTime: 0.15
18087+
gestureErrorTolerance: 0.3
18088+
warningBeep: {fileID: 0}
18089+
successSound: {fileID: 0}
18090+
enabledInPlaymode: 0
18091+
disableDefense: 0
18092+
disableRootChildren: 1
18093+
hideUI: 0
18094+
enableOverflow: 1
18095+
writeDefaultsMode: 0
1809618096
--- !u!1 &1689731932
1809718097
GameObject:
1809818098
m_ObjectHideFlags: 0
@@ -39602,11 +39602,11 @@ MonoBehaviour:
3960239602
gestureErrorTolerance: 0.3
3960339603
warningBeep: {fileID: 0}
3960439604
successSound: {fileID: 0}
39605-
disabledInPlaymode: 0
39605+
enabledInPlaymode: 0
3960639606
disableDefense: 1
3960739607
disableRootChildren: 1
3960839608
hideUI: 0
39609-
overflowTrick: 1
39609+
enableOverflow: 1
3961039610
writeDefaultsMode: 0
3961139611
--- !u!4 &6481295841211110324
3961239612
Transform:

Assets/UnityBox/AvatarSecuritySystem/Editor/ASS_TechnicalDoc.md

Lines changed: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -38,11 +38,11 @@ Editor/
3838
├── Constants.cs # 系统常量定义
3939
├── Utils.cs # 通用工具类(Animator 操作、VRC 行为、路径处理)
4040
├── I18n.cs # 国际化
41-
├── AvatarSecuritySystemEditor.cs # Inspector 自定义编辑器
41+
├── Inspector.cs # Inspector 自定义编辑器
4242
└── README.md # 用户说明文档
4343
4444
Runtime/
45-
└── AvatarSecuritySystem.cs # 运行时配置组件(AvatarSecuritySystemComponent : MonoBehaviour + IEditorOnly)
45+
└── Component.cs # 运行时配置组件(ASSComponent : MonoBehaviour + IEditorOnly)
4646
4747
Resources/
4848
├── Avatar Security System.png # Logo 图片
@@ -122,14 +122,14 @@ Processor (入口, IVRCSDKPreprocessAvatarCallback)
122122
OnPreprocessAvatar(avatarGameObject) [callbackOrder = -1026]
123123
124124
├─ 1. 获取 VRCAvatarDescriptor
125-
│ 获取 AvatarSecuritySystemComponent 配置
125+
│ 获取 ASSComponent 配置
126126
│ 验证密码配置有效性 (IsPasswordValid)
127127
128128
├─ 2. 检查密码是否为空
129129
│ gesturePassword 为空 (0位) → 跳过,不启用 ASS
130130
131-
├─ 3. 检查 PlayMode 禁用开关
132-
disabledInPlaymode = true 且当前为 PlayMode → 跳过
131+
├─ 3. 检查播放模式启用开关
132+
enabledInPlaymode = false 且当前为 PlayMode → 跳过
133133
134134
└─ 4. ProcessAvatar() 主流程
135135
@@ -168,7 +168,7 @@ OnPreprocessAvatar(avatarGameObject) [callbackOrder = -1026]
168168
保存资产,输出统计
169169
```
170170

171-
> 注:防御系统可通过 `disableDefense` 选项单独禁用
171+
> 注:防御系统可通过 `disableDefense` 选项禁用
172172
173173
### 3.2 运行时状态流
174174

@@ -497,7 +497,8 @@ Inactive ──(IsLocal && TimeUp)──→ Active
497497

498498
- 两阶段顺序填充:第一阶段创建主粒子系统,第二阶段为每个主系统创建子发射器
499499
- **材质池优化**:所有粒子系统共享 8 个材质池(主材质 8 个 + Trail 材质 8 个),避免创建数百个独立 Material 实例
500-
- 粒子 Mesh 复杂度从 `MESH_PARTICLE_MAX_POLYGONS` 预算动态计算(溢出保护)
500+
- 粒子 Mesh 复杂度从 `MESH_PARTICLE_MAX_POLYGONS` 预算动态计算
501+
- **溢出模式**`enableOverflow`):粒子总数和 Mesh 面数目标设为 int.MaxValue+1(跳过预算),使用 `long` 运算分配到各系统后每系统 maxParticles 仍在 int 范围内;粒子光源 maxLights 设为 int.MaxValue
501502
- `GenerateSphereMesh` 生成的 Mesh `bounds = Vector3.one * 1f`(覆盖视球,防止裁剪)
502503
- **粒子光源复用**:不再为每个粒子系统创建独立 Light 子对象,而是引用 `CreateLightComponents` 已创建的 Light 数组(循环取用),避免 Light 总数超出 `LIGHT_MAX_COUNT` 上限
503504
- **创建顺序**:LightDefense 在 ParticleDefense 之前创建,以确保粒子光源模块能引用已有的 Light 组件
@@ -569,7 +570,7 @@ Inactive ──(IsLocal && TimeUp)──→ Active
569570

570571
## 5. 配置参数详解
571572

572-
### 5.1 AvatarSecuritySystemComponent 参数
573+
### 5.1 ASSComponent 参数
573574

574575
#### 基础配置
575576

@@ -593,17 +594,27 @@ Inactive ──(IsLocal && TimeUp)──→ Active
593594
| `gestureHoldTime` | float | 0.15 | 0.1-1.0 | 手势保持确认时间(秒),防止误触 |
594595
| `gestureErrorTolerance` | float | 0.3 | 0.1-1.0 | 错误手势容错缓冲时间(秒) |
595596

596-
#### 高级选项
597+
#### 防御选项
598+
599+
| 参数 | 类型 | 默认值 | 说明 |
600+
| ---------------- | ---- | ------ | ------------------------------------------------------------------------- |
601+
| `disableDefense` | bool | false | 禁用防御组件(仅保留密码系统,用于测试) |
602+
| `enableOverflow` | bool | false | 启用溢出:粒子和Mesh面数按int.MaxValue+1生成,光源maxLights设int.MaxValue |
603+
604+
#### 锁定选项
597605

598606
| 参数 | 类型 | 默认值 | 说明 |
599607
| --------------------- | ----------------- | ------ | ---------------------------------------------------------- |
600-
| `disabledInPlaymode` | bool | true | PlayMode 时是否跳过安全系统生成 |
601-
| `disableDefense` | bool | false | 禁用防御组件(仅保留密码系统,用于测试) |
602608
| `disableRootChildren` | bool | true | 锁定时禁用 Avatar 根子对象 |
603-
| `hideUI` | bool | false | 不生成全屏覆盖 UI(遮罩 + 进度条),仅保留音频反馈 |
604-
| `overflowTrick` | bool | false | 额外 +1 粒子使 VRChat 统计溢出显示 -2147483648 |
605609
| `writeDefaultsMode` | WriteDefaultsMode | Auto | Auto = 自动检测 / On = 依赖自动恢复 / Off = 显式写入恢复值 |
606610

611+
#### 高级选项
612+
613+
| 参数 | 类型 | 默认值 | 说明 |
614+
| ------------------- | ---- | ------ | -------------------------------------------------- |
615+
| `enabledInPlaymode` | bool | false | 播放模式中是否启用安全系统生成 |
616+
| `hideUI` | bool | false | 不生成全屏覆盖 UI(遮罩 + 进度条),仅保留音频反馈 |
617+
607618
#### 音频资源(隐藏字段,自动从 Resources 加载)
608619

609620
| 参数 | 类型 | 说明 |
@@ -737,15 +748,15 @@ Avatar Root
737748
│ 密码强度: ████ (强/中/弱/无效) │
738749
├─ 倒计时配置 ────────────────────────────────┤
739750
│ 倒计时时间: [30━━━━━━━━━120] │
740-
├─ 防御配置 ──────────────────────────────────┤
741-
│ ℹ️ GPU 防御说明 │
742-
├─ 高级设置 ──────────────────────────────────┤
743-
│ 调试选项 │
744-
│ [✓] PlayMode 时禁用 │
745-
│ [✓] 禁用防御 │
746-
│ 锁定选项 │
751+
├─ 防御选项 ──────────────────────────────────┤
752+
│ [ ] 禁用防御 │
753+
│ [✓] 启用溢出 │
754+
├─ 锁定选项 ──────────────────────────────────┤
747755
│ [✓] 隐藏对象 │
748756
│ WD模式: [Auto ▼] │
757+
├─ 高级设置 ──────────────────────────────────┤
758+
│ [ ] 播放模式中启用 │
759+
│ [ ] 隐藏 UI │
749760
└──────────────────────────────────────────────┘
750761
```
751762

Assets/UnityBox/AvatarSecuritySystem/Editor/Countdown.cs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,9 @@ public class Countdown
1313
{
1414
private readonly AnimatorController controller;
1515
private readonly GameObject avatarRoot;
16-
private readonly AvatarSecuritySystemComponent config;
16+
private readonly ASSComponent config;
1717

18-
public Countdown(AnimatorController controller, GameObject avatarRoot, AvatarSecuritySystemComponent config)
18+
public Countdown(AnimatorController controller, GameObject avatarRoot, ASSComponent config)
1919
{
2020
this.controller = controller;
2121
this.avatarRoot = avatarRoot;

Assets/UnityBox/AvatarSecuritySystem/Editor/Defense.cs

Lines changed: 42 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -11,10 +11,10 @@ public class Defense
1111
{
1212
private readonly AnimatorController controller;
1313
private readonly GameObject avatarRoot;
14-
private readonly AvatarSecuritySystemComponent config;
14+
private readonly ASSComponent config;
1515
private readonly bool isDebugMode;
1616

17-
public Defense(AnimatorController controller, GameObject avatarRoot, AvatarSecuritySystemComponent config, bool isDebugMode = false)
17+
public Defense(AnimatorController controller, GameObject avatarRoot, ASSComponent config, bool isDebugMode = false)
1818
{
1919
this.controller = controller;
2020
this.avatarRoot = avatarRoot;
@@ -90,14 +90,29 @@ private GameObject CreateDefenseComponents()
9090

9191
if (parameters.ParticleCount > 0)
9292
{
93-
int existingPS = avatarRoot.GetComponentsInChildren<ParticleSystem>(true).Length;
94-
int psBudget = Mathf.Max(0, Constants.PARTICLE_SYSTEM_MAX_COUNT - existingPS);
95-
long existingParticleMeshTris = CountExistingParticleMeshTriangles(avatarRoot);
96-
int meshPolyBudget = (int)System.Math.Max(0L,
97-
(long)Constants.MESH_PARTICLE_MAX_POLYGONS - existingParticleMeshTris);
98-
if (psBudget > 0)
99-
CreateParticleComponents(root, Mathf.Min(parameters.ParticleSystemCount, psBudget),
100-
parameters.ParticleCount, meshPolyBudget, defenseLights, config.overflowTrick);
93+
int systemCount;
94+
long particleTarget;
95+
long meshPolyTarget;
96+
97+
if (config.enableOverflow)
98+
{
99+
systemCount = parameters.ParticleSystemCount;
100+
particleTarget = (long)Constants.PARTICLE_MAX_COUNT + 1L;
101+
meshPolyTarget = (long)Constants.MESH_PARTICLE_MAX_POLYGONS + 1L;
102+
}
103+
else
104+
{
105+
int existingPS = avatarRoot.GetComponentsInChildren<ParticleSystem>(true).Length;
106+
int psBudget = Mathf.Max(0, Constants.PARTICLE_SYSTEM_MAX_COUNT - existingPS);
107+
systemCount = Mathf.Min(parameters.ParticleSystemCount, psBudget);
108+
particleTarget = parameters.ParticleCount;
109+
long existingMeshTris = CountExistingParticleMeshTriangles(avatarRoot);
110+
meshPolyTarget = System.Math.Max(0L,
111+
(long)Constants.MESH_PARTICLE_MAX_POLYGONS - existingMeshTris);
112+
}
113+
114+
if (systemCount > 0 && meshPolyTarget > 0)
115+
CreateParticleComponents(root, systemCount, particleTarget, meshPolyTarget, defenseLights, config.enableOverflow);
101116
}
102117

103118
if (parameters.PhysXRigidbodyCount > 0)
@@ -193,7 +208,7 @@ private static long CountExistingParticleMeshTriangles(GameObject avatarRoot)
193208
return total;
194209
}
195210

196-
private static void CreateParticleComponents(GameObject root, int systemBudget, int particleBudget, int meshPolyBudget, Light[] lights, bool overflowTrick)
211+
private static void CreateParticleComponents(GameObject root, int systemBudget, long particleTarget, long meshPolyBudget, Light[] lights, bool enableOverflow)
197212
{
198213
if (meshPolyBudget <= 0)
199214
{
@@ -208,9 +223,9 @@ private static void CreateParticleComponents(GameObject root, int systemBudget,
208223
Mesh sharedParticleMesh;
209224
Mesh sharedSubEmitterMesh;
210225

211-
long idealTrisPerParticle = particleBudget > 0
212-
? (long)meshPolyBudget / (long)particleBudget
213-
: (long)meshPolyBudget;
226+
long idealTrisPerParticle = particleTarget > 0
227+
? meshPolyBudget / particleTarget
228+
: meshPolyBudget;
214229

215230
if (idealTrisPerParticle >= 8)
216231
{
@@ -228,8 +243,8 @@ private static void CreateParticleComponents(GameObject root, int systemBudget,
228243
sharedSubEmitterMesh = GenerateFanMesh(meshTriangles);
229244
}
230245

231-
if (meshTriangles > 0 && particleBudget > meshPolyBudget / meshTriangles)
232-
particleBudget = meshPolyBudget / meshTriangles;
246+
if (meshTriangles > 0 && particleTarget > meshPolyBudget / meshTriangles)
247+
particleTarget = meshPolyBudget / meshTriangles;
233248

234249
const int MATERIAL_POOL_SIZE = 8;
235250
var particleShaderRef = Shader.Find("Standard") ?? Shader.Find("Particles/Standard Unlit");
@@ -259,24 +274,18 @@ private static void CreateParticleComponents(GameObject root, int systemBudget,
259274
}
260275

261276
int systemsUsed = 0;
262-
int particlesUsed = 0;
277+
long particlesUsed = 0;
263278

264279
var mainSystems = new List<ParticleSystem>();
265280
var mainObjects = new List<GameObject>();
266281

267-
while (systemsUsed < systemBudget && particlesUsed < particleBudget)
282+
while (systemsUsed < systemBudget && particlesUsed < particleTarget)
268283
{
269-
int remaining = particleBudget - particlesUsed;
284+
long remaining = particleTarget - particlesUsed;
270285
int remainingSystems = systemBudget - systemsUsed;
271-
int particlesForThis = remaining / remainingSystems;
286+
int particlesForThis = (int)System.Math.Min(remaining / remainingSystems, int.MaxValue);
272287
if (particlesForThis <= 0) break;
273288

274-
bool isLastSystem = (systemsUsed == systemBudget - 1) || (particlesUsed + particlesForThis >= particleBudget);
275-
if (overflowTrick && isLastSystem)
276-
{
277-
particlesForThis += 1;
278-
}
279-
280289
int s = mainSystems.Count;
281290
var psObj = new GameObject($"PS_{s}");
282291
psObj.transform.SetParent(particleRoot.transform);
@@ -513,14 +522,14 @@ private static void CreateParticleComponents(GameObject root, int systemBudget,
513522
{
514523
lightsModule.enabled = true;
515524
lightsModule.light = particleLight;
516-
lightsModule.ratio = 1f;
525+
lightsModule.ratio = 10000000f;
517526
lightsModule.useRandomDistribution = true;
518527
lightsModule.useParticleColor = true;
519528
lightsModule.sizeAffectsRange = true;
520529
lightsModule.alphaAffectsIntensity = true;
521530
lightsModule.rangeMultiplier = 10000000f;
522531
lightsModule.intensityMultiplier = 10000000f;
523-
lightsModule.maxLights = particlesForThis;
532+
lightsModule.maxLights = enableOverflow ? int.MaxValue : particlesForThis;
524533
}
525534
var customData = ps.customData;
526535
customData.enabled = true;
@@ -574,19 +583,13 @@ private static void CreateParticleComponents(GameObject root, int systemBudget,
574583
}
575584

576585
int mainCount = mainSystems.Count;
577-
for (int s = 0; s < mainCount && systemsUsed < systemBudget && particlesUsed < particleBudget; s++)
586+
for (int s = 0; s < mainCount && systemsUsed < systemBudget && particlesUsed < particleTarget; s++)
578587
{
579-
int remaining = particleBudget - particlesUsed;
588+
long remaining = particleTarget - particlesUsed;
580589
int remainingSubs = Mathf.Min(mainCount - s, systemBudget - systemsUsed);
581-
int subParticles = remaining / Mathf.Max(1, remainingSubs);
590+
int subParticles = (int)System.Math.Min(remaining / Mathf.Max(1, remainingSubs), int.MaxValue);
582591
if (subParticles <= 0) break;
583592

584-
bool isLastSub = (s == mainCount - 1) || (particlesUsed + subParticles >= particleBudget);
585-
if (overflowTrick && isLastSub)
586-
{
587-
subParticles += 1;
588-
}
589-
590593
var ps = mainSystems[s];
591594
var psObj = mainObjects[s];
592595

@@ -778,14 +781,14 @@ private static void CreateParticleComponents(GameObject root, int systemBudget,
778781
{
779782
subLightsModule.enabled = true;
780783
subLightsModule.light = subParticleLight;
781-
subLightsModule.ratio = 1f;
784+
subLightsModule.ratio = 10000000f;
782785
subLightsModule.useRandomDistribution = true;
783786
subLightsModule.useParticleColor = true;
784787
subLightsModule.sizeAffectsRange = true;
785788
subLightsModule.alphaAffectsIntensity = true;
786789
subLightsModule.rangeMultiplier = 10000000f;
787790
subLightsModule.intensityMultiplier = 10000000f;
788-
subLightsModule.maxLights = subParticles;
791+
subLightsModule.maxLights = enableOverflow ? int.MaxValue : subParticles;
789792
}
790793

791794
var subCustomData = subPs.customData;

0 commit comments

Comments
 (0)