
PastaClient
Shitter추가, 나간사람 조회 등등Details
Pasta Client 개발 문서
이 문서는 Lethal Company용 모드 Pasta Client의 현재 개발 진행 상황, 내부 구조, 각 기능의 처리 방식, 디자인 패턴, 코드 스타일 가이드 등을 정리해 다른 개발자가 프로젝트를 이어받아도 무리 없이 진행할 수 있도록 작성되었습니다.
🚀 빠른 시작 (사용자용)
설치 방법
- Thunderstore에서 Pasta Client 모드 다운로드
- BepInEx 폴더에 설치
- 게임 실행
사용 방법
명령어
:st- Shitter 추가/확인 UI 열기:who- 최근 나간 플레이어 목록 확인
주요 기능
-
Shitter 추가
:st명령어 입력- 현재 방 플레이어 또는 최근 나간 플레이어 선택
- 이유 입력 (최대 500자)
- "추가 요청" 버튼 클릭
- 서버로 투표가 전송됨
-
최근 나간 플레이어 확인
:who명령어 입력- 최근 나간 플레이어 목록 확인
- Steam 프로필 열기 가능
-
킥당했을 때
- 킥당하면 자동으로 킥 UI 표시
- 킥당한 시점의 방 플레이어 목록 확인 가능
- Steam 프로필 열기 가능
서버 설정
서버를 사용하려면:
-
server.py실행:python server.py -
설정에서 서버 URL 변경 (기본값:
https://shitter.asta.rs):- 게임 내 Config 메뉴 또는
BepInEx/config/dev523.pasta.client.cfg파일 수정
📌 1. 현재 진행 상황
✅ 구현 완료
- ✅ 기본 프로젝트 구조 (BepInEx Plugin + Harmony Patch + LethalConfig 연동)
- ✅ 설정(Enable/Disable) 및 Config 시스템 구현
- ✅ Shitter 데이터 구조 및 저장 시스템
- ✅ UI Framework IMGUI 기반 구현
- ✅ 명령어 시스템(
:st,:who) 구현 - ✅ 네트워크 RPC 시스템 (Unity Netcode)
- ✅ Steam ID 기반 플레이어 추적 시스템
- ✅ 서버 통신 (HTTP 요청)
- ✅ 플레이어 이름 가져오기 (Steam API + 게임 내 이름)
- ✅ 최근 나간 플레이어 추적 시스템
- ✅ 킥 UI 및 킥 감지 시스템
- ✅ 자동 킥 기능 (투표 수 기준)
- ✅ Steam 프로필 열기 기능
- ✅ 플레이어 목록 수집 및 표시
- ✅ 기본 이름 필터링 ("Player #1" 등)
- ✅ 텍스트 입력 중 인게임 입력 차단
- ✅ UI 투명 버그 수정
🚧 구현 중 / 개선 필요
- Shitter DB 파일 저장 기능 (현재 메모리 기반)
- 서버와의 동기화 개선
- UI 성능 최적화
❗ 향후 작업
- UI uGUI/UIToolkit 전환 (IMGUI 유지보수 어려움)
- 에러 핸들링 및 로깅 체계 확립
- 서버 보안 강화
📁 2. 폴더/파일 구조
PastaClient/
│
├── Plugin.cs # 메인 엔트리포인트
├── ConfigManager.cs # 설정 관리 (BepInEx Config)
├── PastaClient.csproj # 프로젝트 파일
│
├── Network/
│ └── PastaNetwork.cs # Unity Netcode 네트워크 처리
│ # - 플레이어 입장/퇴장 감지
│ # - RPC (ServerRpc, ClientRpc)
│ # - 플레이어 목록 전송
│
├── Systems/
│ ├── ShitterDatabase.cs # Shitter 데이터 저장소
│ ├── RecentLeaveTracker.cs # 최근 나간 플레이어 추적
│ └── KickTracker.cs # 킥당했을 때 플레이어 목록 저장
│
├── Utils/
│ ├── ServerClient.cs # 외부 서버와 HTTP 통신
│ ├── SteamIDHelper.cs # Unity Netcode clientId → Steam ID 변환
│ ├── SteamNameFetcher.cs # Steam 프로필에서 이름 가져오기
│ ├── UIHelper.cs # IMGUI 관리 및 커서 제어
│ ├── UIStyle.cs # UI 스타일 정의
│ ├── ShitterUI.cs # Shitter 추가/확인 UI
│ ├── RecentUI.cs # 최근 나간 플레이어 UI
│ └── KickUI.cs # 킥 UI
│
├── Patches/
│ ├── ChatPatch.cs # 채팅 명령어 처리
│ └── PlayerPatches.cs # 플레이어 입력 패치 (UI 열려있을 때 입력 차단)
│
└── server.py # Python Flask 서버 (Shitter 투표 저장)
🧩 3. 내부 설계 개요
(1) 전체 플로우 요약
명령어 입력 (:st, :who)
↓
UI 표시 (ShitterUI, RecentUI, KickUI)
↓
플레이어 선택 + 이유 입력
↓
서버로 HTTP 요청 전송 (ServerClient)
↓
로컬 DB 업데이트 (ShitterDatabase)
↓
Unity Netcode RPC로 동기화 (PastaNetwork)
↓
자동 킥 판단 (투표 수 ≥ 임계값)
(2) 플레이어 입장/퇴장 감지 플로우
플레이어 입장/퇴장 감지 (PastaNetwork)
↓
Steam ID 변환 (SteamIDHelper)
↓
플레이어 이름 캐싱 (SteamNameFetcher)
↓
RecentLeaveTracker에 추가 (퇴장 시)
↓
서버에 플레이어 목록 전송 (클라이언트 접속 시)
🗂 4. 주요 시스템 설명
4.1 Shitter Database
- 목적: 문제 플레이어(Shitter)의 투표 기록 저장
- 구조:
Dictionary<ulong, ShitterInfo>- Key: Steam ID
- Value:
ShitterInfo(Steam ID + 투표자 목록 및 이유)
ShitterInfo 구조:
public class ShitterInfo
{
public ulong SteamId;
public Dictionary<ulong, string> Reasons; // 투표자 Steam ID → 이유
}
저장 방식:
- 로컬: 메모리 기반 Dictionary
- 서버: HTTP POST 요청으로 외부 서버에 저장
- 동기화: Unity Netcode RPC로 게임 내 클라이언트 간 동기화
4.2 Recent Leave Tracker
- 목적: 최근 나간 플레이어 목록 관리
- 최대 저장 개수: 5명
- 기능:
- 플레이어 퇴장 시 자동 추가
- 플레이어 이름 비동기 로딩 (Steam API)
- 이름 캐싱
RecentPlayerInfo 구조:
public class RecentPlayerInfo
{
public ulong ClientId; // Steam ID
public string PlayerName; // 플레이어 이름
public bool IsNameLoading; // 이름 로딩 중 여부
}
4.3 Kick Tracker
- 목적: 킥당했을 때 방에 있던 플레이어 목록 저장
- 사용: 킥 UI에서 킥한 사람 확인용
- 저장 시점:
- 플레이어 퇴장 시 (현재 플레이어 목록 스냅샷)
- 클라이언트 접속 시 (서버에서 플레이어 목록 수신)
4.4 Steam ID Helper
- 목적: Unity Netcode의
clientId를 실제 Steam ID로 변환 - 변환 방법:
- 캐시 확인
PlayerControllerB에서 Reflection으로 Steam ID 필드 찾기NetworkObject.OwnerClientId확인clientId가 Steam ID 형식인지 확인 (7656119로 시작)- 실패 시
clientId반환 (fallback)
4.5 Steam Name Fetcher
- 목적: Steam ID로부터 플레이어 이름 가져오기
- 우선순위:
- 게임 내 이름 (
PlayerControllerB.playerUsername,name필드) - 캐시된 이름
- Steam 프로필 HTML 파싱 (비동기)
- 게임 내 이름 (
- 캐싱: 가져온 이름은 메모리에 캐시
4.6 Server Client
- 목적: 외부 서버와 HTTP 통신
- 기능:
POST /api/shitter/vote- Shitter 투표 전송GET /api/shitter/info/<target_id>- Shitter 정보 조회GET /api/shitter/list- 모든 Shitter 목록
- 구현: Unity
UnityWebRequest사용
4.7 Commands
:st
- 기능: Shitter 추가/확인 UI 열기
- 표시 내용:
- 현재 방 플레이어 목록
- 최근 나간 플레이어 목록
- 이유 입력 필드
- 추가 요청 버튼
:who
- 기능: 최근 나간 플레이어 목록 UI 열기
- 표시 내용:
- 최근 나간 플레이어 목록 (최대 5명)
- 각 플레이어의 Steam 프로필 열기 버튼
4.8 자동 킥 시스템
- 조건:
- 플레이어 입장 감지
ShitterDatabase에 해당 플레이어 존재- 투표 수 ≥
ConfigManager.VoteKickThreshold(기본값: 2) ConfigManager.EnableAutoKick= true
- 동작: 호스트가
NetworkManager.Singleton.DisconnectClient()호출
4.9 킥 UI
- 트리거: 로컬 클라이언트가 킥당했을 때 자동 표시
- 표시 내용:
- 킥당한 시점의 방 플레이어 목록
- 각 플레이어의 Steam 프로필 열기 버튼
- 목적: 킥한 사람 확인
🎨 5. 디자인 패턴
✔ Singleton Pattern
PastaNetwork.Instance- NetworkBehaviour 싱글톤UIHelper.Instance- UI 관리 싱글톤 (MonoBehaviour)
✔ Observer Pattern
- 플레이어 입장/퇴장 이벤트 구독 (
NetworkManager.OnClientConnectedCallback,OnClientDisconnectCallback) - 백업 폴링 방식 (
MonitorPlayerChanges코루틴)
✔ Factory Pattern
SteamNameFetcher- 이름 가져오기 전략 패턴 (게임 → 캐시 → Steam API)
✔ MVC-like 구조
- Model:
ShitterDatabase,RecentLeaveTracker,KickTracker - View:
ShitterUI,RecentUI,KickUI - Controller:
PastaNetwork,ChatPatch
🛠 6. 코딩 컨벤션
네이밍 규칙
- 클래스:
PascalCase - 메서드:
PascalCase - 변수:
camelCase - 상수:
ALL_CAPS - private 필드:
_camelCase
파일 규칙
- 기능별 폴더 분리 (
Network/,Systems/,Utils/,Patches/) - 한 파일에는 한 클래스 원칙
- UI는
Utils/폴더에 위치
주석 규칙
- 메서드 상단에 XML 문서 주석 (
/// <summary>) - 중요한 로직은 인라인 주석
- 한글 주석 허용
🔧 7. 네트워크 통신 구조
Unity Netcode RPC
ServerRpc
AddShitterServerRpc(ulong targetId, string reason, ulong senderId)- 클라이언트 → 서버: Shitter 투표 요청
- 서버에서
ShitterDatabase업데이트 - 모든 클라이언트에
UpdateShitterClientsClientRpc브로드캐스트
ClientRpc
-
UpdateShitterClientsClientRpc(ulong id)- 서버 → 클라이언트: Shitter DB 업데이트 알림
- UI 갱신
-
SendPlayerListClientRpc(ulong[] playerIds)- 서버 → 특정 클라이언트: 방 플레이어 목록 전송
- 클라이언트 접속 시 한 번 전송
HTTP 서버 통신
엔드포인트
-
POST /api/shitter/vote- Shitter 투표 추가{ "targetId": "76561198000000000", "senderId": "76561198000000001", "reason": "팀킬", "timestamp": 1234567890 } -
GET /api/shitter/info/<target_id>- Shitter 정보 조회 -
GET /api/shitter/list- 모든 Shitter 목록 -
GET /health- 서버 상태 확인
🖥 8. UI 구조
UI 시스템
- 프레임워크: Unity IMGUI
- 관리:
UIHelper- UI 등록/해제 및 커서 제어 - 스타일:
UIStyle- 통일된 UI 스타일 정의
UI 윈도우
-
ShitterUI (Window ID: 987654)
- 현재 방 플레이어 목록
- 최근 나간 플레이어 목록
- 이유 입력 필드
- 추가 요청 버튼
-
RecentUI (Window ID: 987655)
- 최근 나간 플레이어 목록
- Steam 프로필 열기 버튼
-
KickUI (Window ID: 987656)
- 킥당한 시점의 방 플레이어 목록
- Steam 프로필 열기 버튼
커서 관리
- UI가 열려있을 때:
Cursor.visible = true,Cursor.lockState = CursorLockMode.None - UI가 닫혔을 때: 게임이 커서 상태 관리 (강제 변경하지 않음)
입력 차단
- UI가 열려있을 때: 마우스 입력 (Mouse X, Mouse Y) 차단
- 텍스트 입력 필드 포커스 시: 모든 입력 차단 (ESC 제외)
🔐 9. 보안 고려사항
클라이언트/서버 구분
- Shitter DB 변경: 서버에서만 가능 (
ServerRpc) - ConnectedClients 접근: 서버에서만 가능 (클라이언트 접근 시 예외 처리)
- 플레이어 정보 수집: 클라이언트는
PlayerControllerB직접 탐색
데이터 검증
- 자기 자신에게 투표 불가 (
targetId == senderId체크) - Steam ID 형식 검증 (7656119로 시작하는 큰 숫자)
- 기본 이름 필터링 ("Player #1" 등 제외)
🐛 10. 알려진 이슈 및 해결 방법
이슈 1: 플레이어 목록이 표시되지 않음
- 원인: 클라이언트에서
ConnectedClients접근 시도 - 해결:
PlayerControllerB직접 탐색 +KickTracker병합
이슈 2: UI가 투명해짐
- 원인: 텍스처가 매 프레임 재생성
- 해결: 텍스처 캐싱 시스템 구현
이슈 3: 접속 전 플레이어가 표시되지 않음
- 원인: 초기 플레이어 수집 타이밍 문제
- 해결: 여러 번 시도하는 초기 수집 로직 + 서버에서 플레이어 목록 전송
🔮 11. 향후 개선 방향
단기
- [ ] Shitter DB 파일 저장 (JSON)
- [ ] 서버 데이터와 로컬 DB 동기화
- [ ] UI 성능 최적화
중기
- [ ] UI uGUI/UIToolkit 전환
- [ ] 에러 핸들링 및 로깅 체계 확립
- [ ] 서버 보안 강화 (인증 등)
장기
- [ ] 웹 대시보드 (Shitter 목록 조회)
- [ ] 모드 간 호환성 검사 시스템
- [ ] 통계 시스템 (가장 많은 투표 받은 플레이어 등)
📞 12. 개발자 정보
주요 클래스 의존성
Plugin
├── ConfigManager
├── PastaNetwork (NetworkBehaviour)
│ ├── ServerClient
│ ├── SteamNameFetcher
│ ├── ShitterDatabase
│ ├── RecentLeaveTracker
│ └── KickTracker
├── ChatPatch (Harmony)
│ └── ShitterUI, RecentUI
└── PlayerPatches (Harmony)
└── UIHelper
핵심 컴포넌트
- PastaNetwork: 네트워크 이벤트 처리 및 RPC 관리
- SteamIDHelper: clientId ↔ Steam ID 변환
- SteamNameFetcher: 플레이어 이름 가져오기 (비동기)
- ServerClient: 외부 서버 통신
- UIHelper: UI 관리 및 커서 제어
📚 13. 사용 예시
Shitter 추가하기
// 클라이언트에서 호출
PastaNetwork.RequestAddShitter(steamId, "팀킬");
// 내부 처리:
// 1. ServerClient.SendShitterVote() - HTTP 서버에 요청
// 2. ShitterDatabase.AddVote() - 로컬 DB 업데이트
// 3. AddShitterServerRpc() - Unity Netcode 동기화 (서버인 경우)
플레이어 이름 가져오기
// 비동기로 이름 가져오기
SteamNameFetcher.FetchPlayerNameFromGameOrSteam(steamId, (sid, name) =>
{
Debug.Log($"플레이어 {sid}의 이름: {name}");
});
// 캐시에서 이름 가져오기 (동기)
string cachedName = SteamNameFetcher.GetCachedName(steamId);
Steam ID 변환
// Unity Netcode clientId를 Steam ID로 변환
ulong steamId = SteamIDHelper.GetSteamID(clientId);
// 역변환 (필요시)
ulong clientId = SteamIDHelper.GetClientID(steamId);
🛡 14. 서버 설정 및 실행
서버 실행
# Python Flask 서버 실행
python server.py
# 서버는 기본적으로 http://localhost:8000 에서 실행됩니다
서버 API 문서
POST /api/shitter/vote
Shitter 투표 추가
Request:
{
"targetId": "76561198000000000",
"senderId": "76561198000000001",
"reason": "팀킬",
"timestamp": 1234567890
}
Response:
{
"success": true,
"message": "Vote added successfully",
"data": {
"targetId": "76561198000000000",
"voteCount": 3
}
}
GET /api/shitter/info/<target_id>
Shitter 정보 조회
Response:
{
"success": true,
"data": {
"steamId": "76561198000000000",
"voteCount": 3,
"votes": {
"76561198000000001": {
"reason": "팀킬",
"timestamp": 1234567890
}
}
}
}
📝 15. 변경 이력
최근 업데이트
- ✅ Steam ID 기반 플레이어 추적 시스템 구현
- ✅ 서버 통신 (HTTP) 구현
- ✅ 플레이어 이름 가져오기 (Steam API) 구현
- ✅ 킥 UI 및 킥 감지 시스템 구현
- ✅ 접속 전 플레이어 목록 수집 개선
- ✅ 기본 이름 필터링 ("Player #1" 등) 구현
- ✅ 텍스트 입력 중 인게임 입력 차단
- ✅ UI 투명 버그 수정
gpt한태 써달라했는데 개잘써주네 ㄹㅇ