Hashengine-2.3/hashengine.py

410 lines
14 KiB
Python
Raw Permalink Normal View History

import sys
sys.dont_write_bytecode = True
2024-07-03 18:22:50 +02:00
import mtTkinter as tk
2024-07-06 15:21:14 +02:00
from HEMD import color3, vector2, event, NULL
import audiosys
from loadbar import loadbar
2024-07-04 15:23:29 +02:00
import random
import string
import math
2024-07-04 20:26:48 +02:00
import time
2024-07-05 15:27:31 +02:00
import threading
2024-07-06 15:21:14 +02:00
import pickle
2024-07-06 16:32:26 +02:00
from pathfinding import pathfinding
2024-07-07 12:27:18 +02:00
from keyboard import keyboard
import copy
import ast
import os
import shutil
2024-07-03 19:07:33 +02:00
#import itertools
#import multiprocessing
2024-07-03 18:22:50 +02:00
# designated graphics size pixel 5x5
__VERSION__ = "HE2.3-HASHENGINE-2.3"
2024-07-03 19:07:33 +02:00
2024-07-04 15:23:29 +02:00
class obj:
2024-07-03 19:07:33 +02:00
def __init__(self):
2024-07-04 15:23:29 +02:00
self.position = vector2()
self.collide = True
self.anchored = True
self.velocity = vector2()
self.acceleration = vector2()
self.id = NULL()
self.color = color3()
self.colliding = event()
2024-07-06 15:21:14 +02:00
self._parent = NULL()
2024-07-04 15:23:29 +02:00
self.children = []
2024-07-04 20:26:48 +02:00
self.ignorecollision = []
self.type = "OBJ"
self.name = "object"
2024-07-03 19:07:33 +02:00
2024-07-06 15:21:14 +02:00
@property
def parent(self):
return self._parent
@parent.setter
def parent(self, value):
if hasattr(self._parent, "children"): self._parent.children.remove(self)
2024-07-06 15:21:14 +02:00
self._parent = value
if hasattr(self._parent, "children"): self._parent.children.append(self)
2024-07-06 15:21:14 +02:00
2024-07-07 17:32:02 +02:00
class folder:
def __init__(self):
self._parent = NULL()
self.children = []
self.type = "FOLD"
self.name = "folder"
self.id = NULL()
2024-07-07 17:32:02 +02:00
2024-08-02 19:30:35 +02:00
def move(self, target: vector2):
"""move the children of the folder to an specified position
"""
2024-08-02 19:30:35 +02:00
temp = []
for i in self.children:
temp.append(i.position)
temp = target.__getdiff__(temp, True)
target -= temp
for i in self.children:
i.position += target
2024-07-07 17:32:02 +02:00
@property
def parent(self):
return self._parent
@parent.setter
def parent(self, value):
if hasattr(self._parent, "children"): self._parent.children.remove(self)
2024-07-07 17:32:02 +02:00
self._parent = value
if hasattr(self._parent, "children"): self._parent.children.append(self)
2024-07-07 17:32:02 +02:00
2024-07-03 19:07:33 +02:00
class game:
def __init__(self, canvas: tk.Canvas, win, pixelsize=3, chunksize=10):
2024-07-03 19:07:33 +02:00
self._canvas = canvas
2024-07-04 20:26:48 +02:00
self._height = int(canvas.winfo_reqheight()/pixelsize)
self._width = int(canvas.winfo_reqwidth()/pixelsize)
self._pixelsize = pixelsize
2024-07-03 19:07:33 +02:00
self._OAP = {}
self._objects = {}
self._visobjects = {}
2024-07-04 20:26:48 +02:00
self._camera = obj()
self._camera.zoom = pixelsize
2024-07-05 15:27:31 +02:00
self._OAPUPDATING = False
2024-07-06 15:21:14 +02:00
self._handler = audiosys.handler()
self._threads = []
self._root = obj()
self._scripts = {}
2024-07-28 16:43:05 +02:00
self._keyboard = keyboard(win)
self._things = {}
2024-07-26 17:17:19 +02:00
self._win = win
self._chunksize = chunksize
self._globalvars = {}
2024-07-03 19:07:33 +02:00
"""self._workers = []
self._processes = 2 # total number of processes.
for i in range(self._processes):
xresult = multiprocessing.Array("i")
yresult = multiprocessing.Array("i")
oresult = multiprocessing.Array("s")
temp = multiprocessing.Process()
temp.start()
2024-07-04 20:26:48 +02:00
self._workers.append({"process": temp, ""})""" # scraped idea, im keeping it in incase i ever decide to use it
2024-08-02 19:30:35 +02:00
def cloneobj(self, target):
return copy.deepcopy(target)
def getchunkbypos(self, position: vector2):
return vector2(int(position.x/self._chunksize), int(position.y/self._chunksize))
def getposbychunk(self, chunk: vector2):
return vector2(int(chunk.x*self._chunksize), int(chunk.y*self._chunksize))
2024-07-04 15:23:29 +02:00
def genid(self):
out = ""
for i in range(255):
out = out + random.choice(list(string.ascii_letters))
return out
2024-07-04 20:26:48 +02:00
def v2tuple(self, target: vector2):
return (target.x, target.y)
def tuple2v(self, target: tuple):
return vector2(target[0], target[1])
2024-07-04 15:23:29 +02:00
def addtooap(self, target: obj):
if self.v2tuple(self.getchunkbypos(target.position.__round__())) in self._OAP:
self._OAP[self.v2tuple(self.getchunkbypos(target.position.__round__()))].append(target)
2024-07-04 15:23:29 +02:00
else:
self._OAP[self.v2tuple(self.getchunkbypos(target.position.__round__()))] = [target]
2024-07-04 20:26:48 +02:00
def updateobjinoap(self, target: obj):
self.remfromoap(target)
self.addtooap(target)
2024-07-04 15:23:29 +02:00
def remfromoap(self, target: obj):
2024-07-04 20:26:48 +02:00
for i in self._OAP:
if target in self._OAP[i]:
self._OAP[i].remove(target)
if len(self._OAP[i]) == 0:
self._OAP.pop(i)
break
2024-07-04 15:23:29 +02:00
def getfromoap(self, target: vector2):
if self.v2tuple(self.getchunkbypos(target.__round__())) in self._OAP:
return self._OAP[self.v2tuple(self.getchunkbypos(target.__round__()))]
2024-07-04 15:23:29 +02:00
else:
return []
def addobj(self, target: obj, physics=True, id=None, parent=None):
2024-07-05 15:27:31 +02:00
if id == None: temp = self.genid()
else: temp = id
2024-07-04 15:23:29 +02:00
if physics: self._objects[temp] = target
if parent == None: parent = self._root
2024-07-04 15:23:29 +02:00
self._visobjects[temp] = target
2024-07-04 20:26:48 +02:00
target.id = temp
target.parent = parent
self._things[temp] = target
2024-07-04 15:23:29 +02:00
self.addtooap(target)
def addfold(self, target: folder, id=None, parent=None):
if id == None: temp = self.genid()
else: temp = id
if parent == None: parent = self._root
target.id = temp
target.parent = parent
self._things[temp] = target
2024-07-06 16:32:26 +02:00
def getobjbyid(self, id):
if not id in self._objects: raise TypeError(f"No object with id {id} was found")
return self._objects[id]
def getglobalthing(self, id):
if not id in self._things: raise TypeError(f"No thing with id {id} was found")
return self._things[id]
2024-07-27 12:21:27 +02:00
def recursiverem(self, target, TLB: loadbar):
TLB.repeat += len(target.children)
TLB.steps = TLB.repeat/TLB.length
count = 0
2024-07-27 12:53:00 +02:00
#overflow = int(len(target.children)/10)
overflow = 1000000 # whoever deletes one million objects is not human anymore.
2024-07-27 12:21:27 +02:00
for i in target.children.copy():
self.INROBJ(i)
2024-07-27 12:21:27 +02:00
self.recursiverem(i, TLB)
TLB.current += 1
TLB.render()
count += 1
if count > overflow:
count = 0
self.render()
self._win.update()
messagebox.showinfo("why", "just why, one million objects, seriously???")
def INROBJ(self, target):
2024-07-06 16:32:26 +02:00
if target.id in self._visobjects: self._visobjects.pop(target.id)
if target.id in self._objects: self._objects.pop(target.id)
if target.id in self._things: self._things.pop(target.id)
if target.type == "OBJ": self.remfromoap(target)
target.parent = NULL()
def removeobj(self, target: obj):
self.INROBJ(target)
2024-07-27 12:21:27 +02:00
TLB = loadbar(20, 1)
self.recursiverem(target, TLB)
2024-07-04 15:23:29 +02:00
def distance(self, pos1, pos2):
return math.dist(((pos1.x, pos1.y), (pos2.x, pos2.y)))
def getcolliding(self, target):
return self.getfromoap(target.position)
2024-07-04 20:26:48 +02:00
def handlecollision(self, obj1: obj, obj2: obj):
#False is blocked
#True is not blocked
#returns tuple like this (True, True)
xblock = False
yblock = False
obj1pos = obj1.position.__round__()
obj2pos = obj2.position.__round__()
if obj2.collide == False: return (xblock, yblock)
if obj2pos.x > obj1pos.x > obj2pos.x: xblock = True
if obj2pos.y > obj1pos.y > obj2pos.y: yblock = True
if obj2.anchored == True:
obj1.velocity = vector2()
else:
2024-07-05 15:27:31 +02:00
if xblock: obj1.velocity.x = obj1.velocity.x/2;obj2.velocity.x = obj2.velocity.x/2;obj2.position.x += obj2.velocity.x
if yblock: obj1.velocity.y = obj1.velocity.y/2;obj2.velocity.y = obj2.velocity.y/2;obj2.position.y += obj2.velocity.y
2024-07-04 20:26:48 +02:00
return (xblock, yblock)
def calcphysobj(self, target: obj):
if target.anchored: target.velocity=vector2();return
if target.type == "FOLD": return
2024-07-04 20:26:48 +02:00
new = target.position + target.velocity
oldvel = target.velocity.__copy__()
if target.collide == True:
colliding = self.getfromoap(new)
if len(colliding) > 0: target.colliding.execute()
for i in colliding:
if i == target: continue
if i in target.ignorecollision or target in i.ignorecollision: continue
i.colliding.execute()
temp = self.handlecollision(target, i)
if temp[0] == False: target.position.x += oldvel.x
if temp[1] == False: target.position.y += oldvel.y
2024-07-05 15:27:31 +02:00
if len(colliding) <= 1: target.position += target.velocity
2024-07-04 20:26:48 +02:00
else:
target.position += target.velocity
target.velocity += target.acceleration
self.updateobjinoap(target)
2024-07-05 15:27:31 +02:00
def updallobjpositions(self):
2024-07-26 17:17:19 +02:00
otime = time.time()
2024-07-05 15:27:31 +02:00
self._OAPUPDATING = True
for i in self._visobjects.values():
try:
self.updateobjinoap(i)
except Exception as e:
pass
self._OAPUPDATING = False
2024-07-26 17:17:19 +02:00
return time.time()-otime
2024-07-05 15:27:31 +02:00
2024-07-04 20:26:48 +02:00
def render(self):
#if self._OAPUPDATING == False: self.updallobjpositions()
2024-07-04 20:26:48 +02:00
self._canvas.delete(tk.ALL)
2024-07-06 16:32:26 +02:00
self._height = int(self._canvas.winfo_reqheight()/self._camera.zoom)
self._width = int(self._canvas.winfo_reqwidth()/self._camera.zoom)
2024-07-04 20:26:48 +02:00
self._pixelsize = self._camera.zoom
2024-07-06 16:32:26 +02:00
#for y in range(self._camera.position.y, self._height+self._camera.position.y):
#for x in range(self._camera.position.x, self._width+self._camera.position.x):
for y2 in range(int(self._height/self._chunksize+1)):
for x2 in range(int(self._width/self._chunksize+1)):
obj = self.getfromoap(self.getposbychunk(vector2(x2+self.getchunkbypos(self._camera.position).x, y2+self.getchunkbypos(self._camera.position).y)))
2024-07-04 20:26:48 +02:00
if len(obj) == 0: continue
for i in obj:
x = i.position.x-self._camera.position.x
y = i.position.y-self._camera.position.y
self._canvas.create_rectangle(x*self._pixelsize, y*self._pixelsize, x*self._pixelsize+self._pixelsize, y*self._pixelsize+self._pixelsize, fill=i.color.__tohex__(), width=0)
2024-07-04 20:26:48 +02:00
def updobjs(self):
2024-07-05 15:27:31 +02:00
start = time.time()
2024-07-04 20:26:48 +02:00
for i in self._objects.values():
self.calcphysobj(i)
2024-07-05 15:27:31 +02:00
return time.time()-start
2024-07-04 15:23:29 +02:00
2024-07-06 15:21:14 +02:00
def savegame(self):
print("pickling root...")
outobjects = pickle.dumps(self._root)
print("copying scripts...")
outscripts = {}
2024-07-06 15:21:14 +02:00
TLB = loadbar(20, len(self._scripts))
for i in self._scripts:
outscripts[i] = self._scripts[i]
2024-07-06 15:21:14 +02:00
TLB.current += 1
TLB.render()
print("encoding sounds...")
outsounds = []
TLB = loadbar(20, len(self._handler.storage))
for i in self._handler.storage:
outsounds.append(self._handler.tostring(i))
TLB.current += 1
TLB.render()
print()
print("done.")
2024-07-06 15:21:14 +02:00
return {"obj": outobjects, "scripts": outscripts, "sounds": outsounds}
def readdobj(self, target, TLB):
TLB.repeat += len(target)
TLB.steps = TLB.repeat/TLB.length
for i in target.copy():
if i.type == "OBJ": self.addobj(i, True, i.id, i.parent)
if i.type == "FOLD": self.addfold(i, i.id, i.parent)
2024-07-06 15:21:14 +02:00
if len(i.children) > 0: self.readdobj(i.children, TLB)
TLB.current += 1
TLB.render()
2024-07-07 12:27:18 +02:00
def isdown(self, key):
temp = self._keyboard.getkeys()
if key in temp:
return temp[key]
2024-07-06 15:21:14 +02:00
def loadgame(self, target):
print("loading objects...")
self._root = pickle.loads(target["obj"])
print("loading scripts...")
self._scripts = {}
2024-07-06 15:21:14 +02:00
TLB = loadbar(20, len(target["scripts"]))
for i in target["scripts"]:
self._scripts[i] = target["scripts"][i]
2024-07-06 15:21:14 +02:00
TLB.current += 1
TLB.render()
print()
print("loading sounds...")
self._handler.storage = {}
TLB = loadbar(20, len(target["sounds"]))
for i in target["sounds"]:
self._handler.loadfromstring(i)
TLB.current += 1
TLB.render()
print("readding objects...")
self._OAP = {}
self._objects = {}
self._visobjects = {}
TLB = loadbar(20, 0)
self.readdobj(self._root.children, TLB)
print()
print("done.")
2024-07-06 15:21:14 +02:00
2024-07-07 12:27:18 +02:00
def APIGEN(self):
API = {}
API["HASHGAME"] = self
API["vector2"] = vector2
API["color3"] = color3
API["event"] = event
API["NULL"] = NULL
API["obj"] = obj
API["SOUND"] = self._handler
2024-07-26 17:17:19 +02:00
API["PATHFIND"] = pathfinding(self)
API["GLOBAL"] = self._globalvars
2024-07-07 12:27:18 +02:00
return API
def rungame(self):
2024-07-26 17:17:19 +02:00
"""warning, yields forever!
"""
2024-07-07 12:27:18 +02:00
print("preparing scripts")
for i in list(self._scripts.values()):
2024-07-26 17:17:19 +02:00
self._threads.append(threading.Thread(target=lambda i=i: exec(i, self.APIGEN())))
2024-07-07 12:27:18 +02:00
print("starting scripts")
for i in self._threads:
i.start()
print("starting loop")
while True:
took = self.updobjs()
took += self.updallobjpositions()
2024-07-07 12:27:18 +02:00
self.render()
2024-07-26 17:17:19 +02:00
self._win.update()
took = 0.01-took
2024-07-07 12:27:18 +02:00
if took > 0:
time.sleep(took)
def build(self, targetdir="out"):
os.makedirs(targetdir, exist_ok=True)
shutil.copyfile("hashengine.py", targetdir+"/main.py")
shutil.copyfile("mtTkinter.py", targetdir+"/mtTkinter.py")
file = open(targetdir+"/game.HEGF", 'w')
file.write(str(self.savegame()))
file.close()
2024-07-20 19:06:03 +02:00
if not "__CMD__" in globals() and __name__ == "__main__":
2024-07-04 15:23:29 +02:00
root = tk.Tk()
canvas = tk.Canvas(root)
#load game file
if not os.path.exists("game.HEGF"): from tkinter import messagebox; messagebox.showerror("ERROR", "Hashengine was unable to find the game.HEGF file! Hashengine will be closing now"); exit()
file = open("game.HEGF", 'r')
gafi = ast.literal_eval(file.read())
file.close()
gamec = game(canvas, root, 3)
gamec.loadgame(gafi)
2024-07-06 15:21:14 +02:00
root.update()
gamec.rungame()