Files
Colosseum/AGENTS.md

351 lines
12 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Colosseum - Unity Game Project
## Project Overview
Multiplayer arena game built with **Unity 6000.3.10f1** and **Unity Netcode for GameObjects**.
- **Language**: C# 9.0
- **Target Framework**: .NET Standard 2.1
- **Root Namespace**: `Colosseum`
- **Assembly Definition**: `Colosseum.Game` (Assets/Scripts/Colosseum.Game.asmdef)
## Game Design Documentation
Design docs are maintained in Obsidian Vault: `/mnt/smb/Obsidian Vault/Colosseum`
- Always use the shared Obsidian Vault at `/mnt/smb/Obsidian Vault/Colosseum` for project documentation updates.
- **Obsidian Vault 파일은 반드시 파일 도구(read/write/edit)로만 접근한다.** cmd, powershell, bash 등은 UNC 경로를 정상적으로 처리하지 못하므로 사용하지 않는다.
- Unless the user explicitly names another file, `체크리스트` means `/mnt/smb/Obsidian Vault/Colosseum/개발/프로토타입 체크리스트.md`.
- After completing work, always check whether the prototype checklist should be updated and reflect the new status when needed.
- If the work also changes a domain-specific checklist such as boss/player/combat, sync that checklist too.
- When editing user-authored Obsidian notes, preserve the user's original text structure as much as possible.
- 에이전트가 작성자가 아닌 보완 메모나 제안을 추가할 때는 `보완 메모` 또는 `제안` 같이 명확히 구분되는 섹션에 작성하여 원본과 구별되도록 한다.
- Cross-session design agreements that should be checked before related work are summarized in `/mnt/smb/Obsidian Vault/Colosseum/개발/세션 공통 합의.md`.
### Game Concept
- **Genre**: Online multiplayer co-op action RPG (3rd person)
- **Theme**: Gladiator survival boss raid in Colosseum
- **Roles**: Multi-role system - players can hybridize (e.g., Tank 0.5 + DPS 0.5) instead of fixed Tank/DPS/Healer
### Stats System
| Stat | Abbr | Description | Derived Formula |
|------|------|-------------|-----------------|
| Strength | STR | Weapon damage | Physical Damage = STR × 2 |
| Dexterity | DEX | Ranged aim/damage, melee speed | Ranged Damage = DEX × 2 |
| Intelligence | INT | Magic damage | Magic Damage = INT × 2 |
| Vitality | VIT | Max health | Max HP = VIT × 10 |
| Wisdom | WIS | Healing power | Heal Power = WIS × 1.5 |
| Spirit | SPI | Max mana | Max MP = SPI × 5 |
### Damage Calculation
```
Final Damage = baseDamage + (statDamage × statScaling)
```
| DamageType | Base Stat | Description |
|------------|-----------|-------------|
| Physical | STR | Melee weapon damage |
| Magical | INT | Spell damage |
| Ranged | DEX | Bow/ranged damage |
| True | None | Fixed damage, no stat scaling |
### Stat Modifier System
Modifiers are applied in order:
1. **Flat**: Add fixed value
2. **PercentAdd**: Sum percentages, then multiply
3. **PercentMult**: Multiply individually
```
Final = (Base + FlatSum) × (1 + PercentAddSum) × PercentMult1 × PercentMult2...
```
### Skill System
- **Active Skills**: 6 slots (L-click, R-click, 1, 2, 3, 4)
- **Passive Skills**: Tree-based progression from center
- **Effects**: Triggered via animation events (`OnEffect(index)`)
- **Animation**: Start clip + optional end clip
## Build/Run Commands
This is a Unity project. Use Unity Editor for building and testing.
```bash
# Open in Unity Editor (requires Unity Hub)
# Build via: File > Build Settings > Build
# Run tests in Unity Editor
# Window > General > Test Runner > EditMode / PlayMode
```
### Build from Command Line (Linux)
```bash
# Build Linux standalone (adjust paths as needed)
"/path/to/Unity/Editor/Unity" -batchmode -projectPath . -buildLinux64Player ./Builds/Linux/Colosseum -quit
```
## Project Structure
```
Assets/
Scripts/
Abnormalities/ # Buff/debuff system
Editor/ # Unity editor extensions
Network/ # Network management
Player/ # Player controllers
Skills/ # Skill system
Effects/ # Skill effects (damage, heal, etc.)
Stats/ # Character statistics
UI/ # User interface
```
## Code Style Guidelines
### Namespaces
Follow `Colosseum.{Subnamespace}` pattern:
```csharp
namespace Colosseum.Player { }
namespace Colosseum.Skills { }
namespace Colosseum.Skills.Effects { }
namespace Colosseum.Stats { }
namespace Colosseum.Network { }
namespace Colosseum.Abnormalities { }
```
### Using Statements Order
Organize imports in this order, separated by blank lines:
1. System namespaces
2. UnityEngine namespaces
3. Unity.Netcode / Unity packages
4. Colosseum namespaces
```csharp
using System;
using System.Collections.Generic;
using UnityEngine;
using Unity.Netcode;
using Colosseum.Stats;
using Colosseum.Player;
```
### Naming Conventions
| Element | Convention | Example |
|---------|------------|---------|
| Classes | PascalCase | `PlayerNetworkController` |
| Interfaces | IPascalCase | `IDamageable` |
| Methods | PascalCase | `TakeDamageRpc()` |
| Public Properties | PascalCase | `MaxHealth`, `IsStunned` |
| Private Fields | camelCase | `currentHealth`, `characterStats` |
| Constants | PascalCase or SCREAMING_SNAKE | `SKILL_STATE_NAME`, `MaxValue` |
| Enum values | PascalCase | `DamageType.Physical` |
### Serialization & Inspector
Use `[SerializeField]` with `[Header]` and `[Tooltip]` for organization:
```csharp
[Header("References")]
[Tooltip("CharacterStats component (auto-searched if null)")]
[SerializeField] private CharacterStats characterStats;
[Header("Settings")]
[Min(0f)] [SerializeField] private float baseDamage = 10f;
[SerializeField] private DamageType damageType = DamageType.Physical;
```
### Documentation
Use XML documentation comments in **Korean**:
```csharp
/// <summary>
/// 플레이어 네트워크 상태 관리 (HP, MP 등)
/// </summary>
public class PlayerNetworkController : NetworkBehaviour
{
/// <summary>
/// 대미지 적용 (서버에서만 실행)
/// </summary>
[Rpc(SendTo.Server)]
public void TakeDamageRpc(float damage)
{
// ...
}
}
```
### Network Code Patterns
Use Unity Netcode patterns:
```csharp
// Network variables for synchronized state
private NetworkVariable<float> currentHealth = new NetworkVariable<float>(100f);
// Server RPCs for client-to-server calls
[Rpc(SendTo.Server)]
public void TakeDamageRpc(float damage)
{
currentHealth.Value = Mathf.Max(0f, currentHealth.Value - damage);
}
// Check authority before modifying
if (IsServer)
{
currentHealth.Value = MaxHealth;
}
```
### Expression Body Members
Use for simple properties and methods:
```csharp
public float MaxHealth => vitality.FinalValue * 10f;
public bool IsStunned => stunCount > 0;
public bool CanAct => !IsStunned;
```
### Switch Expressions
Prefer switch expressions for concise mapping:
```csharp
public CharacterStat GetStat(StatType statType)
{
return statType switch
{
StatType.Strength => strength,
StatType.Dexterity => dexterity,
StatType.Intelligence => intelligence,
_ => null,
};
}
```
### ScriptableObjects for Data
Use ScriptableObject for configuration data:
```csharp
[CreateAssetMenu(fileName = "NewSkill", menuName = "Colosseum/Skill")]
public class SkillData : ScriptableObject
{
[SerializeField] private string skillName;
[SerializeField] private List<SkillEffect> effects;
public string SkillName => skillName;
public IReadOnlyList<SkillEffect> Effects => effects;
}
```
### Error Handling
- Use `Debug.LogWarning()` for recoverable issues
- Use `Debug.LogError()` for critical failures
- Null-check parameters in public methods
```csharp
public void ApplyAbnormality(AbnormalityData data, GameObject source)
{
if (data == null)
{
Debug.LogWarning("[Abnormality] ApplyAbnormality called with null data");
return;
}
// ...
}
```
### Events
Use C# events with `Action<T>` or custom delegates:
```csharp
public event Action<ActiveAbnormality> OnAbnormalityAdded;
public event Action<ActiveAbnormality> OnAbnormalityRemoved;
public event Action OnAbnormalitiesChanged;
// Invoke with null-conditional
OnAbnormalityAdded?.Invoke(newAbnormality);
```
## Key Dependencies
| Package | Purpose |
|---------|---------|
| Unity.Netcode.Runtime | Multiplayer networking |
| Unity.InputSystem | New input system |
| Unity.TextMeshPro | Text rendering |
| Unity.Networking.Transport | Low-level networking |
## Common Patterns
### MonoBehaviour Components
```csharp
public class ExampleComponent : MonoBehaviour
{
[Header("References")]
[SerializeField] private Animator animator;
public Animator Animator => animator;
private void Awake()
{
if (animator == null)
animator = GetComponentInChildren<Animator>();
}
}
```
### NetworkBehaviour Components
```csharp
public class NetworkedComponent : NetworkBehaviour
{
private NetworkVariable<int> value = new NetworkVariable<int>();
public override void OnNetworkSpawn()
{
// Initialize networked state
}
public override void OnNetworkDespawn()
{
// Cleanup
}
}
```
## Notes
- For Unity work, prefer Unity MCP for active scene inspection, runtime verification, prefab checks, and console review when it is available in the session.
- Never edit code, scenes, prefabs, components, or Unity asset settings while the Unity Editor is in play mode. Stop play mode first, then edit.
- **CRITICAL**: After any code change (edit, create, delete), always perform a force refresh with compile request and wait for ready before entering play mode. Failing to do so causes mid-play compilation which can leave network ports occupied on the next run. Use `refresh_unity(mode="force", compile="request", wait_for_ready=true)`.
- After Unity-related edits, check the Unity console for errors before proceeding.
- For networked play tests, prefer a temporary non-conflicting test port when needed and restore the default port after validation.
- The user has a strong project preference that play mode must be stopped before edits because network ports can remain occupied otherwise.
- Commit messages should follow the recent project history style: use a type prefix such as `feat:`, `fix:`, or `chore:` and write the subject in Korean so the gameplay/UI/system change is clear from the log alone.
- When the change is substantial, include a blank line after the subject and add Korean bullet points that summarize the work by feature/purpose, similar to commit `0889bb0` (`feat: 드로그 집행 개시 패턴 및 낙인 디버프 추가`).
- Prefer the format `type: 한글 요약` for the subject, then `- 변경 사항` bullet lines for the body. Use `feat:` for feature work, `fix:` for bug fixes, and `chore:` for non-feature maintenance such as scene/prefab cleanup, asset reorganization, or other miscellaneous upkeep. The body should mention key implementation scope, affected systems/assets, and validation or rollback notes when relevant.
- All code comments and documentation should be in Korean
- Use `[Min()]` attribute for numeric minimums in Inspector
- Use `[TextArea]` for multi-line string fields
- Private fields should use `camelCase` (no `m_` or `_` prefix)
- Prefer `IReadOnlyList<T>` for exposing collections
- 프로젝트 용어로는 `필살기`보다 `고위력 기술`을 우선 사용한다.
- 보호막은 단일 값이 아니라 `타입별 독립 인스턴스`로 취급한다. 같은 타입은 자기 자신만 갱신되고, 서로 다른 타입은 공존하며, 흡수 순서는 적용 순서를 따른다.
- 보스 시그니처 전조는 가능한 한 정확한 진행 수치 UI보다 명확한 모션/VFX로 읽히게 한다. 차단 진행도나 정확한 누적 수치 노출은 명시 요청이 없으면 피한다.