Abstract
이 페이지의 본문은 초기 방식(2025년)의 기록입니다. 당시에는 코어를 External/ 에서 따로 빌드해 GameFramework.dll 로 Unity 에 넣었습니다. 현재 ToyboxNightmare 는 그 방식을 쓰지 않습니다. 코어와 Unity 래퍼를 모두 소스 그대로 담은 UPM 패키지 하나로 바꿨습니다. 새로 시작한다면 이 Abstract 의 방법을 따르고, 본문은 "DLL 로 분리하는 방법이 궁금할 때"의 참고 자료로 보세요.
"연동"이 풀어야 하는 문제는 하나입니다 — Unity 를 모르는 순수 C# 코드(코어)를 Unity 프로젝트 안에서 어떻게 컴파일하고 디버깅할 것인가. 답은 두 가지가 있고, 이 프로젝트는 처음에 DLL 방식을 썼다가 패키지 방식으로 옮겼습니다.
현재 구조
ToyboxNightmare/
├─ Packages/
│ └─ com.yamyamcoding.gameframework/ ← 프레임워크 전체 (임베디드 UPM 패키지)
│ ├─ package.json
│ ├─ LICENSE.md / Third Party Notices.md
│ └─ Runtime/
│ ├─ Core/ ← 코어 소스. 어셈블리 "GameFramework"
│ │ └─ GameFramework.asmdef (noEngineReferences, allowUnsafeCode)
│ └─ UnityGameFramework/ ← Unity 래퍼. 어셈블리 "UnityGameFramework.Runtime"
│ └─ UnityGameFramework.Runtime.asmdef
└─ Assets/
├─ GameMain/ ← 게임 코드 (Assembly-CSharp)
└─ Prefabs/GameFramework.prefab ← 컴포넌트 20개가 붙은 부트스트랩 프리팹
Plain Text
복사
Assets/Plugins/GameFramework.dll 과 Assets/Scripts/(예전의 Unity 래퍼 위치)는 더 이상 없습니다.
두 방식 비교
DLL 방식 (본문) | 패키지 방식 (현재) | |
코어 수정 후 | Visual Studio 에서 빌드 → Post-build 로 DLL 복사 → Unity 리로드 | 저장하면 Unity 가 바로 다시 컴파일 |
코어 안 디버깅 | PDB 가 맞아야 스텝 인 가능 | 소스라서 그냥 된다 |
"코어는 Unity 를 몰라야 한다"는 규칙 | 별도 프로젝트라 물리적으로 보장 | asmdef 의 No Engine References 로 보장 — UnityEngine 을 쓰면 컴파일 에러 |
unsafe 코드 | DLL 안에서 해결 | 코어 asmdef 의 Allow Unsafe Code 만 켠다. 게임 코드에는 영향 없음 |
다른 프로젝트에 설치 | DLL + 스크립트 폴더 + 프리팹을 따로 옮긴다 | 패키지 폴더 하나를 복사하거나 git URL 로 추가 |
필요한 도구 | Visual Studio, .csproj, 빌드 스크립트 | Unity 만 |
본문은 "소스를 Unity 안에 직접 두는 것"을 안티패턴으로 꼽았습니다. 그 걱정(컴파일러 제약, unsafe, 네임스페이스 충돌)은 소스를 Assets/ 에 그냥 풀어놓았을 때의 이야기이고, asmdef 로 어셈블리를 분리한 패키지에서는 해당하지 않습니다. 반대로 DLL 방식의 장점이던 "Unity 와 무관한 빌드"는 서버와 코드를 공유하는 프로젝트라면 여전히 유효합니다.
새 프로젝트에 설치하기 (패키지 방식)
1.
패키지를 넣는다. com.yamyamcoding.gameframework 폴더를 새 프로젝트의 Packages/ 아래에 복사한다. 또는 Package Manager → + → Add package from git URL 에 저장소 주소 뒤에 ?path=Packages/com.yamyamcoding.gameframework 를 붙여 넣는다(저장소 접근 권한 필요). Addressables 와 SharpZipLib 은 의존성으로 자동 설치된다.
2.
로그를 켠다. Project Settings → Player → Scripting Define Symbols 에 ENABLE_LOG 를 추가한다. 안 하면 프레임워크의 모든 로그가 컴파일에서 빠져 문제가 생겨도 콘솔이 조용하다.
3.
부트스트랩 오브젝트를 씬에 둔다. 루트에 BaseComponent, 자식 오브젝트마다 필요한 ~Component 를 하나씩 붙인다. 엔티티만 띄우는 최소 구성은 Base + Event + Resource + Entity + Procedure 다섯 개이고, Fsm · UI · Sound · ObjectPool 등은 쓸 때 추가한다(UI 와 Sound 도 Event 와 Resource 가 있어야 한다). ToyboxNightmare 의 Assets/Prefabs/GameFramework.prefab 을 복사해 시작하는 것이 가장 빠르다.
4.
첫 Procedure 를 만든다. ProcedureBase 를 상속한 클래스를 만들고 Procedure 컴포넌트의 Available / Entrance Procedure 에 네임스페이스를 포함한 전체 이름을 적는다.
5.
Addressables 를 준비한다. Groups 창에서 Play Mode Script 를 Use Asset Database 로 두고, 프리팹을 등록해 짧은 주소를 붙인다.
게임 코드에서 달라지는 한 가지: 프레임워크가 별도 어셈블리가 되면서 EntityLogic, UIFormLogic, ProcedureBase, FsmState<T> 의 훅을 오버라이드할 때 protected override 로 써야 합니다. 예전처럼 protected internal override 로 쓰면 CS0507 컴파일 에러가 납니다.
페이지 맨 아래에 첨부된 .unitypackage 두 개는 예전 구조(DLL + Assets/Scripts) 기준으로 만든 것입니다. 현재 패키지와 함께 임포트하면 같은 타입이 두 번 정의되어 충돌합니다. 새로 시작한다면 첨부 파일 대신 위 설치 절차를 따르세요.
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 사용을 체크한다.
토이박스 나이트메어 프로젝트 패키지 파일 (리소스 참고 자료)
스크립트와 프리팹 파일을 위 깃허브 프로젝트에서 가져와서 내 프로젝트에서 사용!





