본문 바로가기
게임/메이플랜드

메이플랜드 경험치 측청기,분석기 만들기 - 시계열 데이터 쌓기

by 낭만법사 2024. 1. 21.

Python 기반의 OCR 프로그램의 PoC를 성공한 뒤, 본래 니즈에 맞는 기능들을 하나 둘 쌓아나가려합니다.

일단 데이터를 DB에 저장하는 것, 그리고 파이썬 스크립트를 백그라운드로 실행시킴과 동시에 실시간으로 GUI에 데이터가 업데이트되는 것 까지 만들어볼까 합니다.

(분량상 전체 코드를 업로드하진 않고 코드 조각을 조금씩 첨부할 예정입니다.)

 

경험치 크롤링을 백그라운드로 실행하기

기존 코드에서는 메인 프로세스에서 단일 쓰레드로 프로그램이 실행되었습니다.

경험치를 추출하여 출력하는 것 외에 다른일을 할 수 없는 구조라 이를 백그라운드 태스크로 전환하여 실행할 수 있게끔 변경했습니다.

import schedule

def read_text_from_screen(x, y, width, height):
    ....

def job():
    read_text_from_screen(screen_x, screen_y, screen_width, screen_height)


# 5초마다 job 함수 실행
schedule.every(5).seconds.do(job)

 

Python schedule 라이브러리를 사용해 5초 간격으로 job 함수를 실행하게끔 설정했습니다.

나중엔 실행 간격 역시도 프로그램의 환경 설정에서 변경할 수 있다면 좋겠군요.

이제 메인 프로세스가 종료되기 전 까지는 job 함수가 실행되는 것이 보장됩니다.

 

Tkinter를 이용해 UI 만들기

현재는 print문을 사용해 로그를 터미널에 출력시키고 있었으나, GUI 상에서 로그를 확인할 수 있도록 변경을 해보겠습니다. 이는 디버깅 로그처럼 별도의 탭을 눌렀을 때에만 로그를 확인할 수 있도록 숨겨질 예정입니다.

def read_text_from_screen(x, y, width, height):
    try:
        ...
        log_text = f"[{time.strftime('%Y-%m-%d %H:%M:%S')}] {exp_point_integer}, {exp_percentage_float}%\n"
        log_display.insert(tk.END, log_text)
        log_display.see(tk.END)  # 스크롤을 항상 가장 아래로 이동
    except Exception as e:
        print(f"Error: {e}")

def job():
    screen_x = 608
    screen_y = 983
    screen_width = 120
    screen_height = 20
    read_text_from_screen(screen_x, screen_y, screen_width, screen_height)

schedule.every(5).seconds.do(job)

root = tk.Tk()
root.title("메이플랜드 경험치 측정기")

root.geometry("400x300")
root.resizable(True, True)

log_display = scrolledtext.ScrolledText(root, width=40, height=30)
log_display.pack(padx=10, pady=10)

def on_exit():
    conn.close()
    root.destroy()

exit_button = tk.Button(root, text="Exit", command=on_exit)
exit_button.pack(pady=10)

while True:
    root.update()
    schedule.run_pending()
    time.sleep(1)

 

경험치 분석기 UI 테스트

파이썬으로 GUI를 만들어보는 것이 처음이라 아직 심미성이 떨어지긴하나, 5초 간격으로 경험치를 정확하게 출력하는 모습입니다.

 

SQLite에 데이터를 저장하기

스케쥴러도 잘 돌고, UI를 그리는 법도 대강 알았으니 이제 데이터를 저장할 차례입니다.

데이터 수집을 충분히 해 두어야 유의미한 UI를 그릴 수 있고, 몇 레벨 이상의 데이터가 쌓여야만 레벨별 경험치 효율 역시 비교해볼 수 있겠죠.

이번엔 SQLite에 데이터를 저장하는 스크립트까지 추가해보겠습니다.

# SQLite 데이터베이스 연결
conn = sqlite3.connect('data.db')
cursor = conn.cursor()

# 테이블 생성
cursor.execute('''
CREATE TABLE IF NOT EXISTS extracted_data (
    id INTEGER PRIMARY KEY AUTOINCREMENT,
    timestamp DATETIME DEFAULT CURRENT_TIMESTAMP,
    exp_point INTEGER,
    exp_percentage REAL
)
''')
conn.commit()

def read_text_from_screen(x, y, width, height):
    try:
        # 경험치 추출
        if exp_point and exp_percentage:
            exp_point_integer = int(exp_point.group())
            exp_percentage_float = float(exp_percentage.group(1))
            # 데이터베이스에 저장
            cursor.execute('INSERT INTO extracted_data (exp_point, exp_percentage) VALUES (?, ?)',
                           (exp_point_integer, exp_percentage_float))
            conn.commit()
            # GUI 작업
    except Exception as e:
        print(f"Error: {e}")

 

SQLite 테이블 데이터 확인

 

테이블 초기화 스크립트와, read_text_from_screen 함수에 데이터 저장 스크립트까지 추가해보았습니다.

SQLite DB에 경험치 데이터가 잘 저장되고 있는 것을 볼 수 있습니다. 현재 캐릭터의 레벨이나 해당 레벨의 총 경험치량을 함께 저장하면 더 유용할 수 있겠군요, 코드를 모듈화하고 데이터를 보강해봅시다.

 

코드 정리

main.py에 한데 모인 코드를 재사용성 높게 분류하는 작업을 진행했습니다.

앞으로는 scheduler나 ui란에 기능들이 추가되겠군요.

또 level의 이미지를 파싱해보려 했는데 테서렉트에서는 OCR로 레벨란의 숫자를 읽어들이는 것이 쉽지 않았습니다.

당장에 아주 큰 의미를 가지진 않기에 이 이슈는 잠시 백로그에 두고 다시 꺼내보겠습니다.

 

이제 쌓인 데이터를 기반으로 UI를 이쁘게 꾸미는 일이 남았습니다.

다음 편엔 저장된 데이터를 기반으로 그래프를 그리는 등의 인사이트를 보여주는 작업을 진행해보겠습니다.