Compare commits

...

10 Commits

6 changed files with 298 additions and 164 deletions

1
.gitignore vendored
View File

@ -1 +1,2 @@
/__pycache__/
/mm.db

View File

@ -54,7 +54,7 @@ class ImguiWindow():
# Load a new font
io = im.get_io()
new_font = io.fonts.add_font_from_file_ttf("/usr/share/fonts/TTF/RobotoMono-Regular.ttf", 24)
new_font = io.fonts.add_font_from_file_ttf("./fira.ttf", 24)
impl.refresh_font_texture()
init_fn()

View File

@ -12,52 +12,18 @@ INSERT INTO users(name) VALUES
('Plug'),
('Upgrade');
INSERT INTO bank_account(user_id, resource_id, balance) VALUES
INSERT INTO resource_account(user_id, resource_id, balance) VALUES
(1, 1, 200),
(1, 2, 175),
(1, 3, 0),
(1, 4, 25),
(1, 5, 10);
INSERT INTO store_item(name, currency, target_resource, price, claim_amount) VALUES
('Drill 1A', 1, 1, 25, 500),
('Drill 1B', 1, 2, 25, 500),
('Drill 1C', 1, 3, 25, 500),
('Drill 1D', 1, 4, 25, 500),
('Drill 1E', 1, 5, 25, 500);
INSERT INTO bank_account(user_id, balance) VALUES (1, 500);
SELECT staking_event.id,well_id,staking_event.source_id,
inventory_item_id,staking_event.created_at,expiration_at
FROM staking_event
INNER JOIN resource_well ON resource_well.id = well_id
INNER JOIN staking_source on staking_event.source_id = staking_source.id
WHERE staking_event.source_id = ? AND staking_source.user_id = ?;
SELECT name,init_supply
FROM resource_well
INNER JOIN resource ON resource.id = resource_well.resource_id
WHERE source_id = 1;
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 = 1
GROUP BY inventory_item.id;
SELECT inventory_item.id,store_item_id
FROM inventory_item;
SELECT staking_event.id,well_id,staking_event.source_id,
inventory_item_id,staking_event.created_at,expiration_at
FROM staking_event
INNER JOIN staking_source on staking_event.source_id = staking_source.id
WHERE staking_event.source_id = 4 AND staking_source.user_id = 1;
SELECT staking_event.id, staking_event.well_id, staking_event.source_id,
staking_event.inventory_item_id, staking_event.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 = 4 AND claim_event.staking_event_id IS NULL;
INSERT INTO store_item(name, price, claim_amount, completion_time_mins) VALUES
('Drill A', 25, 50, 2),
('Drill B', 25, 50, 2),
('Drill C', 25, 50, 2),
('Drill D', 25, 50, 2),
('Drill E', 25, 50, 2);

344
mm.py
View File

@ -1,7 +1,6 @@
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
@ -11,41 +10,104 @@ 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
SELECT resource_account.id,resource.name,balance FROM resource_account
INNER JOIN resource ON resource.id = resource_account.resource_id
WHERE user_id = ?
""", (world.current_user_id,))
bank = {name: balance for name,balance in cursor.fetchall()}
resources = {id:(name, balance) for id,name,balance in cursor.fetchall()}
cursor.execute("SELECT bank_account.id,balance FROM bank_account WHERE user_id = ?",
(world.current_user_id,))
bank = cursor.fetchone()
cursor.close()
return bank
return (bank, resources)
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
SELECT store_item.id, store_item.name, price, claim_amount, completion_time_mins
FROM store_item
""")
items = {item[0]:item[1:] for item in cursor.fetchall()}
cursor.close()
return items
def get_stakes():
cursor = conn.cursor()
cursor.execute("""
SELECT staking_event.id, well_id, inventory_item_id, stake_amount, duration_in_mins,
staking_event.created_at,
CASE WHEN claim_event.staking_event_id IS NULL THEN 1 ELSE 0 END AS is_active
FROM staking_event
INNER JOIN resource_well ON resource_well.id = staking_event.well_id
INNER JOIN staking_source ON staking_source.id = resource_well.source_id
LEFT JOIN claim_event ON claim_event.staking_event_id = staking_event.id
WHERE staking_source.user_id = ?;
""", (world.current_user_id,))
stakes = {item[0]:(item[1],item[2],item[3],item[4],bool(item[-1])) for item in cursor.fetchall()}
cursor.close()
return stakes
# 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, well_id, inventory_item_id, stake_amount, duration_in_mins,
staking_event.created_at
FROM staking_event
LEFT JOIN claim_event ON staking_event.id = claim_event.staking_event_id
INNER JOIN resource_well ON resource_well.id = staking_event.well_id
WHERE resource_well.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_wells(source_id):
cursor = conn.cursor()
cursor.execute("""
SELECT resource_well.id,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 = ?;
""", (source_id,))
wells = {id: (name,supply,timestamp) for id,name,supply,timestamp in cursor.fetchall()}
cursor.close()
return wells
def get_all_wells():
cursor = conn.cursor()
cursor.execute("""
SELECT resource_well.id,name,supply FROM resource_well
INNER JOIN resource ON resource.id = resource_well.resource_id
INNER JOIN staking_source ON staking_source.id = resource_well.source_id
WHERE staking_source.user_id = ?;
""", (world.current_user_id,))
wells = {w[0]:w[1:] for w in cursor.fetchall()}
cursor.close()
return wells
def get_moons():
cursor = conn.cursor()
cursor.execute("SELECT id,created_at FROM staking_source")
cursor.execute("SELECT id,created_at FROM staking_source WHERE user_id = ?",
(world.current_user_id,))
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)
for sid,ts in cursor.fetchall():
staking_sources[sid] = (ts, get_wells(sid), get_active_stakes(sid))
cursor.close()
return staking_sources
@ -66,42 +128,6 @@ def get_inventory():
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, staking_event.source_id, staking_event.well_id,
staking_event.inventory_item_id, staking_event.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)
@ -133,45 +159,107 @@ def mint():
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))
cost = world.store[item_id][1]
if cost > world.bank[0][1]:
print(f"Not enough money: Bank {world.bank[0][1]} < Cost {cost}")
return -1
item_id = cursor.lastrowid
conn.commit()
cursor.close()
world.inventory = get_inventory()
return item_id
cursor.execute('BEGIN')
try:
cursor.execute("""
INSERT INTO inventory_item (user_id, store_item_id) VALUES (?, ?)
""", (world.current_user_id, item_id))
cursor.execute("""
UPDATE bank_account SET balance = balance - ? WHERE bank_account.id = ?
""", (cost, world.bank[0][0]))
except sql.Error as error:
conn.rollback()
finally:
item_id = cursor.lastrowid
conn.commit()
cursor.close()
world.inventory = get_inventory()
world.bank = get_bank()
return item_id
def mine(source_id, resource, item_id):
def sell_item(item_id):
cursor = conn.cursor()
cost = world.store[world.inventory[item_id][0]][1]
cursor.execute('BEGIN')
try:
# TODO: We have to cascade delete stakes and claims after this
cursor.execute("DELETE FROM inventory_item WHERE user_id = ? AND id = ?",
(world.current_user_id, item_id))
cursor.execute("""
UPDATE bank_account SET balance = balance + ? WHERE bank_account.id = ?
""", (cost, world.bank[0][0]))
except sql.Error as error:
conn.rollback()
finally:
conn.commit()
cursor.close()
world.inventory = get_inventory()
world.bank = get_bank()
def mine(well_id, item_id):
cursor = conn.cursor()
store_item = world.store[world.inventory[item_id][0]]
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))
INSERT INTO staking_event (well_id, inventory_item_id, stake_amount, duration_in_mins)
VALUES (?, ?, ?, ?)
""", (well_id, item_id, store_item[2], store_item[3]))
conn.commit()
world.staking_sources = get_moons()
world.stakes = get_stakes()
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))
claim_amount = world.stakes[staking_event_id][2]
well_id = world.stakes[staking_event_id][0]
try:
cursor.execute("SELECT supply FROM resource_well WHERE id = ?",
(well_id,))
supply = cursor.fetchone()[0]
claim_amount = claim_amount if supply >= claim_amount else supply
cursor.execute("""
UPDATE resource_well SET supply = supply - ? WHERE resource_well.id = ?
""", (claim_amount, well_id))
cursor.execute("INSERT INTO claim_event (claim_amount, staking_event_id) VALUES (?, ?)",
(claim_amount, staking_event_id))
cursor.execute("""
WITH w_res_id AS (SELECT resource_id FROM resource_well WHERE id = ?)
UPDATE resource_account SET balance = balance + ?
FROM w_res_id
WHERE resource_account.user_id = ?
AND resource_account.resource_id = w_res_id.resource_id
""", (well_id, claim_amount, world.current_user_id))
except sql.Error as error:
print(error)
conn.rollback()
finally:
conn.commit()
world.stakes = get_stakes()
world.staking_sources = get_moons()
world.bank = get_bank()
cursor.close()
def upgrade(item_id):
cursor = conn.cursor()
cursor.execute("INSERT INTO upgrade_event (inventory_item_id) VALUES (?)", (item_id,))
conn.commit()
world.staking_sources = get_moons()
world.inventory = get_inventory()
cursor.close()
def upgrade(a,b,user_data):
()
def destroy(source_id):
cursor = conn.cursor()
@ -181,16 +269,6 @@ def destroy(source_id):
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()
@ -200,26 +278,60 @@ def sell_all():
cursor.close()
world.inventory = get_inventory()
def trade():
cursor = conn.cursor()
cursor.execute("""
UPDATE resource_account SET balance = balance - ? WHERE resource_account.user_id = ?
""", (10, world.current_user_id))
cursor.execute("""
UPDATE bank_account SET balance = balance + ? WHERE bank_account.user_id = ?
""", (1, world.current_user_id))
conn.commit()
cursor.close()
world.bank = get_bank()
def draw_dashboard():
im.text(f"Current User: {world.current_user}")
for _ in range(5):
im.spacing()
im.text(f"Moon Bucks: {world.bank[0][1]}")
for _ in range(10):
im.spacing()
for name,balance in world.bank.items():
for id,(name,balance) in world.bank[1].items():
im.text(f"{name.capitalize()}: {balance}")
for _ in range(10):
im.spacing()
resources = world.bank[1]
can_sell = True
for _,supply in resources.values():
if supply < 10:
can_sell = False
im.text("Sell 10 resources for 1 Moon Bucks")
if can_sell:
if im.button("Sell"):
trade()
else:
im.text("Sell (Not enough funds)")
def draw_store():
for id,(name,resource,price,claim) in world.store.items():
for id,(name,price,claim,duration) 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()}")
im.text(f"{name}: Mine {claim} in {duration} mins")
if owned:
im.text_disabled(f"Buy {price} {resource[0:3]}")
im.text_disabled(f"Buy {price}")
else:
im.push_id(f"Buy{id}")
if im.button(f"Buy {price} {resource[0:3]}"):
if im.button(f"Buy {price}"):
buy_item(id)
im.pop_id()
for _ in range(5):
@ -227,15 +339,15 @@ def draw_store():
def draw_inventory():
for id,(sid,tier) in world.inventory.items():
im.text(f"{id} - {world.store[sid][0]} - Tier {tier+1}")
im.text(f"{world.store[sid][0]} - Tier {tier+1}")
im.push_id(f"Upgrade{id}")
if im.button("Upgrade"):
print("Upgrade")
upgrade(id)
im.pop_id()
im.same_line()
im.push_id(f"Sell{id}")
if im.button("Sell"):
sell(id)
sell_item(id)
im.pop_id()
for _ in range(5):
im.spacing()
@ -259,37 +371,46 @@ def draw_moons():
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}")
im.push_id(f"Destroy{source_id}")
if im.button("Destroy"):
destroy(source_id)
im.pop_id()
im.next_column()
for name,(supply,ts) in wells.items():
for well_id,(name,supply,ts) in wells.items():
im.text(f"{name.capitalize()}: {supply}")
items = [(item[0], world.store[item[1][0]][0]) for item in world.inventory.items()]
for item_id,item_name in items:
im.push_id(f"Mine{id}{name}")
for item_id,(store_id,_) in world.inventory.items():
item_name = world.store[store_id][0]
skip = False
for ss in world.stakes.values():
if ss[1] == item_id and ss[4] == True or supply == 0:
skip = True
if skip == True:
continue
im.push_id(f"Mine{well_id}")
if im.button(item_name):
mine(source_id, name, item_id)
mine(well_id, 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():
for stake_id,(well_id,invId,amount,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"):
btn_txt = f"Claim {amount} {world.wells[well_id][0].capitalize()}"
elapsed = now - start_time
if elapsed > datetime.timedelta(minutes=dur):
im.push_id(f"Claim{stake_id}")
if im.button(btn_txt):
claim(stake_id)
im.pop_id()
im.text(f"Finished {elapsed} ago")
else:
im.text_disabled("Claim")
im.pop_id()
im.text(f"{world.store[world.inventory[invId][0]][0]}: {delta}")
remaining = start_time + datetime.timedelta(minutes=dur) - now
im.text_disabled(btn_txt)
im.text(f"{remaining} left")
im.next_column()
@ -301,8 +422,7 @@ def draw_moons():
def draw_panels():
screen_width, screen_height = glfw.get_video_mode(glfw.get_primary_monitor())[0]
# Main
# TODO: This is probably not the right way to do this
# 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
@ -386,6 +506,8 @@ world.bank = get_bank()
world.store = get_store_items()
world.inventory = get_inventory()
world.staking_sources = get_moons()
world.stakes = get_stakes()
world.wells = get_all_wells()
def imgui_init():
world.moon_img_tex_id = texture_id = load_texture("moon.png")

44
queries.sql Normal file
View File

@ -0,0 +1,44 @@
SELECT staking_event.id,well_id,staking_event.source_id,
inventory_item_id,staking_event.created_at,expiration_at
FROM staking_event
INNER JOIN resource_well ON resource_well.id = well_id
INNER JOIN staking_source on staking_event.source_id = staking_source.id
WHERE staking_event.source_id = ? AND staking_source.user_id = ?;
SELECT name,init_supply
FROM resource_well
INNER JOIN resource ON resource.id = resource_well.resource_id
WHERE source_id = 1;
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 = 1
GROUP BY inventory_item.id;
SELECT inventory_item.id,store_item_id
FROM inventory_item;
SELECT staking_event.id,well_id,staking_event.source_id,
inventory_item_id,staking_event.created_at,expiration_at
FROM staking_event
INNER JOIN staking_source on staking_event.source_id = staking_source.id
WHERE staking_event.source_id = 4 AND staking_source.user_id = 1;
SELECT staking_event.id, staking_event.well_id, staking_event.source_id,
staking_event.inventory_item_id, staking_event.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 = 4 AND claim_event.staking_event_id IS NULL;
UPDATE staking_event SET created_at = '2023-02-21 12:58:02' WHERE id = 5;
SELECT staking_event.id,well_id,inventory_item_id,duration_in_mins,
staking_event.created_at,
CASE WHEN claim_event.staking_event_id IS NULL THEN 1 ELSE 0 END AS is_active
FROM staking_event
INNER JOIN resource_well ON resource_well.id = staking_event.well_id
INNER JOIN staking_source ON staking_source.id = resource_well.source_id
LEFT JOIN claim_event ON claim_event.staking_event_id = staking_event.id
WHERE staking_source.user_id = 1;

View File

@ -34,12 +34,10 @@ CREATE TABLE resource_well(
CREATE TABLE staking_event(
id integer primary key autoincrement,
well_id int not null,
source_id int not null,
inventory_item_id int not null,
duration_in_mins int not null,
stake_amount int not null,
created_at timestamp DEFAULT (current_timestamp),
CONSTRAINT fk_sid FOREIGN KEY(source_id)
REFERENCES staking_source(id)
CONSTRAINT fk_wid FOREIGN KEY(well_id)
REFERENCES resource_well(id)
CONSTRAINT fk_iiid FOREIGN KEY(inventory_item_id)
@ -48,8 +46,8 @@ CREATE TABLE staking_event(
CREATE TABLE claim_event(
id integer primary key autoincrement,
claim_amount int not null,
staking_event_id int not null,
claim_amount int not null,
created_at timestamp DEFAULT (current_timestamp),
CONSTRAINT fk_se_id FOREIGN KEY(staking_event_id)
REFERENCES staking_event(id)
@ -66,14 +64,9 @@ CREATE TABLE upgrade_event(
CREATE TABLE store_item(
id integer primary key autoincrement,
name varchar(128) not null,
currency int not null,
price int not null,
target_resource int not null,
claim_amount int not null,
CONSTRAINT fk_rid FOREIGN KEY(currency)
REFERENCES resource(id)
CONSTRAINT fk_targetid FOREIGN KEY(target_resource)
REFERENCES resource(id)
completion_time_mins int not null
);
CREATE TABLE inventory_item(
@ -88,6 +81,14 @@ CREATE TABLE inventory_item(
);
CREATE TABLE bank_account(
id integer primary key autoincrement,
user_id int not null,
balance int not null default 0 CHECK (balance >= 0),
CONSTRAINT fk_user FOREIGN KEY(user_id)
REFERENCES users(id)
);
CREATE TABLE resource_account(
id integer primary key autoincrement,
user_id int not null,
resource_id int not null,