added new building system, added sound, added keyboard

main
Justus Jan Nico Wolff 2024-05-15 17:47:45 +02:00
parent ae80270d71
commit f540626b4b
43 changed files with 4641 additions and 52 deletions

2
clang
View File

@ -1 +1 @@
de_DE
en_EN

View File

@ -3,12 +3,22 @@ import string
import random
import threading
import time
import wave
import os
class stdrend:
def __init__(self, size, cam):
self._size = size
self._grid = {}
self._win = tk.Tk()
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(text=" ")
@ -16,6 +26,19 @@ class stdrend:
self._win.update()
self._grid[f"{x}:{y}"] = temp
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]
@ -122,6 +145,11 @@ class enum:
def getposssel(self):
return list(self._sel.keys())
def loadsound(path):
with wave.open(path) as fd:
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
class event:
@ -168,14 +196,25 @@ class camera(obj):
self.position = self.subject.position
class game:
def __init__(self, size=[10, 10], renderer=stdrend):
def __init__(self, size=[10, 10], renderer=stdrend, sounddir=""):
if renderer == None: raise TypeError("Renderer class needed!")
self.sounds = {}
self.currentsounds = []
for i in os.listdir(sounddir):
if not "." in i: continue
if i.split(".")[1] != "wav": continue
self.sounds[i.split(".")[0]] = loadsound(sounddir+"/"+i)
self._size = size
self._objects = {}
self.camera = camera()
self._renderer = renderer(size, self.camera)
self._threads = []
def isdown(self, key):
temp = self._renderer.getkeys()
if key in temp:
return temp[key]
def collidingpos(self, pos, ignore):
out = []
for i in self._objects:
@ -243,13 +282,19 @@ class game:
return self._objects[id]
def render(self):
tochange = []
for x in range(self._size[0]):
for y in range(self._size[1]):
self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
tochange.append((x, y))
#self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
for i in list(self._objects.values()):
pos = i.position + self.camera.position
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue
self._renderer.pix(round(pos.x), round(pos.y), i.char, i.bcolor, i.fcolor)
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue#
pos = vector2(round(pos.x), round(pos.y))
self._renderer.pix(pos.x, pos.y, i.char, i.bcolor, i.fcolor)
if (pos.x, pos.y) in tochange: tochange.remove((pos.x, pos.y))
for i in tochange:
self._renderer.pix(i[0], i[1], " ", color3(255, 255, 255), color3(255, 255, 255))
self._renderer.update()
def startscript(self, target):
@ -261,8 +306,12 @@ class game:
for i in self._threads:
i.join(.0)
def stopsounds(self):
for i in self.currentsounds:
i.stop()
if __name__ == "__main__":
testgame = game()
testgame = game(sounddir="testsound")
object = obj()
object.char = "#"
object.anchored = False

BIN
icons/rawsound.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

BIN
icons/sound.png 100644

Binary file not shown.

After

Width:  |  Height:  |  Size: 213 B

View File

@ -28,4 +28,5 @@
"stest": "Test stoppen",
"building": "Bauen",
"build": "Bauen",
"sound": "Sound",
}

View File

@ -28,4 +28,5 @@
"stest": "Stop execution",
"building": "Building",
"build": "Build",
"sound": "Sound",
}

View File

@ -0,0 +1,8 @@
Log file start!
Preparing API...
Done!
main game initalised!
copying sounds...
objects transferred!
game test started!!!
---------------------

View File

@ -0,0 +1,8 @@
Log file start!
Preparing API...
Done!
main game initalised!
copying sounds...
objects transferred!
game test started!!!
---------------------

256
main.py
View File

@ -6,31 +6,41 @@ from tkinter import ttk as tkk
from tkinter import messagebox
from tkinter import filedialog
import copy
import PCPL
import langsys
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 hashengine
import shutil
import os
import random
import string
import easygui
import base64
import simpleaudio as sa
import multiprocessing
global LH
global gamedata
global cooldown
cooldown = False
gamedata = {}
LH = langsys.langhandler()
lang = open("clang", 'r')
lang = lang.read()
LH.setlang(lang)
# LH.string("")
PCPL.interpreter.ENG = hashengine
def prepgamedata():
out = []
@ -50,11 +60,14 @@ def prepgamedata():
tempargs = {}
tosearch = {}
for arg in i["args"]:
if not arg in extypes and not arg in ignoreat:
if not arg in extypes and not arg in ignoreat and arg != "sdata":
tosearch[arg] = i["args"][arg]
continue
if arg in ignoreat: continue
tempargs[arg] = i["args"][arg]
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)
@ -89,6 +102,14 @@ class previewrend:
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)
@ -98,6 +119,19 @@ class previewrend:
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]
@ -117,6 +151,80 @@ class previewrend:
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)
@ -136,12 +244,12 @@ def add(objtype):
chars = list(string.ascii_letters)
for i in range(255):
id = id + random.choice(chars)
objtree.insert("", tk.END, text=LH.string(objtype), image=icons[objtype], iid=id, tags=("objsel"))
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
preview.render()
if GUIe == True: preview.render()
return id
def renameobj():
@ -239,11 +347,21 @@ def clear():
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"]
objtree.item(oid, text=target["name"])
if GUIe == True: objtree.item(oid, text=target["name"])
#create arguments
outargs = {}
for argname in target["args"]:
@ -287,14 +405,41 @@ def load():
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(text+end)
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
@ -310,9 +455,16 @@ def testing():
log("Done!")
window = tk.Tk()
window.protocol("WM_DELETE_WINDOW", NULL)
maingame = hashengine.game(renderer=lambda size, cam: previewrend(size, cam, window, [0, 0]))
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 = []
@ -323,8 +475,6 @@ def testing():
obj = script()
obj.code = i
scripts.append(obj)
for i in scripts:
maingame.startscript(lambda: i.execute(API))
log("objects transferred!")
gamescript = """
global HASHGAME
@ -340,18 +490,23 @@ while True:
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():
maingame.stopscripts()
window.destroy()
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())
@ -360,10 +515,20 @@ def build():
file.close()
print("done.")
print("copying files...")
tocopy = ["mtTkinter.py", "player.py", "hashengine.py"]
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!")
@ -374,6 +539,8 @@ def GUIinit():
global atritree
global currentat
global preview
global GUIe
GUIe = True
container = tk.Tk()
container.bind("<KeyPress>", updatepreviewcam)
@ -384,7 +551,7 @@ def GUIinit():
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]))
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=("-"))
@ -422,6 +589,7 @@ def GUIinit():
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)
@ -481,6 +649,35 @@ def acode(old):
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
@ -488,8 +685,8 @@ global extypes
global attypes
global crucial
crucial = ["obj"]
types = hashengine.enum({"obj": hashengine.obj, "script": script})
ignoreat = ["ID", "execute"]
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
@ -516,10 +713,13 @@ valtypes = {
"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,
}
GUIinit()
if __name__ == "__main__":
GUIinit()

View File

@ -0,0 +1,336 @@
import tkinter as tk
import string
import random
import threading
import time
import wave
import os
class stdrend:
def __init__(self, size, cam):
self._size = size
self._grid = {}
self._win = tk.Tk()
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(text=" ")
temp.grid(row=y, column=x)
self._win.update()
self._grid[f"{x}:{y}"] = temp
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(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):
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(text=text, bg=self.coltohex(bcolor), fg=self.coltohex(fcolor))
class color3:
def __init__(self, r=0, g=0, b=0):
self.r = r
self.g = g
self.b = b
self._type = "color3"
def __add__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __sub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __mul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __iadd__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __isub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __imul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
class vector2:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self._type = "vector2"
def _magnitude(self):
return abs(self.x+self.y)
def __add__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __sub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __mul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
def __iadd__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __isub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __imul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
class NULL:
def __init__(self):
return None
class enum:
def __init__(self, sel):
self._sel = dict(sel)
for i in self._sel:
setattr(self, i, self._sel[i])
def getposssel(self):
return list(self._sel.keys())
def loadsound(path):
with wave.open(path) as fd:
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
class event:
def __init__(self):
self._attached = []
def execute(self):
threads = []
for i in self._attached:
temp = threading.Thread(target=i)
temp.start()
threads.append(temp)
return threads
def attach(self, target):
self._attached.append(target)
class obj:
def __init__(self):
self.position = vector2()
self.char = " "
self.ID = 0
self.gravity = 0
self.acceleration = vector2()
self.velocity = vector2()
self.friction = 0
self.collide = True
self.anchored = False
self.bcolor = color3(255, 255, 255)
self.fcolor = color3()
self._touching = event()
class camera(obj):
def __init__(self):
super().__init__()
self.mode = cammode.editable
self.subject = None
self.collide = False
self.touch = False
self.char = " "
def update(self):
if self.mode == cammode.follow and self.subject:
self.position = self.subject.position
class game:
def __init__(self, size=[10, 10], renderer=stdrend, sounddir=""):
if renderer == None: raise TypeError("Renderer class needed!")
self.sounds = {}
self.currentsounds = []
for i in os.listdir(sounddir):
if not "." in i: continue
if i.split(".")[1] != "wav": continue
self.sounds[i.split(".")[0]] = loadsound(sounddir+"/"+i)
self._size = size
self._objects = {}
self.camera = camera()
self._renderer = renderer(size, self.camera)
self._threads = []
def isdown(self, key):
temp = self._renderer.getkeys()
if key in temp:
return temp[key]
def collidingpos(self, pos, ignore):
out = []
for i in self._objects:
i = self._objects[i]
if i in ignore: continue
if (i.position-pos)._magnitude() < 1 and i.collide == True:
out.append(i)
return out
def colliding(self, target):
out = []
if target.collide == False: return []
out = self.collidingpos(target.position, [target,])
return out
def handlecollision(self, target: obj, target2: obj):
if target2.anchored == True:
target.velocity = vector2()
else:
half = vector2(target.velocity.x/2, target.velocity.y/2)
target.velocity = vector2(half.x, half.y)
target2.velocity = half
def calcphysobj(self, target: obj):
if target.anchored == True: return
if target.collide == True:
colliding = self.collidingpos(target.position+target.velocity, [target,])
for i in colliding:
target._touching.execute()
i._touching.execute()
self.handlecollision(target, i)
target.position += target.velocity
target.velocity += vector2(0, target.gravity)
target.velocity += target.acceleration
temp = 2
if target.friction != 0:
temp = 2 / target.friction
x = target.velocity.x
y = target.velocity.y
if x != 0:
x = x/temp
if y != 0:
y = y/temp
target.velocity = vector2(x, y)
def addobj(self, obj):
id = ""
for i in range(256):
id = id + random.choice(list(string.ascii_letters))
obj.ID = id
self._objects[id] = obj
def removeobj(self, obj):
self._objects.pop(obj.ID)
obj.ID = NULL()
def removeobjbyid(self, id):
self._objects.pop(id).ID = NULL()
def between(self, min, max, target):
if min < target < max: return True
return False
def getobjbyid(self, id):
return self._objects[id]
def render(self):
tochange = []
for x in range(self._size[0]):
for y in range(self._size[1]):
tochange.append((x, y))
#self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
for i in list(self._objects.values()):
pos = i.position + self.camera.position
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue#
pos = vector2(round(pos.x), round(pos.y))
self._renderer.pix(pos.x, pos.y, i.char, i.bcolor, i.fcolor)
if (pos.x, pos.y) in tochange: tochange.remove((pos.x, pos.y))
for i in tochange:
self._renderer.pix(i[0], i[1], " ", color3(255, 255, 255), color3(255, 255, 255))
self._renderer.update()
def startscript(self, target):
temp = threading.Thread(target=target)
temp.start()
self._threads.append(temp)
def stopscripts(self):
for i in self._threads:
i.join(.0)
def stopsounds(self):
for i in self.currentsounds:
i.stop()
if __name__ == "__main__":
testgame = game(sounddir="testsound")
object = obj()
object.char = "#"
object.anchored = False
object.position = vector2(5, 5)
object.gravity = 1
floor = obj()
floor.char = "#"
floor.anchored = True
floor.position = vector2(5, 9)
floor.gravity = 0
floor.bcolor = color3(255, 255, 255)
testgame.addobj(object)
testgame.addobj(floor)
testgame.render()
print(object.ID)
while True:
testgame.calcphysobj(object)
testgame.calcphysobj(floor)
testgame.render()
time.sleep(0)

View File

@ -0,0 +1,8 @@
Log file start!
Preparing API...
Done!
main game initalised!
copying sounds...
objects transferred!
game test started!!!
---------------------

View File

@ -0,0 +1,8 @@
Log file start!
Preparing API...
Done!
main game initalised!
copying sounds...
objects transferred!
game test started!!!
---------------------

View File

@ -0,0 +1,7 @@
import player
import ast
file = open("game.HEGF", 'r')
file = file.read()
file = ast.literal_eval(file)
player.execgame(file)

View File

@ -0,0 +1,664 @@
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 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: previewrend(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()

View File

@ -0,0 +1,336 @@
import tkinter as tk
import string
import random
import threading
import time
import wave
import os
class stdrend:
def __init__(self, size, cam):
self._size = size
self._grid = {}
self._win = tk.Tk()
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(text=" ")
temp.grid(row=y, column=x)
self._win.update()
self._grid[f"{x}:{y}"] = temp
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(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):
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(text=text, bg=self.coltohex(bcolor), fg=self.coltohex(fcolor))
class color3:
def __init__(self, r=0, g=0, b=0):
self.r = r
self.g = g
self.b = b
self._type = "color3"
def __add__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __sub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __mul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __iadd__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __isub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __imul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
class vector2:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self._type = "vector2"
def _magnitude(self):
return abs(self.x+self.y)
def __add__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __sub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __mul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
def __iadd__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __isub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __imul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
class NULL:
def __init__(self):
return None
class enum:
def __init__(self, sel):
self._sel = dict(sel)
for i in self._sel:
setattr(self, i, self._sel[i])
def getposssel(self):
return list(self._sel.keys())
def loadsound(path):
with wave.open(path) as fd:
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
class event:
def __init__(self):
self._attached = []
def execute(self):
threads = []
for i in self._attached:
temp = threading.Thread(target=i)
temp.start()
threads.append(temp)
return threads
def attach(self, target):
self._attached.append(target)
class obj:
def __init__(self):
self.position = vector2()
self.char = " "
self.ID = 0
self.gravity = 0
self.acceleration = vector2()
self.velocity = vector2()
self.friction = 0
self.collide = True
self.anchored = False
self.bcolor = color3(255, 255, 255)
self.fcolor = color3()
self._touching = event()
class camera(obj):
def __init__(self):
super().__init__()
self.mode = cammode.editable
self.subject = None
self.collide = False
self.touch = False
self.char = " "
def update(self):
if self.mode == cammode.follow and self.subject:
self.position = self.subject.position
class game:
def __init__(self, size=[10, 10], renderer=stdrend, sounddir=""):
if renderer == None: raise TypeError("Renderer class needed!")
self.sounds = {}
self.currentsounds = []
for i in os.listdir(sounddir):
if not "." in i: continue
if i.split(".")[1] != "wav": continue
self.sounds[i.split(".")[0]] = loadsound(sounddir+"/"+i)
self._size = size
self._objects = {}
self.camera = camera()
self._renderer = renderer(size, self.camera)
self._threads = []
def isdown(self, key):
temp = self._renderer.getkeys()
if key in temp:
return temp[key]
def collidingpos(self, pos, ignore):
out = []
for i in self._objects:
i = self._objects[i]
if i in ignore: continue
if (i.position-pos)._magnitude() < 1 and i.collide == True:
out.append(i)
return out
def colliding(self, target):
out = []
if target.collide == False: return []
out = self.collidingpos(target.position, [target,])
return out
def handlecollision(self, target: obj, target2: obj):
if target2.anchored == True:
target.velocity = vector2()
else:
half = vector2(target.velocity.x/2, target.velocity.y/2)
target.velocity = vector2(half.x, half.y)
target2.velocity = half
def calcphysobj(self, target: obj):
if target.anchored == True: return
if target.collide == True:
colliding = self.collidingpos(target.position+target.velocity, [target,])
for i in colliding:
target._touching.execute()
i._touching.execute()
self.handlecollision(target, i)
target.position += target.velocity
target.velocity += vector2(0, target.gravity)
target.velocity += target.acceleration
temp = 2
if target.friction != 0:
temp = 2 / target.friction
x = target.velocity.x
y = target.velocity.y
if x != 0:
x = x/temp
if y != 0:
y = y/temp
target.velocity = vector2(x, y)
def addobj(self, obj):
id = ""
for i in range(256):
id = id + random.choice(list(string.ascii_letters))
obj.ID = id
self._objects[id] = obj
def removeobj(self, obj):
self._objects.pop(obj.ID)
obj.ID = NULL()
def removeobjbyid(self, id):
self._objects.pop(id).ID = NULL()
def between(self, min, max, target):
if min < target < max: return True
return False
def getobjbyid(self, id):
return self._objects[id]
def render(self):
tochange = []
for x in range(self._size[0]):
for y in range(self._size[1]):
tochange.append((x, y))
#self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
for i in list(self._objects.values()):
pos = i.position + self.camera.position
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue#
pos = vector2(round(pos.x), round(pos.y))
self._renderer.pix(pos.x, pos.y, i.char, i.bcolor, i.fcolor)
if (pos.x, pos.y) in tochange: tochange.remove((pos.x, pos.y))
for i in tochange:
self._renderer.pix(i[0], i[1], " ", color3(255, 255, 255), color3(255, 255, 255))
self._renderer.update()
def startscript(self, target):
temp = threading.Thread(target=target)
temp.start()
self._threads.append(temp)
def stopscripts(self):
for i in self._threads:
i.join(.0)
def stopsounds(self):
for i in self.currentsounds:
i.stop()
if __name__ == "__main__":
testgame = game(sounddir="testsound")
object = obj()
object.char = "#"
object.anchored = False
object.position = vector2(5, 5)
object.gravity = 1
floor = obj()
floor.char = "#"
floor.anchored = True
floor.position = vector2(5, 9)
floor.gravity = 0
floor.bcolor = color3(255, 255, 255)
testgame.addobj(object)
testgame.addobj(floor)
testgame.render()
print(object.ID)
while True:
testgame.calcphysobj(object)
testgame.calcphysobj(floor)
testgame.render()
time.sleep(0)

View File

@ -0,0 +1,8 @@
Log file start!
Preparing API...
Done!
main game initalised!
copying sounds...
objects transferred!
game test started!!!
---------------------

View File

@ -0,0 +1,7 @@
import player
import ast
file = open("game.HEGF", 'r')
file = file.read()
file = ast.literal_eval(file)
player.execgame(file)

View File

@ -0,0 +1,725 @@
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()

View File

@ -0,0 +1 @@
[{'id': 'obj', 'name': 'testobj', 'args': {'anchored': False, 'char': '#', 'collide': True, 'friction': 0, 'gravity': 0, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 0, 'g': 255, 'r': 255, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 255, 'ARGID': 'color3'}, 'position': {'x': 5, 'y': 5, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}, {'id': 'script', 'name': 'skript pos test', 'args': {'code': 'import random\nimport time\ntime.sleep(3)\nobjects = list(HASHGAME._objects.values())\nobject = objects[0]\nstartpos = object.position\nwhile True:\n\tobject.position = startpos + HASHBASE.vector2(random.randint(-3, 3), random.randint(-3, 3))\n\ttime.sleep(.01)'}}]

View File

@ -0,0 +1,175 @@
import sys
import threading
if sys.version_info[0] == 2:
# Python 2
from Tkinter import *
import Queue as queue
else:
# Python 3
from tkinter import *
import queue
class _Tk(object):
"""Wrapper for underlying attribute tk of class Tk"""
def __init__(self, tk, mt_debug=0, mt_check_period=10):
"""
:param tk: Tkinter.Tk.tk Tk interpreter object
:param mt_debug: Determines amount of debug output.
0 = No debug output (default)
1 = Minimal debug output
...
9 = Full debug output
:param mt_check_period: Amount of time in milliseconds (default
10) between checks for out-of-thread events when things are
otherwise idle. Decreasing this value can improve GUI
responsiveness, but at the expense of consuming more CPU
cycles.
# TODO: Replace custom logging functionality with standard
# TODO: logging.Logger for easier access and standardization
"""
self._tk = tk
# Create the incoming event queue
self._event_queue = queue.Queue(1)
# Identify the thread from which this object is being created
# so we can tell later whether an event is coming from another
# thread.
self._creation_thread = threading.current_thread()
# Create attributes for kwargs
self._debug = mt_debug
self._check_period = mt_check_period
# Destroying flag to be set by the .destroy() hook
self._destroying = False
def __getattr__(self, name):
"""
Diverts attribute accesses to a wrapper around the underlying tk
object.
"""
return _TkAttr(self, getattr(self._tk, name))
class _TkAttr(object):
"""Thread-safe callable attribute wrapper"""
def __init__(self, tk, attr):
self._tk = tk
self._attr = attr
def __call__(self, *args, **kwargs):
"""
Thread-safe method invocation. Diverts out-of-thread calls
through the event queue. Forwards all other method calls to the
underlying tk object directly.
"""
# Check if we're in the creation thread
if threading.current_thread() == self._tk._creation_thread:
# We're in the creation thread; just call the event directly
if self._tk._debug >= 8 or \
self._tk._debug >= 3 and self._attr.__name__ == 'call' and \
len(args) >= 1 and args[0] == 'after':
print('Calling event directly:', self._attr.__name__, args, kwargs)
return self._attr(*args, **kwargs)
else:
if not self._tk._destroying:
# We're in a different thread than the creation thread;
# enqueue the event, and then wait for the response.
response_queue = queue.Queue(1)
if self._tk._debug >= 1:
print('Marshalling event:', self._attr.__name__, args, kwargs)
self._tk._event_queue.put((self._attr, args, kwargs, response_queue), True, 1)
is_exception, response = response_queue.get(True, None)
# Handle the response, whether it's a normal return value or
# an exception.
if is_exception:
ex_type, ex_value, ex_tb = response
raise ex_type(ex_value, ex_tb)
return response
def _Tk__init__(self, *args, **kwargs):
"""
Hook for Tkinter.Tk.__init__ method
:param self: Tk instance
:param args, kwargs: Arguments for Tk initializer
"""
# We support some new keyword arguments that the original __init__ method
# doesn't expect, so separate those out before doing anything else.
new_kwnames = ('mt_check_period', 'mt_debug')
new_kwargs = {
kw_name: kwargs.pop(kw_name) for kw_name in new_kwnames
if kwargs.get(kw_name, None) is not None
}
# Call the original __init__ method, creating the internal tk member.
self.__original__init__mtTkinter(*args, **kwargs)
# Replace the internal tk member with a wrapper that handles calls from
# other threads.
self.tk = _Tk(self.tk, **new_kwargs)
# Set up the first event to check for out-of-thread events.
self.after_idle(_check_events, self)
# Define a hook for class Tk's destroy method.
def _Tk_destroy(self):
self.tk._destroying = True
self.__original__destroy()
def _check_events(tk):
"""Checks events in the queue on a given Tk instance"""
used = False
try:
# Process all enqueued events, then exit.
while True:
try:
# Get an event request from the queue.
method, args, kwargs, response_queue = tk.tk._event_queue.get_nowait()
except queue.Empty:
# No more events to process.
break
else:
# Call the event with the given arguments, and then return
# the result back to the caller via the response queue.
used = True
if tk.tk._debug >= 2:
print('Calling event from main thread:', method.__name__, args, kwargs)
try:
response_queue.put((False, method(*args, **kwargs)))
except SystemExit:
raise # Raises original SystemExit
except Exception:
# Calling the event caused an exception; return the
# exception back to the caller so that it can be raised
# in the caller's thread.
from sys import exc_info # Python 2 requirement
ex_type, ex_value, ex_tb = exc_info()
response_queue.put((True, (ex_type, ex_value, ex_tb)))
finally:
# Schedule to check again. If we just processed an event, check
# immediately; if we didn't, check later.
if used:
tk.after_idle(_check_events, tk)
else:
tk.after(tk.tk._check_period, _check_events, tk)
"""Perform in-memory modification of Tkinter module"""
# Replace Tk's original __init__ with the hook.
Tk.__original__init__mtTkinter = Tk.__init__
Tk.__init__ = _Tk__init__
# Replace Tk's original destroy with the hook.
Tk.__original__destroy = Tk.destroy
Tk.destroy = _Tk_destroy

View File

@ -0,0 +1 @@
[{'id': 'obj', 'name': 'boden', 'args': {'anchored': True, 'char': ' ', 'collide': True, 'friction': 0, 'gravity': 0, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'position': {'x': 5, 'y': 5, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}, {'id': 'obj', 'name': 'obj', 'args': {'anchored': False, 'char': '#', 'collide': True, 'friction': 0, 'gravity': 1, 'acceleration': {'x': 0, 'y': 0, 'ARGID': 'vector2'}, 'bcolor': {'b': 255, 'g': 255, 'r': 255, 'ARGID': 'color3'}, 'fcolor': {'b': 0, 'g': 0, 'r': 0, 'ARGID': 'color3'}, 'position': {'x': 5, 'y': 0, 'ARGID': 'vector2'}, 'velocity': {'x': 0, 'y': 0, 'ARGID': 'vector2'}}}]

View File

@ -0,0 +1,310 @@
import tkinter as tk
import string
import random
import threading
import time
import wave
import os
class stdrend:
def __init__(self, size, cam):
self._size = size
self._grid = {}
self._win = tk.Tk()
for y in range(size[1]):
for x in range(size[0]):
temp = tk.Label(text=" ")
temp.grid(row=y, column=x)
self._win.update()
self._grid[f"{x}:{y}"] = temp
def coltohex(self, target):
colors = []
target = [target.r, target.g, target.b]
for i in target:
colors.append(("0"*(2-len(hex(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):
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(text=text, bg=self.coltohex(bcolor), fg=self.coltohex(fcolor))
class color3:
def __init__(self, r=0, g=0, b=0):
self.r = r
self.g = g
self.b = b
self._type = "color3"
def __add__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __sub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __mul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __iadd__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __isub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __imul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
class vector2:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self._type = "vector2"
def _magnitude(self):
return abs(self.x+self.y)
def __add__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __sub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __mul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
def __iadd__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __isub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __imul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
class NULL:
def __init__(self):
return None
class enum:
def __init__(self, sel):
self._sel = dict(sel)
for i in self._sel:
setattr(self, i, self._sel[i])
def getposssel(self):
return list(self._sel.keys())
def loadsound(path):
with wave.open(path) as fd:
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
class event:
def __init__(self):
self._attached = []
def execute(self):
threads = []
for i in self._attached:
temp = threading.Thread(target=i)
temp.start()
threads.append(temp)
return threads
def attach(self, target):
self._attached.append(target)
class obj:
def __init__(self):
self.position = vector2()
self.char = " "
self.ID = 0
self.gravity = 0
self.acceleration = vector2()
self.velocity = vector2()
self.friction = 0
self.collide = True
self.anchored = False
self.bcolor = color3(255, 255, 255)
self.fcolor = color3()
self._touching = event()
class camera(obj):
def __init__(self):
super().__init__()
self.mode = cammode.editable
self.subject = None
self.collide = False
self.touch = False
self.char = " "
def update(self):
if self.mode == cammode.follow and self.subject:
self.position = self.subject.position
class game:
def __init__(self, size=[10, 10], renderer=stdrend, sounddir=""):
if renderer == None: raise TypeError("Renderer class needed!")
self.sounds = {}
self.currentsounds = []
for i in os.listdir(sounddir):
if not "." in i: continue
if i.split(".")[1] != "wav": continue
self.sounds[i.split(".")[0]] = loadsound(sounddir+"/"+i)
self._size = size
self._objects = {}
self.camera = camera()
self._renderer = renderer(size, self.camera)
self._threads = []
def collidingpos(self, pos, ignore):
out = []
for i in self._objects:
i = self._objects[i]
if i in ignore: continue
if (i.position-pos)._magnitude() < 1 and i.collide == True:
out.append(i)
return out
def colliding(self, target):
out = []
if target.collide == False: return []
out = self.collidingpos(target.position, [target,])
return out
def handlecollision(self, target: obj, target2: obj):
if target2.anchored == True:
target.velocity = vector2()
else:
half = vector2(target.velocity.x/2, target.velocity.y/2)
target.velocity = vector2(half.x, half.y)
target2.velocity = half
def calcphysobj(self, target: obj):
if target.anchored == True: return
if target.collide == True:
colliding = self.collidingpos(target.position+target.velocity, [target,])
for i in colliding:
target._touching.execute()
i._touching.execute()
self.handlecollision(target, i)
target.position += target.velocity
target.velocity += vector2(0, target.gravity)
target.velocity += target.acceleration
temp = 2
if target.friction != 0:
temp = 2 / target.friction
x = target.velocity.x
y = target.velocity.y
if x != 0:
x = x/temp
if y != 0:
y = y/temp
target.velocity = vector2(x, y)
def addobj(self, obj):
id = ""
for i in range(256):
id = id + random.choice(list(string.ascii_letters))
obj.ID = id
self._objects[id] = obj
def removeobj(self, obj):
self._objects.pop(obj.ID)
obj.ID = NULL()
def removeobjbyid(self, id):
self._objects.pop(id).ID = NULL()
def between(self, min, max, target):
if min < target < max: return True
return False
def getobjbyid(self, id):
return self._objects[id]
def render(self):
tochange = []
for x in range(self._size[0]):
for y in range(self._size[1]):
tochange.append((x, y))
#self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
for i in list(self._objects.values()):
pos = i.position + self.camera.position
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue#
pos = vector2(round(pos.x), round(pos.y))
self._renderer.pix(pos.x, pos.y, i.char, i.bcolor, i.fcolor)
if (pos.x, pos.y) in tochange: tochange.remove((pos.x, pos.y))
for i in tochange:
self._renderer.pix(i[0], i[1], " ", color3(255, 255, 255), color3(255, 255, 255))
self._renderer.update()
def startscript(self, target):
temp = threading.Thread(target=target)
temp.start()
self._threads.append(temp)
def stopscripts(self):
for i in self._threads:
i.join(.0)
def stopsounds(self):
for i in self.currentsounds:
i.stop()
if __name__ == "__main__":
testgame = game(sounddir="testsound")
object = obj()
object.char = "#"
object.anchored = False
object.position = vector2(5, 5)
object.gravity = 1
floor = obj()
floor.char = "#"
floor.anchored = True
floor.position = vector2(5, 9)
floor.gravity = 0
floor.bcolor = color3(255, 255, 255)
testgame.addobj(object)
testgame.addobj(floor)
testgame.render()
print(object.ID)
while True:
testgame.calcphysobj(object)
testgame.calcphysobj(floor)
testgame.render()
time.sleep(0)

View File

@ -0,0 +1,175 @@
import sys
import threading
if sys.version_info[0] == 2:
# Python 2
from Tkinter import *
import Queue as queue
else:
# Python 3
from tkinter import *
import queue
class _Tk(object):
"""Wrapper for underlying attribute tk of class Tk"""
def __init__(self, tk, mt_debug=0, mt_check_period=10):
"""
:param tk: Tkinter.Tk.tk Tk interpreter object
:param mt_debug: Determines amount of debug output.
0 = No debug output (default)
1 = Minimal debug output
...
9 = Full debug output
:param mt_check_period: Amount of time in milliseconds (default
10) between checks for out-of-thread events when things are
otherwise idle. Decreasing this value can improve GUI
responsiveness, but at the expense of consuming more CPU
cycles.
# TODO: Replace custom logging functionality with standard
# TODO: logging.Logger for easier access and standardization
"""
self._tk = tk
# Create the incoming event queue
self._event_queue = queue.Queue(1)
# Identify the thread from which this object is being created
# so we can tell later whether an event is coming from another
# thread.
self._creation_thread = threading.current_thread()
# Create attributes for kwargs
self._debug = mt_debug
self._check_period = mt_check_period
# Destroying flag to be set by the .destroy() hook
self._destroying = False
def __getattr__(self, name):
"""
Diverts attribute accesses to a wrapper around the underlying tk
object.
"""
return _TkAttr(self, getattr(self._tk, name))
class _TkAttr(object):
"""Thread-safe callable attribute wrapper"""
def __init__(self, tk, attr):
self._tk = tk
self._attr = attr
def __call__(self, *args, **kwargs):
"""
Thread-safe method invocation. Diverts out-of-thread calls
through the event queue. Forwards all other method calls to the
underlying tk object directly.
"""
# Check if we're in the creation thread
if threading.current_thread() == self._tk._creation_thread:
# We're in the creation thread; just call the event directly
if self._tk._debug >= 8 or \
self._tk._debug >= 3 and self._attr.__name__ == 'call' and \
len(args) >= 1 and args[0] == 'after':
print('Calling event directly:', self._attr.__name__, args, kwargs)
return self._attr(*args, **kwargs)
else:
if not self._tk._destroying:
# We're in a different thread than the creation thread;
# enqueue the event, and then wait for the response.
response_queue = queue.Queue(1)
if self._tk._debug >= 1:
print('Marshalling event:', self._attr.__name__, args, kwargs)
self._tk._event_queue.put((self._attr, args, kwargs, response_queue), True, 1)
is_exception, response = response_queue.get(True, None)
# Handle the response, whether it's a normal return value or
# an exception.
if is_exception:
ex_type, ex_value, ex_tb = response
raise ex_type(ex_value, ex_tb)
return response
def _Tk__init__(self, *args, **kwargs):
"""
Hook for Tkinter.Tk.__init__ method
:param self: Tk instance
:param args, kwargs: Arguments for Tk initializer
"""
# We support some new keyword arguments that the original __init__ method
# doesn't expect, so separate those out before doing anything else.
new_kwnames = ('mt_check_period', 'mt_debug')
new_kwargs = {
kw_name: kwargs.pop(kw_name) for kw_name in new_kwnames
if kwargs.get(kw_name, None) is not None
}
# Call the original __init__ method, creating the internal tk member.
self.__original__init__mtTkinter(*args, **kwargs)
# Replace the internal tk member with a wrapper that handles calls from
# other threads.
self.tk = _Tk(self.tk, **new_kwargs)
# Set up the first event to check for out-of-thread events.
self.after_idle(_check_events, self)
# Define a hook for class Tk's destroy method.
def _Tk_destroy(self):
self.tk._destroying = True
self.__original__destroy()
def _check_events(tk):
"""Checks events in the queue on a given Tk instance"""
used = False
try:
# Process all enqueued events, then exit.
while True:
try:
# Get an event request from the queue.
method, args, kwargs, response_queue = tk.tk._event_queue.get_nowait()
except queue.Empty:
# No more events to process.
break
else:
# Call the event with the given arguments, and then return
# the result back to the caller via the response queue.
used = True
if tk.tk._debug >= 2:
print('Calling event from main thread:', method.__name__, args, kwargs)
try:
response_queue.put((False, method(*args, **kwargs)))
except SystemExit:
raise # Raises original SystemExit
except Exception:
# Calling the event caused an exception; return the
# exception back to the caller so that it can be raised
# in the caller's thread.
from sys import exc_info # Python 2 requirement
ex_type, ex_value, ex_tb = exc_info()
response_queue.put((True, (ex_type, ex_value, ex_tb)))
finally:
# Schedule to check again. If we just processed an event, check
# immediately; if we didn't, check later.
if used:
tk.after_idle(_check_events, tk)
else:
tk.after(tk.tk._check_period, _check_events, tk)
"""Perform in-memory modification of Tkinter module"""
# Replace Tk's original __init__ with the hook.
Tk.__original__init__mtTkinter = Tk.__init__
Tk.__init__ = _Tk__init__
# Replace Tk's original destroy with the hook.
Tk.__original__destroy = Tk.destroy
Tk.destroy = _Tk_destroy

View File

@ -5,6 +5,9 @@ import string
import threading
import mtTkinter as tk
import time
import simpleaudio as sa
import os
import base64
global gamedata
gamedata = {}
@ -69,7 +72,17 @@ def add(objtype):
game.addobj(obj)
gamedata[id]["args"]["ID"] = obj.ID
return id
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"]
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"]
@ -106,11 +119,31 @@ def log(text, end="\n", flush=False):
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 run():
print("preparing log file...")
global logfile
global win
global game
global maingame
global window
temp = time.gmtime(time.time())
logfile = ""
for i in temp:
@ -120,8 +153,18 @@ def run():
log("Preparing API...")
API = {"print": log, "HASHBASE": hashengine}
log("Done!")
API["HASHGAME"] = game
window = tk.Tk()
window.protocol("WM_DELETE_WINDOW", NULL)
maingame = game
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"])
scripts = []
for i in gamedata:
i = gamedata[i]
@ -131,7 +174,8 @@ def run():
obj.code = i
scripts.append(obj)
for i in scripts:
game.startscript(lambda: i.execute(API))
maingame.startscript(lambda: i.execute(API))
log("objects transferred!")
gamescript = """
global HASHGAME
import time
@ -143,7 +187,7 @@ while True:
"""
gameloopsc = script()
gameloopsc.code = gamescript
game.startscript(lambda: gameloopsc.execute(API))
maingame.startscript(lambda: gameloopsc.execute(API))
log("game test started!!!")
log("---------------------")
@ -152,6 +196,19 @@ def wait():
load("game.HEGF")
run()
def apath(old, ext):
return "/"
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
@ -160,10 +217,10 @@ global attypes
global crucial
global game
win = tk.Tk()
game = hashengine.game(renderer=lambda size, cam: rend(size, cam, win, [0, 0]))
game = hashengine.game(renderer=lambda size, cam: rend(size, cam, win, [0, 0]), sounddir="/")
crucial = ["obj",]
types = hashengine.enum({"obj": hashengine.obj, "script": script})
ignoreat = ["ID", "execute"]
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

File diff suppressed because one or more lines are too long

View File

@ -3,6 +3,8 @@ import string
import random
import threading
import time
import wave
import os
class stdrend:
def __init__(self, size, cam):
@ -122,6 +124,11 @@ class enum:
def getposssel(self):
return list(self._sel.keys())
def loadsound(path):
with wave.open(path) as fd:
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
class event:
@ -168,8 +175,14 @@ class camera(obj):
self.position = self.subject.position
class game:
def __init__(self, size=[10, 10], renderer=stdrend):
def __init__(self, size=[10, 10], renderer=stdrend, sounddir=""):
if renderer == None: raise TypeError("Renderer class needed!")
self.sounds = {}
self.currentsounds = []
for i in os.listdir(sounddir):
if not "." in i: continue
if i.split(".")[1] != "wav": continue
self.sounds[i.split(".")[0]] = loadsound(sounddir+"/"+i)
self._size = size
self._objects = {}
self.camera = camera()
@ -261,8 +274,12 @@ class game:
for i in self._threads:
i.join(.0)
def stopsounds(self):
for i in self.currentsounds:
i.stop()
if __name__ == "__main__":
testgame = game()
testgame = game(sounddir="testsound")
object = obj()
object.char = "#"
object.anchored = False

View File

@ -0,0 +1,175 @@
import sys
import threading
if sys.version_info[0] == 2:
# Python 2
from Tkinter import *
import Queue as queue
else:
# Python 3
from tkinter import *
import queue
class _Tk(object):
"""Wrapper for underlying attribute tk of class Tk"""
def __init__(self, tk, mt_debug=0, mt_check_period=10):
"""
:param tk: Tkinter.Tk.tk Tk interpreter object
:param mt_debug: Determines amount of debug output.
0 = No debug output (default)
1 = Minimal debug output
...
9 = Full debug output
:param mt_check_period: Amount of time in milliseconds (default
10) between checks for out-of-thread events when things are
otherwise idle. Decreasing this value can improve GUI
responsiveness, but at the expense of consuming more CPU
cycles.
# TODO: Replace custom logging functionality with standard
# TODO: logging.Logger for easier access and standardization
"""
self._tk = tk
# Create the incoming event queue
self._event_queue = queue.Queue(1)
# Identify the thread from which this object is being created
# so we can tell later whether an event is coming from another
# thread.
self._creation_thread = threading.current_thread()
# Create attributes for kwargs
self._debug = mt_debug
self._check_period = mt_check_period
# Destroying flag to be set by the .destroy() hook
self._destroying = False
def __getattr__(self, name):
"""
Diverts attribute accesses to a wrapper around the underlying tk
object.
"""
return _TkAttr(self, getattr(self._tk, name))
class _TkAttr(object):
"""Thread-safe callable attribute wrapper"""
def __init__(self, tk, attr):
self._tk = tk
self._attr = attr
def __call__(self, *args, **kwargs):
"""
Thread-safe method invocation. Diverts out-of-thread calls
through the event queue. Forwards all other method calls to the
underlying tk object directly.
"""
# Check if we're in the creation thread
if threading.current_thread() == self._tk._creation_thread:
# We're in the creation thread; just call the event directly
if self._tk._debug >= 8 or \
self._tk._debug >= 3 and self._attr.__name__ == 'call' and \
len(args) >= 1 and args[0] == 'after':
print('Calling event directly:', self._attr.__name__, args, kwargs)
return self._attr(*args, **kwargs)
else:
if not self._tk._destroying:
# We're in a different thread than the creation thread;
# enqueue the event, and then wait for the response.
response_queue = queue.Queue(1)
if self._tk._debug >= 1:
print('Marshalling event:', self._attr.__name__, args, kwargs)
self._tk._event_queue.put((self._attr, args, kwargs, response_queue), True, 1)
is_exception, response = response_queue.get(True, None)
# Handle the response, whether it's a normal return value or
# an exception.
if is_exception:
ex_type, ex_value, ex_tb = response
raise ex_type(ex_value, ex_tb)
return response
def _Tk__init__(self, *args, **kwargs):
"""
Hook for Tkinter.Tk.__init__ method
:param self: Tk instance
:param args, kwargs: Arguments for Tk initializer
"""
# We support some new keyword arguments that the original __init__ method
# doesn't expect, so separate those out before doing anything else.
new_kwnames = ('mt_check_period', 'mt_debug')
new_kwargs = {
kw_name: kwargs.pop(kw_name) for kw_name in new_kwnames
if kwargs.get(kw_name, None) is not None
}
# Call the original __init__ method, creating the internal tk member.
self.__original__init__mtTkinter(*args, **kwargs)
# Replace the internal tk member with a wrapper that handles calls from
# other threads.
self.tk = _Tk(self.tk, **new_kwargs)
# Set up the first event to check for out-of-thread events.
self.after_idle(_check_events, self)
# Define a hook for class Tk's destroy method.
def _Tk_destroy(self):
self.tk._destroying = True
self.__original__destroy()
def _check_events(tk):
"""Checks events in the queue on a given Tk instance"""
used = False
try:
# Process all enqueued events, then exit.
while True:
try:
# Get an event request from the queue.
method, args, kwargs, response_queue = tk.tk._event_queue.get_nowait()
except queue.Empty:
# No more events to process.
break
else:
# Call the event with the given arguments, and then return
# the result back to the caller via the response queue.
used = True
if tk.tk._debug >= 2:
print('Calling event from main thread:', method.__name__, args, kwargs)
try:
response_queue.put((False, method(*args, **kwargs)))
except SystemExit:
raise # Raises original SystemExit
except Exception:
# Calling the event caused an exception; return the
# exception back to the caller so that it can be raised
# in the caller's thread.
from sys import exc_info # Python 2 requirement
ex_type, ex_value, ex_tb = exc_info()
response_queue.put((True, (ex_type, ex_value, ex_tb)))
finally:
# Schedule to check again. If we just processed an event, check
# immediately; if we didn't, check later.
if used:
tk.after_idle(_check_events, tk)
else:
tk.after(tk.tk._check_period, _check_events, tk)
"""Perform in-memory modification of Tkinter module"""
# Replace Tk's original __init__ with the hook.
Tk.__original__init__mtTkinter = Tk.__init__
Tk.__init__ = _Tk__init__
# Replace Tk's original destroy with the hook.
Tk.__original__destroy = Tk.destroy
Tk.destroy = _Tk_destroy

View File

@ -5,6 +5,9 @@ import string
import threading
import mtTkinter as tk
import time
import simpleaudio as sa
import os
import base64
global gamedata
gamedata = {}
@ -69,7 +72,17 @@ def add(objtype):
game.addobj(obj)
gamedata[id]["args"]["ID"] = obj.ID
return id
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"]
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"]
@ -106,11 +119,31 @@ def log(text, end="\n", flush=False):
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 run():
print("preparing log file...")
global logfile
global win
global game
global maingame
global window
temp = time.gmtime(time.time())
logfile = ""
for i in temp:
@ -120,8 +153,18 @@ def run():
log("Preparing API...")
API = {"print": log, "HASHBASE": hashengine}
log("Done!")
API["HASHGAME"] = game
window = tk.Tk()
window.protocol("WM_DELETE_WINDOW", NULL)
maingame = game
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"])
scripts = []
for i in gamedata:
i = gamedata[i]
@ -131,7 +174,8 @@ def run():
obj.code = i
scripts.append(obj)
for i in scripts:
game.startscript(lambda: i.execute(API))
maingame.startscript(lambda: i.execute(API))
log("objects transferred!")
gamescript = """
global HASHGAME
import time
@ -143,7 +187,7 @@ while True:
"""
gameloopsc = script()
gameloopsc.code = gamescript
game.startscript(lambda: gameloopsc.execute(API))
maingame.startscript(lambda: gameloopsc.execute(API))
log("game test started!!!")
log("---------------------")
@ -152,6 +196,19 @@ def wait():
load("game.HEGF")
run()
def apath(old, ext):
return "/"
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
@ -160,10 +217,10 @@ global attypes
global crucial
global game
win = tk.Tk()
game = hashengine.game(renderer=lambda size, cam: rend(size, cam, win, [0, 0]))
game = hashengine.game(renderer=lambda size, cam: rend(size, cam, win, [0, 0]), sounddir="/")
crucial = ["obj",]
types = hashengine.enum({"obj": hashengine.obj, "script": script})
ignoreat = ["ID", "execute"]
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

File diff suppressed because one or more lines are too long

View File

@ -0,0 +1,336 @@
import tkinter as tk
import string
import random
import threading
import time
import wave
import os
class stdrend:
def __init__(self, size, cam):
self._size = size
self._grid = {}
self._win = tk.Tk()
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(text=" ")
temp.grid(row=y, column=x)
self._win.update()
self._grid[f"{x}:{y}"] = temp
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(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):
if f"{x}:{y}" in self._grid:
self._grid[f"{x}:{y}"].config(text=text, bg=self.coltohex(bcolor), fg=self.coltohex(fcolor))
class color3:
def __init__(self, r=0, g=0, b=0):
self.r = r
self.g = g
self.b = b
self._type = "color3"
def __add__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __sub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __mul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __iadd__(self, v):
temp = color3(self.r+v.r, self.g+v.g, self.b+v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __isub__(self, v):
temp = color3(self.r-v.r, self.g-v.g, self.b-v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
def __imul__(self, v):
temp = color3(self.r*v.r, self.g*v.g, self.b*v.b)
temp.r = temp.r%255
temp.g = temp.g%255
temp.b = temp.b%255
return temp
class vector2:
def __init__(self, x=0, y=0):
self.x = x
self.y = y
self._type = "vector2"
def _magnitude(self):
return abs(self.x+self.y)
def __add__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __sub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __mul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
def __iadd__(self, v):
return vector2(self.x+v.x, self.y+v.y)
def __isub__(self, v):
return vector2(self.x-v.x, self.y-v.y)
def __imul__(self, v):
return vector2(self.x*v.x, self.y*v.y)
class NULL:
def __init__(self):
return None
class enum:
def __init__(self, sel):
self._sel = dict(sel)
for i in self._sel:
setattr(self, i, self._sel[i])
def getposssel(self):
return list(self._sel.keys())
def loadsound(path):
with wave.open(path) as fd:
frames = fd.readframes(1000000000)
return frames
cammode = enum({"editable": 0, "follow": 1})
class event:
def __init__(self):
self._attached = []
def execute(self):
threads = []
for i in self._attached:
temp = threading.Thread(target=i)
temp.start()
threads.append(temp)
return threads
def attach(self, target):
self._attached.append(target)
class obj:
def __init__(self):
self.position = vector2()
self.char = " "
self.ID = 0
self.gravity = 0
self.acceleration = vector2()
self.velocity = vector2()
self.friction = 0
self.collide = True
self.anchored = False
self.bcolor = color3(255, 255, 255)
self.fcolor = color3()
self._touching = event()
class camera(obj):
def __init__(self):
super().__init__()
self.mode = cammode.editable
self.subject = None
self.collide = False
self.touch = False
self.char = " "
def update(self):
if self.mode == cammode.follow and self.subject:
self.position = self.subject.position
class game:
def __init__(self, size=[10, 10], renderer=stdrend, sounddir=""):
if renderer == None: raise TypeError("Renderer class needed!")
self.sounds = {}
self.currentsounds = []
for i in os.listdir(sounddir):
if not "." in i: continue
if i.split(".")[1] != "wav": continue
self.sounds[i.split(".")[0]] = loadsound(sounddir+"/"+i)
self._size = size
self._objects = {}
self.camera = camera()
self._renderer = renderer(size, self.camera)
self._threads = []
def isdown(self, key):
temp = self._renderer.getkeys()
if key in temp:
return temp[key]
def collidingpos(self, pos, ignore):
out = []
for i in self._objects:
i = self._objects[i]
if i in ignore: continue
if (i.position-pos)._magnitude() < 1 and i.collide == True:
out.append(i)
return out
def colliding(self, target):
out = []
if target.collide == False: return []
out = self.collidingpos(target.position, [target,])
return out
def handlecollision(self, target: obj, target2: obj):
if target2.anchored == True:
target.velocity = vector2()
else:
half = vector2(target.velocity.x/2, target.velocity.y/2)
target.velocity = vector2(half.x, half.y)
target2.velocity = half
def calcphysobj(self, target: obj):
if target.anchored == True: return
if target.collide == True:
colliding = self.collidingpos(target.position+target.velocity, [target,])
for i in colliding:
target._touching.execute()
i._touching.execute()
self.handlecollision(target, i)
target.position += target.velocity
target.velocity += vector2(0, target.gravity)
target.velocity += target.acceleration
temp = 2
if target.friction != 0:
temp = 2 / target.friction
x = target.velocity.x
y = target.velocity.y
if x != 0:
x = x/temp
if y != 0:
y = y/temp
target.velocity = vector2(x, y)
def addobj(self, obj):
id = ""
for i in range(256):
id = id + random.choice(list(string.ascii_letters))
obj.ID = id
self._objects[id] = obj
def removeobj(self, obj):
self._objects.pop(obj.ID)
obj.ID = NULL()
def removeobjbyid(self, id):
self._objects.pop(id).ID = NULL()
def between(self, min, max, target):
if min < target < max: return True
return False
def getobjbyid(self, id):
return self._objects[id]
def render(self):
tochange = []
for x in range(self._size[0]):
for y in range(self._size[1]):
tochange.append((x, y))
#self._renderer.pix(x, y, " ", color3(255, 255, 255), color3(255, 255, 255))
for i in list(self._objects.values()):
pos = i.position + self.camera.position
if not self.between(-1, self._size[0], pos.x) or not self.between(-1, self._size[1], pos.y): continue#
pos = vector2(round(pos.x), round(pos.y))
self._renderer.pix(pos.x, pos.y, i.char, i.bcolor, i.fcolor)
if (pos.x, pos.y) in tochange: tochange.remove((pos.x, pos.y))
for i in tochange:
self._renderer.pix(i[0], i[1], " ", color3(255, 255, 255), color3(255, 255, 255))
self._renderer.update()
def startscript(self, target):
temp = threading.Thread(target=target)
temp.start()
self._threads.append(temp)
def stopscripts(self):
for i in self._threads:
i.join(.0)
def stopsounds(self):
for i in self.currentsounds:
i.stop()
if __name__ == "__main__":
testgame = game(sounddir="testsound")
object = obj()
object.char = "#"
object.anchored = False
object.position = vector2(5, 5)
object.gravity = 1
floor = obj()
floor.char = "#"
floor.anchored = True
floor.position = vector2(5, 9)
floor.gravity = 0
floor.bcolor = color3(255, 255, 255)
testgame.addobj(object)
testgame.addobj(floor)
testgame.render()
print(object.ID)
while True:
testgame.calcphysobj(object)
testgame.calcphysobj(floor)
testgame.render()
time.sleep(0)

View File

@ -0,0 +1,8 @@
Log file start!
Preparing API...
Done!
main game initalised!
copying sounds...
objects transferred!
game test started!!!
---------------------

View File

@ -0,0 +1,7 @@
import player
import ast
file = open("game.HEGF", 'r')
file = file.read()
file = ast.literal_eval(file)
player.execgame(file)

View File

@ -0,0 +1,175 @@
import sys
import threading
if sys.version_info[0] == 2:
# Python 2
from Tkinter import *
import Queue as queue
else:
# Python 3
from tkinter import *
import queue
class _Tk(object):
"""Wrapper for underlying attribute tk of class Tk"""
def __init__(self, tk, mt_debug=0, mt_check_period=10):
"""
:param tk: Tkinter.Tk.tk Tk interpreter object
:param mt_debug: Determines amount of debug output.
0 = No debug output (default)
1 = Minimal debug output
...
9 = Full debug output
:param mt_check_period: Amount of time in milliseconds (default
10) between checks for out-of-thread events when things are
otherwise idle. Decreasing this value can improve GUI
responsiveness, but at the expense of consuming more CPU
cycles.
# TODO: Replace custom logging functionality with standard
# TODO: logging.Logger for easier access and standardization
"""
self._tk = tk
# Create the incoming event queue
self._event_queue = queue.Queue(1)
# Identify the thread from which this object is being created
# so we can tell later whether an event is coming from another
# thread.
self._creation_thread = threading.current_thread()
# Create attributes for kwargs
self._debug = mt_debug
self._check_period = mt_check_period
# Destroying flag to be set by the .destroy() hook
self._destroying = False
def __getattr__(self, name):
"""
Diverts attribute accesses to a wrapper around the underlying tk
object.
"""
return _TkAttr(self, getattr(self._tk, name))
class _TkAttr(object):
"""Thread-safe callable attribute wrapper"""
def __init__(self, tk, attr):
self._tk = tk
self._attr = attr
def __call__(self, *args, **kwargs):
"""
Thread-safe method invocation. Diverts out-of-thread calls
through the event queue. Forwards all other method calls to the
underlying tk object directly.
"""
# Check if we're in the creation thread
if threading.current_thread() == self._tk._creation_thread:
# We're in the creation thread; just call the event directly
if self._tk._debug >= 8 or \
self._tk._debug >= 3 and self._attr.__name__ == 'call' and \
len(args) >= 1 and args[0] == 'after':
print('Calling event directly:', self._attr.__name__, args, kwargs)
return self._attr(*args, **kwargs)
else:
if not self._tk._destroying:
# We're in a different thread than the creation thread;
# enqueue the event, and then wait for the response.
response_queue = queue.Queue(1)
if self._tk._debug >= 1:
print('Marshalling event:', self._attr.__name__, args, kwargs)
self._tk._event_queue.put((self._attr, args, kwargs, response_queue), True, 1)
is_exception, response = response_queue.get(True, None)
# Handle the response, whether it's a normal return value or
# an exception.
if is_exception:
ex_type, ex_value, ex_tb = response
raise ex_type(ex_value, ex_tb)
return response
def _Tk__init__(self, *args, **kwargs):
"""
Hook for Tkinter.Tk.__init__ method
:param self: Tk instance
:param args, kwargs: Arguments for Tk initializer
"""
# We support some new keyword arguments that the original __init__ method
# doesn't expect, so separate those out before doing anything else.
new_kwnames = ('mt_check_period', 'mt_debug')
new_kwargs = {
kw_name: kwargs.pop(kw_name) for kw_name in new_kwnames
if kwargs.get(kw_name, None) is not None
}
# Call the original __init__ method, creating the internal tk member.
self.__original__init__mtTkinter(*args, **kwargs)
# Replace the internal tk member with a wrapper that handles calls from
# other threads.
self.tk = _Tk(self.tk, **new_kwargs)
# Set up the first event to check for out-of-thread events.
self.after_idle(_check_events, self)
# Define a hook for class Tk's destroy method.
def _Tk_destroy(self):
self.tk._destroying = True
self.__original__destroy()
def _check_events(tk):
"""Checks events in the queue on a given Tk instance"""
used = False
try:
# Process all enqueued events, then exit.
while True:
try:
# Get an event request from the queue.
method, args, kwargs, response_queue = tk.tk._event_queue.get_nowait()
except queue.Empty:
# No more events to process.
break
else:
# Call the event with the given arguments, and then return
# the result back to the caller via the response queue.
used = True
if tk.tk._debug >= 2:
print('Calling event from main thread:', method.__name__, args, kwargs)
try:
response_queue.put((False, method(*args, **kwargs)))
except SystemExit:
raise # Raises original SystemExit
except Exception:
# Calling the event caused an exception; return the
# exception back to the caller so that it can be raised
# in the caller's thread.
from sys import exc_info # Python 2 requirement
ex_type, ex_value, ex_tb = exc_info()
response_queue.put((True, (ex_type, ex_value, ex_tb)))
finally:
# Schedule to check again. If we just processed an event, check
# immediately; if we didn't, check later.
if used:
tk.after_idle(_check_events, tk)
else:
tk.after(tk.tk._check_period, _check_events, tk)
"""Perform in-memory modification of Tkinter module"""
# Replace Tk's original __init__ with the hook.
Tk.__original__init__mtTkinter = Tk.__init__
Tk.__init__ = _Tk__init__
# Replace Tk's original destroy with the hook.
Tk.__original__destroy = Tk.destroy
Tk.destroy = _Tk_destroy

View File

@ -0,0 +1,725 @@
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()

1
tests/keytest 100644
View File

@ -0,0 +1 @@
[{'id': 'script', 'name': 'Skript', 'args': {'code': 'import time\nwhile True:\n\tprint(HASHGAME.isdown("q"))\n\ttime.sleep(1)'}}]

1
tests/soundtest 100644

File diff suppressed because one or more lines are too long

Binary file not shown.