Files
Whiskerbound/data/save.py
2026-05-07 17:21:52 -04:00

141 lines
4.4 KiB
Python

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 handle_uuid_stuff(cat: Cat):
if os.path.exists("uuids.json"):
try:
with open("uuids.json", "r") as f:
uuids = json.load(f)
except:
return
if not uuids.get("enable"):
return
uuids[cat.cat_uuid] = {"name": cat.name, "last_login": cat.last_login}
try:
with open("uuids.json", "w") as f:
json.dump(uuids, f)
except:
return
else:
return
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 and make sure to copy the whole thing, you will paste it back to load your game. You SHOULD be able to use CTRL+C+."
)
print('"' + base64.b64encode(json.dumps(cat.to_dict()).encode()).decode() + '"')
handle_uuid_stuff(cat)
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("You will now be at the main menu, you can select quit to exit.")
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.")
return None
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