Skip to content

Commit

Permalink
fix handling trailing newline in p8 files (now always included/ignore…
Browse files Browse the repository at this point in the history
…d) and fix interaction test
  • Loading branch information
thisismypassport committed Feb 24, 2024
1 parent 356b207 commit 085e28c
Show file tree
Hide file tree
Showing 58 changed files with 671 additions and 566 deletions.
4 changes: 2 additions & 2 deletions pico_cart.py
Original file line number Diff line number Diff line change
Expand Up @@ -313,7 +313,7 @@ def ext_nybbles(line):
code = []
code_line = 0
y = 0
for line_i, line in enumerate(data.split("\n")): # not splitlines, that eats a trailing empty line
for line_i, line in enumerate(data.splitlines()): # splitlines eats a trailing empty line, like pico8 does
try:
clean = line.strip()

Expand Down Expand Up @@ -483,7 +483,7 @@ def get_needed_lines(max_lines, addr_func, size):
lines.append(f"__{k_meta_prefix + meta}__")
lines += metalines

return "\n".join(lines)
return "\n".join(lines) + "\n"

def write_cart_to_raw_source(cart, with_header=False, unicode_caps=False, **_):
source = from_p8str(cart.code, unicaps=unicode_caps)
Expand Down
76 changes: 6 additions & 70 deletions run_bbs_tests.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,7 +37,7 @@ def CommaSep(val):
g_opts = parser.parse_args()

if not g_opts.pico8_time:
g_opts.pico8_time = 8.0 if g_opts.pico8_interact else 2.0
g_opts.pico8_time = 15.0 if g_opts.pico8_interact else 2.0

if g_opts.carts_file and not g_opts.carts:
g_opts.carts = file_read_text(g_opts.carts_file).splitlines()
Expand Down Expand Up @@ -111,8 +111,6 @@ def apply_dictionary(m, other):

def check_run(name, result, parse_meta=False):
success, stdout = result
if "SHORT" in stdout:
print(name, stdout)
if not success:
print(f"Run {name} failed. Stdout:\n{stdout}")
fail_test()
Expand Down Expand Up @@ -222,71 +220,6 @@ def process_output(kind, output):

return (cart, get_test_results(), new_cart_input, cart_output, deltas, best_path_for_pico8)

def interact_with_pico8s():
import win32api, win32gui, win32process, win32con as wc, pywintypes # type: ignore

pico8_paths = set(path_normalize(pico8) for pico8 in g_opts.pico8)

pico8_keys = [wc.VK_LEFT, wc.VK_RIGHT, wc.VK_UP, wc.VK_DOWN, ord('X'), ord('Z')]
pico8_key_counts = [0, 0, 0, 0, 1, 1, 1, 1, 2, 2, 2, 3, 3, 4]
prev_hwnd_data = defaultdict(lambda: Dynamic(keys=[], pid=None))

wc_MAPVK_VK_TO_VSC_EX = 4 # missing...

def send_key(key, state):
scode = win32api.MapVirtualKey(key, wc_MAPVK_VK_TO_VSC_EX)
flags = 0 if state else wc.KEYEVENTF_KEYUP
if scode >= 0x100:
flags |= wc.KEYEVENTF_EXTENDEDKEY
scope >>= 8
win32api.keybd_event(key, scode, flags, 0)

while True:
# activate a random pico8 window
pico8_windows = []

def on_window(hwnd, _):
try:
_, pid = win32process.GetWindowThreadProcessId(hwnd)
proc = win32api.OpenProcess(wc.PROCESS_QUERY_INFORMATION | wc.PROCESS_VM_READ, False, pid)
if proc:
try:
ppath = win32process.GetModuleFileNameEx(proc, None)
finally:
proc.close()

if ppath and path_normalize(ppath) in pico8_paths:

if prev_hwnd_data[hwnd].pid != pid: # just in case?
prev_hwnd_data[hwnd].keys.clear()
prev_hwnd_data[hwnd].pid = pid

pico8_windows.append(hwnd)
except pywintypes.error:
pass # e.g. can't access hwnd, or hwnd/process died

win32gui.EnumWindows(on_window, None)

if pico8_windows:
hwnd = random.choice(pico8_windows)
try:
win32gui.SetForegroundWindow(hwnd)
except pywintypes.error:
pass # e.g. hwnd died
else:
key_count = random.choice(pico8_key_counts)
keys = random.sample(pico8_keys, k=key_count)
prev_keys = prev_hwnd_data[hwnd].keys

for key in prev_keys:
if key not in keys:
send_key(key, False)
for key in keys:
if key not in prev_keys:
send_key(key, True)

time.sleep(0.05)

def run(focus):
prefix = f"{focus}_" if focus else ""

Expand All @@ -301,7 +234,7 @@ def run(focus):
deltas = DeltaInfoDictionary()

if g_opts.pico8_interact:
Thread(target=interact_with_pico8s, daemon=True).start()
Thread(target=interact_with_pico8s, args=(g_opts.pico8, g_opts.pico8_time), daemon=True).start()

with mp.Pool(g_opts.parallel_jobs, init_for_process, (g_opts,)) as mp_pool, \
mt.Pool(g_opts.parallel_jobs) as mt_pool:
Expand All @@ -322,7 +255,10 @@ def run(focus):
if cart_pico8_path and g_opts.pico8 and not g_opts.no_pico8:
for pico8 in g_opts.pico8:
def run(pico8=pico8, path=cart_pico8_path):
return run_pico8(pico8, path, allow_timeout=True, timeout=g_opts.pico8_time, with_window=g_opts.pico8_interact)
if g_opts.pico8_interact:
return run_interactive_pico8(pico8, path)
else:
return run_pico8(pico8, path, allow_timeout=True, timeout=g_opts.pico8_time)

p8_results.append(mt_pool.apply_async(run))

Expand Down
Loading

0 comments on commit 085e28c

Please sign in to comment.