0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

東方projectSTGゲームのAIを作るときの便利なやつまとめ

Posted at

TL;DR

まとめただけなのでこの記事にあまり価値はないです
ctypes大事

環境

OS:Windows 10
Python:3.9.0

スクショ取得

pillowを使います

from PIL import ImageGrab

def get_screenshot():
    region=get_region() #こちらは各自で実装してください
    img=ImageGrab.grab(region)
    return region

キー入力

pyautoguiを使うを失敗します(原因わからん)
なのでctypesを利用して直接win32apiをたたきます。
そこでこの記事

(日本語英語以外を毛嫌いしてたら一生見なかったかも)
コード抜粋、変更

import ctypes

PUL = ctypes.POINTER(ctypes.c_ulong)

key = {"up":0x48, "down":0x50, "left":0x4D, "right":0x4B,"z":0x2C,"Enter":0x1C,"Shift":54}
class KeyBdInput(ctypes.Structure):
    _fields_ = [("wVk", ctypes.c_ushort),
                ("wScan", ctypes.c_ushort),
                ("dwFlags", ctypes.c_ulong),
                ("time", ctypes.c_ulong),
                ("dwExtraInfo", PUL)]

class Input_I(ctypes.Union):
    _fields_ = [("ki", KeyBdInput),
                 ("mi", MouseInput),
                 ("hi", HardwareInput)]


class Input(ctypes.Structure):
    _fields_ = [("type", ctypes.c_ulong),
                ("ii", Input_I)]

# Actuals Functions
def PressKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput(0, hexKeyCode, 0x0008, 0, ctypes.pointer(extra))
    x = Input(ctypes.c_ulong(1), ii_)
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))


def ReleaseKey(hexKeyCode):
    extra = ctypes.c_ulong(0)
    ii_ = Input_I()
    ii_.ki = KeyBdInput( 0, hexKeyCode, 0x0008 | 0x0002, 0, ctypes.pointer(extra) )
    x = Input(ctypes.c_ulong(1), ii_)
    ctypes.windll.user32.SendInput(1, ctypes.pointer(x), ctypes.sizeof(x))

プロセスメモリ参照

うさみみハリケーンで実験を行った後にReadProcessMemory関数でメモリ参照を行います。
ただ正直よくわからなかったので下の記事を参考に必要部分のみをコードに書き起こしました。

以下抜粋コード(コピペばかりでごめんなさい)

defines.py
from ctypes import *

# types
DWORD     = c_ulong
PVOID     = c_void_p
ULONG_PTR = c_ulong
LONG      = c_long
# constant
INFINITE                  = 0xFFFFFFFF
DBG_CONTINUE              = 0x00010002
DBG_EXCEPTION_NOT_HANDLED = 0x80010001
PROCESS_ALL_ACCESS= ( 0x000F0000 ) | ( 0x00100000 ) |0xFFFF  #ここだけ追加
class EXCEPTION_RECORD(Structure):
    pass

EXCEPTION_RECORD._fields_ = [
    ("ExceptionCode",        DWORD),
    ("ExceptionFlags",       DWORD),
    ("ExceptionRecord",      POINTER(EXCEPTION_RECORD)),
    ("ExceptionAddress",     PVOID),
    ("NumberParameters",     DWORD),
    ("ExceptionInformation", ULONG_PTR*15),
]

class EXCEPTION_RECORD(Structure):
    _fields_ = [
        ("ExceptionCode",        DWORD),
        ("ExceptionFlags",       DWORD),
        ("ExceptionRecord",      POINTER(EXCEPTION_RECORD)),
        ("ExceptionAddress",     PVOID),
        ("NumberParameters",     DWORD),
        ("ExceptionInformation", ULONG_PTR*15),
    ]

class EXCEPTION_DEBUG_INFO(Structure):
    _fields_ = [
        ("ExceptionRecord", EXCEPTION_RECORD),
        ("dwFirstCance",    DWORD),
    ]

class U(Union):
    _fields_ = [
        ("Exception", EXCEPTION_DEBUG_INFO),
    ]

class DEBUG_EVENT(Structure):
    _fields_ = [
        ("dwDebugEventCode", DWORD),
        ("dwProcessId",      DWORD),
        ("dwThreadId",       DWORD),
        ("u",                U),
    ]

class LUID(Structure):
    _fields_ = [
        ("LowPart",  DWORD),
        ("HighPart", LONG),
    ]

class LUID_AND_ATTRIBUTES(Structure):
    _fields_ = [
        ("Luid",       LUID),
        ("Attributes", DWORD),
    ]

class TOKEN_PRIVILEGES(Structure):
    _fields_ = [
        ("PrivilegeCount", DWORD),
        ("Privileges",     LUID_AND_ATTRIBUTES),
    ]
from ctypes          import *
from defines         import *
#from privilege       import set_debug_privilege
#from page_protection import get_page_info, set_page_protection, show_protection

kernel32 = windll.kernel32

#set_debug_privilege()  #書かなくても動いたけど、場合によっては必要かも

def open_process(pid):
    h_process = kernel32.OpenProcess(PROCESS_ALL_ACCESS, False, pid)
    if not h_process:
        print(WinError(GetLastError()))
        return False
    return h_process

def read_process_memory(h_process, address, length):
    data     = None
    read_buf = create_string_buffer(length)
    count    = c_ulonglong(0)
    if not kernel32.ReadProcessMemory(h_process, address, read_buf, length, byref(count)):
        print(WinError(GetLastError()))
        return False
    else:
        data += str(read_buf.raw)
    return data


def address_main():
    pid  = input("pid: ")#後述の方法で自動化可能

    h_process = open_process(int(pid))
    address=0x004F7844
    data = read_process_memory(h_process, address, 1)
    print(data)


if __name__ == "__main__":
    address_main()

実行時の残基を表示するコードです

PID取得

tasklistコマンドを使う
東方輝針城の場合

tasklist | find "th14.exe"

以下実行結果例

th14.exe                     16984 Console                    1    159,780 K

これを加工すればpython側で自動取得できます


import subprocess

def get_pid():
    r=subprocess.run("tasklist | find \"th14.exe\"",shell=True,stdout=subprocess.PIPE)
    return int(r.split()[1].stdout.decode())

追記

新規の情報ほぼ0のしょうもない記事すぎる...

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?