Compare commits

...

2 Commits

Author SHA1 Message Date
2593b6dd37 데이터 파이프라인 개선 및 포탈 로직 생성
csv import 시 자동으로 완전한 프리팹이 생성될 수 있도록 함.
2026-02-01 00:29:22 +09:00
b54e016283 포탈이 글로벌 타이머 사이클에 맞춰 웨이브를 소환하도록 함
시작 코스트 4, 웨이브당 증가량 10%
2026-01-31 21:36:56 +09:00
53 changed files with 12120 additions and 71 deletions

5
.gitignore vendored
View File

@@ -8,4 +8,7 @@
[Uu]ser[Ss]ettings/
.vs
.vs/*
.vs/*
.vscode
Assets/_Recovery
Assets/_Recovery.meta

View File

@@ -0,0 +1,120 @@
# Automated Prefab Generation Pipeline
## Overview
This system automates the creation of monster prefabs from CSV data. No manual prefab setup required!
## How It Works
1. **CSV Data****ScriptableObject (SO)****Prefab** (automatically generated)
2. Template prefabs define required components and defaults
3. CSV importer creates complete prefabs with mesh, components, and SO references
## Setup Instructions
### Step 1: Create Template Prefab
1. In Unity, go to `Tools > Data > Create Monster Template`
2. This creates `Assets/Data/Templates/MonsterTemplate.prefab`
3. The template includes all required components:
- NetworkObject
- EnemyUnit
- MonsterDataComponent (links to SO)
- NavMeshAgent
- EnemyAIController
- CapsuleCollider
- MeshFilter & MeshRenderer
4. **Customize the template if needed:**
- Adjust default AI behavior
- Set default collider size
- Add visual effects
- Configure NavMeshAgent settings
### Step 2: Update CSV with Mesh Path
Add `meshPath` column to your `Monster.csv`:
```csv
id,name,memo,moveSpeed,maxHp,atkRange,atkDamage,atkIntervalSec,meshPath,cost,weight
101,Grunt,Basic Monster,2.6,30,1,3,1.2,Assets/Models/Monsters/Monster101.fbx,1,1.0
102,Fast,Fast/Weak,3.4,18,1,2,1,Assets/Models/Monsters/Monster102.fbx,2,0.5
```
### Step 3: Import Data
1. In Unity, go to `Tools > Data > Import All CSV`
2. The importer will:
- Create/update SO files in `Assets/Data/ScriptableObjects/Monster/`
- Create/update prefabs in `Assets/Prefabs/Monster/`
- Apply mesh from `meshPath` column
- Link SO reference to prefab's MonsterDataComponent
### Step 4: Use Prefabs
Your generated prefabs are ready to use! Example with EnemyPortal:
- Open EnemyPortal prefab
- Click "Load Monster Data" button
- All monster prefabs are automatically loaded
## File Structure
```
Assets/
├── Data/
│ ├── ScriptableObjects/
│ │ └── Monster/ # SO files (generated from CSV)
│ └── Templates/ # Template prefabs (created once)
│ └── MonsterTemplate.prefab
├── Prefabs/
│ └── Monster/ # Generated monster prefabs
│ ├── Monster101.prefab
│ ├── Monster102.prefab
│ └── ...
└── GameData/
└── Monster.csv # Source data (editable)
```
## Benefits
-**One source of truth**: Edit CSV, everything updates
-**No manual setup**: Prefabs generated automatically
-**Designer-friendly**: Templates visual, CSV simple
-**Error-proof**: All components guaranteed to exist
-**Easy customization**: Edit template once, applies to all
## Customization
### Adding New Components
1. Open `MonsterTemplate.prefab`
2. Add the component
3. Configure defaults
4. Save template
5. All future imports will include it
### Modifying Existing Monsters
- Edit the prefab directly (changes persist on next import)
- OR modify CSV and re-import (will update SO link and mesh)
### Creating Other Data Types
Use the same pattern:
1. Create template: `Tools > Data > Create Tower Template`
2. Add meshPath column to Tower.csv
3. Import: `Tools > Data > Import All CSV`
## Troubleshooting
**Prefab not created?**
- Check if template exists in `Assets/Data/Templates/`
- Verify `meshPath` column in CSV
**Mesh not showing?**
- Verify `meshPath` is correct in CSV
- Check that mesh file exists at specified path
**Components not configured?**
- Edit template prefab
- Re-import CSV to apply template changes to new prefabs
**Want to keep manual prefab edits?**
- Prefabs created by importer are NOT overwritten
- Edits persist on next import (SO and mesh only update)

View File

@@ -43,21 +43,24 @@
<UnityVersion>6000.3.5f2</UnityVersion>
</PropertyGroup>
<ItemGroup>
<Analyzer Include="C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\Microsoft\Visual Studio Tools for Unity\Analyzers\Microsoft.Unity.Analyzers.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.SourceGenerators.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.Properties.SourceGenerator.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.UIToolkit.SourceGenerator.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="Assets\Scripts\Editor\MonsterPrefabSetup.cs" />
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\Water\Editor\Tooltips.cs" />
<Compile Include="Assets\Scripts\Editor\EnemyPortalEditor.cs" />
<Compile Include="Assets\Editor\DataImporter\ImporterWindow.cs" />
<Compile Include="Assets\Scripts\Editor\ObstacleSpawnerEditor.cs" />
<Compile Include="Assets\Editor\DataImporter\CSVDebugger.cs" />
<Compile Include="Assets\Scripts\Editor\IPrefabSetup.cs" />
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\Water\Editor\WaterEditor.cs" />
<Compile Include="Assets\Editor\DataImporter\CSVToSOImporter.cs" />
<Compile Include="Assets\FlatKit\Shaders\Editor\ObjectOutlineEditorUtils.cs" />
<Compile Include="Assets\FlatKit\Demos\Common\Scripts\Motion\Editor\LinearMotionEditor.cs" />
<Compile Include="Assets\FlatKit\Shaders\GradientSkybox\Editor\GradientSkyboxEditor.cs" />
<Compile Include="Assets\Scripts\Editor\TemplateCreator.cs" />
<Compile Include="Assets\FlatKit\Shaders\Editor\Tooltips.cs" />
<Compile Include="Assets\FlatKit\Shaders\Editor\StylizedSurfaceEditor.cs" />
<Compile Include="Assets\Scripts\Editor\FogOfWarVisibilitySetup.cs" />
@@ -1245,14 +1248,14 @@
<HintPath>Library\ScriptAssemblies\PPv2URPConverters.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.2D.Common.Editor">
<HintPath>Library\ScriptAssemblies\Unity.2D.Common.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.AI.Navigation.Updater">
<HintPath>Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.2D.Common.Editor">
<HintPath>Library\ScriptAssemblies\Unity.2D.Common.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.AI.Navigation.Editor">
<HintPath>Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll</HintPath>
<Private>False</Private>
@@ -1289,10 +1292,6 @@
<HintPath>Library\ScriptAssemblies\Unity.2D.Aseprite.Common.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.Rider.Editor">
<HintPath>Library\ScriptAssemblies\Unity.Rider.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.AI.Navigation.Editor.ConversionSystem">
<HintPath>Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll</HintPath>
<Private>False</Private>
@@ -1301,6 +1300,10 @@
<HintPath>Library\ScriptAssemblies\Unity.2D.Aseprite.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.Rider.Editor">
<HintPath>Library\ScriptAssemblies\Unity.Rider.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary">
<HintPath>Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll</HintPath>
<Private>False</Private>

View File

@@ -43,14 +43,12 @@
<UnityVersion>6000.3.5f2</UnityVersion>
</PropertyGroup>
<ItemGroup>
<Analyzer Include="C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\Microsoft\Visual Studio Tools for Unity\Analyzers\Microsoft.Unity.Analyzers.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.SourceGenerators.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.Properties.SourceGenerator.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.UIToolkit.SourceGenerator.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="Assets\Scripts\NetworkManagerUI.cs" />
<Compile Include="Assets\Data\Scripts\DataClasses\WaveMasterData.cs" />
<Compile Include="Assets\FlatKit\Demos\[Demo] Desert\Scripts\FloatingMotion.cs" />
<Compile Include="Assets\Scripts\PlayerResourceInventory.cs" />
<Compile Include="Assets\Scripts\ITeamMember.cs" />
@@ -69,6 +67,7 @@
<Compile Include="Assets\Scripts\BuildingDamageTest.cs" />
<Compile Include="Assets\Scripts\EnemyAIController.cs" />
<Compile Include="Assets\Scripts\EquipmentSocket.cs" />
<Compile Include="Assets\Data\Scripts\DataClasses\PlayerData.cs" />
<Compile Include="Assets\Scripts\TeamManager.cs" />
<Compile Include="Assets\Scripts\TeamGate.cs" />
<Compile Include="Assets\Scripts\BuildingData.cs" />
@@ -83,7 +82,6 @@
<Compile Include="Assets\FlatKit\Demos\Common\Scripts\UvScroller.cs" />
<Compile Include="Assets\Scripts\GlobalTimer.cs" />
<Compile Include="Assets\InputSystem_Actions.cs" />
<Compile Include="Assets\Data\Scripts\DataClasses\MonsterMasterData.cs" />
<Compile Include="Assets\FlatKit\Demos\[Demo] Desert\Scripts\BillboardLineRendererCircle.cs" />
<Compile Include="Assets\Scripts\BuildingHealthBar.cs" />
<Compile Include="Assets\Scripts\PlayerSpawnPoint.cs" />
@@ -93,16 +91,20 @@
<Compile Include="Assets\Scripts\BuildingManager.cs" />
<Compile Include="Assets\Scripts\GhostMaterialTest.cs" />
<Compile Include="Assets\Scripts\BuildingPlacement.cs" />
<Compile Include="Assets\Scripts\MonsterDataComponent.cs" />
<Compile Include="Assets\Scripts\Core.cs" />
<Compile Include="Assets\Scripts\EnemyPortal.cs" />
<Compile Include="Assets\FlatKit\Demos\Common\Scripts\Motion\LinearMotion.cs" />
<Compile Include="Assets\Scripts\IDamageable.cs" />
<Compile Include="Assets\Scripts\NetworkSpawnManager.cs" />
<Compile Include="Assets\Scripts\FogOfWarSystem.cs" />
<Compile Include="Assets\Data\Scripts\DataClasses\MonsterData.cs" />
<Compile Include="Assets\Data\Scripts\DataClasses\TowerData.cs" />
<Compile Include="Assets\Scripts\IAction.cs" />
<Compile Include="Assets\Scripts\NetworkPlayerController.cs" />
<Compile Include="Assets\Scripts\PlayerInteraction.cs" />
<Compile Include="Assets\Scripts\FogOfWarVisibility.cs" />
<Compile Include="Assets\Data\Scripts\DataClasses\DefaultSettingsData.cs" />
<Compile Include="Assets\Scripts\EnemyAIState.cs" />
<Compile Include="Assets\Scripts\EquipmentData.cs" />
<Compile Include="Assets\Scripts\NetworkConnectionHandler.cs" />
@@ -1263,14 +1265,14 @@
<HintPath>Library\ScriptAssemblies\PPv2URPConverters.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.2D.Common.Editor">
<HintPath>Library\ScriptAssemblies\Unity.2D.Common.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.AI.Navigation.Updater">
<HintPath>Library\ScriptAssemblies\Unity.AI.Navigation.Updater.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.2D.Common.Editor">
<HintPath>Library\ScriptAssemblies\Unity.2D.Common.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.AI.Navigation.Editor">
<HintPath>Library\ScriptAssemblies\Unity.AI.Navigation.Editor.dll</HintPath>
<Private>False</Private>
@@ -1307,10 +1309,6 @@
<HintPath>Library\ScriptAssemblies\Unity.2D.Aseprite.Common.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.Rider.Editor">
<HintPath>Library\ScriptAssemblies\Unity.Rider.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.AI.Navigation.Editor.ConversionSystem">
<HintPath>Library\ScriptAssemblies\Unity.AI.Navigation.Editor.ConversionSystem.dll</HintPath>
<Private>False</Private>
@@ -1319,6 +1317,10 @@
<HintPath>Library\ScriptAssemblies\Unity.2D.Aseprite.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.Rider.Editor">
<HintPath>Library\ScriptAssemblies\Unity.Rider.Editor.dll</HintPath>
<Private>False</Private>
</Reference>
<Reference Include="Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary">
<HintPath>Library\ScriptAssemblies\Unity.RenderPipelines.ShaderGraph.ShaderGraphLibrary.dll</HintPath>
<Private>False</Private>

View File

@@ -19,6 +19,6 @@ MonoBehaviour:
atkRange: 1
atkDamage: 3
atkIntervalSec: 1.2
prefabPath: Assets/Prefabs/EnemyTest
meshPath: Assets/Meshes/Skeleton_Minion.fbx
cost: 1
weight: 1

View File

@@ -19,6 +19,6 @@ MonoBehaviour:
atkRange: 1
atkDamage: 2
atkIntervalSec: 1
prefabPath: Assets/Prefabs/MonsterTest
meshPath: Assets/Meshes/Skeleton_Minion.fbx
cost: 2
weight: 0.5

View File

@@ -19,6 +19,6 @@ MonoBehaviour:
atkRange: 1
atkDamage: 4
atkIntervalSec: 1.5
prefabPath: Assets/Prefabs/Core
meshPath: Assets/Meshes/Skeleton_Minion.fbx
cost: 5
weight: 0.2

View File

@@ -19,6 +19,6 @@ MonoBehaviour:
atkRange: 5
atkDamage: 2
atkIntervalSec: 1.4
prefabPath: Assets/Prefabs/Resource
meshPath: Assets/Meshes/Skeleton_Minion.fbx
cost: 3
weight: 0.333

View File

@@ -19,6 +19,6 @@ MonoBehaviour:
atkRange: 1
atkDamage: 7
atkIntervalSec: 1.3
prefabPath: Assets/Prefabs/ResourcePickup
meshPath: Assets/Meshes/Skeleton_Minion.fbx
cost: 10
weight: 0.1

View File

@@ -24,8 +24,10 @@ namespace Northbound.Data
public int atkDamage;
/// <summary>공격 주기</summary>
public float atkIntervalSec;
/// <summary>프리팹/리소스 경로</summary>
public string prefabPath;
/// <summary>메시 경로</summary>
public string meshPath;
/// <summary>애니메이터 컨트롤러 경로</summary>
public string animatorControllerPath;
/// <summary>몬스터 난이도 점수</summary>
public int cost;
/// <summary>등장 가중치</summary>

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 6430af38bc9c421459efd6be785c0853
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,229 @@
%YAML 1.1
%TAG !u! tag:unity3d.com,2011:
--- !u!1 &3810918154428190126
GameObject:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
serializedVersion: 6
m_Component:
- component: {fileID: 244366501961263783}
- component: {fileID: 6694091345637567571}
- component: {fileID: 876002834352819743}
- component: {fileID: 3376121002006894933}
- component: {fileID: 4485945348237935463}
- component: {fileID: 3318886927439461238}
- component: {fileID: 3710510283885710978}
- component: {fileID: 8707976825772989039}
- component: {fileID: 305627289932973437}
m_Layer: 11
m_Name: MonsterTemplate
m_TagString: Untagged
m_Icon: {fileID: 0}
m_NavMeshLayer: 0
m_StaticEditorFlags: 0
m_IsActive: 1
--- !u!4 &244366501961263783
Transform:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
serializedVersion: 2
m_LocalRotation: {x: 0, y: 0, z: 0, w: 1}
m_LocalPosition: {x: 0, y: 0, z: 0}
m_LocalScale: {x: 1, y: 1, z: 1}
m_ConstrainProportionsScale: 0
m_Children: []
m_Father: {fileID: 0}
m_LocalEulerAnglesHint: {x: 0, y: 0, z: 0}
--- !u!136 &6694091345637567571
CapsuleCollider:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Material: {fileID: 0}
m_IncludeLayers:
serializedVersion: 2
m_Bits: 0
m_ExcludeLayers:
serializedVersion: 2
m_Bits: 0
m_LayerOverridePriority: 0
m_IsTrigger: 0
m_ProvidesContacts: 0
m_Enabled: 1
serializedVersion: 2
m_Radius: 0.5
m_Height: 2
m_Direction: 1
m_Center: {x: 0, y: 0, z: 0}
--- !u!114 &876002834352819743
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
GlobalObjectIdHash: 949228241
InScenePlacedSourceGlobalObjectIdHash: 0
DeferredDespawnTick: 0
Ownership: 1
AlwaysReplicateAsRoot: 0
SynchronizeTransform: 1
ActiveSceneSynchronization: 0
SceneMigrationSynchronization: 0
SpawnWithObservers: 1
DontDestroyWithOwner: 0
AutoObjectParentSync: 1
SyncOwnerTransformWhenParented: 1
AllowOwnerToParent: 0
--- !u!114 &3376121002006894933
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 345fc6e7d4f06314f8b548129700eccb, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Northbound.EnemyUnit
ShowTopMostFoldoutHeaderGroup: 1
enemyTeam: 3
maxHealth: 100
damageEffectPrefab: {fileID: 0}
destroyEffectPrefab: {fileID: 0}
--- !u!195 &4485945348237935463
NavMeshAgent:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Enabled: 1
m_AgentTypeID: 0
m_Radius: 0.5
m_Speed: 3.5
m_Acceleration: 8
avoidancePriority: 50
m_AngularSpeed: 120
m_StoppingDistance: 0
m_AutoTraverseOffMeshLink: 1
m_AutoBraking: 1
m_AutoRepath: 1
m_Height: 2
m_BaseOffset: 0
m_WalkableMask: 4294967295
m_ObstacleAvoidanceType: 4
--- !u!114 &3318886927439461238
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: 453e726e48d16214f84c6d5737edd7df, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Northbound.EnemyAIController
ShowTopMostFoldoutHeaderGroup: 1
aiType: 3
detectionRange: 15
detectionAngle: 120
playerLayer:
serializedVersion: 2
m_Bits: 4294967295
obstacleLayer:
serializedVersion: 2
m_Bits: 4294967295
maxChaseDistance: 30
chaseGiveUpDistance: 25
attackRange: 2
attackInterval: 1.5
attackDamage: 10
moveSpeed: 3.5
chaseSpeedMultiplier: 1.5
showDebugInfo: 1
--- !u!114 &3710510283885710978
MonoBehaviour:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Enabled: 1
m_EditorHideFlags: 0
m_Script: {fileID: 11500000, guid: d702d872f7bcec54baa1f2ee285fc844, type: 3}
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Northbound.MonsterDataComponent
monsterData: {fileID: 0}
autoApplyOnAwake: 1
--- !u!33 &8707976825772989039
MeshFilter:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Mesh: {fileID: 0}
--- !u!23 &305627289932973437
MeshRenderer:
m_ObjectHideFlags: 0
m_CorrespondingSourceObject: {fileID: 0}
m_PrefabInstance: {fileID: 0}
m_PrefabAsset: {fileID: 0}
m_GameObject: {fileID: 3810918154428190126}
m_Enabled: 1
m_CastShadows: 1
m_ReceiveShadows: 1
m_DynamicOccludee: 1
m_StaticShadowCaster: 0
m_MotionVectors: 1
m_LightProbeUsage: 1
m_ReflectionProbeUsage: 1
m_RayTracingMode: 2
m_RayTraceProcedural: 0
m_RayTracingAccelStructBuildFlagsOverride: 0
m_RayTracingAccelStructBuildFlags: 1
m_SmallMeshCulling: 1
m_ForceMeshLod: -1
m_MeshLodSelectionBias: 0
m_RenderingLayerMask: 1
m_RendererPriority: 0
m_Materials:
- {fileID: 0}
m_StaticBatchInfo:
firstSubMesh: 0
subMeshCount: 0
m_StaticBatchRoot: {fileID: 0}
m_ProbeAnchor: {fileID: 0}
m_LightProbeVolumeOverride: {fileID: 0}
m_ScaleInLightmap: 1
m_ReceiveGI: 1
m_PreserveUVs: 0
m_IgnoreNormalsForChartDetection: 0
m_ImportantGI: 0
m_StitchLightmapSeams: 1
m_SelectedEditorRenderState: 3
m_MinimumChartSize: 4
m_AutoUVMaxDistance: 0.5
m_AutoUVMaxAngle: 89
m_LightmapParameters: {fileID: 0}
m_GlobalIlluminationMeshLod: 0
m_SortingLayerID: 0
m_SortingLayer: 0
m_SortingOrder: 0
m_MaskInteraction: 0
m_AdditionalVertexStreams: {fileID: 0}

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: a91e5d5b7475218478febc7ec41f4b9a
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -69,3 +69,33 @@ MonoBehaviour:
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 3810918154428190126, guid: a91e5d5b7475218478febc7ec41f4b9a, type: 3}
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 5764052602947399654, guid: eccdace7a7b21a446891da5739b1549f, type: 3}
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 8497750939283614707, guid: 4ee9b364dfe9d0949a23374e660d3e13, type: 3}
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 7862005309935152867, guid: 9cac250ebe8d420469bd4da3ab8cfd86, type: 3}
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 4357115039351603180, guid: ff2924ffa397a8e44925625790831d25, type: 3}
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}
- Override: 0
Prefab: {fileID: 4147164034265547914, guid: e8d09b814275ad745a427433c28dd53f, type: 3}
SourcePrefabToOverride: {fileID: 0}
SourceHashToOverride: 0
OverridingTargetPrefab: {fileID: 0}

View File

@@ -12,6 +12,27 @@ namespace Northbound.Editor
{
private static readonly string GAMEDATA_PATH = Path.Combine(Application.dataPath, "..", "GameData");
private static readonly string SO_BASE_PATH = "Assets/Data/ScriptableObjects";
private static readonly string PREFAB_BASE_PATH = "Assets/Prefabs";
private static readonly string TEMPLATE_BASE_PATH = "Assets/Data/Templates";
private static System.Collections.Generic.Dictionary<string, IPrefabSetup> prefabSetups =
new System.Collections.Generic.Dictionary<string, IPrefabSetup>();
static CSVToSOImporter()
{
RegisterPrefabSetups();
}
private static void RegisterPrefabSetups()
{
prefabSetups.Clear();
prefabSetups["Monster"] = new MonsterPrefabSetup();
// To add new data types, create a class implementing IPrefabSetup
// Example:
// prefabSetups["Tower"] = new TowerPrefabSetup();
// prefabSetups["Player"] = new PlayerPrefabSetup();
}
[MenuItem("Tools/Data/Import All CSV")] // 메뉴 추가 (편의성)
public static void ImportAll()
@@ -54,6 +75,7 @@ namespace Northbound.Editor
if (lines.Length < 2) return false;
var headers = ParseCSVLine(lines[0]);
var createdSOs = new List<ScriptableObject>();
for (int lineIndex = 1; lineIndex < lines.Length; lineIndex++)
{
@@ -72,7 +94,12 @@ namespace Northbound.Editor
}
string assetName = GetAssetName(so, lineIndex);
AssetDatabase.CreateAsset(so, Path.Combine(outputPath, $"{assetName}.asset"));
string soPath = Path.Combine(outputPath, $"{assetName}.asset");
AssetDatabase.CreateAsset(so, soPath);
createdSOs.Add(so);
GenerateOrUpdatePrefab(schemaName, assetName, so, lineIndex);
}
AssetDatabase.SaveAssets();
@@ -148,11 +175,97 @@ namespace Northbound.Editor
return l == "true" || l == "1" || l == "yes";
}
if (targetType == typeof(string)) return value.Replace("\\n", "\n");
return Convert.ChangeType(value, targetType);
return Convert.ChangeType(value, targetType);
}
catch { return null; }
}
private static int GetColumnIndex(string[] headers, string columnName)
{
for (int i = 0; i < headers.Length; i++)
{
if (headers[i].Equals(columnName, System.StringComparison.OrdinalIgnoreCase))
{
return i;
}
}
return -1;
}
private static void GenerateOrUpdatePrefab(string schemaName, string prefabName, ScriptableObject so, int lineNumber)
{
string prefabOutputPath = Path.Combine(PREFAB_BASE_PATH, schemaName);
if (!Directory.Exists(prefabOutputPath))
{
Directory.CreateDirectory(prefabOutputPath);
}
string prefabPath = Path.Combine(prefabOutputPath, $"{prefabName}.prefab");
IPrefabSetup prefabSetup = GetPrefabSetup(schemaName);
if (prefabSetup == null)
{
Debug.LogWarning($"[CSVImporter] No prefab setup found for {schemaName}, skipping prefab generation");
return;
}
GameObject template = LoadTemplate(schemaName);
if (template == null)
{
Debug.LogWarning($"[CSVImporter] No template found for {schemaName}, skipping prefab generation");
return;
}
if (AssetDatabase.LoadAssetAtPath<GameObject>(prefabPath) != null)
{
UpdateExistingPrefab(prefabPath, so, prefabSetup);
}
else
{
GameObject prefabInstance = GameObject.Instantiate(template);
prefabInstance.name = prefabName;
PrefabUtility.SaveAsPrefabAsset(prefabInstance, prefabPath);
GameObject.DestroyImmediate(prefabInstance);
UpdateExistingPrefab(prefabPath, so, prefabSetup);
Debug.Log($"[CSVImporter] Created prefab: {prefabPath}");
}
AssetDatabase.SaveAssets();
}
private static GameObject LoadTemplate(string schemaName)
{
string templatePath = Path.Combine(TEMPLATE_BASE_PATH, $"{schemaName}Template.prefab");
return AssetDatabase.LoadAssetAtPath<GameObject>(templatePath);
}
private static IPrefabSetup GetPrefabSetup(string schemaName)
{
prefabSetups.TryGetValue(schemaName, out IPrefabSetup setup);
return setup;
}
private static void UpdateExistingPrefab(string prefabPath, ScriptableObject so, IPrefabSetup prefabSetup)
{
GameObject prefabContents = PrefabUtility.LoadPrefabContents(prefabPath);
prefabSetup.SetupPrefab(prefabContents, so);
PrefabUtility.SaveAsPrefabAsset(prefabContents, prefabPath);
GameObject.DestroyImmediate(prefabContents);
}
private static void RemoveOldModel(GameObject prefab)
{
Transform oldModel = prefab.transform.Find("Model");
if (oldModel != null)
{
GameObject.DestroyImmediate(oldModel.gameObject);
}
}
// --- 유틸리티 메서드 (기존과 동일) ---
private static string[] ParseCSVLine(string line)
{

8
Assets/Meshes.meta Normal file
View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 8e1c86a713708ce44a1f0dfaec088917
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,110 @@
fileFormatVersion: 2
guid: 134023580cb126541be31f65cf1db789
ModelImporter:
serializedVersion: 24200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 3
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importPhysicalCameras: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
generateMeshLods: 0
meshLodGenerationFlags: 0
maximumMeshLod: -1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
strictVertexDataChecks: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName: root
hasTranslationDoF: 0
hasExtraRoot: 1
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 1
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

Binary file not shown.

View File

@@ -0,0 +1,110 @@
fileFormatVersion: 2
guid: e5f93785b41f28a41b45c24d60a3eb28
ModelImporter:
serializedVersion: 24200
internalIDToNameTable: []
externalObjects: {}
materials:
materialImportMode: 2
materialName: 0
materialSearch: 1
materialLocation: 1
animations:
legacyGenerateAnimations: 4
bakeSimulation: 0
resampleCurves: 1
optimizeGameObjects: 0
removeConstantScaleCurves: 0
motionNodeName:
animationImportErrors:
animationImportWarnings:
animationRetargetingWarnings:
animationDoRetargetingWarnings: 0
importAnimatedCustomProperties: 0
importConstraints: 0
animationCompression: 1
animationRotationError: 0.5
animationPositionError: 0.5
animationScaleError: 0.5
animationWrapMode: 0
extraExposedTransformPaths: []
extraUserProperties: []
clipAnimations: []
isReadable: 0
meshes:
lODScreenPercentages: []
globalScale: 1
meshCompression: 0
addColliders: 0
useSRGBMaterialColor: 1
sortHierarchyByName: 1
importPhysicalCameras: 1
importVisibility: 1
importBlendShapes: 1
importCameras: 1
importLights: 1
nodeNameCollisionStrategy: 1
fileIdsGeneration: 2
swapUVChannels: 0
generateSecondaryUV: 0
useFileUnits: 1
keepQuads: 0
weldVertices: 1
bakeAxisConversion: 0
preserveHierarchy: 0
skinWeightsMode: 0
maxBonesPerVertex: 4
minBoneWeight: 0.001
optimizeBones: 1
generateMeshLods: 0
meshLodGenerationFlags: 0
maximumMeshLod: -1
meshOptimizationFlags: -1
indexFormat: 0
secondaryUVAngleDistortion: 8
secondaryUVAreaDistortion: 15.000001
secondaryUVHardAngle: 88
secondaryUVMarginMethod: 1
secondaryUVMinLightmapResolution: 40
secondaryUVMinObjectScale: 1
secondaryUVPackMargin: 4
useFileScale: 1
strictVertexDataChecks: 0
tangentSpace:
normalSmoothAngle: 60
normalImportMode: 0
tangentImportMode: 3
normalCalculationMode: 4
legacyComputeAllNormalsFromSmoothingGroupsWhenMeshHasBlendShapes: 0
blendShapeNormalImportMode: 1
normalSmoothingSource: 0
referencedClips: []
importAnimation: 1
humanDescription:
serializedVersion: 3
human: []
skeleton: []
armTwist: 0.5
foreArmTwist: 0.5
upperLegTwist: 0.5
legTwist: 0.5
armStretch: 0.05
legStretch: 0.05
feetSpacing: 0
globalScale: 1
rootMotionBoneName:
hasTranslationDoF: 0
hasExtraRoot: 0
skeletonHasParents: 1
lastHumanDescriptionAvatarSource: {instanceID: 0}
autoGenerateAvatarMappingIfUnspecified: 1
animationType: 2
humanoidOversampling: 1
avatarSetup: 0
addHumanoidExtraRootOnlyWhenUsingAvatar: 1
importBlendShapeDeformPercent: 1
remapMaterialsIfMaterialImportModeIsNone: 0
additionalBone: 0
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: a685391aa8ab5b94a9930a3b11bdb4e4
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -49,7 +49,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: d5a57f767e5e46a458fc5d3c628d0cbb, type: 3}
m_Name:
m_EditorClassIdentifier: Unity.Netcode.Runtime::Unity.Netcode.NetworkObject
GlobalObjectIdHash: 3777549664
GlobalObjectIdHash: 2325681781
InScenePlacedSourceGlobalObjectIdHash: 190018048
DeferredDespawnTick: 0
Ownership: 1
@@ -77,7 +77,6 @@ MonoBehaviour:
ShowTopMostFoldoutHeaderGroup: 1
enemyTeam: 2
maxHealth: 100
visionRange: 0
damageEffectPrefab: {fileID: 0}
destroyEffectPrefab: {fileID: 0}
--- !u!195 &3722870329869553245

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 01eaba87f2878e2419105e30e0b9e572
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: eccdace7a7b21a446891da5739b1549f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 4ee9b364dfe9d0949a23374e660d3e13
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 9cac250ebe8d420469bd4da3ab8cfd86
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: ff2924ffa397a8e44925625790831d25
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: e8d09b814275ad745a427433c28dd53f
PrefabImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: 9f4ee65fec2f6ff439a564550b072221
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: e2baea03a27214c4fb8085788c5b7443
folderAsset: yes
DefaultImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:

View File

@@ -1891,6 +1891,26 @@ PrefabInstance:
propertyPath: m_Name
value: EnemyPortal (1)
objectReference: {fileID: 0}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[0].prefab
value:
objectReference: {fileID: 8774623643640324048, guid: c92c9f1bf0ae6364f85409ecdc4aeaf3, type: 3}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[1].prefab
value:
objectReference: {fileID: 5176576196123937037, guid: 951b69041a2ace947afd721fefb3eaba, type: 3}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[0].monsterData
value:
objectReference: {fileID: 0}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[1].monsterData
value:
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []
@@ -2341,10 +2361,10 @@ MonoBehaviour:
m_Name:
m_EditorClassIdentifier: Assembly-CSharp::Northbound.GlobalTimer
ShowTopMostFoldoutHeaderGroup: 1
cycleLength: 90
cycleLength: 5
autoStart: 1
pauseOnZero: 0
exceptionalFirstCycleLength: 10
exceptionalFirstCycleLength: 1
showDebugLogs: 1
--- !u!4 &1442785555
Transform:
@@ -3224,6 +3244,26 @@ PrefabInstance:
propertyPath: m_Name
value: EnemyPortal
objectReference: {fileID: 0}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.size
value: 0
objectReference: {fileID: 0}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[0].prefab
value:
objectReference: {fileID: 8774623643640324048, guid: c92c9f1bf0ae6364f85409ecdc4aeaf3, type: 3}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[1].prefab
value:
objectReference: {fileID: 5176576196123937037, guid: 951b69041a2ace947afd721fefb3eaba, type: 3}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[0].monsterData
value:
objectReference: {fileID: 0}
- target: {fileID: 6859825394817103090, guid: 11e3760dda2c0164abf759c18d918893, type: 3}
propertyPath: monsterEntries.Array.data[1].monsterData
value:
objectReference: {fileID: 0}
m_RemovedComponents: []
m_RemovedGameObjects: []
m_AddedGameObjects: []

View File

@@ -0,0 +1,77 @@
using Northbound;
using Northbound.Data;
using UnityEngine;
using UnityEditor;
using System.Collections.Generic;
using System.Linq;
[CustomEditor(typeof(EnemyPortal))]
public class EnemyPortalEditor : Editor
{
private const string MONSTER_PREFAB_FOLDER = "Assets/Prefabs/Monster";
public override void OnInspectorGUI()
{
DrawDefaultInspector();
EnemyPortal portal = (EnemyPortal)target;
EditorGUILayout.Space();
EditorGUILayout.LabelField("Monster Data Loader", EditorStyles.boldLabel);
if (GUILayout.Button("Load Monster Data"))
{
LoadMonsterData(portal);
}
EditorGUILayout.HelpBox("Click 'Load Monster Data' to automatically load all monster prefabs from " + MONSTER_PREFAB_FOLDER, MessageType.Info);
}
private void LoadMonsterData(EnemyPortal portal)
{
string[] guids = AssetDatabase.FindAssets("t:Prefab", new[] { MONSTER_PREFAB_FOLDER });
List<EnemyPortal.MonsterEntry> entries = new List<EnemyPortal.MonsterEntry>();
int loadedCount = 0;
foreach (string guid in guids)
{
string assetPath = AssetDatabase.GUIDToAssetPath(guid);
GameObject prefab = AssetDatabase.LoadAssetAtPath<GameObject>(assetPath);
if (prefab != null)
{
MonsterDataComponent monsterDataComponent = prefab.GetComponent<MonsterDataComponent>();
if (monsterDataComponent != null && monsterDataComponent.monsterData != null)
{
entries.Add(new EnemyPortal.MonsterEntry
{
prefab = prefab
});
loadedCount++;
}
else
{
Debug.LogWarning($"[EnemyPortal] Prefab {prefab.name} does not have MonsterDataComponent with valid monsterData reference");
}
}
}
serializedObject.Update();
SerializedProperty entriesProperty = serializedObject.FindProperty("monsterEntries");
entriesProperty.ClearArray();
entriesProperty.arraySize = entries.Count;
for (int i = 0; i < entries.Count; i++)
{
SerializedProperty element = entriesProperty.GetArrayElementAtIndex(i);
element.FindPropertyRelative("prefab").objectReferenceValue = entries[i].prefab;
}
serializedObject.ApplyModifiedProperties();
AssetDatabase.SaveAssets();
Debug.Log($"[EnemyPortal] Loaded {loadedCount} monsters from {MONSTER_PREFAB_FOLDER}");
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 70cde0c89ff88c149b6535cc2e9903b3

View File

@@ -0,0 +1,10 @@
using UnityEngine;
namespace Northbound.Editor
{
public interface IPrefabSetup
{
string GetTemplateName();
void SetupPrefab(GameObject prefab, ScriptableObject data);
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: ddd133259cf685c4da37370144003c52

View File

@@ -0,0 +1,99 @@
using Northbound.Data;
using UnityEditor;
using UnityEngine;
namespace Northbound.Editor
{
public class MonsterPrefabSetup : IPrefabSetup
{
public string GetTemplateName()
{
return "MonsterTemplate";
}
public void SetupPrefab(GameObject prefab, ScriptableObject data)
{
if (!(data is MonsterData monsterData))
{
Debug.LogWarning($"[MonsterPrefabSetup] Expected MonsterData, got {data.GetType().Name}");
return;
}
var monsterDataComponent = prefab.GetComponent<MonsterDataComponent>();
if (monsterDataComponent != null)
{
monsterDataComponent.monsterData = monsterData;
monsterDataComponent.ApplyMonsterData();
}
if (!string.IsNullOrEmpty(monsterData.meshPath))
{
RemoveOldModel(prefab);
if (monsterData.meshPath.ToLower().EndsWith(".fbx"))
{
GameObject fbxModel = AssetDatabase.LoadAssetAtPath<GameObject>(monsterData.meshPath);
if (fbxModel != null)
{
GameObject fbxInstance = GameObject.Instantiate(fbxModel);
fbxInstance.name = "Model";
fbxInstance.transform.SetParent(prefab.transform, false);
fbxInstance.transform.localPosition = Vector3.zero;
fbxInstance.transform.localRotation = Quaternion.identity;
fbxInstance.transform.localScale = Vector3.one;
Debug.Log($"[MonsterPrefabSetup] Applied FBX model: {monsterData.meshPath}");
}
else
{
Debug.LogWarning($"[MonsterPrefabSetup] Could not load FBX model: {monsterData.meshPath}");
}
}
else
{
var meshFilter = prefab.GetComponent<MeshFilter>();
if (meshFilter != null)
{
Mesh mesh = AssetDatabase.LoadAssetAtPath<Mesh>(monsterData.meshPath);
if (mesh != null)
{
meshFilter.sharedMesh = mesh;
Debug.Log($"[MonsterPrefabSetup] Applied mesh: {monsterData.meshPath}");
}
else
{
Debug.LogWarning($"[MonsterPrefabSetup] Could not load mesh: {monsterData.meshPath}");
}
}
}
}
if (!string.IsNullOrEmpty(monsterData.animatorControllerPath))
{
Animator animator = prefab.GetComponent<Animator>();
if (animator != null)
{
RuntimeAnimatorController controller = AssetDatabase.LoadAssetAtPath<RuntimeAnimatorController>(monsterData.animatorControllerPath);
if (controller != null)
{
animator.runtimeAnimatorController = controller;
Debug.Log($"[MonsterPrefabSetup] Applied Animator Controller: {monsterData.animatorControllerPath}");
}
else
{
Debug.LogWarning($"[MonsterPrefabSetup] Could not load Animator Controller: {monsterData.animatorControllerPath}");
}
}
}
}
private void RemoveOldModel(GameObject prefab)
{
Transform oldModel = prefab.transform.Find("Model");
if (oldModel != null)
{
GameObject.DestroyImmediate(oldModel.gameObject);
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9d78ef5bde300404a89bb3af71df1610

View File

@@ -0,0 +1,180 @@
using Unity.Netcode;
using UnityEditor;
using UnityEngine;
using UnityEngine.AI;
namespace Northbound.Editor
{
public class TemplateCreator
{
private const string TEMPLATE_BASE_PATH = "Assets/Data/Templates";
[MenuItem("Tools/Data/Create Monster Template")]
public static void CreateMonsterTemplate()
{
CreateTemplate("Monster", SetupMonsterComponents);
}
[MenuItem("Tools/Data/Create Tower Template")]
public static void CreateTowerTemplate()
{
CreateTemplate("Tower", SetupTowerComponents);
}
[MenuItem("Tools/Data/Create Player Template")]
public static void CreatePlayerTemplate()
{
CreateTemplate("Player", SetupPlayerComponents);
}
private static void CreateTemplate(string typeName, System.Action<GameObject> setupComponents)
{
if (!AssetDatabase.IsValidFolder(TEMPLATE_BASE_PATH))
{
System.IO.Directory.CreateDirectory(Application.dataPath + "/Data/Templates");
AssetDatabase.Refresh();
}
string templateName = $"{typeName}Template";
string templatePath = $"{TEMPLATE_BASE_PATH}/{templateName}.prefab";
GameObject templateGO = new GameObject(templateName);
setupComponents(templateGO);
PrefabUtility.SaveAsPrefabAsset(templateGO, templatePath);
GameObject.DestroyImmediate(templateGO);
Debug.Log($"[TemplateCreator] Created template: {templatePath}");
AssetDatabase.Refresh();
Selection.activeObject = AssetDatabase.LoadAssetAtPath<GameObject>(templatePath);
}
private static void SetupMonsterComponents(GameObject go)
{
Transform t = go.transform;
t.localPosition = Vector3.zero;
t.localRotation = Quaternion.identity;
t.localScale = Vector3.one;
if (go.GetComponent<CapsuleCollider>() == null)
{
CapsuleCollider collider = go.AddComponent<CapsuleCollider>();
collider.isTrigger = false;
collider.radius = 0.5f;
collider.height = 2f;
collider.direction = 1;
collider.center = Vector3.zero;
}
if (go.GetComponent<Animator>() == null)
{
Animator animator = go.AddComponent<Animator>();
animator.runtimeAnimatorController = null;
animator.avatar = null;
animator.applyRootMotion = false;
animator.updateMode = AnimatorUpdateMode.Normal;
animator.cullingMode = AnimatorCullingMode.CullUpdateTransforms;
}
if (go.GetComponent<NetworkObject>() == null)
go.AddComponent<NetworkObject>();
if (go.GetComponent<EnemyUnit>() == null)
go.AddComponent<EnemyUnit>();
if (go.GetComponent<MonsterDataComponent>() == null)
go.AddComponent<MonsterDataComponent>();
if (go.GetComponent<NavMeshAgent>() == null)
{
NavMeshAgent agent = go.AddComponent<NavMeshAgent>();
agent.speed = 2.6f;
agent.angularSpeed = 120f;
agent.acceleration = 8f;
agent.stoppingDistance = 0f;
agent.autoBraking = true;
agent.radius = 0.5f;
agent.height = 2f;
}
if (go.GetComponent<EnemyAIController>() == null)
{
EnemyAIController ai = go.AddComponent<EnemyAIController>();
ai.aiType = TeamType.Monster;
ai.detectionRange = 6f;
ai.detectionAngle = 360f;
ai.maxChaseDistance = 30f;
ai.attackRange = 1f;
ai.attackInterval = 1.2f;
ai.attackDamage = 3;
ai.moveSpeed = 2.6f;
ai.chaseSpeedMultiplier = 1.2f;
}
MeshFilter meshFilter = go.GetComponent<MeshFilter>();
if (meshFilter == null)
meshFilter = go.AddComponent<MeshFilter>();
MeshRenderer meshRenderer = go.GetComponent<MeshRenderer>();
if (meshRenderer == null)
meshRenderer = go.AddComponent<MeshRenderer>();
int monsterLayer = LayerMask.NameToLayer("Monster");
if (monsterLayer >= 0)
{
go.layer = monsterLayer;
}
else
{
go.layer = 0;
}
NetworkObject netObj = go.GetComponent<NetworkObject>();
if (netObj != null)
{
netObj.SynchronizeTransform = true;
netObj.SpawnWithObservers = true;
netObj.AlwaysReplicateAsRoot = false;
}
EnemyUnit enemyUnit = go.GetComponent<EnemyUnit>();
if (enemyUnit != null)
{
enemyUnit.enemyTeam = TeamType.Monster;
}
}
private static void SetupTowerComponents(GameObject go)
{
if (go.GetComponent<NetworkObject>() == null)
go.AddComponent<NetworkObject>();
int defaultLayer = LayerMask.NameToLayer("Default");
if (defaultLayer >= 0)
{
go.layer = defaultLayer;
}
else
{
go.layer = 0;
}
}
private static void SetupPlayerComponents(GameObject go)
{
if (go.GetComponent<NetworkObject>() == null)
go.AddComponent<NetworkObject>();
int playerLayer = LayerMask.NameToLayer("Player");
if (playerLayer >= 0)
{
go.layer = playerLayer;
}
else
{
go.layer = 0;
}
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: 9b0786fac9db245429b33a2597a2d7b4

View File

@@ -1,44 +1,150 @@
using Northbound;
using Northbound.Data;
using System.Collections.Generic;
using Unity.Netcode;
using UnityEngine;
using static Northbound.ObstacleSpawner;
using static UnityEditor.FilePathAttribute;
public class EnemyPortal : MonoBehaviour
{
[Header("Spawn Settings")]
[Tooltip("소환할 몬스터 목록")]
[SerializeField] private List<GameObject> Enemies = new();
// Start is called once before the first execution of Update after the MonoBehaviour is created
void Start()
[System.Serializable]
public class MonsterEntry
{
GlobalTimer.Instance.OnCycleComplete += SpawnEnemy;
public GameObject prefab;
}
private void SpawnEnemy()
{
foreach (GameObject obj in Enemies)
{
GameObject enemy = Instantiate(obj, transform);
[Header("Spawn Settings")]
[Tooltip("몬스터 프리팹 목록 (Editor에서 자동 로드 가능)")]
[SerializeField] private List<MonsterEntry> monsterEntries = new();
// Add FogOfWarVisibility component to hide enemies in unexplored areas
if (enemy.GetComponent<FogOfWarVisibility>() == null)
[Header("Cost Settings")]
[Tooltip("시간당 코스트 시작 값")]
[SerializeField] private float initialCost = 4f;
[Tooltip("사이클마다 코스트 증가율 (%)")]
[SerializeField] private float costIncreaseRate = 10f;
private float currentCost;
void Start()
{
currentCost = initialCost;
GlobalTimer.Instance.OnCycleStart += OnCycleStart;
}
private void OnCycleStart(int cycleNumber)
{
SpawnMonsters();
IncreaseCost();
}
private void SpawnMonsters()
{
float remainingCost = currentCost;
int spawnedCount = 0;
while (remainingCost > 0 && monsterEntries.Count > 0)
{
MonsterEntry selectedEntry = SelectMonsterByWeight();
MonsterData monsterData = GetMonsterDataFromPrefab(selectedEntry.prefab);
if (monsterData == null)
{
var visibility = enemy.AddComponent<FogOfWarVisibility>();
visibility.showInExploredAreas = false; // Enemies hidden when not visible
visibility.updateInterval = 0.2f;
Debug.LogWarning($"[EnemyPortal] Could not find MonsterData on {selectedEntry.prefab.name}");
continue;
}
enemy.GetComponent<NetworkObject>().Spawn();
Debug.Log(enemy);
if (monsterData.cost > remainingCost)
{
if (!CanSpawnAnyMonster(remainingCost))
{
break;
}
continue;
}
SpawnEnemy(selectedEntry.prefab);
remainingCost -= monsterData.cost;
spawnedCount++;
}
if (spawnedCount > 0)
{
Debug.Log($"[EnemyPortal] Spawned {spawnedCount} monsters (Cost used: {currentCost - remainingCost:F2})");
}
}
// Update is called once per frame
void Update()
private bool CanSpawnAnyMonster(float remainingCost)
{
foreach (var entry in monsterEntries)
{
MonsterData monsterData = GetMonsterDataFromPrefab(entry.prefab);
if (monsterData != null && monsterData.cost <= remainingCost)
{
return true;
}
}
return false;
}
private MonsterEntry SelectMonsterByWeight()
{
float totalWeight = 0f;
foreach (var entry in monsterEntries)
{
MonsterData monsterData = GetMonsterDataFromPrefab(entry.prefab);
if (monsterData != null)
{
totalWeight += monsterData.weight;
}
}
float randomValue = Random.Range(0f, totalWeight);
float cumulativeWeight = 0f;
foreach (var entry in monsterEntries)
{
MonsterData monsterData = GetMonsterDataFromPrefab(entry.prefab);
if (monsterData != null)
{
cumulativeWeight += monsterData.weight;
if (randomValue <= cumulativeWeight)
{
return entry;
}
}
}
return monsterEntries[0];
}
private MonsterData GetMonsterDataFromPrefab(GameObject prefab)
{
if (prefab == null) return null;
MonsterDataComponent component = prefab.GetComponent<MonsterDataComponent>();
if (component != null)
{
return component.monsterData;
}
return null;
}
private void SpawnEnemy(GameObject prefab)
{
GameObject enemy = Instantiate(prefab, transform);
if (enemy.GetComponent<FogOfWarVisibility>() == null)
{
var visibility = enemy.AddComponent<FogOfWarVisibility>();
visibility.showInExploredAreas = false;
visibility.updateInterval = 0.2f;
}
enemy.GetComponent<NetworkObject>().Spawn();
}
private void IncreaseCost()
{
currentCost *= (1f + costIncreaseRate / 100f);
}
}

View File

@@ -0,0 +1,62 @@
using Northbound.Data;
using Unity.Netcode;
using UnityEngine;
using UnityEngine.AI;
namespace Northbound
{
[RequireComponent(typeof(EnemyUnit))]
[RequireComponent(typeof(EnemyAIController))]
[RequireComponent(typeof(NavMeshAgent))]
[RequireComponent(typeof(NetworkObject))]
public class MonsterDataComponent : MonoBehaviour
{
[Header("Data Reference")]
[Tooltip("ScriptableObject containing monster data")]
public MonsterData monsterData;
[Header("Auto-Apply Settings")]
[Tooltip("Automatically apply stats from monsterData on Awake")]
public bool autoApplyOnAwake = true;
private void Awake()
{
if (autoApplyOnAwake && monsterData != null)
{
ApplyMonsterData();
}
}
public void ApplyMonsterData()
{
if (monsterData == null)
{
Debug.LogWarning("[MonsterDataComponent] monsterData is null", this);
return;
}
EnemyUnit enemyUnit = GetComponent<EnemyUnit>();
if (enemyUnit != null)
{
enemyUnit.maxHealth = monsterData.maxHp;
}
EnemyAIController aiController = GetComponent<EnemyAIController>();
if (aiController != null)
{
aiController.moveSpeed = monsterData.moveSpeed;
aiController.attackDamage = monsterData.atkDamage;
aiController.attackRange = monsterData.atkRange;
aiController.attackInterval = monsterData.atkIntervalSec;
}
NavMeshAgent navAgent = GetComponent<NavMeshAgent>();
if (navAgent != null)
{
navAgent.speed = monsterData.moveSpeed;
}
Debug.Log($"[MonsterDataComponent] Applied data for {monsterData.id} ({monsterData.memo})", this);
}
}
}

View File

@@ -0,0 +1,2 @@
fileFormatVersion: 2
guid: d702d872f7bcec54baa1f2ee285fc844

View File

@@ -43,7 +43,6 @@
<UnityVersion>6000.3.5f2</UnityVersion>
</PropertyGroup>
<ItemGroup>
<Analyzer Include="C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\Microsoft\Visual Studio Tools for Unity\Analyzers\Microsoft.Unity.Analyzers.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.SourceGenerators.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.Properties.SourceGenerator.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.UIToolkit.SourceGenerator.dll" />

View File

@@ -43,7 +43,6 @@
<UnityVersion>6000.3.5f2</UnityVersion>
</PropertyGroup>
<ItemGroup>
<Analyzer Include="C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\Microsoft\Visual Studio Tools for Unity\Analyzers\Microsoft.Unity.Analyzers.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.SourceGenerators.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.Properties.SourceGenerator.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.UIToolkit.SourceGenerator.dll" />

154
GENERIC_IMPORTER.md Normal file
View File

@@ -0,0 +1,154 @@
# Generic CSV Importer System
## Overview
The CSV importer now works with **any data type**, not just monsters! Each data type has its own prefab setup logic.
## How It Works
```
CSV File (any type)
↓ Importer
ScriptableObject (data)
↓ Prefab Setup
Prefab (with components, models, etc.)
```
## Architecture
### 1. IPrefabSetup Interface
```csharp
public interface IPrefabSetup
{
string GetTemplateName(); // Which template to use
void SetupPrefab(GameObject prefab, ScriptableObject data); // How to setup
}
```
### 2. Prefab Setup Handlers
Each data type has its own setup class:
**MonsterPrefabSetup.cs**
- Handles MonsterData
- Applies FBX models
- Sets Animator controllers
- Updates MonsterDataComponent
**To add new types:**
1. Create `NewTypePrefabSetup.cs` implementing `IPrefabSetup`
2. Register in `CSVToSOImporter.RegisterPrefabSetups()`
3. Done!
### 3. Templates
Each data type has its own template:
```
Assets/Data/Templates/
├── MonsterTemplate.prefab → For monsters
├── TowerTemplate.prefab → For towers (to create)
└── PlayerTemplate.prefab → For players (to create)
```
Templates define:
- Required components
- Component defaults
- Layer settings
- etc.
## Adding New Data Types
### Step 1: Create Template
```csharp
// TemplateCreator.cs
Tools > Data > Create [TypeName] Template
```
### Step 2: Create Setup Handler
```csharp
// TowerPrefabSetup.cs
using UnityEditor;
using UnityEngine;
namespace Northbound.Editor
{
public class TowerPrefabSetup : IPrefabSetup
{
public string GetTemplateName()
{
return "TowerTemplate";
}
public void SetupPrefab(GameObject prefab, ScriptableObject data)
{
// Your custom logic here
// e.g., add models, apply stats, etc.
Debug.Log($"[TowerPrefabSetup] Setting up {data.name}");
}
}
}
```
### Step 3: Register Handler
```csharp
// CSVToSOImporter.cs - RegisterPrefabSetups()
prefabSetups["Tower"] = new TowerPrefabSetup();
```
### Step 4: Create CSV
```
GameData/Tower.csv
id,name,cost,...
101,ArrowTower,50,...
```
### Step 5: Import
```
Tools > Data > Import All CSV
```
Done! Prefabs auto-generated for Towers.
## Benefits
**Generic**: Works for ANY data type
**Extensible**: Easy to add new types
**Type-Safe**: Each type has its own logic
**Maintainable**: No monster-specific code in importer
**Automated**: CSV → SO → Prefab in one click
## Example: Complete Flow for Monster
1. **Designer edits CSV**: `GameData/Monster.csv`
2. **Imports data**: `Tools > Data > Import All CSV`
3. **Importer**:
- Reads CSV rows
- Creates Monster101.asset (SO)
- Clones MonsterTemplate.prefab
- Calls MonsterPrefabSetup.SetupPrefab()
- Saves as Monster101.prefab
4. **MonsterPrefabSetup**:
- Links SO to MonsterDataComponent
- Applies FBX model
- Sets Animator controller
5. **Result**: Complete prefab ready to use!
## Troubleshooting
**"No prefab setup found for [Type]"**
- Create `TypePrefabSetup.cs` implementing `IPrefabSetup`
- Register it in `RegisterPrefabSetups()`
**"No template found for [Type]"**
- Create `[Type]Template.prefab` using `Tools > Data > Create Template`
- Ensure name matches `GetTemplateName()` return value
**Prefabs not updating**
- Check that your setup logic is in `SetupPrefab()`
- Verify SO fields are being read correctly

View File

@@ -1,6 +1,6 @@
id,memo,move_speed,max_hp,atk_range,atk_damage,atk_interval_sec,prefab_path,cost,weight
101,Grunt(기본),2.6,30,1,3,1.2,Assets/Prefabs/EnemyTest,1,1.0
102,Fast(빠름/약함),3.4,18,1,2,1.0,Assets/Prefabs/MonsterTest,2,0.5
103,Tank(느림/단단),2.0,70,1,4,1.5,Assets/Prefabs/Core,5,0.2
104,Ranged(원거리/약함),2.4,22,5,2,1.4,Assets/Prefabs/Resource,3,0.333
105,Elite(소수 정예),2.8,120,1,7,1.3,Assets/Prefabs/ResourcePickup,10,0.1
id,memo,move_speed,max_hp,atk_range,atk_damage,atk_interval_sec,prefab_path,cost,weight,mesh_path
101,Grunt(기본),2.6,30,1,3,1.2,Assets/Prefabs/EnemyTest,1,1.0,Assets/Meshes/Skeleton_Minion.fbx
102,Fast(빠름/약함),3.4,18,1,2,1.0,Assets/Prefabs/MonsterTest,2,0.5,Assets/Meshes/Skeleton_Minion.fbx
103,Tank(느림/단단),2.0,70,1,4,1.5,Assets/Prefabs/Core,5,0.2,Assets/Meshes/Skeleton_Minion.fbx
104,Ranged(원거리/약함),2.4,22,5,2,1.4,Assets/Prefabs/Resource,3,0.333,Assets/Meshes/Skeleton_Minion.fbx
105,Elite(소수 정예),2.8,120,1,7,1.3,Assets/Prefabs/ResourcePickup,10,0.1,Assets/Meshes/Skeleton_Minion.fbx
1 id memo move_speed max_hp atk_range atk_damage atk_interval_sec prefab_path cost weight mesh_path
2 101 Grunt(기본) 2.6 30 1 3 1.2 Assets/Prefabs/EnemyTest 1 1.0 Assets/Meshes/Skeleton_Minion.fbx
3 102 Fast(빠름/약함) 3.4 18 1 2 1.0 Assets/Prefabs/MonsterTest 2 0.5 Assets/Meshes/Skeleton_Minion.fbx
4 103 Tank(느림/단단) 2.0 70 1 4 1.5 Assets/Prefabs/Core 5 0.2 Assets/Meshes/Skeleton_Minion.fbx
5 104 Ranged(원거리/약함) 2.4 22 5 2 1.4 Assets/Prefabs/Resource 3 0.333 Assets/Meshes/Skeleton_Minion.fbx
6 105 Elite(소수 정예) 2.8 120 1 7 1.3 Assets/Prefabs/ResourcePickup 10 0.1 Assets/Meshes/Skeleton_Minion.fbx

View File

@@ -16,8 +16,8 @@ TagManager:
- Enemy
- Player
- Obstacle
-
-
- Monster
-
-
-
-

View File

@@ -43,15 +43,14 @@
<UnityVersion>6000.3.5f2</UnityVersion>
</PropertyGroup>
<ItemGroup>
<Analyzer Include="C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\Extensions\Microsoft\Visual Studio Tools for Unity\Analyzers\Microsoft.Unity.Analyzers.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.SourceGenerators.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.Properties.SourceGenerator.dll" />
<Analyzer Include="C:\Program Files\Unity\Hub\Editor\6000.3.5f2\Editor\Data\Tools\BuildPipeline\Unity.SourceGenerators\Unity.UIToolkit.SourceGenerator.dll" />
</ItemGroup>
<ItemGroup>
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Overrides\ColorAdjustments.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Passes\ScreenSpaceAmbientOcclusionPass.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Decal\Entities\DecalEntityManager.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Passes\ScreenSpaceAmbientOcclusionPass.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Overrides\ScreenSpaceLensFlare.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\History\RawColorHistory.cs" />
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\EditorAttributes\Core\DrawerAttributes\InfoBoxAttribute.cs" />
@@ -143,8 +142,8 @@
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\RenderFeatures\Outline\FlatKitOutline.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Passes\AdditionalLightsShadowAtlasLayout.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Deprecated.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Passes\ColorGradingLutPass.cs" />
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\RenderFeatures\Common\ScreenRenderPass.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Passes\ColorGradingLutPass.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Tiling\TileRangeExpansionJob.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\TemporalAA.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\VFXGraph\Utility\PropertyBinders\URPCameraBinder.cs" />
@@ -247,8 +246,8 @@
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Data\UniversalRenderPipelineAsset.DefaultResources.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Data\RenderStateData.cs" />
<Compile Include="Assets\FlatKit\[Render Pipeline] URP\EditorAttributes\Core\DrawerAttributes\DrawerAttribute.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\FrameData\UniversalLightData.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Debug\DebugHandler.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\FrameData\UniversalLightData.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Decal\Entities\DecalDrawSystem.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Passes\PostProcessPass.cs" />
<Compile Include="Library\PackageCache\com.unity.render-pipelines.universal@1e87cf1dccb8\Runtime\Passes\CapturePass.cs" />