hashhub/main.py

725 lines
21 KiB
Python

import sys
sys.dont_write_bytecode = True
import mtTkinter as tk
from tkinter import ttk as tkk
from tkinter import messagebox
from tkinter import filedialog
import copy
import hashengine
global LH
if __name__ == "__main__":
import PCPL
import langsys
PCPL.interpreter.ENG = hashengine
LH = langsys.langhandler()
lang = open("clang", 'r')
lang = lang.read()
LH.setlang(lang)
# LH.string("")
else:
class rLH:
def __init__(self):
pass
def string(self, target):
return target
LH = rLH()
import ast
import subprocess
import sys
import time
import shutil
import os
import random
import string
import easygui
import base64
import simpleaudio as sa
import multiprocessing
global gamedata
global cooldown
cooldown = False
gamedata = {}
def prepgamedata():
out = []
tempwin = tk.Tk()
bar = tkk.Progressbar(tempwin)
bar.place(width=200)
ptext = tk.Label(tempwin, text="NONE")
ptext.place()
count = 1
for i in gamedata:
i = gamedata[i]
ptext.config(text=i["name"])
bar.step(count/len(gamedata))
count += 1
tempwin.update()
temp = {"id": i["id"], "name": i["name"]}
tempargs = {}
tosearch = {}
for arg in i["args"]:
if not arg in extypes and not arg in ignoreat and arg != "sdata":
tosearch[arg] = i["args"][arg]
continue
if arg in ignoreat and arg != "sdata": continue
if arg != "sdata":
tempargs[arg] = i["args"][arg]
else:
tempargs[arg] = str(base64.b64encode(i["args"][arg]), "ascii", "ignore")
for argname in tosearch:
arg = tosearch[argname]
temp2 = getattributes(arg)
temp2.update({"ARGID": arg._type})
tempargs[argname] = temp2
temp["args"] = tempargs
out.append(temp)
tempwin.destroy()
return out
class script:
def __init__(self):
self.code = ""
def execute(self, API):
#old code for PCPL code execution, replaced with python code execution
"""
PCPL.resetvar()
PCPL.LIS("HASHBASE")
PCPL.run(self.code)"""
exec(self.code, API)
class previewrend:
def __init__(self, size, cam, container, offset):
self._size = size
self._grid = {}
self._win = container
self._frame = tk.Frame(container)
self._posframe = tk.Frame(self._frame)
self._cam = cam
self._xcam = tk.Label(self._posframe, text="-")
self._ycam = tk.Label(self._posframe, text="-")
self._xcam.grid(row=size[1], column=0)
self._ycam.grid(row=size[1]+1, column=0)
tkeys = list(string.ascii_letters)
self._keys = {}
for i in tkeys:
self._keys[i] = False
self._win.bind("<KeyPress>", self.keypupd)
self._win.bind("<KeyRelease>", self.keydupd)
for y in range(size[1]):
for x in range(size[0]):
temp = tk.Label(self._frame, text=" ", borderwidth=1, relief=tk.GROOVE, width=3)
temp.grid(row=y+offset[1], column=x+offset[0]+1)
self._win.update()
self._grid[f"{x}:{y}"] = temp
self._posframe.grid()
self._frame.grid()
def keypupd(self, event):
event = event.char
if event in self._keys:
self._keys[event] = True
def keydupd(self, event):
event = event.char
if event in self._keys:
self._keys[event] = False
def getkeys(self):
return self._keys
def coltohex(self, target):
colors = []
target = [target.r, target.g, target.b]
for i in target:
colors.append(("0"*(2-len(hex(int(i))[2:])))+hex(i)[2:])
out = ""
for i in colors:
out = out + i
return "#"+out
def update(self):
self._win.update()
def pix(self, x, y, text, bcolor, fcolor):
self._xcam.config(text=LH.string("xcam")+str(self._cam.position.x))
self._ycam.config(text=LH.string("ycam")+str(self._cam.position.y))
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(text=text, bg=self.coltohex(bcolor), fg=self.coltohex(fcolor))
class render:
def __init__(self, size, cam, container, offset):
self._size = size
self._grid = {}
self._win = container
self._frame = tk.Frame(container)
self._posframe = tk.Frame(self._frame)
self._cam = cam
self._xcam = tk.Label(self._posframe, text="-")
self._ycam = tk.Label(self._posframe, text="-")
#self._xcam.grid(row=size[1], column=0)
#self._ycam.grid(row=size[1]+1, column=0)
tkeys = list(string.ascii_letters)
self._keys = {}
for i in tkeys:
self._keys[i] = False
self._win.bind("<KeyPress>", self.keypupd)
self._win.bind("<KeyRelease>", self.keydupd)
for y in range(size[1]):
for x in range(size[0]):
temp = tk.Label(self._frame, text=" ", width=3)
temp.grid(row=y+offset[1], column=x+offset[0]+1)
self._win.update()
self._grid[f"{x}:{y}"] = temp
self._posframe.grid()
self._frame.grid()
def keypupd(self, event):
event = event.char
if event in self._keys:
self._keys[event] = True
def keydupd(self, event):
event = event.char
if event in self._keys:
self._keys[event] = False
def getkeys(self):
return self._keys
def coltohex(self, target):
colors = []
target = [target.r, target.g, target.b]
for i in target:
colors.append(("0"*(2-len(hex(int(i))[2:])))+hex(i)[2:])
out = ""
for i in colors:
out = out + i
return "#"+out
def update(self):
self._win.update()
def pix(self, x, y, text, bcolor, fcolor):
self._xcam.config(text=LH.string("xcam")+str(self._cam.position.x))
self._ycam.config(text=LH.string("ycam")+str(self._cam.position.y))
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(text=text, bg=self.coltohex(bcolor), fg=self.coltohex(fcolor))
class nullrend:
def __init__(self, size, cam):
pass
def getkeys(self):
pass
def update(self):
pass
def pix(self, x, y, text, bcolor, fcolor):
pass
def selectlang(new):
lang = open("clang", 'w')
lang.write(new)
lang.close()
container.quit()
subprocess.Popen([sys.executable, __file__])
def add(objtype):
global objtree
obj = getattr(types, objtype)()
args = {}
for i in dir(obj):
if i.startswith("_"): continue
args[i] = getattr(obj, i)
temp = {"id": objtype, "args": args, "name": LH.string(objtype)}
id = ""
chars = list(string.ascii_letters)
for i in range(255):
id = id + random.choice(chars)
if GUIe == True: objtree.insert("", tk.END, text=LH.string(objtype), image=icons[objtype], iid=id, tags=("objsel"))
gamedata[id] = temp
if objtype in crucial:
preview.addobj(obj)
gamedata[id]["args"]["ID"] = obj.ID
if GUIe == True: preview.render()
return id
def renameobj():
target = objtree.focus()
if target == "": return
new = easygui.enterbox(LH.string("NN"), LH.string("rename"))
if new:
objtree.item(target, text=new)
gamedata[target]["name"] = new
def delobj():
target = objtree.focus()
if target == "": return
atritree.delete(*atritree.get_children())
objtree.delete(target)
temp = gamedata.pop(target)
if temp["id"] in crucial:
preview.removeobjbyid(temp["args"]["ID"])
preview.render()
def rpopup(event):
try:
rmenu.tk_popup(event.x_root, event.y_root)
finally:
rmenu.grab_release()
def getattributes(target):
out = {}
for i in dir(target):
if i.startswith("_"): continue
out[i] = getattr(target, i)
return out
def updatribute(event):
global currentat
target = objtree.focus()
currentat = target
atritree.delete(*atritree.get_children())
for i in gamedata[target]["args"]:
if i in ignoreat: continue
if i in valtypes:
val = gamedata[target]["args"][i]
atritree.insert("", tk.END, text=i, values=(val))
else:
root = atritree.insert("", tk.END, text=i)
temp = getattributes(gamedata[target]["args"][i])
for f in temp:
atritree.insert(root, tk.END, text=f, values=(temp[f]))
def halatribute(event):
target = atritree.focus()
name = atritree.item(target, "text")
parent = atritree.parent(target)
if name in valtypes:
if parent == "":
new = valtypes[name](gamedata[currentat]["args"][name])
gamedata[currentat]["args"][name] = new
if "ID" in gamedata[currentat]["args"]:
temp = preview.getobjbyid(gamedata[currentat]["args"]["ID"])
setattr(temp, name, new)
atritree.item(target, values=(new))
else:
parent = atritree.item(parent, "text")
new = valtypes[name](getattr(gamedata[currentat]["args"][parent], name))
setattr(gamedata[currentat]["args"][parent], name, new)
atritree.item(target, values=(new))
preview.render()
def updatepreviewcam(char):
global cooldown
if cooldown == True: return
cooldown = True
char = char.char
if char == "w": preview.camera.position += hashengine.vector2(y=1)
if char == "a": preview.camera.position += hashengine.vector2(x=1)
if char == "s": preview.camera.position -= hashengine.vector2(y=1)
if char == "d": preview.camera.position -= hashengine.vector2(x=1)
preview.render()
time.sleep(0)
cooldown = False
def save():
target = filedialog.asksaveasfile()
target.write(str(prepgamedata()))
target.close()
messagebox.showinfo(LH.string("suc"), LH.string("save-suc"))
def clear():
global gamedata
objtree.delete(*objtree.get_children())
atritree.delete(*atritree.get_children())
gamedata = {}
preview._objects = {}
preview.camera.position = hashengine.vector2()
preview.render()
def importsound(target):
oid = add("rawsound")
gamedata[oid]["name"] = target["name"]
gamedata[oid]["args"]["sdata"] = base64.b64decode(target["args"]["sdata"])
gamedata[oid]["args"]["spath"] = target["args"]["spath"]
if GUIe == True: objtree.item(oid, text=target["name"])
def importobj(target):
if target["id"] == "sound" or target["id"] == "rawsound":
importsound(target)
return
oid = add(target["id"])
id = gamedata[oid]
id["name"] = target["name"]
if GUIe == True: objtree.item(oid, text=target["name"])
#create arguments
outargs = {}
for argname in target["args"]:
arg = target["args"][argname]
if isinstance(arg, dict):
ID = arg.pop("ARGID")
obj = attypes[ID]()
for i in arg:
setattr(obj, i, arg[i])
arg = obj
outargs[argname] = arg
#apply arguments to obj
if target["id"] in crucial:
for i in outargs:
setattr(preview.getobjbyid(gamedata[oid]["args"]["ID"]), i, outargs[i])
id["args"].update(outargs)
def load():
file = filedialog.askopenfile()
tempwin = tk.Tk()
ptext = tk.Label(tempwin, text="NONE")
ptext.place(y=30)
stat = tk.Label(tempwin, text="NONE")
stat.place(y=50)
target = file.read()
file.close()
target = ast.literal_eval(target)
clear()
count = 1
bar = tkk.Progressbar(tempwin, maximum=len(target))
bar.place(width=200)
for i in target:
ptext.config(text="Current: "+i["name"])
bar.step()
stat.config(text=f"Object {count}/{len(target)}")
tempwin.update()
importobj(i)
count += 1
tempwin.destroy()
preview.render()
def log(text, end="\n", flush=False):
global logfile
if not os.path.exists("logs"):
os.mkdir("logs")
file = open("logs/"+logfile+".txt", 'a')
file.write(str(text)+end)
file.close()
def NULL():
pass
class gsound:
def __init__(self, data, game):
self._playing = False
self._data = data
game.currentsounds.append(self)
def play(self):
if self._playing == True: return
self._sound = sa.play_buffer(self._data, 2, 2, 44100)
self._playing = True
def stop(self):
if self._playing == False: return
self._sound.stop()
self._playing = False
def wait(self):
if self._playing == False: return
self._sound.wait_done()
def testing():
global testproc
testproc = multiprocessing.Process(target=execgame, args=(prepgamedata(),))
testproc.start()
def run():
print("preparing log file...")
global logfile
global maingame
global window
temp = time.gmtime(time.time())
logfile = ""
for i in temp:
logfile = logfile + "S" + str(i)
print("done")
log("Log file start!")
log("Preparing API...")
API = {"print": log, "HASHBASE": hashengine}
log("Done!")
window = tk.Tk()
window.protocol("WM_DELETE_WINDOW", NULL)
maingame = hashengine.game(renderer=lambda size, cam: render(size, cam, window, [0, 0]), sounddir="/")
API["HASHGAME"] = maingame
API["SOUND"] = lambda data: gsound(data, maingame)
log("main game initalised!")
log("copying sounds...")
for i in gamedata:
i = gamedata[i]
if i["id"] != "sound" and i["id"] != "rawsound": continue
maingame.sounds[i["args"]["spath"]] = i["args"]["sdata"]
print(i["args"]["spath"])
objects = copy.deepcopy(preview._objects)
maingame._objects = objects
scripts = []
for i in gamedata:
i = gamedata[i]
if i["id"] != "script": continue
i = i["args"]["code"]
obj = script()
obj.code = i
scripts.append(obj)
log("objects transferred!")
gamescript = """
global HASHGAME
import time
while True:
for i in HASHGAME._objects:
i = HASHGAME._objects[i]
HASHGAME.calcphysobj(i)
HASHGAME.render()
"""
gameloopsc = script()
gameloopsc.code = gamescript
maingame.startscript(lambda: gameloopsc.execute(API))
log("game test started!!!")
log("---------------------")
for i in scripts:
maingame.startscript(lambda: i.execute(API))
window.mainloop()
def muladd(target):
for i in range(10):
add(target)
def stoptest():
global testproc
testproc.terminate()
def build():
print("asking user for output directory...")
target = filedialog.askdirectory()
os.mkdir(target+"/out")
target = target+"/out"
print("building started")
print("generating HEGF file...")
hegf = str(prepgamedata())
file = open(target+"/game.HEGF", 'w')
file.write(hegf)
file.close()
print("done.")
print("copying files...")
tocopy = ["mtTkinter.py", "hashengine.py"]
for i in tocopy:
print(f"copying {i}...")
shutil.copyfile(i, target+"/"+i)
shutil.copyfile(__file__, target+"/"+"player.py")
file = open(target+"/main.py", 'w')
file.write("""
import player
import ast
file = open("game.HEGF", 'r')
file = file.read()
file = ast.literal_eval(file)
player.execgame(file)
""")
print("done.")
print("building finished!")
def GUIinit():
global container
global objtree
global rmenu
global atritree
global currentat
global preview
global GUIe
GUIe = True
container = tk.Tk()
container.bind("<KeyPress>", updatepreviewcam)
global icons
icons = {}
for i in os.listdir("icons"):
icons[i.split(".")[0]] = tk.PhotoImage(file=f"icons/{i}")
#preview init
preview = hashengine.game(renderer=lambda size, cam: previewrend(size, cam, container=container, offset=[0, 0]), sounddir="/")
#tree init
objtree = tkk.Treeview(container, selectmode="browse", columns=("-"))
objtree.heading("#0", text=LH.string("objs"))
objtree.tag_bind("objsel", "<<TreeviewSelect>>", updatribute)
objtree.grid(row=1, column=0)
#attribute tree init
currentat = "temp"
atritree = tkk.Treeview(container, columns=("#1"), selectmode="browse")
atritree.heading("#0", text=LH.string("attribute"))
atritree.heading("#1", text=LH.string("attribute-val"))
atritree.bind("<Double-1>", halatribute)
atritree.grid(row=2, column=0)
#right click menu
rmenu = tk.Menu(container, tearoff=0)
rmenu.add_command(label=LH.string("rename"), command=renameobj)
rmenu.add_command(label=LH.string("delete"), command=delobj)
objtree.bind("<Button-3>", rpopup)
#menu init
menu = tk.Menu(container)
container.config(menu=menu)
filemenu = tk.Menu(menu)
menu.add_cascade(label=LH.string("file"), menu=filemenu)
filemenu.add_command(label=LH.string("new"), command=clear)
filemenu.add_command(label=LH.string("open"), command=load)
filemenu.add_command(label=LH.string("save"), command=save)
filemenu.add_separator()
filemenu.add_command(label=LH.string("exit"), command=container.quit)
addmenu = tk.Menu(menu)
menu.add_cascade(label=LH.string("add"), menu=addmenu)
addmenu.add_command(label=LH.string("obj"), command=lambda: add("obj"))
addmenu.add_command(label=LH.string("script"), command=lambda: add("script"))
addmenu.add_command(label=LH.string("sound"), command=lambda: add("sound"))
#addmenu.add_command(label=LH.string("obj"), command=lambda: muladd("obj"))
testmenu = tk.Menu(menu)
menu.add_cascade(label=LH.string("testing"), menu=testmenu)
testmenu.add_command(label=LH.string("test"), command=testing, image=icons["test"], compound="left")
testmenu.add_command(label=LH.string("stest"), command=stoptest, image=icons["stop-test"], compound="left")
buildmenu = tk.Menu(menu)
menu.add_cascade(label=LH.string("building"), menu=buildmenu)
buildmenu.add_command(label=LH.string("build"), command=build, image=icons["build"], compound="left")
langmenu = tk.Menu(menu)
menu.add_cascade(label=LH.string("langs"), menu=langmenu)
for i in LH.getlangs():
langmenu.add_command(label=i, command=lambda i=i: selectlang(i))
container.mainloop()
# attribute changers
def ats(mode, old):
#mode 0 = string
#mode 1 = single character
out = easygui.enterbox(LH.string("newval"), LH.string("newval"))
if out:
if mode == 1 and len(out) != 1:
messagebox.showerror(LH.string("error"), LH.string("SCE"))
return "N"
return out
else:
return old
def anum(old):
out = easygui.enterbox(LH.string("newval"), LH.string("newval"))
if out:
if "." in out:
try:
out = float(out)
return out
except ValueError:
return old
else:
return int(out)
else:
return old
def abool(old):
out = easygui.boolbox(LH.string("newval"), LH.string("newval"), (LH.string("true"), LH.string("false")))
if out:
return out
else:
return old
def acode(old):
out = easygui.textbox(LH.string("newval"), LH.string("newval"), old)
if out:
return out
else:
return old
def apath(old, ext):
new = filedialog.askopenfilename(defaultextension=ext, filetypes=(ext))
if new:
return new
else:
return old
def aNULL(old):
return old
def execgame(gametree):
global GUIe
global preview
preview = hashengine.game(renderer=nullrend, sounddir="/")
GUIe = False
for i in gametree:
importobj(i)
run()
class rsound:
def __init__(self):
self.spath = ""
self.sdata = b""
class sound():
def __init__(self, new):
self.spath = os.path.basename(new).split(".")[0]
self.sdata = hashengine.loadsound(new)
global types
global ignoreat
global valtypes
global extypes
global attypes
global crucial
crucial = ["obj"]
types = hashengine.enum({"obj": hashengine.obj, "script": script, "rawsound": rsound, "sound": lambda: sound(apath("", [("Wave files", ".wave .wav")]))})
ignoreat = ["ID", "execute", "sdata"]
"""self.position = vector2()
self.char = " "
self.ID = 0
self.gravity = 0
self.acceleration = vector2()
self.velocity = vector2()
self.friction = 0
self.collide = True
self.touch = True
self.anchored = False
self.bcolor = color3(255, 255, 255)
self.fcolor = color3()"""
valtypes = {
"char": lambda old: ats(1, old),
"gravity": anum,
"x": anum,
"y": anum,
"z": anum,
"r": anum,
"g": anum,
"b": anum,
"friction": anum,
"collide": abool,
"touch": abool,
"anchored": abool,
"code": acode,
"spath": aNULL,
}
#lambda old: apath(old, [("Wave files", ".wave .wav")])
extypes = list(valtypes.keys())
attypes = {
"vector2": hashengine.vector2,
"color3": hashengine.color3,
}
if __name__ == "__main__":
GUIinit()