1) 폴더/깃 구조 결정
권장 디렉토리 구조
D:\Github\ToyboxNightmare\
├─ .git/
├─ External/
│ └─ GameFramework/ ← 외부 C# 프레임워크 (별도 .csproj)
│ ├─ .git/ ← (옵션) Git 서브모듈로 관리 가능
│ ├─ GameFramework.csproj
│ ├─ Runtime/
│ └─ ... (소스 코드)
├─ Assets/
│ ├─ Plugins/
│ │ ├─ GameFramework.dll ← 빌드된 DLL (자동 복사)
│ │ └─ GameFramework.pdb ← Debug 빌드 시에만
│ ├─ Scripts/ ← 게임 로직 (DLL 참조)
│ └─ ...
├─ Packages/
│ └─ manifest.json ← Unity.SharpZipLib 등록
└─ ProjectSettings/
Plain Text
복사
이 구조의 장점
1. Assets 외부 배치의 핵심 이점
•
Unity가 External/ 폴더를 컴파일 대상에서 제외한다
•
unsafe 코드, 고급 C# 문법 사용 시 Unity 설정과 무관하게 자유롭게 개발할 수 있다
•
.csproj 파일 기반으로 Visual Studio의 모든 기능(리팩토링, 분석, NuGet 등)을 완전히 활용할 수 있다
•
참조/네임스페이스 충돌을 방지한다 (Unity의 자동 컴파일 파이프라인 우회)
2. 빌드 산출물만 Unity로 전달
•
DLL + PDB 조합으로 깔끔한 디버깅 환경을 구성한다
•
프레임워크 소스 변경 → 빌드 → Post-build로 자동 복사 → Unity가 리로드하는 흐름이다
•
CI/CD 파이프라인 구성 시 명확한 빌드 단계를 분리할 수 있다
3. Git 서브모듈 활용 (선택적)
# GameFramework를 별도 저장소로 관리하는 경우
git submodule add https://github.com/yourname/GameFramework.git External/GameFramework
Bash
복사
•
프레임워크를 여러 프로젝트에서 재사용할 수 있다
•
버전 관리 독립성을 확보할 수 있다 (Unity 프로젝트 ≠ 프레임워크 버전)
피해야 할 안티패턴
구조 | 문제점 |
Assets/GameFramework/ (소스 직접 배치) | Unity의 제한된 C# 컴파일러 사용, unsafe/고급 기능 제약, asmdef 복잡도 증가 |
Plugins에 의존성 DLL 중복 복사 | SharpZipLib 등 Unity 패키지와 충돌 (중복 타입 정의 오류) |
Debug/Release DLL 혼재 | 런타임 동작 불일치, 디버깅 혼란 |
2) External\GameFramework 프로젝트 설정(.csproj)
•
프로젝트 형식: Class Library
•
Target: .NET Standard 2.1 (또는 Unity 설정이 .NET 4.x이면 거기에 맞춤)
•
Debugging information: portable PDB
•
(필요 시) /unsafe ON → 사전 컴파일 DLL이므로 Unity 전역 "Allow 'unsafe'"는 필요 없다.
•
NuGet 의존성: (개발·빌드용) SharpZipLib 참조 추가 가능
단, Unity 쪽에 Unity.SharpZipLib 패키지를 추가했으므로 Assets로는 SharpZipLib DLL을 복사하지 않아야 한다 (중복 타입 방지).
3) 빌드 산출물 → Unity로 자동 복사 (Post-build)
프로젝트 속성 → Build Events → Post-build event 에 아래 스크립트 등록
:: === Copy to Unity (relative from csproj) ===
set "DEST=$(ProjectDir)..\..\Assets\Plugins"
if not exist "%DEST%" mkdir "%DEST%"
:: 깨끗이 정리
del /Q "%DEST%\$(TargetName).dll" 2>nul
del /Q "%DEST%\$(TargetName).pdb" 2>nul
:: (중요) Unity.SharpZipLib 패키지를 쓸 것이므로, SharpZipLib는 복사/동봉하지 않음
del /Q "%DEST%\ICSharpCode.SharpZipLib.dll" 2>nul
del /Q "%DEST%\ICSharpCode.SharpZipLib.pdb" 2>nul
:: 공통: 내 프레임워크 DLL 복사
if exist "$(TargetDir)$(TargetName).dll" copy /Y "$(TargetDir)$(TargetName).dll" "%DEST%\"
:: Debug일 때만 PDB 복사(에디터 스텝-인 디버깅)
if /I "$(ConfigurationName)"=="Debug" (
if exist "$(TargetDir)$(TargetName).pdb" copy /Y "$(TargetDir)$(TargetName).pdb" "%DEST%\"
)
echo Copied $(ConfigurationName) to: %DEST%
Shell
복사
•
경로 해석: \$(ProjectDir)..\\..\\Assets\\Plugins → External\\GameFramework\\에서 두 단계 위가 프로젝트 루트이다.
•
하나의 DLL만 유지하도록 기존 파일을 삭제한 후 복사한다.
4) Unity 쪽 설정
•
→ ICSharpCode.SharpZipLib 어셈블리를 Unity가 제공한다.
•
Api Compatibility Level: .NET 4.x(권장)
•
(asmdef 사용하는 경우)
◦
게임 코드 asmdef의 Override References를 꺼두면 Plugins의 DLL/패키지 DLL을 자동 참조한다
◦
Override References가 켜져 있다면 Assembly Definition References에 GameFramework.dll(프리컴파일)만 추가하면 된다.
(SharpZipLib는 패키지가 제공하므로 따로 추가하지 않는다)
5) 디버깅/릴리즈 운용
•
Editor에서 디버깅: Debug 빌드 + PDB 복사 → VS에서 Attach to Unity 후 스텝-인이 가능하다
•
공유/CI/릴리즈: Release 빌드 → DLL만 복사한다(필요 시 PDB도 가능하지만 최적화로 스텝이 튈 수 있다)
•
Plugins에는 동시에 하나의 변형만 유지한다(Debug/Release를 섞지 않는다)
6) (선택) 소스 직접 디버깅이 필요할 때
•
소스를 그대로 확인하고 싶다면 External/.../Runtime을 Assets/...에 심볼릭 링크/정크션으로 노출하거나,
로컬 UPM 패키지(manifest.json에 file:../External/GameFramework)로 등록한 후 디버깅이 끝나면 링크/의존성을 해제한다.
•
이때 다시 unsafe/참조 문제가 발생하면 asmdef에서 Allow Unsafe를 활성화하거나, DLL 방식으로 회귀한다.
7) 자주 나오는 오류와 빠른 해결
•
CS0246 ‘GameFramework’ 네임스페이스 없음
→ Plugins에 DLL이 없는 상태이다. 빌드/복사 스크립트 동작을 확인하거나 경로 오타를 확인한다.
→ asmdef가 있으면 Override References 해제(자동 참조) 또는 참조를 추가한다.
•
CS0227 unsafe 관련
→ DLL 방식이면 무관하다. 만약 소스가 Assets로 들어왔다면 asmdef Allow 'Unsafe'를 활성화하거나 다시 DLL 방식을 사용한다.
•
SharpZipLib 타입을 못 찾음 / 중복 정의
→ 하나만 유지한다. Unity.SharpZipLib 패키지를 사용한다면 Plugins에 SharpZipLib DLL이 있는 경우 삭제한다.
•
브레이크포인트 비활성(Unbound)
→ Unity에 복사된 DLL과 PDB가 같은 빌드인지 확인하고, VS Just My Code 해제 / Source Link 사용을 체크한다.
토이박스 나이트메어 프로젝트 패키지 파일 (리소스 참고 자료)
스크립트와 프리팹 파일을 위 깃허브 프로젝트에서 가져와서 내 프로젝트에서 사용!
