Company
교육 철학

C# / GameFramework 연동

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\\PluginsExternal\\GameFramework\\에서 두 단계 위가 프로젝트 루트이다.
하나의 DLL만 유지하도록 기존 파일을 삭제한 후 복사한다.

4) Unity 쪽 설정

Package Manager에서 Unity.SharpZipLib(com.unity.sharp-zip-lib) 설치
ICSharpCode.SharpZipLib 어셈블리를 Unity가 제공한다.
Api Compatibility Level: .NET 4.x(권장)
(asmdef 사용하는 경우)
게임 코드 asmdef의 Override References를 꺼두면 Plugins의 DLL/패키지 DLL을 자동 참조한다
Override References가 켜져 있다면 Assembly Definition ReferencesGameFramework.dll(프리컴파일)만 추가하면 된다.
(SharpZipLib는 패키지가 제공하므로 따로 추가하지 않는다)

5) 디버깅/릴리즈 운용

Editor에서 디버깅: Debug 빌드 + PDB 복사 → VS에서 Attach to Unity 후 스텝-인이 가능하다
공유/CI/릴리즈: Release 빌드 → DLL만 복사한다(필요 시 PDB도 가능하지만 최적화로 스텝이 튈 수 있다)
Plugins에는 동시에 하나의 변형만 유지한다(Debug/Release를 섞지 않는다)

6) (선택) 소스 직접 디버깅이 필요할 때

소스를 그대로 확인하고 싶다면 External/.../RuntimeAssets/...심볼릭 링크/정크션으로 노출하거나,
로컬 UPM 패키지(manifest.jsonfile:../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 사용을 체크한다.

토이박스 나이트메어 프로젝트 패키지 파일 (리소스 참고 자료)

ProjectAssets.unitypackage
630.4 MiB
GmaeFrameworkScriptAndPrefabs.unitypackage
373.7 KiB
ToyboxNightmare
eazuooz
스크립트와 프리팹 파일을 위 깃허브 프로젝트에서 가져와서 내 프로젝트에서 사용!