Chat
코드에만 신경 쓰게 하게 하는 방법
cs newbie
2025. 6. 26. 03:39
게임 시스템, 툴, 유틸리티 등 여러 기능을 '플러그인'으로 붙이고 싶다면?
게다가 그 플러그인들이 Python뿐 아니라 Go, JS, C#, Rust처럼 다양한 언어로 구현되어도 동작하게 만들고 싶다면?
오늘은 그런 구조를 직접 만들어 봅니다.
🎯 목표
- plugin/ 폴더에 어떤 실행 가능한 파일(.py, .exe 등)을 넣더라도
- main.py가 이를 탐색해 JSON으로 통신하며 실행
- 기능은 확장 가능하고 언어에 구애받지 않음!
📁 프로젝트 구조
my_game_project/
├── main.py # 메인 프로그램 (Python으로 구현)
└── plugin/ # 플러그인 모음 폴더
├── hunt.py # 플러그인 1: 사냥 기능 (JSON 입출력 기반)
└── chat.py # 플러그인 2: 채팅 기능 (JSON 입출력 기반)
🔧 1. main.py - 플러그인 실행 관리자
# main.py
import os
import json
import subprocess
PLUGIN_DIR = "plugin"
def load_plugins():
"""
plugin 폴더 안에 있는 실행 가능한 파일(.py, .exe 등)을 찾아
딕셔너리로 저장 (이름: 실행 경로)
"""
plugins = {}
for filename in os.listdir(PLUGIN_DIR):
# .py 또는 .exe 등 실행 가능한 파일만 등록
if filename.endswith(".py") or filename.endswith(".exe"):
name = filename.split('.')[0] # 파일명에서 확장자 제거
path = os.path.join(PLUGIN_DIR, filename)
plugins[name] = path
return plugins
def run_plugin(executable_path, input_data):
"""
실행 파일을 외부 프로세스로 실행,
JSON 문자열을 입력(stdin), JSON 결과를 출력(stdout)으로 받음
"""
input_json = json.dumps(input_data)
# 플러그인 실행
proc = subprocess.Popen(
["python", executable_path], # Python 파일 실행, 다른 언어면 실행기 바꿔야 함
stdin=subprocess.PIPE,
stdout=subprocess.PIPE,
stderr=subprocess.PIPE,
text=True
)
stdout, stderr = proc.communicate(input=input_json)
if proc.returncode != 0:
print(f"[오류] 플러그인 실행 실패: {stderr.strip()}")
return None
try:
return json.loads(stdout)
except Exception as e:
print(f"[오류] 플러그인 JSON 파싱 실패: {e}")
return None
def main():
# 초기 게임 데이터 예시
game_data = {
"player": {"name": "용사", "level": 1, "hp": 100}
}
plugins = load_plugins()
while True:
print("\n=== 메인 메뉴 ===")
for idx, name in enumerate(plugins.keys(), 1):
print(f"{idx}. {name}")
print(f"{len(plugins)+1}. 종료")
choice = input("선택: ")
if not choice.isdigit():
print("숫자를 입력하세요.")
continue
choice = int(choice)
if choice == len(plugins) + 1:
print("게임을 종료합니다.")
break
if 1 <= choice <= len(plugins):
plugin_name = list(plugins.keys())[choice - 1]
path = plugins[plugin_name]
print(f"[실행] {plugin_name}...")
result = run_plugin(path, game_data)
if result:
print("> 결과:", result.get("msg", "메시지 없음"))
if "game_data" in result:
game_data = result["game_data"]
else:
print("잘못된 선택입니다.")
if __name__ == "__main__":
main()
🧩 2. plugin/hunt.py - 사냥 기능 (외부 실행 JSON 기반)
# plugin/hunt.py
import sys
import json
def main():
# 표준입력(stdin)으로 들어온 JSON 문자열을 읽고 파싱
input_json = sys.stdin.read()
data = json.loads(input_json)
# 플레이어 데이터 추출 및 레벨업 처리
player = data.get("player", {})
player["level"] = player.get("level", 1) + 1
result = {
"success": True,
"msg": f"[사냥 완료] {player.get('name')}님이 레벨 {player['level']}이 되었습니다!",
"game_data": {"player": player}
}
# 결과를 JSON으로 표준출력(stdout)에 출력
print(json.dumps(result))
if __name__ == "__main__":
main()
💬 3. plugin/chat.py - 채팅 기능 (입장 메시지만)
# plugin/chat.py
import sys
import json
def main():
input_json = sys.stdin.read()
data = json.loads(input_json)
player = data.get("player", {})
name = player.get("name", "???")
result = {
"success": True,
"msg": f"[채팅방 입장] {name}님이 채팅방에 입장했습니다.",
"game_data": {"player": player}
}
print(json.dumps(result))
if __name__ == "__main__":
main()
✅ 실행 예시
$ python main.py
=== 메인 메뉴 ===
1. hunt
2. chat
3. 종료
선택: 1
[실행] hunt...
> 결과: [사냥 완료] 용사님이 레벨 2이 되었습니다!
선택: 2
[실행] chat...
> 결과: [채팅방 입장] 용사님이 채팅방에 입장했습니다.
🚀 이 구조의 장점
항목 설명
언어 독립 | JSON 입출력만 지키면 어떤 언어로든 플러그인 제작 가능 |
확장 쉬움 | plugin 폴더에 파일 추가만 해도 자동 등록됨 |
유지보수 편리 | 각 기능은 별도 파일/언어로 완전히 분리됨 |
실제 게임 구조와 유사 | JSON으로 게임 상태 주고받는 방식이 서버 구조와 흡사함 |
📌 마무리
이런 구조는 단순한 테스트 용도뿐 아니라
실제 게임 서버, 유틸 앱, 업무 자동화 시스템에도 응용 가능합니다.
다양한 언어로 만든 기능들을 유연하게 연결하고 싶다면
**"표준 입출력 + JSON"**이라는 간단한 규칙만으로도 강력한 시스템을 만들 수 있습니다.