import json from data.cat import Cat import os import sys import hashlib import systems.ui import shutil import base64 import systems.ui def punish(cat): print( "You have tampered with your cat, your cat is sad, you must pet your cat 20,000 times to continue playing." ) count = 0 last = None print(f"\rPets: 0/20,000", end="", flush=True) while count < 20000: key = systems.ui.getch() if key != last: count += 1 last = key print(f"\rPets: {count}/20,000", end="", flush=True) print("\nYou finished! Your cat is a bit upset but you may continue playing.") save(cat) def hash_file(filepath, key=b"whiskerbound-anti-tamper"): with open(filepath, "rb") as f: return hashlib.blake2s(f.read(), key=key).hexdigest() def get_data_dir(): if sys.platform == "win32": return os.path.join(os.environ["APPDATA"], "Whiskerbound") else: return os.path.join( os.environ.get("XDG_DATA_HOME", os.path.expanduser("~/.local/share")), "Whiskerbound", ) def prepare_move(): data_dir = get_data_dir() hash_path = os.path.join(data_dir, "dont hurt cats.json") if os.path.exists(hash_path): shutil.copy(hash_path, "saves/.moved") print("Ready to move! Copy your saves folder to your new PC.") else: print("No save data to prepare.") def save(cat: Cat, dont_save=False): if os.path.exists("WEB_VERSION") and not dont_save: print( "Under this message, in quotes, will be a long string of text, this is your savefile, please copy this somewhere safe (WITHOUT THE QUOTES) and make sure to copy the whole thing, you will paste it back to load your game. DO NOT use control+c to copy, instead, select it, and use the right click menu to copy, ctrl+c will crash this." ) print('"' + base64.b64encode(json.dumps(cat.to_dict()).encode()).decode() + '"') print( "Your savefile has been printed above this, please save it somewhere safe." ) print( "Any progress done after this will not be saved in this string, please generate a new one to update your progress." ) print("To get back to the main menu and quit, reload the page.") systems.ui.press_any_key_to_continue("Press any key to continue.") return currentjson = {} data_dir = get_data_dir() hash_path = os.path.join(data_dir, "dont hurt cats.json") if not os.path.exists("saves"): os.mkdir("saves") with open(f"saves/{cat.name}.kitten", "w") as f: json.dump(cat.to_dict(), f) os.makedirs(data_dir, exist_ok=True) if os.path.exists(hash_path): with open(hash_path, "r") as f: currentjson = json.load(f) currentjson[f"saves/{cat.name}.kitten"] = hash_file(f"saves/{cat.name}.kitten") with open(hash_path, "w") as f: json.dump(currentjson, f) print("Saved.") def load( filepath, bypass_tamper_check=False, force_punish=False, hide_web_message=False ): if os.path.exists("WEB_VERSION"): if not hide_web_message: print("Loading is disabled.") punished = False data_dir = get_data_dir() hash_path = os.path.join(data_dir, "dont hurt cats.json") file_hash = hash_file(filepath) if not os.path.exists(hash_path) and os.path.exists("saves/.moved"): os.makedirs(data_dir, exist_ok=True) shutil.move("saves/.moved", hash_path) if os.path.exists(hash_path): with open(hash_path, "r") as f: hashes = json.load(f) if not filepath in hashes: punished = True else: if not hashes[filepath] == file_hash: punished = True else: pass # ur good else: punished = True with open(filepath) as f: raw = json.load(f) cat = Cat(**raw) if punished or force_punish: if not bypass_tamper_check: punish(cat) return cat