Skip to content

woogyeom/Flutter-Python-EXP-Tracker

Repository files navigation

Mapleland EXP Tracker

Mapleland EXP Tracker는 메이플랜드 유저를 위한 실시간 경험치 및 메소 측정 애플리케이션입니다.
게임 화면을 인식하여 사냥 효율을 손쉽게 추적하고 분석할 수 있도록 돕습니다.

사용 예시


⚠️ 주의 사항

본 앱은 메이플스토리 월드 클라이언트나 네트워크에 어떠한 접근도 하지 않는 단순 화면 인식 프로그램입니다. 자동 사냥 매크로가 아니며 게임 플레이에 직접적인 영향을 주지 않는다고 판단하여 배포합니다. 앱 사용에 대한 최종적인 책임은 사용자 본인에게 있음을 유의해 주시기 바랍니다.

  • 본 앱은 Windows 환경에서만 정상적으로 작동합니다.
  • 일정 주기마다 화면 캡처와 OCR이 수행되므로 약간의 시스템 리소스를 사용합니다.
  • 게임 해상도가 너무 낮거나, 지정된 영역이 다른 UI에 의해 가려지면 인식률이 저하될 수 있습니다.
  • C:\temp\MaplelandEXPTracker 경로에 디버그용 이미지와 최근 3일 치 로그 파일이 저장됩니다.

📥 다운로드

가장 최신 버전의 앱은 아래 깃허브 릴리즈 페이지에서 받으실 수 있습니다.

[실행 경고 안내] 본 앱은 개인 개발자가 제작하여 별도의 코드 서명이 되어있지 않습니다. 이로 인해 실행 시 "알 수 없는 게시자" 또는 "Windows의 PC 보호" 화면이 표시될 수 있습니다. 이는 유료 인증서가 없어 발생하는 자연스러운 경고이며, 신뢰성 보장을 위해 전체 코드를 깃허브에 공개하고 있으니 안심하고 사용하셔도 됩니다.

🔗 최신 버전 다운로드 (GitHub Releases)


❓ 자주 묻는 질문 (Troubleshooting)

Q. 앱을 실행했는데 아무런 창이 뜨지 않아요!

A. 대부분의 경우 MSVC 런타임 라이브러리가 없어 발생하는 문제입니다. 아래 링크에서 최신 버전을 받아 설치한 후 다시 시도해 보세요.

🔗 최신 지원 Visual C++ 재배포 가능 패키지 다운로드

Q. 런타임을 설치해도 여전히 실행되지 않아요!

A. 일부 PC 환경에서 알림음 재생 기능이 문제를 일으키는 경우가 있습니다. 이럴 경우, 소리 기능이 제거된 no-audio 버전을 릴리즈 페이지에서 다운로드하여 사용해 주세요.

🔗 최신 버전 다운로드 (GitHub Releases)

Q. 타이머 종료 효과음이 마음에 들지 않아요!

A. 앱이 설치된 폴더 내의 data\flutter_assets\assets 경로로 이동하여 timer_alarm.mp3 파일을 원하는 소리 파일(MP3)로 교체하시면 됩니다. (단, no-audio 버전에서는 이 기능을 사용할 수 없습니다.)

Q. 버그 제보 또는 문의 사항이 있어요!

A. 그동안 앱에 많은 관심과 피드백을 보내주셔서 진심으로 감사합니다. 덕분에 프로젝트를 꾸준히 개선하고 발전시킬 수 있었습니다.

이제 저는 새로운 프로젝트에 집중하고자, 아쉽지만 1.8.0 버전의 업데이트와 함께 1:1 문의 및 버그 제보에 대한 실시간 지원을 종료하게 되었습니다. 너른 양해 부탁드립니다.

혹시 문제가 발생하셨나요? 아래의 해결 방법을 먼저 확인해 주세요. 대부분의 문제는 이 과정에서 해결됩니다.

  • 다운로드: GitHub 릴리즈 페이지의 Assets 목록에서 최신 파일을 받아주세요.
  • 실행 오류: MSVC 런타임을 설치하시거나 no-audio 버전을 사용해 보세요.
  • 인식 오류: 게임 해상도를 높이거나 측정 영역을 재설정해 주세요.

앞으로 심각한 버그나 새로운 아이디어 제보는 GitHub의 [Issues] 탭에 남겨주시면, 다른 사용자들과 논의하거나 개발자가 향후 참고할 수 있는 좋은 자료가 될 것입니다. 다만, 이슈에 대한 즉각적인 답변이나 수정은 어려운 점 미리 양해 바랍니다.

다시 한번, 그동안의 성원에 감사드립니다!


📖 사용 방법 및 예시

아래 영상을 통해 실제 사용 모습을 확인하실 수 있습니다.

사용 예시 영상

기본 사용법

  1. 앱 실행 및 준비 앱을 실행하면 초기 설정을 위해 잠시 로딩합니다. 잠시 후 타이머 버튼이 활성화되면 사용할 준비가 된 것입니다.

  2. 측정 영역 지정 영역 지정 아이콘을 눌러, 게임 화면의 ①레벨과 ②경험치가 표시되는 영역을 예시 화면에 따라 차례대로 드래그하여 지정합니다.

  3. 측정 시작 메인 화면의 시작(▶) 버튼을 눌러 측정을 시작하세요. 이제 앱에서 실시간으로 누적 경험치와 사냥 효율을 확인할 수 있습니다.

  4. 단축키로 제어 게임을 플레이하는 중에도 키보드의 ~ 키(Tab 키 위)를 누르면 측정을 일시정지하거나 재개할 수 있습니다.

  5. 기록 초기화 새로운 측정을 원할 경우, 상단 메뉴의 초기화 아이콘을 눌러 현재까지의 모든 기록을 깨끗하게 리셋할 수 있습니다.


🖥️ 화면 및 기능 안내

1. 메인 화면

메인 화면에서는 측정 시간, 예상 경과 시각, 그리고 누적된 측정 결과를 한눈에 볼 수 있습니다.

메인 스크린

  • 타이머: 현재 측정 중인 시간을 표시합니다.
  • N 시간 후 예상 시각: 타이머 시작 시점을 기준으로, 1시간, 2시간, 4시간 등이 지났을 때의 실제 시각을 미리 보여줍니다.
  • 측정 결과: 타이머가 동작하는 동안 누적된 경험치와 메소, 그리고 이를 바탕으로 계산된 시간당 평균 획득량을 표시합니다.

상단 메뉴 기능

아이콘 기능 설명
Github GitHub 프로젝트 깃허브 페이지를 엽니다.
메소 측정 토글 메소 측정 메소 획득량 측정 기능을 켜거나 끕니다.
타이머 초기화 초기화 타이머와 측정된 모든 값을 초기 상태로 리셋합니다.
인식 영역 재설정 영역 재설정 경험치/레벨이 표시되는 화면 영역을 다시 지정합니다.
설정 화면 이동 설정 알람, 업데이트 주기 등 세부 옵션을 조정하는 설정창을 엽니다.
앱 종료 종료 앱을 안전하게 종료합니다.

2. 설정 화면

상단 메뉴의 설정 아이콘을 통해 진입할 수 있으며, 앱의 세부 동작을 제어할 수 있습니다.

세팅 스크린 1 세팅 스크린 2

  • 업데이트 주기: 화면을 인식하는 간격(초)을 설정합니다. (기본값: 1초)
  • 타이머 자동 정지: 설정한 시간이 지나면 타이머가 자동으로 멈추고 알림음이 울리게 설정할 수 있습니다.
  • 알람 볼륨: 타이머 자동 종료 시 재생되는 알람 소리의 크기를 조절합니다.
  • 평균 표시: '안 함/5분/15분/30분/1시간' 중 하나를 선택합니다. 현재 효율을 기준으로, 선택한 시간만큼 사냥했을 때의 예상 경험치/메소 획득량을 계산하여 메인 화면에 보여줍니다.
  • N 시간 후 예상 시각 표시: 메인 화면에 'N 시간 후 예상 시각' 정보의 표시 여부를 설정하는 토글 옵션입니다.

📜 업데이트 내역

업데이트 기록 전체 보기
  • Ver 1.8.0: 앱 윈도우의 크기를 조정할 수 있게 변경, 설정 화면의 레이아웃을 페이지뷰로 변경
  • Ver 1.7.1: @myungwoo님의 기여로 누락되었던 수정 부분 추가
  • Ver 1.7.0: @myungwoo님의 기여로 N 시간 후 예상 시각 표시 기능 추가(후에 확인 결과, 일부 누락)
  • Ver 1.6.1: 로컬 CRT DLL 번들링(MSVCP140.dll/VCRUNTIME140.dll/ucrtbase.dll/CONCRT140.dll) 및 네이티브 크래시 시 crash.log에 콜스택 기록하는 전역 예외 필터 기능 추가
  • Ver 1.6.0: 타이머의 기본 조작을 시작 -> 정지 -> 초기화에서 시작 -> 일시정지 -> 재개의 형태로 변경, 초기화 버튼은 상단 메뉴로 이동
  • Ver 1.5.1: 더 나은 정확도를 위해 레벨 ROI 방식 변경
  • Ver 1.5.0: 종료 전 위치 기억, 타이머 조작 핫키{`(backquote)} 추가, 메소 인식 정확도 향상, 타이머 동작 중 불투명도 감소(더 투명하게)
  • Ver 1.4.2: 레벨 업 시 수치가 ??로 표시되는 오류 수정
  • Ver 1.4.1: 업데이트 주기에만 평균값 계산하게 변경, 전체 코드 구조 개선, 초기 인식 이전 수치 ??로 표시
  • Ver 1.3.6: 업데이트 주기 설정 옵션 추가, 초기 경험치 및 메소 데이터가 인식되기 전까지 --로 표시
  • Ver 1.3.5: 앱 실행 시 로그 기록. exit 호출 직전 로그 기록은 await처리
  • Ver 1.3.4: 서버 로그 기록 기능 보완, 로컬 서버 포트 5000로 재변경, 서버 초기화 구조 개선
  • Ver 1.3.2: JSON 파싱 오류 발생 시 빈 JSON 파일 재생성하게 수정, 타임아웃 시 로그를 남긴 후 앱을 종료하게 수정, 안전 상태 업데이트 기능 추가, 각 초기화 작업을 명확히 분리, 분산되어 있던 여러 setState 호출 및 비동기 작업들을 통합·분리
  • Ver 1.3.1: PyInstaller 빌드 시 stdout/stderr 재설정으로 uvicorn 로깅 오류 해결
  • Ver 1.3.0: 임시 폴더 내에 클라이언트 로그 저장 추가, 메소 측정/집계 기능 시범 추가, 로컬 서버 포트 1108로 변경, 최근 3일 로그만 저장하게 수정, 초기 볼륨이 항상 0.5로 설정되던 오류 수정, config.json 파일 내부에 새로 추가된 필드가 없을 시 서버와 연결이 실패하던 오류 수정, 경험치/메소 집계 로직을 1초 전 수치와 비교하는 방식에서 초기값과 비교하는 방식으로 수정
  • Ver 1.2.0: 타이머 시간 만료 정지 시 알람 소리 추가, 볼륨 설정 옵션 추가
  • Ver 1.1.5: 서버 준비 확인 시 타임아웃 시간 연장하여 안정성 개선, 타임아웃 시 오류 알림 표시
  • Ver 1.1.4: 임시 폴더 내에 서버 로그 저장 추가
  • Ver 1.1.3: 임시 폴더 경로 지정 추가 (한글 사용자명 환경에서도 정상 동작하도록 명시적 지정)
  • Ver 1.1.2: 경험치 숫자 표시 형식을 1,000,000 형태로 변경
  • Ver 1.1.1: ROI 설정을 불러오는 과정에서 누락된 서버 통신 기능 수정
  • Ver 1.1.0: 설정 저장 기능 추가, 평균 경험치 계산 옵션 추가
  • Ver 1.0.2: 모니터 배율 적용 시 발생하는 ROI 관련 버그 수정
  • Ver 1.0.0: 정식 배포 시작

🛠️ 프로젝트 소개

자세한 프로젝트 소개 보기

1. 기술 구현 상세

아키텍처 및 데이터 흐름

본 애플리케이션은 사용자 인터페이스를 위한 Flutter 클라이언트와 데이터 처리를 위한 Python 백엔드 서버로 구성된 클라이언트-서버 아키텍처를 채택했습니다. 두 구성 요소는 로컬 환경에서 RESTful API를 통해 통신하며, 이를 통해 역할 분리 및 유지보수성을 확보했습니다.

  • 초기화 및 설정:

    1. Flutter 클라이언트가 시작되면, 내장된 Python 서버 실행 파일(ocr_server.exe)을 백그라운드 프로세스로 실행합니다.
    2. 클라이언트는 서버의 /health 엔드포인트를 주기적으로 호출하여 서버의 응답 가능 상태를 확인합니다.
    3. config.json 파일에서 이전 세션의 창 위치, ROI 좌표, 사용자 설정 등을 불러와 적용합니다.
    4. 사용자가 영역을 지정하면, 앱은 전체 화면 크기의 반투명 오버레이를 생성하고, 선택된 영역의 좌표는 기기 DPI를 고려하여 물리적 화면 좌표로 변환된 후 /set_roi API를 통해 서버로 전송됩니다.
  • 실시간 데이터 측정 흐름:

    1. Flutter의 Timer는 설정된 주기에 맞춰 Python 서버의 데이터 추출 API (/extract_exp_and_level 등)를 호출합니다.
    2. 서버는 mss 라이브러리로 지정된 화면 영역을 캡처하고, OpenCV를 통해 이미지 전처리(그레이스케일, 이진화, 리사이징 등)를 수행하여 OCR 인식률을 높입니다.
    3. Tesseract OCR 엔진이 전처리된 이미지에서 텍스트를 추출하며, 숫자만 인식하도록 whitelist와 최적화된 페이지 분할 모드(psm 7)를 사용합니다.
    4. 추출된 텍스트는 정규식(Regex)으로 파싱되어 JSON 형식으로 클라이언트에 반환됩니다.
    5. 클라이언트는 수신한 데이터를 기반으로 누적 값과 효율을 계산한 뒤 UI를 갱신합니다.

핵심 기술

  • PyInstaller 기반 독립 실행형 OCR 서버: Python 서버를 PyInstaller를 통해 Tesseract OCR 엔진과 함께 하나의 독립 실행 파일(.exe)로 패키징했습니다. 이를 통해 사용자는 별도의 런타임 설치 없이 앱을 즉시 사용할 수 있습니다. Flutter 클라이언트는 이 서버 프로세스의 실행부터 종료까지 전체 생명주기를 직접 관리합니다.

  • 전체 화면 오버레이를 이용한 ROI 설정: Flutter 프레임워크의 제약을 해결하기 위해, 영역 선택 시 window_manager 패키지로 앱을 전체 화면 크기의 반투명 창으로 일시적으로 전환합니다. 이를 통해 사용자는 앱 외부의 게임 화면을 보면서 정확한 영역을 마우스로 지정할 수 있으며, 선택 완료 후 앱은 이전 크기로 복귀합니다.

  • 클라이언트/서버 분리 로깅 시스템: 문제 해결 및 디버깅을 위해 클라이언트(Dart)와 서버(Python)에 각각 독립적인 로깅 시스템을 구축했습니다. 로그는 날짜별 파일로 관리되며, 3일이 지난 로그는 자동 삭제됩니다. 특히 Dart에서는 synchronized 패키지를 사용하여 비동기 환경에서의 동시 접근으로부터 로그 기록의 무결성을 보장합니다.


2. 사용자 경험(UX) 설계

기술 구현과 더불어, 사용자가 게임 플레이에 온전히 집중하면서도 필요한 정보를 손쉽게 얻을 수 있도록 하는 것에 UX 설계의 목표를 두었습니다. 핵심 원칙은 "최소한의 방해, 최대한의 직관성" 이었습니다.

정보 설계

  • 정보의 계층 구조: 사용자가 가장 빈번하게 확인하는 타이머와 실시간 획득 경험치를 가장 눈에 잘 띄게 배치하고, 부가 정보는 더 작은 글씨로 표시하여 시각적 중요도를 조절했습니다.
  • 점진적 공개(Progressive Disclosure):
    • 메소 측정 토글: 메소 측정 기능은 사용자가 토글을 켰을 때만 관련 UI가 나타나고 창 크기가 확장되도록 하여 기본 화면의 간결함을 유지했습니다.
    • 페이지뷰 기반의 설정 화면: 창 크기 조절 기능을 추가하면서도 일관된 UX를 위해 창의 가로세로 비율은 고정했습니다. 이 과정에서 화면 전환 시 창 크기를 매번 변경하는 대신, 페이지뷰를 도입하여 설정 화면의 크기를 일정하게 유지하면서도 여러 카테고리의 설정을 담을 수 있도록 구현했습니다. 이는 향후 기능 확장에도 유연하게 대처할 수 있는 구조입니다.

사용자 중심의 개선 및 협업

  • 피드백 기반 기능 개선: '평균값 표시 기준' 세분화, 'No-Audio 버전' 제공 등 실제 사용자들의 피드백을 적극적으로 수용하여 앱의 편의성과 안정성을 개선했습니다.
  • 오픈 소스 협업: 이 프로젝트는 오픈 소스로 운영되며, 외부 개발자들의 기여를 환영합니다. 메인 화면의 "'N 시간 후' 예상 시각 표시" 기능은 다른 개발자의 Pull Request를 검토하고 적용한 대표적인 협업 사례입니다.

편의 기능

  • 지속성: 창의 마지막 위치, 크기, 모든 사용자 설정을 config.json 파일에 저장하여 다음 실행 시 그대로 복원됩니다.
  • 전역 핫키: hotkey_manager를 사용하여 앱이 비활성 상태일 때도 단축키로 타이머를 제어할 수 있습니다.
  • 상황 인지형 UI: 타이머 동작 여부에 따라 창의 투명도를 다르게 적용하여 사용자가 앱의 현재 상태를 쉽게 인지할 수 있도록 했습니다.

©️ 라이선스

본 프로그램은 Mapleland 플레이어를 위한 개인 용도로 제공됩니다. 코드의 상업적/비상업적 재배포는 허용되지 않습니다. 개인적인 학습 목적의 수정 및 활용은 가능하나, 이를 외부에 배포하거나 상업적으로 이용하는 것은 금지됩니다.