Lethal Company

Details

Last Updated
last week
First Uploaded
last week
Downloads
48
Likes
0
Size
39KB
Dependency string
asta-PastaClient-0.0.4
Dependants

Pasta Client 개발 문서

이 문서는 Lethal Company용 모드 Pasta Client의 현재 개발 진행 상황, 내부 구조, 각 기능의 처리 방식, 디자인 패턴, 코드 스타일 가이드 등을 정리해 다른 개발자가 프로젝트를 이어받아도 무리 없이 진행할 수 있도록 작성되었습니다.


🚀 빠른 시작 (사용자용)

설치 방법

  1. Thunderstore에서 Pasta Client 모드 다운로드
  2. BepInEx 폴더에 설치
  3. 게임 실행

사용 방법

명령어

  • :st - Shitter 추가/확인 UI 열기
  • :who - 최근 나간 플레이어 목록 확인

주요 기능

  1. Shitter 추가

    • :st 명령어 입력
    • 현재 방 플레이어 또는 최근 나간 플레이어 선택
    • 이유 입력 (최대 500자)
    • "추가 요청" 버튼 클릭
    • 서버로 투표가 전송됨
  2. 최근 나간 플레이어 확인

    • :who 명령어 입력
    • 최근 나간 플레이어 목록 확인
    • Steam 프로필 열기 가능
  3. 킥당했을 때

    • 킥당하면 자동으로 킥 UI 표시
    • 킥당한 시점의 방 플레이어 목록 확인 가능
    • Steam 프로필 열기 가능

서버 설정

서버를 사용하려면:

  1. server.py 실행:

    python server.py
    
  2. 설정에서 서버 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로 변환
  • 변환 방법:
    1. 캐시 확인
    2. PlayerControllerB에서 Reflection으로 Steam ID 필드 찾기
    3. NetworkObject.OwnerClientId 확인
    4. clientId가 Steam ID 형식인지 확인 (7656119로 시작)
    5. 실패 시 clientId 반환 (fallback)

4.5 Steam Name Fetcher

  • 목적: Steam ID로부터 플레이어 이름 가져오기
  • 우선순위:
    1. 게임 내 이름 (PlayerControllerB.playerUsername, name 필드)
    2. 캐시된 이름
    3. 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 자동 킥 시스템

  • 조건:
    1. 플레이어 입장 감지
    2. ShitterDatabase에 해당 플레이어 존재
    3. 투표 수 ≥ ConfigManager.VoteKickThreshold (기본값: 2)
    4. 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 윈도우

  1. ShitterUI (Window ID: 987654)

    • 현재 방 플레이어 목록
    • 최근 나간 플레이어 목록
    • 이유 입력 필드
    • 추가 요청 버튼
  2. RecentUI (Window ID: 987655)

    • 최근 나간 플레이어 목록
    • Steam 프로필 열기 버튼
  3. 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한태 써달라했는데 개잘써주네 ㄹㅇ

Thunderstore development is made possible with ads. Please consider making an exception to your adblock.
Thunderstore development is made possible with ads. Please consider making an exception to your adblock.
Thunderstore development is made possible with ads. Please consider making an exception to your adblock.