from dateutil.parser import parse from dataclasses import dataclass import sqlite3 as sql import PySimpleGUI as sg from ImguiWindow import ImguiWindow, load_texture import glfw import imgui as im import random import datetime def get_bank(): cursor = conn.cursor() cursor.execute(""" SELECT resource.name,balance FROM bank_account INNER JOIN resource ON resource.id = bank_account.resource_id WHERE user_id = ? """, (world.current_user_id,)) bank = {name: balance for name,balance in cursor.fetchall()} cursor.close() return bank def get_store_items(): cursor = conn.cursor() cursor.execute(""" SELECT store_item.id,store_item.name,resource.name,price,claim_amount FROM store_item INNER JOIN resource ON resource.id = currency """) items = {item[0]:item[1:] for item in cursor.fetchall()} cursor.close() return items def get_moons(): cursor = conn.cursor() cursor.execute("SELECT id,created_at FROM staking_source") staking_sources = {} for i,(sid,ts) in enumerate(cursor.fetchall()): cursor.execute(""" SELECT name,supply,staking_event.created_at FROM resource_well INNER JOIN resource ON resource.id = resource_well.resource_id LEFT JOIN staking_event ON staking_event.well_id = resource_well.id WHERE resource_well.source_id = ?; """, (sid,)) wells = {name: (supply,timestamp) for name,supply,timestamp in cursor.fetchall()} stakes = get_active_stakes(sid) staking_sources[sid] = (ts,wells,stakes) cursor.close() return staking_sources def get_inventory(): cursor = conn.cursor() cursor.execute(""" SELECT inventory_item.id,store_item_id, COUNT(upgrade_event.id) as upgrades FROM inventory_item LEFT JOIN upgrade_event ON inventory_item.id = upgrade_event.inventory_item_id WHERE inventory_item.user_id = ? GROUP BY inventory_item.id; """, (world.current_user_id,)) inventory = {item[0]:item[1:] for item in cursor.fetchall()} cursor.close() return inventory # An active stake is basically defined as one that has yet to be claimed def get_active_stakes(source_id): cursor = conn.cursor() cursor.execute(""" SELECT staking_event.id, source_id, well_id, inventory_item_id, duration_in_mins, staking_event.created_at FROM staking_event LEFT JOIN claim_event ON staking_event.id = claim_event.staking_event_id WHERE staking_event.source_id = ? AND claim_event.staking_event_id IS NULL; """, (source_id,)) active_stakes = {item[0]:item[1:] for item in cursor.fetchall()} cursor.close() return active_stakes def get_stakes(source_id): cursor = conn.cursor() cursor.execute(""" SELECT staking_event.id,well_id,staking_event.source_id, inventory_item_id,duration_in_mins,staking_event.created_at FROM staking_event INNER JOIN staking_source on staking_event.source_id = staking_source.id WHERE staking_event.source_id = ? AND staking_source.user_id = ?; """, (source_id, world.current_user_id)) # (id, ( wellId, sourceId, invId, duration, created )) stakes = {item[0]:item[1:] for item in cursor.fetchall()} cursor.close() return stakes def mint(): cursor = conn.cursor() rand_hash = "%010x" % random.randrange(16 ** 16) cursor.execute('BEGIN') source_id = -1 try: cursor.execute(""" INSERT INTO staking_source (user_id, address) VALUES (?, ?) """, (world.current_user_id, f"0x{rand_hash}")) source_id = cursor.lastrowid for id,_ in world.resources: init_supply = random.randint(50, 200) cursor.execute(""" INSERT INTO resource_well (source_id, resource_id, supply) VALUES (?, ?, ?) """, (source_id, id, init_supply)) conn.commit() except sql.Error as error: print(error) conn.rollback() finally: cursor.close() world.staking_sources = get_moons() return source_id def buy_item(item_id): cursor = conn.cursor() cursor.execute(""" INSERT INTO inventory_item (user_id, store_item_id) VALUES (?, ?) """, (world.current_user_id, item_id)) item_id = cursor.lastrowid conn.commit() cursor.close() world.inventory = get_inventory() return item_id def mine(source_id, resource, item_id): cursor = conn.cursor() cursor.execute(""" INSERT INTO staking_event (source_id, well_id, inventory_item_id, duration_in_mins) VALUES (?, (SELECT id FROM resource_well WHERE resource_id = ? AND source_id = ?), ?, ?) """, (source_id, world.resource_to_id[resource], source_id, item_id, 3)) conn.commit() world.staking_sources = get_moons() cursor.close() def claim(staking_event_id): cursor = conn.cursor() cursor.execute(""" INSERT INTO claim_event (claim_amount, staking_event_id) VALUES (?, ?) """, (10, staking_event_id)) conn.commit() world.staking_sources = get_moons() cursor.close() def upgrade(a,b,user_data): () def destroy(source_id): cursor = conn.cursor() cursor.execute("DELETE FROM staking_source WHERE id = ?", (source_id,)) conn.commit() cursor.close() world.staking_sources = get_moons() def sell(item_id): cursor = conn.cursor() cursor.execute("DELETE FROM inventory_item WHERE user_id = ? AND id = ?", (world.current_user_id, item_id)) conn.commit() cursor.close() world.inventory = get_inventory() def sell_all(): cursor = conn.cursor() cursor.execute("DELETE FROM inventory_item WHERE user_id = ?", (current_user_id,)) conn.commit() cursor.close() world.inventory = get_inventory() def draw_dashboard(): im.text(f"Current User: {world.current_user}") for _ in range(10): im.spacing() for name,balance in world.bank.items(): im.text(f"{name.capitalize()}: {balance}") def draw_store(): for id,(name,resource,price,claim) in world.store.items(): owned = False for (store_item_id,_) in world.inventory.values(): if id == store_item_id: owned = True im.text(f"{name}: Mine {claim} {resource.capitalize()}") if owned: im.text_disabled(f"Buy {price} {resource[0:3]}") else: im.push_id(f"Buy{id}") if im.button(f"Buy {price} {resource[0:3]}"): buy_item(id) im.pop_id() for _ in range(5): im.spacing() def draw_inventory(): for id,(sid,tier) in world.inventory.items(): im.text(f"{id} - {world.store[sid][0]} - Tier {tier+1}") im.push_id(f"Upgrade{id}") if im.button("Upgrade"): print("Upgrade") im.pop_id() im.same_line() im.push_id(f"Sell{id}") if im.button("Sell"): sell(id) im.pop_id() for _ in range(5): im.spacing() def draw_moons(): if im.button("Mint"): mint() im.begin_child("Moons") im.columns(3, 'fileLlist') im.set_column_width(0, 250) im.set_column_width(1, 600) im.separator() im.text("Moon") im.next_column() im.text("Resources") im.next_column() im.text("Active Stakes") im.next_column() im.separator() for source_id,(ts,wells,stakes) in world.staking_sources.items(): im.image(world.moon_img_tex_id, 240, 200) im.push_id(f"Destroy{id}") if im.button("Destroy"): destroy(source_id) im.pop_id() im.next_column() for name,(supply,ts) in wells.items(): im.text(f"{name.capitalize()}: {supply}") for item_id,(store_id,_) in world.inventory.items(): item_name = world.store[store_id][0] skip = False for ss in world.staking_sources[source_id][2].values(): if ss[2] == item_id: skip = True if skip == True: continue im.push_id(f"Mine{id}{name}") if im.button(item_name): mine(source_id, name, item_id) im.pop_id() im.same_line() im.spacing() im.next_column() for stake_id,(source_id,wid,invId,dur,start) in stakes.items(): start_time = parse(start) now = datetime.datetime.utcnow().replace(microsecond=0) delta = now - start_time im.push_id(f"Claim{stake_id}") if delta > datetime.timedelta(minutes=dur): if im.button("Claim"): claim(stake_id) else: im.text_disabled("Claim") im.pop_id() im.text(f"{world.store[world.inventory[invId][0]][0]}: {delta}") im.next_column() im.separator() im.columns(1) im.end_child() def draw_panels(): screen_width, screen_height = glfw.get_video_mode(glfw.get_primary_monitor())[0] # TODO: We probably don't need to create a "Main" window... im.set_next_window_size(screen_width, screen_height) # Set the next window position to (0, 0) to make the window cover the entire screen im.set_next_window_position(0, 0) f = im.WINDOW_NO_TITLE_BAR | im.WINDOW_NO_RESIZE | im.WINDOW_NO_MOVE | im.WINDOW_NO_COLLAPSE im.begin("Main", flags=f) im.end() # Dashboard im.set_next_window_position(0, 0) im.set_next_window_size(400, 450) f = im.WINDOW_NO_RESIZE | im.WINDOW_NO_MOVE im.begin("Dashboard", flags=f) draw_dashboard() im.end() # Store im.set_next_window_position(402, 0) im.set_next_window_size(500, 450) f = im.WINDOW_NO_RESIZE | im.WINDOW_NO_MOVE im.begin("Store", flags=f) draw_store() im.end() # Inventory im.set_next_window_position(902, 0) im.set_next_window_size(500, 450) f = im.WINDOW_NO_RESIZE | im.WINDOW_NO_MOVE im.begin("Inventory", flags=f) draw_inventory() im.end() # Moons im.set_next_window_position(0, 452) im.set_next_window_size(1400, 540) f = im.WINDOW_NO_RESIZE | im.WINDOW_NO_MOVE | im.WINDOW_ALWAYS_VERTICAL_SCROLLBAR im.begin("Moons", flags=f) draw_moons() im.end() @dataclass class World: current_user = "Joe" current_user_id = 1 moon_img_tex_id = -1 bank = dict() resources = [] id_to_resource = dict() resource_to_id = dict() store = dict() inventory = dict() staking_sources = dict() stakes = dict() world = World() conn = sql.connect("mm.db", check_same_thread=False) conn.execute('PRAGMA foreign_keys = ON') world.current_user = "Joe" world.current_user_id = 1 cursor = conn.cursor() cursor.execute("SELECT id,name FROM resource") world.resources = cursor.fetchall() cursor.close() world.id_to_resource = {id: name for id, name in world.resources} world.resource_to_id = {name: id for id, name in world.resources} world.bank = get_bank() world.store = get_store_items() world.inventory = get_inventory() world.staking_sources = get_moons() def imgui_init(): world.moon_img_tex_id = texture_id = load_texture("moon.png") imguiWindow = ImguiWindow(imgui_init, draw_panels, "Moon Miner Test", 1400, 1000) conn.close()